16 from datetime
import datetime
17 from threading
import Thread
20 from pvrecorder
import PvRecorder
25 Microphone Demo for Porcupine wake word engine. It creates an input audio stream from a microphone, monitors it, and
26 upon detecting the specified wake word(s) prints the detection time and wake word on console. It optionally saves
27 the recorded audio into a file for further debugging.
37 input_device_index=None,
43 :param library_path: Absolute path to Porcupine's dynamic library.
44 :param model_path: Absolute path to the file containing model parameters.
45 :param keyword_paths: Absolute paths to keyword model files.
46 :param sensitivities: Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A
47 higher sensitivity results in fewer misses at the cost of increasing the false alarm rate. If not set 0.5 will
49 :param input_device_index: Optional argument. If provided, audio is recorded from this input device. Otherwise,
50 the default audio input device is used.
51 :param output_path: If provided recorded audio will be stored in this location at the end of the run.
54 super(PorcupineDemo, self).
__init__()
67 Creates an input audio stream, instantiates an instance of Porcupine object, and monitors the audio stream for
68 occurrences of the wake word(s). It prints the time of detection for each occurrence and the wake word.
73 keyword_phrase_part = os.path.basename(x).replace(
'.ppn',
'').split(
'_')
74 if len(keyword_phrase_part) > 6:
75 keywords.append(
' '.join(keyword_phrase_part[0:-6]))
77 keywords.append(keyword_phrase_part[0])
83 porcupine = pvporcupine.create(
90 recorder = PvRecorder(device_index=self.
_input_device_index, frame_length=porcupine.frame_length)
95 wav_file.setparams((1, 2, 16000, 512,
"NONE",
"NONE"))
97 print(f
'Using device: {recorder.selected_device}')
101 print(
' %s (%.2f)' % (keyword, sensitivity))
105 pcm = recorder.read()
107 if wav_file
is not None:
108 wav_file.writeframes(struct.pack(
"h" * len(pcm), *pcm))
110 result = porcupine.process(pcm)
112 print(
'[%s] Detected %s' % (str(datetime.now()), keywords[result]))
113 except pvporcupine.PorcupineInvalidArgumentError
as e:
114 print(
"One or more arguments provided to Porcupine is invalid: {\n" +
115 f
"\t{self._access_key=}\n" +
116 f
"\t{self._library_path=}\n" +
117 f
"\t{self._model_path=}\n" +
118 f
"\t{self._keyword_paths=}\n" +
119 f
"\t{self._sensitivities=}\n" +
121 print(f
"If all other arguments seem valid, ensure that '{self._access_key}' is a valid AccessKey")
123 except pvporcupine.PorcupineActivationError
as e:
124 print(
"AccessKey activation error")
126 except pvporcupine.PorcupineActivationLimitError
as e:
127 print(f
"AccessKey '{self._access_key}' has reached it's temporary device limit")
129 except pvporcupine.PorcupineActivationRefusedError
as e:
130 print(f
"AccessKey '{self._access_key}' refused")
132 except pvporcupine.PorcupineActivationThrottledError
as e:
133 print(f
"AccessKey '{self._access_key}' has been throttled")
135 except pvporcupine.PorcupineError
as e:
136 print(f
"Failed to initialize Porcupine")
138 except KeyboardInterrupt:
139 print(
'Stopping ...')
141 if porcupine
is not None:
144 if recorder
is not None:
147 if wav_file
is not None:
152 devices = PvRecorder.get_audio_devices()
154 for i
in range(len(devices)):
155 print(f
'index: {i}, device name: {devices[i]}')
159 parser = argparse.ArgumentParser()
161 parser.add_argument(
'--access_key',
162 help=
'AccessKey obtained from Picovoice Console (https://picovoice.ai/console/)')
167 help=
'List of default keywords for detection. Available keywords: %s' %
', '.join(sorted(pvporcupine.KEYWORDS)),
168 choices=sorted(pvporcupine.KEYWORDS),
174 help=
"Absolute paths to keyword model files. If not set it will be populated from `--keywords` argument")
176 parser.add_argument(
'--library_path', help=
'Absolute path to dynamic library.', default=pvporcupine.LIBRARY_PATH)
180 help=
'Absolute path to the file containing model parameters.',
181 default=pvporcupine.MODEL_PATH)
186 help=
"Sensitivities for detecting keywords. Each value should be a number within [0, 1]. A higher " +
187 "sensitivity results in fewer misses at the cost of increasing the false alarm rate. If not set 0.5 " +
192 parser.add_argument(
'--audio_device_index', help=
'Index of input audio device.', type=int, default=-1)
194 parser.add_argument(
'--output_path', help=
'Absolute path to recorded audio for debugging.', default=
None)
196 parser.add_argument(
'--show_audio_devices', action=
'store_true')
198 args = parser.parse_args()
200 if args.show_audio_devices:
201 PorcupineDemo.show_audio_devices()
203 if args.access_key
is None:
204 raise ValueError(
"AccessKey (--access_key) is required")
205 if args.keyword_paths
is None:
206 if args.keywords
is None:
207 raise ValueError(
"Either `--keywords` or `--keyword_paths` must be set.")
209 keyword_paths = [pvporcupine.KEYWORD_PATHS[x]
for x
in args.keywords]
211 keyword_paths = args.keyword_paths
213 if args.sensitivities
is None:
214 args.sensitivities = [0.5] * len(keyword_paths)
216 if len(keyword_paths) != len(args.sensitivities):
217 raise ValueError(
'Number of keywords does not match the number of sensitivities.')
220 access_key=args.access_key,
221 library_path=args.library_path,
222 model_path=args.model_path,
223 keyword_paths=keyword_paths,
224 sensitivities=args.sensitivities,
225 output_path=args.output_path,
226 input_device_index=args.audio_device_index).run()
229 if __name__ ==
'__main__':