예제 #1
0
def test_espeak():
    text = 'hello, world!'
    expected1 = 'həloʊ wɜːld'
    expected2 = 'həloʊ, wɜːld!'
    expected3 = 'həloʊ wɜːld '
    expected4 = 'həloʊ, wɜːld!'

    out1 = EspeakBackend('en-us',
                         preserve_punctuation=False).phonemize([text],
                                                               strip=True)[0]
    assert out1 == expected1

    out2 = EspeakBackend('en-us',
                         preserve_punctuation=True).phonemize([text],
                                                              strip=True)[0]
    assert out2 == expected2

    out3 = EspeakBackend('en-us',
                         preserve_punctuation=False).phonemize([text],
                                                               strip=False)[0]
    assert out3 == expected3

    out4 = EspeakBackend('en-us',
                         preserve_punctuation=True).phonemize([text],
                                                              strip=False)[0]
    assert out4 == expected4
예제 #2
0
def test_french():
    backend = EspeakBackend('fr-fr')
    text = u'bonjour le monde'
    sep = separator.Separator(word=';eword ', syllable=None, phone=' ')
    expected = [u'b ɔ̃ ʒ u ʁ ;eword l ə ;eword m ɔ̃ d ;eword ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected
예제 #3
0
def test_french():
    backend = EspeakBackend('fr-fr')
    text = u'bonjour le monde'
    sep = separator.Separator(word=';eword ', syllable=None, phone=' ')
    expected = [u'b ɔ̃ ʒ u ʁ ;eword l ə- ;eword m ɔ̃ d ;eword ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected
예제 #4
0
def version():
    """Return version information for front and backends"""
    # version of the phonemizer
    version = ('phonemizer-' +
               pkg_resources.get_distribution('phonemizer').version)

    # for each backend, check if it is available or not. If so get its version
    available = []
    unavailable = []

    if EspeakBackend.is_available():
        available.append('espeak-' +
                         ('ng-' if EspeakBackend.is_espeak_ng() else '') +
                         EspeakBackend.version())
    else:  # pragma: nocover
        unavailable.append('espeak')

    if FestivalBackend.is_available():
        available.append('festival-' + FestivalBackend.version())
    else:  # pragma: nocover
        unavailable.append('festival')

    if SegmentsBackend.is_available():
        available.append('segments-' + SegmentsBackend.version())
    else:  # pragma: nocover
        unavailable.append('segments')

    # resumes the backends status in the final version string
    if available:
        version += '\navailable backends: ' + ', '.join(available)
    if unavailable:  # pragma: nocover
        version += '\nuninstalled backends: ' + ', '.join(unavailable)

    return version
def test_no_switch(policy, caplog):
    text = ["j'aime l'anglais", "tu parles le français"]
    backend = EspeakBackend('fr-fr', language_switch=policy)
    out = backend.phonemize(text, separator=Separator(), strip=True)
    assert out == ['ʒɛm lɑ̃ɡlɛ', 'ty paʁl lə fʁɑ̃sɛ']

    messages = [msg[2] for msg in caplog.record_tuples]
    assert not messages
예제 #6
0
def test_bad_text():
    backend = EspeakBackend('en-us')
    text = 'hello world'
    with pytest.raises(RuntimeError) as err:
        backend.phonemize(text, default_separator, True)
    assert 'input text to phonemize() is str' in str(err)

    assert backend.phonemize([text], default_separator,
                             True) == ['həloʊ wɜːld']
예제 #7
0
파일: main.py 프로젝트: tronin/phonemizer
def version():
    """Return version information for front and backends"""
    version = ('phonemizer-' +
               pkg_resources.get_distribution('phonemizer').version)

    return version + '\navailable backends: ' + ', '.join(
        ('festival-' + FestivalBackend.version(),
         ('espeak-' + ('ng-' if EspeakBackend.is_espeak_ng() else '') +
          EspeakBackend.version()), 'segments-' + SegmentsBackend.version()))
예제 #8
0
파일: main.py 프로젝트: bootphon/phonemizer
def version():
    """Return version information for front and backends"""
    version = ('phonemizer-'
               + pkg_resources.get_distribution('phonemizer').version)

    return version + '\navailable backends: ' + ', '.join(
        ('festival-' + FestivalBackend.version(),
         ('espeak-' + ('ng-' if EspeakBackend.is_espeak_ng() else '')
          + EspeakBackend.version()),
         'segments-' + SegmentsBackend.version()))
예제 #9
0
def test_tie_simple(caplog, tie, expected):
    backend = EspeakBackend('en-us', tie=tie)
    assert backend.phonemize(['Jackie Chan'],
                             separator=Separator(word=' ',
                                                 phone='_'))[0] == expected

    if tie:
        messages = [msg[2] for msg in caplog.record_tuples]
        assert (
            'cannot use ties AND phone separation, ignoring phone separator'
            in messages)
예제 #10
0
def test_arabic():
    backend = EspeakBackend('ar')
    text = u'السلام عليكم'
    sep = separator.Separator()
    # Arabic seems to have changed starting at espeak-ng-1.49.3
    if tuple(EspeakBackend.version().split('.')) >= ('1', '49', '3'):
        expected = [u'ʔassalaːm ʕliːkm ']
    else:
        expected = [u'ʔassalaam ʕaliijkum ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected
예제 #11
0
def test_arabic():
    backend = EspeakBackend('ar')
    text = u'السلام عليكم'
    sep = separator.Separator()
    # Arabic seems to have changed starting at espeak-ng-1.49.3
    if tuple(EspeakBackend.version().split('.')) >= ('1', '49', '3'):
        expected = [u'ʔassalaːm ʕliːkm ']
    else:
        expected = [u'ʔassalaam ʕaliijkum ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected
예제 #12
0
def test_phone_separator_simple():
    text = 'The lion and the tiger ran'
    sep = separator.Separator(phone='_')
    backend = EspeakBackend('en-us')

    output = backend.phonemize(text, separator=sep, strip=True)
    expected = 'ð_ə l_aɪə_n æ_n_d ð_ə t_aɪ_ɡ_ɚ ɹ_æ_n'
    assert expected == output

    output = backend.phonemize(text, separator=sep, strip=False)
    expected = 'ð_ə_ l_aɪə_n_ æ_n_d_ ð_ə_ t_aɪ_ɡ_ɚ_ ɹ_æ_n_ '
    assert expected == output
예제 #13
0
def test_arabic():
    backend = EspeakBackend('ar')
    text = ['السلام عليكم']
    sep = Separator()

    # Arabic seems to have changed starting at espeak-ng-1.49.3
    if EspeakBackend.version() >= (1, 49, 3):
        expected = ['ʔassalaːm ʕliːkm ']
    else:
        expected = ['ʔassalaam ʕaliijkum ']
    out = backend.phonemize(text, sep, False)
    assert out == expected
예제 #14
0
def test_tie_utf8():
    # NOTE this is a bug in espeak to append ties on (en) language switch
    # flags. For now phonemizer does not fix it.
    backend = EspeakBackend('fr-fr', tie=True)

    # used to be 'bɔ̃͡ʒuʁ '
    assert backend.phonemize(['bonjour']) == ['bɔ̃ʒuʁ ']

    # used to be 'ty ɛm lə (͡e͡n͡)fʊtbɔ͡ːl(͡f͡r͡)'
    assert backend.phonemize(['tu aimes le football'
                              ]) == ['ty ɛm lə (͡e͡n)fʊtbɔːl(͡f͡r) ']

    assert backend.phonemize(['bonjour apple'
                              ]) == ['bɔ̃ʒuʁ (͡e͡n)apə͡l(͡f͡r) ']
def test_language_switch_remove_utterance(caplog, langswitch_text, njobs):
    backend = EspeakBackend('fr-fr', language_switch='remove-utterance')
    out = backend.phonemize(langswitch_text,
                            separator=Separator(),
                            strip=True,
                            njobs=njobs)
    assert out == ['ʒɛm lɑ̃ɡlɛ', '', '', '', '']

    messages = [msg[2] for msg in caplog.record_tuples]
    assert ('removed 4 utterances containing language switches '
            '(applying "remove-utterance" policy)' in messages)

    with pytest.raises(RuntimeError):
        backend = EspeakBackend('fr-fr', language_switch='foo')
def test_language_switch_remove_flags(caplog, langswitch_text, njobs):
    backend = EspeakBackend('fr-fr', language_switch='remove-flags')
    out = backend.phonemize(langswitch_text,
                            separator=Separator(),
                            strip=True,
                            njobs=njobs)
    assert out == [
        'ʒɛm lɑ̃ɡlɛ', 'ʒɛm lə fʊtbɔːl', 'fʊtbɔːl', 'syʁtu lə ɹiəl madʁid',
        'nytiliz pa ɡuːɡəl'
    ]

    messages = [msg[2] for msg in caplog.record_tuples]
    assert ('4 utterances containing language switches on lines 2, 3, 4, 5'
            in messages)
    assert ('language switch flags have been removed '
            '(applying "remove-flags" policy)' in messages)
예제 #17
0
def test_path_venv():
    try:
        os.environ['PHONEMIZER_ESPEAK_LIBRARY'] = (shutil.which('python'))
        with pytest.raises(RuntimeError):
            EspeakBackend('en-us').phonemize(['hello'])
        with pytest.raises(RuntimeError):
            EspeakBackend.version()

        os.environ['PHONEMIZER_ESPEAK_LIBRARY'] = __file__
        with pytest.raises(RuntimeError):
            EspeakBackend.version()

    finally:
        try:
            del os.environ['PHONEMIZER_ESPEAK_LIBRARY']
        except KeyError:
            pass
예제 #18
0
def test_path_venv():
    try:
        os.environ['PHONEMIZER_ESPEAK_PATH'] = (
            distutils.spawn.find_executable('python'))
        with pytest.raises(RuntimeError):
            EspeakBackend('en-us').phonemize('hello')
        with pytest.raises(RuntimeError):
            EspeakBackend.version()

        os.environ['PHONEMIZER_ESPEAK_PATH'] = __file__
        with pytest.raises(ValueError):
            EspeakBackend.version()

    finally:
        try:
            del os.environ['PHONEMIZER_ESPEAK_PATH']
        except KeyError:
            pass
예제 #19
0
def test_path_bad():
    espeak = EspeakBackend.espeak_path()
    try:
        # corrupt the default espeak path, try to use python executable instead
        binary = distutils.spawn.find_executable('python')
        EspeakBackend.set_espeak_path(binary)

        with pytest.raises(RuntimeError):
            EspeakBackend('en-us').phonemize('hello')
        with pytest.raises(RuntimeError):
            EspeakBackend.version()

        with pytest.raises(ValueError):
            EspeakBackend.set_espeak_path(__file__)

    # restore the espeak path to default
    finally:
        EspeakBackend.set_espeak_path(espeak)
예제 #20
0
def test_punctuation(text, strip, sep):
    if sep == separator.Separator():
        expected = 'ɐ kɑːmə ɐ pɔɪnt' if strip else 'ɐ kɑːmə ɐ pɔɪnt '
    else:
        expected = (
            'ɐ_k ɑː m ə_ɐ_p ɔɪ n t' if strip else 'ɐ _k ɑː m ə _ɐ _p ɔɪ n t _')

    output = EspeakBackend('en-us').phonemize(text, strip=strip, separator=sep)
    assert expected == output
예제 #21
0
def test_path_bad():
    try:
        # corrupt the default espeak path, try to use python executable instead
        binary = shutil.which('python')
        EspeakBackend.set_library(binary)

        with pytest.raises(RuntimeError):
            EspeakBackend('en-us')
        with pytest.raises(RuntimeError):
            EspeakBackend.version()

        EspeakBackend.set_library(__file__)
        with pytest.raises(RuntimeError):
            EspeakBackend('en-us')

    # restore the espeak path to default
    finally:
        EspeakBackend.set_library(None)
def test_language_switch_default(caplog, langswitch_text, njobs):
    # default behavior is to keep the flags
    backend = EspeakBackend('fr-fr')
    out = backend.phonemize(langswitch_text,
                            separator=Separator(),
                            strip=True,
                            njobs=njobs)
    assert out == [
        'ʒɛm lɑ̃ɡlɛ', 'ʒɛm lə (en)fʊtbɔːl(fr)', '(en)fʊtbɔːl(fr)',
        'syʁtu lə (en)ɹiəl(fr) madʁid', 'nytiliz pa (en)ɡuːɡəl(fr)'
    ]

    messages = [msg[2] for msg in caplog.record_tuples]
    assert ('4 utterances containing language switches on lines 2, 3, 4, 5'
            in messages)
    assert (
        'language switch flags have been kept (applying "keep-flags" policy)'
        in messages)
    def __init__(
        self,
        text_cleaners=["basic_cleaners"],
        use_phonemes=True,
        n_jobs=1,
        with_stress=True,
        language="en-us",
    ):
        """
        Text sequencies preprocessor with G2P support.
        :param text_cleaners: text cleaner type:
            * `basic_cleaners`: basic pipeline that lowercases and collapses whitespace without transliteration.
            * `transliteration_cleaners`: pipeline for non-English text that transliterates to ASCII.
            * `english_cleaners`: pipeline for English text, including number and abbreviation expansion.
        :param use_phonemes: file path with phonemes set separated by `|`
        :param n_jobs: number of workers for phonemization
        :param with_stress: set `True` to stress words during phonemization
        """
        self.text_cleaners = text_cleaners
        self.use_phonemes = use_phonemes
        self.n_jobs = n_jobs
        self.with_stress = with_stress
        self.language = language

        CHARS = _GRAPHEMES if not self.use_phonemes else _PHONEMES

        self.SYMBOLS = ([_PAD, _EOS, _SPACE] + _PUNCTUATIONS + ["¡", "¿"] +
                        _NUMBERS + CHARS)

        # Mappings from symbol to numeric ID and vice versa:
        self._symbol_to_id = {s: i for i, s in enumerate(self.SYMBOLS)}
        self._id_to_symbol = {i: s for i, s in enumerate(self.SYMBOLS)}

        self._separator = Separator(word=_WORD_SEP,
                                    syllable="",
                                    phone=_PHONEME_SEP)
        self.p = EspeakBackend(
            self.language,
            punctuation_marks="".join(_PUNCTUATIONS),
            preserve_punctuation=True,
            with_stress=self.with_stress,
        )
예제 #24
0
def test_espeak(njobs):
    text = ['one two', 'three', 'four five']

    out = phonemize(text,
                    language='en-us',
                    backend='espeak',
                    strip=True,
                    njobs=njobs)
    assert out == [u'wʌn tuː', u'θɹiː', u'foːɹ faɪv']

    if EspeakBackend.is_espeak_ng():
        out = phonemize(text,
                        language='en-us',
                        backend='espeak',
                        use_sampa=True,
                        strip=True,
                        njobs=njobs)
        assert out == [u'wVn tu:', u'Tri:', u'fo@ faIv']

    out = phonemize(text,
                    language='en-us',
                    backend='espeak',
                    strip=False,
                    njobs=njobs)
    assert out == [u'wʌn tuː ', u'θɹiː ', u'foːɹ faɪv ']

    out = phonemize(' '.join(text),
                    language='en-us',
                    backend='espeak',
                    strip=True,
                    njobs=njobs)
    assert out == ' '.join([u'wʌn tuː', u'θɹiː', u'foːɹ faɪv'])

    out = phonemize(' '.join(text),
                    language='en-us',
                    backend='espeak',
                    strip=False,
                    njobs=njobs)
    assert out == ' '.join([u'wʌn tuː', u'θɹiː', u'foːɹ faɪv '])

    out = phonemize('\n'.join(text),
                    language='en-us',
                    backend='espeak',
                    strip=True,
                    njobs=njobs)
    assert out == '\n'.join([u'wʌn tuː', u'θɹiː', u'foːɹ faɪv'])

    out = phonemize('\n'.join(text),
                    language='en-us',
                    backend='espeak',
                    strip=False,
                    njobs=njobs)
    assert out == '\n'.join([u'wʌn tuː ', u'θɹiː ', u'foːɹ faɪv '])
예제 #25
0
def test_path_good():
    espeak = EspeakBackend.espeak_path()
    try:
        EspeakBackend.set_espeak_path(None)
        assert espeak == EspeakBackend.espeak_path()

        binary = distutils.spawn.find_executable('espeak')
        EspeakBackend.set_espeak_path(binary)

        test_english()

    # restore the espeak path to default
    finally:
        EspeakBackend.set_espeak_path(espeak)
예제 #26
0
def test_path_good():
    espeak = EspeakBackend.library()
    try:
        EspeakBackend.set_library(None)
        assert espeak == EspeakBackend.library()

        library = EspeakWrapper().library_path
        EspeakBackend.set_library(library)

        test_english()

    # restore the espeak path to default
    finally:
        EspeakBackend.set_library(None)
예제 #27
0
def test_stress():
    backend = EspeakBackend('en-us', with_stress=False)
    assert backend.phonemize(['hello world'], default_separator,
                             True) == ['həloʊ wɜːld']

    backend = EspeakBackend('en-us', with_stress=True)
    assert backend.phonemize(['hello world'], default_separator,
                             True) == ['həlˈoʊ wˈɜːld']
예제 #28
0
def test_stress():
    backend = EspeakBackend('en-us', with_stress=False)
    assert u'həloʊ wɜːld' == backend._phonemize_aux(
        u'hello world', separator.default_separator, True)[0]

    backend = EspeakBackend('en-us', with_stress=True)
    assert u'həlˈoʊ wˈɜːld' == backend._phonemize_aux(
        u'hello world', separator.default_separator, True)[0]
예제 #29
0
파일: main.py 프로젝트: songkey/phonemizer
def parse_args():
    """Argument parser for the phonemization script"""
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description='''Multilingual text to phonemes converter

The 'phonemize' program allows simple phonemization of words and texts
in many language using three backends: espeak, festival and segments.

- espeak is a text-to-speech software supporting multiple languages
  and IPA (Internatinal Phonetic Alphabet) output. See
  http://espeak.sourceforge.net or
  https://github.com/espeak-ng/espeak-ng

- festival is also a text-to-speech software. Currently only American
  English is supported and festival uses a custom phoneset
  (http://www.festvox.org/bsv/c4711.html), but festival is the only
  backend supporting tokenization at the syllable
  level. See http://www.cstr.ed.ac.uk/projects/festival

- segments is a Unicode tokenizer that build a phonemization from a
  grapheme to phoneme mapping provided as a file by the user. See
  https://github.com/cldf/segments.

See the '--language' option below for details on the languages
supported by each backend.

''',
        epilog='''
   Languages supported by the festival backend are:
   {festival}

   Languages supported by the segments backend are:
   {segments}
   Instead of a language you can also provide a file specifying a
   grapheme to phoneme mapping (see the files above for exemples).

   Languages supported by the espeak backend are:
   {espeak}


Exemples:

* Phonemize a US English text with espeak

   $ echo 'hello world' | phonemize -l en-us -b espeak
   həloʊ wɜːld

* Phonemize a US English text with festival

   $ echo 'hello world' | phonemize -l en-us -b festival
   hhaxlow werld

* Phonemize a Japanese text with segments

  $ echo 'konnichiwa tsekai' | phonemize -l japanese -b segments
  konnitʃiwa t͡sekai

* Add a separator between phones

  $ echo 'hello world' | phonemize -l en-us -b festival -p '-' --strip
  hh-ax-l-ow w-er-l-d

* Phonemize some French text file using espeak

  $ phonemize -l fr-fr -b espeak text.txt -o phones.txt
        '''.format(festival='\n'.join(
            '\t{}\t->\t{}'.format(k, v)
            for k, v in sorted(FestivalBackend.supported_languages().items())),
                   segments='\n'.join(
                       '\t{}\t->\t{}'.format(k, v) for k, v in sorted(
                           SegmentsBackend.supported_languages().items())),
                   espeak='\n'.join(
                       '\t{}\t->\t{}'.format(k, v) for k, v in sorted(
                           EspeakBackend.supported_languages().items()))))

    # general arguments
    parser.add_argument('--version',
                        action='store_true',
                        help='show version information and exit.')

    group = parser.add_mutually_exclusive_group()
    group.add_argument('-v',
                       '--verbose',
                       action='store_true',
                       help='write all log messages to stderr '
                       '(displays only warnings by default).')
    group.add_argument('-q',
                       '--quiet',
                       action='store_true',
                       help='do not display any log message, even warnings.')

    parser.add_argument(
        '-j',
        '--njobs',
        type=int,
        metavar='<int>',
        default=1,
        help='number of parallel jobs, default is %(default)s.')

    # input/output arguments
    group = parser.add_argument_group('input/output')
    group.add_argument(
        'input',
        default=sys.stdin,
        nargs='?',
        metavar='<file>',
        help='input text file to phonemize, if not specified read from stdin.')

    group.add_argument(
        '-o',
        '--output',
        default=sys.stdout,
        metavar='<file>',
        help='output text file to write, if not specified write to stdout.')

    group = parser.add_argument_group('separators')
    group.add_argument('-p',
                       '--phone-separator',
                       metavar='<str>',
                       default=separator.default_separator.phone,
                       help='phone separator, default is "%(default)s".')

    group.add_argument('-w',
                       '--word-separator',
                       metavar='<str>',
                       default=separator.default_separator.word,
                       help='word separator, default is "%(default)s".')

    group.add_argument(
        '-s',
        '--syllable-separator',
        metavar='<str>',
        default=separator.default_separator.syllable,
        help='''syllable separator, only valid for festival backend,
        this option has no effect if espeak or segments is used.
        Default is "%(default)s".''')

    group.add_argument('--strip',
                       action='store_true',
                       help='removes the end separators in phonemized tokens.')

    group = parser.add_argument_group('backends')
    group.add_argument(
        '-b',
        '--backend',
        metavar='<str>',
        default='espeak',
        choices=['espeak', 'festival', 'segments'],
        help="""the phonemization backend, must be 'espeak', 'festival' or
        'segments'. Default is %(default)s.""")

    group = parser.add_argument_group('specific to espeak backend')
    group.add_argument(
        '--with-stress',
        action='store_true',
        help='''when the option is set, the stresses on phonemes are present
        (stresses characters are ˈ'ˌ). By default stresses are removed.''')
    group.add_argument(
        '--sampa',
        action='store_true',
        help='''only valid for espeak-ng and NOT supported for espeak, use the
        "sampa" (Speech Assessment Methods Phonetic Alphabet) alphabet instead
        of "ipa" (International Phonetic Alphabet).''')
    group.add_argument(
        '--language-switch',
        default='keep-flags',
        choices=['keep-flags', 'remove-flags', 'remove-utterance'],
        help="""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.""")

    group = parser.add_argument_group('language')
    group.add_argument(
        '-l',
        '--language',
        metavar='<str|file>',
        default='en-us',
        help='''the language code of the input text, see below for a list of
        supported languages. According to the language code you
        specify, the appropriate backend (segments, espeak or
        festival) will be called in background. Default is
        %(default)s.''')

    return parser.parse_args()
예제 #30
0
파일: main.py 프로젝트: bootphon/phonemizer
def parse_args():
    """Argument parser for the phonemization script"""
    parser = argparse.ArgumentParser(
        formatter_class=argparse.RawDescriptionHelpFormatter,
        description='''Multilingual text to phonemes converter

The 'phonemize' program allows simple phonemization of words and texts
in many language using three backends: espeak, festival and segments.

- espeak is a text-to-speech software supporting multiple languages
  and IPA (Internatinal Phonetic Alphabet) output. See
  http://espeak.sourceforge.net or
  https://github.com/espeak-ng/espeak-ng

- festival is also a text-to-speech software. Currently only American
  English is supported and festival uses a custom phoneset
  (http://www.festvox.org/bsv/c4711.html), but festival is the only
  backend supporting tokenization at the syllable
  level. See http://www.cstr.ed.ac.uk/projects/festival

- segments is a Unicode tokenizer that build a phonemization from a
  grapheme to phoneme mapping provided as a file by the user. See
  https://github.com/cldf/segments.

See the '--language' option below for details on the languages
supported by each backend.

''',
        epilog='''
   Languages supported by the festival backend are:
   {festival}

   Languages supported by the segments backend are:
   {segments}
   Instead of a language you can also provide a file specifying a
   grapheme to phoneme mapping (see the files above for exemples).

   Languages supported by the espeak backend are:
   {espeak}


Exemples:

* Phonemize a US English text with espeak

   $ echo 'hello world' | phonemize -l en-us -b espeak
   həloʊ wɜːld

* Phonemize a US English text with festival

   $ echo 'hello world' | phonemize -l en-us -b festival
   hhaxlow werld

* Phonemize a Japanese text with segments

  $ echo 'konnichiwa tsekai' | phonemize -l japanese -b segments
  konnitʃiwa t͡sekai

* Add a separator between phones

  $ echo 'hello world' | phonemize -l en-us -b festival -p '-' --strip
  hh-ax-l-ow w-er-l-d

* Phonemize some French text file using espeak

  $ phonemize -l fr-fr -b espeak text.txt -o phones.txt
        '''.format(
            festival='\n'.join(
                '\t{}\t->\t{}'.format(k, v) for k, v in
                sorted(FestivalBackend.supported_languages().items())),
            segments='\n'.join(
                '\t{}\t->\t{}'.format(k, v) for k, v in
                sorted(SegmentsBackend.supported_languages().items())),
            espeak='\n'.join(
                '\t{}\t->\t{}'.format(k, v) for k, v in
                sorted(EspeakBackend.supported_languages().items()))))

    # general arguments
    parser.add_argument(
        '--version', action='store_true',
        help='show version information and exit')

    parser.add_argument(
        '-v', '--verbose', action='store_true',
        help='write some log messages to stderr')

    parser.add_argument(
        '-j', '--njobs', type=int, metavar='<int>', default=1,
        help='number of parallel jobs, default is %(default)s')

    # input/output arguments
    group = parser.add_argument_group('input/output')
    group.add_argument(
        'input', default=sys.stdin, nargs='?', metavar='<file>',
        help='input text file to phonemize, if not specified read from stdin')

    group.add_argument(
        '-o', '--output', default=sys.stdout, metavar='<file>',
        help='output text file to write, if not specified write to stdout')

    group = parser.add_argument_group('separators')
    group.add_argument(
        '-p', '--phone-separator', metavar='<str>',
        default=separator.default_separator.phone,
        help='phone separator, default is "%(default)s"')

    group.add_argument(
        '-w', '--word-separator', metavar='<str>',
        default=separator.default_separator.word,
        help='word separator, default is "%(default)s"')

    group.add_argument(
        '-s', '--syllable-separator', metavar='<str>',
        default=separator.default_separator.syllable,
        help='''syllable separator is available only for the festival backend,
        this option has no effect if espeak or segments is used.
        Default is "%(default)s"''')

    group.add_argument(
        '--strip', action='store_true',
        help='removes the end separators in phonemized tokens')

    group = parser.add_argument_group('language')

    group.add_argument(
        '-b', '--backend', metavar='<str>', default='espeak',
        choices=['espeak', 'festival', 'segments'],
        help="""the phonemization backend, must be 'espeak', 'festival' or
        'segments'. Default is %(default)s""")

    group.add_argument(
        '-l', '--language', metavar='<str|file>', default='en-us',
        help='''the language code of the input text, see below for a list of
        supported languages. According to the language code you
        specify, the appropriate backend (segments, espeak or
        festival) will be called in background. Default is
        %(default)s''')

    return parser.parse_args()
예제 #31
0
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)
예제 #32
0
    backend = EspeakBackend('en-us')
    text = u'hello world\ngoodbye\nthird line\nyet another'
    out = '\n'.join(backend._phonemize_aux(
        text, separator.default_separator, True))
    assert out == u'həloʊ wɜːld\nɡʊdbaɪ\nθɜːd laɪn\njɛt ɐnʌðɚ'


def test_french():
    backend = EspeakBackend('fr-fr')
    text = u'bonjour le monde'
    sep = separator.Separator(word=';eword ', syllable=None, phone=' ')
    expected = [u'b ɔ̃ ʒ u ʁ ;eword l ə- ;eword m ɔ̃ d ;eword ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected


@pytest.mark.skipif(
    not EspeakBackend.is_espeak_ng(),
    reason='Arabic is only supported by espeak-ng')
def test_arabic():
    backend = EspeakBackend('ar')
    text = u'السلام عليكم'
    sep = separator.Separator()
    # Arabic seems to have changed starting at espeak-ng-1.49.3
    if tuple(EspeakBackend.version().split('.')) >= ('1', '49', '3'):
        expected = [u'ʔassalaːm ʕliːkm ']
    else:
        expected = [u'ʔassalaam ʕaliijkum ']
    out = backend._phonemize_aux(text, sep, False)
    assert out == expected
예제 #33
0
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with phonemizer. If not, see <http://www.gnu.org/licenses/>.
"""Test of the punctuation processing"""

# pylint: disable=missing-docstring

import pytest

from phonemizer.backend import EspeakBackend, FestivalBackend, SegmentsBackend
from phonemizer.punctuation import Punctuation
from phonemizer.phonemize import phonemize

# True if we are using espeak>=1.50
ESPEAK_150 = (EspeakBackend.version() >= (1, 50))

# True if we are using espeak>=1.49.3
ESPEAK_143 = (EspeakBackend.version() >= (1, 49, 3))

# True if we are using festival>=2.5
FESTIVAL_25 = (FestivalBackend.version() >= (2, 5))


@pytest.mark.parametrize('inp, out', [('a, b,c.', 'a b c'),
                                      ('abc de', 'abc de'),
                                      ('!d.d. dd??  d!', 'd d dd d')])
def test_remove(inp, out):
    assert Punctuation().remove(inp) == out

예제 #34
0
def test_english():
    backend = EspeakBackend('en-us')
    text = u'hello world\ngoodbye\nthird line\nyet another'
    out = '\n'.join(backend._phonemize_aux(
        text, separator.default_separator, True))
    assert out == u'həloʊ wɜːld\nɡʊdbaɪ\nθɜːd laɪn\njɛt ɐnʌðɚ'
예제 #35
0
    out3 = phonemize(text2,
                     language='en-us',
                     backend='espeak',
                     strip=True,
                     prepend_text=True)
    text3 = [o[0] for o in out3]
    phn3 = [o[1] for o in out3]

    assert isinstance(phn1, list)
    assert isinstance(phn2, str)
    assert os.linesep.join(phn1) == phn2
    assert os.linesep.join(phn3) == phn2
    assert text3 == text1


@pytest.mark.skipif(not EspeakBackend.is_espeak_ng(),
                    reason='language switch only exists for espeak-ng')
def test_lang_switch():
    text = ['bonjour apple', 'bonjour toi']
    out = phonemize(text,
                    language='fr-fr',
                    backend='espeak',
                    prepend_text=True,
                    language_switch='remove-utterance')
    assert out == [('bonjour apple', ''), ('bonjour toi', 'bɔ̃ʒuʁ twa ')]


@pytest.mark.parametrize('njobs', [2, 4])
def test_espeak(njobs):
    text = ['one two', 'three', 'four five']
예제 #36
0
파일: main.py 프로젝트: welgazil/phonemizer
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')