├── fifa_voice_assistant.png ├── porcupine_res ├── porcupine_params.pv ├── commands │ ├── skills │ │ ├── turn up_windows.ppn │ │ ├── flick up_windows.ppn │ │ ├── turn down_windows.ppn │ │ ├── turn left_windows.ppn │ │ ├── flick down_windows.ppn │ │ ├── flick left_windows.ppn │ │ ├── flick right_windows.ppn │ │ └── turn right_windows.ppn │ ├── wakewords │ │ └── OkayEA_windows.ppn │ ├── tactics │ │ ├── long ball_windows.ppn │ │ ├── possession_windows.ppn │ │ ├── swap wings_windows.ppn │ │ ├── high pressure_windows.ppn │ │ ├── offside trap_windows.ppn │ │ ├── team pressing_windows.ppn │ │ ├── C B joins attack_windows.ppn │ │ └── counter attack_windows.ppn │ └── celebrations │ │ ├── work out_windows.ppn │ │ └── mannequin_windows.ppn ├── __pycache__ │ └── porcupine.cpython-35.pyc └── porcupine.py ├── README.md ├── directkeys.py ├── voice_assistant_fifa_celebrations.py ├── voice_assistant_fifa_skills.py └── voice_assistant_fifa_tactics.py /fifa_voice_assistant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/fifa_voice_assistant.png -------------------------------------------------------------------------------- /porcupine_res/porcupine_params.pv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/porcupine_params.pv -------------------------------------------------------------------------------- /porcupine_res/commands/skills/turn up_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/turn up_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/__pycache__/porcupine.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/__pycache__/porcupine.cpython-35.pyc -------------------------------------------------------------------------------- /porcupine_res/commands/skills/flick up_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/flick up_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/turn down_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/turn down_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/turn left_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/turn left_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/wakewords/OkayEA_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/wakewords/OkayEA_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/flick down_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/flick down_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/flick left_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/flick left_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/flick right_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/flick right_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/skills/turn right_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/skills/turn right_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/long ball_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/long ball_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/possession_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/possession_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/swap wings_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/swap wings_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/celebrations/work out_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/celebrations/work out_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/high pressure_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/high pressure_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/offside trap_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/offside trap_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/team pressing_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/team pressing_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/celebrations/mannequin_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/celebrations/mannequin_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/C B joins attack_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/C B joins attack_windows.ppn -------------------------------------------------------------------------------- /porcupine_res/commands/tactics/counter attack_windows.ppn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChintanTrivedi/DeepGamingAI_FIFAVA/HEAD/porcupine_res/commands/tactics/counter attack_windows.ppn -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DeepGamingAI_FIFAVA 2 | A voice-assistant for the game of FIFA (windows platform) to control game actions with your voice. 3 | 4 | Click the image below to see the project video on YouTube. 5 | YOUTUBE VIDEO 7 | 8 | # Tutorial/Blog 9 | [Blogpost and tutorial on medium](https://medium.com/@chintan.t93/creating-voice-assistant-for-games-tutorial-for-fifa-71cfbe428bd1) 10 | 11 | # Dependencies 12 | 1. Install porcupine keyword detection engine from [this github repo](https://github.com/Picovoice/Porcupine). 13 | 2. PyAudio 14 | 15 | # How to run 16 | This implementation supports three types of actions:- 17 | 1. Game tactics (team mentality) 18 | 2. Skill moves 19 | 3. Goal celebrations 20 | 21 | Run the respective python scripts to enable keyword detection for these actions. Make sure the key combinations in the code match with those within the game. 22 | 23 | The commands supported for each are under the `porcupine_res/commands` directory. 24 | 25 | # Create custom commands for any game other than FIFA 26 | - Use the porcupine tutorial [here](https://www.youtube.com/watch?v=3z7LBW_Rl9c) to create your own wake words, or use the tutorial [here](https://www.youtube.com/watch?v=YQQ5Bq5HqpQ) to create your custom commands. Place the resultant `.ppn` files under the `porcupine_res/commands` directory and map the key controls in the python scripts with that within the game you are making the voice assistant for. 27 | -------------------------------------------------------------------------------- /directkeys.py: -------------------------------------------------------------------------------- 1 | # direct inputs 2 | # source to this solution and code: 3 | # http://stackoverflow.com/questions/14489013/simulate-python-keypresses-for-controlling-a-game 4 | # http://www.gamespp.com/directx/directInputKeyboardScanCodes.html 5 | 6 | import ctypes 7 | 8 | W = 0x11 9 | Q = 0x10 10 | F = 0x21 11 | spacebar = 0x39 12 | leftarrow = 0xcb 13 | rightarrow = 0xcd 14 | uparrow = 0xc8 15 | downarrow = 0xd0 16 | U = 0x16 17 | J = 0x24 18 | H = 0x23 19 | L = 0x26 20 | E = 0x12 21 | insert = 0xD2 22 | delete = 0xD3 23 | home = 0xC7 24 | end = 0xCF 25 | pageup = 0xC9 26 | pagedown = 0xD1 27 | pad8 = 0x48 28 | pad6 = 0x4D 29 | pad2 = 0x50 30 | pad4 = 0x4B 31 | caps = 0x3A 32 | # C struct redefinitions 33 | PUL = ctypes.POINTER(ctypes.c_ulong) 34 | 35 | 36 | class KeyBdInput(ctypes.Structure): 37 | _fields_ = [("wVk", ctypes.c_ushort), 38 | ("wScan", ctypes.c_ushort), 39 | ("dwFlags", ctypes.c_ulong), 40 | ("time", ctypes.c_ulong), 41 | ("dwExtraInfo", PUL)] 42 | 43 | 44 | class HardwareInput(ctypes.Structure): 45 | _fields_ = [("uMsg", ctypes.c_ulong), 46 | ("wParamL", ctypes.c_short), 47 | ("wParamH", ctypes.c_ushort)] 48 | 49 | 50 | class MouseInput(ctypes.Structure): 51 | _fields_ = [("dx", ctypes.c_long), 52 | ("dy", ctypes.c_long), 53 | ("mouseData", ctypes.c_ulong), 54 | ("dwFlags", ctypes.c_ulong), 55 | ("time", ctypes.c_ulong), 56 | ("dwExtraInfo", PUL)] 57 | 58 | 59 | class Input_I(ctypes.Union): 60 | _fields_ = [("ki", KeyBdInput), 61 | ("mi", MouseInput), 62 | ("hi", HardwareInput)] 63 | 64 | 65 | class Input(ctypes.Structure): 66 | _fields_ = [("type", ctypes.c_ulong), 67 | ("ii", Input_I)] 68 | 69 | 70 | # Actuals Functions 71 | 72 | def PressKey(hexKeyCode): 73 | extra = ctypes.c_ulong(0) 74 | ii_ = Input_I() 75 | ii_.ki = KeyBdInput(0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra)) 76 | x = Input(ctypes.c_ulong(1), ii_) 77 | ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x)) 78 | 79 | 80 | def ReleaseKey(hexKeyCode): 81 | extra = ctypes.c_ulong(0) 82 | ii_ = Input_I() 83 | ii_.ki = KeyBdInput(0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra)) 84 | x = Input(ctypes.c_ulong(1), ii_) 85 | ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x)) 86 | -------------------------------------------------------------------------------- /voice_assistant_fifa_celebrations.py: -------------------------------------------------------------------------------- 1 | import pyaudio 2 | import struct 3 | from datetime import datetime 4 | import time 5 | from porcupine_res.porcupine import Porcupine 6 | from directkeys import * 7 | 8 | porcupine_commands = None 9 | pa = None 10 | audio_stream = None 11 | 12 | try: 13 | porcupine_commands = Porcupine(library_path='porcupine_res/libpv_porcupine.dll', 14 | model_file_path='porcupine_res/porcupine_params.pv', 15 | keyword_file_paths=[ 16 | 'porcupine_res/commands/celebrations/mannequin_windows.ppn', 17 | 'porcupine_res/commands/celebrations/work out_windows.ppn'], 18 | sensitivities=[0.9, 0.9]) 19 | 20 | pa = pyaudio.PyAudio() 21 | audio_stream = pa.open( 22 | rate=porcupine_commands.sample_rate, 23 | channels=1, 24 | format=pyaudio.paInt16, 25 | input=True, 26 | frames_per_buffer=porcupine_commands.frame_length) 27 | 28 | while True: 29 | pcm = audio_stream.read(porcupine_commands.frame_length) 30 | pcm = struct.unpack_from("h" * porcupine_commands.frame_length, pcm) 31 | 32 | command_result = porcupine_commands.process(pcm) 33 | print('...') 34 | if command_result >= 0: 35 | # print('{} detected command: {}'.format(str(datetime.now()), command_result)) 36 | if command_result == 0: 37 | # mannequin 38 | print('Performing celebration: mannequin') 39 | PressKey(caps) 40 | PressKey(pad8) 41 | time.sleep(6) 42 | ReleaseKey(caps) 43 | ReleaseKey(pad8) 44 | elif command_result == 1: 45 | # work out 46 | print('Performing celebration: work out') 47 | PressKey(caps) 48 | PressKey(Q) 49 | time.sleep(0.3) 50 | ReleaseKey(Q) 51 | time.sleep(0.2) 52 | PressKey(Q) 53 | time.sleep(0.3) 54 | ReleaseKey(Q) 55 | ReleaseKey(caps) 56 | 57 | except KeyboardInterrupt: 58 | print('stopping ...') 59 | finally: 60 | if porcupine_commands is not None: 61 | porcupine_commands.delete() 62 | 63 | if audio_stream is not None: 64 | audio_stream.close() 65 | 66 | if pa is not None: 67 | pa.terminate() 68 | -------------------------------------------------------------------------------- /voice_assistant_fifa_skills.py: -------------------------------------------------------------------------------- 1 | import pyaudio 2 | import struct 3 | from datetime import datetime 4 | import time 5 | from porcupine_res.porcupine import Porcupine 6 | from directkeys import * 7 | 8 | porcupine_commands = None 9 | pa = None 10 | audio_stream = None 11 | 12 | try: 13 | porcupine_commands = Porcupine(library_path='porcupine_res/libpv_porcupine.dll', 14 | model_file_path='porcupine_res/porcupine_params.pv', 15 | keyword_file_paths=[ 16 | 'porcupine_res/commands/skills/turn left_windows.ppn', 17 | 'porcupine_res/commands/skills/turn right_windows.ppn', 18 | 'porcupine_res/commands/skills/turn down_windows.ppn', 19 | 'porcupine_res/commands/skills/turn up_windows.ppn', 20 | 'porcupine_res/commands/skills/flick up_windows.ppn', 21 | 'porcupine_res/commands/skills/flick down_windows.ppn', 22 | 'porcupine_res/commands/skills/flick right_windows.ppn', 23 | 'porcupine_res/commands/skills/flick left_windows.ppn'], 24 | sensitivities=[0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]) 25 | 26 | pa = pyaudio.PyAudio() 27 | audio_stream = pa.open( 28 | rate=porcupine_commands.sample_rate, 29 | channels=1, 30 | format=pyaudio.paInt16, 31 | input=True, 32 | frames_per_buffer=porcupine_commands.frame_length) 33 | 34 | while True: 35 | pcm = audio_stream.read(porcupine_commands.frame_length) 36 | pcm = struct.unpack_from("h" * porcupine_commands.frame_length, pcm) 37 | 38 | command_result = porcupine_commands.process(pcm) 39 | print('...') 40 | if command_result >= 0: 41 | # print('{} detected command: {}'.format(str(datetime.now()), command_result)) 42 | if command_result == 0: 43 | # turn left 44 | print('Performing skill: turn left') 45 | PressKey(pad8) 46 | PressKey(pad6) 47 | time.sleep(0.5) 48 | ReleaseKey(pad8) 49 | ReleaseKey(pad6) 50 | time.sleep(0.5) 51 | PressKey(pad8) 52 | PressKey(pad6) 53 | time.sleep(0.5) 54 | ReleaseKey(pad8) 55 | ReleaseKey(pad6) 56 | elif command_result == 1: 57 | # turn right 58 | print('Performing skill: turn right') 59 | PressKey(pad8) 60 | PressKey(pad4) 61 | time.sleep(0.5) 62 | ReleaseKey(pad8) 63 | ReleaseKey(pad4) 64 | time.sleep(0.5) 65 | PressKey(pad8) 66 | PressKey(pad4) 67 | time.sleep(0.5) 68 | ReleaseKey(pad8) 69 | ReleaseKey(pad4) 70 | elif command_result == 2: 71 | # turn down 72 | print('Performing skill: turn down') 73 | PressKey(pad4) 74 | PressKey(pad2) 75 | time.sleep(0.5) 76 | ReleaseKey(pad4) 77 | ReleaseKey(pad2) 78 | time.sleep(0.5) 79 | PressKey(pad4) 80 | PressKey(pad2) 81 | time.sleep(0.5) 82 | ReleaseKey(pad4) 83 | ReleaseKey(pad2) 84 | elif command_result == 3: 85 | # turn up 86 | print('Performing skill: turn up') 87 | PressKey(pad6) 88 | PressKey(pad2) 89 | time.sleep(0.5) 90 | ReleaseKey(pad6) 91 | ReleaseKey(pad2) 92 | time.sleep(0.5) 93 | PressKey(pad6) 94 | PressKey(pad2) 95 | time.sleep(0.5) 96 | ReleaseKey(pad6) 97 | ReleaseKey(pad2) 98 | elif command_result == 4: 99 | # flick up 100 | print('Performing skill: flick up') 101 | PressKey(pad2) 102 | time.sleep(0.3) 103 | ReleaseKey(pad2) 104 | time.sleep(0.1) 105 | PressKey(pad8) 106 | time.sleep(0.3) 107 | ReleaseKey(pad8) 108 | time.sleep(0.3) 109 | PressKey(pad8) 110 | time.sleep(0.3) 111 | ReleaseKey(pad8) 112 | elif command_result == 5: 113 | # flick down 114 | print('Performing skill: flick down') 115 | PressKey(pad8) 116 | time.sleep(0.3) 117 | ReleaseKey(pad8) 118 | time.sleep(0.1) 119 | PressKey(pad2) 120 | time.sleep(0.3) 121 | ReleaseKey(pad2) 122 | time.sleep(0.3) 123 | PressKey(pad2) 124 | time.sleep(0.3) 125 | ReleaseKey(pad2) 126 | elif command_result == 6: 127 | # flick right 128 | print('Performing skill: flick right') 129 | PressKey(pad4) 130 | time.sleep(0.3) 131 | ReleaseKey(pad4) 132 | time.sleep(0.1) 133 | PressKey(pad6) 134 | time.sleep(0.3) 135 | ReleaseKey(pad6) 136 | time.sleep(0.3) 137 | PressKey(pad6) 138 | time.sleep(0.3) 139 | ReleaseKey(pad6) 140 | elif command_result == 7: 141 | # flick left 142 | print('Performing skill: flick left') 143 | PressKey(pad6) 144 | time.sleep(0.3) 145 | ReleaseKey(pad6) 146 | time.sleep(0.1) 147 | PressKey(pad4) 148 | time.sleep(0.3) 149 | ReleaseKey(pad4) 150 | time.sleep(0.3) 151 | PressKey(pad4) 152 | time.sleep(0.3) 153 | ReleaseKey(pad4) 154 | 155 | except KeyboardInterrupt: 156 | print('stopping ...') 157 | finally: 158 | if porcupine_commands is not None: 159 | porcupine_commands.delete() 160 | 161 | if audio_stream is not None: 162 | audio_stream.close() 163 | 164 | if pa is not None: 165 | pa.terminate() 166 | -------------------------------------------------------------------------------- /voice_assistant_fifa_tactics.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import time 3 | 4 | import pyaudio 5 | 6 | from directkeys import * 7 | from porcupine_res.porcupine import Porcupine 8 | 9 | porcupine_wakeword = None 10 | pa = None 11 | audio_stream = None 12 | awake = False 13 | start_time = None 14 | wake_time = 5000 # ms 15 | try: 16 | porcupine_wakeword = Porcupine(library_path='porcupine_res/libpv_porcupine.dll', 17 | model_file_path='porcupine_res/porcupine_params.pv', 18 | keyword_file_paths=['porcupine_res/commands/wakewords/OkayEA_windows.ppn'], 19 | sensitivities=[0.9]) 20 | 21 | porcupine_commands = Porcupine(library_path='porcupine_res/libpv_porcupine.dll', 22 | model_file_path='porcupine_res/porcupine_params.pv', 23 | keyword_file_paths=[ 24 | 'porcupine_res/commands/tactics/C B joins attack_windows.ppn', 25 | 'porcupine_res/commands/tactics/team pressing_windows.ppn', 26 | 'porcupine_res/commands/tactics/swap wings_windows.ppn', 27 | 'porcupine_res/commands/tactics/offside trap_windows.ppn', 28 | 'porcupine_res/commands/tactics/long ball_windows.ppn', 29 | 'porcupine_res/commands/tactics/possession_windows.ppn', 30 | 'porcupine_res/commands/tactics/counter attack_windows.ppn', 31 | 'porcupine_res/commands/tactics/high pressure_windows.ppn'], 32 | sensitivities=[0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9, 0.9]) 33 | 34 | pa = pyaudio.PyAudio() 35 | audio_stream = pa.open( 36 | rate=porcupine_wakeword.sample_rate, 37 | channels=1, 38 | format=pyaudio.paInt16, 39 | input=True, 40 | frames_per_buffer=porcupine_wakeword.frame_length) 41 | 42 | while True: 43 | pcm = audio_stream.read(porcupine_wakeword.frame_length) 44 | pcm = struct.unpack_from("h" * porcupine_wakeword.frame_length, pcm) 45 | 46 | if not awake: 47 | print('...') 48 | result = porcupine_wakeword.process(pcm) 49 | if result: 50 | awake = True 51 | start_time = time.time() 52 | print('Voice Assistant activated, give command...') 53 | else: 54 | if (time.time() - start_time) * 1000 > wake_time: 55 | print('Voice assistant going back to sleep') 56 | awake = False 57 | command_result = porcupine_commands.process(pcm) 58 | if command_result >= 0: 59 | # print('{} detected command: {}'.format(str(datetime.now()), command_result)) 60 | if command_result == 0: 61 | # C B joins attack 62 | print('Activating - C B joins attack') 63 | PressKey(home) 64 | time.sleep(0.3) 65 | ReleaseKey(home) 66 | time.sleep(1) 67 | PressKey(pagedown) 68 | time.sleep(0.3) 69 | ReleaseKey(pagedown) 70 | elif command_result == 1: 71 | # team pressing 72 | print('Activating - team pressing') 73 | PressKey(home) 74 | time.sleep(0.3) 75 | ReleaseKey(home) 76 | time.sleep(1) 77 | PressKey(end) 78 | time.sleep(0.3) 79 | ReleaseKey(end) 80 | elif command_result == 2: 81 | # swap wings 82 | print('Activating - swap wings') 83 | PressKey(home) 84 | time.sleep(0.3) 85 | ReleaseKey(home) 86 | time.sleep(1) 87 | PressKey(delete) 88 | time.sleep(0.3) 89 | ReleaseKey(delete) 90 | elif command_result == 3: 91 | # offside trap 92 | print('Activating - offside trap') 93 | PressKey(home) 94 | time.sleep(0.3) 95 | ReleaseKey(home) 96 | time.sleep(1) 97 | PressKey(home) 98 | time.sleep(0.3) 99 | ReleaseKey(home) 100 | elif command_result == 4: 101 | # long ball 102 | print('Activating - long ball') 103 | PressKey(end) 104 | time.sleep(0.3) 105 | ReleaseKey(end) 106 | time.sleep(1) 107 | PressKey(pagedown) 108 | time.sleep(0.3) 109 | ReleaseKey(pagedown) 110 | elif command_result == 5: 111 | # possession 112 | print('Activating - possession') 113 | PressKey(end) 114 | time.sleep(0.3) 115 | ReleaseKey(end) 116 | time.sleep(1) 117 | PressKey(delete) 118 | time.sleep(0.3) 119 | ReleaseKey(delete) 120 | elif command_result == 6: 121 | # counter attack 122 | print('Activating - counter attack') 123 | PressKey(end) 124 | time.sleep(0.3) 125 | ReleaseKey(end) 126 | time.sleep(1) 127 | PressKey(home) 128 | time.sleep(0.3) 129 | ReleaseKey(home) 130 | elif command_result == 7: 131 | # high pressure 132 | print('Activating - high pressure') 133 | PressKey(end) 134 | time.sleep(0.3) 135 | ReleaseKey(end) 136 | time.sleep(1) 137 | PressKey(end) 138 | time.sleep(0.3) 139 | ReleaseKey(end) 140 | 141 | # Put back to sleep state after executing command 142 | awake = False 143 | 144 | except KeyboardInterrupt: 145 | print('stopping ...') 146 | finally: 147 | if porcupine_wakeword is not None: 148 | porcupine_wakeword.delete() 149 | 150 | if audio_stream is not None: 151 | audio_stream.close() 152 | 153 | if pa is not None: 154 | pa.terminate() 155 | -------------------------------------------------------------------------------- /porcupine_res/porcupine.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018 Picovoice Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | import os 18 | from ctypes import * 19 | from enum import Enum 20 | 21 | 22 | class Porcupine(object): 23 | """Python binding for Picovoice's wake word detection (aka Porcupine) library.""" 24 | 25 | class PicovoiceStatuses(Enum): 26 | """Status codes corresponding to 'pv_status_t' defined in 'include/picovoice.h'""" 27 | 28 | SUCCESS = 0 29 | OUT_OF_MEMORY = 1 30 | IO_ERROR = 2 31 | INVALID_ARGUMENT = 3 32 | 33 | _PICOVOICE_STATUS_TO_EXCEPTION = { 34 | PicovoiceStatuses.OUT_OF_MEMORY: MemoryError, 35 | PicovoiceStatuses.IO_ERROR: IOError, 36 | PicovoiceStatuses.INVALID_ARGUMENT: ValueError 37 | } 38 | 39 | class CPorcupine(Structure): 40 | pass 41 | 42 | def __init__( 43 | self, 44 | library_path, 45 | model_file_path, 46 | keyword_file_path=None, 47 | sensitivity=None, 48 | keyword_file_paths=None, 49 | sensitivities=None): 50 | """ 51 | Loads Porcupine's shared library and creates an instance of wake word detection object. 52 | 53 | :param library_path: Absolute path to Porcupine's shared library. 54 | :param model_file_path: Absolute path to file containing model parameters. 55 | :param keyword_file_path: Absolute path to keyword file containing hyper-parameters. If not present then 56 | 'keyword_file_paths' will be used. 57 | :param sensitivity: Sensitivity parameter. A higher sensitivity value lowers miss rate at the cost of increased 58 | false alarm rate. For more information regarding this parameter refer to 'include/pv_porcupine.h'. If not 59 | present then 'sensitivities' is used. 60 | :param keyword_file_paths: List of absolute paths to keyword files. Intended to be used for multiple keyword 61 | scenario. This parameter is used only when 'keyword_file_path' is not set. 62 | :param sensitivities: List of sensitivity parameters. Intended to be used for multiple keyword scenario. This 63 | parameter is used only when 'sensitivity' is not set. 64 | """ 65 | 66 | if not os.path.exists(library_path): 67 | raise IOError("Could not find Porcupine's library at '%s'" % library_path) 68 | 69 | library = cdll.LoadLibrary(library_path) 70 | 71 | if not os.path.exists(model_file_path): 72 | raise IOError("Could not find model file at '%s'" % model_file_path) 73 | 74 | if sensitivity is not None and keyword_file_path is not None: 75 | if not os.path.exists(keyword_file_path): 76 | raise IOError("Could not find keyword file at '%s'" % keyword_file_path) 77 | keyword_file_paths = [keyword_file_path] 78 | 79 | if not (0 <= sensitivity <= 1): 80 | raise ValueError('Sensitivity should be within [0, 1]') 81 | sensitivities = [sensitivity] 82 | elif sensitivities is not None and keyword_file_paths is not None: 83 | if len(keyword_file_paths) != len(sensitivities): 84 | raise ValueError("Different number of sensitivity and keyword file path parameters are provided.") 85 | 86 | for x in keyword_file_paths: 87 | if not os.path.exists(os.path.expanduser(x)): 88 | raise IOError("Could not find keyword file at '%s'" % x) 89 | 90 | for x in sensitivities: 91 | if not (0 <= x <= 1): 92 | raise ValueError('Sensitivity should be within [0, 1]') 93 | else: 94 | raise ValueError("Sensitivity and/or keyword file path is missing") 95 | 96 | self._num_keywords = len(keyword_file_paths) 97 | 98 | init_func = library.pv_porcupine_multiple_keywords_init 99 | init_func.argtypes = [ 100 | c_char_p, 101 | c_int, 102 | POINTER(c_char_p), 103 | POINTER(c_float), 104 | POINTER(POINTER(self.CPorcupine))] 105 | init_func.restype = self.PicovoiceStatuses 106 | 107 | self._handle = POINTER(self.CPorcupine)() 108 | 109 | status = init_func( 110 | model_file_path.encode(), 111 | self._num_keywords, 112 | (c_char_p * self._num_keywords)(*[os.path.expanduser(x).encode() for x in keyword_file_paths]), 113 | (c_float * self._num_keywords)(*sensitivities), 114 | byref(self._handle)) 115 | if status is not self.PicovoiceStatuses.SUCCESS: 116 | raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]('Initialization failed') 117 | 118 | self.process_func = library.pv_porcupine_multiple_keywords_process 119 | self.process_func.argtypes = [POINTER(self.CPorcupine), POINTER(c_short), POINTER(c_int)] 120 | self.process_func.restype = self.PicovoiceStatuses 121 | 122 | self._delete_func = library.pv_porcupine_delete 123 | self._delete_func.argtypes = [POINTER(self.CPorcupine)] 124 | self._delete_func.restype = None 125 | 126 | self._sample_rate = library.pv_sample_rate() 127 | self._frame_length = library.pv_porcupine_frame_length() 128 | 129 | @property 130 | def sample_rate(self): 131 | """Audio sample rate accepted by Porcupine library.""" 132 | 133 | return self._sample_rate 134 | 135 | @property 136 | def frame_length(self): 137 | """Number of audio samples per frame expected by C library.""" 138 | 139 | return self._frame_length 140 | 141 | def process(self, pcm): 142 | """ 143 | Monitors incoming audio stream for given wake word(s). 144 | 145 | :param pcm: An array (or array-like) of consecutive audio samples. For more information regarding required audio 146 | properties (i.e. sample rate, number of channels encoding, and number of samples per frame) please refer to 147 | 'include/pv_porcupine.h'. 148 | :return: For a single wake-word use cse True if wake word is detected. For multiple wake-word use case it 149 | returns the index of detected wake-word. Indexing is 0-based and according to ordering of input keyword file 150 | paths. It returns -1 when no keyword is detected. 151 | """ 152 | 153 | result = c_int() 154 | status = self.process_func(self._handle, (c_short * len(pcm))(*pcm), byref(result)) 155 | if status is not self.PicovoiceStatuses.SUCCESS: 156 | raise self._PICOVOICE_STATUS_TO_EXCEPTION[status]('Processing failed') 157 | 158 | keyword_index = result.value 159 | 160 | if self._num_keywords == 1: 161 | return keyword_index == 0 162 | else: 163 | return keyword_index 164 | 165 | def delete(self): 166 | """Releases resources acquired by Porcupine's library.""" 167 | 168 | self._delete_func(self._handle) 169 | --------------------------------------------------------------------------------