Skip to content

Commit

Permalink
feat/g2p (#9)
Browse files Browse the repository at this point in the history
phonemes plugin, allows mouth for movements for all TTS in the mk1
  • Loading branch information
JarbasAl authored Jul 4, 2023
1 parent 0a76403 commit fe8c997
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
57 changes: 56 additions & 1 deletion ovos_tts_plugin_mimic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,69 @@
import subprocess
from distutils.spawn import find_executable
from os.path import join, isfile, expanduser

from ovos_plugin_manager.templates.g2p import Grapheme2PhonemePlugin, OutOfVocabulary
from ovos_plugin_manager.templates.tts import TTS, TTSValidator
from ovos_utils.configuration import get_xdg_base
from ovos_utils.configuration import read_mycroft_config
from ovos_utils.lang.visimes import VISIMES
from ovos_utils.xdg_utils import xdg_config_home


class MimicPhonemesPlugin(Grapheme2PhonemePlugin):

def __init__(self, config=None):
super().__init__(config)
self.mimic_bin = expanduser(self.config.get("binary") or
find_executable("mimic") or
"mimic")

@staticmethod
def parse_phonemes(phonemes, normalize=False):
"""Parse mimic phoneme string into a list of phone, duration pairs.
Arguments
phonemes (bytes): phoneme output from mimic
Returns:
(list) list of phoneme duration pairs
"""
phon_str = phonemes.decode()
pairs = phon_str.replace("pau", ".").split(' ')
phones = [pair.split(':') for pair in pairs if ':' in pair]
# remove silence at start/end/repeated
if normalize:
for idx, (pho, dur) in enumerate(phones):
next_pho = phones[idx + 1][0] if idx + 1 < len(phones) else None
if pho == ".":
if idx == 0 or idx == len(phones) - 1 or next_pho == ".":
phones[idx] = None
return [p for p in phones if p is not None]

def get_mimic_phonemes(self, sentence, normalize=True):
args = [self.mimic_bin, '-psdur', '-ssml', '-t', sentence, '-o', '/tmp/mimic.pho']
phonemes = subprocess.check_output(args)
return self.parse_phonemes(phonemes, normalize)

def get_arpa(self, word, lang, ignore_oov=True):
if lang.lower().startswith("en"):
return [p[0].upper() for p in self.get_mimic_phonemes(word)]
if ignore_oov:
return None
raise OutOfVocabulary

def utterance2visemes(self, utterance, lang="en", default_dur=0.4):
phonemes = self.get_mimic_phonemes(utterance, normalize=False)
return [(VISIMES.get(pho[0], '4'), float(pho[1])) for pho in phonemes]

@property
def available_languages(self):
"""Return languages supported by this G2P implementation in this state
This property should be overridden by the derived class to advertise
what languages that engine supports.
Returns:
set: supported languages
"""
return {"en"}


class MimicTTSPlugin(TTS):
"""Interface to Mimic TTS."""

Expand Down
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ def required(requirements_file):


PLUGIN_ENTRY_POINT = 'ovos-tts-plugin-mimic = ovos_tts_plugin_mimic:MimicTTSPlugin'
G2P_ENTRY_POINT = 'ovos-g2p-plugin-mimic = ovos_tts_plugin_mimic:MimicPhonemesPlugin'
SAMPLE_CONFIGS = 'ovos-tts-plugin-mimic.config = ovos_tts_plugin_mimic:MimicTTSPluginConfig'

setup(
Expand Down Expand Up @@ -83,5 +84,6 @@ def required(requirements_file):
],
keywords='mycroft plugin tts OVOS OpenVoiceOS',
entry_points={'mycroft.plugin.tts': PLUGIN_ENTRY_POINT,
'mycroft.plugin.tts.config': SAMPLE_CONFIGS}
'mycroft.plugin.tts.config': SAMPLE_CONFIGS,
'ovos.plugin.g2p': G2P_ENTRY_POINT}
)

0 comments on commit fe8c997

Please sign in to comment.