aboutsummaryrefslogtreecommitdiff
path: root/music_sampler/mixer.py
diff options
context:
space:
mode:
Diffstat (limited to 'music_sampler/mixer.py')
-rw-r--r--music_sampler/mixer.py63
1 files changed, 63 insertions, 0 deletions
diff --git a/music_sampler/mixer.py b/music_sampler/mixer.py
new file mode 100644
index 0000000..9242b61
--- /dev/null
+++ b/music_sampler/mixer.py
@@ -0,0 +1,63 @@
1import sounddevice as sd
2import audioop
3import time
4
5from . import Config
6
7sample_width = Config.sample_width
8
9def sample_width_to_dtype(sample_width):
10 if sample_width == 1 or sample_width == 2 or sample_width == 4:
11 return 'int' + str(8*sample_width)
12 else:
13 raise "Unknown sample width"
14
15def _latency(latency):
16 if latency == "high" or latency == "low":
17 return latency
18 else:
19 return float(latency)
20
21class Mixer:
22 def __init__(self):
23 self.stream = sd.RawOutputStream(
24 samplerate=Config.frame_rate,
25 channels=Config.channels,
26 dtype=sample_width_to_dtype(Config.sample_width),
27 latency=_latency(Config.latency),
28 blocksize=Config.blocksize,
29 callback=self.play_callback)
30 self.open_files = []
31
32 def add_file(self, music_file):
33 if music_file not in self.open_files:
34 self.open_files.append(music_file)
35 self.start()
36
37 def remove_file(self, music_file):
38 if music_file in self.open_files:
39 self.open_files.remove(music_file)
40 if len(self.open_files) == 0:
41 self.stop()
42
43 def stop(self):
44 self.stream.stop()
45
46 def start(self):
47 self.stream.start()
48
49 def play_callback(self, out_data, frame_count, time_info, status_flags):
50 out_data_length = len(out_data)
51 empty_data = b"\0" * out_data_length
52 data = b"\0" * out_data_length
53
54 for open_file in self.open_files:
55 file_data = open_file.play_callback(out_data_length, frame_count)
56
57 if data == empty_data:
58 data = file_data
59 elif file_data != empty_data:
60 data = audioop.add(data, file_data, sample_width)
61
62 out_data[:] = data
63