diff --git a/mimic3-tts/mimic3_tts/__main__.py b/mimic3-tts/mimic3_tts/__main__.py
index 72ed425..f145da0 100644
--- a/mimic3-tts/mimic3_tts/__main__.py
+++ b/mimic3-tts/mimic3_tts/__main__.py
@@ -21,7 +21,23 @@ speaker = SSMLSpeaker(tts)
# ssml = 'бажав'
# ssml = 'HelloWorld'
# ssml = 'Hello world'
-ssml = '12'
+# ssml = '12'
+ssml = '''
+
+
+
+ Today is 1/2.
+
+
+
+
+
+
+ Soy el 1.
+
+
+'''
+
wav_file: wave.Wave_write = wave.open("out.wav", "wb")
params_set = False
diff --git a/mimic3-tts/mimic3_tts/tts.py b/mimic3-tts/mimic3_tts/tts.py
index 7fb3009..e26bb06 100644
--- a/mimic3-tts/mimic3_tts/tts.py
+++ b/mimic3-tts/mimic3_tts/tts.py
@@ -27,7 +27,7 @@ from opentts_abc import (
from mimic3_tts.config import TrainingConfig
from mimic3_tts.utils import audio_float_to_int16
-from mimic3_tts.voice import Mimic3Voice
+from mimic3_tts.voice import Mimic3Voice, SPEAKER_TYPE
_DIR = Path(__file__).parent
@@ -47,7 +47,7 @@ class Mimic3Settings:
voice: typing.Optional[str] = None
language: typing.Optional[str] = None
voices_directories: typing.Optional[typing.Iterable[typing.Union[str, Path]]] = None
- speaker_id: typing.Optional[int] = None
+ speaker: typing.Optional[SPEAKER_TYPE] = None
length_scale: float = 1.0
noise_scale: float = 0.667
noise_w: float = 0.8
@@ -81,26 +81,24 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
@voice.setter
def voice(self, new_voice: str):
if new_voice != self.settings.voice:
- # Clear speaker id on voice change
- self.speaker_id = None
+ # Clear speaker on voice change
+ self.speaker = None
self.settings.voice = new_voice
if "#" in self.settings.voice:
# Split
- voice, speaker_id_str = self.settings.voice.split("#", maxsplit=1)
+ voice, speaker = self.settings.voice.split("#", maxsplit=1)
self.settings.voice = voice
-
- # TODO: Use speaker map
- self.speaker_id = int(speaker_id_str)
+ self.speaker = speaker
@property
- def speaker_id(self) -> typing.Optional[int]:
- return self.settings.speaker_id
+ def speaker(self) -> typing.Optional[SPEAKER_TYPE]:
+ return self.settings.speaker
- @speaker_id.setter
- def speaker_id(self, new_speaker_id: typing.Optional[int]):
- self.settings.speaker_id = new_speaker_id
+ @speaker.setter
+ def speaker(self, new_speaker: typing.Optional[SPEAKER_TYPE]):
+ self.settings.speaker = new_speaker
@property
def language(self) -> str:
@@ -154,12 +152,15 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
for sent_phonemes in voice.text_to_phonemes(text, text_language=text_language):
self._results.append(
Mimic3Phonemes(
- current_settings=deepcopy(self.settings), phonemes=sent_phonemes,
+ current_settings=deepcopy(self.settings),
+ phonemes=sent_phonemes,
)
)
def _speak_sentence_phonemes(
- self, sent_phonemes, settings: typing.Optional[Mimic3Settings] = None,
+ self,
+ sent_phonemes,
+ settings: typing.Optional[Mimic3Settings] = None,
) -> AudioResult:
settings = settings or self.settings
voice = self._get_or_load_voice(settings.voice or self.voice)
@@ -169,7 +170,7 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
audio = voice.ids_to_audio(
sent_phoneme_ids,
- speaker=self.speaker_id,
+ speaker=self.speaker,
length_scale=settings.length_scale,
noise_scale=settings.noise_scale,
noise_w=settings.noise_w,
diff --git a/mimic3-tts/mimic3_tts/voice.py b/mimic3-tts/mimic3_tts/voice.py
index 140e6ce..8483ab6 100644
--- a/mimic3-tts/mimic3_tts/voice.py
+++ b/mimic3-tts/mimic3_tts/voice.py
@@ -1,4 +1,5 @@
#!/usr/bin/env python3
+import csv
import itertools
import logging
import time
@@ -24,6 +25,7 @@ PHONEME_MAP_TYPE = typing.Dict[PHONEME_TYPE, typing.List[PHONEME_TYPE]]
SPEAKER_NAME_TYPE = str
SPEAKER_ID_TYPE = int
+SPEAKER_TYPE = typing.Union[SPEAKER_NAME_TYPE, SPEAKER_ID_TYPE]
SPEAKER_MAP_TYPE = typing.Dict[SPEAKER_NAME_TYPE, SPEAKER_ID_TYPE]
DEFAULT_LANGUAGE = "en_US"
@@ -137,7 +139,19 @@ class Mimic3Voice(metaclass=ABCMeta):
speaker_id = 0
if isinstance(speaker, SPEAKER_NAME_TYPE):
if self.speaker_map:
- speaker_id = self.speaker_map.get(speaker, speaker_id)
+ maybe_speaker_id = self.speaker_map.get(speaker)
+ if maybe_speaker_id is None:
+ try:
+ # Interpret as speaker id
+ speaker_id = int(speaker)
+ except ValueError:
+ _LOGGER.warning(
+ "Unable to find a speaker with the name '%s'. Falling back to first speaker.",
+ speaker,
+ )
+ pass
+ else:
+ speaker_id = maybe_speaker_id
elif speaker is not None:
speaker_id = speaker
@@ -198,7 +212,18 @@ class Mimic3Voice(metaclass=ABCMeta):
with open(phoneme_map_path, "r", encoding="utf-8") as map_file:
phoneme_map = phonemes2ids.utils.load_phoneme_map(map_file)
- # TODO: Load speaker map
+ # id -> speaker | alias | alias ...
+ speaker_map: typing.Optional[SPEAKER_MAP_TYPE] = None
+ speaker_map_path = voice_dir / "speaker_map.csv"
+ if speaker_map_path.is_file():
+ _LOGGER.debug("Loading speaker map from %s", speaker_map_path)
+ with open(speaker_map_path, "r", encoding="utf-8") as map_file:
+ reader = csv.reader(map_file, delimiter="|")
+ speaker_map = {}
+ for row in reader:
+ speaker_id = int(row[0])
+ for alias in row[1:]:
+ speaker_map[alias] = speaker_id
if config.phonemizer == Phonemizer.GRUUT:
return GruutVoice(
@@ -206,6 +231,7 @@ class Mimic3Voice(metaclass=ABCMeta):
onnx_model=onnx_model,
phoneme_to_id=phoneme_to_id,
phoneme_map=phoneme_map,
+ speaker_map=speaker_map,
)
if config.phonemizer == Phonemizer.ESPEAK:
@@ -214,6 +240,7 @@ class Mimic3Voice(metaclass=ABCMeta):
onnx_model=onnx_model,
phoneme_to_id=phoneme_to_id,
phoneme_map=phoneme_map,
+ speaker_map=speaker_map,
)
if config.phonemizer == Phonemizer.SYMBOLS:
return SymbolsVoice(
@@ -221,6 +248,7 @@ class Mimic3Voice(metaclass=ABCMeta):
onnx_model=onnx_model,
phoneme_to_id=phoneme_to_id,
phoneme_map=phoneme_map,
+ speaker_map=speaker_map,
)
raise ValueError(f"Unsupported phonemizer: {config.phonemizer}")