fighter-programmer/voicegen
0
1""" from https://github.com/keithito/tacotron """2 3'''4Cleaners are transformations that run over the input text at both training and eval time.5 6Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners"7hyperparameter. Some cleaners are English-specific. You'll typically want to use:8 1. "english_cleaners" for English text9 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using10 the Unidecode library (https://pypi.python.org/pypi/Unidecode)11 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update12 the symbols in symbols.py to match your data).13'''14 15 16# Regular expression matching whitespace:17 18 19import re20import inflect21from unidecode import unidecode22import eng_to_ipa as ipa23_inflect = inflect.engine()24_comma_number_re = re.compile(r'([0-9][0-9\,]+[0-9])')25_decimal_number_re = re.compile(r'([0-9]+\.[0-9]+)')26_pounds_re = re.compile(r'£([0-9\,]*[0-9]+)')27_dollars_re = re.compile(r'\$([0-9\.\,]*[0-9]+)')28_ordinal_re = re.compile(r'[0-9]+(st|nd|rd|th)')29_number_re = re.compile(r'[0-9]+')30 31# List of (regular expression, replacement) pairs for abbreviations:32_abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [33 ('mrs', 'misess'),34 ('mr', 'mister'),35 ('dr', 'doctor'),36 ('st', 'saint'),37 ('co', 'company'),38 ('jr', 'junior'),39 ('maj', 'major'),40 ('gen', 'general'),41 ('drs', 'doctors'),42 ('rev', 'reverend'),43 ('lt', 'lieutenant'),44 ('hon', 'honorable'),45 ('sgt', 'sergeant'),46 ('capt', 'captain'),47 ('esq', 'esquire'),48 ('ltd', 'limited'),49 ('col', 'colonel'),50 ('ft', 'fort'),51]]52 53 54# List of (ipa, lazy ipa) pairs:55_lazy_ipa = [(re.compile('%s' % x[0]), x[1]) for x in [56 ('r', 'ɹ'),57 ('æ', 'e'),58 ('ɑ', 'a'),59 ('ɔ', 'o'),60 ('ð', 'z'),61 ('θ', 's'),62 ('ɛ', 'e'),63 ('ɪ', 'i'),64 ('ʊ', 'u'),65 ('ʒ', 'ʥ'),66 ('ʤ', 'ʥ'),67 ('ˈ', '↓'),68]]69 70# List of (ipa, lazy ipa2) pairs:71_lazy_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [72 ('r', 'ɹ'),73 ('ð', 'z'),74 ('θ', 's'),75 ('ʒ', 'ʑ'),76 ('ʤ', 'dʑ'),77 ('ˈ', '↓'),78]]79 80# List of (ipa, ipa2) pairs81_ipa_to_ipa2 = [(re.compile('%s' % x[0]), x[1]) for x in [82 ('r', 'ɹ'),83 ('ʤ', 'dʒ'),84 ('ʧ', 'tʃ')85]]86 87 88def expand_abbreviations(text):89 for regex, replacement in _abbreviations:90 text = re.sub(regex, replacement, text)91 return text92 93 94def collapse_whitespace(text):95 return re.sub(r'\s+', ' ', text)96 97 98def _remove_commas(m):99 return m.group(1).replace(',', '')100 101 102def _expand_decimal_point(m):103 return m.group(1).replace('.', ' point ')104 105 106def _expand_dollars(m):107 match = m.group(1)108 parts = match.split('.')109 if len(parts) > 2:110 return match + ' dollars' # Unexpected format111 dollars = int(parts[0]) if parts[0] else 0112 cents = int(parts[1]) if len(parts) > 1 and parts[1] else 0113 if dollars and cents:114 dollar_unit = 'dollar' if dollars == 1 else 'dollars'115 cent_unit = 'cent' if cents == 1 else 'cents'116 return '%s %s, %s %s' % (dollars, dollar_unit, cents, cent_unit)117 elif dollars:118 dollar_unit = 'dollar' if dollars == 1 else 'dollars'119 return '%s %s' % (dollars, dollar_unit)120 elif cents:121 cent_unit = 'cent' if cents == 1 else 'cents'122 return '%s %s' % (cents, cent_unit)123 else:124 return 'zero dollars'125 126 127def _expand_ordinal(m):128 return _inflect.number_to_words(m.group(0))129 130 131def _expand_number(m):132 num = int(m.group(0))133 if num > 1000 and num < 3000:134 if num == 2000:135 return 'two thousand'136 elif num > 2000 and num < 2010:137 return 'two thousand ' + _inflect.number_to_words(num % 100)138 elif num % 100 == 0:139 return _inflect.number_to_words(num // 100) + ' hundred'140 else:141 return _inflect.number_to_words(num, andword='', zero='oh', group=2).replace(', ', ' ')142 else:143 return _inflect.number_to_words(num, andword='')144 145 146def normalize_numbers(text):147 text = re.sub(_comma_number_re, _remove_commas, text)148 text = re.sub(_pounds_re, r'\1 pounds', text)149 text = re.sub(_dollars_re, _expand_dollars, text)150 text = re.sub(_decimal_number_re, _expand_decimal_point, text)151 text = re.sub(_ordinal_re, _expand_ordinal, text)152 text = re.sub(_number_re, _expand_number, text)153 return text154 155 156def mark_dark_l(text):157 return re.sub(r'l([^aeiouæɑɔəɛɪʊ ]*(?: |$))', lambda x: 'ɫ'+x.group(1), text)158 159 160def english_to_ipa(text):161 text = unidecode(text).lower()162 text = expand_abbreviations(text)163 text = normalize_numbers(text)164 phonemes = ipa.convert(text)165 phonemes = collapse_whitespace(phonemes)166 return phonemes167 168 169def english_to_lazy_ipa(text):170 text = english_to_ipa(text)171 for regex, replacement in _lazy_ipa:172 text = re.sub(regex, replacement, text)173 return text174 175 176def english_to_ipa2(text):177 text = english_to_ipa(text)178 text = mark_dark_l(text)179 for regex, replacement in _ipa_to_ipa2:180 text = re.sub(regex, replacement, text)181 return text.replace('...', '…')182 183 184def english_to_lazy_ipa2(text):185 text = english_to_ipa(text)186 for regex, replacement in _lazy_ipa2:187 text = re.sub(regex, replacement, text)188 return text189 