Use speaker names as well as ids
This commit is contained in:
parent
fb9cd71919
commit
3b730bfd9a
3 changed files with 64 additions and 19 deletions
|
|
@ -21,7 +21,23 @@ speaker = SSMLSpeaker(tts)
|
||||||
# ssml = '<speak><voice name="uk_UK/m-ailabs_low"><s><w>бажав</w></s></voice></speak>'
|
# ssml = '<speak><voice name="uk_UK/m-ailabs_low"><s><w>бажав</w></s></voice></speak>'
|
||||||
# ssml = '<speak><s><w>Hello</w><w>World</w></s></speak>'
|
# ssml = '<speak><s><w>Hello</w><w>World</w></s></speak>'
|
||||||
# ssml = '<speak><s>Hello world</s></speak>'
|
# ssml = '<speak><s>Hello world</s></speak>'
|
||||||
ssml = '<speak><s><voice name="el_GR/rapunzelina_low"><say-as interpret-as="characters">12</say-as></voice></s></speak>'
|
# ssml = '<speak><s><voice name="el_GR/rapunzelina_low"><say-as interpret-as="characters">12</say-as></voice></s></speak>'
|
||||||
|
ssml = '''
|
||||||
|
<speak>
|
||||||
|
<voice name="en_US/amy_low">
|
||||||
|
<s>
|
||||||
|
Today is 1/2.
|
||||||
|
<break time="1s" />
|
||||||
|
</s>
|
||||||
|
</voice>
|
||||||
|
|
||||||
|
|
||||||
|
<voice name="es_ES/carlfm_low">
|
||||||
|
<s>Soy el <say-as interpret-as="number" format="ordinal">1</say-as>.</s>
|
||||||
|
</voice>
|
||||||
|
</speak>
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
wav_file: wave.Wave_write = wave.open("out.wav", "wb")
|
wav_file: wave.Wave_write = wave.open("out.wav", "wb")
|
||||||
params_set = False
|
params_set = False
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ from opentts_abc import (
|
||||||
|
|
||||||
from mimic3_tts.config import TrainingConfig
|
from mimic3_tts.config import TrainingConfig
|
||||||
from mimic3_tts.utils import audio_float_to_int16
|
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
|
_DIR = Path(__file__).parent
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ class Mimic3Settings:
|
||||||
voice: typing.Optional[str] = None
|
voice: typing.Optional[str] = None
|
||||||
language: typing.Optional[str] = None
|
language: typing.Optional[str] = None
|
||||||
voices_directories: typing.Optional[typing.Iterable[typing.Union[str, Path]]] = 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
|
length_scale: float = 1.0
|
||||||
noise_scale: float = 0.667
|
noise_scale: float = 0.667
|
||||||
noise_w: float = 0.8
|
noise_w: float = 0.8
|
||||||
|
|
@ -81,26 +81,24 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
|
||||||
@voice.setter
|
@voice.setter
|
||||||
def voice(self, new_voice: str):
|
def voice(self, new_voice: str):
|
||||||
if new_voice != self.settings.voice:
|
if new_voice != self.settings.voice:
|
||||||
# Clear speaker id on voice change
|
# Clear speaker on voice change
|
||||||
self.speaker_id = None
|
self.speaker = None
|
||||||
|
|
||||||
self.settings.voice = new_voice
|
self.settings.voice = new_voice
|
||||||
|
|
||||||
if "#" in self.settings.voice:
|
if "#" in self.settings.voice:
|
||||||
# Split
|
# Split
|
||||||
voice, speaker_id_str = self.settings.voice.split("#", maxsplit=1)
|
voice, speaker = self.settings.voice.split("#", maxsplit=1)
|
||||||
self.settings.voice = voice
|
self.settings.voice = voice
|
||||||
|
self.speaker = speaker
|
||||||
# TODO: Use speaker map
|
|
||||||
self.speaker_id = int(speaker_id_str)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speaker_id(self) -> typing.Optional[int]:
|
def speaker(self) -> typing.Optional[SPEAKER_TYPE]:
|
||||||
return self.settings.speaker_id
|
return self.settings.speaker
|
||||||
|
|
||||||
@speaker_id.setter
|
@speaker.setter
|
||||||
def speaker_id(self, new_speaker_id: typing.Optional[int]):
|
def speaker(self, new_speaker: typing.Optional[SPEAKER_TYPE]):
|
||||||
self.settings.speaker_id = new_speaker_id
|
self.settings.speaker = new_speaker
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def language(self) -> str:
|
def language(self) -> str:
|
||||||
|
|
@ -154,12 +152,15 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
|
||||||
for sent_phonemes in voice.text_to_phonemes(text, text_language=text_language):
|
for sent_phonemes in voice.text_to_phonemes(text, text_language=text_language):
|
||||||
self._results.append(
|
self._results.append(
|
||||||
Mimic3Phonemes(
|
Mimic3Phonemes(
|
||||||
current_settings=deepcopy(self.settings), phonemes=sent_phonemes,
|
current_settings=deepcopy(self.settings),
|
||||||
|
phonemes=sent_phonemes,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _speak_sentence_phonemes(
|
def _speak_sentence_phonemes(
|
||||||
self, sent_phonemes, settings: typing.Optional[Mimic3Settings] = None,
|
self,
|
||||||
|
sent_phonemes,
|
||||||
|
settings: typing.Optional[Mimic3Settings] = None,
|
||||||
) -> AudioResult:
|
) -> AudioResult:
|
||||||
settings = settings or self.settings
|
settings = settings or self.settings
|
||||||
voice = self._get_or_load_voice(settings.voice or self.voice)
|
voice = self._get_or_load_voice(settings.voice or self.voice)
|
||||||
|
|
@ -169,7 +170,7 @@ class Mimic3TextToSpeechSystem(TextToSpeechSystem):
|
||||||
|
|
||||||
audio = voice.ids_to_audio(
|
audio = voice.ids_to_audio(
|
||||||
sent_phoneme_ids,
|
sent_phoneme_ids,
|
||||||
speaker=self.speaker_id,
|
speaker=self.speaker,
|
||||||
length_scale=settings.length_scale,
|
length_scale=settings.length_scale,
|
||||||
noise_scale=settings.noise_scale,
|
noise_scale=settings.noise_scale,
|
||||||
noise_w=settings.noise_w,
|
noise_w=settings.noise_w,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import csv
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
@ -24,6 +25,7 @@ PHONEME_MAP_TYPE = typing.Dict[PHONEME_TYPE, typing.List[PHONEME_TYPE]]
|
||||||
|
|
||||||
SPEAKER_NAME_TYPE = str
|
SPEAKER_NAME_TYPE = str
|
||||||
SPEAKER_ID_TYPE = int
|
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]
|
SPEAKER_MAP_TYPE = typing.Dict[SPEAKER_NAME_TYPE, SPEAKER_ID_TYPE]
|
||||||
|
|
||||||
DEFAULT_LANGUAGE = "en_US"
|
DEFAULT_LANGUAGE = "en_US"
|
||||||
|
|
@ -137,7 +139,19 @@ class Mimic3Voice(metaclass=ABCMeta):
|
||||||
speaker_id = 0
|
speaker_id = 0
|
||||||
if isinstance(speaker, SPEAKER_NAME_TYPE):
|
if isinstance(speaker, SPEAKER_NAME_TYPE):
|
||||||
if self.speaker_map:
|
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:
|
elif speaker is not None:
|
||||||
speaker_id = speaker
|
speaker_id = speaker
|
||||||
|
|
||||||
|
|
@ -198,7 +212,18 @@ class Mimic3Voice(metaclass=ABCMeta):
|
||||||
with open(phoneme_map_path, "r", encoding="utf-8") as map_file:
|
with open(phoneme_map_path, "r", encoding="utf-8") as map_file:
|
||||||
phoneme_map = phonemes2ids.utils.load_phoneme_map(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:
|
if config.phonemizer == Phonemizer.GRUUT:
|
||||||
return GruutVoice(
|
return GruutVoice(
|
||||||
|
|
@ -206,6 +231,7 @@ class Mimic3Voice(metaclass=ABCMeta):
|
||||||
onnx_model=onnx_model,
|
onnx_model=onnx_model,
|
||||||
phoneme_to_id=phoneme_to_id,
|
phoneme_to_id=phoneme_to_id,
|
||||||
phoneme_map=phoneme_map,
|
phoneme_map=phoneme_map,
|
||||||
|
speaker_map=speaker_map,
|
||||||
)
|
)
|
||||||
|
|
||||||
if config.phonemizer == Phonemizer.ESPEAK:
|
if config.phonemizer == Phonemizer.ESPEAK:
|
||||||
|
|
@ -214,6 +240,7 @@ class Mimic3Voice(metaclass=ABCMeta):
|
||||||
onnx_model=onnx_model,
|
onnx_model=onnx_model,
|
||||||
phoneme_to_id=phoneme_to_id,
|
phoneme_to_id=phoneme_to_id,
|
||||||
phoneme_map=phoneme_map,
|
phoneme_map=phoneme_map,
|
||||||
|
speaker_map=speaker_map,
|
||||||
)
|
)
|
||||||
if config.phonemizer == Phonemizer.SYMBOLS:
|
if config.phonemizer == Phonemizer.SYMBOLS:
|
||||||
return SymbolsVoice(
|
return SymbolsVoice(
|
||||||
|
|
@ -221,6 +248,7 @@ class Mimic3Voice(metaclass=ABCMeta):
|
||||||
onnx_model=onnx_model,
|
onnx_model=onnx_model,
|
||||||
phoneme_to_id=phoneme_to_id,
|
phoneme_to_id=phoneme_to_id,
|
||||||
phoneme_map=phoneme_map,
|
phoneme_map=phoneme_map,
|
||||||
|
speaker_map=speaker_map,
|
||||||
)
|
)
|
||||||
|
|
||||||
raise ValueError(f"Unsupported phonemizer: {config.phonemizer}")
|
raise ValueError(f"Unsupported phonemizer: {config.phonemizer}")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue