Пакет porcupine поставляется с демонстрацией того, как использовать дикобраза в неблокирующем режиме, что необходимо для того, чтобы mainloop
мог обрабатывать события tkinter. Ключ заключается в том, чтобы прикрепить обратный вызов к аудиопотоку.
Я никогда не использовал дикобраза прежде, поэтому я не знаю, насколько хорошо это работает в реальном мире, но оно работает для меня на моем Mac и не требует явной многопоточности.
import sys
sys.path.append("/tmp/Porcupine/binding/python")
import Tkinter as tk
import struct
from datetime import datetime
from porcupine import Porcupine
import pyaudio
library_path = "/tmp/Porcupine/lib/mac/x86_64/libpv_porcupine.dylib"
model_file_path = "/tmp/Porcupine/lib/common/porcupine_params.pv"
keyword_file_paths = ["/tmp/Porcupine/words_mac.ppn",]
num_keywords = len(keyword_file_paths)
sensitivities = [0.5] * num_keywords
class TkPorcupine(object):
def __init__(self):
self.initialize_ui()
self.initialize_porcupine()
def initialize_ui(self):
self.state = False
self.root = tk.Tk()
self.text = tk.Text(self.root, width=60, height=8)
self.vsb = tk.Scrollbar(self.root, orient="vertical", command=self.text.yview)
self.text.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.text.pack(fill="both", expand=True)
def initialize_porcupine(self):
self.porcupine = Porcupine(library_path, model_file_path,
keyword_file_paths=keyword_file_paths,
sensitivities=sensitivities)
self.audio_stream = pyaudio.PyAudio().open(
rate=self.porcupine.sample_rate,
channels=1,
format=pyaudio.paInt16,
input=True,
frames_per_buffer=self.porcupine.frame_length,
input_device_index=None,
stream_callback=self.audio_callback)
self.audio_stream.start_stream()
def audio_callback(self, in_data, frame_count, time_info, status):
if frame_count >= self.porcupine.frame_length:
pcm = struct.unpack_from("h" * self.porcupine.frame_length, in_data)
result = self.porcupine.process(pcm)
if num_keywords == 1 and result:
message = '[%s] detected keyword' % str(datetime.now())
self.text.insert("end", message + "\n")
self.text.see("end")
elif num_keywords > 1 and result >= 0:
message = '[%s] detected keyword #%d' % (str(datetime.now()), result)
self.text.insert("end", message + "\n")
self.text.see("end")
return None, pyaudio.paContinue
if __name__ == '__main__':
demo = TkPorcupine()
tk.mainloop()