Giter VIP home page Giter VIP logo

Comments (7)

rye761 avatar rye761 commented on June 15, 2024 1

image
It's alive! Thanks for pointing that out. I didn't think of just simply spawning another thread and importing it on the thread.

from anki.

rye761 avatar rye761 commented on June 15, 2024

You can mark that first checkbox complete! I was able to test the WinRT bindings for python and the missing voices are showing. My voice list from python perfectly matches that from the Control Panel.

pythonvoicelist

I'm not at my regular dev environment this week but when I get back home I would be willing to go a little further with this.

Here is the voice list code:

import winrt.windows.media.speechsynthesis as speechsynthesis

voices = speechsynthesis.SpeechSynthesizer.get_all_voices()

for voice in voices:
    print(voice.display_name)

from anki.

dae avatar dae commented on June 15, 2024

That's great, thanks for working on this Ryan.

from anki.

rye761 avatar rye761 commented on June 15, 2024

Back at home this week and did some more playing around. While getting a list of voices was very simple, finding the best way to play the generated RandomAccessStream from the speech API wasn't quite so. I tried using the MediaPlayer API but was met with silence and the default device returning None. A bit of research seemed to indicate it wasn't going to be possible to use that API with the Python bindings as I wasn't able to find anyone successfully using it with "C++/WinRT". The Windows Media Foundation API was the suggested alternative by someone on Stack Overflow. The code below successfully writes to a file which I was able to play. My plan going forward is to implement the same way the Mac file player is implemented in tts.py using a temporary file. This would be my first Anki contribution so I'll get the development environment setup soon and then create a pull request sometime in the next week or two if I'm able to get it to work and we can discuss further there.

Here is the code that successfully creates a playable WAV file:

import winrt.windows.media.speechsynthesis as speechsynthesis
import winrt.windows.storage.streams as streams
import asyncio
import os

voices = speechsynthesis.SpeechSynthesizer.get_all_voices()

for voice in voices:
    print(voice.display_name)
print('Default: ' + speechsynthesis.SpeechSynthesizer.get_default_voice().display_name)

async def speakText(text):
    synthesizer = speechsynthesis.SpeechSynthesizer()
    stream = await synthesizer.synthesize_text_to_stream_async(text)
    inputStream = stream.get_input_stream_at(0)
    dataReader = streams.DataReader(inputStream)
    dataReader.load_async(stream.size)
    f = open(os.getcwd() + '/test.wav', 'wb')
    for x in range(stream.size):
        f.write(bytes([dataReader.read_byte()]))
    f.close()
asyncio.run(speakText("Holy man, that was difficult!"))

from anki.

rye761 avatar rye761 commented on June 15, 2024

Tried to get this going in the Anki codebase but ran into an issue documented on the Xlang repo: microsoft/xlang#690 Since pythoncom already initializes COM, this issue comes up. I tried using sys.coinit_flags = 0 but as I mentioned on that issue that causes the Qt GUI to fail to load. Unless I find a way to get Qt to load with pythoncom set to MTA, it seems we will need to wait for this issue to be resolved before implementing WinRT voice support in Anki. I'm subscribed to the issue and would be happy to give this another try if it is fixed in an upcoming release. However, I was also not able to get the most recent version to work in Python 3.8. I had to install version 1.0.20239.1 to dodge a missing DLL error. This wasn't a big deal at this time but could prove to be an issue if a fix is published for the COM threading mode issue but the package doesn't work properly with Python 3.8 (unless of course Anki is ready for 3.9 by that time).

from anki.

dae avatar dae commented on June 15, 2024

Have you only tested this code on the main thread so far? Googling the error yields:

RPC_E_CHANGED_MODE
A previous call to CoInitializeEx specified a concurrency model for this thread different from the one currently specified for this thread.

That seems to imply the setting is thread-local, so perhaps you'd have more luck if you spawned a new thread and ran it there? Presumably that's what you'd want to do in the long run anyway, as asyncio.run() on the main thread would block the UI.

from anki.

dae avatar dae commented on June 15, 2024

Closed by #855 - thanks Ryan!

from anki.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.