def main(): args = arg_parser() play = Player(dummy=args.quiet) tts = TTS(threads=1) text_size_all = 0 reply_size_all = 0 reply_time_all = 0 full_time_all = 0 counts = 0 while True: text = args.file.read(args.chunks) if not text: break text_size = len(text) reply_size = 0 full_time = time.time() reply_time = None with tts.say(text, voice=args.voice, format_='wav') as say: for chunk in say: if reply_time is None: reply_time = time.time() - full_time reply_size += len(chunk) play.play_chunk(chunk) full_time = time.time() - full_time text_size_all += text_size reply_size_all += reply_size reply_time_all += reply_time full_time_all += full_time counts += 1 _print(text_size, reply_size, reply_time, full_time) args.file.close() play.close() tts.join() if counts: print('Summary:') _print(text_size_all, reply_size_all, reply_time_all / counts, full_time_all) print('bye.')
class Player(threading.Thread): def __init__(self): super().__init__() self.tts = TTS(threads=1, force_process=False) self._queue = queue.Queue() self._p_audio = pyaudio.PyAudio() self._stream = self._p_audio.open( format=self._p_audio.get_format_from_width(2), channels=1, rate=24000, output=True, start=False, ) self._sets = { 'absolute_rate': '50', 'absolute_pitch': '50', 'absolute_volume': '50', 'voice': ['anna'] } self._nums = 'min: 0, max 100' self._info = '{}: [{}] current: {}' self._work = True self._clear_queue = threading.Event() self.start() def volume(self, volume): if not volume: return self._info.format('Volume', self._nums, self._sets['absolute_volume']) else: return self._set_set('absolute_volume', volume) def rate(self, rate): if not rate: return self._info.format('Rate', self._nums, self._sets['absolute_rate']) else: return self._set_set('absolute_rate', rate) def pitch(self, pitch): if not pitch: return self._info.format('Pitch', self._nums, self._sets['absolute_pitch']) else: return self._set_set('absolute_pitch', pitch) def voice(self, voice): if not voice: return self._info.format('Voice', ', '.join(self.tts.voices), ', '.join(self._sets['voice'])) else: if isinstance(voice, str): voice = [voice] voice = voice[:2] return self._set_set('voice', voice) def _set_set(self, param, value): if self._sets[param] == value: return 'unchanged' if param == 'voice': return self._set_voice(value) else: n_value = _prepare_set(value) if n_value is None: return 'bad value: {}'.format(value) self._sets[param] = str(n_value) self.tts.set_params(**{param: _normalize_set(n_value)}) return 'success' def _set_voice(self, voice): for target in voice: if target not in self.tts.voices: return 'unknown voice: {}'.format(target) self._sets['voice'] = voice return 'success' def _text(self, text): for line in textwrap.wrap(text, 200): if not self._work: break line = line.strip('\n') if line: yield line def _clear(self): if self._clear_queue.is_set(): while self._queue.qsize(): try: self._queue.get_nowait() except queue.Empty: break self._clear_queue.clear() def clear(self): self._clear_queue.set() def stop(self): if self._work: self._work = False self._queue.put_nowait(None) self.join() self.tts.join() self._stream.stop_stream() self._stream.close() self._p_audio.terminate() def run(self): while self._work: self._clear() data = self._queue.get() if not data: break self._say(data) def say(self, text: str, print_=True): if not text: return if print_: print(text) self._queue.put_nowait(text) def _say(self, text): self._stream.start_stream() with self.tts.say(self._text(text), self._sets['voice'], 'pcm') as gen: for chunk in gen: if not self._work or self._clear_queue.is_set(): break self._stream.write(chunk) self._stream.stop_stream()
class Monolithic(unittest.TestCase): def step_00_init(self): all_formats = ['pcm', 'wav', 'mp3', 'opus', 'flac'] self.files = {'wav_base': 'wav_engine'} self.files.update({key: key for key in all_formats}) self.files2 = {key: '{}_2'.format(key) for key in all_formats} self.sizes = {} self.msg = 'Я умею сохранять свой голос в {}' self.voice = 'anna' self.wav_size = None self.engine = rhvoice_proxy.Engine() self.wave = WaveWriteFpCallback() self.engine.init(self.wave, self.wave.set_sample_rate) self.tts = TTS(quiet=True) def step_01_info(self): print() print('Versions:') print(' RHVoice: {}'.format(self.engine.version)) print(' Python API: {}'.format(rhvoice_proxy.__version__)) print() voices = self.engine.voices name_len = 5 voice_order = [] for v in sorted(voices.items(), key=lambda x: x[1]['no']): voice_order.append(v[0]) if len(v[1]['name']) > name_len: name_len = len(v[1]['name']) print('Voice {}Language Gender Country'.format(' ' * (name_len - 5))) line = ' {name:#} {lang:2} {gender:6} {country:2}'.replace('#', str(name_len + 1), 1) for i in range(len(voices)): voice = voices[voice_order[i]] print(line.format(**voice)) print('Number of voices: {}'.format(len(voices))) print('Formats: {} ... '.format(', '.join(self.tts.formats)), end='') def step_02_engine(self): self.assertGreater(len(self.engine.voices), 0) self.assertIn(self.voice, self.engine.voices) self.engine.set_voice(self.voice) self.engine.generate(self.msg.format('wav')) self.sizes[self.files['wav_base']] = self.wave.size del self.wave def step_030_tts(self): self.assertGreater(len(self.tts.voices), 0) self.assertIn(self.voice, self.tts.voices) for target in [[key, val] for key, val in self.files.items() if key in self.tts.formats]: self.sizes[target[1]] = say_size( self.tts.say, text=self.msg.format(target[0]), voice=self.voice, format_=target[0] ) def step_031_empty_text(self): size = say_size(self.tts.say, text='', format_='wav') self.assertEqual(size, 0, 'No text - no audio. Return {} bytes'.format(size)) def step_04_wave(self): self.assertTrue(self.files['wav_base'] in self.sizes) self.assertTrue(self.files['wav'] in self.sizes) self.assertEqual(self.sizes[self.files['wav_base']], self.sizes[self.files['wav']]) self.assertGreater(self.sizes[self.files['wav']], 0) def step_050_sets_recovery(self): sets = {'absolute_rate': 0.5} wav1 = say_size(self.tts.say, text=self.msg, voice=self.voice, format_='wav', sets=sets) wav2 = say_size(self.tts.say, text=self.msg, voice=self.voice, format_='wav') self.assertNotEqual(wav1, wav2) def step_05_other_files(self): for target in [val for key, val in self.files.items() if key not in ['wav_base', 'wav']]: if target in self.sizes: self.assertGreater(self.sizes[target], 0) def step_06_gen_files2(self): self.assertTrue(self.tts.set_params(absolute_rate=1, absolute_pitch=1)) self.assertFalse(self.tts.set_params(absolute_rate=1, absolute_pitch=1)) self.assertEqual(self.tts.get_params('absolute_rate'), 1) self.assertEqual(self.tts.get_params('absolute_pitch'), 1) self.assertTrue(isinstance(self.tts.get_params(), dict)) self.assertIsNone(self.tts.get_params('always missing')) for target in [[key, val] for key, val in self.files2.items() if key in self.tts.formats]: self.sizes[target[1]] = say_size( self.tts.say, text=self.msg.format(target[0]), voice=self.voice, format_=target[0] ) def step_07_compare_1_2(self): for key, val in self.files2.items(): if val in self.sizes: s1 = self.sizes[self.files[key]] s2 = self.sizes[val] self.assertGreater(s1, s2) self.assertGreater(s2, 0) def step_080_processes_create(self): self.tts.join() self.clear_sizes() self.tts = TTS(threads=3, quiet=True) def step_081_processes_init(self): self._test_format('pcm') def step_082_processes_wave(self): self.wav_size = self._test_format('wav') def step_083_processes__pcm(self): self._test_format('pcm') def step_084_processes_opus(self): self._test_format('opus') def step_085_processes__mp3(self): self._test_format('mp3') def step_086_processes_flac(self): self._test_format('flac') def _test_format(self, format_): if format_ not in self.tts.formats: return print('skip ', end='') work_time = time.perf_counter() self._test_processes_format(format_) work_time = time.perf_counter() - work_time print('{:.3f} s '.format(work_time / len(self.files)), end='') data_size = self._processes_eq_size() if self.wav_size is not None: self.assertGreater(self.wav_size, data_size, 'wav must be more {}'.format(format_)) self.clear_sizes() return data_size def _test_processes_format(self, format_, sets=None): ths = {} pos = 0 buff = 1024 * 4 for x in self.files.values(): current_set = None if sets: current_set = sets[pos] pos += 1 kwargs = {'text': self.msg, 'voice': self.voice, 'format_': format_, 'buff': buff, 'sets': current_set} buff += 256 ths[x] = ThChecker(self.tts.say, kwargs) for key, val in ths.items(): self.sizes[key] = val.size def _processes_eq_size(self): all_size = [self.sizes[file] for file in self.files.values()] self.assertGreater(all_size[0], 0, 'Empty file {}'.format(str(all_size))) for test in all_size: self.assertEqual(all_size[0], test, 'File sizes must be equal: {}'.format(all_size)) return all_size[0] def _processes_diff_size(self): all_size = [self.sizes[file] for file in self.files.values()] counts = len(all_size) for one in range(counts): for two in range(counts): if one == two: continue self.assertNotEqual(all_size[one], all_size[two], 'File sizes must be not equal: {}'.format(all_size)) def step_09_test_sets(self): volumes = [{'absolute_rate': x * 0.01} for x in range(-100, 101, 200 // (len(self.files) - 1))] self._test_processes_format('wav', volumes) self._processes_diff_size() def clear_sizes(self): self.sizes = {} def step_11_join(self): self.tts.join() def _steps(self): for name in sorted(dir(self)): if name.startswith('step_'): yield name, getattr(self, name) def test_steps(self): print() for name, step in self._steps(): try: print('{} ... '.format(name), end='') step() print('ok') except Exception as e: print('FAILED') traceback.print_exc() self.step_11_join() self.fail('{} failed ({}: {})'.format(step, type(e), e))
return path def cache_init() -> CacheWorker or None: path = _get_cache_path() dyn_cache = _check_env('RHVOICE_DYNCACHE') return CacheWorker(path, tts.say) if path or dyn_cache else None if __name__ == "__main__": tts = TTS() cache = cache_init() voice_streamer = voice_streamer_cache if cache else voice_streamer_nocache CHUNKED_TRANSFER = _check_env('CHUNKED_TRANSFER') print('Chunked transfer encoding: {}'.format(CHUNKED_TRANSFER)) formats = tts.formats DEFAULT_FORMAT = _get_def(formats, DEFAULT_FORMAT, 'wav') FORMATS = {key: val for key, val in FORMATS.items() if key in formats} SUPPORT_VOICES = tts.voices DEFAULT_VOICE = _get_def(SUPPORT_VOICES, DEFAULT_VOICE) SUPPORT_VOICES = set(SUPPORT_VOICES) print('Threads: {}'.format(tts.thread_count)) app.run(host='0.0.0.0', port=8080, threaded=True) if cache: cache.join() tts.join()