Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Speak.activity/voice.py
blob: a3bb1c6795409c67280363d89b2e82f25ffa0ce0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# Speak.activity
# A simple front end to the espeak text-to-speech engine on the XO laptop
# http://wiki.laptop.org/go/Speak
#
# Copyright (C) 2008  Joshua Minor
# This file is part of Speak.activity
#
# Parts of Speak.activity are based on code from Measure.activity
# Copyright (C) 2007  Arjun Sarwal - arjun@laptop.org
# 
#     Speak.activity is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 3 of the License, or
#     (at your option) any later version.
# 
#     Speak.activity 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 General Public License for more details.
# 
#     You should have received a copy of the GNU General Public License
#     along with Speak.activity.  If not, see <http://www.gnu.org/licenses/>.


import subprocess
import re, os
from gettext import gettext as _

# Lets trick gettext into generating entries for the voice names we expect espeak to have
# If espeak actually has new or different names then they won't get translated, but they
# should still show up in the interface.
expectedVoiceNames = [
    _("Brazil"),
    _("Swedish"),
    _("Icelandic"),
    _("Romanian"),
    _("Swahili"),
    _("Hindi"),
    _("Dutch"),
    _("Latin"),
    _("Hungarian"),
    _("Macedonian"),
    _("Welsh"),
    _("French"),
    _("Norwegian"),
    _("Russian"),
    _("Afrikaans"),
    _("Finnish"),
    _("Default"),
    _("Cantonese"),
    _("Scottish"),
    _("Greek"),
    _("Vietnam"),
    _("English"),
    _("Lancashire"),
    _("Italian"),
    _("Portugal"),
    _("German"),
    _("Whisper"),
    _("Croatian"),
    _("Czech"),
    _("Slovak"),
    _("Spanish"),
    _("Polish"),
    _("Esperanto")
]

_allVoices = {}

class Voice:
    def __init__(self, language, gender, name):
        self.language = language
        self.gender = gender
        self.name = name

        friendlyname = name
        friendlyname = friendlyname.replace('-test','')
        friendlyname = friendlyname.replace('_test','')
        friendlyname = friendlyname.replace('en-','')
        friendlyname = friendlyname.replace('english-wisper','whisper')
        friendlyname = friendlyname.capitalize()
        self.friendlyname = _(friendlyname)
    
def allVoices():
    if len(_allVoices) == 0:
        result = subprocess.Popen(["espeak", "--voices"], stdout=subprocess.PIPE).communicate()[0]
        for line in result.split('\n'):
            m = re.match(r'\s*\d+\s+([\w-]+)\s+([MF])\s+([\w_-]+)\s+(.+)', line)
            if m:
                language, gender, name, stuff = m.groups()
                if stuff.startswith('mb/') or name in ('en-rhotic','english_rp','english_wmids'):
                    # these voices don't produce sound
                    continue
                voice = Voice(language, gender, name)
                _allVoices[voice.friendlyname] = voice
    return _allVoices

def defaultVoice():
    """Try to figure out the default voice, from the current locale ($LANG).
       Fall back to espeak's voice called Default."""

    def fit(a,b):
        "Compare two language ids to see if they are similar."
	as = re.split(r'[^a-z]+', a.lower())
	bs = re.split(r'[^a-z]+', b.lower())
	for count in range(0, min(len(as),len(bs))):
            if as[count] != bs[count]:
                count -= 1
                break
        return count
    try:
        lang = os.environ["LANG"]
    except:
        lang = ""
    
    best = _allVoices[_("Default")]
    for voice in _allVoices.values():
        voiceMetric = fit(voice.language, lang)
        bestMetric  = fit(best.language, lang)
        if voiceMetric > bestMetric:
            best = voice

    print "Best voice for LANG %s seems to be %s %s" % (lang, best.language, best.friendlyname)
    return best