import os
from os.path import exists
import pkg_resources
import six
from tqdm.auto import tqdm
if six.PY2:
from urllib import urlretrieve
else:
from urllib.request import urlretrieve
import tarfile
try:
from .version import __version__ # NOQA
except ImportError:
raise ImportError("BUG: version.py doesn't exist. Please file a bug report.")
from .htsengine import HTSEngine
from .openjtalk import OpenJTalk
# Dictionary directory
# defaults to the package directory where the dictionary will be automatically downloaded
OPEN_JTALK_DICT_DIR = os.environ.get(
"OPEN_JTALK_DICT_DIR",
pkg_resources.resource_filename(__name__, "open_jtalk_dic_utf_8-1.11"),
).encode("utf-8")
_dict_download_url = "https://github.com/r9y9/open_jtalk/releases/download/v1.11.1"
_DICT_URL = f"{_dict_download_url}/open_jtalk_dic_utf_8-1.11.tar.gz"
# Default mei_normal.voice for HMM-based TTS
DEFAULT_HTS_VOICE = pkg_resources.resource_filename(
__name__, "htsvoice/mei_normal.htsvoice"
).encode("utf-8")
# Global instance of OpenJTalk
_global_jtalk = None
# Global instance of HTSEngine
# mei_normal.voice is used as default
_global_htsengine = None
# https://github.com/tqdm/tqdm#hooks-and-callbacks
class _TqdmUpTo(tqdm): # type: ignore
def update_to(self, b=1, bsize=1, tsize=None):
if tsize is not None:
self.total = tsize
return self.update(b * bsize - self.n)
def _extract_dic():
global OPEN_JTALK_DICT_DIR
filename = pkg_resources.resource_filename(__name__, "dic.tar.gz")
print('Downloading: "{}"'.format(_DICT_URL))
with _TqdmUpTo(
unit="B",
unit_scale=True,
unit_divisor=1024,
miniters=1,
desc="dic.tar.gz",
) as t: # all optional kwargs
urlretrieve(_DICT_URL, filename, reporthook=t.update_to)
t.total = t.n
print("Extracting tar file {}".format(filename))
with tarfile.open(filename, mode="r|gz") as f:
f.extractall(path=pkg_resources.resource_filename(__name__, ""))
OPEN_JTALK_DICT_DIR = pkg_resources.resource_filename(
__name__, "open_jtalk_dic_utf_8-1.11"
).encode("utf-8")
os.remove(filename)
def _lazy_init():
if not exists(OPEN_JTALK_DICT_DIR):
_extract_dic()
[docs]def g2p(*args, **kwargs):
"""Grapheme-to-phoeneme (G2P) conversion
This is just a convenient wrapper around `run_frontend`.
Args:
text (str): Unicode Japanese text.
kana (bool): If True, returns the pronunciation in katakana, otherwise in phone.
Default is False.
join (bool): If True, concatenate phones or katakana's into a single string.
Default is True.
Returns:
str or list: G2P result in 1) str if join is True 2) list if join is False.
"""
global _global_jtalk
if _global_jtalk is None:
_lazy_init()
_global_jtalk = OpenJTalk(dn_mecab=OPEN_JTALK_DICT_DIR)
return _global_jtalk.g2p(*args, **kwargs)
[docs]def synthesize(labels, speed=1.0, half_tone=0.0):
"""Run OpenJTalk's speech synthesis backend
Args:
labels (list): Full-context labels
speed (float): speech speed rate. Default is 1.0.
half_tone (float): additional half-tone. Default is 0.
Returns:
np.ndarray: speech waveform (dtype: np.float64)
int: sampling frequency (defualt: 48000)
"""
if isinstance(labels, tuple) and len(labels) == 2:
labels = labels[1]
global _global_htsengine
if _global_htsengine is None:
_global_htsengine = HTSEngine(DEFAULT_HTS_VOICE)
sr = _global_htsengine.get_sampling_frequency()
_global_htsengine.set_speed(speed)
_global_htsengine.add_half_tone(half_tone)
return _global_htsengine.synthesize(labels), sr
[docs]def tts(text, speed=1.0, half_tone=0.0):
"""Text-to-speech
Args:
text (str): Input text
speed (float): speech speed rate. Default is 1.0.
half_tone (float): additional half-tone. Default is 0.
Returns:
np.ndarray: speech waveform (dtype: np.float64)
int: sampling frequency (defualt: 48000)
"""
return synthesize(extract_fullcontext(text), speed, half_tone)
[docs]def run_frontend(text, verbose=0):
"""Run OpenJTalk's text processing frontend
Args:
text (str): Unicode Japanese text.
verbose (int): Verbosity. Default is 0.
Returns:
tuple: Pair of 1) NJD_print and 2) JPCommon_make_label.
The latter is the full-context labels in HTS-style format.
"""
global _global_jtalk
if _global_jtalk is None:
_lazy_init()
_global_jtalk = OpenJTalk(dn_mecab=OPEN_JTALK_DICT_DIR)
return _global_jtalk.run_frontend(text, verbose)