#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2013, 2014 Guenter Bartsch
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
import sys
import xml.sax
import re
import random
import unittest
#
# big phoneme table
#
# entries:
# ( IPA, XSAMPA, MARY )
#
MAX_PHONEME_LENGTH = 2
big_phoneme_table = [
#
# stop
#
( u'p' , 'p' , 'p' ),
( u'b' , 'b' , 'b' ),
( u't' , 't' , 't' ),
( u'd' , 'd' , 'd' ),
( u'k' , 'k' , 'k' ),
( u'g' , 'g' , 'g' ),
( u'ʔ' , '?' , '?' ),
#
# 2 consonants
#
( u'pf' , 'pf' , 'pf' ),
( u'ts' , 'ts' , 'ts' ),
( u'tʃ' , 'tS' , 'tS' ),
( u'dʒ' , 'dZ' , 'dZ' ),
#
# fricative
#
( u'f' , 'f' , 'f' ),
( u'v' , 'v' , 'v' ),
( u'θ' , 'T' , 'T' ),
( u'ð' , 'D' , 'D' ),
( u's' , 's' , 's' ),
( u'z' , 'z' , 'z' ),
( u'ʃ' , 'S' , 'S' ),
( u'ʒ' , 'Z' , 'Z' ),
( u'ç' , 'C' , 'C' ),
( u'j' , 'j' , 'j' ),
( u'x' , 'x' , 'x' ),
( u'ʁ' , 'R' , 'R' ),
( u'h' , 'h' , 'h' ),
( u'ɥ' , 'H' , 'H' ),
#
# nasal
#
( u'm' , 'm' , 'm' ),
( u'n' , 'n' , 'n' ),
( u'ɳ' , 'N' , 'N' ),
#
# liquid
#
( u'l' , 'l' , 'l' ),
( u'r' , 'r' , 'r' ),
#
# glide
#
( u'w' , 'w' , 'w' ),
# see above ( u'j' , 'j' , 'j' ),
#
# vowels: monophongs
#
# front
( u'i' , 'i' , 'i' ),
( u'ɪ' , 'I' , 'I' ),
( u'y' , 'y' , 'y' ),
( u'ʏ' , 'Y' , 'Y' ),
( u'e' , 'e' , 'e' ),
( u'ø' , '2' , '2' ),
( u'œ' , '9' , '9' ),
( u'ɛ' , 'E' , 'E' ),
( u'æ' , '{' , '{' ),
( u'a' , 'a' , 'a' ),
# central
( u'ʌ' , 'V' , 'V' ),
( u'ə' , '@' , '@' ),
( u'ɐ' , '6' , '6' ),
( u'ɜ' , '3' , 'r=' ),
# back
( u'u' , 'u' , 'u' ),
( u'ʊ' , 'U' , 'U' ),
( u'o' , 'o' , 'o' ),
( u'ɔ' , 'O' , 'O' ),
( u'ɑ' , 'A' , 'A' ),
( u'ɒ' , 'Q' , 'Q' ),
# diphtongs
( u'aɪ' , 'aI' , 'aI' ),
( u'ɔɪ' , 'OI' , 'OI' ),
( u'aʊ' , 'aU' , 'aU' ),
( u'ɔʏ' , 'OY' , 'OY' ),
#
# misc
#
( u'ː' , ':' , ':' ),
( u'-' , '-' , '-' ),
( u'\'' , '\'' , '\'' ),
]
IPA_normalization = {
u':' : u'ː',
u'?' : u'ʔ',
u'ɾ' : u'ʁ',
u'ɡ' : u'g',
u'ŋ' : u'ɳ',
u' ' : None,
u'(' : None,
u')' : None,
u'\u02c8' : u'\'',
u'\u032f' : None,
u'\u0329' : None,
u'\u02cc' : None,
u'\u200d' : None,
u'\u0279' : None,
}
XSAMPA_normalization = {
' ': None,
'~': None,
'0': 'O',
',': None,
}
def _normalize (s, norm_table):
buf = ""
for c in s:
if c in norm_table:
x = norm_table[c]
if x:
buf += x
else:
buf += c
return buf
def _translate (graph, s, f_idx, t_idx, spaces=False):
buf = ""
i = 0
l = len(s)
while i < l:
found = False
for pl in range(MAX_PHONEME_LENGTH, 0, -1):
if i + pl > l:
continue
substr = s[i : i+pl ]
#print u"i: %s, pl: %d, substr: '%s'" % (i, pl, substr)
for pe in big_phoneme_table:
p_f = pe[f_idx]
p_t = pe[t_idx]
if substr == p_f:
buf += p_t
i += pl
if i l:
continue
substr = s[i : i+pl ]
#print u"i: %s, pl: %d, substr: '%s'" % (i, pl, substr)
for pe in xs2xa_table:
p_f = pe[0]
p_t = pe[1]
if substr == p_f:
if len(buf)>0:
buf += ' '
buf += p_t
i += pl
found = True
break
if found:
break
if not found:
p = s[i]
msg = u"xsampa2xarpabet: graph:'%s' - s:'%s' Phoneme not found: '%s' (%d) '%s'" % (graph, s, p, ord(p), s[i:])
raise Exception (msg.encode('UTF8'))
return buf
class TestPhoneticAlphabets (unittest.TestCase):
def setUp(self):
self.seq = range(10)
def test_ipa(self):
res = ipa2xsampa ("EISENBAHN", u"ˈaɪ̯zən̩ˌbaːn")
#print "res: %s" % res
self.assertEqual (res, "'aIz@nba:n")
res = ipa2xsampa ("DIPHTONGTEST", u"aɪɔɪaʊɜ'")
#print "res: %s" % res
self.assertEqual (res, "aIOIaU3'")
res = ipa2mary ("EISENBAHN", u"ˈaɪ̯zən̩ˌbaːn")
#print "res: %s" % res
self.assertEqual (res, "'aIz@nba:n")
res = ipa2mary ("DIPHTONGTEST", u"aɪɔɪaʊɜ'")
#print "res: %s" % res
self.assertEqual (res, "aIOIaUr='")
def test_xarpa(self):
res = xsampa2xarpabet ("JAHRHUNDERTE", "ja:6-'hUn-d6-t@")
#print "res: %s" % res
self.assertEqual (res, "Y AAH EX HH UU N D EX T AX")
res = xsampa2xarpabet ("ABGESCHRIEBEN", "'ap-g@-SRi:-b@n")
#print "res: %s" % res
self.assertEqual (res, "AH P G AX SH RR IIH B AX N")
res = xsampa2xarpabet ("ZUGEGRIFFEN", "'tsu:-g@-gRI-f@n")
#print "res: %s" % res
self.assertEqual (res, "TS UUH G AX G RR IH F AX N")
res = xsampa2xarpabet ("AUSLEGUNG", "'aU-sle:-gUN")
#print "res: %s" % res
self.assertEqual (res, "AW S L EEH G UU NG")
def test_xarpa_unique(self):
# all xarpa transcriptions have to be unique
uniq_xs = set()
uniq_xa = set()
for entry in xs2xa_table:
xs = entry[0]
xa = entry[1]
#print (u"xs: %s, xa: %s" % (xs, xa)).encode('utf8')
self.assertFalse (xa in uniq_xa)
uniq_xa.add(xa)
self.assertFalse (xs in uniq_xs)
uniq_xs.add(xs)
if __name__ == "__main__":
unittest.main()