diff options
Diffstat (limited to 'music_sampler/mixer.py')
-rw-r--r-- | music_sampler/mixer.py | 63 |
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 @@ | |||
1 | import sounddevice as sd | ||
2 | import audioop | ||
3 | import time | ||
4 | |||
5 | from . import Config | ||
6 | |||
7 | sample_width = Config.sample_width | ||
8 | |||
9 | def 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 | |||
15 | def _latency(latency): | ||
16 | if latency == "high" or latency == "low": | ||
17 | return latency | ||
18 | else: | ||
19 | return float(latency) | ||
20 | |||
21 | class 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 | |||