From eef892a90fd20435db1f2dc07583f8bf1bd8db45 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 1 Feb 2023 21:30:06 +0530 Subject: [PATCH] Basic speech seems to work --- src/calibre/gui2/tts/windows.py | 27 +++++++++++++------------- src/calibre/utils/windows/winspeech.py | 7 ++++--- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/calibre/gui2/tts/windows.py b/src/calibre/gui2/tts/windows.py index 19e6395871..c9957e5fcb 100644 --- a/src/calibre/gui2/tts/windows.py +++ b/src/calibre/gui2/tts/windows.py @@ -51,6 +51,7 @@ class Client: self.dispatch_on_main_thread = dispatch_on_main_thread self.synthesizing = False self.settings = settings or {} + self.clear_chunks() self.apply_settings() def __del__(self): @@ -63,19 +64,17 @@ class Client: self.dispatch_on_main_thread(partial(self.handle_event, msg)) def handle_event(self, x): - if isinstance(x, MarkReached): + if isinstance(x, MarkReached) and self.current_chunks: self.last_mark = x.id + self.callback_ignoring_errors(Event(EventType.mark, x.id)) elif isinstance(x, MediaStateChanged) and self.current_chunks: - if x.state is MediaState.opened: - if self.current_chunk == 0: - self.callback_ignoring_errors(Event(EventType.begin)) - elif x.state is MediaState.ended: - if self.current_chunk >= len(self.chunks) - 1: + if x.state is MediaState.ended: + if self.current_chunk_idx >= len(self.current_chunks) - 1: self.clear_chunks() self.callback_ignoring_errors(Event(EventType.end)) else: - self.current_chunk += 1 - self.backend.speak(self.chunks[self.current_chunk], is_cued=True) + self.current_chunk_idx += 1 + self.backend.speak(self.current_chunks[self.current_chunk_idx], is_cued=True) elif x.state is MediaState.failed: raise x.as_exception() elif isinstance(x, Error): @@ -92,11 +91,13 @@ class Client: self.backend.pause() self.clear_chunks() self.current_callback = callback - self.chunks = tuple(split_into_chunks(text, self.chunk_size)) - self.current_chunk = 0 - if self.chunks: - self.backend.speak(self.chunks[self.current_chunk], is_cued=True) + self.current_chunks = tuple(split_into_chunks(text, self.chunk_size)) + self.current_chunk_idx = 0 + if self.current_chunks: + self.backend.speak(self.current_chunks[self.current_chunk_idx], is_cued=True) self.synthesizing = True + if self.current_callback is not None: + self.current_callback(Event(EventType.begin)) def callback_ignoring_errors(self, ev): if self.current_callback is not None: @@ -108,7 +109,7 @@ class Client: def clear_chunks(self): self.synthesizing = False - self.current_chunk = 0 + self.current_chunk_idx = -100 self.current_chunks = [] self.last_mark = -1 diff --git a/src/calibre/utils/windows/winspeech.py b/src/calibre/utils/windows/winspeech.py index 0a3bf52802..e612bf890f 100644 --- a/src/calibre/utils/windows/winspeech.py +++ b/src/calibre/utils/windows/winspeech.py @@ -107,7 +107,8 @@ class SpeechError(OSError): class NoAudioDevices(Exception): def __init__(self): - super().__init__(_('No active audio output devices found. Connect headphones or speakers.')) + super().__init__(_('No active audio output devices found.' + ' Connect headphones or speakers. If you are using Remote Desktop then enable Remote Audio for it.')) class Error(NamedTuple): @@ -119,8 +120,8 @@ class Error(NamedTuple): related_to: int = 0 def as_exception(self, msg='', check_for_no_audio_devices=False): - if check_for_no_audio_devices and self.hr == 0x8004503a: - raise NoAudioDevices(_('No active audio output devices found. Connect headphones or speakers.')) + if check_for_no_audio_devices and self.hr == 0xc00d36fa: + raise NoAudioDevices() raise SpeechError(self, msg)