From 7b47a70493edaf3998486d81179ddeb41ec989a1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 24 Jan 2023 14:12:51 +0530 Subject: [PATCH] Get basic speaking working again --- src/calibre/utils/windows/winspeech.cpp | 15 ++++++++--- src/calibre/utils/windows/winspeech.py | 35 ++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/calibre/utils/windows/winspeech.cpp b/src/calibre/utils/windows/winspeech.cpp index 1e019575a2..9da95078ed 100644 --- a/src/calibre/utils/windows/winspeech.cpp +++ b/src/calibre/utils/windows/winspeech.cpp @@ -34,6 +34,13 @@ using namespace winrt::Windows::Media::Core; using namespace winrt::Windows::Storage::Streams; typedef unsigned long long id_type; +#define debug(format_string, ...) { \ + std::scoped_lock _sl_(output_lock); \ + DWORD _tid_ = GetCurrentThreadId(); \ + char _buf_[64] = {0}; snprintf(_buf_, sizeof(_buf_)-1, "thread-%u", _tid_); \ + fprintf(stderr, "%s " format_string "\n", main_thread_id == _tid_ ? "thread-main" : _buf_, __VA_ARGS__); fflush(stderr);\ +} + static std::mutex output_lock; static std::atomic_bool main_loop_is_running; static DWORD main_thread_id; @@ -119,7 +126,7 @@ serialize_string_for_json(std::string const &src) { return ans; } -class json_val { +class json_val { // {{{ private: enum { DT_INT, DT_STRING, DT_LIST, DT_OBJECT, DT_NONE, DT_BOOL } type; std::string s; @@ -208,7 +215,7 @@ public: } return ""; } -}; +}; // }}} static void output(id_type cmd_id, std::string_view const &msg_type, json_val const &&msg) { @@ -672,9 +679,9 @@ class Synthesizer { } public: bool cmd_id_is_current(id_type cmd_id) const noexcept { return current_cmd_id.load() == cmd_id; } - void output(id_type cmd_id, std::string_view const& type, json_val const& x) { + void output(id_type cmd_id, std::string_view const& type, json_val const && x) { std::scoped_lock sl(recursive_lock); - if (cmd_id_is_current(cmd_id)) output(cmd_id, type, x); + if (cmd_id_is_current(cmd_id)) ::output(cmd_id, type, std::move(x)); } void initialize() { synth = SpeechSynthesizer(); diff --git a/src/calibre/utils/windows/winspeech.py b/src/calibre/utils/windows/winspeech.py index c8d98cefa4..b2d66ffe86 100644 --- a/src/calibre/utils/windows/winspeech.py +++ b/src/calibre/utils/windows/winspeech.py @@ -2,10 +2,37 @@ # License: GPLv3 Copyright: 2023, Kovid Goyal -import calibre_extensions.winspeech as winspeech +import sys +import time +from contextlib import closing +from threading import Thread -winspeech +from calibre.utils.ipc.simple_worker import start_pipe_worker -def develop(): - pass +def develop_speech(text='Lucca brazzi sleeps with the fishes'): + p = start_pipe_worker('from calibre_extensions.winspeech import run_main_loop; run_main_loop()') + print('\x1b[32mSpeaking', text, '\x1b[39m', flush=True) + + def echo_output(p): + for line in p.stdout: + sys.stdout.buffer.write(b'\x1b[33m' + line + b'\x1b[39m') + sys.stdout.buffer.flush() + + def send(*a): + cmd = ' '.join(map(str, a)) + '\n' + p.stdin.write(cmd.encode()) + p.stdin.flush() + + Thread(name='Echo', target=echo_output, args=(p,), daemon=True).start() + with closing(p.stdin), closing(p.stdout): + try: + send('1 echo Synthesizer started') + send('2 speak text inline', text) + time.sleep(6) + send('3 echo Synthesizer exiting') + send('exit') + time.sleep(1) + finally: + if p.poll() is None: + p.kill()