Add initial files for mimic3
This commit is contained in:
parent
5889edbba5
commit
a69f8c1fac
5 changed files with 28571 additions and 0 deletions
28336
data/stened.json
Executable file
28336
data/stened.json
Executable file
File diff suppressed because it is too large
Load diff
7
install.sh
Normal file
7
install.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
python3 -m venv .venv
|
||||||
|
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
pip install -U pip
|
||||||
|
|
||||||
|
pip install mycroft-plugin-tts-mimic3[all]
|
||||||
79
main.py
Normal file
79
main.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import json
|
||||||
|
from collections import defaultdict
|
||||||
|
from time import sleep
|
||||||
|
from tts import create_mimic3_system, say_words
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mimic3 = create_mimic3_system(voice="en_US/vctk_low", preload_voices=["en_US/vctk_low"], rate=1)
|
||||||
|
steno_data: dict = {}
|
||||||
|
reverse_dict = defaultdict(set)
|
||||||
|
|
||||||
|
with open("data/stened.json", "rb") as f:
|
||||||
|
steno_data = json.load(f)
|
||||||
|
|
||||||
|
for k, v in steno_data.items():
|
||||||
|
reverse_dict[v].add(k)
|
||||||
|
|
||||||
|
key_set = set(reverse_dict.keys())
|
||||||
|
|
||||||
|
simple_words = []
|
||||||
|
|
||||||
|
for word in key_set:
|
||||||
|
new_word = word.replace('c', 'k').replace('ll', 'l')
|
||||||
|
for val in reverse_dict[word]:
|
||||||
|
steno = val.lower()
|
||||||
|
# if len(val) == len(word) or len(val) == (len(word) - 1) or len(val) == (len(word) - 2):
|
||||||
|
if new_word == steno:
|
||||||
|
# print(word)
|
||||||
|
# print(val)
|
||||||
|
# print()
|
||||||
|
simple_words.append((word, val))
|
||||||
|
break
|
||||||
|
|
||||||
|
#say_words("Can you do what I can do?", mimic3=mimic3, length_scale=3)
|
||||||
|
|
||||||
|
sentence_data = [line.strip() for line in open("sentences.txt").readlines()]
|
||||||
|
seconds_per_word = sentence_data[0]
|
||||||
|
sentences = sentence_data[1:]
|
||||||
|
|
||||||
|
ssml_data = []
|
||||||
|
|
||||||
|
for words in sentences:
|
||||||
|
ssml = " <break time='{seconds_per_word}s'/> ".join(words.split(" "))
|
||||||
|
ssml = ssml.replace(",", ", comma,").replace("?", ", query?").replace(".", ", period.")
|
||||||
|
ssml = ssml.format(seconds_per_word=seconds_per_word)
|
||||||
|
ssml_data.append(f"<s>{ssml}</s>")
|
||||||
|
|
||||||
|
print(ssml_data)
|
||||||
|
|
||||||
|
speech = """
|
||||||
|
<speak>
|
||||||
|
<voice name="en_US/vctk_low">
|
||||||
|
<prosody rate="0.6">""" + "<break time='1s'/>".join(ssml_data) + """
|
||||||
|
</prosody>
|
||||||
|
</voice>
|
||||||
|
</speak>
|
||||||
|
"""
|
||||||
|
say_words(speech, mimic3=mimic3, ssml=True)
|
||||||
|
|
||||||
|
# say_words("""<speak>
|
||||||
|
# <voice name="en_US/cmu-arctic_low">
|
||||||
|
# <prosody rate="0.4">
|
||||||
|
# <s>Can <break time="2s"/> you <break time="2s"/> hear me <break time="2s"/> now, query?</s>
|
||||||
|
# </prosody>
|
||||||
|
# </voice>
|
||||||
|
# </speak>""",mimic3=mimic3, ssml=True)
|
||||||
|
return
|
||||||
|
print(len(simple_words))
|
||||||
|
count = 0
|
||||||
|
for (word, sten) in simple_words:
|
||||||
|
print("Saying: " + word + ": " + sten)
|
||||||
|
say_words(word.capitalize() + ".", mimic3=mimic3)
|
||||||
|
sleep(3)
|
||||||
|
if count > 3:
|
||||||
|
break
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
2
sentences.txt
Normal file
2
sentences.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
2.5
|
||||||
|
Would you please take my beans?
|
||||||
147
tts.py
Normal file
147
tts.py
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
# Copyright 2022 Mycroft AI Inc.
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
import argparse
|
||||||
|
import io
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
import tempfile
|
||||||
|
import typing
|
||||||
|
import simpleaudio as sa
|
||||||
|
import wave
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
from mimic3_tts import (
|
||||||
|
AudioResult,
|
||||||
|
Mimic3Settings,
|
||||||
|
Mimic3TextToSpeechSystem,
|
||||||
|
SSMLSpeaker,
|
||||||
|
)
|
||||||
|
from mimic3_tts.config import InferenceConfig
|
||||||
|
|
||||||
|
from mimic3_http.const import TextToWavParams
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
inf_conf = InferenceConfig()
|
||||||
|
|
||||||
|
def do_synthesis(params: TextToWavParams, mimic3: Mimic3TextToSpeechSystem) -> bytes:
|
||||||
|
"""Synthesize text into audio.
|
||||||
|
|
||||||
|
Returns: WAV bytes
|
||||||
|
"""
|
||||||
|
mimic3.speaker = None
|
||||||
|
mimic3.voice = params.voice
|
||||||
|
|
||||||
|
mimic3.settings.length_scale = params.length_scale
|
||||||
|
mimic3.settings.noise_scale = params.noise_scale
|
||||||
|
mimic3.settings.noise_w = params.noise_w
|
||||||
|
|
||||||
|
with io.BytesIO() as wav_io:
|
||||||
|
wav_file: wave.Wave_write = wave.open(wav_io, "wb")
|
||||||
|
wav_params_set = False
|
||||||
|
|
||||||
|
with wav_file:
|
||||||
|
try:
|
||||||
|
if params.ssml:
|
||||||
|
# SSML
|
||||||
|
results = SSMLSpeaker(mimic3).speak(params.text)
|
||||||
|
else:
|
||||||
|
# Plain text
|
||||||
|
mimic3.begin_utterance()
|
||||||
|
mimic3.speak_text(params.text, text_language=params.text_language)
|
||||||
|
results = mimic3.end_utterance()
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
# Add audio to existing WAV file
|
||||||
|
if isinstance(result, AudioResult):
|
||||||
|
if not wav_params_set:
|
||||||
|
wav_file.setframerate(result.sample_rate_hz)
|
||||||
|
wav_file.setsampwidth(result.sample_width_bytes)
|
||||||
|
wav_file.setnchannels(result.num_channels)
|
||||||
|
wav_params_set = True
|
||||||
|
|
||||||
|
wav_file.writeframes(result.audio_bytes)
|
||||||
|
except Exception as e:
|
||||||
|
if not wav_params_set:
|
||||||
|
# Set default parameters so exception can propagate
|
||||||
|
wav_file.setframerate(22050)
|
||||||
|
wav_file.setsampwidth(2)
|
||||||
|
wav_file.setnchannels(1)
|
||||||
|
|
||||||
|
raise e
|
||||||
|
|
||||||
|
wav_bytes = wav_io.getvalue()
|
||||||
|
|
||||||
|
return wav_bytes
|
||||||
|
|
||||||
|
def create_mimic3_system(
|
||||||
|
voice: str=None, speaker: str=None, length_scale:float=None,
|
||||||
|
rate: float = None,
|
||||||
|
noise_scale:float=None, noise_w:float=None, use_cuda: bool=None,
|
||||||
|
voices_directories: list[str]=None, use_deterministic_compute:bool=None,
|
||||||
|
preload_voices:list[str]=None
|
||||||
|
) -> Mimic3TextToSpeechSystem:
|
||||||
|
|
||||||
|
mimic3 = Mimic3TextToSpeechSystem(
|
||||||
|
Mimic3Settings(
|
||||||
|
rate=rate,
|
||||||
|
voice=voice,
|
||||||
|
speaker=speaker,
|
||||||
|
length_scale=length_scale,
|
||||||
|
noise_scale=noise_scale,
|
||||||
|
noise_w=noise_w,
|
||||||
|
use_cuda=use_cuda,
|
||||||
|
voices_directories=voices_directories,
|
||||||
|
use_deterministic_compute=use_deterministic_compute,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
with mimic3:
|
||||||
|
if preload_voices:
|
||||||
|
# Ensure voices are preloaded
|
||||||
|
for voice_key in preload_voices:
|
||||||
|
mimic3.preload_voice(voice_key)
|
||||||
|
return mimic3
|
||||||
|
|
||||||
|
def play_wav_bytes(wav_bytes: bytes):
|
||||||
|
with tempfile.NamedTemporaryFile(mode="wb+", suffix=".wav") as wav_file:
|
||||||
|
wav_file.write(wav_bytes)
|
||||||
|
wav_file.seek(0)
|
||||||
|
|
||||||
|
filename = wav_file.name
|
||||||
|
wave_obj = sa.WaveObject.from_wave_file(filename)
|
||||||
|
play_obj = wave_obj.play()
|
||||||
|
play_obj.wait_done()
|
||||||
|
|
||||||
|
def say_words(words: str, mimic3: Mimic3TextToSpeechSystem, length_scale: float = None, ssml=False):
|
||||||
|
"""Thread handler for synthesis requests"""
|
||||||
|
try:
|
||||||
|
with mimic3:
|
||||||
|
params = TextToWavParams(
|
||||||
|
text=words, voice=mimic3.settings.voice,
|
||||||
|
noise_scale=mimic3.settings.noise_scale,
|
||||||
|
noise_w=mimic3.settings.noise_w,
|
||||||
|
ssml=ssml,
|
||||||
|
length_scale=length_scale if length_scale is not None else mimic3.settings.length_scale
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
play_wav_bytes(do_synthesis(params, mimic3))
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise(e)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue