def __init__(self, language, logger=get_logger()): self.logger = logger self.logger.info('initializing backend %s-%s', self.name(), self.version()) profile = self._load_g2p_profile(language) self.tokenizer = segments.Tokenizer(profile=profile)
def __init__(self, language, logger=get_logger()): super(self.__class__, self).__init__(language, logger=logger) self.script = pkg_resources.resource_filename( pkg_resources.Requirement.parse('phonemizer'), 'phonemizer/share/phonemize.scm') self.logger.info('loaded {}'.format(self.script))
def __init__(self, language, use_sampa=False, language_switch='keep-flags', with_stress=False, logger=get_logger()): super(self.__class__, self).__init__(language, logger=logger) # adapt some command line option to the espeak version (for # phoneme separation and IPA output) version = self.version() self.sep = '--sep=_' if version == '1.48.03' or int(version.split('.')[1]) <= 47: self.sep = '' # pragma: nocover self.ipa = '--ipa=3' if self.is_espeak_ng(): # this is espeak-ng self.ipa = '-x --ipa' self._with_stress = with_stress if use_sampa is True: if not self.is_espeak_ng(): raise RuntimeError( # pragma: nocover 'sampa alphabet is only supported by espeak-ng backend, ' 'please install it instead of espeak') self.ipa = '-x --pho' # ensure the lang_switch argument is valid valid_lang_switch = [ 'keep-flags', 'remove-flags', 'remove-utterance'] if language_switch not in valid_lang_switch: raise RuntimeError( 'lang_switch argument "{}" invalid, must be in {}' .format(language_switch, ", ".join(valid_lang_switch))) self._lang_switch = language_switch self._lang_switch_list = []
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, language_switch='keep-flags', with_stress=False, logger=get_logger()): super().__init__(language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) self.logger.debug('espeak is %s', self.espeak_path()) # adapt some command line option to the espeak version (for # phoneme separation and IPA output) version = self.version() self.sep = '--sep=_' if version == '1.48.03' or version.split('.')[1] <= '47': self.sep = '' # pragma: nocover self.ipa = '--ipa=3' if self.is_espeak_ng(): # this is espeak-ng self.ipa = '-x --ipa' # ensure the lang_switch argument is valid valid_lang_switch = ['keep-flags', 'remove-flags', 'remove-utterance'] if language_switch not in valid_lang_switch: raise RuntimeError( 'lang_switch argument "{}" invalid, must be in {}'.format( language_switch, ", ".join(valid_lang_switch))) self._lang_switch = language_switch self._lang_switch_list = [] self._with_stress = with_stress
def get_logger(verbose, quiet): """Returns a configured logger""" verbosity = 'normal' if verbose: verbosity = 'verbose' elif quiet: verbosity = 'quiet' return logger.get_logger(verbosity=verbosity)
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): super(self.__class__, self).__init__( language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) self.script = get_package_resource('festival/phonemize.scm') self.logger.info('loaded {}'.format(self.script))
def main(): """Phonemize a text from command-line arguments""" args = parse_args() if args.version: print(version.version()) return # configure logging according to --verbose/--quiet options verbosity = 'normal' if args.verbose: verbosity = 'verbose' elif args.quiet: verbosity = 'quiet' log = logger.get_logger(verbosity=verbosity) # configure input as a readable stream streamin = args.input if isinstance(streamin, str): streamin = codecs.open(streamin, 'r', encoding='utf8') log.debug('reading from %s', streamin.name) # configure output as a writable stream streamout = args.output if isinstance(streamout, str): streamout = codecs.open(streamout, 'w', 'utf8') log.debug('writing to %s', streamout.name) # configure the separator for phonemes, syllables and words. sep = separator.Separator(phone=args.phone_separator, syllable=args.syllable_separator, word=args.word_separator) log.debug('separator is %s', sep) # load the input text (python2 optionnally needs an extra decode) text = streamin.read() try: text = text.decode('utf8') except (AttributeError, UnicodeEncodeError): pass # phonemize the input text out = phonemize.phonemize(text, language=args.language, backend=args.backend, separator=sep, strip=args.strip, with_stress=args.with_stress, use_sampa=args.sampa, language_switch=args.language_switch, njobs=args.njobs, logger=log) if len(out): streamout.write(out + '\n')
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): # will be initialized in _init_language() from super().__init__() self._tokenizer = None super().__init__(language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger)
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): self._espeak = EspeakWrapper() logger.debug('loaded %s', self._espeak.library_path) super().__init__(language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger)
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): self.logger = logger self.logger.info( 'initializing backend %s-%s', self.name(), self.version()) # load the grapheme to phoneme mapping profile = self._load_g2p_profile(language) self.tokenizer = segments.Tokenizer(profile=profile) # setup punctuation processing self.preserve_punctuation = preserve_punctuation self._punctuator = Punctuation(punctuation_marks)
def __init__(self, language, logger=get_logger()): # ensure the backend is installed on the system if not self.is_available(): raise RuntimeError( # pragma: nocover '{} not installed on your system'.format(self.name())) self.logger = logger self.logger.info('initializing backend %s-%s', self.name(), self.version()) # ensure the backend support the requested language if not self.is_supported_language(language): raise RuntimeError( 'language "{}" is not supported by the {} backend'.format( language, self.name())) self.language = language
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): super().__init__(language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) self.logger.debug('festival executable is %s', self.executable()) # the Scheme script to be send to festival script_file = get_package_resource('festival/phonemize.scm') with open(script_file, 'r') as fscript: self._script = fscript.read() self.logger.debug('loaded %s', script_file)
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, with_stress=False, tie=False, language_switch='keep-flags', words_mismatch='ignore', logger=get_logger()): super().__init__(language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) self._espeak.set_voice(language) self._with_stress = with_stress self._tie = self._init_tie(tie) self._lang_switch = get_language_switch_processor( language_switch, self.logger, self.language)
def __init__(self, language, punctuation_marks=Punctuation.default_marks(), preserve_punctuation=False, logger=get_logger()): # ensure the backend is installed on the system if not self.is_available(): raise RuntimeError( # pragma: nocover '{} not installed on your system'.format(self.name())) self._logger = logger self._logger.info('initializing backend %s-%s', self.name(), '.'.join(str(v) for v in self.version())) # ensure the backend support the requested language self._language = self._init_language(language) # setup punctuation processing self._preserve_punctuation = preserve_punctuation self._punctuator = Punctuation(punctuation_marks)
def __init__(self, language, logger=get_logger()): super().__init__(language, logger=logger) self._espeak.set_voice(language)
def __init__(self, language, logger=get_logger()): super().__init__(language, logger=logger) self.logger.debug('espeak is %s', self.espeak_path())
def phonemize(text, language='en-us', backend='festival', separator=default_separator, strip=False, with_stress=False, use_sampa=False, language_switch='keep-flags', njobs=1, logger=get_logger()): """Multilingual text to phonemes converter Return a phonemized version of an input `text`, given its `language` and a phonemization `backend`. Parameters ---------- text (str or list of str): The text to be phonemized. Any empty line will be ignored. If `text` is an str, it can be multiline (lines being separated by \n). If `text` is a list, each element is considered as a separated line. Each line is considered as a text utterance. language (str): The language code of the input text, must be supported by the backend. If `backend` is 'segments', the language can be a file with a grapheme to phoneme mapping. backend (str): The software backend to use for phonemization, must be 'festival' (US English only is supported, coded 'en-us'), 'espeak' or 'segments'. separator (Separator): string separators between phonemes, syllables and words, default to separator.default_separator. strip (bool): If True, don't output the last word and phone separators of a token, default to False. with_stress (bool): This option is only valid for the espeak/espeak-ng backend. When True the stresses on phonemes are present (stresses characters are ˈ'ˌ). When False stresses are removed. Default to False. use_sampa (bool): Use the 'sampa' phonetic alphabet (Speech Assessment Methods Phonetic Alphabet) instead of 'ipa' (International Phonetic Alphabet). This option is only valid for the 'espeak-ng' backend. Default to False. language_switch (str) : espeak can pronounce some words in another language (typically English) when phonemizing a text. This option setups the policy to use when such a language switch occurs. Three values are available: 'keep-flags' (the default), 'remove-flags' or 'remove-utterance'. The 'keep-flags' policy keeps the language switching flags, for example (en) or (jp), in the output. The 'remove-flags' policy removes them and the 'remove-utterance' policy removes the whole line of text including a language switch. njobs (int): The number of parallel jobs to launch. The input text is split in `njobs` parts, phonemized on parallel instances of the backend and the outputs are finally collapsed. logger (logging.Logger): the logging instance where to send messages. If not specified, use the default system logger. Returns ------- phonemized text (str or list of str) : The input `text` phonemized for the given `language` and `backend`. The returned value has the same type of the input text (either a list or a string). Raises ------ RuntimeError If the `backend` is not valid or is valid but not installed, if the `language` is not supported by the `backend`, if `use_sampa`, `with_stress` or `language_switch` are used but the backend is not 'espeak-ng'. """ # ensure the backend is either espeak, festival or segments if backend not in ('espeak', 'festival', 'segments'): raise RuntimeError( '{} is not a supported backend, choose in {}.'.format( backend, ', '.join(('espeak', 'festival', 'segments')))) # ensure the phonetic alphabet is valid if use_sampa is True: if backend == 'espeak' and not EspeakBackend.is_espeak_ng(): raise RuntimeError( # pragma: nocover 'sampa alphabet is not supported by espeak, ' 'please install espeak-ng') if backend != 'espeak': raise RuntimeError( 'sampa alphabet is only supported by espeak backend') # with_stress option only valid for espeak if with_stress and backend != 'espeak': raise RuntimeError( 'the "with_stress" option is available for espeak backend only, ' 'but you are using {} backend'.format(backend)) # language_switch option only valid for espeak if language_switch != 'keep-flags' and backend != 'espeak': raise RuntimeError( 'the "language_switch" option is available for espeak backend ' 'only, but you are using {} backend'.format(backend)) # instanciate the requested backend for the given language (raises # a RuntimeError if the language is not supported). backends = { b.name(): b for b in (EspeakBackend, FestivalBackend, SegmentsBackend) } if backend == 'espeak': phonemizer = backends[backend](language, with_stress=with_stress, use_sampa=use_sampa, language_switch=language_switch, logger=logger) else: phonemizer = backends[backend](language, logger=logger) # phonemize the input text with the backend return phonemizer.phonemize(text, separator=separator, strip=strip, njobs=njobs)
def phonemize( # pylint: disable=too-many-arguments text, language='en-us', backend='espeak', separator=default_separator, strip=False, prepend_text=False, preserve_punctuation=False, punctuation_marks=Punctuation.default_marks(), with_stress=False, tie=False, language_switch='keep-flags', words_mismatch='ignore', njobs=1, logger=get_logger()): """Multilingual text to phonemes converter Return a phonemized version of an input `text`, given its `language` and a phonemization `backend`. Note ---- To improve the processing speed it is better to minimize the calls to this function: provide the input text as a list and call phonemize() a single time is much more efficient than calling it on each element of the list. Indeed the initialization of the phonemization backend can be expensive, especially for espeak. In one exemple, Do this: >>> text = [line1, line2, ...] >>> phonemize(text, ...) Not this: >>> for line in text: >>> phonemize(line, ...) Parameters ---------- text (str or list of str): The text to be phonemized. Any empty line will be ignored. If `text` is an str, it can be multiline (lines being separated by \n). If `text` is a list, each element is considered as a separated line. Each line is considered as a text utterance. language (str): The language code of the input text, must be supported by the backend. If `backend` is 'segments', the language can be a file with a grapheme to phoneme mapping. backend (str, optional): The software backend to use for phonemization, must be 'festival' (US English only is supported, coded 'en-us'), 'espeak', 'espeak-mbrola' or 'segments'. separator (Separator): string separators between phonemes, syllables and words, default to separator.default_separator. Syllable separator is considered only for the festival backend. Word separator is ignored by the 'espeak-mbrola' backend. Initialize it as follows: >>> from phonemizer.separator import Separator >>> separator = Separator(phone='-', word=' ') strip (bool, optional): If True, don't output the last word and phone separators of a token, default to False. prepend_text (bool, optional): When True, returns a pair (input utterance, phonemized utterance) for each line of the input text. When False, returns only the phonemized utterances. Default to False preserve_punctuation (bool, optional): When True, will keep the punctuation in the phonemized output. Not supported by the 'espeak-mbrola' backend. Default to False and remove all the punctuation. punctuation_marks (str, optional): The punctuation marks to consider when dealing with punctuation, either for removal or preservation. Default to Punctuation.default_marks(). with_stress (bool, optional): This option is only valid for the 'espeak' backend. When True the stresses on phonemes are present (stresses characters are ˈ'ˌ). When False stresses are removed. Default to False. tie (bool or char, optional): This option is only valid for the 'espeak' backend with espeak>=1.49. It is incompatible with phone separator. When not False, use a tie character within multi-letter phoneme names. When True, the char 'U+361' is used (as in d͡ʒ), 'z' means ZWJ character, default to False. language_switch (str, optional): Espeak can output some words in another language (typically English) when phonemizing a text. This option setups the policy to use when such a language switch occurs. Three values are available: 'keep-flags' (the default), 'remove-flags' or 'remove-utterance'. The 'keep-flags' policy keeps the language switching flags, for example "(en) or (jp)", in the output. The 'remove-flags' policy removes them and the 'remove-utterance' policy removes the whole line of text including a language switch. This option is only valid for the 'espeak' backend. words_mismatch (str, optional): Espeak can join two consecutive words or drop some words, yielding a word count mismatch between orthographic and phonemized text. This option setups the policy to use when such a words count mismatch occurs. Three values are available: 'ignore' (the default) which do nothing, 'warn' which issue a warning for each mismatched line, and 'remove' which remove the mismatched lines from the output. njobs (int): The number of parallel jobs to launch. The input text is split in `njobs` parts, phonemized on parallel instances of the backend and the outputs are finally collapsed. logger (logging.Logger): the logging instance where to send messages. If not specified, use the default system logger. Returns ------- phonemized text (str or list of str) : The input `text` phonemized for the given `language` and `backend`. The returned value has the same type of the input text (either a list or a string), excepted if `prepend_input` is True where the output is forced as a list of pairs (input_text, phonemized text). Raises ------ RuntimeError if the `backend` is not valid or is valid but not installed, if the `language` is not supported by the `backend`, if any incompatible options are used. """ # ensure we are using a compatible Python version if sys.version_info < (3, 6): # pragma: nocover logger.error( 'Your are using python-%s which is unsupported by the phonemizer, ' 'please update to python>=3.6', ".".join(sys.version_info)) # ensure the arguments are valid _check_arguments(backend, with_stress, tie, separator, language_switch, words_mismatch) # preserve_punctuation and word separator not valid for espeak-mbrola if backend == 'espeak-mbrola' and preserve_punctuation: logger.warning('espeak-mbrola backend cannot preserve punctuation') if backend == 'espeak-mbrola' and separator.word: logger.warning('espeak-mbrola backend cannot preserve word separation') # initialize the phonemization backend if backend == 'espeak': phonemizer = BACKENDS[backend]( language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, with_stress=with_stress, tie=tie, language_switch=language_switch, words_mismatch=words_mismatch, logger=logger) elif backend == 'espeak-mbrola': phonemizer = BACKENDS[backend](language, logger=logger) else: # festival or segments phonemizer = BACKENDS[backend]( language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) # do the phonemization return _phonemize(phonemizer, text, separator, strip, njobs, prepend_text)
def phonemize( text, language='en-us', backend='festival', separator=default_separator, strip=False, preserve_punctuation=False, punctuation_marks=Punctuation.default_marks(), with_stress=False, language_switch='keep-flags', njobs=1, logger=get_logger()): """Multilingual text to phonemes converter Return a phonemized version of an input `text`, given its `language` and a phonemization `backend`. Parameters ---------- text (str or list of str): The text to be phonemized. Any empty line will be ignored. If `text` is an str, it can be multiline (lines being separated by \n). If `text` is a list, each element is considered as a separated line. Each line is considered as a text utterance. language (str): The language code of the input text, must be supported by the backend. If `backend` is 'segments', the language can be a file with a grapheme to phoneme mapping. backend (str): The software backend to use for phonemization, must be 'festival' (US English only is supported, coded 'en-us'), 'espeak', 'espeak-mbrola' or 'segments'. separator (Separator): string separators between phonemes, syllables and words, default to separator.default_separator. Syllable separator is considered only for the festival backend. Word separator is ignored by the 'espeak-mbrola' backend. strip (bool): If True, don't output the last word and phone separators of a token, default to False. preserve_punctuation (bool): When True, will keep the punctuation in the phonemized output. Not supportyed by the 'espeak-mbrola' backend. Default to False and remove all the punctuation. punctuation_marks (str): The punctuation marks to consider when dealing with punctuation. Default to Punctuation.default_marks(). with_stress (bool): This option is only valid for the 'espeak' backend. When True the stresses on phonemes are present (stresses characters are ˈ'ˌ). When False stresses are removed. Default to False. language_switch (str): Espeak can output some words in another language (typically English) when phonemizing a text. This option setups the policy to use when such a language switch occurs. Three values are available: 'keep-flags' (the default), 'remove-flags' or 'remove-utterance'. The 'keep-flags' policy keeps the language switching flags, for example (en) or (jp), in the output. The 'remove-flags' policy removes them and the 'remove-utterance' policy removes the whole line of text including a language switch. This option is only valid for the 'espeak' backend. njobs (int): The number of parallel jobs to launch. The input text is split in `njobs` parts, phonemized on parallel instances of the backend and the outputs are finally collapsed. logger (logging.Logger): the logging instance where to send messages. If not specified, use the default system logger. Returns ------- phonemized text (str or list of str) : The input `text` phonemized for the given `language` and `backend`. The returned value has the same type of the input text (either a list or a string). Raises ------ RuntimeError if the `backend` is not valid or is valid but not installed, if the `language` is not supported by the `backend`, if with_stress` or `language_switch` are used but the backend is not 'espeak'. """ # ensure the backend is either espeak, festival or segments if backend not in ('espeak', 'espeak-mbrola', 'festival', 'segments'): raise RuntimeError( '{} is not a supported backend, choose in {}.' .format(backend, ', '.join( ('espeak', 'espeak-mbrola', 'festival', 'segments')))) # with_stress option only valid for espeak if with_stress and backend != 'espeak': raise RuntimeError( 'the "with_stress" option is available for espeak backend only, ' 'but you are using {} backend'.format(backend)) # language_switch option only valid for espeak if ( language_switch != 'keep-flags' and backend not in ('espeak', 'espeak-mbrola') ): raise RuntimeError( 'the "language_switch" option is available for espeak backend ' 'only, but you are using {} backend'.format(backend)) # preserve_punctuation and word separator not valid for espeak-mbrola if backend == 'espeak-mbrola' and preserve_punctuation: logger.warning('espeak-mbrola backend cannot preserve punctuation') if backend == 'espeak-mbrola' and separator.word: logger.warning('espeak-mbrola backend cannot preserve word separation') # python2 needs additional utf8 encoding if sys.version_info[0] == 2: # pragma: nocover logger.warning( 'Your are using python2 but unsupported by the phonemizer, ' 'please update to python>=3.6') # instanciate the requested backend for the given language (raises # a RuntimeError if the language is not supported). backends = {b.name(): b for b in ( EspeakBackend, FestivalBackend, SegmentsBackend, EspeakMbrolaBackend)} if backend == 'espeak': phonemizer = backends[backend]( language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, with_stress=with_stress, language_switch=language_switch, logger=logger) elif backend == 'espeak-mbrola': phonemizer = backends[backend]( language, logger=logger) else: # festival or segments phonemizer = backends[backend]( language, punctuation_marks=punctuation_marks, preserve_punctuation=preserve_punctuation, logger=logger) # phonemize the input text return phonemizer.phonemize( text, separator=separator, strip=strip, njobs=njobs)
def main(): """Phonemize a text from command-line arguments""" args = parse_args() # setup a custom path to espeak and festival if required (this must be done # before generating the version message) if args.espeak_path: EspeakBackend.set_espeak_path(args.espeak_path) if args.festival_path: FestivalBackend.set_festival_path(args.festival_path) # display version information and exit if args.version: print(version.version()) return # list supported languages and exit if args.list_languages: backends = (['festival', 'segments', 'espeak', 'espeak-mbrola'] if not args.backend else [args.backend]) for backend in backends: print(f'supported languages for {backend} are:\n' + '\n'.join(f'\t{k}\t->\t{v}' for k, v in sorted( BACKENDS_MAP[backend].supported_languages().items()))) return # set default backend as espeak if not specified args.backend = args.backend or 'espeak' # configure logging according to --verbose/--quiet options verbosity = 'normal' if args.verbose: verbosity = 'verbose' elif args.quiet: verbosity = 'quiet' log = logger.get_logger(verbosity=verbosity) # configure input as a readable stream streamin = args.input if isinstance(streamin, str): streamin = codecs.open(streamin, 'r', encoding='utf8') log.debug('reading from %s', streamin.name) # configure output as a writable stream streamout = args.output if isinstance(streamout, str): streamout = codecs.open(streamout, 'w', 'utf8') log.debug('writing to %s', streamout.name) # configure the separator for phonemes, syllables and words. if args.backend == 'espeak-mbrola': log.debug('using espeak-mbrola backend: ignoring word separator') sep = separator.Separator(phone=args.phone_separator, syllable=None, word=None) else: sep = separator.Separator(phone=args.phone_separator, syllable=args.syllable_separator, word=args.word_separator) log.debug('separator is %s', sep) text = [line.strip() for line in streamin] # phonemize the input text out = phonemize(text, language=args.language, backend=args.backend, separator=sep, strip=args.strip, preserve_punctuation=args.preserve_punctuation, punctuation_marks=args.punctuation_marks, with_stress=args.with_stress, language_switch=args.language_switch, njobs=args.njobs, logger=log) if out: streamout.write('\n'.join(out) + '\n')
def test_logger(): with pytest.raises(RuntimeError): logger.get_logger(verbosity=1)