From 9a0b112a0fca8b2924885069297b862167e210bb Mon Sep 17 00:00:00 2001 From: Ryan Aird Date: Sat, 19 Dec 2020 20:10:23 -0600 Subject: [PATCH] Lower default rank for non-RT voices and restrict to Windows 10 October 2018 or greater --- qt/aqt/sound.py | 9 +++++++-- qt/aqt/tts.py | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py index e936e499b..1b44adebc 100644 --- a/qt/aqt/sound.py +++ b/qt/aqt/sound.py @@ -5,6 +5,7 @@ from __future__ import annotations import atexit import os +import platform import re import subprocess import sys @@ -916,10 +917,14 @@ def setup_audio(taskman: TaskManager, base_folder: str) -> None: av_player.players.append(MacTTSPlayer(taskman)) elif isWin: - from aqt.tts import WindowsTTSPlayer, WindowsRTTTSFilePlayer + from aqt.tts import WindowsRTTTSFilePlayer, WindowsTTSPlayer av_player.players.append(WindowsTTSPlayer(taskman)) - av_player.players.append(WindowsRTTTSFilePlayer(taskman)) + + if platform.release() == "10": + # If Windows 10, ensure it's October 2018 update or later + if int(platform.version().split(".")[-1]) >= 17763: + av_player.players.append(WindowsRTTTSFilePlayer(taskman)) # cleanup at shutdown atexit.register(av_player.shutdown) diff --git a/qt/aqt/tts.py b/qt/aqt/tts.py index b3ee56fda..2536a8d56 100644 --- a/qt/aqt/tts.py +++ b/qt/aqt/tts.py @@ -25,11 +25,11 @@ expose the name of the engine, which would mean the user could write from __future__ import annotations +import asyncio import os import re import subprocess import threading -import asyncio from concurrent.futures import Future from dataclasses import dataclass from operator import attrgetter @@ -470,6 +470,7 @@ if isWin: return LCIDS.get(dec_str, "unknown") class WindowsTTSPlayer(TTSProcessPlayer): + default_rank = -1 try: speaker = win32com.client.Dispatch("SAPI.SpVoice") except: @@ -529,14 +530,22 @@ if isWin: def import_voices(self) -> None: import winrt.windows.media.speechsynthesis as speechsynthesis + self.voice_list = speechsynthesis.SpeechSynthesizer.get_all_voices() + def get_available_voices(self) -> List[TTSVoice]: t = threading.Thread(target=self.import_voices) t.start() t.join() return list(map(self._voice_to_object, self.voice_list)) + def _voice_to_object(self, voice: Any) -> TTSVoice: - return WindowsRTVoice(id=voice.id, name=voice.display_name.replace(" ", "_"), lang=voice.language.replace("-", "_")) + return WindowsRTVoice( + id=voice.id, + name=voice.display_name.replace(" ", "_"), + lang=voice.language.replace("-", "_"), + ) + def _play(self, tag: AVTag) -> None: assert isinstance(tag, TTSTag) match = self.voice_for_tag(tag) @@ -547,6 +556,7 @@ if isWin: lambda: gui_hooks.av_player_did_begin_playing(self, tag) ) asyncio.run(self.speakText(tag, voice.id)) + def _on_done(self, ret: Future, cb: OnDoneCallback): ret.result() @@ -557,9 +567,11 @@ if isWin: # then tell player to advance, which will cause the file to be played cb() + async def speakText(self, tag: TTSTag, voice_id): import winrt.windows.media.speechsynthesis as speechsynthesis import winrt.windows.storage.streams as streams + synthesizer = speechsynthesis.SpeechSynthesizer() voices = speechsynthesis.SpeechSynthesizer.get_all_voices() @@ -574,7 +586,7 @@ if isWin: inputStream = stream.get_input_stream_at(0) dataReader = streams.DataReader(inputStream) dataReader.load_async(stream.size) - f = open(self.tmppath, 'wb') + f = open(self.tmppath, "wb") for x in range(stream.size): f.write(bytes([dataReader.read_byte()])) f.close()