xsynth_core/channel/
mod.rs

1use std::sync::{atomic::AtomicU64, Arc};
2
3use crate::{
4    effects::MultiChannelBiQuad,
5    helpers::{db_to_amp, prepapre_cache_vec, sum_simd, FREQS},
6    voice::VoiceControlData,
7    AudioStreamParams, ChannelCount,
8};
9
10use xsynth_soundfonts::FilterType;
11
12use self::{key::KeyData, params::VoiceChannelParams};
13
14use super::AudioPipe;
15
16use biquad::Q_BUTTERWORTH_F32;
17
18use rayon::prelude::*;
19
20mod channel_sf;
21mod key;
22mod params;
23mod voice_buffer;
24mod voice_spawner;
25
26mod event;
27pub use event::*;
28
29pub use params::VoiceChannelStatsReader;
30
31pub(crate) struct ValueLerp {
32    lerp_length: f32,
33    step: f32,
34    current: f32,
35    end: f32,
36}
37
38impl ValueLerp {
39    pub fn new(current: f32, sample_rate: u32) -> Self {
40        Self {
41            lerp_length: sample_rate as f32 * 0.01,
42            step: 0.0,
43            current,
44            end: current,
45        }
46    }
47
48    pub fn set_end(&mut self, end: f32) {
49        self.step = (end - self.current) / self.lerp_length;
50        self.end = end;
51    }
52
53    pub fn get_next(&mut self) -> f32 {
54        if self.end > self.current {
55            self.current = (self.current + self.step).min(self.end);
56        } else if self.end < self.current {
57            self.current = (self.current + self.step).max(self.end);
58        }
59        self.current
60    }
61}
62
63struct Key {
64    data: KeyData,
65    audio_cache: Vec<f32>,
66    event_cache: Vec<KeyNoteEvent>,
67}
68
69impl Key {
70    pub fn new(key: u8, shared_voice_counter: Arc<AtomicU64>, options: ChannelInitOptions) -> Self {
71        Key {
72            data: KeyData::new(key, shared_voice_counter, options),
73            audio_cache: Vec::new(),
74            event_cache: Vec::new(),
75        }
76    }
77}
78
79struct ControlEventData {
80    selected_lsb: i8,
81    selected_msb: i8,
82    pitch_bend_sensitivity_lsb: u8,
83    pitch_bend_sensitivity_msb: u8,
84    pitch_bend_sensitivity: f32,
85    pitch_bend_value: f32,
86    fine_tune_lsb: u8,
87    fine_tune_msb: u8,
88    fine_tune_value: f32,
89    coarse_tune_value: f32,
90    volume: ValueLerp, // 0.0 = silent, 1.0 = max volume
91    pan: ValueLerp,    // 0.0 = left, 0.5 = center, 1.0 = right
92    cutoff: Option<f32>,
93    resonance: Option<f32>,
94    expression: ValueLerp,
95}
96
97impl ControlEventData {
98    pub fn new_defaults(sample_rate: u32) -> Self {
99        ControlEventData {
100            selected_lsb: -1,
101            selected_msb: -1,
102            pitch_bend_sensitivity_lsb: 0,
103            pitch_bend_sensitivity_msb: 2,
104            pitch_bend_sensitivity: 2.0,
105            pitch_bend_value: 0.0,
106            fine_tune_lsb: 0,
107            fine_tune_msb: 0,
108            fine_tune_value: 0.0,
109            coarse_tune_value: 0.0,
110            volume: ValueLerp::new(1.0, sample_rate),
111            pan: ValueLerp::new(0.5, sample_rate),
112            cutoff: None,
113            resonance: None,
114            expression: ValueLerp::new(1.0, sample_rate),
115        }
116    }
117}
118
119/// Options for initializing a new VoiceChannel.
120#[derive(Clone, Copy, Debug, PartialEq)]
121#[cfg_attr(
122    feature = "serde",
123    derive(serde::Deserialize, serde::Serialize),
124    serde(default)
125)]
126pub struct ChannelInitOptions {
127    /// If set to true, the voices killed due to the voice limit will fade out.
128    /// If set to false, they will be killed immediately, usually causing clicking
129    /// but improving performance.
130    ///
131    /// Default: `false`
132    pub fade_out_killing: bool,
133}
134
135#[allow(clippy::derivable_impls)]
136impl Default for ChannelInitOptions {
137    fn default() -> Self {
138        Self {
139            fade_out_killing: false,
140        }
141    }
142}
143
144/// Represents a single MIDI channel within XSynth.
145///
146/// Keeps track and manages MIDI events and the active voices of a channel.
147///
148/// MIDI CC Support Chart:
149/// - `CC0`: Bank Select
150/// - `CC6`, `CC38`, `CC100`, `CC101`: RPN & NRPN
151/// - `CC7`: Volume
152/// - `CC8`: Balance
153/// - `CC10`: Pan
154/// - `CC11`: Expression
155/// - `CC64`: Damper pedal
156/// - `CC71`: Cutoff resonance
157/// - `CC72`: Release time multiplier
158/// - `CC73`: Attack time multiplier
159/// - `CC74`: Cutoff frequency
160/// - `CC120`: All sounds off
161/// - `CC121`: Reset all controllers
162/// - `CC123`: All notes off
163pub struct VoiceChannel {
164    key_voices: Vec<Key>,
165
166    params: VoiceChannelParams,
167    threadpool: Option<Arc<rayon::ThreadPool>>,
168
169    stream_params: AudioStreamParams,
170
171    /// The helper struct for keeping track of MIDI control event data
172    control_event_data: ControlEventData,
173
174    /// Processed control data, ready to feed to voices
175    voice_control_data: VoiceControlData,
176
177    /// Effects
178    cutoff: MultiChannelBiQuad,
179}
180
181impl VoiceChannel {
182    /// Initializes a new voice channel.
183    ///
184    /// - `options`: Channel configuration
185    /// - `stream_params`: Parameters of the output audio
186    /// - `threadpool`: The thread-pool that will be used to render the individual
187    ///   keys' voices concurrently. If None is used, the voices will be
188    ///   rendered on the same thread.
189    pub fn new(
190        options: ChannelInitOptions,
191        stream_params: AudioStreamParams,
192        threadpool: Option<Arc<rayon::ThreadPool>>,
193    ) -> VoiceChannel {
194        fn fill_key_array<T, F: Fn(u8) -> T>(func: F) -> Vec<T> {
195            let mut vec = Vec::with_capacity(128);
196            for i in 0..128 {
197                vec.push(func(i));
198            }
199            vec
200        }
201
202        let params = VoiceChannelParams::new(stream_params);
203        let shared_voice_counter = params.stats.voice_counter.clone();
204
205        VoiceChannel {
206            params,
207            key_voices: fill_key_array(|i| Key::new(i, shared_voice_counter.clone(), options)),
208
209            threadpool,
210
211            stream_params,
212
213            control_event_data: ControlEventData::new_defaults(stream_params.sample_rate),
214            voice_control_data: VoiceControlData::new_defaults(),
215
216            cutoff: MultiChannelBiQuad::new(
217                stream_params.channels.count() as usize,
218                FilterType::LowPass,
219                20000.0,
220                stream_params.sample_rate as f32,
221                None,
222            ),
223        }
224    }
225
226    fn apply_channel_effects(&mut self, out: &mut [f32]) {
227        let control = &mut self.control_event_data;
228
229        match self.stream_params.channels {
230            ChannelCount::Mono => {
231                // Volume
232                for sample in out.iter_mut() {
233                    let vol = control.volume.get_next() * control.expression.get_next();
234                    let vol = vol.powi(2);
235                    *sample *= vol;
236                }
237            }
238            ChannelCount::Stereo => {
239                // Volume
240                for sample in out.chunks_mut(2) {
241                    let vol = control.volume.get_next() * control.expression.get_next();
242                    let vol = vol.powi(2);
243                    sample[0] *= vol;
244                    sample[1] *= vol;
245                }
246
247                // Pan
248                for sample in out.chunks_mut(2) {
249                    let pan = control.pan.get_next();
250                    sample[0] *= ((pan * std::f32::consts::PI / 2.0).cos()).min(1.0);
251                    sample[1] *= ((pan * std::f32::consts::PI / 2.0).sin()).min(1.0);
252                }
253            }
254        }
255
256        // Cutoff
257        if let Some(cutoff) = control.cutoff {
258            self.cutoff
259                .set_filter_type(FilterType::LowPass, cutoff, control.resonance);
260            self.cutoff.process(out);
261        }
262    }
263
264    fn push_key_events_and_render(&mut self, out: &mut [f32]) {
265        self.params.load_program();
266
267        out.fill(0.0);
268        match self.threadpool.as_ref() {
269            Some(pool) => {
270                let len = out.len();
271                let key_voices = &mut self.key_voices;
272                let params = &self.params;
273                let control_data = &self.voice_control_data;
274                pool.install(|| {
275                    key_voices.par_iter_mut().for_each(move |key| {
276                        for e in key.event_cache.drain(..) {
277                            key.data
278                                .send_event(e, control_data, &params.channel_sf, params.layers);
279                        }
280
281                        prepapre_cache_vec(&mut key.audio_cache, len, 0.0);
282                        key.data.render_to(&mut key.audio_cache);
283                    });
284                });
285
286                for key in self.key_voices.iter() {
287                    sum_simd(&key.audio_cache, out);
288                }
289            }
290            None => {
291                for key in self.key_voices.iter_mut() {
292                    for e in key.event_cache.drain(..) {
293                        key.data.send_event(
294                            e,
295                            &self.voice_control_data,
296                            &self.params.channel_sf,
297                            self.params.layers,
298                        );
299                    }
300
301                    key.data.render_to(out);
302                }
303            }
304        }
305
306        self.apply_channel_effects(out);
307    }
308
309    fn propagate_voice_controls(&mut self) {
310        for key in self.key_voices.iter_mut() {
311            key.data.process_controls(&self.voice_control_data);
312        }
313    }
314
315    /// Sends a ControlEvent to the channel.
316    /// See the `ControlEvent` documentation for more information.
317    pub fn process_control_event(&mut self, event: ControlEvent) {
318        match event {
319            ControlEvent::Raw(controller, value) => match controller {
320                0x00 => {
321                    // Bank select
322                    self.params.set_bank(value);
323                }
324                0x64 => {
325                    self.control_event_data.selected_lsb = value as i8;
326                }
327                0x65 => {
328                    self.control_event_data.selected_msb = value as i8;
329                }
330                0x06 | 0x26 => {
331                    let (lsb, msb) = {
332                        let data = &self.control_event_data;
333                        (data.selected_lsb, data.selected_msb)
334                    };
335                    if msb == 0 {
336                        match lsb {
337                            0 => {
338                                // Pitch
339                                match controller {
340                                    0x06 => {
341                                        self.control_event_data.pitch_bend_sensitivity_msb = value
342                                    }
343                                    0x26 => {
344                                        self.control_event_data.pitch_bend_sensitivity_lsb = value
345                                    }
346                                    _ => (),
347                                }
348
349                                let sensitivity = {
350                                    let data = &self.control_event_data;
351                                    (data.pitch_bend_sensitivity_msb as f32)
352                                        + (data.pitch_bend_sensitivity_lsb as f32) / 100.0
353                                };
354
355                                self.process_control_event(ControlEvent::PitchBendSensitivity(
356                                    sensitivity,
357                                ))
358                            }
359                            1 => {
360                                // Fine tune
361                                match controller {
362                                    0x06 => self.control_event_data.fine_tune_msb = value,
363                                    0x26 => self.control_event_data.fine_tune_lsb = value,
364                                    _ => (),
365                                }
366                                let val: u16 = ((self.control_event_data.fine_tune_msb as u16)
367                                    << 6)
368                                    + self.control_event_data.fine_tune_lsb as u16;
369                                let val = (val as f32 - 4096.0) / 4096.0 * 100.0;
370                                self.process_control_event(ControlEvent::FineTune(val));
371                            }
372                            2 => {
373                                // Coarse tune
374                                if controller == 0x06 {
375                                    self.process_control_event(ControlEvent::CoarseTune(
376                                        value as f32 - 64.0,
377                                    ))
378                                }
379                            }
380                            _ => {}
381                        }
382                    }
383                }
384                0x07 => {
385                    // Volume
386                    let vol: f32 = value as f32 / 128.0;
387                    self.control_event_data.volume.set_end(vol);
388                }
389                0x0A | 0x08 => {
390                    // Pan
391                    let pan: f32 = value as f32 / 128.0;
392                    self.control_event_data.pan.set_end(pan);
393                }
394                0x0B => {
395                    // Expression
396                    let expr = value as f32 / 128.0;
397                    self.control_event_data.expression.set_end(expr);
398                }
399                0x40 => {
400                    // Damper / Sustain
401                    let damper = match value {
402                        0..=63 => false,
403                        64..=127 => true,
404                        _ => false,
405                    };
406
407                    for key in self.key_voices.iter_mut() {
408                        key.data.set_damper(damper);
409                    }
410                }
411                0x47 => {
412                    // Resonance
413                    if value > 64 {
414                        let db = (value as f32 - 64.0) / 2.4;
415                        let value = db_to_amp(db) * Q_BUTTERWORTH_F32;
416                        self.control_event_data.resonance = Some(value);
417                    } else {
418                        self.control_event_data.resonance = None;
419                    }
420                }
421                0x48 => {
422                    // Release
423                    self.voice_control_data.envelope.release = Some(value);
424                    self.propagate_voice_controls();
425                }
426                0x49 => {
427                    // Attack
428                    self.voice_control_data.envelope.attack = Some(value);
429                    self.propagate_voice_controls();
430                }
431                0x4A => {
432                    // Cutoff
433                    if value < 64 {
434                        let value = value as usize + 64;
435                        let mut freq = FREQS[value];
436                        if freq > 7000.0 {
437                            // I hate BASS
438                            let mult = freq / 7000.0 - 1.0;
439                            let mult = mult * 2.36 + 1.0;
440                            freq = mult * 7000.0;
441                        }
442                        self.control_event_data.cutoff = Some(freq);
443                    } else {
444                        self.control_event_data.cutoff = None;
445                    }
446                }
447                0x78 => {
448                    // All Sounds Off
449                    if value == 0 {
450                        self.process_event(ChannelEvent::Audio(ChannelAudioEvent::AllNotesKilled));
451                    }
452                }
453                0x79 => {
454                    // Reset All Controllers
455                    if value == 0 {
456                        self.reset_control();
457                    }
458                }
459                0x7B => {
460                    // All Notes Off
461                    if value == 0 {
462                        self.process_event(ChannelEvent::Audio(ChannelAudioEvent::AllNotesOff));
463                    }
464                }
465                _ => {}
466            },
467            ControlEvent::PitchBendSensitivity(sensitivity) => {
468                let pitch_bend = {
469                    let data = &mut self.control_event_data;
470                    data.pitch_bend_sensitivity = sensitivity;
471                    data.pitch_bend_sensitivity * data.pitch_bend_value
472                };
473                self.process_control_event(ControlEvent::PitchBend(pitch_bend));
474            }
475            ControlEvent::PitchBendValue(value) => {
476                let pitch_bend = {
477                    let data = &mut self.control_event_data;
478                    data.pitch_bend_value = value;
479                    data.pitch_bend_sensitivity * data.pitch_bend_value
480                };
481                self.process_control_event(ControlEvent::PitchBend(pitch_bend));
482            }
483            ControlEvent::PitchBend(value) => {
484                self.control_event_data.pitch_bend_value = value;
485                self.process_pitch();
486            }
487            ControlEvent::FineTune(value) => {
488                self.control_event_data.fine_tune_value = value;
489                self.process_pitch();
490            }
491            ControlEvent::CoarseTune(value) => {
492                self.control_event_data.coarse_tune_value = value;
493                self.process_pitch();
494            }
495        }
496    }
497
498    fn process_pitch(&mut self) {
499        let data = &mut self.control_event_data;
500        let pitch_bend = data.pitch_bend_value;
501        let fine_tune = data.fine_tune_value;
502        let coarse_tune = data.coarse_tune_value;
503        let combined = pitch_bend + coarse_tune + fine_tune / 100.0;
504
505        self.voice_control_data.voice_pitch_multiplier = 2.0f32.powf(combined / 12.0);
506        self.propagate_voice_controls();
507    }
508
509    /// Sends a ChannelEvent to the channel.
510    /// See the `ChannelEvent` documentation for more information.
511    pub fn process_event(&mut self, event: ChannelEvent) {
512        self.push_events_iter(std::iter::once(event));
513    }
514
515    /// Sends multiple ChannelEvent items to the channel as an iterator.
516    pub fn push_events_iter<T: Iterator<Item = ChannelEvent>>(&mut self, iter: T) {
517        for e in iter {
518            match e {
519                ChannelEvent::Audio(audio) => match audio {
520                    ChannelAudioEvent::NoteOn { key, vel } => {
521                        if let Some(key) = self.key_voices.get_mut(key as usize) {
522                            let ev = KeyNoteEvent::On(vel);
523                            key.event_cache.push(ev);
524                        }
525                    }
526                    ChannelAudioEvent::NoteOff { key } => {
527                        if let Some(key) = self.key_voices.get_mut(key as usize) {
528                            let ev = KeyNoteEvent::Off;
529                            key.event_cache.push(ev);
530                        }
531                    }
532                    ChannelAudioEvent::AllNotesOff => {
533                        for key in self.key_voices.iter_mut() {
534                            let ev = KeyNoteEvent::AllOff;
535                            key.event_cache.push(ev);
536                        }
537                    }
538                    ChannelAudioEvent::AllNotesKilled => {
539                        for key in self.key_voices.iter_mut() {
540                            let ev = KeyNoteEvent::AllKilled;
541                            key.event_cache.push(ev);
542                        }
543                    }
544                    ChannelAudioEvent::ResetControl => {
545                        self.reset_control();
546                    }
547                    ChannelAudioEvent::Control(control) => {
548                        self.process_control_event(control);
549                    }
550                    ChannelAudioEvent::ProgramChange(preset) => {
551                        self.params.set_preset(preset);
552                    }
553                },
554                ChannelEvent::Config(config) => self.params.process_config_event(config),
555            }
556        }
557    }
558
559    /// Returns a reader for the VoiceChannel statistics.
560    /// See the `VoiceChannelStatsReader` documentation for more information.
561    pub fn get_channel_stats(&self) -> VoiceChannelStatsReader {
562        let stats = self.params.stats.clone();
563        VoiceChannelStatsReader::new(stats)
564    }
565
566    fn reset_control(&mut self) {
567        self.control_event_data = ControlEventData::new_defaults(self.stream_params.sample_rate);
568        self.voice_control_data = VoiceControlData::new_defaults();
569        self.process_event(ChannelEvent::Audio(ChannelAudioEvent::ProgramChange(0)));
570        self.propagate_voice_controls();
571
572        self.control_event_data.cutoff = None;
573
574        for key in self.key_voices.iter_mut() {
575            key.data.set_damper(false);
576        }
577    }
578}
579
580impl AudioPipe for VoiceChannel {
581    fn stream_params(&self) -> &AudioStreamParams {
582        &self.params.constant.stream_params
583    }
584
585    fn read_samples_unchecked(&mut self, out: &mut [f32]) {
586        self.push_key_events_and_render(out);
587    }
588}