import sounddevice as sd import audioop import time frame_rate = 44100 channels = 2 sample_width = 2 class Mixer: def __init__(self): self.stream = sd.RawOutputStream(samplerate=frame_rate, channels=channels, dtype='int' + str(8*sample_width), # FIXME: ? latency="high", blocksize=5000, callback=self.play_callback, ) self.open_files = [] def add_file(self, music_file): if music_file not in self.open_files: self.open_files.append(music_file) self.start() def remove_file(self, music_file): self.open_files.remove(music_file) if len(self.open_files) == 0: self.stop() def stop(self): self.stream.stop() def start(self): self.stream.start() def play_callback(self, out_data, frame_count, time_info, status_flags): out_data_length = len(out_data) empty_data = b"\0" * out_data_length data = b"\0" * out_data_length for open_file in self.open_files: file_data = open_file.play_callback(out_data_length, frame_count) if data == empty_data: data = file_data elif file_data != empty_data: data = audioop.add(data, file_data, sample_width) out_data[:] = data