diff --git a/precise/_coninput.py b/precise/_coninput.py new file mode 100644 index 00000000..42ed3644 --- /dev/null +++ b/precise/_coninput.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Copyright 2019 Mycroft AI Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Platform independent console Input abstraction +""" +from abc import abstractmethod + +from os import name as os_name + +from typing import AnyStr + +if os_name == 'nt': + import msvcrt +else: + from select import select + from sys import stdin + from termios import tcsetattr, tcgetattr, TCSADRAIN + import tty + + +class InputInterface: + + @abstractmethod + def key_pressed(self) -> bool: + pass + + @abstractmethod + def show_input(self): + pass + + @abstractmethod + def hide_input(self): + pass + + @abstractmethod + def read_key(self) -> AnyStr: + pass + + +class POSIXInput(InputInterface): + + def __init__(self): + self.orig_settings = tcgetattr(stdin) + + def key_pressed(self) -> bool: + return select([stdin], [], [], 0) == ([stdin], [], []) + + def show_input(self): + tcsetattr(stdin, TCSADRAIN, self.orig_settings) + + def hide_input(self): + tty.setcbreak(stdin.fileno()) + + def read_key(self) -> AnyStr: + return stdin.read(1) + + +class WindowsInput(InputInterface): + + def __init__(self): + self.input_shown = True + + def key_pressed(self) -> bool: + return msvcrt.kbhit() + + def show_input(self): + self.input_shown = True + pass + + def hide_input(self): + self.input_shown = False + pass + + def read_key(self) -> AnyStr: + if self.input_shown: + char = msvcrt.getche() + else: + char = msvcrt.getch() + return char.decode('utf-8') + + +def get_input() -> InputInterface: + if os_name == "nt": + return WindowsInput() + else: + return POSIXInput() diff --git a/precise/scripts/collect.py b/precise/scripts/collect.py index 09f4f595..02ae966a 100644 --- a/precise/scripts/collect.py +++ b/precise/scripts/collect.py @@ -24,12 +24,10 @@ :-c --channels int 1 Number of audio channels """ -from select import select -from sys import stdin -from termios import tcsetattr, tcgetattr, TCSADRAIN -import tty + import wave +from precise import _coninput from os.path import isfile from prettyparse import Usage from pyaudio import PyAudio @@ -70,17 +68,8 @@ class CollectScript(BaseScript): def __init__(self, args): super().__init__(args) - self.orig_settings = tcgetattr(stdin) self.p = PyAudio() - - def key_pressed(self): - return select([stdin], [], [], 0) == ([stdin], [], []) - - def show_input(self): - tcsetattr(stdin, TCSADRAIN, self.orig_settings) - - def hide_input(self): - tty.setcbreak(stdin.fileno()) + self.input = _coninput.get_input() def next_name(self, name): name += '.wav' @@ -106,7 +95,7 @@ def get_name(i): def wait_to_continue(self): while True: - c = stdin.read(1) + c = self.input.read_key() if c == self.RECORD_KEY: return True elif ord(c) == self.EXIT_KEY_CODE: @@ -114,16 +103,16 @@ def wait_to_continue(self): def record_until_key(self): def should_return(): - return self.key_pressed() and stdin.read(1) == self.RECORD_KEY + return self.input.key_pressed() and self.input.read_key() == self.RECORD_KEY return record_until(self.p, should_return, self.args) def _run(self): args = self.args - self.show_input() + self.input.show_input() args.file_label = args.file_label or input("File label (Ex. recording-##): ") args.file_label = args.file_label + ('' if '#' in args.file_label else '-##') - self.hide_input() + self.input.hide_input() while True: print('Press space to record (esc to exit)...') @@ -139,10 +128,10 @@ def _run(self): def run(self): try: - self.hide_input() + self.input.hide_input() self._run() finally: - tcsetattr(stdin, TCSADRAIN, self.orig_settings) + self.input.show_input() self.p.terminate() diff --git a/precise/util.py b/precise/util.py index 4971eccf..985600a7 100644 --- a/precise/util.py +++ b/precise/util.py @@ -77,13 +77,8 @@ def play_audio(filename: str): Args: filename: Audio filename """ - import platform - from subprocess import Popen - - if platform.system() == 'Darwin': - Popen(['afplay', filename]) - else: - Popen(['aplay', '-q', filename]) + from playsound import playsound + playsound(filename, block=False) def activate_notify(): diff --git a/requirements.txt b/requirements.txt index 38f303f4..dc14aafc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -42,3 +42,4 @@ tqdm==4.31.1 typing==3.6.6 wavio==0.0.4 Werkzeug==0.15.3 +playsound diff --git a/requirements/prod.txt b/requirements/prod.txt index bf6b1033..119dd775 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -3,7 +3,7 @@ tensorflow>=1.13,<1.14 # Must be on piwheels sonopy pyaudio keras<=2.1.5 -h5py +h5py<3.0.0 wavio typing prettyparse>=1.1.0 @@ -12,3 +12,4 @@ attrs fitipy<1.0 speechpy-fast pyache +playsound \ No newline at end of file diff --git a/setup.py b/setup.py index 44a9916b..af0d8caa 100644 --- a/setup.py +++ b/setup.py @@ -76,7 +76,7 @@ 'sonopy', 'pyaudio', 'keras<=2.1.5', - 'h5py', + 'h5py<3.0.0', 'wavio', 'typing', 'prettyparse>=1.1.0', @@ -84,6 +84,7 @@ 'attrs', 'fitipy<1.0', 'speechpy-fast', - 'pyache' + 'pyache', + 'playsound' ] )