xsynth_core/channel/
control.rs1use biquad::Q_BUTTERWORTH_F32;
2
3use crate::{
4 helpers::{db_to_amp, FREQS},
5 voice::VoiceControlData,
6};
7
8use super::{ChannelAudioEvent, ChannelEvent, ControlEvent, VoiceChannel};
9
10pub(crate) struct ValueLerp {
11 lerp_length: f32,
12 step: f32,
13 current: f32,
14 end: f32,
15}
16
17impl ValueLerp {
18 pub fn new(current: f32, sample_rate: u32) -> Self {
19 Self {
20 lerp_length: sample_rate as f32 * 0.01,
21 step: 0.0,
22 current,
23 end: current,
24 }
25 }
26
27 pub fn set_end(&mut self, end: f32) {
28 self.step = (end - self.current) / self.lerp_length;
29 self.end = end;
30 }
31
32 pub fn get_next(&mut self) -> f32 {
33 if self.end > self.current {
34 self.current = (self.current + self.step).min(self.end);
35 } else if self.end < self.current {
36 self.current = (self.current + self.step).max(self.end);
37 }
38 self.current
39 }
40}
41
42pub(super) struct ControlEventData {
43 selected_lsb: i8,
44 selected_msb: i8,
45 pitch_bend_sensitivity_lsb: u8,
46 pitch_bend_sensitivity_msb: u8,
47 pitch_bend_sensitivity: f32,
48 pitch_bend_value: f32,
49 fine_tune_lsb: u8,
50 fine_tune_msb: u8,
51 fine_tune_value: f32,
52 coarse_tune_value: f32,
53 pub volume: ValueLerp, pub pan: ValueLerp, pub cutoff: Option<f32>,
56 pub resonance: Option<f32>,
57 pub expression: ValueLerp,
58}
59
60impl ControlEventData {
61 pub fn new_defaults(sample_rate: u32) -> Self {
62 ControlEventData {
63 selected_lsb: -1,
64 selected_msb: -1,
65 pitch_bend_sensitivity_lsb: 0,
66 pitch_bend_sensitivity_msb: 2,
67 pitch_bend_sensitivity: 2.0,
68 pitch_bend_value: 0.0,
69 fine_tune_lsb: 0,
70 fine_tune_msb: 0,
71 fine_tune_value: 0.0,
72 coarse_tune_value: 0.0,
73 volume: ValueLerp::new(1.0, sample_rate),
74 pan: ValueLerp::new(0.5, sample_rate),
75 cutoff: None,
76 resonance: None,
77 expression: ValueLerp::new(1.0, sample_rate),
78 }
79 }
80}
81
82impl VoiceChannel {
83 pub fn process_control_event(&mut self, event: ControlEvent) {
86 match event {
87 ControlEvent::Raw(controller, value) => match controller {
88 0x00 => {
89 self.params.set_bank(value);
91 }
92 0x64 => {
93 self.control_event_data.selected_lsb = value as i8;
94 }
95 0x65 => {
96 self.control_event_data.selected_msb = value as i8;
97 }
98 0x06 | 0x26 => {
99 let (lsb, msb) = {
100 let data = &self.control_event_data;
101 (data.selected_lsb, data.selected_msb)
102 };
103 if msb == 0 {
104 match lsb {
105 0 => {
106 match controller {
108 0x06 => {
109 self.control_event_data.pitch_bend_sensitivity_msb = value
110 }
111 0x26 => {
112 self.control_event_data.pitch_bend_sensitivity_lsb = value
113 }
114 _ => (),
115 }
116
117 let sensitivity = {
118 let data = &self.control_event_data;
119 (data.pitch_bend_sensitivity_msb as f32)
120 + (data.pitch_bend_sensitivity_lsb as f32) / 100.0
121 };
122
123 self.process_control_event(ControlEvent::PitchBendSensitivity(
124 sensitivity,
125 ))
126 }
127 1 => {
128 match controller {
130 0x06 => self.control_event_data.fine_tune_msb = value,
131 0x26 => self.control_event_data.fine_tune_lsb = value,
132 _ => (),
133 }
134 let val: u16 = ((self.control_event_data.fine_tune_msb as u16)
135 << 6)
136 + self.control_event_data.fine_tune_lsb as u16;
137 let val = (val as f32 - 4096.0) / 4096.0 * 100.0;
138 self.process_control_event(ControlEvent::FineTune(val));
139 }
140 2 if controller == 0x06 => {
141 self.process_control_event(ControlEvent::CoarseTune(
143 value as f32 - 64.0,
144 ))
145 }
146 2 => {}
147 _ => {}
148 }
149 }
150 }
151 0x07 => {
152 let vol: f32 = value as f32 / 128.0;
154 self.control_event_data.volume.set_end(vol);
155 }
156 0x0A | 0x08 => {
157 let pan: f32 = value as f32 / 128.0;
159 self.control_event_data.pan.set_end(pan);
160 }
161 0x0B => {
162 let expr = value as f32 / 128.0;
164 self.control_event_data.expression.set_end(expr);
165 }
166 0x40 => {
167 let damper = match value {
169 0..=63 => false,
170 64..=127 => true,
171 _ => false,
172 };
173
174 for key in self.key_voices.iter_mut() {
175 key.data.set_damper(damper);
176 }
177 }
178 0x47 => {
179 if value > 64 {
181 let db = (value as f32 - 64.0) / 2.4;
182 let value = db_to_amp(db) * Q_BUTTERWORTH_F32;
183 self.control_event_data.resonance = Some(value);
184 } else {
185 self.control_event_data.resonance = None;
186 }
187 }
188 0x48 => {
189 self.voice_control_data.envelope.release = Some(value);
191 self.propagate_voice_controls();
192 }
193 0x49 => {
194 self.voice_control_data.envelope.attack = Some(value);
196 self.propagate_voice_controls();
197 }
198 0x4A => {
199 if value < 64 {
201 let value = value as usize + 64;
202 let mut freq = FREQS[value];
203 if freq > 7000.0 {
204 let mult = freq / 7000.0 - 1.0;
206 let mult = mult * 2.36 + 1.0;
207 freq = mult * 7000.0;
208 }
209 self.control_event_data.cutoff = Some(freq);
210 } else {
211 self.control_event_data.cutoff = None;
212 }
213 }
214 0x78 if value == 0 => {
215 self.process_event(ChannelEvent::Audio(ChannelAudioEvent::AllNotesKilled));
217 }
218 0x79 if value == 0 => {
219 self.reset_control();
221 }
222 0x7B if value == 0 => {
223 self.process_event(ChannelEvent::Audio(ChannelAudioEvent::AllNotesOff));
225 }
226 _ => {}
227 },
228 ControlEvent::PitchBendSensitivity(sensitivity) => {
229 let pitch_bend = {
230 let data = &mut self.control_event_data;
231 data.pitch_bend_sensitivity = sensitivity;
232 data.pitch_bend_sensitivity * data.pitch_bend_value
233 };
234 self.process_control_event(ControlEvent::PitchBend(pitch_bend));
235 }
236 ControlEvent::PitchBendValue(value) => {
237 let pitch_bend = {
238 let data = &mut self.control_event_data;
239 data.pitch_bend_value = value;
240 data.pitch_bend_sensitivity * data.pitch_bend_value
241 };
242 self.process_control_event(ControlEvent::PitchBend(pitch_bend));
243 }
244 ControlEvent::PitchBend(value) => {
245 self.control_event_data.pitch_bend_value = value;
246 self.process_pitch();
247 }
248 ControlEvent::FineTune(value) => {
249 self.control_event_data.fine_tune_value = value;
250 self.process_pitch();
251 }
252 ControlEvent::CoarseTune(value) => {
253 self.control_event_data.coarse_tune_value = value;
254 self.process_pitch();
255 }
256 }
257 }
258
259 fn process_pitch(&mut self) {
260 let data = &mut self.control_event_data;
261 let pitch_bend = data.pitch_bend_value;
262 let fine_tune = data.fine_tune_value;
263 let coarse_tune = data.coarse_tune_value;
264 let combined = pitch_bend + coarse_tune + fine_tune / 100.0;
265
266 self.voice_control_data.voice_pitch_multiplier = 2.0f32.powf(combined / 12.0);
267 self.propagate_voice_controls();
268 }
269
270 pub(super) fn reset_control(&mut self) {
271 self.control_event_data = ControlEventData::new_defaults(self.stream_params.sample_rate);
272 self.voice_control_data = VoiceControlData::new_defaults();
273 self.propagate_voice_controls();
274
275 self.control_event_data.cutoff = None;
276
277 for key in self.key_voices.iter_mut() {
278 key.data.set_damper(false);
279 }
280 }
281
282 pub(super) fn reset_program(&mut self) {
283 self.params.set_bank(0);
284 self.params.set_preset(0);
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use crate::{AudioStreamParams, ChannelCount};
291
292 use super::*;
293
294 fn new_channel() -> VoiceChannel {
295 VoiceChannel::new(
296 Default::default(),
297 AudioStreamParams::new(48_000, ChannelCount::Stereo),
298 None,
299 )
300 }
301
302 #[test]
303 fn coarse_tune_only_uses_data_entry_msb() {
304 let mut channel = new_channel();
305
306 channel.process_control_event(ControlEvent::Raw(0x65, 0));
307 channel.process_control_event(ControlEvent::Raw(0x64, 2));
308 channel.process_control_event(ControlEvent::Raw(0x26, 100));
309
310 assert_eq!(channel.control_event_data.coarse_tune_value, 0.0);
311
312 channel.process_control_event(ControlEvent::Raw(0x06, 70));
313
314 assert_eq!(channel.control_event_data.coarse_tune_value, 6.0);
315 }
316
317 #[test]
318 fn reset_all_controllers_requires_zero_value() {
319 let mut channel = new_channel();
320 channel.process_control_event(ControlEvent::Raw(0x07, 32));
321 channel.process_control_event(ControlEvent::Raw(0x79, 1));
322
323 assert_eq!(channel.control_event_data.volume.end, 32.0 / 128.0);
324
325 channel.process_control_event(ControlEvent::Raw(0x79, 0));
326
327 assert_eq!(channel.control_event_data.volume.end, 1.0);
328 }
329}