class SoundEffectEngine(EffectEngine): def __init__(self, queue): super().__init__(queue) self._name = "SoundEffectEngine" self._chunk = 1024 self._player = pyaudio.PyAudio() self._wav_dir = config.SOUNDFILE_DIR self._wav_files = {} self._cur_wav_file = None self._stream = None self._dataFile = open("history.csv", "w") self._dataWriter = csv.writer(self._dataFile, delimiter=",", quotechar='"', quoting=csv.QUOTE_MINIMAL) self._currentBpms = RingBuffer(config.AVG_WINDOW) self._heartbeat = config.HEARTBEAT_TIMEOUT if config.BPM_RANGE_LOW >= config.BPM_RANGE_HIGH: raise ValueError( "BPM Ranges are not configured correctly in config") def read_wav_files(self): self._wav_files = [ join(self._wav_dir, f) for f in listdir(self._wav_dir) if isfile(join(self._wav_dir, f)) and ".wav" in f ] self._wav_files = natsorted(self._wav_files, key=lambda y: y.lower()) if len(self._wav_files) < 1: raise FileNotFoundError("No wav files found in given directory.") def run(self): print("Starting " + self._name) self.read_wav_files() self.effect_loop() def shutdown_audio(self): self._cur_wav_file.close() self._stream.stop_stream() try: self._player.close(self._stream) except ValueError: pass def idle(self): print(self._name + " idling..") self.shutdown_audio() self._currentBpms.reset() while not self._stop_event.is_set(): try: bpm = self._queue.get(timeout=2) if bpm > 0: self._currentBpms.append(bpm) self.open_wav_file() self._heartbeat = config.HEARTBEAT_TIMEOUT break except queue.Empty: pass def poll_bpm(self): try: bpm = self._queue.get_nowait() self._heartbeat = config.HEARTBEAT_TIMEOUT if bpm > 0: self._currentBpms.append(bpm) self._bpmHistory.append(bpm) # write into csv self._dataWriter.writerow([bpm]) self._dataFile.flush() # save data history except queue.Empty: self._heartbeat = self._heartbeat - 1 def open_wav_file(self): index = self.choose_wav_file() self._cur_wav_file = wave.open(self._wav_files[index], "rb") self._stream = self._player.open( format=self._player.get_format_from_width( self._cur_wav_file.getsampwidth()), channels=self._cur_wav_file.getnchannels(), rate=self._cur_wav_file.getframerate(), output=True) def choose_wav_file(self): if self._currentBpms.get_len() is 0: return 0 if config.SOUND_MODE is config.SoundMode.AVERAGE: bpm = self._currentBpms.get_sum() / self._currentBpms.get_len() limited_bpm = config.BPM_RANGE_LOW if bpm < config.BPM_RANGE_LOW else \ config.BPM_RANGE_HIGH if bpm > config.BPM_RANGE_HIGH else bpm total_range = config.BPM_RANGE_HIGH - config.BPM_RANGE_LOW index = math.floor((limited_bpm - config.BPM_RANGE_LOW) / math.ceil(total_range / len(self._wav_files))) elif config.SOUND_MODE is config.SoundMode.DIFFERENCE: diff = max(self._currentBpms.get()) - min(self._currentBpms.get()) if diff > len(self._wav_files) - 1: diff = len(self._wav_files) - 1 index = diff print(index) return index def effect_loop(self): self.poll_bpm() self.open_wav_file() try: while True: if self._stop_event.is_set(): self.shutdown_audio() return data = self._cur_wav_file.readframes(self._chunk) while data != b'': self._stream.write(data) data = self._cur_wav_file.readframes(self._chunk) self.poll_bpm() if self._heartbeat is 0: self.idle() else: self.shutdown_audio() self.open_wav_file() time.sleep(0.1) except KeyboardInterrupt: print("Got interrupt, crunching Data...")