|
| 1 | +import festival |
| 2 | +import os |
| 3 | + |
| 4 | + |
1 | 5 | class TTS:
|
2 |
| - __VOICES = () |
| 6 | + __VOICE_DIR = os.path.join(os.sep, "usr", "share", "festival", "voices") |
3 | 7 |
|
4 | 8 | def __init__(self):
|
| 9 | + self._speed = 1.0 |
| 10 | + self.__voices = self.get_voices() |
| 11 | + self._language = None |
| 12 | + self.language = "us" |
5 | 13 | self._voice = None
|
| 14 | + self.voice = self.__voices.get(self.language)[0] |
6 | 15 |
|
7 | 16 | def __call__(self, text: str):
|
8 |
| - print(text) |
| 17 | + festival.sayText(text) |
| 18 | + |
| 19 | + def get_voices(self): |
| 20 | + languages = os.listdir(self.__VOICE_DIR) |
| 21 | + language_dirs = (os.path.join(self.__VOICE_DIR, lang) for lang in languages) |
| 22 | + |
| 23 | + voice_dict = {} |
| 24 | + for lang, lang_dir in zip(languages, language_dirs): |
| 25 | + voice_dict[lang] = os.listdir(lang_dir) |
| 26 | + |
| 27 | + return voice_dict |
9 | 28 |
|
10 | 29 | @property
|
11 | 30 | def voice(self):
|
12 | 31 | return self._voice
|
13 | 32 |
|
14 | 33 | @voice.setter
|
15 | 34 | def voice(self, voice: str):
|
16 |
| - if voice not in self.__VOICES: |
17 |
| - raise ValueError(f"Invalid voice choice. " |
18 |
| - f"Choose from {', '.join(self.__VOICES[:-1])} or {self.__VOICES[-1]}") |
| 35 | + available_voices = self.__voices.get(self.language) |
| 36 | + if voice not in available_voices: |
| 37 | + raise ValueError(f"Invalid voice choice. Please choose from:\n" |
| 38 | + f"{available_voices}\n" |
| 39 | + f"Or choose a different language. Run display_voices() method to see what is available.") |
19 | 40 | self._voice = voice
|
| 41 | + success = festival.execCommand(f"(voice_{self._voice})") |
| 42 | + if not success: |
| 43 | + print("Changing voice failed.") |
| 44 | + |
| 45 | + @property |
| 46 | + def language(self): |
| 47 | + return self._language |
| 48 | + |
| 49 | + @language.setter |
| 50 | + def language(self, language: str): |
| 51 | + available_languages = list(self.__voices.keys()) |
| 52 | + if language not in available_languages: |
| 53 | + raise ValueError("Invalid language choice. Please choose from:\n" |
| 54 | + f"{available_languages}") |
| 55 | + self._language = language |
| 56 | + |
| 57 | + @property |
| 58 | + def speed(self): |
| 59 | + return self._speed |
| 60 | + |
| 61 | + @speed.setter |
| 62 | + def speed(self, value: float): |
| 63 | + if value < 0.2: |
| 64 | + raise ValueError("Speed value must be greater than or equal to 0.2.") |
| 65 | + |
| 66 | + self._speed = value |
| 67 | + success = festival.setStretchFactor(1 / self._speed) |
| 68 | + |
| 69 | + if not success: |
| 70 | + print("Changing speed failed.") |
20 | 71 |
|
21 |
| - def list_voices(self): |
22 |
| - print(f"Available voices: f{self.__VOICES}") |
| 72 | + def display_voices(self): |
| 73 | + print("LANGUAGE VOICES") |
| 74 | + for language, voices in self.__voices.items(): |
| 75 | + print(f"{language:<10} {', '.join(voices)}") |
| 76 | + print() |
0 commit comments