def _callback(self, in_data, frame_count, time_info, status): if self.status & self.recording_mask: pass if self.status & self.detecting_mask: self.detect_queue.put(in_data) if self.status & self.listening_mask: active = vad.is_speech(in_data) if active: if not self.active: for d in self.listen_history: self.listen_queue.put(d) self.listen_countdown[0] -= 1 self.listen_history.clear() self.listen_queue.put(in_data) self.listen_countdown[0] -= 1 else: if self.active: self.listen_queue.put(in_data) else: self.listen_history.append(in_data) self.listen_countdown[1] -= 1 if self.listen_countdown[0] <= 0 or self.listen_countdown[1] <= 0: self.listen_queue.put('') self.status &= ~self.listening_mask logger.info('Stop listening') self.active = active return None, pyaudio.paContinue
def main(): sample_rate = 48000 channels = 2 N = 4096 * 4 mic = Microphone(sample_rate, channels) window = np.hanning(N) sound_speed = 343 distance = 0.14 max_tau = distance / sound_speed def signal_handler(sig, num): print('Quit') mic.close() signal.signal(signal.SIGINT, signal_handler) for data in mic.read_chunks(N): buf = np.fromstring(data, dtype='int16') mono = buf[0::channels].tostring() if sample_rate != 16000: mono, _ = audioop.ratecv(mono, 2, 1, sample_rate, 16000, None) if vad.is_speech(mono): tau, _ = gcc_phat(buf[0::channels] * window, buf[1::channels] * window, fs=sample_rate, max_tau=max_tau) theta = math.asin(tau / max_tau) * 180 / math.pi print('\ntheta: {}'.format(int(theta)))
def start(self, detected_callback=play_audio_file, interrupt_check=lambda: False, sleep_time=0.03): """ Start the voice detector. For every `sleep_time` second it checks the audio buffer for triggering keywords. If detected, then call corresponding function in `detected_callback`, which can be a single function (single model) or a list of callback functions (multiple models). Every loop it also calls `interrupt_check` -- if it returns True, then breaks from the loop and return. :param detected_callback: a function or list of functions. The number of items must match the number of models in `decoder_model`. :param interrupt_check: a function that returns True if the main loop needs to stop. :param float sleep_time: how much time in second every loop waits. :return: None """ if interrupt_check(): logger.debug("detect voice return") return tc = type(detected_callback) if tc is not list: detected_callback = [detected_callback] if len(detected_callback) == 1 and self.num_hotwords > 1: detected_callback *= self.num_hotwords assert self.num_hotwords == len(detected_callback), \ "Error: hotwords in your models (%d) do not match the number of " \ "callbacks (%d)" % (self.num_hotwords, len(detected_callback)) logger.debug("detecting...") while True: if interrupt_check(): logger.debug("detect voice break") break data = self.ring_buffer.get() if len(data) == 0: time.sleep(sleep_time) continue ans = self.detector.RunDetection(data) if ans == -1: logger.warning( "Error initializing streams or reading audio data") elif ans > 0: message = "Keyword " + str(ans) + " detected at time: " message += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) logger.info(message) play_audio_file(fname=DETECT_DING) callback = detected_callback[ans - 1] if callback is not None: listen = True listen_history = [] cnt = 0 VAD_DELAY = 0.2 MAX_CNT = int(3 / VAD_DELAY) vad_trig = False vad.reset() while listen: data = self.ring_buffer.get() active = vad.is_speech(data) if active and cnt > 1: vad_trig = True ans = self.detector.RunDetection(data) logger.info("Detection status: %d, VAD: %s" % (ans, active)) if ans == 1: listen_history = [] continue elif ans == 0: listen_history.extend(data) cnt += 1 if cnt > MAX_CNT: listen = False elif vad_trig and not active: listen = False elif ans == -2: if not vad_trig: listen_history = [] cnt += 1 if cnt > MAX_CNT: listen = False # elif vad_trig and not active: # listen_history.extend(data) else: time.sleep(VAD_DELAY) continue listen = False time.sleep(VAD_DELAY) if len(listen_history) > 0: callback(listen_history, rate=self.detector.SampleRate())