xsynth_core/channel_group/
mod.rs1use std::sync::Arc;
2
3use crate::{
4 channel::{ChannelAudioEvent, ChannelConfigEvent, ChannelEvent, VoiceChannel},
5 helpers::{prepapre_cache_vec, sum_simd},
6 AudioPipe, AudioStreamParams,
7};
8
9mod config;
10pub use config::*;
11mod events;
12pub use events::*;
13use rayon::prelude::*;
14
15const MAX_EVENT_CACHE_SIZE: u32 = 1024 * 1024;
16
17pub struct ChannelGroup {
22 thread_pool: Option<rayon::ThreadPool>,
23 cached_event_count: u32,
24 channel_events_cache: Box<[Vec<ChannelAudioEvent>]>,
25 sample_cache_vecs: Box<[Vec<f32>]>,
26 channels: Box<[VoiceChannel]>,
27 audio_params: AudioStreamParams,
28}
29
30impl ChannelGroup {
31 pub fn new(config: ChannelGroupConfig) -> Self {
34 let mut channels = Vec::new();
35 let mut channel_events_cache = Vec::new();
36 let mut sample_cache_vecs = Vec::new();
37
38 let channel_pool = match config.parallelism.key {
40 ThreadCount::None => None,
41 ThreadCount::Auto => Some(Arc::new(rayon::ThreadPoolBuilder::new().build().unwrap())),
42 ThreadCount::Manual(threads) => Some(Arc::new(
43 rayon::ThreadPoolBuilder::new()
44 .num_threads(threads)
45 .build()
46 .unwrap(),
47 )),
48 };
49
50 let group_pool = match config.parallelism.channel {
52 ThreadCount::None => None,
53 ThreadCount::Auto => Some(rayon::ThreadPoolBuilder::new().build().unwrap()),
54 ThreadCount::Manual(threads) => Some(
55 rayon::ThreadPoolBuilder::new()
56 .num_threads(threads)
57 .build()
58 .unwrap(),
59 ),
60 };
61
62 let channel_count = match config.format {
63 SynthFormat::Midi => 16,
64 SynthFormat::Custom { channels } => channels,
65 };
66
67 for _ in 0..channel_count {
68 channels.push(VoiceChannel::new(
69 config.channel_init_options,
70 config.audio_params,
71 channel_pool.clone(),
72 ));
73 channel_events_cache.push(Vec::new());
74 sample_cache_vecs.push(Vec::new());
75 }
76
77 if config.format == SynthFormat::Midi {
78 channels[9].push_events_iter(std::iter::once(ChannelEvent::Config(
79 ChannelConfigEvent::SetPercussionMode(true),
80 )));
81 }
82
83 Self {
84 thread_pool: group_pool,
85 cached_event_count: 0,
86 channel_events_cache: channel_events_cache.into_boxed_slice(),
87 channels: channels.into_boxed_slice(),
88 sample_cache_vecs: sample_cache_vecs.into_boxed_slice(),
89 audio_params: config.audio_params,
90 }
91 }
92
93 pub fn send_event(&mut self, event: SynthEvent) {
96 match event {
97 SynthEvent::Channel(channel, event) => match event {
98 ChannelEvent::Audio(e) => {
99 if let Some(events) = self.channel_events_cache.get_mut(channel as usize) {
100 events.push(e);
101 self.cached_event_count += 1;
102 if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
103 self.flush_events();
104 }
105 }
106 }
107 ChannelEvent::Config(_) => {
108 if let Some(channel) = self.channels.get_mut(channel as usize) {
109 channel.process_event(event);
110 }
111 }
112 },
113 SynthEvent::AllChannels(event) => match event {
114 ChannelEvent::Audio(e) => {
115 for channel in self.channel_events_cache.iter_mut() {
116 channel.push(e);
117 }
118 self.cached_event_count += self.channel_events_cache.len() as u32;
119 if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
120 self.flush_events();
121 }
122 }
123 ChannelEvent::Config(_) => {
124 for channel in self.channels.iter_mut() {
125 channel.process_event(event.clone());
126 }
127 }
128 },
129 }
130 }
131
132 fn flush_events(&mut self) {
133 if self.cached_event_count == 0 {
134 return;
135 }
136
137 match self.thread_pool.as_ref() {
138 Some(pool) => {
139 let channels = &mut self.channels;
140 let channel_events_cache = &mut self.channel_events_cache;
141
142 pool.install(move || {
143 channels
144 .par_iter_mut()
145 .zip(channel_events_cache.par_iter_mut())
146 .for_each(|(channel, events)| {
147 channel.push_events_iter(events.drain(..).map(ChannelEvent::Audio));
148 });
149 });
150 }
151 None => {
152 for (channel, events) in self
153 .channels
154 .iter_mut()
155 .zip(self.channel_events_cache.iter_mut())
156 {
157 channel.push_events_iter(events.drain(..).map(ChannelEvent::Audio));
158 }
159 }
160 }
161
162 self.cached_event_count = 0;
163 }
164
165 fn render_to(&mut self, buffer: &mut [f32]) {
166 self.flush_events();
167 buffer.fill(0.0);
168
169 match self.thread_pool.as_ref() {
170 Some(pool) => {
171 let len = buffer.len();
172 let channels = &mut self.channels;
173 let sample_cache_vecs = &mut self.sample_cache_vecs;
174 pool.install(move || {
175 channels
176 .par_iter_mut()
177 .zip(sample_cache_vecs.par_iter_mut())
178 .for_each(|(channel, samples)| {
179 prepapre_cache_vec(samples, len, 0.0);
180 channel.read_samples(samples.as_mut_slice());
181 });
182
183 for vec in sample_cache_vecs.iter_mut() {
184 sum_simd(vec, buffer);
185 }
186 });
187 }
188 None => {
189 let len = buffer.len();
190
191 for (channel, samples) in self
192 .channels
193 .iter_mut()
194 .zip(self.sample_cache_vecs.iter_mut())
195 {
196 prepapre_cache_vec(samples, len, 0.0);
197 channel.read_samples(samples.as_mut_slice());
198 }
199
200 for vec in self.sample_cache_vecs.iter_mut() {
201 sum_simd(vec, buffer);
202 }
203 }
204 }
205 }
206
207 pub fn voice_count(&self) -> u64 {
209 self.channels
210 .iter()
211 .map(|c| c.get_channel_stats().voice_count())
212 .sum()
213 }
214}
215
216impl AudioPipe for ChannelGroup {
217 fn stream_params(&self) -> &AudioStreamParams {
218 &self.audio_params
219 }
220
221 fn read_samples_unchecked(&mut self, to: &mut [f32]) {
222 self.render_to(to);
223 }
224}
225
226#[cfg(test)]
227mod tests {
228 use crate::{
229 channel::{ChannelAudioEvent, ChannelEvent, ChannelInitOptions},
230 channel_group::{
231 ChannelGroupConfig, ParallelismOptions, SynthEvent, SynthFormat, ThreadCount,
232 },
233 AudioStreamParams, ChannelCount,
234 };
235
236 use super::ChannelGroup;
237
238 #[test]
239 fn out_of_range_channel_event_is_ignored() {
240 let mut group = ChannelGroup::new(ChannelGroupConfig {
241 channel_init_options: ChannelInitOptions::default(),
242 format: SynthFormat::Custom { channels: 1 },
243 audio_params: AudioStreamParams::new(44_100, ChannelCount::Stereo),
244 parallelism: ParallelismOptions {
245 channel: ThreadCount::None,
246 key: ThreadCount::None,
247 },
248 });
249
250 group.send_event(SynthEvent::Channel(
251 1,
252 ChannelEvent::Audio(ChannelAudioEvent::NoteOn { key: 60, vel: 100 }),
253 ));
254
255 assert_eq!(group.voice_count(), 0);
256 }
257}