diff --git a/README_desktop_client.md b/README_desktop_client.md index 95e8bedd3..4b84d4d4c 100644 --- a/README_desktop_client.md +++ b/README_desktop_client.md @@ -28,6 +28,12 @@ Or if you have picospeaker installed: ~/epicyon-client-pico ``` +Or if you have mimic3 installed: + +``` bash +~/epicyon-client-mimic3 +``` + ## Commands The desktop client has a few commands, which may be more convenient than the web interface for some purposes: @@ -87,7 +93,13 @@ Or a quicker version, if you have installed the desktop client as described abov Or if you have [picospeaker](https://gitlab.com/ky1e/picospeaker) installed: ``` bash -python3 epicyon.py --notifyShowNewPosts --screenreader picospeaker --desktop yournickname@yourdomain +~/epicyon-stream-pico +``` + +Or if you have mimic3 installed: + +``` bash +~/epicyon-stream-mimic3 ``` You can also use the **--password** option to provide the password. This will then stay running and incoming posts will be announced as they arrive. diff --git a/desktop_client.py b/desktop_client.py index 40c2e80f2..fa1643087 100644 --- a/desktop_client.py +++ b/desktop_client.py @@ -316,6 +316,18 @@ def _desktop_wait_for_cmd(timeout: int, debug: bool) -> str: return None +def _play_sound(sound_filename: str, + player: str = 'ffplay') -> None: + """Plays a sound + """ + if not os.path.isfile(sound_filename): + return + + if player == 'ffplay': + os.system('ffplay ' + sound_filename + + ' -autoexit -hide_banner -nodisp 2> /dev/null') + + def _speaker_espeak(espeak, pitch: int, rate: int, srange: int, say_text: str) -> None: """Speaks the given text with espeak @@ -326,6 +338,40 @@ def _speaker_espeak(espeak, pitch: int, rate: int, srange: int, espeak.synth(html.unescape(say_text)) +def _speaker_mimic3(pitch: int, rate: int, srange: int, + say_text: str) -> None: + """Speaks the given text with mimic3 + """ + voice = 'en_UK/apope_low' + if pitch > 20: + voice = 'en_US/m-ailabs_low' + if pitch > 40: + voice = 'en_US/hifi-tts_low' + if pitch >= 50: + voice = 'en_US/ljspeech_low' + if pitch > 75: + voice = 'en_US/vctk_low' + length_scale = str(1.2 - (rate / 600.0)) + if srange > 100: + srange = 100 + noise_w = str(srange / 100.0) + text = html.unescape(say_text).replace('"', "'") + if not text: + return + audio_filename = '/tmp/epicyon_voice.wav' + cmd = 'mimic3 -v ' + voice + \ + ' --length-scale ' + length_scale + \ + ' --noise-w ' + noise_w + \ + ' --stdout' + \ + ' "' + text + '" > ' + \ + audio_filename + ' 2> /dev/null' + try: + os.system(cmd) + except OSError as ex: + print('EX: unable to play ' + audio_filename + ' ' + str(ex)) + _play_sound(audio_filename) + + def _speaker_picospeaker(pitch: int, rate: int, system_language: str, say_text: str) -> None: """TTS using picospeaker @@ -350,18 +396,6 @@ def _speaker_picospeaker(pitch: int, rate: int, system_language: str, os.system(speaker_cmd) -def _play_notification_sound(sound_filename: str, - player: str = 'ffplay') -> None: - """Plays a sound - """ - if not os.path.isfile(sound_filename): - return - - if player == 'ffplay': - os.system('ffplay ' + sound_filename + - ' -autoexit -hide_banner -nodisp 2> /dev/null') - - def _desktop_notification(notification_type: str, title: str, message: str) -> None: """Shows a desktop notification @@ -396,6 +430,8 @@ def _text_to_speech(say_str: str, screenreader: str, _speaker_espeak(espeak, pitch, rate, srange, say_str) elif screenreader == 'picospeaker': _speaker_picospeaker(pitch, rate, system_language, say_str) + elif screenreader == 'mimic3': + _speaker_mimic3(pitch, rate, srange, say_str) def _say_command(content: str, say_str: str, screenreader: str, @@ -1380,7 +1416,7 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, if screenreader == 'espeak': print('Setting up espeak') from espeak import espeak - elif screenreader != 'picospeaker': + elif screenreader not in ('picospeaker', 'mimic3'): print(screenreader + ' is not a supported TTS system') return @@ -1501,7 +1537,7 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, "Epicyon", "New DM " + your_actor + '/dm') if notification_sounds: - _play_notification_sound(dm_sound_filename, player) + _play_sound(dm_sound_filename, player) if notify_json.get('repliesNotify'): if notify_json.get('repliesNotifyChanged'): _desktop_notification(notification_type, @@ -1509,7 +1545,7 @@ def run_desktop_client(base_dir: str, proxy_type: str, http_prefix: str, "New reply " + your_actor + '/replies') if notification_sounds: - _play_notification_sound(reply_sound_filename, player) + _play_sound(reply_sound_filename, player) if box_json: timeline_first_id = _get_first_item_id(box_json) diff --git a/epicyon.py b/epicyon.py index f55158717..b82de1818 100644 --- a/epicyon.py +++ b/epicyon.py @@ -181,7 +181,8 @@ def _command_options() -> None: help='Nickname of the account to use') parser.add_argument('--screenreader', dest='screenreader', type=str, default=None, - help='Name of the screen reader: espeak/picospeaker') + help='Name of the screen reader: ' + + 'espeak/picospeaker/mimic3') parser.add_argument('--fol', '--follow', dest='follow', type=str, default=None, help='Handle of account to follow. eg. ' + diff --git a/install-desktop-client b/install-desktop-client index cf15c158c..c1ac5e83b 100755 --- a/install-desktop-client +++ b/install-desktop-client @@ -126,9 +126,24 @@ cp ~/epicyon-client ~/epicyon-client-pico chmod +x ~/epicyon-client-pico sed -i 's|epicyon.py|epicyon.py --screenreader picospeaker|g' ~/epicyon-client-pico +# TTS version with mimic3 +cp ~/epicyon-client ~/epicyon-client-mimic3 +chmod +x ~/epicyon-client-mimic3 +sed -i 's|epicyon.py|epicyon.py --screenreader mimic3|g' ~/epicyon-client-mimic3 + # TTS stream cp ~/epicyon-client ~/epicyon-client-stream chmod +x ~/epicyon-client-stream sed -i 's|epicyon.py|epicyon.py --notifyShowNewPosts --screenreader espeak|g' ~/epicyon-client-stream +# TTS stream +cp ~/epicyon-client ~/epicyon-stream-pico +chmod +x ~/epicyon-stream-pico +sed -i 's|epicyon.py|epicyon.py --notifyShowNewPosts --screenreader picospeaker|g' ~/epicyon-stream-pico + +# TTS stream +cp ~/epicyon-client ~/epicyon-stream-mimic3 +chmod +x ~/epicyon-stream-mimic3 +sed -i 's|epicyon.py|epicyon.py --notifyShowNewPosts --screenreader mimic3|g' ~/epicyon-stream-mimic3 + zenity --info --width=400 --text "Epicyon desktop client is now installed. You can run it with ~/epicyon-client"