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 self.channel_events_cache[channel as usize].push(e);
100 self.cached_event_count += 1;
101 if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
102 self.flush_events();
103 }
104 }
105 ChannelEvent::Config(_) => self.channels[channel as usize].process_event(event),
106 },
107 SynthEvent::AllChannels(event) => match event {
108 ChannelEvent::Audio(e) => {
109 for channel in self.channel_events_cache.iter_mut() {
110 channel.push(e);
111 }
112 self.cached_event_count += self.channel_events_cache.len() as u32;
113 if self.cached_event_count > MAX_EVENT_CACHE_SIZE {
114 self.flush_events();
115 }
116 }
117 ChannelEvent::Config(_) => {
118 for channel in self.channels.iter_mut() {
119 channel.process_event(event.clone());
120 }
121 }
122 },
123 }
124 }
125
126 fn flush_events(&mut self) {
127 if self.cached_event_count == 0 {
128 return;
129 }
130
131 match self.thread_pool.as_ref() {
132 Some(pool) => {
133 let channels = &mut self.channels;
134 let channel_events_cache = &mut self.channel_events_cache;
135
136 pool.install(move || {
137 channels
138 .par_iter_mut()
139 .zip(channel_events_cache.par_iter_mut())
140 .for_each(|(channel, events)| {
141 channel.push_events_iter(events.drain(..).map(ChannelEvent::Audio));
142 });
143 });
144 }
145 None => {
146 for (channel, events) in self
147 .channels
148 .iter_mut()
149 .zip(self.channel_events_cache.iter_mut())
150 {
151 channel.push_events_iter(events.drain(..).map(ChannelEvent::Audio));
152 }
153 }
154 }
155
156 self.cached_event_count = 0;
157 }
158
159 fn render_to(&mut self, buffer: &mut [f32]) {
160 self.flush_events();
161 buffer.fill(0.0);
162
163 match self.thread_pool.as_ref() {
164 Some(pool) => {
165 let len = buffer.len();
166 let channels = &mut self.channels;
167 let sample_cache_vecs = &mut self.sample_cache_vecs;
168 pool.install(move || {
169 channels
170 .par_iter_mut()
171 .zip(sample_cache_vecs.par_iter_mut())
172 .for_each(|(channel, samples)| {
173 prepapre_cache_vec(samples, len, 0.0);
174 channel.read_samples(samples.as_mut_slice());
175 });
176
177 for vec in sample_cache_vecs.iter_mut() {
178 sum_simd(vec, buffer);
179 }
180 });
181 }
182 None => {
183 let len = buffer.len();
184
185 for (channel, samples) in self
186 .channels
187 .iter_mut()
188 .zip(self.sample_cache_vecs.iter_mut())
189 {
190 prepapre_cache_vec(samples, len, 0.0);
191 channel.read_samples(samples.as_mut_slice());
192 }
193
194 for vec in self.sample_cache_vecs.iter_mut() {
195 sum_simd(vec, buffer);
196 }
197 }
198 }
199 }
200
201 pub fn voice_count(&self) -> u64 {
203 self.channels
204 .iter()
205 .map(|c| c.get_channel_stats().voice_count())
206 .sum()
207 }
208}
209
210impl AudioPipe for ChannelGroup {
211 fn stream_params(&self) -> &AudioStreamParams {
212 &self.audio_params
213 }
214
215 fn read_samples_unchecked(&mut self, to: &mut [f32]) {
216 self.render_to(to);
217 }
218}