]>
Commit | Line | Data |
---|---|---|
1 | import sounddevice as sd | |
2 | import audioop | |
3 | import time | |
4 | ||
5 | from .helpers 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 |