Skip to main content

xsynth_core/channel/
mod.rs

1use std::sync::{atomic::AtomicU64, Arc};
2
3use crate::{
4    effects::MultiChannelBiQuad,
5    helpers::{prepapre_cache_vec, sum_simd},
6    voice::VoiceControlData,
7    AudioStreamParams, ChannelCount,
8};
9
10use xsynth_soundfonts::FilterType;
11
12use self::{control::ControlEventData, key::KeyData, params::VoiceChannelParams};
13
14use super::AudioPipe;
15
16use rayon::prelude::*;
17
18mod channel_sf;
19mod control;
20mod key;
21mod params;
22mod voice_buffer;
23mod voice_spawner;
24
25mod event;
26pub use event::*;
27
28pub(crate) use control::ValueLerp;
29pub use params::VoiceChannelStatsReader;
30
31struct Key {
32    data: KeyData,
33    audio_cache: Vec<f32>,
34    event_cache: Vec<KeyNoteEvent>,
35}
36
37impl Key {
38    pub fn new(key: u8, shared_voice_counter: Arc<AtomicU64>, options: ChannelInitOptions) -> Self {
39        Key {
40            data: KeyData::new(key, shared_voice_counter, options),
41            audio_cache: Vec::new(),
42            event_cache: Vec::new(),
43        }
44    }
45}
46
47/// Options for initializing a new VoiceChannel.
48#[derive(Clone, Copy, Debug, PartialEq)]
49#[cfg_attr(
50    feature = "serde",
51    derive(serde::Deserialize, serde::Serialize),
52    serde(default)
53)]
54pub struct ChannelInitOptions {
55    /// If set to true, the voices killed due to the voice limit will fade out.
56    /// If set to false, they will be killed immediately, usually causing clicking
57    /// but improving performance.
58    ///
59    /// Default: `false`
60    pub fade_out_killing: bool,
61}
62
63#[allow(clippy::derivable_impls)]
64impl Default for ChannelInitOptions {
65    fn default() -> Self {
66        Self {
67            fade_out_killing: false,
68        }
69    }
70}
71
72/// Represents a single MIDI channel within XSynth.
73///
74/// Keeps track and manages MIDI events and the active voices of a channel.
75///
76/// MIDI CC Support Chart:
77/// - `CC0`: Bank Select
78/// - `CC6`, `CC38`, `CC100`, `CC101`: RPN & NRPN
79/// - `CC7`: Volume
80/// - `CC8`: Balance
81/// - `CC10`: Pan
82/// - `CC11`: Expression
83/// - `CC64`: Damper pedal
84/// - `CC71`: Cutoff resonance
85/// - `CC72`: Release time multiplier
86/// - `CC73`: Attack time multiplier
87/// - `CC74`: Cutoff frequency
88/// - `CC120`: All sounds off
89/// - `CC121`: Reset all controllers
90/// - `CC123`: All notes off
91pub struct VoiceChannel {
92    key_voices: Vec<Key>,
93
94    params: VoiceChannelParams,
95    threadpool: Option<Arc<rayon::ThreadPool>>,
96
97    stream_params: AudioStreamParams,
98
99    /// The helper struct for keeping track of MIDI control event data
100    control_event_data: ControlEventData,
101
102    /// Processed control data, ready to feed to voices
103    voice_control_data: VoiceControlData,
104
105    /// Effects
106    cutoff: MultiChannelBiQuad,
107}
108
109impl VoiceChannel {
110    /// Initializes a new voice channel.
111    ///
112    /// - `options`: Channel configuration
113    /// - `stream_params`: Parameters of the output audio
114    /// - `threadpool`: The thread-pool that will be used to render the individual
115    ///   keys' voices concurrently. If None is used, the voices will be
116    ///   rendered on the same thread.
117    pub fn new(
118        options: ChannelInitOptions,
119        stream_params: AudioStreamParams,
120        threadpool: Option<Arc<rayon::ThreadPool>>,
121    ) -> VoiceChannel {
122        fn fill_key_array<T, F: Fn(u8) -> T>(func: F) -> Vec<T> {
123            let mut vec = Vec::with_capacity(128);
124            for i in 0..128 {
125                vec.push(func(i));
126            }
127            vec
128        }
129
130        let params = VoiceChannelParams::new(stream_params);
131        let shared_voice_counter = params.stats.voice_counter.clone();
132
133        VoiceChannel {
134            params,
135            key_voices: fill_key_array(|i| Key::new(i, shared_voice_counter.clone(), options)),
136
137            threadpool,
138
139            stream_params,
140
141            control_event_data: ControlEventData::new_defaults(stream_params.sample_rate),
142            voice_control_data: VoiceControlData::new_defaults(),
143
144            cutoff: MultiChannelBiQuad::new(
145                stream_params.channels.count() as usize,
146                FilterType::LowPass,
147                stream_params.sample_rate as f32 / 2.0,
148                stream_params.sample_rate as f32,
149                None,
150            ),
151        }
152    }
153
154    fn apply_channel_effects(&mut self, out: &mut [f32]) {
155        let control = &mut self.control_event_data;
156
157        match self.stream_params.channels {
158            ChannelCount::Mono => {
159                // Volume
160                for sample in out.iter_mut() {
161                    let vol = control.volume.get_next() * control.expression.get_next();
162                    let vol = vol.powi(2);
163                    *sample *= vol;
164                }
165            }
166            ChannelCount::Stereo => {
167                // Volume
168                for sample in out.chunks_mut(2) {
169                    let vol = control.volume.get_next() * control.expression.get_next();
170                    let vol = vol.powi(2);
171                    sample[0] *= vol;
172                    sample[1] *= vol;
173                }
174
175                // Pan
176                for sample in out.chunks_mut(2) {
177                    let pan = control.pan.get_next();
178                    sample[0] *= ((pan * std::f32::consts::PI / 2.0).cos()).min(1.0);
179                    sample[1] *= ((pan * std::f32::consts::PI / 2.0).sin()).min(1.0);
180                }
181            }
182        }
183
184        // Cutoff
185        if let Some(cutoff) = control.cutoff {
186            self.cutoff
187                .set_filter_type(FilterType::LowPass, cutoff, control.resonance);
188            self.cutoff.process(out);
189        }
190    }
191
192    fn push_key_events_and_render(&mut self, out: &mut [f32]) {
193        self.params.load_program();
194
195        out.fill(0.0);
196        match self.threadpool.as_ref() {
197            Some(pool) => {
198                let len = out.len();
199                let key_voices = &mut self.key_voices;
200                let params = &self.params;
201                let control_data = &self.voice_control_data;
202                pool.install(|| {
203                    key_voices.par_iter_mut().for_each(move |key| {
204                        for e in key.event_cache.drain(..) {
205                            key.data
206                                .send_event(e, control_data, &params.channel_sf, params.layers);
207                        }
208
209                        prepapre_cache_vec(&mut key.audio_cache, len, 0.0);
210                        key.data.render_to(&mut key.audio_cache);
211                    });
212                });
213
214                for key in self.key_voices.iter() {
215                    sum_simd(&key.audio_cache, out);
216                }
217            }
218            None => {
219                for key in self.key_voices.iter_mut() {
220                    for e in key.event_cache.drain(..) {
221                        key.data.send_event(
222                            e,
223                            &self.voice_control_data,
224                            &self.params.channel_sf,
225                            self.params.layers,
226                        );
227                    }
228
229                    key.data.render_to(out);
230                }
231            }
232        }
233
234        self.apply_channel_effects(out);
235    }
236
237    fn propagate_voice_controls(&mut self) {
238        for key in self.key_voices.iter_mut() {
239            key.data.process_controls(&self.voice_control_data);
240        }
241    }
242
243    fn kill_voices_in_exclusive_class(&mut self, class: u8) {
244        for key in self.key_voices.iter_mut() {
245            key.data.kill_by_exclusive_class(class);
246        }
247    }
248
249    /// Sends a ChannelEvent to the channel.
250    /// See the `ChannelEvent` documentation for more information.
251    pub fn process_event(&mut self, event: ChannelEvent) {
252        self.push_events_iter(std::iter::once(event));
253    }
254
255    /// Sends multiple ChannelEvent items to the channel as an iterator.
256    pub fn push_events_iter<T: Iterator<Item = ChannelEvent>>(&mut self, iter: T) {
257        for e in iter {
258            match e {
259                ChannelEvent::Audio(audio) => match audio {
260                    ChannelAudioEvent::NoteOn { key, vel } => {
261                        let classes: Vec<_> = self
262                            .params
263                            .channel_sf
264                            .exclusive_classes_attack(key, vel)
265                            .collect();
266                        for class in classes {
267                            self.kill_voices_in_exclusive_class(class);
268                        }
269                        if let Some(key) = self.key_voices.get_mut(key as usize) {
270                            let ev = KeyNoteEvent::On(vel);
271                            key.event_cache.push(ev);
272                        }
273                    }
274                    ChannelAudioEvent::NoteOff { key } => {
275                        if let Some(key) = self.key_voices.get_mut(key as usize) {
276                            let ev = KeyNoteEvent::Off;
277                            key.event_cache.push(ev);
278                        }
279                    }
280                    ChannelAudioEvent::AllNotesOff => {
281                        for key in self.key_voices.iter_mut() {
282                            let ev = KeyNoteEvent::AllOff;
283                            key.event_cache.push(ev);
284                        }
285                    }
286                    ChannelAudioEvent::AllNotesKilled => {
287                        for key in self.key_voices.iter_mut() {
288                            let ev = KeyNoteEvent::AllKilled;
289                            key.event_cache.push(ev);
290                        }
291                    }
292                    ChannelAudioEvent::ResetControl => {
293                        self.reset_control();
294                    }
295                    ChannelAudioEvent::Control(control) => {
296                        self.process_control_event(control);
297                    }
298                    ChannelAudioEvent::ProgramChange(preset) => {
299                        self.params.set_preset(preset);
300                    }
301                    ChannelAudioEvent::SystemReset => {
302                        for key in self.key_voices.iter_mut() {
303                            key.event_cache.clear();
304                            key.event_cache.push(KeyNoteEvent::AllKilled);
305                        }
306                        self.reset_control();
307                        self.reset_program();
308                    }
309                },
310                ChannelEvent::Config(config) => self.params.process_config_event(config),
311            }
312        }
313    }
314
315    /// Returns a reader for the VoiceChannel statistics.
316    /// See the `VoiceChannelStatsReader` documentation for more information.
317    pub fn get_channel_stats(&self) -> VoiceChannelStatsReader {
318        let stats = self.params.stats.clone();
319        VoiceChannelStatsReader::new(stats)
320    }
321}
322
323impl AudioPipe for VoiceChannel {
324    fn stream_params(&self) -> &AudioStreamParams {
325        &self.params.constant.stream_params
326    }
327
328    fn read_samples_unchecked(&mut self, out: &mut [f32]) {
329        self.push_key_events_and_render(out);
330    }
331}