mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Speed buttons now work on macOS
And for some reason didFinishSpeaking has started working again.
This commit is contained in:
parent
b10a85e948
commit
e86b505350
@ -81,7 +81,7 @@ class Widget(QWidget):
|
||||
l.addRow(_('&Speed of speech:'), s)
|
||||
s.setRange(self.tts_client.min_rate, self.tts_client.max_rate)
|
||||
s.setSingleStep(10)
|
||||
s.setTickInterval((self.tts_client.max_rate - self.tts_client.min_rate) // 2)
|
||||
s.setTickInterval((s.maximum() - s.minimum()) // 2)
|
||||
|
||||
self.output_modules = om = QComboBox(self)
|
||||
with BusyCursor():
|
||||
|
@ -10,6 +10,8 @@ class Client:
|
||||
mark_template = '[[sync 0x{:x}]]'
|
||||
END_MARK = 0xffffffff
|
||||
name = 'nsss'
|
||||
min_rate = 10
|
||||
max_rate = 340
|
||||
|
||||
@classmethod
|
||||
def escape_marked_text(cls, text):
|
||||
@ -24,12 +26,20 @@ class Client:
|
||||
self.current_marked_text = self.last_mark = None
|
||||
self.dispatch_on_main_thread = dispatch_on_main_thread
|
||||
self.status = {'synthesizing': False, 'paused': False}
|
||||
self.apply_settings(settings)
|
||||
self.settings = settings
|
||||
self.ignore_next_stop_event = False
|
||||
self.apply_settings()
|
||||
|
||||
def apply_settings(self, new_settings=None):
|
||||
settings = new_settings or {}
|
||||
self.nsss.set_current_rate(settings.get('rate', self.default_system_rate))
|
||||
self.nsss.set_current_voice(settings.get('voice') or self.default_system_voice)
|
||||
if self.status['paused']:
|
||||
self.nsss.resume()
|
||||
self.ignore_next_stop_event = True
|
||||
self.status = {'synthesizing': False, 'paused': False}
|
||||
if new_settings is not None:
|
||||
self.settings = new_settings
|
||||
self.nsss.set_current_voice(self.settings.get('voice') or self.default_system_voice)
|
||||
rate = self.settings.get('rate', self.default_system_rate)
|
||||
self.nsss.set_current_rate(rate)
|
||||
|
||||
def __del__(self):
|
||||
self.nsss = None
|
||||
@ -40,14 +50,12 @@ class Client:
|
||||
event = None
|
||||
if message_type == MARK:
|
||||
self.last_mark = data
|
||||
if data == self.END_MARK:
|
||||
event = Event(EventType.end)
|
||||
self.status = {'synthesizing': False, 'paused': False}
|
||||
else:
|
||||
event = Event(EventType.mark, data)
|
||||
elif message_type == END:
|
||||
if not data: # normal end event is handled by END_MARK
|
||||
event = Event(EventType.cancel)
|
||||
if self.ignore_next_stop_event:
|
||||
self.ignore_next_stop_event = False
|
||||
return
|
||||
event = Event(EventType.end if data else EventType.cancel)
|
||||
self.status = {'synthesizing': False, 'paused': False}
|
||||
if event is not None and self.current_callback is not None:
|
||||
try:
|
||||
@ -64,9 +72,6 @@ class Client:
|
||||
|
||||
def speak_marked_text(self, text, callback):
|
||||
self.current_callback = callback
|
||||
# on macOS didFinishSpeaking is never called for some reason, so work
|
||||
# around it by adding an extra, special mark at the end
|
||||
text += self.mark_template.format(self.END_MARK)
|
||||
self.current_marked_text = text
|
||||
self.last_mark = None
|
||||
self.nsss.speak(text)
|
||||
@ -88,7 +93,12 @@ class Client:
|
||||
self.current_callback(Event(EventType.resume))
|
||||
|
||||
def resume_after_configure(self):
|
||||
if self.status['paused'] and self.last_mark is not None and self.current_marked_text:
|
||||
if self.status['paused']:
|
||||
self.resume()
|
||||
return
|
||||
if self.last_mark is None:
|
||||
idx = -1
|
||||
else:
|
||||
mark = self.mark_template.format(self.last_mark)
|
||||
idx = self.current_marked_text.find(mark)
|
||||
if idx == -1:
|
||||
@ -121,3 +131,18 @@ class Client:
|
||||
def config_widget(self, backend_settings, parent):
|
||||
from calibre.gui2.tts.macos_config import Widget
|
||||
return Widget(self, backend_settings, parent)
|
||||
|
||||
def change_rate(self, steps=1):
|
||||
rate = current_rate = self.settings.get('rate', self.default_system_rate)
|
||||
step_size = (self.max_rate - self.min_rate) // 10
|
||||
rate += steps * step_size
|
||||
rate = max(self.min_rate, min(rate, self.max_rate))
|
||||
if rate != current_rate:
|
||||
self.settings['rate'] = rate
|
||||
prev_state = self.status.copy()
|
||||
self.pause()
|
||||
self.apply_settings()
|
||||
if prev_state['synthesizing']:
|
||||
self.status = {'synthesizing': True, 'paused': False}
|
||||
self.resume_after_configure()
|
||||
return self.settings
|
||||
|
@ -83,8 +83,9 @@ class Widget(QWidget):
|
||||
self.speed = s = QSlider(Qt.Orientation.Horizontal, self)
|
||||
s.setMinimumWidth(200)
|
||||
l.addRow(_('&Speed of speech (words per minute):'), s)
|
||||
delta = self.default_system_rate - 50
|
||||
s.setRange(self.default_system_rate - delta, self.default_system_rate + delta)
|
||||
s.setRange(self.tts_client.min_rate, self.tts_client.max_rate)
|
||||
s.setTickPosition(QSlider.TickPosition.TicksAbove)
|
||||
s.setTickInterval((s.maximum() - s.minimum()) // 2)
|
||||
s.setSingleStep(10)
|
||||
|
||||
self.voices = v = QTableView(self)
|
||||
|
@ -138,6 +138,9 @@ class Client:
|
||||
def resume_after_configure(self):
|
||||
if self.status['paused']:
|
||||
self.resume()
|
||||
else:
|
||||
if self.last_mark is None:
|
||||
idx = -1
|
||||
else:
|
||||
mark = self.mark_template.format(self.last_mark)
|
||||
idx = self.current_marked_text.find(mark)
|
||||
|
@ -95,7 +95,7 @@ class TTS(QObject):
|
||||
|
||||
def play(self, data):
|
||||
marked_text = add_markup(data['marked_text'], self.tts_client_class.mark_template)
|
||||
self.tts_client.speak_marked_text(marked_text, self.callback)
|
||||
self.tts_client.speak_marked_text(marked_text.strip(), self.callback)
|
||||
|
||||
def pause(self, data):
|
||||
self.tts_client.pause()
|
||||
|
Loading…
x
Reference in New Issue
Block a user