From c5c26bdc3e38c3c4aab2d1e5f37cd55e23494cf3 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Sun, 17 Jul 2022 11:58:28 +0200 Subject: [PATCH] Applied rustfmt --- examples/cpal_demo_node_api.rs | 109 +- examples/jack_demo_node_api.rs | 160 +-- rustfmt.toml | 2 + src/cell_dir.rs | 42 +- src/dsp/biquad.rs | 73 +- src/dsp/dattorro.rs | 268 ++--- src/dsp/helpers.rs | 649 +++++----- src/dsp/mod.rs | 861 +++++++------- src/dsp/node_ad.rs | 226 ++-- src/dsp/node_allp.rs | 55 +- src/dsp/node_amp.rs | 124 +- src/dsp/node_biqfilt.rs | 141 ++- src/dsp/node_bosc.rs | 152 ++- src/dsp/node_bowstri.rs | 128 +- src/dsp/node_comb.rs | 86 +- src/dsp/node_cqnt.rs | 113 +- src/dsp/node_delay.rs | 103 +- src/dsp/node_fbwr_fbrd.rs | 93 +- src/dsp/node_map.rs | 130 +- src/dsp/node_mix3.rs | 81 +- src/dsp/node_mux9.rs | 219 ++-- src/dsp/node_noise.rs | 91 +- src/dsp/node_out.rs | 78 +- src/dsp/node_pverb.rs | 139 +-- src/dsp/node_quant.rs | 60 +- src/dsp/node_rndwk.rs | 157 ++- src/dsp/node_sampl.rs | 379 +++--- src/dsp/node_sfilter.rs | 490 ++++---- src/dsp/node_sin.rs | 54 +- src/dsp/node_smap.rs | 138 ++- src/dsp/node_test.rs | 120 +- src/dsp/node_tseq.rs | 178 ++- src/dsp/node_tslfo.rs | 64 +- src/dsp/node_vosc.rs | 132 +-- src/dsp/satom.rs | 53 +- src/dsp/tracker/mod.rs | 169 +-- src/dsp/tracker/pattern.rs | 294 ++--- src/dsp/tracker/sequencer.rs | 356 +++--- src/lib.rs | 27 +- src/log.rs | 28 +- src/matrix.rs | 785 ++++++------- src/matrix_repr.rs | 360 +++--- src/monitor.rs | 199 ++-- src/nodes/drop_thread.rs | 10 +- src/nodes/feedback_filter.rs | 26 +- src/nodes/mod.rs | 61 +- src/nodes/node_conf.rs | 572 ++++----- src/nodes/node_exec.rs | 238 ++-- src/nodes/node_graph_ordering.rs | 100 +- src/nodes/node_prog.rs | 105 +- src/nodes/visual_sampling_filter.rs | 26 +- src/sample_lib.rs | 27 +- src/util.rs | 70 +- tests/basics.rs | 674 ++++++----- tests/common/mod.rs | 356 +++--- tests/modamt.rs | 77 +- tests/node_ad.rs | 605 +++++++--- tests/node_allp.rs | 44 +- tests/node_bosc.rs | 66 +- tests/node_comb.rs | 111 +- tests/node_cqnt.rs | 92 +- tests/node_delay.rs | 310 ++--- tests/node_map.rs | 28 +- tests/node_mix3.rs | 59 +- tests/node_mux9.rs | 60 +- tests/node_noise.rs | 85 +- tests/node_pverb.rs | 144 +-- tests/node_quant.rs | 136 ++- tests/node_rndwk.rs | 216 ++-- tests/node_sampl.rs | 349 +++--- tests/node_sfilter.rs | 1697 ++++++++++++++++++--------- tests/node_smap.rs | 26 +- tests/node_test.rs | 76 +- tests/node_tslfo.rs | 114 +- tests/node_vosc.rs | 543 +++++---- tests/quant.rs | 184 ++- 76 files changed, 7990 insertions(+), 7463 deletions(-) create mode 100644 rustfmt.toml diff --git a/examples/cpal_demo_node_api.rs b/examples/cpal_demo_node_api.rs index 6c38fa6..daac2e8 100644 --- a/examples/cpal_demo_node_api.rs +++ b/examples/cpal_demo_node_api.rs @@ -55,17 +55,20 @@ fn main() { // first the input: (amp, amp.inp("inp").unwrap()), // then the output that is assigned to it: - (sin, sin.out("sig").unwrap())); + (sin, sin.out("sig").unwrap()), + ); node_conf.set_prog_node_exec_connection( &mut prog, (out, out.inp("ch1").unwrap()), - (amp, amp.out("sig").unwrap())); + (amp, amp.out("sig").unwrap()), + ); node_conf.set_prog_node_exec_connection( &mut prog, (out, out.inp("ch2").unwrap()), - (amp, amp.out("sig").unwrap())); + (amp, amp.out("sig").unwrap()), + ); // Finally upload the NodeProg to the audio thread. node_conf.upload_prog(prog, true); @@ -84,40 +87,38 @@ fn main() { // different application (MIDI processing has not been // implemented yet though). - let new_gain = - match amp_counter { - 0 => 0.2, - 1 => 0.3, - 2 => 0.35, - 3 => 0.3, - 4 => 0.1, - _ => { - amp_counter = 0; - // Pitch is defined in 0.1 per octave. - // 0.0 is A4, - // 0.1 is A5 - // -0.1 is A3 - let new_pitch = - match pitch_counter { - 0 => 0.0, // A4 - 1 => -0.1, // A3 - 2 => 0.1, // A5 - 3 => -0.1, // A3 - 4 => -0.2, // A2 - _ => { - pitch_counter = 0; - // -0.15 is 6 semitones above A3 => D#3 - -0.15 - }, - }; - pitch_counter += 1; + let new_gain = match amp_counter { + 0 => 0.2, + 1 => 0.3, + 2 => 0.35, + 3 => 0.3, + 4 => 0.1, + _ => { + amp_counter = 0; + // Pitch is defined in 0.1 per octave. + // 0.0 is A4, + // 0.1 is A5 + // -0.1 is A3 + let new_pitch = match pitch_counter { + 0 => 0.0, // A4 + 1 => -0.1, // A3 + 2 => 0.1, // A5 + 3 => -0.1, // A3 + 4 => -0.2, // A2 + _ => { + pitch_counter = 0; + // -0.15 is 6 semitones above A3 => D#3 + -0.15 + } + }; + pitch_counter += 1; - println!("set pitch={:4.2}", new_pitch); - node_conf.set_param(sin_freq_param, new_pitch.into()); + println!("set pitch={:4.2}", new_pitch); + node_conf.set_param(sin_freq_param, new_pitch.into()); - 0.1 - }, - }; + 0.1 + } + }; amp_counter += 1; println!("set gain={:4.2}", new_gain); @@ -138,7 +139,7 @@ where T: cpal::Sample, { let sample_rate = config.sample_rate.0 as f32; - let channels = config.channels as usize; + let channels = config.channels as usize; node_exec.set_sample_rate(sample_rate); @@ -156,31 +157,20 @@ where node_exec.process_graph_updates(); while frames_left > 0 { - let cur_nframes = - if frames_left >= hexodsp::dsp::MAX_BLOCK_SIZE { - hexodsp::dsp::MAX_BLOCK_SIZE - } else { - frames_left - }; + let cur_nframes = if frames_left >= hexodsp::dsp::MAX_BLOCK_SIZE { + hexodsp::dsp::MAX_BLOCK_SIZE + } else { + frames_left + }; - let input = &[ - &input_bufs[0][0..cur_nframes], - &input_bufs[1][0..cur_nframes], - ]; + let input = &[&input_bufs[0][0..cur_nframes], &input_bufs[1][0..cur_nframes]]; let split = outputbufs.split_at_mut(1); - let mut output = [ - &mut ((split.0[0])[0..cur_nframes]), - &mut ((split.1[0])[0..cur_nframes]), - ]; + let mut output = + [&mut ((split.0[0])[0..cur_nframes]), &mut ((split.1[0])[0..cur_nframes])]; - let mut context = - Context { - nframes: cur_nframes, - output: &mut output[..], - input, - }; + let mut context = Context { nframes: cur_nframes, output: &mut output[..], input }; context.output[0].fill(0.0); context.output[1].fill(0.0); @@ -196,8 +186,7 @@ where if let Some(frame) = out_iter.next() { let mut ctx_chan = 0; for sample in frame.iter_mut() { - let value: T = - cpal::Sample::from::(&context.output[ctx_chan][i]); + let value: T = cpal::Sample::from::(&context.output[ctx_chan][i]); *sample = value; ctx_chan += 1; @@ -231,6 +220,6 @@ fn start_backend(node_exec: NodeExecutor, frontend_loop: F) { cpal::SampleFormat::F32 => run::(&device, &config.into(), node_exec, frontend_loop), cpal::SampleFormat::I16 => run::(&device, &config.into(), node_exec, frontend_loop), cpal::SampleFormat::U16 => run::(&device, &config.into(), node_exec, frontend_loop), - }.expect("cpal works fine"); + } + .expect("cpal works fine"); } - diff --git a/examples/jack_demo_node_api.rs b/examples/jack_demo_node_api.rs index 05c9eae..a41a78c 100644 --- a/examples/jack_demo_node_api.rs +++ b/examples/jack_demo_node_api.rs @@ -55,17 +55,20 @@ fn main() { // first the input: (amp, amp.inp("inp").unwrap()), // then the output that is assigned to it: - (sin, sin.out("sig").unwrap())); + (sin, sin.out("sig").unwrap()), + ); node_conf.set_prog_node_exec_connection( &mut prog, (out, out.inp("ch1").unwrap()), - (amp, amp.out("sig").unwrap())); + (amp, amp.out("sig").unwrap()), + ); node_conf.set_prog_node_exec_connection( &mut prog, (out, out.inp("ch2").unwrap()), - (amp, amp.out("sig").unwrap())); + (amp, amp.out("sig").unwrap()), + ); // Finally upload the NodeProg to the audio thread. node_conf.upload_prog(prog, true); @@ -85,40 +88,38 @@ fn main() { // implemented yet (2021-05-18) and is not implemented // in this jack interface). - let new_gain = - match amp_counter { - 0 => 0.2, - 1 => 0.3, - 2 => 0.35, - 3 => 0.3, - 4 => 0.1, - _ => { - amp_counter = 0; - // Pitch is defined in 0.1 per octave. - // 0.0 is A4, - // 0.1 is A5 - // -0.1 is A3 - let new_pitch = - match pitch_counter { - 0 => 0.0, // A4 - 1 => -0.1, // A3 - 2 => 0.1, // A5 - 3 => -0.1, // A3 - 4 => -0.2, // A2 - _ => { - pitch_counter = 0; - // -0.15 is 6 semitones above A3 => D#3 - -0.15 - }, - }; - pitch_counter += 1; + let new_gain = match amp_counter { + 0 => 0.2, + 1 => 0.3, + 2 => 0.35, + 3 => 0.3, + 4 => 0.1, + _ => { + amp_counter = 0; + // Pitch is defined in 0.1 per octave. + // 0.0 is A4, + // 0.1 is A5 + // -0.1 is A3 + let new_pitch = match pitch_counter { + 0 => 0.0, // A4 + 1 => -0.1, // A3 + 2 => 0.1, // A5 + 3 => -0.1, // A3 + 4 => -0.2, // A2 + _ => { + pitch_counter = 0; + // -0.15 is 6 semitones above A3 => D#3 + -0.15 + } + }; + pitch_counter += 1; - println!("set pitch={:4.2}", new_pitch); - node_conf.set_param(sin_freq_param, new_pitch.into()); + println!("set pitch={:4.2}", new_pitch); + node_conf.set_param(sin_freq_param, new_pitch.into()); - 0.1 - }, - }; + 0.1 + } + }; amp_counter += 1; println!("set gain={:4.2}", new_gain); @@ -139,17 +140,11 @@ impl jack::NotificationHandler for Notifications { } fn shutdown(&mut self, status: jack::ClientStatus, reason: &str) { - println!( - "JACK: shutdown with status {:?} because \"{}\"", - status, reason - ); + println!("JACK: shutdown with status {:?} because \"{}\"", status, reason); } fn freewheel(&mut self, _: &jack::Client, is_enabled: bool) { - println!( - "JACK: freewheel mode is {}", - if is_enabled { "on" } else { "off" } - ); + println!("JACK: freewheel mode is {}", if is_enabled { "on" } else { "off" }); } fn buffer_size(&mut self, _: &jack::Client, sz: jack::Frames) -> jack::Control { @@ -192,10 +187,7 @@ impl jack::NotificationHandler for Notifications { old_name: &str, new_name: &str, ) -> jack::Control { - println!( - "JACK: port with id {} renamed from {} to {}", - port_id, old_name, new_name - ); + println!("JACK: port with id {} renamed from {} to {}", port_id, old_name, new_name); jack::Control::Continue } @@ -210,11 +202,7 @@ impl jack::NotificationHandler for Notifications { "JACK: ports with id {} and {} are {}", port_id_a, port_id_b, - if are_connected { - "connected" - } else { - "disconnected" - } + if are_connected { "connected" } else { "disconnected" } ); } @@ -243,24 +231,15 @@ impl jack::NotificationHandler for Notifications { // runs the audio loop with the NodeExecutor. fn start_backend(node_exec: NodeExecutor, mut frontend_loop: F) { let (client, _status) = - jack::Client::new("HexoDSPJackDemo", jack::ClientOptions::NO_START_SERVER) - .unwrap(); + jack::Client::new("HexoDSPJackDemo", jack::ClientOptions::NO_START_SERVER).unwrap(); - let in_a = - client.register_port("hexodsp_in1", jack::AudioIn::default()) - .unwrap(); - let in_b = - client.register_port("hexodsp_in2", jack::AudioIn::default()) - .unwrap(); - let mut out_a = - client.register_port("hexodsp_out1", jack::AudioOut::default()) - .unwrap(); - let mut out_b = - client.register_port("hexodsp_out2", jack::AudioOut::default()) - .unwrap(); + let in_a = client.register_port("hexodsp_in1", jack::AudioIn::default()).unwrap(); + let in_b = client.register_port("hexodsp_in2", jack::AudioIn::default()).unwrap(); + let mut out_a = client.register_port("hexodsp_out1", jack::AudioOut::default()).unwrap(); + let mut out_b = client.register_port("hexodsp_out2", jack::AudioOut::default()).unwrap(); - let ne = Arc::new(Mutex::new(node_exec)); - let ne2 = ne.clone(); + let ne = Arc::new(Mutex::new(node_exec)); + let ne2 = ne.clone(); let mut first = true; let process_callback = move |client: &jack::Client, ps: &jack::ProcessScope| -> jack::Control { @@ -270,9 +249,11 @@ fn start_backend(node_exec: NodeExecutor, mut frontend_loop: F) { let in_b_p = in_b.as_slice(ps); if first { - client.connect_ports_by_name("HexoDSPJackDemo:hexodsp_out1", "system:playback_1") + client + .connect_ports_by_name("HexoDSPJackDemo:hexodsp_out1", "system:playback_1") .expect("jack connect ports works"); - client.connect_ports_by_name("HexoDSPJackDemo:hexodsp_out2", "system:playback_2") + client + .connect_ports_by_name("HexoDSPJackDemo:hexodsp_out2", "system:playback_2") .expect("jack connect ports works"); first = false; } @@ -293,30 +274,24 @@ fn start_backend(node_exec: NodeExecutor, mut frontend_loop: F) { node_exec.process_graph_updates(); let mut frames_left = nframes; - let mut offs = 0; + let mut offs = 0; while frames_left > 0 { - let cur_nframes = - if frames_left >= hexodsp::dsp::MAX_BLOCK_SIZE { - hexodsp::dsp::MAX_BLOCK_SIZE - } else { - frames_left - }; + let cur_nframes = if frames_left >= hexodsp::dsp::MAX_BLOCK_SIZE { + hexodsp::dsp::MAX_BLOCK_SIZE + } else { + frames_left + }; frames_left -= cur_nframes; - let output = &mut [&mut out_a_p[offs..(offs + cur_nframes)], - &mut out_b_p[offs..(offs + cur_nframes)]]; - let input = - &[&in_a_p[offs..(offs + cur_nframes)], - &in_b_p[offs..(offs + cur_nframes)]]; + let output = &mut [ + &mut out_a_p[offs..(offs + cur_nframes)], + &mut out_b_p[offs..(offs + cur_nframes)], + ]; + let input = &[&in_a_p[offs..(offs + cur_nframes)], &in_b_p[offs..(offs + cur_nframes)]]; - let mut context = - Context { - nframes: cur_nframes, - output, - input, - }; + let mut context = Context { nframes: cur_nframes, output, input }; for i in 0..context.nframes { context.output[0][i] = 0.0; @@ -331,17 +306,12 @@ fn start_backend(node_exec: NodeExecutor, mut frontend_loop: F) { jack::Control::Continue }; - let process = - jack::ClosureProcessHandler::new(process_callback); + let process = jack::ClosureProcessHandler::new(process_callback); // Activate the client, which starts the processing. - let active_client = - client.activate_async(Notifications { - node_exec: ne2, - }, process).unwrap(); + let active_client = client.activate_async(Notifications { node_exec: ne2 }, process).unwrap(); frontend_loop(); active_client.deactivate().unwrap(); } - diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7996b44 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,2 @@ +use_small_heuristics = "Max" +use_field_init_shorthand = true diff --git a/src/cell_dir.rs b/src/cell_dir.rs index 837c869..d4517bb 100644 --- a/src/cell_dir.rs +++ b/src/cell_dir.rs @@ -11,7 +11,7 @@ pub enum CellDir { TL, T, /// Center - C + C, } impl CellDir { @@ -31,11 +31,11 @@ impl CellDir { match self { CellDir::TR => CellDir::BL, CellDir::BR => CellDir::TL, - CellDir::B => CellDir::T, + CellDir::B => CellDir::T, CellDir::BL => CellDir::TR, CellDir::TL => CellDir::BR, - CellDir::T => CellDir::B, - CellDir::C => CellDir::T, + CellDir::T => CellDir::B, + CellDir::C => CellDir::T, } } @@ -62,46 +62,43 @@ impl CellDir { // out 2 - BR CellDir::BR => (1, 1), // out 3 - B - CellDir::B => (0, 1), + CellDir::B => (0, 1), // in 3 - BL CellDir::BL => (-1, 1), // in 2 - TL CellDir::TL => (-1, 0), // in 1 - T - CellDir::T => (0, -1), - _ => (0, 0), + CellDir::T => (0, -1), + _ => (0, 0), } } - pub fn path_from_to(mut a: (usize, usize), b: (usize, usize)) - -> Vec - { + pub fn path_from_to(mut a: (usize, usize), b: (usize, usize)) -> Vec { let mut path = vec![]; - let mut defensive_max : i32 = 1024; + let mut defensive_max: i32 = 1024; while (a.0 != b.0 || a.1 != b.1) && defensive_max > 0 { //d// println!("ITER START: A={:?} B={:?}", a, b); defensive_max -= 1; let mut min_distance = 99999.0; - let mut min_dir = CellDir::C; - let mut min_new_a = a; + let mut min_dir = CellDir::C; + let mut min_new_a = a; for e in 0..6 { let dir = Self::from(e); if let Some(new_pos) = dir.offs_pos(a) { - let dist = - (b.0 as f32 - new_pos.0 as f32).powf(2.0) + let dist = (b.0 as f32 - new_pos.0 as f32).powf(2.0) + (b.1 as f32 - new_pos.1 as f32).powf(2.0); //d// println!("DIST={:5.3} FOR {:?} (B={:?})", dist, new_pos, b); if dist < min_distance { min_distance = dist; - min_dir = dir; - min_new_a = new_pos; + min_dir = dir; + min_new_a = new_pos; } } else { //d// println!("NOPOS {:?} {:?}", dir, a); @@ -128,10 +125,7 @@ impl CellDir { pub fn offs_pos(&self, pos: (usize, usize)) -> Option<(usize, usize)> { let offs = self.as_offs(pos.0); - let new_pos = ( - pos.0 as i32 + offs.0, - pos.1 as i32 + offs.1 - ); + let new_pos = (pos.0 as i32 + offs.0, pos.1 as i32 + offs.1); if new_pos.0 >= 0 && new_pos.1 >= 0 { Some((new_pos.0 as usize, new_pos.1 as usize)) @@ -148,14 +142,14 @@ impl CellDir { // out 2 - BR CellDir::BR => (1, if even { 0 } else { 1 }), // out 3 - B - CellDir::B => (0, 1), + CellDir::B => (0, 1), // in 3 - BL CellDir::BL => (-1, if even { 0 } else { 1 }), // in 2 - TL CellDir::TL => (-1, if even { -1 } else { 0 }), // in 1 - T - CellDir::T => (0, -1), - _ => (0, 0), + CellDir::T => (0, -1), + _ => (0, 0), } } diff --git a/src/dsp/biquad.rs b/src/dsp/biquad.rs index f512a88..fdc3738 100644 --- a/src/dsp/biquad.rs +++ b/src/dsp/biquad.rs @@ -34,24 +34,22 @@ impl BiquadCoefs { /// Cutoff is the -3 dB point of the filter in Hz. #[inline] pub fn butter_lowpass(sample_rate: f32, cutoff: f32) -> BiquadCoefs { - let f = (cutoff * PI / sample_rate).tan(); + let f = (cutoff * PI / sample_rate).tan(); let a0r = 1.0 / (1.0 + SQRT_2 * f + f * f); - let a1 = (2.0 * f * f - 2.0) * a0r; - let a2 = (1.0 - SQRT_2 * f + f * f) * a0r; - let b0 = f * f * a0r; - let b1 = 2.0 * b0; - let b2 = b0; + let a1 = (2.0 * f * f - 2.0) * a0r; + let a2 = (1.0 - SQRT_2 * f + f * f) * a0r; + let b0 = f * f * a0r; + let b1 = 2.0 * b0; + let b2 = b0; BiquadCoefs { a1, a2, b0, b1, b2 } } /// Returns the Q for cascading a butterworth filter: fn calc_cascaded_butter_q(order: usize, casc_idx: usize) -> f32 { - let order = order as f32; + let order = order as f32; let casc_idx = casc_idx as f32; - let b = - -2.0 * ((2.0 * casc_idx + order - 1.0) * PI / (2.0 * order)) - .cos(); + let b = -2.0 * ((2.0 * casc_idx + order - 1.0) * PI / (2.0 * order)).cos(); 1.0 / b } @@ -59,7 +57,7 @@ impl BiquadCoefs { /// Returns settings for a lowpass filter with a specific q #[inline] pub fn lowpass(sample_rate: f32, q: f32, cutoff: f32) -> BiquadCoefs { - let f = (cutoff * PI / sample_rate).tan(); + let f = (cutoff * PI / sample_rate).tan(); let a0r = 1.0 / (1.0 + f / q + f * f); /* @@ -71,11 +69,11 @@ impl BiquadCoefs { this->a[2] = (1.f - K / Q + K * K) * norm; */ - let b0 = f * f * a0r; - let b1 = 2.0 * b0; - let b2 = b0; - let a1 = 2.0 * (f * f - 1.0) * a0r; - let a2 = (1.0 - f / q + f * f) * a0r; + let b0 = f * f * a0r; + let b1 = 2.0 * b0; + let b2 = b0; + let a1 = 2.0 * (f * f - 1.0) * a0r; + let a2 = (1.0 - f / q + f * f) * a0r; BiquadCoefs { a1, a2, b0, b1, b2 } } @@ -85,7 +83,7 @@ impl BiquadCoefs { /// Bandwidth is the difference in Hz between -3 dB points of the filter response. /// The overall gain of the filter is independent of bandwidth. pub fn resonator(sample_rate: f32, center: f32, bandwidth: f32) -> BiquadCoefs { - let r = (-PI * bandwidth / sample_rate).exp(); + let r = (-PI * bandwidth / sample_rate).exp(); let a1 = -2.0 * r * (TAU * center / sample_rate).cos(); let a2 = r * r; let b0 = (1.0 - r * r).sqrt() * 0.5; @@ -94,13 +92,13 @@ impl BiquadCoefs { BiquadCoefs { a1, a2, b0, b1, b2 } } -// /// Frequency response at frequency `omega` expressed as fraction of sampling rate. -// pub fn response(&self, omega: f64) -> Complex64 { -// let z1 = Complex64::from_polar(1.0, -TAU * omega); -// let z2 = Complex64::from_polar(1.0, -2.0 * TAU * omega); -// (re(self.b0) + re(self.b1) * z1 + re(self.b2) * z2) -// / (re(1.0) + re(self.a1) * z1 + re(self.a2) * z2) -// } + // /// Frequency response at frequency `omega` expressed as fraction of sampling rate. + // pub fn response(&self, omega: f64) -> Complex64 { + // let z1 = Complex64::from_polar(1.0, -TAU * omega); + // let z2 = Complex64::from_polar(1.0, -2.0 * TAU * omega); + // (re(self.b0) + re(self.b1) * z1 + re(self.b2) * z2) + // / (re(1.0) + re(self.a1) * z1 + re(self.a2) * z2) + // } } /// 2nd order IIR filter implemented in normalized Direct Form I. @@ -145,10 +143,7 @@ impl Biquad { #[inline] pub fn tick(&mut self, input: f32) -> f32 { let x0 = input; - let y0 = - self.coefs.b0 * x0 - + self.coefs.b1 * self.x1 - + self.coefs.b2 * self.x2 + let y0 = self.coefs.b0 * x0 + self.coefs.b1 * self.x1 + self.coefs.b2 * self.x2 - self.coefs.a1 * self.y1 - self.coefs.a2 * self.y2; self.x2 = self.x1; @@ -174,18 +169,13 @@ pub struct ButterLowpass { #[allow(dead_code)] impl ButterLowpass { pub fn new(sample_rate: f32, cutoff: f32) -> Self { - let mut this = ButterLowpass { - biquad: Biquad::new(), - sample_rate, - cutoff: 0.0, - }; + let mut this = ButterLowpass { biquad: Biquad::new(), sample_rate, cutoff: 0.0 }; this.set_cutoff(cutoff); this } pub fn set_cutoff(&mut self, cutoff: f32) { - self.biquad - .set_coefs(BiquadCoefs::butter_lowpass(self.sample_rate, cutoff)); + self.biquad.set_coefs(BiquadCoefs::butter_lowpass(self.sample_rate, cutoff)); self.cutoff = cutoff; } @@ -218,15 +208,12 @@ impl ButterLowpass { #[derive(Debug, Copy, Clone)] pub struct Oversampling { filters: [Biquad; 4], - buffer: [f32; N], + buffer: [f32; N], } impl Oversampling { pub fn new() -> Self { - let mut this = Self { - filters: [Biquad::new(); 4], - buffer: [0.0; N], - }; + let mut this = Self { filters: [Biquad::new(); 4], buffer: [0.0; N] }; this.set_sample_rate(44100.0); @@ -243,7 +230,7 @@ impl Oversampling { pub fn set_sample_rate(&mut self, srate: f32) { let cutoff = 0.98 * (0.5 * srate); - let ovr_srate = (N as f32) * srate; + let ovr_srate = (N as f32) * srate; let filters_len = self.filters.len(); for (i, filt) in self.filters.iter_mut().enumerate() { @@ -266,7 +253,9 @@ impl Oversampling { } #[inline] - pub fn resample_buffer(&mut self) -> &mut [f32; N] { &mut self.buffer } + pub fn resample_buffer(&mut self) -> &mut [f32; N] { + &mut self.buffer + } #[inline] pub fn downsample(&mut self) -> f32 { diff --git a/src/dsp/dattorro.rs b/src/dsp/dattorro.rs index e45dc4b..8dd70ed 100644 --- a/src/dsp/dattorro.rs +++ b/src/dsp/dattorro.rs @@ -17,90 +17,83 @@ use crate::dsp::helpers::crossfade; -const DAT_SAMPLE_RATE : f64 = 29761.0; -const DAT_SAMPLES_PER_MS : f64 = DAT_SAMPLE_RATE / 1000.0; +const DAT_SAMPLE_RATE: f64 = 29761.0; +const DAT_SAMPLES_PER_MS: f64 = DAT_SAMPLE_RATE / 1000.0; -const DAT_INPUT_APF_TIMES_MS : [f64; 4] = [ +const DAT_INPUT_APF_TIMES_MS: [f64; 4] = [ 141.0 / DAT_SAMPLES_PER_MS, 107.0 / DAT_SAMPLES_PER_MS, 379.0 / DAT_SAMPLES_PER_MS, 277.0 / DAT_SAMPLES_PER_MS, ]; -const DAT_LEFT_APF1_TIME_MS : f64 = 672.0 / DAT_SAMPLES_PER_MS; -const DAT_LEFT_APF2_TIME_MS : f64 = 1800.0 / DAT_SAMPLES_PER_MS; +const DAT_LEFT_APF1_TIME_MS: f64 = 672.0 / DAT_SAMPLES_PER_MS; +const DAT_LEFT_APF2_TIME_MS: f64 = 1800.0 / DAT_SAMPLES_PER_MS; -const DAT_RIGHT_APF1_TIME_MS : f64 = 908.0 / DAT_SAMPLES_PER_MS; -const DAT_RIGHT_APF2_TIME_MS : f64 = 2656.0 / DAT_SAMPLES_PER_MS; +const DAT_RIGHT_APF1_TIME_MS: f64 = 908.0 / DAT_SAMPLES_PER_MS; +const DAT_RIGHT_APF2_TIME_MS: f64 = 2656.0 / DAT_SAMPLES_PER_MS; -const DAT_LEFT_DELAY1_TIME_MS : f64 = 4453.0 / DAT_SAMPLES_PER_MS; -const DAT_LEFT_DELAY2_TIME_MS : f64 = 3720.0 / DAT_SAMPLES_PER_MS; +const DAT_LEFT_DELAY1_TIME_MS: f64 = 4453.0 / DAT_SAMPLES_PER_MS; +const DAT_LEFT_DELAY2_TIME_MS: f64 = 3720.0 / DAT_SAMPLES_PER_MS; -const DAT_RIGHT_DELAY1_TIME_MS : f64 = 4217.0 / DAT_SAMPLES_PER_MS; -const DAT_RIGHT_DELAY2_TIME_MS : f64 = 3163.0 / DAT_SAMPLES_PER_MS; +const DAT_RIGHT_DELAY1_TIME_MS: f64 = 4217.0 / DAT_SAMPLES_PER_MS; +const DAT_RIGHT_DELAY2_TIME_MS: f64 = 3163.0 / DAT_SAMPLES_PER_MS; -const DAT_LEFT_TAPS_TIME_MS : [f64; 7] = [ - 266.0 / DAT_SAMPLES_PER_MS, +const DAT_LEFT_TAPS_TIME_MS: [f64; 7] = [ + 266.0 / DAT_SAMPLES_PER_MS, 2974.0 / DAT_SAMPLES_PER_MS, 1913.0 / DAT_SAMPLES_PER_MS, 1996.0 / DAT_SAMPLES_PER_MS, 1990.0 / DAT_SAMPLES_PER_MS, - 187.0 / DAT_SAMPLES_PER_MS, + 187.0 / DAT_SAMPLES_PER_MS, 1066.0 / DAT_SAMPLES_PER_MS, ]; -const DAT_RIGHT_TAPS_TIME_MS : [f64; 7] = [ - 353.0 / DAT_SAMPLES_PER_MS, +const DAT_RIGHT_TAPS_TIME_MS: [f64; 7] = [ + 353.0 / DAT_SAMPLES_PER_MS, 3627.0 / DAT_SAMPLES_PER_MS, 1228.0 / DAT_SAMPLES_PER_MS, 2673.0 / DAT_SAMPLES_PER_MS, 2111.0 / DAT_SAMPLES_PER_MS, - 335.0 / DAT_SAMPLES_PER_MS, - 121.0 / DAT_SAMPLES_PER_MS, + 335.0 / DAT_SAMPLES_PER_MS, + 121.0 / DAT_SAMPLES_PER_MS, ]; -const DAT_LFO_FREQS_HZ : [f64; 4] = [ 0.1, 0.15, 0.12, 0.18 ]; +const DAT_LFO_FREQS_HZ: [f64; 4] = [0.1, 0.15, 0.12, 0.18]; -const DAT_INPUT_DIFFUSION1 : f64 = 0.75; -const DAT_INPUT_DIFFUSION2 : f64 = 0.625; -const DAT_PLATE_DIFFUSION1 : f64 = 0.7; -const DAT_PLATE_DIFFUSION2 : f64 = 0.5; +const DAT_INPUT_DIFFUSION1: f64 = 0.75; +const DAT_INPUT_DIFFUSION2: f64 = 0.625; +const DAT_PLATE_DIFFUSION1: f64 = 0.7; +const DAT_PLATE_DIFFUSION2: f64 = 0.5; -const DAT_LFO_EXCURSION_MS : f64 = 16.0 / DAT_SAMPLES_PER_MS; -const DAT_LFO_EXCURSION_MOD_MAX : f64 = 16.0; +const DAT_LFO_EXCURSION_MS: f64 = 16.0 / DAT_SAMPLES_PER_MS; +const DAT_LFO_EXCURSION_MOD_MAX: f64 = 16.0; -use crate::dsp::helpers::{ - AllPass, - TriSawLFO, - OnePoleLPF, - OnePoleHPF, - DelayBuffer, - DCBlockFilter -}; +use crate::dsp::helpers::{AllPass, DCBlockFilter, DelayBuffer, OnePoleHPF, OnePoleLPF, TriSawLFO}; #[derive(Debug, Clone)] pub struct DattorroReverb { last_scale: f64, - inp_dc_block: [DCBlockFilter; 2], - out_dc_block: [DCBlockFilter; 2], + inp_dc_block: [DCBlockFilter; 2], + out_dc_block: [DCBlockFilter; 2], lfos: [TriSawLFO; 4], input_hpf: OnePoleHPF, input_lpf: OnePoleLPF, - pre_delay: DelayBuffer, + pre_delay: DelayBuffer, input_apfs: [(AllPass, f64, f64); 4], - apf1: [(AllPass, f64, f64); 2], - hpf: [OnePoleHPF; 2], - lpf: [OnePoleLPF; 2], - apf2: [(AllPass, f64, f64); 2], + apf1: [(AllPass, f64, f64); 2], + hpf: [OnePoleHPF; 2], + lpf: [OnePoleLPF; 2], + apf2: [(AllPass, f64, f64); 2], delay1: [(DelayBuffer, f64); 2], delay2: [(DelayBuffer, f64); 2], - left_sum: f64, + left_sum: f64, right_sum: f64, dbg_count: usize, @@ -140,21 +133,21 @@ impl DattorroReverb { let mut this = Self { last_scale: 1.0, - inp_dc_block: [DCBlockFilter::new(); 2], - out_dc_block: [DCBlockFilter::new(); 2], + inp_dc_block: [DCBlockFilter::new(); 2], + out_dc_block: [DCBlockFilter::new(); 2], lfos: [TriSawLFO::new(); 4], input_hpf: OnePoleHPF::new(), input_lpf: OnePoleLPF::new(), - pre_delay: DelayBuffer::new(), + pre_delay: DelayBuffer::new(), input_apfs: Default::default(), - apf1: Default::default(), - hpf: [OnePoleHPF::new(); 2], - lpf: [OnePoleLPF::new(); 2], - apf2: Default::default(), + apf1: Default::default(), + hpf: [OnePoleHPF::new(); 2], + lpf: [OnePoleLPF::new(); 2], + apf2: Default::default(), delay1: Default::default(), delay2: Default::default(), @@ -176,23 +169,15 @@ impl DattorroReverb { self.input_lpf.set_freq(22000.0); self.input_hpf.set_freq(0.0); - self.input_apfs[0] = - (AllPass::new(), DAT_INPUT_APF_TIMES_MS[0], DAT_INPUT_DIFFUSION1); - self.input_apfs[1] = - (AllPass::new(), DAT_INPUT_APF_TIMES_MS[1], DAT_INPUT_DIFFUSION1); - self.input_apfs[2] = - (AllPass::new(), DAT_INPUT_APF_TIMES_MS[2], DAT_INPUT_DIFFUSION2); - self.input_apfs[3] = - (AllPass::new(), DAT_INPUT_APF_TIMES_MS[3], DAT_INPUT_DIFFUSION2); + self.input_apfs[0] = (AllPass::new(), DAT_INPUT_APF_TIMES_MS[0], DAT_INPUT_DIFFUSION1); + self.input_apfs[1] = (AllPass::new(), DAT_INPUT_APF_TIMES_MS[1], DAT_INPUT_DIFFUSION1); + self.input_apfs[2] = (AllPass::new(), DAT_INPUT_APF_TIMES_MS[2], DAT_INPUT_DIFFUSION2); + self.input_apfs[3] = (AllPass::new(), DAT_INPUT_APF_TIMES_MS[3], DAT_INPUT_DIFFUSION2); - self.apf1[0] = - (AllPass::new(), DAT_LEFT_APF1_TIME_MS, -DAT_PLATE_DIFFUSION1); - self.apf1[1] = - (AllPass::new(), DAT_RIGHT_APF1_TIME_MS, -DAT_PLATE_DIFFUSION1); - self.apf2[0] = - (AllPass::new(), DAT_LEFT_APF2_TIME_MS, -DAT_PLATE_DIFFUSION2); - self.apf2[1] = - (AllPass::new(), DAT_RIGHT_APF2_TIME_MS, -DAT_PLATE_DIFFUSION2); + self.apf1[0] = (AllPass::new(), DAT_LEFT_APF1_TIME_MS, -DAT_PLATE_DIFFUSION1); + self.apf1[1] = (AllPass::new(), DAT_RIGHT_APF1_TIME_MS, -DAT_PLATE_DIFFUSION1); + self.apf2[0] = (AllPass::new(), DAT_LEFT_APF2_TIME_MS, -DAT_PLATE_DIFFUSION2); + self.apf2[1] = (AllPass::new(), DAT_RIGHT_APF2_TIME_MS, -DAT_PLATE_DIFFUSION2); self.delay1[0] = (DelayBuffer::new(), DAT_LEFT_DELAY1_TIME_MS); self.delay1[1] = (DelayBuffer::new(), DAT_RIGHT_DELAY1_TIME_MS); @@ -229,7 +214,7 @@ impl DattorroReverb { self.pre_delay.reset(); - self.left_sum = 0.0; + self.left_sum = 0.0; self.right_sum = 0.0; self.set_time_scale(1.0); @@ -241,14 +226,14 @@ impl DattorroReverb { let scale = scale.max(0.1); self.last_scale = scale; - self.apf1[0].1 = DAT_LEFT_APF1_TIME_MS * scale; + self.apf1[0].1 = DAT_LEFT_APF1_TIME_MS * scale; self.apf1[1].1 = DAT_RIGHT_APF1_TIME_MS * scale; - self.apf2[0].1 = DAT_LEFT_APF2_TIME_MS * scale; + self.apf2[0].1 = DAT_LEFT_APF2_TIME_MS * scale; self.apf2[1].1 = DAT_RIGHT_APF2_TIME_MS * scale; - self.delay1[0].1 = DAT_LEFT_DELAY1_TIME_MS * scale; + self.delay1[0].1 = DAT_LEFT_DELAY1_TIME_MS * scale; self.delay1[1].1 = DAT_RIGHT_DELAY1_TIME_MS * scale; - self.delay2[0].1 = DAT_LEFT_DELAY2_TIME_MS * scale; + self.delay2[0].1 = DAT_LEFT_DELAY2_TIME_MS * scale; self.delay2[1].1 = DAT_RIGHT_DELAY2_TIME_MS * scale; } } @@ -291,44 +276,40 @@ impl DattorroReverb { } #[inline] - fn calc_apf_delay_times(&mut self, params: &mut dyn DattorroReverbParams) - -> (f64, f64, f64, f64) - { - let left_apf1_delay_ms = - self.apf1[0].1 + fn calc_apf_delay_times( + &mut self, + params: &mut dyn DattorroReverbParams, + ) -> (f64, f64, f64, f64) { + let left_apf1_delay_ms = self.apf1[0].1 + (self.lfos[0].next_bipolar() as f64 - * DAT_LFO_EXCURSION_MS - * DAT_LFO_EXCURSION_MOD_MAX - * params.mod_depth()); - let right_apf1_delay_ms = - self.apf1[1].1 + * DAT_LFO_EXCURSION_MS + * DAT_LFO_EXCURSION_MOD_MAX + * params.mod_depth()); + let right_apf1_delay_ms = self.apf1[1].1 + (self.lfos[1].next_bipolar() as f64 - * DAT_LFO_EXCURSION_MS - * DAT_LFO_EXCURSION_MOD_MAX - * params.mod_depth()); - let left_apf2_delay_ms = - self.apf2[0].1 + * DAT_LFO_EXCURSION_MS + * DAT_LFO_EXCURSION_MOD_MAX + * params.mod_depth()); + let left_apf2_delay_ms = self.apf2[0].1 + (self.lfos[2].next_bipolar() as f64 - * DAT_LFO_EXCURSION_MS - * DAT_LFO_EXCURSION_MOD_MAX - * params.mod_depth()); - let right_apf2_delay_ms = - self.apf2[1].1 + * DAT_LFO_EXCURSION_MS + * DAT_LFO_EXCURSION_MOD_MAX + * params.mod_depth()); + let right_apf2_delay_ms = self.apf2[1].1 + (self.lfos[3].next_bipolar() as f64 - * DAT_LFO_EXCURSION_MS - * DAT_LFO_EXCURSION_MOD_MAX - * params.mod_depth()); + * DAT_LFO_EXCURSION_MS + * DAT_LFO_EXCURSION_MOD_MAX + * params.mod_depth()); - (left_apf1_delay_ms, right_apf1_delay_ms, - left_apf2_delay_ms, right_apf2_delay_ms) + (left_apf1_delay_ms, right_apf1_delay_ms, left_apf2_delay_ms, right_apf2_delay_ms) } pub fn process( &mut self, params: &mut dyn DattorroReverbParams, - input_l: f64, input_r: f64 - ) -> (f64, f64) - { + input_l: f64, + input_r: f64, + ) -> (f64, f64) { // Some parameter setup... let timescale = 0.1 + (4.0 - 0.1) * params.time_scale(); self.set_time_scale(timescale); @@ -342,23 +323,18 @@ impl DattorroReverb { let mod_speed = mod_speed * mod_speed; let mod_speed = mod_speed * 99.0 + 1.0; - self.lfos[0].set( - DAT_LFO_FREQS_HZ[0] * mod_speed, params.mod_shape()); - self.lfos[1].set( - DAT_LFO_FREQS_HZ[1] * mod_speed, params.mod_shape()); - self.lfos[2].set( - DAT_LFO_FREQS_HZ[2] * mod_speed, params.mod_shape()); - self.lfos[3].set( - DAT_LFO_FREQS_HZ[3] * mod_speed, params.mod_shape()); + self.lfos[0].set(DAT_LFO_FREQS_HZ[0] * mod_speed, params.mod_shape()); + self.lfos[1].set(DAT_LFO_FREQS_HZ[1] * mod_speed, params.mod_shape()); + self.lfos[2].set(DAT_LFO_FREQS_HZ[2] * mod_speed, params.mod_shape()); + self.lfos[3].set(DAT_LFO_FREQS_HZ[3] * mod_speed, params.mod_shape()); self.apf1[0].2 = -DAT_PLATE_DIFFUSION1 * params.diffusion(); self.apf1[1].2 = -DAT_PLATE_DIFFUSION1 * params.diffusion(); - self.apf2[0].2 = DAT_PLATE_DIFFUSION2 * params.diffusion(); - self.apf2[1].2 = DAT_PLATE_DIFFUSION2 * params.diffusion(); + self.apf2[0].2 = DAT_PLATE_DIFFUSION2 * params.diffusion(); + self.apf2[1].2 = DAT_PLATE_DIFFUSION2 * params.diffusion(); - let (left_apf1_delay_ms, right_apf1_delay_ms, - left_apf2_delay_ms, right_apf2_delay_ms) - = self.calc_apf_delay_times(params); + let (left_apf1_delay_ms, right_apf1_delay_ms, left_apf2_delay_ms, right_apf2_delay_ms) = + self.calc_apf_delay_times(params); // Parameter setup done! @@ -373,13 +349,11 @@ impl DattorroReverb { let out_hpf = self.input_hpf.process(out_lpf); // HPF => Pre-Delay - let out_pre_delay = - if params.pre_delay_time_ms() < 0.1 { - out_hpf - } else { - self.pre_delay.next_cubic( - params.pre_delay_time_ms(), out_hpf) - }; + let out_pre_delay = if params.pre_delay_time_ms() < 0.1 { + out_hpf + } else { + self.pre_delay.next_cubic(params.pre_delay_time_ms(), out_hpf) + }; // Pre-Delay => 4 All-Pass filters let mut diffused = out_pre_delay; @@ -388,11 +362,10 @@ impl DattorroReverb { } // Mix between diffused and pre-delayed intput for further processing - let tank_feed = - crossfade(out_pre_delay, diffused, params.input_diffusion_mix()); + let tank_feed = crossfade(out_pre_delay, diffused, params.input_diffusion_mix()); // First tap for the output - self.left_sum += tank_feed; + self.left_sum += tank_feed; self.right_sum += tank_feed; // Calculate tank decay of the left/right signal channels. @@ -411,22 +384,21 @@ impl DattorroReverb { let left = self.apf2[0].0.next(left_apf2_delay_ms, self.apf2[0].2, left); let left = self.delay2[0].0.next_cubic(self.delay2[0].1, left); -// if self.dbg_count % 48 == 0 { -// println!("APFS dcy={:8.6}; {:8.6} {:8.6} {:8.6} {:8.6} | {:8.6} {:8.6} {:8.6} {:8.6}", -// decay, -// self.apf1[0].2, -// self.apf1[1].2, -// self.apf2[0].2, -// self.apf2[1].2, -// left_apf1_delay_ms, right_apf1_delay_ms, -// left_apf2_delay_ms, right_apf2_delay_ms); -// println!("DELY1/2 {:8.6} / {:8.6} | {:8.6} / {:8.6}", -// self.delay1[0].1, -// self.delay2[0].1, -// self.delay1[1].1, -// self.delay2[1].1); -// } - + // if self.dbg_count % 48 == 0 { + // println!("APFS dcy={:8.6}; {:8.6} {:8.6} {:8.6} {:8.6} | {:8.6} {:8.6} {:8.6} {:8.6}", + // decay, + // self.apf1[0].2, + // self.apf1[1].2, + // self.apf2[0].2, + // self.apf2[1].2, + // left_apf1_delay_ms, right_apf1_delay_ms, + // left_apf2_delay_ms, right_apf2_delay_ms); + // println!("DELY1/2 {:8.6} / {:8.6} | {:8.6} / {:8.6}", + // self.delay1[0].1, + // self.delay2[0].1, + // self.delay1[1].1, + // self.delay2[1].1); + // } // Right Sum => APF1 => Delay1 => LPF => HPF => APF2 => Delay2 // And then send this over to the left sum. @@ -441,27 +413,27 @@ impl DattorroReverb { let right = self.delay2[1].0.next_cubic(self.delay2[1].1, right); self.right_sum = left * decay; - self.left_sum = right * decay; + self.left_sum = right * decay; let mut left_accum = left_apf_tap; - left_accum += self.delay1[0].0.tap_n( DAT_LEFT_TAPS_TIME_MS[0]); - left_accum += self.delay1[0].0.tap_n( DAT_LEFT_TAPS_TIME_MS[1]); + left_accum += self.delay1[0].0.tap_n(DAT_LEFT_TAPS_TIME_MS[0]); + left_accum += self.delay1[0].0.tap_n(DAT_LEFT_TAPS_TIME_MS[1]); left_accum -= self.apf2[0].0.delay_tap_n(DAT_LEFT_TAPS_TIME_MS[2]); - left_accum += self.delay2[0].0.tap_n( DAT_LEFT_TAPS_TIME_MS[3]); - left_accum -= self.delay1[1].0.tap_n( DAT_LEFT_TAPS_TIME_MS[4]); + left_accum += self.delay2[0].0.tap_n(DAT_LEFT_TAPS_TIME_MS[3]); + left_accum -= self.delay1[1].0.tap_n(DAT_LEFT_TAPS_TIME_MS[4]); left_accum -= self.apf2[1].0.delay_tap_n(DAT_LEFT_TAPS_TIME_MS[5]); - left_accum -= self.delay2[1].0.tap_n( DAT_LEFT_TAPS_TIME_MS[6]); + left_accum -= self.delay2[1].0.tap_n(DAT_LEFT_TAPS_TIME_MS[6]); let mut right_accum = right_apf_tap; - right_accum += self.delay1[1].0.tap_n( DAT_RIGHT_TAPS_TIME_MS[0]); - right_accum += self.delay1[1].0.tap_n( DAT_RIGHT_TAPS_TIME_MS[1]); + right_accum += self.delay1[1].0.tap_n(DAT_RIGHT_TAPS_TIME_MS[0]); + right_accum += self.delay1[1].0.tap_n(DAT_RIGHT_TAPS_TIME_MS[1]); right_accum -= self.apf2[1].0.delay_tap_n(DAT_RIGHT_TAPS_TIME_MS[2]); - right_accum += self.delay2[1].0.tap_n( DAT_RIGHT_TAPS_TIME_MS[3]); - right_accum -= self.delay1[0].0.tap_n( DAT_RIGHT_TAPS_TIME_MS[4]); + right_accum += self.delay2[1].0.tap_n(DAT_RIGHT_TAPS_TIME_MS[3]); + right_accum -= self.delay1[0].0.tap_n(DAT_RIGHT_TAPS_TIME_MS[4]); right_accum -= self.apf2[0].0.delay_tap_n(DAT_RIGHT_TAPS_TIME_MS[5]); - right_accum -= self.delay2[0].0.tap_n( DAT_RIGHT_TAPS_TIME_MS[6]); + right_accum -= self.delay2[0].0.tap_n(DAT_RIGHT_TAPS_TIME_MS[6]); - let left_out = self.out_dc_block[0].next(left_accum); + let left_out = self.out_dc_block[0].next(left_accum); let right_out = self.out_dc_block[1].next(right_accum); self.dbg_count += 1; diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 493f673..520133a 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -2,8 +2,8 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use num_traits::{cast::FromPrimitive, cast::ToPrimitive, Float, FloatConst}; use std::cell::RefCell; -use num_traits::{Float, FloatConst, cast::FromPrimitive, cast::ToPrimitive}; macro_rules! trait_alias { ($name:ident = $base1:ident + $($base2:ident +)+) => { @@ -15,19 +15,16 @@ macro_rules! trait_alias { trait_alias!(Flt = Float + FloatConst + ToPrimitive + FromPrimitive +); /// Logarithmic table size of the table in [fast_cos] / [fast_sin]. -static FAST_COS_TAB_LOG2_SIZE : usize = 9; +static FAST_COS_TAB_LOG2_SIZE: usize = 9; /// Table size of the table in [fast_cos] / [fast_sin]. -static FAST_COS_TAB_SIZE : usize = 1 << FAST_COS_TAB_LOG2_SIZE; // =512 +static FAST_COS_TAB_SIZE: usize = 1 << FAST_COS_TAB_LOG2_SIZE; // =512 /// The wave table of [fast_cos] / [fast_sin]. -static mut FAST_COS_TAB : [f32; 513] = [0.0; 513]; +static mut FAST_COS_TAB: [f32; 513] = [0.0; 513]; /// Initializes the cosine wave table for [fast_cos] and [fast_sin]. pub fn init_cos_tab() { - for i in 0..(FAST_COS_TAB_SIZE+1) { - let phase : f32 = - (i as f32) - * ((std::f32::consts::TAU) - / (FAST_COS_TAB_SIZE as f32)); + for i in 0..(FAST_COS_TAB_SIZE + 1) { + let phase: f32 = (i as f32) * ((std::f32::consts::TAU) / (FAST_COS_TAB_SIZE as f32)); unsafe { // XXX: note: mutable statics can be mutated by multiple // threads: aliasing violations or data races @@ -38,7 +35,7 @@ pub fn init_cos_tab() { } /// Internal phase increment/scaling for [fast_cos]. -const PHASE_SCALE : f32 = 1.0_f32 / (std::f32::consts::TAU); +const PHASE_SCALE: f32 = 1.0_f32 / (std::f32::consts::TAU); /// A faster implementation of cosine. It's not that much faster than /// Rust's built in cosine function. But YMMV. @@ -67,8 +64,8 @@ pub fn fast_cos(mut x: f32) -> f32 { // XXX: note: mutable statics can be mutated by multiple // threads: aliasing violations or data races // will cause undefined behavior - let left = FAST_COS_TAB[index as usize]; - let right = FAST_COS_TAB[index as usize + 1]; + let left = FAST_COS_TAB[index as usize]; + let right = FAST_COS_TAB[index as usize + 1]; return left + (right - left) * fract; } @@ -117,7 +114,7 @@ pub struct RandGen { // https://github.com/mscharley/rust-xoroshiro128 /// Given the mutable `state` generates the next pseudo random number. pub fn next_xoroshiro128(state: &mut [u64; 2]) -> u64 { - let s0: u64 = state[0]; + let s0: u64 = state[0]; let mut s1: u64 = state[1]; let result: u64 = s0.wrapping_add(s1); @@ -134,17 +131,15 @@ pub fn next_xoroshiro128(state: &mut [u64; 2]) -> u64 { /// Maps any `u64` to a `f64` in the open interval `[0.0, 1.0)`. pub fn u64_to_open01(u: u64) -> f64 { use core::f64::EPSILON; - let float_size = std::mem::size_of::() as u32 * 8; - let fraction = u >> (float_size - 52); + let float_size = std::mem::size_of::() as u32 * 8; + let fraction = u >> (float_size - 52); let exponent_bits: u64 = (1023 as u64) << 52; f64::from_bits(fraction | exponent_bits) - (1.0 - EPSILON / 2.0) } impl RandGen { pub fn new() -> Self { - RandGen { - r: [0x193a6754a8a7d469, 0x97830e05113ba7bb], - } + RandGen { r: [0x193a6754a8a7d469, 0x97830e05113ba7bb] } } /// Next random unsigned 64bit integer. @@ -206,7 +201,7 @@ pub fn rand_u64() -> u64 { // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -//- splitmix64 (http://xoroshiro.di.unimi.it/splitmix64.c) +//- splitmix64 (http://xoroshiro.di.unimi.it/splitmix64.c) // /// A splitmix64 random number generator. /// @@ -224,7 +219,9 @@ pub struct SplitMix64(pub u64); const PHI: u64 = 0x9e3779b97f4a7c15; impl SplitMix64 { - pub fn new(seed: u64) -> Self { Self(seed) } + pub fn new(seed: u64) -> Self { + Self(seed) + } pub fn new_from_i64(seed: i64) -> Self { Self::new(u64::from_be_bytes(seed.to_be_bytes())) } @@ -249,8 +246,7 @@ impl SplitMix64 { #[inline] pub fn next_i64(&mut self) -> i64 { - i64::from_be_bytes( - self.next_u64().to_be_bytes()) + i64::from_be_bytes(self.next_u64().to_be_bytes()) } #[inline] @@ -283,7 +279,6 @@ pub fn crossfade_clip(v1: F, v2: F, mix: F) -> F { v1 * (f::(1.0) - mix) + (v2 * mix).min(f::(1.0)).max(f::(-1.0)) } - /// Linear (f32) crossfade with driving the `v2` result through a tanh(). /// /// * `v1` - signal 1, range -1.0 to 1.0 @@ -306,8 +301,8 @@ pub fn crossfade_cpow(v1: f32, v2: f32, mix: f32) -> f32 { v1 * s2 + v2 * s1 } -const CROSS_LOG_MIN : f32 = -13.815510557964274; // (0.000001_f32).ln(); -const CROSS_LOG_MAX : f32 = 0.0; // (1.0_f32).ln(); +const CROSS_LOG_MIN: f32 = -13.815510557964274; // (0.000001_f32).ln(); +const CROSS_LOG_MAX: f32 = 0.0; // (1.0_f32).ln(); /// Logarithmic crossfade. /// @@ -316,9 +311,7 @@ const CROSS_LOG_MAX : f32 = 0.0; // (1.0_f32).ln(); /// * `mix` - mix position, range 0.0 to 1.0, mid is at 0.5 #[inline] pub fn crossfade_log(v1: f32, v2: f32, mix: f32) -> f32 { - let x = - (mix * (CROSS_LOG_MAX - CROSS_LOG_MIN) + CROSS_LOG_MIN) - .exp(); + let x = (mix * (CROSS_LOG_MAX - CROSS_LOG_MIN) + CROSS_LOG_MIN).exp(); crossfade(v1, v2, x) } @@ -334,20 +327,21 @@ pub fn crossfade_exp(v1: f32, v2: f32, mix: f32) -> f32 { #[inline] pub fn clamp(f: f32, min: f32, max: f32) -> f32 { - if f < min { min } - else if f > max { max } - else { f } + if f < min { + min + } else if f > max { + max + } else { + f + } } pub fn square_135(phase: f32) -> f32 { - fast_sin(phase) - + fast_sin(phase * 3.0) / 3.0 - + fast_sin(phase * 5.0) / 5.0 + fast_sin(phase) + fast_sin(phase * 3.0) / 3.0 + fast_sin(phase * 5.0) / 5.0 } pub fn square_35(phase: f32) -> f32 { - fast_sin(phase * 3.0) / 3.0 - + fast_sin(phase * 5.0) / 5.0 + fast_sin(phase * 3.0) / 3.0 + fast_sin(phase * 5.0) / 5.0 } // note: MIDI note value? @@ -379,9 +373,7 @@ pub fn note_to_freq(note: f32) -> f32 { /// ``` #[inline] pub fn f_distort(gain: f32, threshold: f32, i: f32) -> f32 { - gain * ( - i * ( i.abs() + threshold ) - / ( i * i + (threshold - 1.0) * i.abs() + 1.0 )) + gain * (i * (i.abs() + threshold) / (i * i + (threshold - 1.0) * i.abs() + 1.0)) } // Ported from LMMS under GPLv2 @@ -397,11 +389,7 @@ pub fn f_distort(gain: f32, threshold: f32, i: f32) -> f32 { #[inline] pub fn f_fold_distort(gain: f32, threshold: f32, i: f32) -> f32 { if i >= threshold || i < -threshold { - gain - * (( - ((i - threshold) % threshold * 4.0).abs() - - threshold * 2.0).abs() - - threshold) + gain * ((((i - threshold) % threshold * 4.0).abs() - threshold * 2.0).abs() - threshold) } else { gain * i } @@ -429,7 +417,6 @@ pub fn p2range_exp4(x: f32, a: f32, b: f32) -> f32 { (a * (1.0 - x)) + (b * x) } - pub fn range2p(v: f32, a: f32, b: f32) -> f32 { ((v - a) / (b - a)).abs() } @@ -475,15 +462,12 @@ pub fn quicker_tanh(v: f32) -> f32 { pub fn quick_tanh64(v: f64) -> f64 { let abs_v = v.abs(); let square = v * v; - let num = - v * (2.45550750702956 - + 2.45550750702956 * abs_v - + square * (0.893229853513558 - + 0.821226666969744 * abs_v)); + let num = v + * (2.45550750702956 + + 2.45550750702956 * abs_v + + square * (0.893229853513558 + 0.821226666969744 * abs_v)); let den = - 2.44506634652299 - + (2.44506634652299 + square) - * (v + 0.814642734961073 * v * abs_v).abs(); + 2.44506634652299 + (2.44506634652299 + square) * (v + 0.814642734961073 * v * abs_v).abs(); num / den } @@ -491,15 +475,12 @@ pub fn quick_tanh64(v: f64) -> f64 { pub fn quick_tanh(v: f32) -> f32 { let abs_v = v.abs(); let square = v * v; - let num = - v * (2.45550750702956 - + 2.45550750702956 * abs_v - + square * (0.893229853513558 - + 0.821226666969744 * abs_v)); + let num = v + * (2.45550750702956 + + 2.45550750702956 * abs_v + + square * (0.893229853513558 + 0.821226666969744 * abs_v)); let den = - 2.44506634652299 - + (2.44506634652299 + square) - * (v + 0.814642734961073 * v * abs_v).abs(); + 2.44506634652299 + (2.44506634652299 + square) * (v + 0.814642734961073 * v * abs_v).abs(); num / den } @@ -552,17 +533,14 @@ pub fn sqrt4_to_pow4(x: f32, v: f32) -> f32 { let xsq = xsq1.sqrt(); let v = (v - 0.75) * 4.0; xsq1 * (1.0 - v) + xsq * v - } else if v > 0.5 { let xsq = x.sqrt(); let v = (v - 0.5) * 4.0; x * (1.0 - v) + xsq * v - } else if v > 0.25 { let xx = x * x; let v = (v - 0.25) * 4.0; x * v + xx * (1.0 - v) - } else { let xx = x * x; let xxxx = xx * xx; @@ -572,27 +550,23 @@ pub fn sqrt4_to_pow4(x: f32, v: f32) -> f32 { } /// A-100 Eurorack states, that a trigger is usually 2-10 milliseconds. -pub const TRIG_SIGNAL_LENGTH_MS : f32 = 2.0; +pub const TRIG_SIGNAL_LENGTH_MS: f32 = 2.0; /// The lower threshold for the schmidt trigger to reset. -pub const TRIG_LOW_THRES : f32 = 0.25; +pub const TRIG_LOW_THRES: f32 = 0.25; /// The threshold, once reached, will cause a trigger event and signals /// a logical '1'. Anything below this is a logical '0'. -pub const TRIG_HIGH_THRES : f32 = 0.5; - +pub const TRIG_HIGH_THRES: f32 = 0.5; #[derive(Debug, Clone, Copy)] pub struct TrigSignal { - length: u32, - scount: u32, + length: u32, + scount: u32, } impl TrigSignal { pub fn new() -> Self { - Self { - length: ((44100.0 * TRIG_SIGNAL_LENGTH_MS) / 1000.0).ceil() as u32, - scount: 0, - } + Self { length: ((44100.0 * TRIG_SIGNAL_LENGTH_MS) / 1000.0).ceil() as u32, scount: 0 } } pub fn reset(&mut self) { @@ -605,7 +579,9 @@ impl TrigSignal { } #[inline] - pub fn trigger(&mut self) { self.scount = self.length; } + pub fn trigger(&mut self) { + self.scount = self.length; + } #[inline] pub fn next(&mut self) -> f32 { @@ -619,20 +595,22 @@ impl TrigSignal { } impl Default for TrigSignal { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[derive(Debug, Clone, Copy)] pub struct ChangeTrig { - ts: TrigSignal, - last: f32, + ts: TrigSignal, + last: f32, } impl ChangeTrig { pub fn new() -> Self { Self { - ts: TrigSignal::new(), - last: -100.0, // some random value :-) + ts: TrigSignal::new(), + last: -100.0, // some random value :-) } } @@ -657,19 +635,19 @@ impl ChangeTrig { } impl Default for ChangeTrig { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[derive(Debug, Clone, Copy)] pub struct Trigger { - triggered: bool, + triggered: bool, } impl Trigger { pub fn new() -> Self { - Self { - triggered: false, - } + Self { triggered: false } } #[inline] @@ -685,11 +663,9 @@ impl Trigger { } false - } else if input > TRIG_HIGH_THRES { self.triggered = true; true - } else { false } @@ -698,27 +674,22 @@ impl Trigger { #[derive(Debug, Clone, Copy)] pub struct TriggerPhaseClock { - clock_phase: f64, - clock_inc: f64, - prev_trigger: bool, - clock_samples: u32, + clock_phase: f64, + clock_inc: f64, + prev_trigger: bool, + clock_samples: u32, } impl TriggerPhaseClock { pub fn new() -> Self { - Self { - clock_phase: 0.0, - clock_inc: 0.0, - prev_trigger: true, - clock_samples: 0, - } + Self { clock_phase: 0.0, clock_inc: 0.0, prev_trigger: true, clock_samples: 0 } } #[inline] pub fn reset(&mut self) { self.clock_samples = 0; - self.clock_inc = 0.0; - self.prev_trigger = true; + self.clock_inc = 0.0; + self.prev_trigger = true; self.clock_samples = 0; } @@ -733,13 +704,11 @@ impl TriggerPhaseClock { if trigger_in <= TRIG_LOW_THRES { self.prev_trigger = false; } - } else if trigger_in > TRIG_HIGH_THRES { self.prev_trigger = true; if self.clock_samples > 0 { - self.clock_inc = - 1.0 / (self.clock_samples as f64); + self.clock_inc = 1.0 / (self.clock_samples as f64); } self.clock_samples = 0; @@ -756,24 +725,20 @@ impl TriggerPhaseClock { #[derive(Debug, Clone, Copy)] pub struct TriggerSampleClock { - prev_trigger: bool, - clock_samples: u32, - counter: u32, + prev_trigger: bool, + clock_samples: u32, + counter: u32, } impl TriggerSampleClock { pub fn new() -> Self { - Self { - prev_trigger: true, - clock_samples: 0, - counter: 0, - } + Self { prev_trigger: true, clock_samples: 0, counter: 0 } } #[inline] pub fn reset(&mut self) { self.clock_samples = 0; - self.counter = 0; + self.counter = 0; } #[inline] @@ -782,11 +747,10 @@ impl TriggerSampleClock { if trigger_in <= TRIG_LOW_THRES { self.prev_trigger = false; } - } else if trigger_in > TRIG_HIGH_THRES { - self.prev_trigger = true; + self.prev_trigger = true; self.clock_samples = self.counter; - self.counter = 0; + self.counter = 0; } self.counter += 1; @@ -798,20 +762,17 @@ impl TriggerSampleClock { /// A slew rate limiter, with a configurable time per 1.0 increase. #[derive(Debug, Clone, Copy)] pub struct SlewValue { - current: F, - slew_per_ms: F, + current: F, + slew_per_ms: F, } impl SlewValue { pub fn new() -> Self { - Self { - current: f(0.0), - slew_per_ms: f(1000.0 / 44100.0), - } + Self { current: f(0.0), slew_per_ms: f(1000.0 / 44100.0) } } pub fn reset(&mut self) { - self.current = f(0.0); + self.current = f(0.0); } pub fn set_sample_rate(&mut self, srate: F) { @@ -819,7 +780,9 @@ impl SlewValue { } #[inline] - pub fn value(&self) -> F { self.current } + pub fn value(&self) -> F { + self.current + } /// * `slew_ms_per_1` - The time (in milliseconds) it should take /// to get to 1.0 from 0.0. @@ -828,13 +791,9 @@ impl SlewValue { // at 0.11ms, there are barely enough samples for proper slew. if slew_ms_per_1 < f(0.11) { self.current = target; - } else { let max_delta = self.slew_per_ms / slew_ms_per_1; - self.current = - target - .min(self.current + max_delta) - .max(self.current - max_delta); + self.current = target.min(self.current + max_delta).max(self.current - max_delta); } self.current @@ -845,28 +804,28 @@ impl SlewValue { #[derive(Debug, Clone, Copy)] pub struct RampValue { slew_count: u64, - current: F, - target: F, - inc: F, - sr_ms: F, + current: F, + target: F, + inc: F, + sr_ms: F, } impl RampValue { pub fn new() -> Self { Self { slew_count: 0, - current: f(0.0), - target: f(0.0), - inc: f(0.0), - sr_ms: f(44100.0 / 1000.0), + current: f(0.0), + target: f(0.0), + inc: f(0.0), + sr_ms: f(44100.0 / 1000.0), } } pub fn reset(&mut self) { self.slew_count = 0; - self.current = f(0.0); - self.target = f(0.0); - self.inc = f(0.0); + self.current = f(0.0); + self.target = f(0.0); + self.inc = f(0.0); } pub fn set_sample_rate(&mut self, srate: F) { @@ -879,9 +838,8 @@ impl RampValue { // 0.02ms, thats a fraction of a sample at 44.1kHz if slew_time_ms < f(0.02) { - self.current = self.target; + self.current = self.target; self.slew_count = 0; - } else { let slew_samples = slew_time_ms * self.sr_ms; self.slew_count = slew_samples.to_u64().unwrap_or(0); @@ -890,7 +848,9 @@ impl RampValue { } #[inline] - pub fn value(&self) -> F { self.current } + pub fn value(&self) -> F { + self.current + } #[inline] pub fn next(&mut self) -> F { @@ -906,46 +866,46 @@ impl RampValue { } /// Default size of the delay buffer: 5 seconds at 8 times 48kHz -const DEFAULT_DELAY_BUFFER_SAMPLES : usize = 8 * 48000 * 5; +const DEFAULT_DELAY_BUFFER_SAMPLES: usize = 8 * 48000 * 5; macro_rules! fc { - ($F: ident, $e: expr) => { F::from_f64($e).unwrap() } + ($F: ident, $e: expr) => { + F::from_f64($e).unwrap() + }; } #[allow(dead_code)] #[inline] -fn f(x: f64) -> F { F::from_f64(x).unwrap() } +fn f(x: f64) -> F { + F::from_f64(x).unwrap() +} #[allow(dead_code)] #[inline] -fn fclamp(x: F, mi: F, mx: F) -> F { x.max(mi).min(mx) } +fn fclamp(x: F, mi: F, mx: F) -> F { + x.max(mi).min(mx) +} #[allow(dead_code)] #[inline] -fn fclampc(x: F, mi: f64, mx: f64) -> F { x.max(f(mi)).min(f(mx)) } +fn fclampc(x: F, mi: f64, mx: f64) -> F { + x.max(f(mi)).min(f(mx)) +} #[derive(Debug, Clone, Default)] pub struct DelayBuffer { - data: Vec, - wr: usize, - srate: F, + data: Vec, + wr: usize, + srate: F, } impl DelayBuffer { pub fn new() -> Self { - Self { - data: vec![f(0.0); DEFAULT_DELAY_BUFFER_SAMPLES], - wr: 0, - srate: f(44100.0), - } + Self { data: vec![f(0.0); DEFAULT_DELAY_BUFFER_SAMPLES], wr: 0, srate: f(44100.0) } } pub fn new_with_size(size: usize) -> Self { - Self { - data: vec![f(0.0); size], - wr: 0, - srate: f(44100.0), - } + Self { data: vec![f(0.0); size], wr: 0, srate: f(44100.0) } } pub fn set_sample_rate(&mut self, srate: F) { @@ -1024,13 +984,13 @@ impl DelayBuffer { /// * `s_offs` - Sample offset in samples. #[inline] pub fn linear_interpolate_at_s(&self, s_offs: F) -> F { - let data = &self.data[..]; - let len = data.len(); - let offs = s_offs.floor().to_usize().unwrap_or(0) % len; - let fract = s_offs.fract(); + let data = &self.data[..]; + let len = data.len(); + let offs = s_offs.floor().to_usize().unwrap_or(0) % len; + let fract = s_offs.fract(); let i = (self.wr + len) - offs; - let x0 = data[i % len]; + let x0 = data[i % len]; let x1 = data[(i - 1) % len]; x0 + fract * (x1 - x0) @@ -1049,14 +1009,14 @@ impl DelayBuffer { /// * `s_offs` - Sample offset in samples. #[inline] pub fn cubic_interpolate_at_s(&self, s_offs: F) -> F { - let data = &self.data[..]; - let len = data.len(); - let offs = s_offs.floor().to_usize().unwrap_or(0) % len; - let fract = s_offs.fract(); + let data = &self.data[..]; + let len = data.len(); + let offs = s_offs.floor().to_usize().unwrap_or(0) % len; + let fract = s_offs.fract(); let i = (self.wr + len) - offs; - // Hermite interpolation, take from + // Hermite interpolation, take from // https://github.com/eric-wood/delay/blob/main/src/delay.rs#L52 // // Thanks go to Eric Wood! @@ -1064,14 +1024,14 @@ impl DelayBuffer { // For the interpolation code: // MIT License, Copyright (c) 2021 Eric Wood let xm1 = data[(i + 1) % len]; - let x0 = data[i % len]; - let x1 = data[(i - 1) % len]; - let x2 = data[(i - 2) % len]; + let x0 = data[i % len]; + let x1 = data[(i - 1) % len]; + let x2 = data[(i - 2) % len]; - let c = (x1 - xm1) * f(0.5); - let v = x0 - x1; - let w = c + v; - let a = w + v + (x2 - x0) * f(0.5); + let c = (x1 - xm1) * f(0.5); + let v = x0 - x1; + let w = c + v; + let a = w + v + (x2 - x0) * f(0.5); let b_neg = w + a; let fract = fract as F; @@ -1080,25 +1040,22 @@ impl DelayBuffer { #[inline] pub fn nearest_at(&self, delay_time_ms: F) -> F { - let len = self.data.len(); - let offs = - ((delay_time_ms * self.srate) - / f(1000.0)) - .floor().to_usize().unwrap_or(0) % len; - let idx = ((self.wr + len) - offs) % len; + let len = self.data.len(); + let offs = ((delay_time_ms * self.srate) / f(1000.0)).floor().to_usize().unwrap_or(0) % len; + let idx = ((self.wr + len) - offs) % len; self.data[idx] } #[inline] pub fn at(&self, delay_sample_count: usize) -> F { - let len = self.data.len(); - let idx = ((self.wr + len) - delay_sample_count) % len; + let len = self.data.len(); + let idx = ((self.wr + len) - delay_sample_count) % len; self.data[idx] } } /// Default size of the delay buffer: 1 seconds at 8 times 48kHz -const DEFAULT_ALLPASS_COMB_SAMPLES : usize = 8 * 48000; +const DEFAULT_ALLPASS_COMB_SAMPLES: usize = 8 * 48000; #[derive(Debug, Clone, Default)] pub struct AllPass { @@ -1107,9 +1064,7 @@ pub struct AllPass { impl AllPass { pub fn new() -> Self { - Self { - delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES), - } + Self { delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES) } } pub fn set_sample_rate(&mut self, srate: F) { @@ -1141,9 +1096,7 @@ pub struct Comb { impl Comb { pub fn new() -> Self { - Self { - delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES), - } + Self { delay: DelayBuffer::new_with_size(DEFAULT_ALLPASS_COMB_SAMPLES) } } pub fn set_sample_rate(&mut self, srate: f32) { @@ -1213,21 +1166,21 @@ pub fn process_1pole_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> #[derive(Debug, Clone, Copy, Default)] pub struct OnePoleLPF { - israte: F, - a: F, - b: F, - freq: F, - z: F, + israte: F, + a: F, + b: F, + freq: F, + z: F, } impl OnePoleLPF { pub fn new() -> Self { Self { israte: f::(1.0) / f(44100.0), - a: f::(0.0), - b: f::(0.0), - freq: f::(1000.0), - z: f::(0.0), + a: f::(0.0), + b: f::(0.0), + freq: f::(1000.0), + z: f::(0.0), } } @@ -1267,36 +1220,29 @@ impl OnePoleLPF { // under MIT License #[derive(Debug, Copy, Clone, Default)] pub struct FixedOnePole { - b0: f32, - a1: f32, - y1: f32, + b0: f32, + a1: f32, + y1: f32, gain: f32, } impl FixedOnePole { pub fn new(pole: f32, gain: f32) -> Self { - let b0 = - if pole > 0.0 { 1.0 - pole } - else { 1.0 + pole }; + let b0 = if pole > 0.0 { 1.0 - pole } else { 1.0 + pole }; - Self { - b0, - a1: -pole, - y1: 0.0, - gain - } + Self { b0, a1: -pole, y1: 0.0, gain } } pub fn reset(&mut self) { self.y1 = 0.0; } - pub fn set_gain(&mut self, gain: f32) { self.gain = gain; } + pub fn set_gain(&mut self, gain: f32) { + self.gain = gain; + } pub fn process(&mut self, input: f32) -> f32 { - let output = - self.b0 * self.gain * input - - self.a1 * self.y1; + let output = self.b0 * self.gain * input - self.a1 * self.y1; self.y1 = output; output } @@ -1329,13 +1275,10 @@ impl FixedOnePole { /// } ///``` pub fn process_1pole_highpass(input: f32, freq: f32, israte: f32, z: &mut f32, y: &mut f32) -> f32 { - let b = (-std::f32::consts::TAU * freq * israte).exp(); - let a = (1.0 + b) / 2.0; + let b = (-std::f32::consts::TAU * freq * israte).exp(); + let a = (1.0 + b) / 2.0; - let v = - a * input - - a * *z - + b * *y; + let v = a * input - a * *z + b * *y; *y = v; *z = input; v @@ -1343,23 +1286,23 @@ pub fn process_1pole_highpass(input: f32, freq: f32, israte: f32, z: &mut f32, y #[derive(Debug, Clone, Copy, Default)] pub struct OnePoleHPF { - israte: F, - a: F, - b: F, - freq: F, - z: F, - y: F, + israte: F, + a: F, + b: F, + freq: F, + z: F, + y: F, } impl OnePoleHPF { pub fn new() -> Self { Self { israte: f(1.0 / 44100.0), - a: f(0.0), - b: f(0.0), - freq: f(1000.0), - z: f(0.0), - y: f(0.0), + a: f(0.0), + b: f(0.0), + freq: f(1000.0), + z: f(0.0), + y: f(0.0), } } @@ -1374,7 +1317,6 @@ impl OnePoleHPF { self.a = (f::(1.0) + self.b) / f(2.0); } - pub fn set_sample_rate(&mut self, srate: F) { self.israte = f::(1.0) / srate; self.recalc(); @@ -1390,10 +1332,7 @@ impl OnePoleHPF { #[inline] pub fn process(&mut self, input: F) -> F { - let v = - self.a * input - - self.a * self.z - + self.b * self.y; + let v = self.a * input - self.a * self.z + self.b * self.y; self.y = v; self.z = input; @@ -1402,7 +1341,6 @@ impl OnePoleHPF { } } - // one pole from: // http://www.willpirkle.com/Downloads/AN-4VirtualAnalogFilters.pdf // (page 5) @@ -1468,7 +1406,7 @@ pub fn process_1pole_tpt_lowpass(input: f32, freq: f32, israte: f32, z: &mut f32 /// } ///``` pub fn process_1pole_tpt_highpass(input: f32, freq: f32, israte: f32, z: &mut f32) -> f32 { - let g = (std::f32::consts::PI * freq * israte).tan(); + let g = (std::f32::consts::PI * freq * israte).tan(); let a1 = g / (1.0 + g); let v1 = a1 * (input - *z); @@ -1479,7 +1417,7 @@ pub fn process_1pole_tpt_highpass(input: f32, freq: f32, israte: f32, z: &mut f3 } /// The internal oversampling factor of [process_hal_chamberlin_svf]. -const FILTER_OVERSAMPLE_HAL_CHAMBERLIN : usize = 2; +const FILTER_OVERSAMPLE_HAL_CHAMBERLIN: usize = 2; // Hal Chamberlin's State Variable (12dB/oct) filter // https://www.earlevel.com/main/2003/03/02/the-digital-state-variable-filter/ // Inspired by SynthV1 by Rui Nuno Capela, under the terms of @@ -1518,17 +1456,21 @@ const FILTER_OVERSAMPLE_HAL_CHAMBERLIN : usize = 2; ///``` #[inline] pub fn process_hal_chamberlin_svf( - input: f32, freq: f32, res: f32, israte: f32, band: &mut f32, low: &mut f32) - -> (f32, f32) -{ - let q = 1.0 - res; + input: f32, + freq: f32, + res: f32, + israte: f32, + band: &mut f32, + low: &mut f32, +) -> (f32, f32) { + let q = 1.0 - res; let cutoff = 2.0 * (std::f32::consts::PI * freq * 0.5 * israte).sin(); - let mut high = 0.0; + let mut high = 0.0; let mut notch = 0.0; for _ in 0..FILTER_OVERSAMPLE_HAL_CHAMBERLIN { - *low += cutoff * *band; + *low += cutoff * *band; high = input - *low - q * *band; *band += cutoff * high; notch = high + *low; @@ -1582,14 +1524,19 @@ pub fn process_hal_chamberlin_svf( // the paper. #[inline] pub fn process_simper_svf( - input: f32, freq: f32, res: f32, israte: f32, ic1eq: &mut f32, ic2eq: &mut f32 + input: f32, + freq: f32, + res: f32, + israte: f32, + ic1eq: &mut f32, + ic2eq: &mut f32, ) -> (f32, f32, f32) { // XXX: the 1.989 were tuned by hand, so the resonance is more audible. let k = 2f32 - (1.989f32 * res); let w = std::f32::consts::PI * freq * israte; - let s1 = w.sin(); - let s2 = (2.0 * w).sin(); + let s1 = w.sin(); + let s2 = (2.0 * w).sin(); let nrm = 1.0 / (2.0 + k * s2); let g0 = s2 * nrm; @@ -1660,11 +1607,16 @@ pub fn process_simper_svf( // and https://github.com/ddiakopoulos/MoogLadders/blob/master/src/MusicDSPModel.h #[inline] pub fn process_stilson_moog( - input: f32, freq: f32, res: f32, israte: f32, - b0: &mut f32, b1: &mut f32, b2: &mut f32, b3: &mut f32, + input: f32, + freq: f32, + res: f32, + israte: f32, + b0: &mut f32, + b1: &mut f32, + b2: &mut f32, + b3: &mut f32, delay: &mut [f32; 4], ) -> f32 { - let cutoff = 2.0 * freq * israte; let p = cutoff * (1.8 - 0.8 * cutoff); @@ -1675,10 +1627,10 @@ pub fn process_stilson_moog( let res = res * (t2 + 6.0 * t1) / (t2 - 6.0 * t1); - let x = input - res * *b3; + let x = input - res * *b3; // Four cascaded one-pole filters (bilinear transform) - *b0 = x * p + delay[0] * p - k * *b0; + *b0 = x * p + delay[0] * p - k * *b0; *b1 = *b0 * p + delay[1] * p - k * *b1; *b2 = *b1 * p + delay[2] * p - k * *b2; *b3 = *b2 * p + delay[3] * p - k * *b3; @@ -1699,18 +1651,14 @@ pub fn process_stilson_moog( // under GPLv3 or any later #[derive(Debug, Clone, Copy)] pub struct DCBlockFilter { - xm1: F, - ym1: F, - r: F, + xm1: F, + ym1: F, + r: F, } impl DCBlockFilter { pub fn new() -> Self { - Self { - xm1: f(0.0), - ym1: f(0.0), - r: f(0.995), - } + Self { xm1: f(0.0), ym1: f(0.0), r: f(0.995) } } pub fn reset(&mut self) { @@ -1747,11 +1695,9 @@ fn poly_blep_64(t: f64, dt: f64) -> f64 { if t < dt { let t = t / dt; 2. * t - (t * t) - 1. - } else if t > (1.0 - dt) { let t = (t - 1.0) / dt; (t * t) + 2. * t + 1. - } else { 0. } @@ -1761,11 +1707,9 @@ fn poly_blep(t: f32, dt: f32) -> f32 { if t < dt { let t = t / dt; 2. * t - (t * t) - 1. - } else if t > (1.0 - dt) { let t = (t - 1.0) / dt; (t * t) + 2. * t + 1. - } else { 0. } @@ -1801,8 +1745,8 @@ fn poly_blep(t: f32, dt: f32) -> f32 { ///``` #[derive(Debug, Clone)] pub struct PolyBlepOscillator { - phase: f32, - init_phase: f32, + phase: f32, + init_phase: f32, last_output: f32, } @@ -1820,18 +1764,14 @@ impl PolyBlepOscillator { /// let mut osc = PolyBlepOscillator::new(rand_01() * 0.25); ///``` pub fn new(init_phase: f32) -> Self { - Self { - phase: 0.0, - last_output: 0.0, - init_phase, - } + Self { phase: 0.0, last_output: 0.0, init_phase } } /// Reset the internal state of the oscillator as if you just called /// [PolyBlepOscillator::new]. #[inline] pub fn reset(&mut self) { - self.phase = self.init_phase; + self.phase = self.init_phase; self.last_output = 0.0; } @@ -1884,9 +1824,7 @@ impl PolyBlepOscillator { pub fn next_tri(&mut self, freq: f32, israte: f32) -> f32 { let phase_inc = freq * israte; - let mut s = - if self.phase < 0.5 { 1.0 } - else { -1.0 }; + let mut s = if self.phase < 0.5 { 1.0 } else { -1.0 }; s += poly_blep(self.phase, phase_inc); s -= poly_blep((self.phase + 0.5).fract(), phase_inc); @@ -1961,13 +1899,10 @@ impl PolyBlepOscillator { let pw = (0.1 * pw) + ((1.0 - pw) * 0.5); // some scaling let dc_compensation = (0.5 - pw) * 2.0; - let mut s = - if self.phase < pw { 1.0 } - else { -1.0 }; + let mut s = if self.phase < pw { 1.0 } else { -1.0 }; s += poly_blep(self.phase, phase_inc); - s -= poly_blep((self.phase + (1.0 - pw)).fract(), - phase_inc); + s -= poly_blep((self.phase + (1.0 - pw)).fract(), phase_inc); s += dc_compensation; @@ -2004,13 +1939,10 @@ impl PolyBlepOscillator { let pw = (0.1 * pw) + ((1.0 - pw) * 0.5); // some scaling - let mut s = - if self.phase < pw { 1.0 } - else { -1.0 }; + let mut s = if self.phase < pw { 1.0 } else { -1.0 }; s += poly_blep(self.phase, phase_inc); - s -= poly_blep((self.phase + (1.0 - pw)).fract(), - phase_inc); + s -= poly_blep((self.phase + (1.0 - pw)).fract(), phase_inc); self.phase += phase_inc; self.phase = self.phase.fract(); @@ -2086,8 +2018,8 @@ impl PolyBlepOscillator { ///``` #[derive(Debug, Clone)] pub struct VPSOscillator { - phase: f32, - init_phase: f32, + phase: f32, + init_phase: f32, } impl VPSOscillator { @@ -2095,10 +2027,7 @@ impl VPSOscillator { /// /// * `init_phase` - The initial phase of the oscillator. pub fn new(init_phase: f32) -> Self { - Self { - phase: 0.0, - init_phase, - } + Self { phase: 0.0, init_phase } } /// Reset the phase of the oscillator to the initial phase. @@ -2117,7 +2046,7 @@ impl VPSOscillator { if x < d { (v * x) / d } else { - v + ((1.0 - v) * (x - d))/(1.0 - d) + v + ((1.0 - v) * (x - d)) / (1.0 - d) } } @@ -2184,13 +2113,13 @@ pub struct TriSawLFO { /// The (inverse) sample rate. Eg. 1.0 / 44100.0. israte: F, /// The current oscillator phase. - phase: F, + phase: F, /// The point from where the falling edge will be used. - rev: F, + rev: F, /// Whether the LFO is currently rising rising: bool, /// The frequency. - freq: F, + freq: F, /// Precomputed rise/fall rate of the LFO. rise_r: F, fall_r: F, @@ -2202,10 +2131,10 @@ impl TriSawLFO { pub fn new() -> Self { let mut this = Self { israte: f(1.0 / 44100.0), - phase: f(0.0), - rev: f(0.5), + phase: f(0.0), + rev: f(0.5), rising: true, - freq: f(1.0), + freq: f(1.0), fall_r: f(0.0), rise_r: f(0.0), init_phase: f(0.0), @@ -2216,13 +2145,13 @@ impl TriSawLFO { pub fn set_phase_offs(&mut self, phase: F) { self.init_phase = phase; - self.phase = phase; + self.phase = phase; } #[inline] fn recalc(&mut self) { - self.rev = fclampc(self.rev, 0.0001, 0.999); - self.rise_r = f::( 1.0) / self.rev; + self.rev = fclampc(self.rev, 0.0001, 0.999); + self.rise_r = f::(1.0) / self.rev; self.fall_r = f::(-1.0) / (f::(1.0) - self.rev); } @@ -2232,15 +2161,15 @@ impl TriSawLFO { } pub fn reset(&mut self) { - self.phase = self.init_phase; - self.rev = f(0.5); + self.phase = self.init_phase; + self.rev = f(0.5); self.rising = true; } #[inline] pub fn set(&mut self, freq: F, rev: F) { self.freq = freq as F; - self.rev = rev as F; + self.rev = rev as F; self.recalc(); } @@ -2255,12 +2184,11 @@ impl TriSawLFO { self.rising = false; } - let s = - if self.rising { - self.phase * self.rise_r - } else { - self.phase * self.fall_r - self.fall_r - }; + let s = if self.rising { + self.phase * self.rise_r + } else { + self.phase * self.fall_r - self.fall_r + }; self.phase = self.phase + self.freq * self.israte; @@ -2275,18 +2203,14 @@ impl TriSawLFO { #[derive(Debug, Clone)] pub struct Quantizer { - old_mask: i64, - lkup_tbl: [(f32, f32); 24], - last_key: f32, + old_mask: i64, + lkup_tbl: [(f32, f32); 24], + last_key: f32, } impl Quantizer { pub fn new() -> Self { - Self { - old_mask: 0xFFFF_FFFF, - lkup_tbl: [(0.0, 0.0); 24], - last_key: 0.0, - } + Self { old_mask: 0xFFFF_FFFF, lkup_tbl: [(0.0, 0.0); 24], last_key: 0.0 } } #[inline] @@ -2301,23 +2225,21 @@ impl Quantizer { #[inline] fn setup_lookup_table(&mut self) { - let mask = self.old_mask; + let mask = self.old_mask; let any_enabled = mask > 0x0; for i in 0..24 { let mut min_d_note_idx = 0; - let mut min_dist = 1000000000; + let mut min_dist = 1000000000; for note in -12..=24 { - let dist = ((i + 1_i64) / 2 - note).abs(); + let dist = ((i + 1_i64) / 2 - note).abs(); let note_idx = note.rem_euclid(12); // XXX: We add 9 here for the mask lookup, // to shift the keyboard, which starts at C! // And first bit in the mask is the C note. 10th is the A note. - if any_enabled - && (mask & (0x1 << ((note_idx + 9) % 12))) == 0x0 - { + if any_enabled && (mask & (0x1 << ((note_idx + 9) % 12))) == 0x0 { continue; } @@ -2328,7 +2250,7 @@ impl Quantizer { if dist < min_dist { min_d_note_idx = note; - min_dist = dist; + min_dist = dist; } else { break; } @@ -2337,9 +2259,13 @@ impl Quantizer { self.lkup_tbl[i as usize] = ( (min_d_note_idx + 9).rem_euclid(12) as f32 * (0.1 / 12.0), min_d_note_idx.rem_euclid(12) as f32 * (0.1 / 12.0) - + ( if min_d_note_idx < 0 { -0.1 } - else if min_d_note_idx > 11 { 0.1 } - else { 0.0 }) + + (if min_d_note_idx < 0 { + -0.1 + } else if min_d_note_idx > 11 { + 0.1 + } else { + 0.0 + }), ); } //d// println!("TBL: {:?}", self.lkup_tbl); @@ -2353,16 +2279,15 @@ impl Quantizer { #[inline] pub fn process(&mut self, inp: f32) -> f32 { let note_num = (inp * 240.0).round() as i64; - let octave = note_num.div_euclid(24); + let octave = note_num.div_euclid(24); let note_idx = note_num - octave * 24; -// println!( -// "INP {:7.4} => octave={:3}, note_idx={:3} note_num={:3} inp={:9.6}", -// inp, octave, note_idx, note_num, inp * 240.0); + // println!( + // "INP {:7.4} => octave={:3}, note_idx={:3} note_num={:3} inp={:9.6}", + // inp, octave, note_idx, note_num, inp * 240.0); //d// println!("TBL: {:?}", self.lkup_tbl); - let (ui_key_pitch, note_pitch) = - self.lkup_tbl[note_idx as usize % 24]; + let (ui_key_pitch, note_pitch) = self.lkup_tbl[note_idx as usize % 24]; self.last_key = ui_key_pitch; note_pitch + octave as f32 * 0.1 } @@ -2382,33 +2307,27 @@ pub struct CtrlPitchQuantizer { last_key: u8, } -const QUANT_TUNE_TO_A4 : f32 = (9.0 / 12.0) * 0.1; +const QUANT_TUNE_TO_A4: f32 = (9.0 / 12.0) * 0.1; impl CtrlPitchQuantizer { pub fn new() -> Self { Self { - keys: vec![0.0; 12 * 10], - used_keys: [0.0; 12], + keys: vec![0.0; 12 * 10], + used_keys: [0.0; 12], mask_key_count: 0, - input_params: 0xFFFFFFFFFF, - last_key: 0, + input_params: 0xFFFFFFFFFF, + last_key: 0, } } #[inline] pub fn last_key_pitch(&self) -> f32 { - self.used_keys[ - self.last_key as usize - % (self.mask_key_count as usize)] - + QUANT_TUNE_TO_A4 + self.used_keys[self.last_key as usize % (self.mask_key_count as usize)] + QUANT_TUNE_TO_A4 } #[inline] pub fn update_keys(&mut self, mut mask: i64, min_oct: i64, max_oct: i64) { - let inp_params = - (mask as u64) - | ((min_oct as u64) << 12) - | ((max_oct as u64) << 20); + let inp_params = (mask as u64) | ((min_oct as u64) << 12) | ((max_oct as u64) << 20); if self.input_params == inp_params { return; @@ -2419,12 +2338,13 @@ impl CtrlPitchQuantizer { let mut mask_count = 0; // set all keys, if none are set! - if mask == 0x0 { mask = 0xFFFF; } + if mask == 0x0 { + mask = 0xFFFF; + } for i in 0..12 { if mask & (0x1 << i) > 0 { - self.used_keys[mask_count] = - (i as f32 / 12.0) * 0.1 - QUANT_TUNE_TO_A4; + self.used_keys[mask_count] = (i as f32 / 12.0) * 0.1 - QUANT_TUNE_TO_A4; mask_count += 1; } } @@ -2465,17 +2385,18 @@ impl CtrlPitchQuantizer { } #[macro_export] -macro_rules! fa_distort { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Off", - 1 => "TanH", - 2 => "B.D.Jong", - 3 => "Fold", - _ => "?", +macro_rules! fa_distort { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Off", + 1 => "TanH", + 2 => "B.D.Jong", + 3 => "Fold", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[inline] pub fn apply_distortion(s: f32, damt: f32, dist_type: u8) -> f32 { @@ -2486,7 +2407,7 @@ pub fn apply_distortion(s: f32, damt: f32, dist_type: u8) -> f32 { let damt = damt.clamp(0.0, 0.99); let damt = 1.0 - damt * damt; f_fold_distort(1.0, damt, s) * (1.0 / damt) - }, + } _ => s, } } diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index ec705dd..e726073 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -2,64 +2,64 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +#[allow(non_upper_case_globals)] +mod node_ad; +#[allow(non_upper_case_globals)] +mod node_allp; #[allow(non_upper_case_globals)] mod node_amp; #[allow(non_upper_case_globals)] +mod node_biqfilt; +#[allow(non_upper_case_globals)] +mod node_bosc; +#[allow(non_upper_case_globals)] +mod node_bowstri; +#[allow(non_upper_case_globals)] +mod node_comb; +#[allow(non_upper_case_globals)] +mod node_cqnt; +#[allow(non_upper_case_globals)] +mod node_delay; +#[allow(non_upper_case_globals)] +mod node_fbwr_fbrd; +#[allow(non_upper_case_globals)] +mod node_map; +#[allow(non_upper_case_globals)] +mod node_mix3; +#[allow(non_upper_case_globals)] +mod node_mux9; +#[allow(non_upper_case_globals)] +mod node_noise; +#[allow(non_upper_case_globals)] +mod node_out; +#[allow(non_upper_case_globals)] +mod node_pverb; +#[allow(non_upper_case_globals)] +mod node_quant; +#[allow(non_upper_case_globals)] +mod node_rndwk; +#[allow(non_upper_case_globals)] +mod node_sampl; +#[allow(non_upper_case_globals)] +mod node_sfilter; +#[allow(non_upper_case_globals)] mod node_sin; #[allow(non_upper_case_globals)] -mod node_out; +mod node_smap; #[allow(non_upper_case_globals)] mod node_test; #[allow(non_upper_case_globals)] mod node_tseq; #[allow(non_upper_case_globals)] -mod node_sampl; -#[allow(non_upper_case_globals)] -mod node_fbwr_fbrd; -#[allow(non_upper_case_globals)] -mod node_ad; -#[allow(non_upper_case_globals)] -mod node_delay; -#[allow(non_upper_case_globals)] -mod node_allp; -#[allow(non_upper_case_globals)] -mod node_noise; -#[allow(non_upper_case_globals)] -mod node_map; -#[allow(non_upper_case_globals)] -mod node_smap; -#[allow(non_upper_case_globals)] -mod node_sfilter; -#[allow(non_upper_case_globals)] -mod node_mix3; -#[allow(non_upper_case_globals)] -mod node_bosc; -#[allow(non_upper_case_globals)] -mod node_vosc; -#[allow(non_upper_case_globals)] -mod node_biqfilt; -#[allow(non_upper_case_globals)] -mod node_comb; -#[allow(non_upper_case_globals)] mod node_tslfo; #[allow(non_upper_case_globals)] -mod node_pverb; -#[allow(non_upper_case_globals)] -mod node_rndwk; -#[allow(non_upper_case_globals)] -mod node_mux9; -#[allow(non_upper_case_globals)] -mod node_cqnt; -#[allow(non_upper_case_globals)] -mod node_quant; -#[allow(non_upper_case_globals)] -mod node_bowstri; +mod node_vosc; pub mod biquad; -pub mod tracker; pub mod dattorro; -mod satom; pub mod helpers; +mod satom; +pub mod tracker; use crate::nodes::NodeAudioContext; use crate::nodes::NodeExecContext; @@ -71,64 +71,63 @@ pub type LedPhaseVals<'a> = &'a [Arc]; pub use satom::*; -use crate::fa_out_mono; -use crate::fa_test_s; -use crate::fa_amp_neg_att; -use crate::fa_tseq_cmode; -use crate::fa_sampl_dclick; -use crate::fa_sampl_pmode; -use crate::fa_sampl_dir; use crate::fa_ad_mult; +use crate::fa_amp_neg_att; +use crate::fa_biqfilt_ord; +use crate::fa_biqfilt_type; +use crate::fa_bosc_wtype; +use crate::fa_comb_mode; +use crate::fa_cqnt; +use crate::fa_cqnt_omax; +use crate::fa_cqnt_omin; use crate::fa_delay_mode; -use crate::fa_noise_mode; +use crate::fa_distort; use crate::fa_map_clip; +use crate::fa_mux9_in_cnt; +use crate::fa_noise_mode; +use crate::fa_out_mono; +use crate::fa_quant; +use crate::fa_sampl_dclick; +use crate::fa_sampl_dir; +use crate::fa_sampl_pmode; +use crate::fa_sfilter_type; use crate::fa_smap_clip; use crate::fa_smap_mode; -use crate::fa_sfilter_type; -use crate::fa_bosc_wtype; -use crate::fa_biqfilt_type; -use crate::fa_biqfilt_ord; +use crate::fa_test_s; +use crate::fa_tseq_cmode; use crate::fa_vosc_ovrsmpl; -use crate::fa_distort; -use crate::fa_comb_mode; -use crate::fa_mux9_in_cnt; -use crate::fa_cqnt; -use crate::fa_cqnt_omin; -use crate::fa_cqnt_omax; -use crate::fa_quant; +use node_ad::Ad; +use node_allp::AllP; use node_amp::Amp; -use node_sin::Sin; +use node_biqfilt::BiqFilt; +use node_bosc::BOsc; +use node_bowstri::BowStri; +use node_comb::Comb; +use node_cqnt::CQnt; +use node_delay::Delay; +use node_fbwr_fbrd::FbRd; +use node_fbwr_fbrd::FbWr; +use node_map::Map; +use node_mix3::Mix3; +use node_mux9::Mux9; +use node_noise::Noise; use node_out::Out; +use node_pverb::PVerb; +use node_quant::Quant; +use node_rndwk::RndWk; +use node_sampl::Sampl; +use node_sfilter::SFilter; +use node_sin::Sin; +use node_smap::SMap; use node_test::Test; use node_tseq::TSeq; -use node_sampl::Sampl; -use node_fbwr_fbrd::FbWr; -use node_fbwr_fbrd::FbRd; -use node_ad::Ad; -use node_delay::Delay; -use node_allp::AllP; -use node_noise::Noise; -use node_map::Map; -use node_smap::SMap; -use node_sfilter::SFilter; -use node_mix3::Mix3; -use node_bosc::BOsc; -use node_vosc::VOsc; -use node_biqfilt::BiqFilt; -use node_comb::Comb; use node_tslfo::TsLFO; -use node_pverb::PVerb; -use node_rndwk::RndWk; -use node_mux9::Mux9; -use node_cqnt::CQnt; -use node_quant::Quant; -use node_bowstri::BowStri; +use node_vosc::VOsc; -pub const MIDI_MAX_FREQ : f32 = 13289.75; - -pub const MAX_BLOCK_SIZE : usize = 128; +pub const MIDI_MAX_FREQ: f32 = 13289.75; +pub const MAX_BLOCK_SIZE: usize = 128; /// A context structure that holds temporary information about the /// currently executed node. @@ -136,12 +135,12 @@ pub const MAX_BLOCK_SIZE : usize = 128; pub struct NodeContext<'a> { /// The bitmask that indicates which input ports are used/connected /// to some output. - pub in_connected: u64, + pub in_connected: u64, /// The bitmask that indicates which output ports are used/connected /// to some input. - pub out_connected: u64, + pub out_connected: u64, /// The node parameters, which are usually not accessed directly. - pub params: &'a [ProcBuf], + pub params: &'a [ProcBuf], } /// This trait is an interface between the graph functions @@ -183,13 +182,20 @@ pub trait DspNode { /// these inputs might be overwritten by outputs of other nodes. /// * `outputs` are the output buffers of this node. fn process( - &mut self, ctx: &mut T, ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + ectx: &mut NodeExecContext, nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], outputs: &mut [ProcBuf], - led: LedPhaseVals); + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + led: LedPhaseVals, + ); /// A function factory for generating a graph for the generic node UI. - fn graph_fun() -> Option { None } + fn graph_fun() -> Option { + None + } } /// A processing buffer with the exact right maximum size. @@ -267,7 +273,9 @@ impl ProcBuf { /// Reads a sample at `idx`. Be careful to not let the `idx` /// land outside of [MAX_BLOCK_SIZE]. #[inline] - pub fn read(&self, idx: usize) -> f32 { unsafe { (*self.0)[idx] } } + pub fn read(&self, idx: usize) -> f32 { + unsafe { (*self.0)[idx] } + } /// Fills the [ProcBuf] with the sample `v`. #[inline] @@ -279,7 +287,9 @@ impl ProcBuf { /// Checks if this is a [ProcBuf::null]. #[inline] - pub fn is_null(&self) -> bool { self.0.is_null() } + pub fn is_null(&self) -> bool { + self.0.is_null() + } /// Deallocates the [ProcBuf]. If you still keep around /// other copies of this [ProcBuf], you will most likely land in @@ -309,9 +319,7 @@ impl std::fmt::Debug for ProcBuf { impl std::fmt::Display for ProcBuf { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - unsafe { - write!(f, "ProcBuf(0: {})", (*self.0)[0]) - } + unsafe { write!(f, "ProcBuf(0: {})", (*self.0)[0]) } } } @@ -343,354 +351,420 @@ pub enum UICategory { impl UICategory { pub fn default_color_idx(&self) -> u8 { match self { - UICategory::None => 17, - UICategory::Osc => 0, - UICategory::Mod => 7, - UICategory::NtoM => 4, + UICategory::None => 17, + UICategory::Osc => 0, + UICategory::Mod => 7, + UICategory::NtoM => 4, UICategory::Signal => 2, - UICategory::Ctrl => 12, + UICategory::Ctrl => 12, UICategory::IOUtil => 10, } } } // The following macros define normalize/denormalize functions: -macro_rules! n_id { ($x: expr) => { $x } } -macro_rules! d_id { ($x: expr) => { $x } } +macro_rules! n_id { + ($x: expr) => { + $x + }; +} +macro_rules! d_id { + ($x: expr) => { + $x + }; +} macro_rules! define_lin { ($n_id: ident $d_id: ident $min: expr, $max: expr) => { - macro_rules! $n_id { ($x: expr) => { - (($x - $min) / ($max - $min) as f32).abs() - } } + macro_rules! $n_id { + ($x: expr) => { + (($x - $min) / ($max - $min) as f32).abs() + }; + } - macro_rules! $d_id { ($x: expr) => { - $min * (1.0 - $x) + $max * $x - } } - } + macro_rules! $d_id { + ($x: expr) => { + $min * (1.0 - $x) + $max * $x + }; + } + }; } macro_rules! define_exp { ($n_id: ident $d_id: ident $min: expr, $max: expr) => { - macro_rules! $n_id { ($x: expr) => { - (($x - $min) / ($max - $min) as f32).abs().sqrt() - } } - macro_rules! $d_id { ($x: expr) => { - { let x : f32 = $x * $x; $min * (1.0 - x) + $max * x } - } } - } + macro_rules! $n_id { + ($x: expr) => { + (($x - $min) / ($max - $min) as f32).abs().sqrt() + }; + } + macro_rules! $d_id { + ($x: expr) => {{ + let x: f32 = $x * $x; + $min * (1.0 - x) + $max * x + }}; + } + }; } macro_rules! define_exp4 { ($n_id: ident $d_id: ident $min: expr, $max: expr) => { - macro_rules! $n_id { ($x: expr) => { - (($x - $min) / ($max - $min) as f32).abs().sqrt().sqrt() - } } - macro_rules! $d_id { ($x: expr) => { - { let x : f32 = $x * $x * $x * $x; $min * (1.0 - x) + $max * x } - } } - } + macro_rules! $n_id { + ($x: expr) => { + (($x - $min) / ($max - $min) as f32).abs().sqrt().sqrt() + }; + } + macro_rules! $d_id { + ($x: expr) => {{ + let x: f32 = $x * $x * $x * $x; + $min * (1.0 - x) + $max * x + }}; + } + }; } macro_rules! define_exp6 { ($n_id: ident $d_id: ident $min: expr, $max: expr) => { - macro_rules! $n_id { ($x: expr) => { - (($x - $min) / ($max - $min) as f32).abs().powf(1.0 / 6.0) - } } - macro_rules! $d_id { ($x: expr) => { - { let x : f32 = ($x).powf(6.0); $min * (1.0 - x) + $max * x } - } } - } + macro_rules! $n_id { + ($x: expr) => { + (($x - $min) / ($max - $min) as f32).abs().powf(1.0 / 6.0) + }; + } + macro_rules! $d_id { + ($x: expr) => {{ + let x: f32 = ($x).powf(6.0); + $min * (1.0 - x) + $max * x + }}; + } + }; } +#[macro_export] +macro_rules! n_pit { + ($x: expr) => { + 0.1 * (($x as f32).max(0.01) / 440.0).log2() + }; +} #[macro_export] -macro_rules! n_pit { ($x: expr) => { - 0.1 * (($x as f32).max(0.01) / 440.0).log2() -} } - -#[macro_export] -macro_rules! d_pit { ($x: expr) => { - { - let note : f32 = ($x as f32) * 10.0; +macro_rules! d_pit { + ($x: expr) => {{ + let note: f32 = ($x as f32) * 10.0; 440.0 * (2.0_f32).powf(note.clamp(-10.0, 10.0)) - } -} } + }}; +} // The following macros define detune parameter behaviour: // 0.2 => 24.0 // 0.1 => 12.0 // 0.008333333 => 1.0 // 0.000083333 => 0.001 -macro_rules! n_det { ($x: expr) => { $x / 120.0 } } -macro_rules! d_det { ($x: expr) => { $x * 120.0 } } +macro_rules! n_det { + ($x: expr) => { + $x / 120.0 + }; +} +macro_rules! d_det { + ($x: expr) => { + $x * 120.0 + }; +} /// The rounding function for detune UI knobs -macro_rules! r_det { ($x: expr, $coarse: expr) => { - if $coarse { - n_det!((d_det!($x)).round()) - } else { - n_det!((d_det!($x) * 100.0).round() / 100.0) - } -} } +macro_rules! r_det { + ($x: expr, $coarse: expr) => { + if $coarse { + n_det!((d_det!($x)).round()) + } else { + n_det!((d_det!($x) * 100.0).round() / 100.0) + } + }; +} /// The rounding function for -1 to 1 signal knobs -macro_rules! r_s { ($x: expr, $coarse: expr) => { - if $coarse { - ($x * 10.0).round() / 10.0 - } else { - ($x * 100.0).round() / 100.0 - } -} } - -/// The rounding function for milliseconds knobs -macro_rules! r_dc_ms { ($x: expr, $coarse: expr) => { - if $coarse { - n_declick!((d_declick!($x)).round()) - } else { - n_declick!((d_declick!($x) * 10.0).round() / 10.0) - } -} } - -/// The rounding function for milliseconds knobs -macro_rules! r_ems { ($x: expr, $coarse: expr) => { - if $coarse { - n_env!((d_env!($x)).round()) - } else { - n_env!((d_env!($x) * 10.0).round() / 10.0) - } -} } - -/// The rounding function for milliseconds knobs -macro_rules! r_tms { ($x: expr, $coarse: expr) => { - if $coarse { - if d_time!($x) > 1000.0 { - n_time!((d_time!($x) / 100.0).round() * 100.0) - } else if d_time!($x) > 100.0 { - n_time!((d_time!($x) / 10.0).round() * 10.0) +macro_rules! r_s { + ($x: expr, $coarse: expr) => { + if $coarse { + ($x * 10.0).round() / 10.0 } else { - n_time!((d_time!($x)).round()) + ($x * 100.0).round() / 100.0 } - } else { - n_time!((d_time!($x) * 10.0).round() / 10.0) - } -} } + }; +} /// The rounding function for milliseconds knobs -macro_rules! r_fms { ($x: expr, $coarse: expr) => { - if $coarse { - if d_ftme!($x) > 1000.0 { - n_ftme!((d_ftme!($x) / 100.0).round() * 100.0) - } else if d_ftme!($x) > 100.0 { - n_ftme!((d_ftme!($x) / 10.0).round() * 10.0) +macro_rules! r_dc_ms { + ($x: expr, $coarse: expr) => { + if $coarse { + n_declick!((d_declick!($x)).round()) } else { - n_ftme!((d_ftme!($x)).round()) + n_declick!((d_declick!($x) * 10.0).round() / 10.0) } - } else { - n_ftme!((d_ftme!($x) * 10.0).round() / 10.0) - } -} } + }; +} + +/// The rounding function for milliseconds knobs +macro_rules! r_ems { + ($x: expr, $coarse: expr) => { + if $coarse { + n_env!((d_env!($x)).round()) + } else { + n_env!((d_env!($x) * 10.0).round() / 10.0) + } + }; +} + +/// The rounding function for milliseconds knobs +macro_rules! r_tms { + ($x: expr, $coarse: expr) => { + if $coarse { + if d_time!($x) > 1000.0 { + n_time!((d_time!($x) / 100.0).round() * 100.0) + } else if d_time!($x) > 100.0 { + n_time!((d_time!($x) / 10.0).round() * 10.0) + } else { + n_time!((d_time!($x)).round()) + } + } else { + n_time!((d_time!($x) * 10.0).round() / 10.0) + } + }; +} + +/// The rounding function for milliseconds knobs +macro_rules! r_fms { + ($x: expr, $coarse: expr) => { + if $coarse { + if d_ftme!($x) > 1000.0 { + n_ftme!((d_ftme!($x) / 100.0).round() * 100.0) + } else if d_ftme!($x) > 100.0 { + n_ftme!((d_ftme!($x) / 10.0).round() * 10.0) + } else { + n_ftme!((d_ftme!($x)).round()) + } + } else { + n_ftme!((d_ftme!($x) * 10.0).round() / 10.0) + } + }; +} /// The rounding function for milliseconds knobs that also have a 0.0 setting -macro_rules! r_tmz { ($x: expr, $coarse: expr) => { - if $coarse { - if d_timz!($x) > 1000.0 { - n_timz!((d_timz!($x) / 100.0).round() * 100.0) - } else if d_timz!($x) > 100.0 { - n_timz!((d_timz!($x) / 10.0).round() * 10.0) +macro_rules! r_tmz { + ($x: expr, $coarse: expr) => { + if $coarse { + if d_timz!($x) > 1000.0 { + n_timz!((d_timz!($x) / 100.0).round() * 100.0) + } else if d_timz!($x) > 100.0 { + n_timz!((d_timz!($x) / 10.0).round() * 10.0) + } else { + n_timz!((d_timz!($x)).round()) + } } else { - n_timz!((d_timz!($x)).round()) + n_timz!((d_timz!($x) * 10.0).round() / 10.0) } - } else { - n_timz!((d_timz!($x) * 10.0).round() / 10.0) - } -} } + }; +} /// The rounding function for freq knobs (n_pit / d_pit) -macro_rules! r_fq { ($x: expr, $coarse: expr) => { - if $coarse { - ($x * 10.0).round() / 10.0 - } else { - let p = d_pit!($x); - if p < 10.0 { - n_pit!((p * 10.0).round() / 10.0) - } else if p < 100.0 { - n_pit!(p.round()) - } else if p < 1000.0 { - n_pit!((p / 10.0).round() * 10.0) - } else if p < 10000.0 { - n_pit!((p / 100.0).round() * 100.0) +macro_rules! r_fq { + ($x: expr, $coarse: expr) => { + if $coarse { + ($x * 10.0).round() / 10.0 } else { - n_pit!((p / 1000.0).round() * 1000.0) + let p = d_pit!($x); + if p < 10.0 { + n_pit!((p * 10.0).round() / 10.0) + } else if p < 100.0 { + n_pit!(p.round()) + } else if p < 1000.0 { + n_pit!((p / 10.0).round() * 10.0) + } else if p < 10000.0 { + n_pit!((p / 100.0).round() * 100.0) + } else { + n_pit!((p / 1000.0).round() * 1000.0) + } } - } -} } + }; +} /// The rounding function for vs (v scale) UI knobs -macro_rules! r_vps { ($x: expr, $coarse: expr) => { - if $coarse { - n_vps!((d_vps!($x)).round()) - } else { - n_vps!((d_vps!($x) * 10.0).round() / 10.0) - } -} } +macro_rules! r_vps { + ($x: expr, $coarse: expr) => { + if $coarse { + n_vps!((d_vps!($x)).round()) + } else { + n_vps!((d_vps!($x) * 10.0).round() / 10.0) + } + }; +} /// The rounding function for LFO time knobs -macro_rules! r_lfot { ($x: expr, $coarse: expr) => { - if $coarse { - let denv = d_lfot!($x); - - if denv < 10.0 { - let hz = 1000.0 / denv; - let hz = (hz / 10.0).round() * 10.0; - n_lfot!(1000.0 / hz) - - } else if denv < 250.0 { - n_lfot!((denv / 5.0).round() * 5.0) - - } else if denv < 1500.0 { - n_lfot!((denv / 50.0).round() * 50.0) - - } else if denv < 2500.0 { - n_lfot!((denv / 100.0).round() * 100.0) - - } else if denv < 5000.0 { - n_lfot!((denv / 500.0).round() * 500.0) - - } else if denv < 60000.0 { - n_lfot!((denv / 1000.0).round() * 1000.0) +macro_rules! r_lfot { + ($x: expr, $coarse: expr) => { + if $coarse { + let denv = d_lfot!($x); + if denv < 10.0 { + let hz = 1000.0 / denv; + let hz = (hz / 10.0).round() * 10.0; + n_lfot!(1000.0 / hz) + } else if denv < 250.0 { + n_lfot!((denv / 5.0).round() * 5.0) + } else if denv < 1500.0 { + n_lfot!((denv / 50.0).round() * 50.0) + } else if denv < 2500.0 { + n_lfot!((denv / 100.0).round() * 100.0) + } else if denv < 5000.0 { + n_lfot!((denv / 500.0).round() * 500.0) + } else if denv < 60000.0 { + n_lfot!((denv / 1000.0).round() * 1000.0) + } else { + n_lfot!((denv / 5000.0).round() * 5000.0) + } } else { - n_lfot!((denv / 5000.0).round() * 5000.0) + let denv = d_lfot!($x); + + let o = if denv < 10.0 { + let hz = 1000.0 / denv; + let hz = hz.round(); + n_lfot!(1000.0 / hz) + } else if denv < 100.0 { + n_lfot!(denv.round()) + } else if denv < 1000.0 { + n_lfot!((denv / 5.0).round() * 5.0) + } else if denv < 2500.0 { + n_lfot!((denv / 10.0).round() * 10.0) + } else if denv < 25000.0 { + n_lfot!((denv / 100.0).round() * 100.0) + } else { + n_lfot!((denv / 500.0).round() * 500.0) + }; + + o } - } else { - let denv = d_lfot!($x); - - let o = - if denv < 10.0 { - let hz = 1000.0 / denv; - let hz = hz.round(); - n_lfot!(1000.0 / hz) - - } else if denv < 100.0 { - n_lfot!(denv.round()) - - } else if denv < 1000.0 { - n_lfot!((denv / 5.0).round() * 5.0) - - } else if denv < 2500.0 { - n_lfot!((denv / 10.0).round() * 10.0) - - } else if denv < 25000.0 { - n_lfot!((denv / 100.0).round() * 100.0) - - } else { - n_lfot!((denv / 500.0).round() * 500.0) - }; - - o - } -} } + }; +} /// The default steps function: -macro_rules! stp_d { () => { (20.0, 100.0) } } +macro_rules! stp_d { + () => { + (20.0, 100.0) + }; +} /// The UI steps to control parameters with a finer fine control: -macro_rules! stp_m { () => { (20.0, 200.0) } } +macro_rules! stp_m { + () => { + (20.0, 200.0) + }; +} /// The UI steps to control parameters with a very fine fine control: -macro_rules! stp_f { () => { (20.0, 1000.0) } } +macro_rules! stp_f { + () => { + (20.0, 1000.0) + }; +} // Rounding function that does nothing -macro_rules! r_id { ($x: expr, $coarse: expr) => { $x } } +macro_rules! r_id { + ($x: expr, $coarse: expr) => { + $x + }; +} // Default formatting function -macro_rules! f_def { ($formatter: expr, $v: expr, $denorm_v: expr) => { - write!($formatter, "{:6.3}", $denorm_v) -} } +macro_rules! f_def { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + write!($formatter, "{:6.3}", $denorm_v) + }; +} // Default formatting function with low precision -macro_rules! f_deflp { ($formatter: expr, $v: expr, $denorm_v: expr) => { - write!($formatter, "{:5.2}", $denorm_v) -} } +macro_rules! f_deflp { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + write!($formatter, "{:5.2}", $denorm_v) + }; +} // Default formatting function with very low precision -macro_rules! f_defvlp { ($formatter: expr, $v: expr, $denorm_v: expr) => { - write!($formatter, "{:4.1}", $denorm_v) -} } +macro_rules! f_defvlp { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + write!($formatter, "{:4.1}", $denorm_v) + }; +} -macro_rules! f_freq { ($formatter: expr, $v: expr, $denorm_v: expr) => { - if ($denorm_v >= 1000.0) { - write!($formatter, "{:6.0}Hz", $denorm_v) - } else if ($denorm_v >= 100.0) { - write!($formatter, "{:6.1}Hz", $denorm_v) - } else { - write!($formatter, "{:6.2}Hz", $denorm_v) - } -} } +macro_rules! f_freq { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + if ($denorm_v >= 1000.0) { + write!($formatter, "{:6.0}Hz", $denorm_v) + } else if ($denorm_v >= 100.0) { + write!($formatter, "{:6.1}Hz", $denorm_v) + } else { + write!($formatter, "{:6.2}Hz", $denorm_v) + } + }; +} -macro_rules! f_ms { ($formatter: expr, $v: expr, $denorm_v: expr) => { - if $denorm_v >= 1000.0 { - write!($formatter, "{:6.0}ms", $denorm_v) - } else if $denorm_v >= 100.0 { - write!($formatter, "{:5.1}ms", $denorm_v) - } else { - write!($formatter, "{:5.2}ms", $denorm_v) - } -} } +macro_rules! f_ms { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + if $denorm_v >= 1000.0 { + write!($formatter, "{:6.0}ms", $denorm_v) + } else if $denorm_v >= 100.0 { + write!($formatter, "{:5.1}ms", $denorm_v) + } else { + write!($formatter, "{:5.2}ms", $denorm_v) + } + }; +} -macro_rules! f_lfot { ($formatter: expr, $v: expr, $denorm_v: expr) => { - if $denorm_v < 10.0 { - write!($formatter, "{:5.1}Hz", 1000.0 / $denorm_v) +macro_rules! f_lfot { + ($formatter: expr, $v: expr, $denorm_v: expr) => { + if $denorm_v < 10.0 { + write!($formatter, "{:5.1}Hz", 1000.0 / $denorm_v) + } else if $denorm_v < 250.0 { + write!($formatter, "{:4.1}ms", $denorm_v) + } else if $denorm_v < 1500.0 { + write!($formatter, "{:4.0}ms", $denorm_v) + } else if $denorm_v < 10000.0 { + write!($formatter, "{:5.2}s", $denorm_v / 1000.0) + } else { + write!($formatter, "{:5.1}s", $denorm_v / 1000.0) + } + }; +} - } else if $denorm_v < 250.0 { - write!($formatter, "{:4.1}ms", $denorm_v) - - } else if $denorm_v < 1500.0 { - write!($formatter, "{:4.0}ms", $denorm_v) - - } else if $denorm_v < 10000.0 { - write!($formatter, "{:5.2}s", $denorm_v / 1000.0) - - } else { - write!($formatter, "{:5.1}s", $denorm_v / 1000.0) - } -} } - - -macro_rules! f_det { ($formatter: expr, $v: expr, $denorm_v: expr) => { - { - let sign = if $denorm_v < 0.0 { -1.0 } else { 1.0 }; +macro_rules! f_det { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let sign = if $denorm_v < 0.0 { -1.0 } else { 1.0 }; let semitones = $denorm_v.trunc().abs(); - let cents = ($denorm_v.fract() * 100.0).round().abs(); + let cents = ($denorm_v.fract() * 100.0).round().abs(); if (cents > 0.1) { write!($formatter, "{:2.0}s {:3.0}c", sign * semitones, cents) } else { write!($formatter, "{:2.0}s", sign * semitones) } - } -} } - + }}; +} // norm-fun denorm-min // denorm-fun denorm-max -define_exp!{n_gain d_gain 0.0, 2.0} -define_exp!{n_att d_att 0.0, 1.0} +define_exp! {n_gain d_gain 0.0, 2.0} +define_exp! {n_att d_att 0.0, 1.0} -define_exp!{n_declick d_declick 0.0, 50.0} +define_exp! {n_declick d_declick 0.0, 50.0} -define_exp!{n_env d_env 0.0, 1000.0} +define_exp! {n_env d_env 0.0, 1000.0} -define_exp6!{n_lfot d_lfot 0.1,300000.0} -define_exp!{n_time d_time 0.5, 5000.0} -define_exp!{n_ftme d_ftme 0.1, 1000.0} -define_exp!{n_timz d_timz 0.0, 5000.0} +define_exp6! {n_lfot d_lfot 0.1,300000.0} +define_exp! {n_time d_time 0.5, 5000.0} +define_exp! {n_ftme d_ftme 0.1, 1000.0} +define_exp! {n_timz d_timz 0.0, 5000.0} // Special linear gain factor for the Out node, to be able // to reach more exact "1.0". -define_lin!{n_ogin d_ogin 0.0, 2.0} +define_lin! {n_ogin d_ogin 0.0, 2.0} -define_lin!{n_pgin d_pgin 1.0, 10.0} +define_lin! {n_pgin d_pgin 1.0, 10.0} -define_lin!{n_vps d_vps 0.0, 20.0} +define_lin! {n_vps d_vps 0.0, 20.0} // A note about the input-indicies: // @@ -708,7 +782,7 @@ define_lin!{n_vps d_vps 0.0, 20.0} // for new nodes. macro_rules! node_list { ($inmacro: ident) => { - $inmacro!{ + $inmacro! { nop => Nop, amp => Amp UIType::Generic UICategory::Signal // node_param_idx @@ -938,7 +1012,7 @@ macro_rules! node_list { [4 out4] [5 outc], } - } + }; } impl UICategory { @@ -968,7 +1042,7 @@ impl UICategory { } } - node_list!{make_cat_lister}; + node_list! {make_cat_lister}; } } @@ -985,20 +1059,18 @@ fn rand_node_satisfies_spec(nid: NodeId, sel: RandNodeSelector) -> bool { match sel { RandNodeSelector::Any => true, - RandNodeSelector::OnlyUseful => { - match nid { - NodeId::Nop => false, - NodeId::Out(_) => false, - NodeId::FbRd(_) => false, - NodeId::Test(_) => false, - _ => true, - } + RandNodeSelector::OnlyUseful => match nid { + NodeId::Nop => false, + NodeId::Out(_) => false, + NodeId::FbRd(_) => false, + NodeId::Test(_) => false, + _ => true, }, } } pub fn get_rand_node_id(count: usize, sel: RandNodeSelector) -> Vec { - let mut sm = crate::dsp::helpers::SplitMix64::new_time_seed(); + let mut sm = crate::dsp::helpers::SplitMix64::new_time_seed(); let mut out = vec![]; let mut cnt = 0; @@ -1029,24 +1101,22 @@ pub fn get_rand_node_id(count: usize, sel: RandNodeSelector) -> Vec { /// [crate::Matrix::info_for]. #[derive(Clone)] pub struct NodeInfo { - node_id: NodeId, - inputs: Vec<&'static str>, - atoms: Vec<&'static str>, - outputs: Vec<&'static str>, - input_help: Vec<&'static str>, - output_help: Vec<&'static str>, - node_help: &'static str, - node_desc: &'static str, - node_name: &'static str, - norm_v: std::rc::Rc f32>, - denorm_v: std::rc::Rc f32>, + node_id: NodeId, + inputs: Vec<&'static str>, + atoms: Vec<&'static str>, + outputs: Vec<&'static str>, + input_help: Vec<&'static str>, + output_help: Vec<&'static str>, + node_help: &'static str, + node_desc: &'static str, + node_name: &'static str, + norm_v: std::rc::Rc f32>, + denorm_v: std::rc::Rc f32>, } impl std::fmt::Debug for NodeInfo { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - f.debug_struct("NodeInfo") - .field("node_id", &self.node_id) - .finish() + f.debug_struct("NodeInfo").field("node_id", &self.node_id).finish() } } @@ -1838,8 +1908,8 @@ macro_rules! make_node_enum { } } -node_list!{make_node_info_enum} -node_list!{make_node_enum} +node_list! {make_node_info_enum} +node_list! {make_node_enum} pub fn node_factory(node_id: NodeId) -> Option<(Node, NodeInfo)> { macro_rules! make_node_factory_match { @@ -1866,7 +1936,7 @@ pub fn node_factory(node_id: NodeId) -> Option<(Node, NodeInfo)> { } } - node_list!{make_node_factory_match} + node_list! {make_node_factory_match} } impl Node { @@ -1905,11 +1975,15 @@ impl Node { /// display some kind of position indicator. #[inline] pub fn process( - &mut self, ctx: &mut T, ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + ectx: &mut NodeExecContext, nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], outputs: &mut [ProcBuf], - led: LedPhaseVals) - { + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + led: LedPhaseVals, + ) { macro_rules! make_node_process { ($s1: ident => $v1: ident, $($str: ident => $variant: ident @@ -1933,20 +2007,19 @@ impl Node { } } - node_list!{make_node_process} + node_list! {make_node_process} } } - #[cfg(test)] mod tests { use super::*; #[test] fn check_node_size_staying_small() { - assert_eq!(std::mem::size_of::(), 56); - assert_eq!(std::mem::size_of::(), 2); - assert_eq!(std::mem::size_of::(), 24); + assert_eq!(std::mem::size_of::(), 56); + assert_eq!(std::mem::size_of::(), 2); + assert_eq!(std::mem::size_of::(), 24); } #[test] @@ -1962,9 +2035,7 @@ mod tests { let x = (((i as f32) / 1000.0) - 0.5) * 2.0; let r = d_pit!(x); //d// println!("x={:8.5} => {:8.5}", x, r); - assert_eq!( - (n_pit!(r) * 10000.0).round() as i32, - (x * 10000.0).round() as i32); + assert_eq!((n_pit!(r) * 10000.0).round() as i32, (x * 10000.0).round() as i32); } } } diff --git a/src/dsp/node_ad.rs b/src/dsp/node_ad.rs index ebc09b1..55c26f5 100644 --- a/src/dsp/node_ad.rs +++ b/src/dsp/node_ad.rs @@ -2,88 +2,82 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; +use super::helpers::{sqrt4_to_pow4, TrigSignal, Trigger}; use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, - GraphAtomData, GraphFun, NodeContext, + DspNode, GraphAtomData, GraphFun, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, }; -use super::helpers::{Trigger, TrigSignal, sqrt4_to_pow4}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_ad_mult { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "x1", - 1 => "x10", - 2 => "x100", - _ => "?", +macro_rules! fa_ad_mult { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "x1", + 1 => "x10", + 2 => "x100", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct Ad { - inc: f64, - stage: u8, - samples_ms: f64, - value: f64, - last_time: f32, - trig: Trigger, - trig_sig: TrigSignal, + inc: f64, + stage: u8, + samples_ms: f64, + value: f64, + last_time: f32, + trig: Trigger, + trig_sig: TrigSignal, } impl Ad { pub fn new(_nid: &NodeId) -> Self { Self { - inc: 0.0, - stage: 0, + inc: 0.0, + stage: 0, samples_ms: 44.1, - value: 0.0, + value: 0.0, last_time: -1.0, - trig: Trigger::new(), - trig_sig: TrigSignal::new(), + trig: Trigger::new(), + trig_sig: TrigSignal::new(), } } - pub const inp : &'static str = + pub const inp: &'static str = "Ad inp\nSignal input. If you don't connect this, and set this to 1.0 \ this will act as envelope signal generator. But you can also just \ route a signal directly through this of course.\nRange: (-1..1)\n"; - pub const trig : &'static str = + pub const trig: &'static str = "Ad trig\nTrigger input that starts the attack phase.\nRange: (0..1)\n"; - pub const atk : &'static str = + pub const atk: &'static str = "Ad atk\nAttack time of the envelope. You can extend the maximum \ range of this with the 'mult' setting.\nRange: (0..1)\n"; - pub const dcy : &'static str = - "Ad atk\nDecay time of the envelope. You can extend the maximum \ + pub const dcy: &'static str = "Ad atk\nDecay time of the envelope. You can extend the maximum \ range of this with the 'mult' setting.\nRange: (0..1)\n"; - pub const ashp : &'static str = - "Ad ashp\nAttack shape. This allows you to change the shape \ + pub const ashp: &'static str = "Ad ashp\nAttack shape. This allows you to change the shape \ of the attack stage from a logarithmic, to a linear and to an \ exponential shape.\nRange: (0..1)\n"; - pub const dshp : &'static str = - "Ad dshp\nDecay shape. This allows you to change the shape \ + pub const dshp: &'static str = "Ad dshp\nDecay shape. This allows you to change the shape \ of the decay stage from a logarithmic, to a linear and to an \ exponential shape.\nRange: (0..1)\n"; - pub const mult : &'static str = - "Ad mult\nAttack and Decay time range multiplier. \ + pub const mult: &'static str = "Ad mult\nAttack and Decay time range multiplier. \ This will extend the maximum range of the 'atk' and 'dcy' parameters."; - pub const sig : &'static str = + pub const sig: &'static str = "Ad sig\nEnvelope signal output. If a signal is sent to the 'inp' port, \ you will receive an attenuated signal here. If you set 'inp' to a \ fixed value (for instance 1.0), this will output an envelope signal \ in the range 0.0 to 'inp' (1.0).\nRange: (-1..1)\n"; - pub const eoet : &'static str = + pub const eoet: &'static str = "Ad eoet\nEnd of envelope trigger. This output sends a trigger once \ the end of the decay stage has been reached.\nRange: (0..1)"; - pub const DESC : &'static str = -r#"Attack-Decay Envelope + pub const DESC: &'static str = r#"Attack-Decay Envelope This is a simple envelope offering an attack time and decay time with a shape parameter. You can use it as envelope generator to modulate other inputs or process a signal with it directly. "#; - pub const HELP : &'static str = -r#"Ad - Attack-Decay Envelope + pub const HELP: &'static str = r#"Ad - Attack-Decay Envelope This simple two stage envelope with attack and decay offers shape parameters for each stage. The attack and decay times can be extended using the 'mult' @@ -97,11 +91,12 @@ other inputs. With the 'eoet' output you can either trigger other envelopes or via 'FbWr'/'FbRd' retrigger the envelope. "#; - } impl DspNode for Ad { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.samples_ms = srate as f64 / 1000.0; @@ -109,134 +104,127 @@ impl DspNode for Ad { } fn reset(&mut self) { - self.stage = 0; - self.value = 0.0; - self.inc = 0.0; - self.last_time = -1.0; + self.stage = 0; + self.value = 0.0; + self.inc = 0.0; + self.last_time = -1.0; self.trig_sig.reset(); self.trig.reset(); } #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let inp = inp::Ad::inp(inputs); - let trig = inp::Ad::trig(inputs); - let atk = inp::Ad::atk(inputs); - let dcy = inp::Ad::dcy(inputs); + let inp = inp::Ad::inp(inputs); + let trig = inp::Ad::trig(inputs); + let atk = inp::Ad::atk(inputs); + let dcy = inp::Ad::dcy(inputs); let atk_shape = inp::Ad::ashp(inputs); let dcy_shape = inp::Ad::dshp(inputs); - let mult = at::Ad::mult(atoms); + let mult = at::Ad::mult(atoms); // block start: - let (mut shape_src, mut inc_time_src, mut target, mut delta) = - match self.stage { - 1 => (atk_shape, atk, 1.0, 1.0), - 2 => (dcy_shape, dcy, 0.0, -1.0), - _ => (atk_shape, atk, 0.0, 0.0), - }; - let mult : f64 = - match mult.i() { - 1 => 10.0, - 2 => 100.0, - _ => 1.0, - }; + let (mut shape_src, mut inc_time_src, mut target, mut delta) = match self.stage { + 1 => (atk_shape, atk, 1.0, 1.0), + 2 => (dcy_shape, dcy, 0.0, -1.0), + _ => (atk_shape, atk, 0.0, 0.0), + }; + let mult: f64 = match mult.i() { + 1 => 10.0, + 2 => 100.0, + _ => 1.0, + }; -// let mut cnt : usize = 0; + // let mut cnt : usize = 0; for frame in 0..ctx.nframes() { if self.trig.check_trigger(denorm::Ad::trig(trig, frame)) { //d// println!("RETRIGGER!"); - self.stage = 1; + self.stage = 1; self.last_time = -1.0; - target = 1.0; - delta = 1.0; - shape_src = atk_shape; - inc_time_src = atk; + target = 1.0; + delta = 1.0; + shape_src = atk_shape; + inc_time_src = atk; } let cur_time = denorm::Ad::atk(inc_time_src, frame); if self.last_time != cur_time { - self.inc = - if cur_time <= 0.0001 { - delta - } else { - delta - / ((cur_time as f64) * mult * self.samples_ms) - }; + self.inc = if cur_time <= 0.0001 { + delta + } else { + delta / ((cur_time as f64) * mult * self.samples_ms) + }; self.last_time = cur_time; -// if cnt % 32 == 0 { -// println!("** v={:8.3}, inc={:8.3}, tar={:8.3}, time={:8.3}", -// self.value, self.inc, target, self.last_time); -// } + // if cnt % 32 == 0 { + // println!("** v={:8.3}, inc={:8.3}, tar={:8.3}, time={:8.3}", + // self.value, self.inc, target, self.last_time); + // } } self.value += self.inc; - let shape = - denorm::Ad::ashp(shape_src, frame) - .clamp(0.0, 1.0); + let shape = denorm::Ad::ashp(shape_src, frame).clamp(0.0, 1.0); -// if cnt % 32 == 0 { -// println!("v={:8.3}, inc={:8.3}, tar={:8.3}, time={:8.3}", -// self.value, self.inc, target, self.last_time); -// } -// cnt += 1; + // if cnt % 32 == 0 { + // println!("v={:8.3}, inc={:8.3}, tar={:8.3}, time={:8.3}", + // self.value, self.inc, target, self.last_time); + // } + // cnt += 1; match self.stage { - 1 => { + 1 => { if self.value >= (target - 0.0001) { - self.stage = 2; + self.stage = 2; self.last_time = -1.0; - self.value = target; - target = 0.0; - delta = -1.0; - shape_src = dcy_shape; - inc_time_src = dcy; + self.value = target; + target = 0.0; + delta = -1.0; + shape_src = dcy_shape; + inc_time_src = dcy; } - }, - 2 => { + } + 2 => { if self.value <= (target + 0.0001) { - self.stage = 0; + self.stage = 0; self.last_time = -1.0; - self.value = target; - target = 0.0; - delta = 0.0; + self.value = target; + target = 0.0; + delta = 0.0; self.trig_sig.trigger(); } - }, - _ => {}, + } + _ => {} } let in_val = denorm::Ad::inp(inp, frame); let out = out::Ad::sig(outputs); //d// println!("VAL in={}, val={} shp: {}=>{}", in_val, self.value, shape, //d// sqrt4_to_pow4(1.0, shape)); - out.write( - frame, - in_val - * sqrt4_to_pow4( - self.value.clamp(0.0, 1.0) as f32, - shape)); + out.write(frame, in_val * sqrt4_to_pow4(self.value.clamp(0.0, 1.0) as f32, shape)); let eoet = out::Ad::eoet(outputs); eoet.write(frame, self.trig_sig.next()); } ctx_vals[0].set(self.value as f32); -// ctx_vals[1].set(self.phase / self. + self.stage * ); + // ctx_vals[1].set(self.phase / self. + self.stage * ); } fn graph_fun() -> Option { Some(Box::new(|gd: &dyn GraphAtomData, _init: bool, x: f32, xn: f32| -> f32 { - let atk_idx = NodeId::Ad(0).inp_param("atk").unwrap().inp(); - let dcy_idx = NodeId::Ad(0).inp_param("dcy").unwrap().inp(); + let atk_idx = NodeId::Ad(0).inp_param("atk").unwrap().inp(); + let dcy_idx = NodeId::Ad(0).inp_param("dcy").unwrap().inp(); let ashp_idx = NodeId::Ad(0).inp_param("ashp").unwrap().inp(); let dshp_idx = NodeId::Ad(0).inp_param("dshp").unwrap().inp(); diff --git a/src/dsp/node_allp.rs b/src/dsp/node_allp.rs index a17c19e..901293d 100644 --- a/src/dsp/node_allp.rs +++ b/src/dsp/node_allp.rs @@ -2,9 +2,9 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; use crate::dsp::helpers::AllPass; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; /// A simple amplifier #[derive(Debug, Clone)] @@ -14,28 +14,22 @@ pub struct AllP { impl AllP { pub fn new(_nid: &NodeId) -> Self { - Self { - allpass: Box::new(AllPass::new()), - } + Self { allpass: Box::new(AllPass::new()) } } - pub const inp : &'static str = + pub const inp: &'static str = "AllP inp\nThe signal input for the allpass filter.\nRange: (-1..1)"; - pub const g : &'static str = + pub const g: &'static str = "AllP g\nThe internal factor for the allpass filter.\nRange: (-1..1)"; - pub const time : &'static str = - "AllP time\nThe allpass delay time.\nRange: (0..1)"; - pub const sig : &'static str = - "AllP sig\nThe output of allpass filter.\nRange: (-1..1)"; + pub const time: &'static str = "AllP time\nThe allpass delay time.\nRange: (0..1)"; + pub const sig: &'static str = "AllP sig\nThe output of allpass filter.\nRange: (-1..1)"; - pub const DESC : &'static str = -r#"Single Allpass Filter + pub const DESC: &'static str = r#"Single Allpass Filter This is an allpass filter that can be used to build reverbs or anything you might find it useful for. "#; -pub const HELP : &'static str = -r#"AllP - A Simple Single Allpass Filter + pub const HELP: &'static str = r#"AllP - A Simple Single Allpass Filter This is an allpass filter that can be used to build reverbs or anything you might find it useful for. @@ -69,7 +63,9 @@ using the FbWr and FbRd nodes!) } impl DspNode for AllP { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.allpass.set_sample_rate(srate as f64); @@ -81,28 +77,35 @@ impl DspNode for AllP { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{denorm, inp, out}; - let inp = inp::AllP::inp(inputs); + let inp = inp::AllP::inp(inputs); let time = inp::AllP::time(inputs); - let g = inp::AllP::g(inputs); - let out = out::AllP::sig(outputs); + let g = inp::AllP::g(inputs); + let out = out::AllP::sig(outputs); let ap = &mut *self.allpass; for frame in 0..ctx.nframes() { let v = inp.read(frame); - out.write(frame, + out.write( + frame, ap.next( denorm::AllP::time(time, frame) as f64, denorm::AllP::g(g, frame) as f64, - v as f64) as f32); + v as f64, + ) as f32, + ); } let last_frame = ctx.nframes() - 1; diff --git a/src/dsp/node_amp.rs b/src/dsp/node_amp.rs index 24079c9..b28d4cf 100644 --- a/src/dsp/node_amp.rs +++ b/src/dsp/node_amp.rs @@ -2,49 +2,44 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; #[macro_export] -macro_rules! fa_amp_neg_att { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Allow", - 1 => "Clip", - _ => "?", +macro_rules! fa_amp_neg_att { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Allow", + 1 => "Clip", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] -pub struct Amp { -} +pub struct Amp {} impl Amp { pub fn new(_nid: &NodeId) -> Self { - Self { - } + Self {} } - pub const inp : &'static str = - "Amp inp\nSignal input\nRange: (-1..1)\n"; - pub const att : &'static str = + pub const inp: &'static str = "Amp inp\nSignal input\nRange: (-1..1)\n"; + pub const att: &'static str = "Amp att\nAttenuate input. Does only attenuate the signal, not amplify it.\n\ Use this for envelope input.\nRange: (0..1)\n"; - pub const gain : &'static str = + pub const gain: &'static str = "Amp gain\nGain input. This control can actually amplify the signal.\nRange: (0..1)\n"; pub const neg_att : &'static str = "Amp neg\nIf this is set to 'Clip', only positive inputs to 'att' are used.\nRange: (0..1)\n"; - pub const sig : &'static str = - "Amp sig\nAmplified signal output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Signal Amplifier + pub const sig: &'static str = "Amp sig\nAmplified signal output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Signal Amplifier This is a simple amplifier to amplify or attenuate a signal. See also nodes like 'atv' for an Attenuverter or 'mix' for mixing signals. "#; - pub const HELP : &'static str = -r#"Amp - Signal Amplifier + pub const HELP: &'static str = r#"Amp - Signal Amplifier It serves the simple purpose of taking an input signal and attenuate (either with the 'att' or the 'gain' parameter) or just amplifying it with @@ -59,63 +54,64 @@ the desired amplification with the 'gain' parameter and automate it using the 'att' parameter. The 'neg' setting then defines what happens with negative inputs on the 'att' port. "#; - } impl DspNode for Amp { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, denorm_v, inp_dir, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, denorm_v, inp, inp_dir, out}; let gain = inp::Amp::gain(inputs); - let att = inp::Amp::att(inputs); - let inp = inp::Amp::inp(inputs); - let out = out::Amp::sig(outputs); - let neg = at::Amp::neg_att(atoms); + let att = inp::Amp::att(inputs); + let inp = inp::Amp::inp(inputs); + let out = out::Amp::sig(outputs); + let neg = at::Amp::neg_att(atoms); - let last_frame = ctx.nframes() - 1; + let last_frame = ctx.nframes() - 1; - let last_val = - if neg.i() > 0 { - for frame in 0..ctx.nframes() { - out.write(frame, - inp.read(frame) - * denorm_v::Amp::att( - inp_dir::Amp::att(att, frame) - .max(0.0)) - * denorm::Amp::gain(gain, frame)); - } + let last_val = if neg.i() > 0 { + for frame in 0..ctx.nframes() { + out.write( + frame, + inp.read(frame) + * denorm_v::Amp::att(inp_dir::Amp::att(att, frame).max(0.0)) + * denorm::Amp::gain(gain, frame), + ); + } - inp.read(last_frame) - * denorm_v::Amp::att( - inp_dir::Amp::att(att, last_frame) - .max(0.0)) + inp.read(last_frame) + * denorm_v::Amp::att(inp_dir::Amp::att(att, last_frame).max(0.0)) * denorm::Amp::gain(gain, last_frame) + } else { + for frame in 0..ctx.nframes() { + out.write( + frame, + inp.read(frame) + * denorm_v::Amp::att(inp_dir::Amp::att(att, frame).abs()) + * denorm::Amp::gain(gain, frame), + ); + } - } else { - for frame in 0..ctx.nframes() { - out.write(frame, - inp.read(frame) - * denorm_v::Amp::att( - inp_dir::Amp::att(att, frame).abs()) - * denorm::Amp::gain(gain, frame)); - } - - inp.read(last_frame) - * denorm_v::Amp::att( - inp_dir::Amp::att(att, last_frame).abs()) + inp.read(last_frame) + * denorm_v::Amp::att(inp_dir::Amp::att(att, last_frame).abs()) * denorm::Amp::gain(gain, last_frame) - }; + }; ctx_vals[0].set(last_val); } diff --git a/src/dsp/node_biqfilt.rs b/src/dsp/node_biqfilt.rs index 8d749d0..43a9d4a 100644 --- a/src/dsp/node_biqfilt.rs +++ b/src/dsp/node_biqfilt.rs @@ -2,43 +2,45 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; use crate::dsp::biquad::*; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_biqfilt_type { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "BtW LP", - 1 => "Res", - _ => "?", +macro_rules! fa_biqfilt_type { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "BtW LP", + 1 => "Res", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[macro_export] -macro_rules! fa_biqfilt_ord { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "1", - 1 => "2", - 2 => "3", - 3 => "4", - _ => "?", +macro_rules! fa_biqfilt_ord { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "1", + 1 => "2", + 2 => "3", + 3 => "4", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct BiqFilt { cascade: Vec, - srate: f32, - ofreq: f32, - oq: f32, - ogain: f32, - otype: u8, + srate: f32, + ofreq: f32, + oq: f32, + ogain: f32, + otype: u8, } impl BiqFilt { @@ -48,33 +50,24 @@ impl BiqFilt { srate: 1.0 / 44100.0, otype: 99, // value that can't be set by the user ofreq: -2.0, // value that can't be set by the user - oq: -2.0, // value that can't be set by the user + oq: -2.0, // value that can't be set by the user ogain: -2.0, // value that can't be set by the user } } - pub const inp : &'static str = - "BiqFilt inp\nSignal input\nRange: (-1..1)\n"; - pub const freq : &'static str = - "BiqFilt freq\nFilter cutoff frequency.\nRange: (-1..1)\n"; - pub const q : &'static str = - "BiqFilt q\nFilter Q factor.\nRange: (0..1)\n"; - pub const gain : &'static str = - "BiqFilt gain\nFilter gain.\nRange: (0..1)\n"; - pub const ftype : &'static str = - "BiqFilt ftype\n'BtW LP' Butterworth Low-Pass, 'Res' Resonator"; - pub const order : &'static str = - "BiqFilt order\n"; - pub const sig : &'static str = - "BiqFilt sig\nFiltered signal output.\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Biquad Filter + pub const inp: &'static str = "BiqFilt inp\nSignal input\nRange: (-1..1)\n"; + pub const freq: &'static str = "BiqFilt freq\nFilter cutoff frequency.\nRange: (-1..1)\n"; + pub const q: &'static str = "BiqFilt q\nFilter Q factor.\nRange: (0..1)\n"; + pub const gain: &'static str = "BiqFilt gain\nFilter gain.\nRange: (0..1)\n"; + pub const ftype: &'static str = "BiqFilt ftype\n'BtW LP' Butterworth Low-Pass, 'Res' Resonator"; + pub const order: &'static str = "BiqFilt order\n"; + pub const sig: &'static str = "BiqFilt sig\nFiltered signal output.\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Biquad Filter This is the implementation of a biquad filter cascade. It is not meant for fast automation. Please use other nodes like eg. SFilter for that. "#; - pub const HELP : &'static str = -r#"BiqFilt - Biquad Filter (Cascade) + pub const HELP: &'static str = r#"BiqFilt - Biquad Filter (Cascade) This is the implementation of a biquad filter cascade. It is not meant for fast automation and might blow up if you @@ -83,7 +76,9 @@ treat it too rough. Please use other nodes like eg. SFilter for that. } impl DspNode for BiqFilt { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.srate = srate; @@ -102,38 +97,41 @@ impl DspNode for BiqFilt { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let inp = inp::BiqFilt::inp(inputs); - let freq = inp::BiqFilt::freq(inputs); - let q = inp::BiqFilt::q(inputs); - let gain = inp::BiqFilt::gain(inputs); + let inp = inp::BiqFilt::inp(inputs); + let freq = inp::BiqFilt::freq(inputs); + let q = inp::BiqFilt::q(inputs); + let gain = inp::BiqFilt::gain(inputs); let ftype = at::BiqFilt::ftype(atoms); let order = at::BiqFilt::order(atoms); - let out = out::BiqFilt::sig(outputs); + let out = out::BiqFilt::sig(outputs); let ftype = ftype.i() as u8; let cfreq = denorm::BiqFilt::freq(freq, 0); let cfreq = cfreq.clamp(0.0, 22000.0); - let cq = denorm::BiqFilt::q(q, 0); + let cq = denorm::BiqFilt::q(q, 0); let cgain = denorm::BiqFilt::gain(gain, 0); - if ftype != self.otype - || (cfreq - self.ofreq).abs() > 0.0001 - || (cq - self.oq).abs() > 0.0001 - || (cgain - self.ogain).abs() > 0.0001 + if ftype != self.otype + || (cfreq - self.ofreq).abs() > 0.0001 + || (cq - self.oq).abs() > 0.0001 + || (cgain - self.ogain).abs() > 0.0001 { // recalculate coeffs of all in the cascade - let coefs = - match ftype { - 1 => BiquadCoefs::resonator(self.srate, cfreq, cq), - _ => BiquadCoefs::butter_lowpass(self.srate, cfreq), - }; + let coefs = match ftype { + 1 => BiquadCoefs::resonator(self.srate, cfreq, cq), + _ => BiquadCoefs::butter_lowpass(self.srate, cfreq), + }; for o in &mut self.cascade { o.set_coefs(coefs); @@ -142,20 +140,21 @@ impl DspNode for BiqFilt { self.otype = ftype; self.ofreq = cfreq; - self.oq = cq; + self.oq = cq; self.ogain = cgain; } let mut order = order.i() as u8; - if ftype == 1 { // The resonator just blows up with higher orders. + if ftype == 1 { + // The resonator just blows up with higher orders. order = 0; } for frame in 0..ctx.nframes() { -// let freq = denorm::BiqFilt::freq(freq, frame); -// let freq = freq.clamp($minfreq, $maxfreq); -// let q = denorm::BiqFilt::q(q, frame); -// let gain = denorm::BiqFilt::gain(gain, frame); + // let freq = denorm::BiqFilt::freq(freq, frame); + // let freq = freq.clamp($minfreq, $maxfreq); + // let q = denorm::BiqFilt::q(q, frame); + // let gain = denorm::BiqFilt::gain(gain, frame); let mut s = inp.read(frame); for i in 0..=order { diff --git a/src/dsp/node_bosc.rs b/src/dsp/node_bosc.rs index c77ca86..b965a41 100644 --- a/src/dsp/node_bosc.rs +++ b/src/dsp/node_bosc.rs @@ -2,25 +2,25 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, - GraphAtomData, GraphFun, -}; use crate::dsp::helpers::PolyBlepOscillator; +use crate::dsp::{ + DspNode, GraphAtomData, GraphFun, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, +}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_bosc_wtype { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Sin", - 1 => "Tri", - 2 => "Saw", - 3 => "Pulse", - _ => "?", +macro_rules! fa_bosc_wtype { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Sin", + 1 => "Tri", + 2 => "Saw", + 3 => "Pulse", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] @@ -33,47 +33,39 @@ impl BOsc { pub fn new(nid: &NodeId) -> Self { let init_phase = nid.init_phase(); - Self { - osc: PolyBlepOscillator::new(init_phase), - israte: 1.0 / 44100.0, - } + Self { osc: PolyBlepOscillator::new(init_phase), israte: 1.0 / 44100.0 } } - pub const freq : &'static str = + pub const freq: &'static str = "BOsc freq\nBase frequency of the oscillator.\n\nRange: (-1..1)\n"; - pub const det : &'static str = - "BOsc det\nDetune the oscillator in semitones and cents. \ + pub const det: &'static str = "BOsc det\nDetune the oscillator in semitones and cents. \ the input of this value is rounded to semitones on coarse input. \ Fine input lets you detune in cents (rounded). \ A signal sent to this port is not rounded.\n\ Note: The signal input allows detune +-10 octaves.\ \nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n"; - pub const pw : &'static str = - "BOsc pw\n\nRange: (0..1)\n"; - pub const wtype : &'static str = - "BOsc wtype\nWaveform type\nAvailable waveforms:\n\ + pub const pw: &'static str = "BOsc pw\n\nRange: (0..1)\n"; + pub const wtype: &'static str = "BOsc wtype\nWaveform type\nAvailable waveforms:\n\ Sin - Sine Waveform\n\ Tri - Triangle Waveform\n\ Saw - Sawtooth Waveform\n\ Pulse - Pulse Waveform with configurable pulse width"; - pub const sig : &'static str = - "BOsc sig\nOscillator output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Basic Oscillator + pub const sig: &'static str = "BOsc sig\nOscillator output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Basic Oscillator A very basic oscillator with a sine, triangle, pulse and sawtooth waveform. "#; - pub const HELP : &'static str = -r#"BOsc - Basic Waveform Oscillator + pub const HELP: &'static str = r#"BOsc - Basic Waveform Oscillator A very basic oscillator with a sine, triangle, pulse and sawtooth waveform. The pulse width `pw` parameter only has an effect for the `Pulse` waveform. "#; - } impl DspNode for BOsc { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.israte = 1.0 / srate; @@ -85,62 +77,54 @@ impl DspNode for BOsc { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, denorm_offs, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, denorm_offs, inp, out}; let freq = inp::BOsc::freq(inputs); - let det = inp::BOsc::det(inputs); - let pw = inp::BOsc::pw(inputs); - let out = out::BOsc::sig(outputs); + let det = inp::BOsc::det(inputs); + let pw = inp::BOsc::pw(inputs); + let out = out::BOsc::sig(outputs); let wtype = at::BOsc::wtype(atoms); let israte = self.israte; match wtype.i() { - 0 => { // sin + 0 => { + // sin for frame in 0..ctx.nframes() { - let freq = - denorm_offs::BOsc::freq( - freq, det.read(frame), frame); - out.write( - frame, - self.osc.next_sin(freq, israte)); + let freq = denorm_offs::BOsc::freq(freq, det.read(frame), frame); + out.write(frame, self.osc.next_sin(freq, israte)); } - }, - 1 => { // tri + } + 1 => { + // tri for frame in 0..ctx.nframes() { - let freq = - denorm_offs::BOsc::freq( - freq, det.read(frame), frame); - out.write( - frame, - self.osc.next_tri(freq, israte)); + let freq = denorm_offs::BOsc::freq(freq, det.read(frame), frame); + out.write(frame, self.osc.next_tri(freq, israte)); } - }, - 2 => { // saw + } + 2 => { + // saw for frame in 0..ctx.nframes() { - let freq = - denorm_offs::BOsc::freq( - freq, det.read(frame), frame); - out.write( - frame, - self.osc.next_saw(freq, israte)); + let freq = denorm_offs::BOsc::freq(freq, det.read(frame), frame); + out.write(frame, self.osc.next_saw(freq, israte)); } - }, - 3 | _ => { // pulse + } + 3 | _ => { + // pulse for frame in 0..ctx.nframes() { - let freq = - denorm_offs::BOsc::freq( - freq, det.read(frame), frame); + let freq = denorm_offs::BOsc::freq(freq, det.read(frame), frame); let pw = denorm::BOsc::pw(pw, frame); - out.write( - frame, - self.osc.next_pulse_no_dc(freq, israte, pw)); + out.write(frame, self.osc.next_pulse_no_dc(freq, israte, pw)); } } } @@ -154,11 +138,11 @@ impl DspNode for BOsc { Some(Box::new(move |gd: &dyn GraphAtomData, init: bool, _x: f32, _xn: f32| -> f32 { let wtype = NodeId::BOsc(0).inp_param("wtype").unwrap().inp(); - let pw = NodeId::BOsc(0).inp_param("pw").unwrap().inp(); + let pw = NodeId::BOsc(0).inp_param("pw").unwrap().inp(); // let det = NodeId::BOsc(0).inp_param("det").unwrap().inp(); let wtype = gd.get(wtype as u32).map(|a| a.i()).unwrap_or(0); - let pw = gd.get_denorm(pw as u32); + let pw = gd.get_denorm(pw as u32); // let det = gd.get_norm(det as u32); // the detune scaling with lerp is wrong... @@ -172,18 +156,18 @@ impl DspNode for BOsc { // we need to initialize the leaky integrator // in the triangle wave form, or it would look // a bit weird. - for _ in 0..256 { osc.next_tri(freq, israte); } + for _ in 0..256 { + osc.next_tri(freq, israte); + } } } - let s = - match wtype { - 0 => (osc.next_sin(freq, israte) + 1.0) * 0.5, - 1 => (osc.next_tri(freq, israte) + 1.0) * 0.5, - 2 => (osc.next_saw(freq, israte) + 1.0) * 0.5, - 3 | _ => (osc.next_pulse_no_dc(freq, israte, pw) - + 1.0) * 0.5, - }; + let s = match wtype { + 0 => (osc.next_sin(freq, israte) + 1.0) * 0.5, + 1 => (osc.next_tri(freq, israte) + 1.0) * 0.5, + 2 => (osc.next_saw(freq, israte) + 1.0) * 0.5, + 3 | _ => (osc.next_pulse_no_dc(freq, israte, pw) + 1.0) * 0.5, + }; s * 0.9 + 0.05 })) diff --git a/src/dsp/node_bowstri.rs b/src/dsp/node_bowstri.rs index ed272b3..a806118 100644 --- a/src/dsp/node_bowstri.rs +++ b/src/dsp/node_bowstri.rs @@ -2,13 +2,12 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, denorm_offs, denorm, - out, inp, DspNode, LedPhaseVals, NodeContext -}; -use crate::dsp::helpers::{FixedOnePole, DelayBuffer}; use crate::dsp::biquad::Biquad; +use crate::dsp::helpers::{DelayBuffer, FixedOnePole}; +use crate::dsp::{ + denorm, denorm_offs, inp, out, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, +}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; // Bowed String instrument oscillator // Bowed string model, a la Smith (1986), @@ -28,22 +27,22 @@ use crate::dsp::biquad::Biquad; // Contributions by Esteban Maestre, 2011. #[derive(Debug, Clone)] struct BowedString { - srate: f32, - nut_to_bow: DelayBuffer, - bow_to_bridge: DelayBuffer, - string_filter: FixedOnePole, - body_filters: [Biquad; 6], + srate: f32, + nut_to_bow: DelayBuffer, + bow_to_bridge: DelayBuffer, + string_filter: FixedOnePole, + body_filters: [Biquad; 6], } impl BowedString { pub fn new() -> Self { let mut s = Self { srate: 44100.0, - nut_to_bow: DelayBuffer::new(), + nut_to_bow: DelayBuffer::new(), bow_to_bridge: DelayBuffer::new(), string_filter: FixedOnePole::new(0.0, 0.0), body_filters: [ - Biquad::new_with(1.0, 1.5667, 0.3133, -0.5509, -0.3925), + Biquad::new_with(1.0, 1.5667, 0.3133, -0.5509, -0.3925), Biquad::new_with(1.0, -1.9537, 0.9542, -1.6357, 0.8697), Biquad::new_with(1.0, -1.6683, 0.8852, -1.7674, 0.8735), Biquad::new_with(1.0, -1.8585, 0.9653, -1.8498, 0.9516), @@ -56,11 +55,8 @@ impl BowedString { } pub fn set_sample_rate(&mut self, sample_rate: f32) { - self.srate = sample_rate; - self.string_filter = - FixedOnePole::new( - 0.75 - (0.2 * (22050.0 / sample_rate)), - 0.9); + self.srate = sample_rate; + self.string_filter = FixedOnePole::new(0.75 - (0.2 * (22050.0 / sample_rate)), 0.9); } pub fn reset(&mut self) { @@ -74,28 +70,21 @@ impl BowedString { } #[inline] - pub fn process(&mut self, - freq: f32, bow_velocity: f32, bow_force: f32, pos: f32 - ) -> f32 - { - let total_l = self.srate / freq.max(20.0); - let total_l = if total_l <= 0.0 { 0.3 } else { total_l }; + pub fn process(&mut self, freq: f32, bow_velocity: f32, bow_force: f32, pos: f32) -> f32 { + let total_l = self.srate / freq.max(20.0); + let total_l = if total_l <= 0.0 { 0.3 } else { total_l }; let bow_position = ((pos + 1.0) / 2.0).clamp(0.01, 0.99); - let bow_nut_l = total_l * (1.0 - bow_position); + let bow_nut_l = total_l * (1.0 - bow_position); let bow_bridge_l = total_l * bow_position; - let nut = -self.nut_to_bow.cubic_interpolate_at_s(bow_nut_l); - let brid = self.bow_to_bridge.cubic_interpolate_at_s(bow_bridge_l); + let nut = -self.nut_to_bow.cubic_interpolate_at_s(bow_nut_l); + let brid = self.bow_to_bridge.cubic_interpolate_at_s(bow_bridge_l); let bridge = -self.string_filter.process(brid); let dv = 0.25 * bow_velocity - (nut + bridge); - let phat = - ((dv + 0.001) * bow_force + 0.75) - .abs() - .powf(-4.0) - .clamp(0.01, 0.98); + let phat = ((dv + 0.001) * bow_force + 0.75).abs().powf(-4.0).clamp(0.01, 0.98); let phat = phat * dv; self.bow_to_bridge.feed(nut + phat); @@ -118,36 +107,27 @@ pub struct BowStri { impl BowStri { pub fn new(_nid: &NodeId) -> Self { - Self { - bstr: Box::new(BowedString::new()), - } + Self { bstr: Box::new(BowedString::new()) } } - pub const freq : &'static str = + pub const freq: &'static str = "BowStri freq\nFrequency of the bowed string oscillator.\n\nRange: (-1..1)\n"; - pub const det : &'static str = - "BowStri det\nDetune the oscillator in semitones and cents. \ + pub const det: &'static str = "BowStri det\nDetune the oscillator in semitones and cents. \ the input of this value is rounded to semitones on coarse input. \ Fine input lets you detune in cents (rounded). \ A signal sent to this port is not rounded.\n\ Note: The signal input allows detune +-10 octaves.\ \nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n"; - pub const vel : &'static str = - "BowStri vel\n\n\nRange: (-1..1)\n"; - pub const force : &'static str = - "BowStri force\n\n\nRange: (-1..1)\n"; - pub const pos : &'static str = - "BowStri pos\n\n\nRange: (-1..1)\n"; - pub const sig : &'static str = - "BowStri sig\nOscillator signal output.\n\nRange: (-1..1)\n"; + pub const vel: &'static str = "BowStri vel\n\n\nRange: (-1..1)\n"; + pub const force: &'static str = "BowStri force\n\n\nRange: (-1..1)\n"; + pub const pos: &'static str = "BowStri pos\n\n\nRange: (-1..1)\n"; + pub const sig: &'static str = "BowStri sig\nOscillator signal output.\n\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Bowed String Oscillator + pub const DESC: &'static str = r#"Bowed String Oscillator This is an oscillator that simulates a bowed string. "#; - pub const HELP : &'static str = -r#"BowStri - A Bowed String Simulation Oscillator + pub const HELP: &'static str = r#"BowStri - A Bowed String Simulation Oscillator This is an oscillator that simulates a bowed string. It's a bit wonky, so play around with the parameters and see what @@ -160,7 +140,9 @@ which is basically the bow's velocity. } impl DspNode for BowStri { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.bstr.set_sample_rate(srate); @@ -172,17 +154,21 @@ impl DspNode for BowStri { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - let o = out::BowStri::sig(outputs); - let freq = inp::BowStri::freq(inputs); - let det = inp::BowStri::det(inputs); - let vel = inp::BowStri::vel(inputs); + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + let o = out::BowStri::sig(outputs); + let freq = inp::BowStri::freq(inputs); + let det = inp::BowStri::det(inputs); + let vel = inp::BowStri::vel(inputs); let force = inp::BowStri::force(inputs); - let pos = inp::BowStri::pos(inputs); + let pos = inp::BowStri::pos(inputs); let mut last_val = 0.0; for frame in 0..ctx.nframes() { @@ -191,22 +177,16 @@ impl DspNode for BowStri { // at 440 Hz. // Calculate some tune correction here based on the // normalized value (-0.2 is 110Hz, 0.0 is 440Hz, ...): - let tune_correction = - (freq.read(frame).clamp(-0.2, 1.0) + 0.2) - * 10.0 * 0.0012; + let tune_correction = (freq.read(frame).clamp(-0.2, 1.0) + 0.2) * 10.0 * 0.0012; - let freq = - denorm_offs::BowStri::freq( - freq, - tune_correction + det.read(frame), - frame); + let freq = denorm_offs::BowStri::freq(freq, tune_correction + det.read(frame), frame); - let out = - self.bstr.process( - freq, - denorm::BowStri::vel(vel, frame), - denorm::BowStri::force(force, frame), - denorm::BowStri::pos(pos, frame)); + let out = self.bstr.process( + freq, + denorm::BowStri::vel(vel, frame), + denorm::BowStri::force(force, frame), + denorm::BowStri::pos(pos, frame), + ); last_val = out; o.write(frame, out); } diff --git a/src/dsp/node_comb.rs b/src/dsp/node_comb.rs index 662a13b..36db6a4 100644 --- a/src/dsp/node_comb.rs +++ b/src/dsp/node_comb.rs @@ -2,21 +2,21 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; use crate::dsp::helpers; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_comb_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "FedBack", - 1 => "FedForw", - _ => "?", +macro_rules! fa_comb_mode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "FedBack", + 1 => "FedForw", + _ => "?", }; - write!($formatter, "{}", s) -} } } - + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] @@ -26,32 +26,24 @@ pub struct Comb { impl Comb { pub fn new(_nid: &NodeId) -> Self { - Self { - comb: Box::new(helpers::Comb::new()), - } + Self { comb: Box::new(helpers::Comb::new()) } } - pub const inp : &'static str = - "Comb inp\nThe signal input for the comb filter.\nRange: (-1..1)"; - pub const g : &'static str = + pub const inp: &'static str = "Comb inp\nThe signal input for the comb filter.\nRange: (-1..1)"; + pub const g: &'static str = "Comb g\nThe internal factor for the comb filter. Be careful with high 'g' \ values (> 0.75) in feedback mode, you will probably have to attenuate \ the output a bit yourself.\nRange: (-1..1)"; - pub const time : &'static str = - "Comb time\nThe comb delay time.\nRange: (0..1)"; - pub const sig : &'static str = - "Comb sig\nThe output of comb filter.\nRange: (-1..1)"; - pub const mode : &'static str = - "Comb mode\nThe mode of the comb filter, whether it's a \ + pub const time: &'static str = "Comb time\nThe comb delay time.\nRange: (0..1)"; + pub const sig: &'static str = "Comb sig\nThe output of comb filter.\nRange: (-1..1)"; + pub const mode: &'static str = "Comb mode\nThe mode of the comb filter, whether it's a \ feedback or feedforward comb filter."; - pub const DESC : &'static str = -r#"Comb Filter + pub const DESC: &'static str = r#"Comb Filter A very simple comb filter. It has interesting filtering effects and can be used to build custom reverbs. "#; -pub const HELP : &'static str = -r#"Comb - A Simple Comb Filter + pub const HELP: &'static str = r#"Comb - A Simple Comb Filter This is a comb filter that can be used for filtering as well as for building reverbs or anything you might @@ -67,7 +59,9 @@ see the documentation of the 'Comb' node! } impl DspNode for Comb { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.comb.set_sample_rate(srate); @@ -79,17 +73,21 @@ impl DspNode for Comb { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let inp = inp::Comb::inp(inputs); + let inp = inp::Comb::inp(inputs); let time = inp::Comb::time(inputs); - let g = inp::Comb::g(inputs); - let out = out::Comb::sig(outputs); + let g = inp::Comb::g(inputs); + let out = out::Comb::sig(outputs); let mode = at::Comb::mode(atoms); let c = &mut *self.comb; @@ -98,21 +96,23 @@ impl DspNode for Comb { for frame in 0..ctx.nframes() { let v = inp.read(frame); - out.write(frame, - c.next_feedback( - denorm::Comb::time(time, frame), - denorm::Comb::g(g, frame), - v)); + out.write( + frame, + c.next_feedback(denorm::Comb::time(time, frame), denorm::Comb::g(g, frame), v), + ); } } else { for frame in 0..ctx.nframes() { let v = inp.read(frame); - out.write(frame, + out.write( + frame, c.next_feedforward( denorm::Comb::time(time, frame), denorm::Comb::g(g, frame), - v)); + v, + ), + ); } } diff --git a/src/dsp/node_cqnt.rs b/src/dsp/node_cqnt.rs index dc8b12a..8d607a4 100644 --- a/src/dsp/node_cqnt.rs +++ b/src/dsp/node_cqnt.rs @@ -2,82 +2,78 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::helpers::{ChangeTrig, CtrlPitchQuantizer}; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::helpers::{CtrlPitchQuantizer, ChangeTrig}; #[macro_export] -macro_rules! fa_cqnt { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - write!($formatter, "?") -} } } +macro_rules! fa_cqnt { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + write!($formatter, "?") + }}; +} #[macro_export] -macro_rules! fa_cqnt_omin { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "-0", - 1 => "-1", - 2 => "-2", - 3 => "-3", - 4 => "-4", - _ => "?", +macro_rules! fa_cqnt_omin { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "-0", + 1 => "-1", + 2 => "-2", + 3 => "-3", + 4 => "-4", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[macro_export] -macro_rules! fa_cqnt_omax { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "+0", - 1 => "+1", - 2 => "+2", - 3 => "+3", - 4 => "+4", - _ => "?", +macro_rules! fa_cqnt_omax { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "+0", + 1 => "+1", + 2 => "+2", + 3 => "+3", + 4 => "+4", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A control signal to pitch quantizer/converter #[derive(Debug, Clone)] pub struct CQnt { - quant: Box, + quant: Box, change_trig: ChangeTrig, } impl CQnt { pub fn new(_nid: &NodeId) -> Self { - Self { - quant: Box::new(CtrlPitchQuantizer::new()), - change_trig: ChangeTrig::new(), - } + Self { quant: Box::new(CtrlPitchQuantizer::new()), change_trig: ChangeTrig::new() } } - pub const inp : &'static str = + pub const inp: &'static str = "CQnt inp\nThe unipolar input signal that is to be mapped to the \ selected pitch range.\nRange: (0..1)"; - pub const oct : &'static str = - "CQnt oct\nThe octave offset from A4.\nRange: (-1..1)"; - pub const omin : &'static str = + pub const oct: &'static str = "CQnt oct\nThe octave offset from A4.\nRange: (-1..1)"; + pub const omin: &'static str = "CQnt omin\nThe minimum octave of the range. If 0 it will be 'oct'.\nRange: (-1..1)"; - pub const omax : &'static str = + pub const omax: &'static str = "CQnt omax\nThe maximum octave of the range. If 0 it will be 'oct'.\nRange: (-1..1)"; - pub const sig : &'static str = - "CQnt sig\nThe output pitch signal.\nRange: (-1..1)"; - pub const t : &'static str = - "CQnt t\nEverytime the quantizer snaps to a new pitch, it will \ + pub const sig: &'static str = "CQnt sig\nThe output pitch signal.\nRange: (-1..1)"; + pub const t: &'static str = "CQnt t\nEverytime the quantizer snaps to a new pitch, it will \ emit a short trigger on this signal output. This is useful \ to trigger for example an envelope."; - pub const keys : &'static str = + pub const keys: &'static str = "CQnt keys\nHere you can select the individual notes of the range. \ If no note is selected, it's the same as if all notes were selected."; - pub const DESC : &'static str = -r#"Ctrl Pitch Quantizer + pub const DESC: &'static str = r#"Ctrl Pitch Quantizer This special quantizer maps the unipolar 0..1 control signal input range on 'inp' evenly to the selected keys and octaves. "#; - pub const HELP : &'static str = -r#"CQnt - A control signal to pitch quantizer + pub const HELP: &'static str = r#"CQnt - A control signal to pitch quantizer This is a specialized control signal quantizer to generate a pitch/frequency from a signal within the 0..1 range. It does not quantize a typical -1..1 @@ -90,7 +86,9 @@ if you sweep accross the input signal range. } impl DspNode for CQnt { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.change_trig.set_sample_rate(srate); @@ -100,20 +98,23 @@ impl DspNode for CQnt { self.change_trig.reset(); } - #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{at, out_buf, inp, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out_buf}; let inp = inp::CQnt::inp(inputs); let oct = inp::CQnt::oct(inputs); let mut out = out_buf::CQnt::sig(outputs); - let mut t = out_buf::CQnt::t(outputs); + let mut t = out_buf::CQnt::t(outputs); let keys = at::CQnt::keys(atoms); let omin = at::CQnt::omin(atoms); let omax = at::CQnt::omax(atoms); @@ -121,9 +122,7 @@ impl DspNode for CQnt { self.quant.update_keys(keys.i(), omin.i(), omax.i()); for frame in 0..ctx.nframes() { - let pitch = - self.quant.signal_to_pitch( - denorm::CQnt::inp(inp, frame)); + let pitch = self.quant.signal_to_pitch(denorm::CQnt::inp(inp, frame)); t.write(frame, self.change_trig.next(pitch)); out.write(frame, pitch + denorm::CQnt::oct(oct, frame)); diff --git a/src/dsp/node_delay.rs b/src/dsp/node_delay.rs index b887707..cd8c821 100644 --- a/src/dsp/node_delay.rs +++ b/src/dsp/node_delay.rs @@ -2,66 +2,58 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::helpers::{crossfade, DelayBuffer, TriggerSampleClock}; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::helpers::{DelayBuffer, crossfade, TriggerSampleClock}; #[macro_export] -macro_rules! fa_delay_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Time", - 1 => "Sync", - _ => "?", - }; +macro_rules! fa_delay_mode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Time", + 1 => "Sync", + _ => "?", + }; write!($formatter, "{}", s) -} } } + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct Delay { - buffer: Box>, - clock: TriggerSampleClock, + buffer: Box>, + clock: TriggerSampleClock, } impl Delay { pub fn new(_nid: &NodeId) -> Self { - Self { - buffer: Box::new(DelayBuffer::new()), - clock: TriggerSampleClock::new(), - } + Self { buffer: Box::new(DelayBuffer::new()), clock: TriggerSampleClock::new() } } - pub const inp : &'static str = - "Delay inp\nThe signal input for the delay. You can mix in this \ + pub const inp: &'static str = "Delay inp\nThe signal input for the delay. You can mix in this \ input to the output with the 'mix' parameter.\nRange: (-1..1)"; - pub const trig : &'static str = + pub const trig: &'static str = "Delay trig\nIf you set 'mode' to 'Sync', the delay time will be \ synchronized to the trigger signals received on this input.\nRange: (-1..1)"; - pub const time : &'static str = + pub const time: &'static str = "Delay time\nThe delay time. It can be freely modulated to your \ likings.\nRange: (0..1)"; - pub const fb : &'static str = + pub const fb: &'static str = "Delay fb\nThe feedback amount of the delay output to it's input. \ \nRange: (-1..1)"; - pub const mix : &'static str = - "Delay mix\nThe dry/wet mix of the delay.\nRange: (0..1)"; - pub const mode : &'static str = - "Delay mode\nAllows different operating modes of the delay. \ + pub const mix: &'static str = "Delay mix\nThe dry/wet mix of the delay.\nRange: (0..1)"; + pub const mode: &'static str = "Delay mode\nAllows different operating modes of the delay. \ 'Time' is the default, and means that the 'time' input \ specifies the delay time. 'Sync' will synchronize the delay time \ with the trigger signals on the 'trig' input."; - pub const sig : &'static str = - "Delay sig\nThe output of the dry/wet mix.\nRange: (-1..1)"; + pub const sig: &'static str = "Delay sig\nThe output of the dry/wet mix.\nRange: (-1..1)"; - pub const DESC : &'static str = -r#"Simple Delay Line + pub const DESC: &'static str = r#"Simple Delay Line This is a very simple single buffer delay node. It provides an internal feedback and dry/wet mix. "#; -pub const HELP : &'static str = -r#"Delay - A Simple Delay Line + pub const HELP: &'static str = r#"Delay - A Simple Delay Line This node provides a very simple delay line with the bare minimum of parameters. Most importantly a freely modulateable 'time' parameter @@ -77,7 +69,9 @@ For other kinds of delay/feedback please see also the 'FbWr'/'FbRd' nodes. } impl DspNode for Delay { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.buffer.set_sample_rate(srate); @@ -90,50 +84,53 @@ impl DspNode for Delay { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{at, out, inp, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let buffer = &mut *self.buffer; + let buffer = &mut *self.buffer; let mode = at::Delay::mode(atoms); - let inp = inp::Delay::inp(inputs); + let inp = inp::Delay::inp(inputs); let trig = inp::Delay::trig(inputs); let time = inp::Delay::time(inputs); - let fb = inp::Delay::fb(inputs); - let mix = inp::Delay::mix(inputs); - let out = out::Delay::sig(outputs); + let fb = inp::Delay::fb(inputs); + let mix = inp::Delay::mix(inputs); + let out = out::Delay::sig(outputs); if mode.i() == 0 { for frame in 0..ctx.nframes() { let dry = inp.read(frame); - let out_sample = - buffer.cubic_interpolate_at( - denorm::Delay::time(time, frame)); + let out_sample = buffer.cubic_interpolate_at(denorm::Delay::time(time, frame)); buffer.feed(dry + out_sample * denorm::Delay::fb(fb, frame)); - out.write(frame, - crossfade(dry, out_sample, - denorm::Delay::mix(mix, frame).clamp(0.0, 1.0))); + out.write( + frame, + crossfade(dry, out_sample, denorm::Delay::mix(mix, frame).clamp(0.0, 1.0)), + ); } } else { for frame in 0..ctx.nframes() { let dry = inp.read(frame); - let clock_samples = - self.clock.next(denorm::Delay::trig(trig, frame)); + let clock_samples = self.clock.next(denorm::Delay::trig(trig, frame)); let out_sample = buffer.at(clock_samples as usize); buffer.feed(dry + out_sample * denorm::Delay::fb(fb, frame)); - out.write(frame, - crossfade(dry, out_sample, - denorm::Delay::mix(mix, frame).clamp(0.0, 1.0))); + out.write( + frame, + crossfade(dry, out_sample, denorm::Delay::mix(mix, frame).clamp(0.0, 1.0)), + ); } } diff --git a/src/dsp/node_fbwr_fbrd.rs b/src/dsp/node_fbwr_fbrd.rs index 73531af..d5da362 100644 --- a/src/dsp/node_fbwr_fbrd.rs +++ b/src/dsp/node_fbwr_fbrd.rs @@ -2,33 +2,28 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; /// A simple amplifier #[derive(Debug, Clone)] pub struct FbWr { - fb_index: u8, + fb_index: u8, } impl FbWr { pub fn new(nid: &NodeId) -> Self { - Self { - fb_index: nid.instance() as u8, - } + Self { fb_index: nid.instance() as u8 } } - pub const inp : &'static str = - "FbWr inp\nSignal input\nRange: (-1..1)\n"; + pub const inp: &'static str = "FbWr inp\nSignal input\nRange: (-1..1)\n"; - pub const DESC : &'static str = -"Feedback Delay Writer\n\n\ + pub const DESC: &'static str = "Feedback Delay Writer\n\n\ HexoSynth does not allow direct feedback cycles in it's graph.\n\ To make feedback possible anyways the 'FbWr' and 'FbRd' nodes are provided.\n\ This node allows you to write a signal into the corresponsing signal delay buffer.\n\ Use 'FbRd' for using the signal.\n\ The delay is 3.14ms."; - pub const HELP : &'static str = -r#"Feedback Delay Writer + pub const HELP: &'static str = r#"Feedback Delay Writer HexoSynth does not allow direct feedback cycles in it's graph. To make feedback possible anyways the 'FbWr' and 'FbRd' nodes are provided. @@ -46,59 +41,57 @@ is running at. } impl DspNode for FbWr { - fn outputs() -> usize { 0 } + fn outputs() -> usize { + 0 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - _outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{inp}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + _outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::inp; - let inp = inp::FbWr::inp(inputs); + let inp = inp::FbWr::inp(inputs); for frame in 0..ctx.nframes() { - ectx.feedback_delay_buffers[self.fb_index as usize] - .write(inp.read(frame)); + ectx.feedback_delay_buffers[self.fb_index as usize].write(inp.read(frame)); } ctx_vals[0].set(inp.read(ctx.nframes() - 1)); } } - /// A simple amplifier #[derive(Debug, Clone)] pub struct FbRd { - fb_index: u8, + fb_index: u8, } impl FbRd { pub fn new(nid: &NodeId) -> Self { - Self { - fb_index: nid.instance() as u8, - } + Self { fb_index: nid.instance() as u8 } } - pub const atv : &'static str = - "FbRd atv\nAttenuate or invert input.\n\ + pub const atv: &'static str = "FbRd atv\nAttenuate or invert input.\n\ Use this to adjust the feedback amount.\nRange: (-1..1)\n"; - pub const sig : &'static str = - "FbRd sig\nFeedback signal output.\nRange: (-1..1)\n"; + pub const sig: &'static str = "FbRd sig\nFeedback signal output.\nRange: (-1..1)\n"; - pub const DESC : &'static str = -"Feedback Delay Reader\n\n\ + pub const DESC: &'static str = "Feedback Delay Reader\n\n\ HexoSynth does not allow direct feedback cycles in it's graph.\n\ To make feedback possible anyways the 'FbWr' and 'FbRd' nodes are provided.\n\ This node allows you to tap into the corresponsing 'FbWr' signal delay \ for feedback.\n\ The delay is 3.14ms."; - pub const HELP : &'static str = -r#"Feedback Delay Reader + pub const HELP: &'static str = r#"Feedback Delay Reader HexoSynth does not allow direct feedback cycles in it's graph. To make feedback possible anyways the 'FbWr' and 'FbRd' nodes are provided. @@ -119,28 +112,32 @@ even inverting the signal. } impl DspNode for FbRd { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{denorm, inp, out}; - let atv = inp::FbRd::atv(inputs); - let sig = out::FbRd::sig(outputs); + let atv = inp::FbRd::atv(inputs); + let sig = out::FbRd::sig(outputs); let mut last_val = 0.0; for frame in 0..ctx.nframes() { - last_val = - ectx.feedback_delay_buffers[self.fb_index as usize] - .read(); + last_val = ectx.feedback_delay_buffers[self.fb_index as usize].read(); last_val *= denorm::FbRd::atv(atv, frame); sig.write(frame, last_val); } diff --git a/src/dsp/node_map.rs b/src/dsp/node_map.rs index 19e8dcc..a6bf6ba 100644 --- a/src/dsp/node_map.rs +++ b/src/dsp/node_map.rs @@ -2,63 +2,53 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; #[macro_export] -macro_rules! fa_map_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Off", - 1 => "Clip", - _ => "?", +macro_rules! fa_map_clip { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Off", + 1 => "Clip", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] -pub struct Map { -} +pub struct Map {} impl Map { pub fn new(_nid: &NodeId) -> Self { - Self { - } + Self {} } - pub const inp : &'static str = - "Map inp\nSignal input\nRange: (-1..1)\n"; + pub const inp: &'static str = "Map inp\nSignal input\nRange: (-1..1)\n"; pub const atv : &'static str = "Map atv\nInput signal attenuverter, to attenuate or invert the input signal.\nRange: (0..1)\n"; - pub const offs : &'static str = + pub const offs: &'static str = "Map offs\nInput signal offset after 'atv' has been applied.\nRange: (-1..1)\n"; - pub const imin : &'static str = - "Map imin\nMinimum of the input signal range, \ + pub const imin: &'static str = "Map imin\nMinimum of the input signal range, \ it's mapped to the 'min' output signal range.\nRange: (0..1)\n"; - pub const imax : &'static str = - "Map imax\nMaximum of the input signal range, \ + pub const imax: &'static str = "Map imax\nMaximum of the input signal range, \ it's mapped to the 'max' output signal range.\nRange: (0..1)\n"; - pub const min : &'static str = - "Map min\nMinimum of the output signal range.\nRange: (0..1)\n"; - pub const max : &'static str = - "Map max\nMaximum of the output signal range.\nRange: (0..1)\n"; - pub const clip : &'static str = - "Map clip\nThe 'clip' mode allows you to limit the output \ + pub const min: &'static str = "Map min\nMinimum of the output signal range.\nRange: (0..1)\n"; + pub const max: &'static str = "Map max\nMaximum of the output signal range.\nRange: (0..1)\n"; + pub const clip: &'static str = "Map clip\nThe 'clip' mode allows you to limit the output \ exactly to the 'min'/'max' range. If this is off, the output \ may be outside the output signal range if the input signal is \ outside the input signal range."; - pub const sig : &'static str = - "Map sig\nMapped signal output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Range Mapper + pub const sig: &'static str = "Map sig\nMapped signal output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Range Mapper This node allows to map an input signal range to a precise output signal range. It's mostly useful to map control signals to modulate inputs. See also the 'SMap' node, which is a simplified version of this node. "#; - pub const HELP : &'static str = -r#"Map - Range Mapper + pub const HELP: &'static str = r#"Map - Range Mapper This node allows to map an input signal range to a precise output signal range. It's main use is for precise control of an input of another node. @@ -79,32 +69,37 @@ This can also be used to invert the signal. For a more simplified version of this node see also 'SMap'. "#; - } impl DspNode for Map { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, inp, out}; - let inp = inp::Map::inp(inputs); - let atv = inp::Map::atv(inputs); + let inp = inp::Map::inp(inputs); + let atv = inp::Map::atv(inputs); let offs = inp::Map::offs(inputs); let imin = inp::Map::imin(inputs); let imax = inp::Map::imax(inputs); - let min = inp::Map::min(inputs); - let max = inp::Map::max(inputs); - let out = out::Map::sig(outputs); + let min = inp::Map::min(inputs); + let max = inp::Map::max(inputs); + let out = out::Map::sig(outputs); let clip = at::Map::clip(atoms); @@ -112,21 +107,18 @@ impl DspNode for Map { if clip.i() == 0 { for frame in 0..ctx.nframes() { - let s = - (inp.read(frame) * atv.read(frame)) - + offs.read(frame); + let s = (inp.read(frame) * atv.read(frame)) + offs.read(frame); let imin = imin.read(frame); let imax = imax.read(frame); - let min = min.read(frame); - let max = max.read(frame); + let min = min.read(frame); + let max = max.read(frame); - let x = - if (imax - imin).abs() < std::f32::EPSILON { - 1.0 - } else { - ((s - imin) / (imax - imin)).abs() - }; + let x = if (imax - imin).abs() < std::f32::EPSILON { + 1.0 + } else { + ((s - imin) / (imax - imin)).abs() + }; last_val = x; let s = min + (max - min) * x; @@ -134,28 +126,22 @@ impl DspNode for Map { } } else { for frame in 0..ctx.nframes() { - let s = - (inp.read(frame) * atv.read(frame)) - + offs.read(frame); + let s = (inp.read(frame) * atv.read(frame)) + offs.read(frame); let imin = imin.read(frame); let imax = imax.read(frame); - let min = min.read(frame); - let max = max.read(frame); + let min = min.read(frame); + let max = max.read(frame); - let x = - if (imax - imin).abs() < std::f32::EPSILON { - 1.0 - } else { - ((s - imin) / (imax - imin)).abs() - }; + let x = if (imax - imin).abs() < std::f32::EPSILON { + 1.0 + } else { + ((s - imin) / (imax - imin)).abs() + }; last_val = x; let s = min + (max - min) * x; - out.write( - frame, - if min < max { s.clamp(min, max) } - else { s.clamp(max, min) }); + out.write(frame, if min < max { s.clamp(min, max) } else { s.clamp(max, min) }); } } diff --git a/src/dsp/node_mix3.rs b/src/dsp/node_mix3.rs index 9be766f..001131e 100644 --- a/src/dsp/node_mix3.rs +++ b/src/dsp/node_mix3.rs @@ -2,43 +2,31 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; /// A 3 channel signal mixer #[derive(Debug, Clone)] -pub struct Mix3 { -} +pub struct Mix3 {} impl Mix3 { pub fn new(_nid: &NodeId) -> Self { - Self { - } + Self {} } - pub const ch1 : &'static str = - "Mix3 ch1\nChannel 1 Signal input\nRange: (-1..1)\n"; - pub const ch2 : &'static str = - "Mix3 ch2\nChannel 2 Signal input\nRange: (-1..1)\n"; - pub const ch3 : &'static str = - "Mix3 ch3\nChannel 3 Signal input\nRange: (-1..1)\n"; - pub const gain1 : &'static str = - "Mix3 gain1\nChannel 1 gain\nRange: (0..1)"; - pub const gain2 : &'static str = - "Mix3 gain2\nChannel 2 gain\nRange: (0..1)"; - pub const gain3 : &'static str = - "Mix3 gain3\nChannel 3 gain\nRange: (0..1)"; - pub const ogain : &'static str = - "Mix3 ogain\nOutput gain of the sum\nRange: (0..1)"; - pub const sig : &'static str = - "Mix3 sig\nMixed signal output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"3 Ch. Signal Mixer + pub const ch1: &'static str = "Mix3 ch1\nChannel 1 Signal input\nRange: (-1..1)\n"; + pub const ch2: &'static str = "Mix3 ch2\nChannel 2 Signal input\nRange: (-1..1)\n"; + pub const ch3: &'static str = "Mix3 ch3\nChannel 3 Signal input\nRange: (-1..1)\n"; + pub const gain1: &'static str = "Mix3 gain1\nChannel 1 gain\nRange: (0..1)"; + pub const gain2: &'static str = "Mix3 gain2\nChannel 2 gain\nRange: (0..1)"; + pub const gain3: &'static str = "Mix3 gain3\nChannel 3 gain\nRange: (0..1)"; + pub const ogain: &'static str = "Mix3 ogain\nOutput gain of the sum\nRange: (0..1)"; + pub const sig: &'static str = "Mix3 sig\nMixed signal output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"3 Ch. Signal Mixer A very simple 3 channel signal mixer. You can mix anything, from audio signals to control signals. "#; - pub const HELP : &'static str = -r#"Mix3 - 3 Channel Signal Mixer + pub const HELP: &'static str = r#"Mix3 - 3 Channel Signal Mixer Just a small 3 channel mixer to create a sum of multiple signals. You can mix anything, from audio signals to control signals. @@ -46,42 +34,45 @@ You can mix anything, from audio signals to control signals. There is even a convenient output gain knob, to turn down the output. "#; - } impl DspNode for Mix3 { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{denorm, inp, out}; let inp1 = inp::Mix3::ch1(inputs); let inp2 = inp::Mix3::ch2(inputs); let inp3 = inp::Mix3::ch3(inputs); - let g1 = inp::Mix3::gain1(inputs); - let g2 = inp::Mix3::gain2(inputs); - let g3 = inp::Mix3::gain3(inputs); - let og = inp::Mix3::ogain(inputs); - let out = out::Mix3::sig(outputs); + let g1 = inp::Mix3::gain1(inputs); + let g2 = inp::Mix3::gain2(inputs); + let g3 = inp::Mix3::gain3(inputs); + let og = inp::Mix3::ogain(inputs); + let out = out::Mix3::sig(outputs); for frame in 0..ctx.nframes() { - let sum = - inp1.read(frame) * denorm::Mix3::gain1(g1, frame) - + inp2.read(frame) * denorm::Mix3::gain2(g2, frame) - + inp3.read(frame) * denorm::Mix3::gain3(g3, frame); + let sum = inp1.read(frame) * denorm::Mix3::gain1(g1, frame) + + inp2.read(frame) * denorm::Mix3::gain2(g2, frame) + + inp3.read(frame) * denorm::Mix3::gain3(g3, frame); out.write(frame, sum * denorm::Mix3::ogain(og, frame)); } - ctx_vals[0].set( - out.read(ctx.nframes() - 1)); + ctx_vals[0].set(out.read(ctx.nframes() - 1)); } } diff --git a/src/dsp/node_mux9.rs b/src/dsp/node_mux9.rs index 021a59f..c637f64 100644 --- a/src/dsp/node_mux9.rs +++ b/src/dsp/node_mux9.rs @@ -2,100 +2,90 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::helpers::Trigger; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::helpers::{Trigger}; #[macro_export] -macro_rules! fa_mux9_in_cnt { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "1", - 1 => "2", - 2 => "3", - 3 => "4", - 4 => "5", - 5 => "6", - 6 => "7", - 7 => "8", - 8 => "9", - _ => "?", +macro_rules! fa_mux9_in_cnt { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "1", + 1 => "2", + 2 => "3", + 3 => "4", + 4 => "5", + 5 => "6", + 6 => "7", + 7 => "8", + 8 => "9", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A 9 channel signal multiplexer #[derive(Debug, Clone)] pub struct Mux9 { - trig_rst: Trigger, - trig_up: Trigger, - trig_down: Trigger, - idx: u8, + trig_rst: Trigger, + trig_up: Trigger, + trig_down: Trigger, + idx: u8, } impl Mux9 { pub fn new(_nid: &NodeId) -> Self { Self { - trig_rst: Trigger::new(), - trig_up: Trigger::new(), + trig_rst: Trigger::new(), + trig_up: Trigger::new(), trig_down: Trigger::new(), - idx: 0, + idx: 0, } } - pub const slct : &'static str = + pub const slct: &'static str = "Mux9 slct\nSelects the input that is routed to the output 'sig'.\ But only if this input is actually connected. If there is no \ connection, the 't_rst', 't_up' and 't_down' inputs are used to \ control the current routing. The maximum routed input is determined \ by the 'in_cnt' setting.\nRange: (0..1)"; - pub const t_rst : &'static str = + pub const t_rst: &'static str = "Mux9 t_rst\nResets the internal routing to the first input 'in_1'.\ Keep in mind: This input is only used if 'slct' is not connected.\ \nRange: (-1..1)\n"; - pub const t_up : &'static str = + pub const t_up: &'static str = "Mux9 t_up\nIncreases the internal routing to the next input port.\ If the last input (depending on the 'in_cnt' setting) was selected\ if will wrap around to 'in_1'.\ Keep in mind: This input is only used if 'slct' is not connected.\ \nRange: (-1..1)\n"; - pub const t_down : &'static str = + pub const t_down: &'static str = "Mux9 t_down\nDecreases the internal routing to the previous input \ port (eg. 'in_3' => 'in_2'). If 'in_1' as selected, then it will \ wrap around to the highest possible input port (depending on the \ 'in_cnt' setting).\ Keep in mind: This input is only used if 'slct' is not connected.\ \nRange: (-1..1)\n"; - pub const in_1 : &'static str = - "Mux9 in_1\nInput port 1.\nRange: (-1..1)\n"; - pub const in_2 : &'static str = - "Mux9 in_2\nInput port 2.\nRange: (-1..1)\n"; - pub const in_3 : &'static str = - "Mux9 in_3\nInput port 3.\nRange: (-1..1)\n"; - pub const in_4 : &'static str = - "Mux9 in_4\nInput port 4.\nRange: (-1..1)\n"; - pub const in_5 : &'static str = - "Mux9 in_5\nInput port 5.\nRange: (-1..1)\n"; - pub const in_6 : &'static str = - "Mux9 in_6\nInput port 6.\nRange: (-1..1)\n"; - pub const in_7 : &'static str = - "Mux9 in_7\nInput port 7.\nRange: (-1..1)\n"; - pub const in_8 : &'static str = - "Mux9 in_8\nInput port 8.\nRange: (-1..1)\n"; - pub const in_9 : &'static str = - "Mux9 in_9\nInput port 9.\nRange: (-1..1)\n"; - pub const in_cnt : &'static str = + pub const in_1: &'static str = "Mux9 in_1\nInput port 1.\nRange: (-1..1)\n"; + pub const in_2: &'static str = "Mux9 in_2\nInput port 2.\nRange: (-1..1)\n"; + pub const in_3: &'static str = "Mux9 in_3\nInput port 3.\nRange: (-1..1)\n"; + pub const in_4: &'static str = "Mux9 in_4\nInput port 4.\nRange: (-1..1)\n"; + pub const in_5: &'static str = "Mux9 in_5\nInput port 5.\nRange: (-1..1)\n"; + pub const in_6: &'static str = "Mux9 in_6\nInput port 6.\nRange: (-1..1)\n"; + pub const in_7: &'static str = "Mux9 in_7\nInput port 7.\nRange: (-1..1)\n"; + pub const in_8: &'static str = "Mux9 in_8\nInput port 8.\nRange: (-1..1)\n"; + pub const in_9: &'static str = "Mux9 in_9\nInput port 9.\nRange: (-1..1)\n"; + pub const in_cnt: &'static str = "Mux9 in_cnt\nThe number of inputs that are routed to the output. \ This will limit the number of maximally used inputs.\n"; - pub const sig : &'static str = + pub const sig: &'static str = "Mux9 sig\nThe currently selected input port will be presented on \ this output port.\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"9 Ch. Multiplexer + pub const DESC: &'static str = r#"9 Ch. Multiplexer An up to 9 channel multiplexer aka switch or junction. You can route one of the 9 (or fewer) inputs to the output. The opposite of this node is the 'Demux9', which demultiplexes or routes the one input signal to one of the 9 outputs. "#; - pub const HELP : &'static str = -r#"Mux9 - 9 Channel Multiplexer/Switch + pub const HELP: &'static str = r#"Mux9 - 9 Channel Multiplexer/Switch This is an up to 9 channel multiplexer, also known as switch or junction. You can route one of the 9 (or fewer) inputs to the one output. @@ -122,87 +112,94 @@ Tip: or 'ESlew') if less harsh transitions between the input routings is desired. "#; - } impl DspNode for Mux9 { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{at, out, inp, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let in_1 = inp::Mux9::in_1(inputs); - let in_2 = inp::Mux9::in_2(inputs); - let in_3 = inp::Mux9::in_3(inputs); - let in_4 = inp::Mux9::in_4(inputs); - let in_5 = inp::Mux9::in_5(inputs); - let in_6 = inp::Mux9::in_6(inputs); - let in_7 = inp::Mux9::in_7(inputs); - let in_8 = inp::Mux9::in_8(inputs); - let in_9 = inp::Mux9::in_9(inputs); - let slct = inp::Mux9::slct(inputs); - let t_rst = inp::Mux9::t_rst(inputs); - let t_up = inp::Mux9::t_up(inputs); + let in_1 = inp::Mux9::in_1(inputs); + let in_2 = inp::Mux9::in_2(inputs); + let in_3 = inp::Mux9::in_3(inputs); + let in_4 = inp::Mux9::in_4(inputs); + let in_5 = inp::Mux9::in_5(inputs); + let in_6 = inp::Mux9::in_6(inputs); + let in_7 = inp::Mux9::in_7(inputs); + let in_8 = inp::Mux9::in_8(inputs); + let in_9 = inp::Mux9::in_9(inputs); + let slct = inp::Mux9::slct(inputs); + let t_rst = inp::Mux9::t_rst(inputs); + let t_up = inp::Mux9::t_up(inputs); let t_down = inp::Mux9::t_down(inputs); - let out = out::Mux9::sig(outputs); + let out = out::Mux9::sig(outputs); - let max : u8 = at::Mux9::in_cnt(atoms).i() as u8 + 1; + let max: u8 = at::Mux9::in_cnt(atoms).i() as u8 + 1; self.idx = self.idx % max; if nctx.in_connected & 0x1 == 0x1 { for frame in 0..ctx.nframes() { - self.idx = - (max as f32 * denorm::Mux9::slct(slct, frame)) - .floor() as u8 - % max; + self.idx = (max as f32 * denorm::Mux9::slct(slct, frame)).floor() as u8 % max; - out.write(frame, match self.idx { - 0 => denorm::Mux9::in_1(in_1, frame), - 1 => denorm::Mux9::in_2(in_2, frame), - 2 => denorm::Mux9::in_3(in_3, frame), - 3 => denorm::Mux9::in_4(in_4, frame), - 4 => denorm::Mux9::in_5(in_5, frame), - 5 => denorm::Mux9::in_6(in_6, frame), - 6 => denorm::Mux9::in_7(in_7, frame), - 7 => denorm::Mux9::in_8(in_8, frame), - _ => denorm::Mux9::in_9(in_9, frame), - }); + out.write( + frame, + match self.idx { + 0 => denorm::Mux9::in_1(in_1, frame), + 1 => denorm::Mux9::in_2(in_2, frame), + 2 => denorm::Mux9::in_3(in_3, frame), + 3 => denorm::Mux9::in_4(in_4, frame), + 4 => denorm::Mux9::in_5(in_5, frame), + 5 => denorm::Mux9::in_6(in_6, frame), + 6 => denorm::Mux9::in_7(in_7, frame), + 7 => denorm::Mux9::in_8(in_8, frame), + _ => denorm::Mux9::in_9(in_9, frame), + }, + ); } - } else { for frame in 0..ctx.nframes() { - if self.trig_rst.check_trigger( - denorm::Mux9::t_rst(t_rst, frame)) - { self.idx = 0; } + if self.trig_rst.check_trigger(denorm::Mux9::t_rst(t_rst, frame)) { + self.idx = 0; + } - if self.trig_up.check_trigger( - denorm::Mux9::t_up(t_up, frame)) - { self.idx = (self.idx + 1) % max; } + if self.trig_up.check_trigger(denorm::Mux9::t_up(t_up, frame)) { + self.idx = (self.idx + 1) % max; + } - if self.trig_down.check_trigger( - denorm::Mux9::t_down(t_down, frame)) - { self.idx = (self.idx + max - 1) % max; } + if self.trig_down.check_trigger(denorm::Mux9::t_down(t_down, frame)) { + self.idx = (self.idx + max - 1) % max; + } - out.write(frame, match self.idx { - 0 => denorm::Mux9::in_1(in_1, frame), - 1 => denorm::Mux9::in_2(in_2, frame), - 2 => denorm::Mux9::in_3(in_3, frame), - 3 => denorm::Mux9::in_4(in_4, frame), - 4 => denorm::Mux9::in_5(in_5, frame), - 5 => denorm::Mux9::in_6(in_6, frame), - 6 => denorm::Mux9::in_7(in_7, frame), - 7 => denorm::Mux9::in_8(in_8, frame), - _ => denorm::Mux9::in_9(in_9, frame), - }); + out.write( + frame, + match self.idx { + 0 => denorm::Mux9::in_1(in_1, frame), + 1 => denorm::Mux9::in_2(in_2, frame), + 2 => denorm::Mux9::in_3(in_3, frame), + 3 => denorm::Mux9::in_4(in_4, frame), + 4 => denorm::Mux9::in_5(in_5, frame), + 5 => denorm::Mux9::in_6(in_6, frame), + 6 => denorm::Mux9::in_7(in_7, frame), + 7 => denorm::Mux9::in_8(in_8, frame), + _ => denorm::Mux9::in_9(in_9, frame), + }, + ); } } diff --git a/src/dsp/node_noise.rs b/src/dsp/node_noise.rs index 91e75da..8f4b548 100644 --- a/src/dsp/node_noise.rs +++ b/src/dsp/node_noise.rs @@ -2,62 +2,52 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; use crate::dsp::helpers::Rng; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_noise_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Bipolar", - 1 => "Unipolar", - _ => "?", - }; +macro_rules! fa_noise_mode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Bipolar", + 1 => "Unipolar", + _ => "?", + }; write!($formatter, "{}", s) -} } } + }}; +} /// A simple noise generator #[derive(Debug, Clone)] pub struct Noise { - seed: u64, - rng: Rng, + seed: u64, + rng: Rng, } impl Noise { pub fn new(nid: &NodeId) -> Self { let mut rng = Rng::new(); - rng.seed( - (0x193a67f4a8a6d769_u64).wrapping_add( - 0x131415 * (nid.instance() as u64 + 1))); + rng.seed((0x193a67f4a8a6d769_u64).wrapping_add(0x131415 * (nid.instance() as u64 + 1))); - Self { - seed: nid.instance() as u64, - rng, - } + Self { seed: nid.instance() as u64, rng } } - pub const atv : &'static str = - "Noise atv\n.Attenuverter input, to attenuate or invert \ + pub const atv: &'static str = "Noise atv\n.Attenuverter input, to attenuate or invert \ the noise.\nRange: (-1..1)"; - pub const offs : &'static str = - "Noise offs\n.Offset input, that is added to the output \ + pub const offs: &'static str = "Noise offs\n.Offset input, that is added to the output \ signal after attenuvertig it.\nRange: (-1..1)"; - pub const mode : &'static str = - "Noise mode\nYou can switch between 'Bipolar' noise, which \ + pub const mode: &'static str = "Noise mode\nYou can switch between 'Bipolar' noise, which \ uses the full range from -1 to 1, or 'Unipolar' noise that \ only uses the range from 0 to 1."; - pub const sig : &'static str = - "Noise sig\nThe noise output.\nRange: (-1..1)"; + pub const sig: &'static str = "Noise sig\nThe noise output.\nRange: (-1..1)"; - pub const DESC : &'static str = -r#"Noise Oscillator + pub const DESC: &'static str = r#"Noise Oscillator This is a very simple noise oscillator, which can be used for any kind of audio rate noise. And as a source for sample & hold like nodes to generate low frequency modulation. "#; -pub const HELP : &'static str = -r#"Noise - A Simple Noise Oscillator + pub const HELP: &'static str = r#"Noise - A Simple Noise Oscillator This is a very simple noise oscillator, which can be used for any kind of audio rate noise. And as a source for sample & hold @@ -70,47 +60,46 @@ unipolar and bipolar output. } impl DspNode for Noise { - fn outputs() -> usize { 1 } - - fn set_sample_rate(&mut self, _srate: f32) { + fn outputs() -> usize { + 1 } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) { - self.rng.seed( - (0x193a67f4a8a6d769_u64).wrapping_add( - 0x131415 * (self.seed + 1))); + self.rng.seed((0x193a67f4a8a6d769_u64).wrapping_add(0x131415 * (self.seed + 1))); } #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{at, out, inp, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; let mode = at::Noise::mode(atoms); - let atv = inp::Noise::atv(inputs); + let atv = inp::Noise::atv(inputs); let offs = inp::Noise::offs(inputs); - let out = out::Noise::sig(outputs); + let out = out::Noise::sig(outputs); let rng = &mut self.rng; if mode.i() == 0 { for frame in 0..ctx.nframes() { let s = (rng.next() * 2.0) - 1.0; - let s = s - * denorm::Noise::atv(atv, frame) - + denorm::Noise::offs(offs, frame); + let s = s * denorm::Noise::atv(atv, frame) + denorm::Noise::offs(offs, frame); out.write(frame, s); } - } else { for frame in 0..ctx.nframes() { - let s = rng.next() - * denorm::Noise::atv(atv, frame) - + denorm::Noise::offs(offs, frame); + let s = + rng.next() * denorm::Noise::atv(atv, frame) + denorm::Noise::offs(offs, frame); out.write(frame, s); } } diff --git a/src/dsp/node_out.rs b/src/dsp/node_out.rs index 46da3ed..48026ec 100644 --- a/src/dsp/node_out.rs +++ b/src/dsp/node_out.rs @@ -2,20 +2,20 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{at, denorm, inp, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, inp, at, denorm, DspNode, LedPhaseVals, NodeContext}; #[macro_export] -macro_rules! fa_out_mono { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Stereo", - 1 => "Mono", - _ => "?", +macro_rules! fa_out_mono { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Stereo", + 1 => "Mono", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// The (stereo) output port of the plugin #[derive(Debug, Clone)] @@ -23,34 +23,30 @@ pub struct Out { /// - 0: signal channel 1 /// - 1: signal channel 2 #[allow(dead_code)] - input: [f32; 2], + input: [f32; 2], } impl Out { pub fn new(_nid: &NodeId) -> Self { - Self { - input: [0.0; 2], - } + Self { input: [0.0; 2] } } - pub const mono : &'static str = + pub const mono: &'static str = "Out mono\nIf set to 'Mono', ch1 will be sent to both output channels.\n(UI only)"; - pub const gain : &'static str = + pub const gain: &'static str = "Out gain\nThe main gain of the synthesizer output, applied to all channels. \ Please note that this is a linear control, to prevent inaccuracies for 1.0. \ \nRange: (0..1)"; - pub const ch1 : &'static str = - "Out ch1\nAudio channel 1 (left)\nRange: (-1..1)"; - pub const ch2 : &'static str = - "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch1: &'static str = "Out ch1\nAudio channel 1 (left)\nRange: (-1..1)"; + pub const ch2: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch3 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch4 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch5 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch6 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch7 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch8 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const ch9 : &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch3: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch4: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch5: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch6: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch7: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch8: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; + pub const ch9: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; pub const ch10: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; pub const ch11: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; pub const ch12: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; @@ -60,12 +56,10 @@ impl Out { pub const ch16: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; pub const ch17: &'static str = "Out ch2\nAudio channel 2 (right)\nRange: (-1..1)"; - pub const DESC : &'static str = - "Audio Output Port\n\n\ + pub const DESC: &'static str = "Audio Output Port\n\n\ This output port node allows you to send audio signals \ to audio devices or tracks in your DAW."; - pub const HELP : &'static str = -r#"Audio Output Port + pub const HELP: &'static str = r#"Audio Output Port This output port node allows you to send audio signals to audio devices or tracks in your DAW. If you need a stereo output but only have a mono @@ -75,19 +69,25 @@ input to the second channel 'ch2'. } impl DspNode for Out { - fn outputs() -> usize { 0 } + fn outputs() -> usize { + 0 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - _outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - let in1 = inp::Out::ch1(inputs); + atoms: &[SAtom], + inputs: &[ProcBuf], + _outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + let in1 = inp::Out::ch1(inputs); let gain = inp::Out::gain(inputs); if at::Out::mono(atoms).i() > 0 { diff --git a/src/dsp/node_pverb.rs b/src/dsp/node_pverb.rs index af2299d..cdb8529 100644 --- a/src/dsp/node_pverb.rs +++ b/src/dsp/node_pverb.rs @@ -2,35 +2,32 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, denorm -}; +use super::dattorro::{DattorroReverb, DattorroReverbParams}; use super::helpers::crossfade; -use super::dattorro::{ - DattorroReverb, - DattorroReverbParams -}; +use crate::dsp::{denorm, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; pub struct DatParams { - frame: usize, + frame: usize, predly: ProcBuf, - size: ProcBuf, - dcy: ProcBuf, - ilpf: ProcBuf, - ihpf: ProcBuf, - dif: ProcBuf, - dmix: ProcBuf, + size: ProcBuf, + dcy: ProcBuf, + ilpf: ProcBuf, + ihpf: ProcBuf, + dif: ProcBuf, + dmix: ProcBuf, mspeed: ProcBuf, - mshp: ProcBuf, + mshp: ProcBuf, mdepth: ProcBuf, - rlpf: ProcBuf, - rhpf: ProcBuf, + rlpf: ProcBuf, + rhpf: ProcBuf, } impl DatParams { #[inline] - pub fn set_frame(&mut self, frame: usize) { self.frame = frame; } + pub fn set_frame(&mut self, frame: usize) { + self.frame = frame; + } } impl DattorroReverbParams for DatParams { @@ -74,74 +71,65 @@ impl DattorroReverbParams for DatParams { #[derive(Debug, Clone)] pub struct PVerb { - verb: Box, + verb: Box, } impl PVerb { pub fn new(_nid: &NodeId) -> Self { - Self { - verb: Box::new(DattorroReverb::new()), - } + Self { verb: Box::new(DattorroReverb::new()) } } - pub const in_l : &'static str = - "PVerb in_l\nLeft input channel, will be summed with the right \ + pub const in_l: &'static str = "PVerb in_l\nLeft input channel, will be summed with the right \ channel. So you can just feed in a mono signal \ without harm.\nRange: (-1..1)\n"; - pub const in_r : &'static str = - "PVerb in_r\nRight input channel, will be summed with the \ + pub const in_r: &'static str = "PVerb in_r\nRight input channel, will be summed with the \ left channel.\nRange: (-1..1)\n"; - pub const sig_l : &'static str = + pub const sig_l: &'static str = "PVerb sig_l\nThe left channel of the output signal.\nRange: (0..1)"; - pub const sig_r : &'static str = + pub const sig_r: &'static str = "PVerb sig_r\nThe right channel of the output signal.\nRange: (0..1)"; - pub const predly : &'static str = + pub const predly: &'static str = "PVerb predly\nThe pre-delay length for the first reflection.\nRange: (0..1)"; - pub const size : &'static str = - "PVerb size\nThe size of the simulated room. Goes from a small \ + pub const size: &'static str = "PVerb size\nThe size of the simulated room. Goes from a small \ chamber to a huge hall.\nRange: (0..1)"; - pub const dcy : &'static str = - "PVerb dcy\nThe decay of the sound. If you set this to '1.0' the + pub const dcy: &'static str = "PVerb dcy\nThe decay of the sound. If you set this to '1.0' the sound will infinitively be sustained. Just be careful feeding in more \ sound with that.\nRange: (0..1)"; - pub const ilpf : &'static str = + pub const ilpf: &'static str = "PVerb ilpf\nInput low-pass filter cutoff frequency, for filtering \ the input before it's fed into the pre-delay.\nRange: (0..1)"; - pub const ihpf : &'static str = + pub const ihpf: &'static str = "PVerb ihpf\nInput high-pass filter cutoff frequency, for filtering \ the input before it's fed into the pre-delay.\nRange: (0..1)"; - pub const dif : &'static str = - "PVerb dif\nThe amount of diffusion inside the reverb tank. \ + pub const dif: &'static str = "PVerb dif\nThe amount of diffusion inside the reverb tank. \ Setting this to 0 will disable any kind of diffusion and the reverb \ will become a more or less simple echo effect.\nRange: (0..1)"; - pub const dmix : &'static str = + pub const dmix: &'static str = "PVerb dmix\nThe mix between input diffusion and clean output of the \ pre-delay. Setting this to 0 will not diffuse any input.\nRange: (0..1)"; - pub const mspeed : &'static str = + pub const mspeed: &'static str = "PVerb mspeed\nThe internal LFO speed, that modulates the internal \ diffusion inside the reverb tank. Keeping this low (< 0.2) will sound \ a bit more natural than a fast LFO.\nRange: (0..1)"; - pub const mshp : &'static str = + pub const mshp: &'static str = "PVerb mshp\nThe shape of the LFO. 0.0 is a down ramp, 1.0 is an up \ ramp and 0.0 is a triangle. Setting this to 0.5 is a good choise. The \ extreme values of 0.0 and 1.0 can lead to audible artifacts.\nRange: (0..1)"; - pub const mdepth : &'static str = + pub const mdepth: &'static str = "PVerb mdepth\nThe depth of the LFO change that is applied to the \ diffusion inside the reverb tank. More extreme values (above 0.2) will \ lead to more detuned sounds reverbing inside the tank.\nRange: (0..1)"; - pub const rlpf : &'static str = + pub const rlpf: &'static str = "PVerb rlpf\nReverb tank low-pass filter cutoff frequency.\nRange: (0..1)"; - pub const rhpf : &'static str = + pub const rhpf: &'static str = "PVerb rhpf\nReverb tank high-pass filter cutoff frequency.\nRange: (0..1)"; - pub const mix : &'static str = + pub const mix: &'static str = "PVerb mix\nDry/Wet mix between the input and the diffused output.\nRange: (0..1)"; - pub const DESC : &'static str = -r#"Plate Reverb + pub const DESC: &'static str = r#"Plate Reverb This is a simple but yet powerful small plate reverb based on the design by Jon Dattorro. It should suit your needs from small rooms up to large athmospheric sound scapes. "#; - pub const HELP : &'static str = -r#"PVerb - Plate Reverb (by Jon Dattorro) + pub const HELP: &'static str = r#"PVerb - Plate Reverb (by Jon Dattorro) This is a simple but yet powerful small plate reverb based on the design by Jon Dattorro. It should suit your needs from small rooms up to large @@ -183,11 +171,12 @@ Structure of the reverb is: Multiple Taps into Left/Right Diffusors 1/2 and Delays 1/2 are then fed to the left and right output channels. "#; - } impl DspNode for PVerb { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.verb.set_sample_rate(srate as f64); @@ -199,15 +188,19 @@ impl DspNode for PVerb { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { use crate::dsp::{inp, out_idx}; - let mut in_l = inp::PVerb::in_l(inputs); - let mut in_r = inp::PVerb::in_r(inputs); + let mut in_l = inp::PVerb::in_l(inputs); + let mut in_r = inp::PVerb::in_r(inputs); if (nctx.in_connected & 0x03) != 0x03 { if nctx.in_connected & 0x01 == 0x01 { @@ -220,21 +213,21 @@ impl DspNode for PVerb { let mut params = DatParams { frame: 0, predly: *inp::PVerb::predly(inputs), - size: *inp::PVerb::size(inputs), - dcy: *inp::PVerb::dcy(inputs), - ilpf: *inp::PVerb::ilpf(inputs), - ihpf: *inp::PVerb::ihpf(inputs), - dif: *inp::PVerb::dif(inputs), - dmix: *inp::PVerb::dmix(inputs), + size: *inp::PVerb::size(inputs), + dcy: *inp::PVerb::dcy(inputs), + ilpf: *inp::PVerb::ilpf(inputs), + ihpf: *inp::PVerb::ihpf(inputs), + dif: *inp::PVerb::dif(inputs), + dmix: *inp::PVerb::dmix(inputs), mspeed: *inp::PVerb::mspeed(inputs), - mshp: *inp::PVerb::mshp(inputs), + mshp: *inp::PVerb::mshp(inputs), mdepth: *inp::PVerb::mdepth(inputs), - rlpf: *inp::PVerb::rlpf(inputs), - rhpf: *inp::PVerb::rhpf(inputs), + rlpf: *inp::PVerb::rlpf(inputs), + rhpf: *inp::PVerb::rhpf(inputs), }; - let mix = inp::PVerb::mix(inputs); - let out_i = out_idx::PVerb::sig_r(); + let mix = inp::PVerb::mix(inputs); + let out_i = out_idx::PVerb::sig_r(); let (out_l, out_r) = outputs.split_at_mut(out_i); let out_l = &mut out_l[0]; let out_r = &mut out_r[0]; @@ -247,14 +240,10 @@ impl DspNode for PVerb { params.set_frame(frame); let (l, r) = verb.process(&mut params, i_l as f64, i_r as f64); - out_l.write( - frame, crossfade(i_l, l as f32, denorm::PVerb::mix(mix, frame))); - out_r.write( - frame, crossfade(i_r, r as f32, denorm::PVerb::mix(mix, frame))); + out_l.write(frame, crossfade(i_l, l as f32, denorm::PVerb::mix(mix, frame))); + out_r.write(frame, crossfade(i_r, r as f32, denorm::PVerb::mix(mix, frame))); } - ctx_vals[0].set( - out_l.read(ctx.nframes() - 1) - + out_r.read(ctx.nframes() - 1)); + ctx_vals[0].set(out_l.read(ctx.nframes() - 1) + out_r.read(ctx.nframes() - 1)); } } diff --git a/src/dsp/node_quant.rs b/src/dsp/node_quant.rs index fc83593..d18ae51 100644 --- a/src/dsp/node_quant.rs +++ b/src/dsp/node_quant.rs @@ -2,54 +2,48 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::helpers::{ChangeTrig, Quantizer}; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::helpers::{Quantizer, ChangeTrig}; #[macro_export] -macro_rules! fa_quant { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - write!($formatter, "?") -} } } +macro_rules! fa_quant { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + write!($formatter, "?") + }}; +} /// A pitch quantizer #[derive(Debug, Clone)] pub struct Quant { - quant: Box, + quant: Box, change_trig: ChangeTrig, } impl Quant { pub fn new(_nid: &NodeId) -> Self { - Self { - quant: Box::new(Quantizer::new()), - change_trig: ChangeTrig::new(), - } + Self { quant: Box::new(Quantizer::new()), change_trig: ChangeTrig::new() } } - pub const freq : &'static str = + pub const freq: &'static str = "Quant freq\nAny signal that is to be pitch quantized.\nRange: (-1..1)"; - pub const oct : &'static str = + pub const oct: &'static str = "Quant oct\nPitch offset, the knob is snapping to octave offsets. \ Feed signal values snapped to 0.1 multiples for exact octave offsets.\ \nRange: (-1..1)"; - pub const sig : &'static str = - "Quant sig\nThe quantized output signal that is rounded to \ + pub const sig: &'static str = "Quant sig\nThe quantized output signal that is rounded to \ the next selected note pitch within the octave of the \ original input to 'freq'.\nRange: (-1..1)"; - pub const keys : &'static str = - "Quant keys\nSelect the notes you want to snap to here. \ + pub const keys: &'static str = "Quant keys\nSelect the notes you want to snap to here. \ If no notes are selected, the quantizer will snap the \ incoming signal to any closest note."; - pub const t : &'static str = - "Quant t\nEverytime the quantizer snaps to a new pitch, it will \ + pub const t: &'static str = "Quant t\nEverytime the quantizer snaps to a new pitch, it will \ emit a short trigger on this signal output. This is useful \ to trigger for example an envelope."; - pub const DESC : &'static str = -r#"Pitch Quantizer + pub const DESC: &'static str = r#"Pitch Quantizer This is a simple quantizer, that snaps a pitch signal on 'freq' to the closest selected notes within their octave. "#; - pub const HELP : &'static str = -r#"Quant - A pitch quantizer + pub const HELP: &'static str = r#"Quant - A pitch quantizer This is a simple quantizer, that snaps a pitch signal on 'freq' to the closest selected notes within their octave. @@ -62,7 +56,9 @@ please see also the 'CQnt' node. } impl DspNode for Quant { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.change_trig.set_sample_rate(srate); @@ -74,18 +70,22 @@ impl DspNode for Quant { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{at, out_buf, inp, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out_buf}; let freq = inp::Quant::freq(inputs); - let oct = inp::Quant::oct(inputs); + let oct = inp::Quant::oct(inputs); let keys = at::Quant::keys(atoms); let mut out = out_buf::CQnt::sig(outputs); - let mut t = out_buf::CQnt::t(outputs); + let mut t = out_buf::CQnt::t(outputs); self.quant.set_keys(keys.i()); diff --git a/src/dsp/node_rndwk.rs b/src/dsp/node_rndwk.rs index f0f01a1..748cc42 100644 --- a/src/dsp/node_rndwk.rs +++ b/src/dsp/node_rndwk.rs @@ -2,71 +2,57 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::helpers::{Rng, SlewValue, Trigger}; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::helpers::{Rng, Trigger, SlewValue}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, -}; /// A triggered random walker #[derive(Debug, Clone)] pub struct RndWk { - rng: Rng, - slew_val: SlewValue, - trig: Trigger, - target: f64, + rng: Rng, + slew_val: SlewValue, + trig: Trigger, + target: f64, } impl RndWk { pub fn new(nid: &NodeId) -> Self { let mut rng = Rng::new(); - rng.seed( - (0x193a67f4a8a6d769_u64).wrapping_add( - 0x262829 * (nid.instance() as u64 + 1))); + rng.seed((0x193a67f4a8a6d769_u64).wrapping_add(0x262829 * (nid.instance() as u64 + 1))); - Self { - rng, - trig: Trigger::new(), - slew_val: SlewValue::new(), - target: 0.0, - } + Self { rng, trig: Trigger::new(), slew_val: SlewValue::new(), target: 0.0 } } - pub const trig : &'static str = - "RndWk trig\nThis trigger generates a new random number within \ + pub const trig: &'static str = "RndWk trig\nThis trigger generates a new random number within \ the current 'min'/'max' range.\nRange: (-1..1)"; - pub const step : &'static str = - "RndWk step\nThis is the maximum possible step size of the \ + pub const step: &'static str = "RndWk step\nThis is the maximum possible step size of the \ random number drawn upon 'trig'. Setting this to 0.0 will disable \ the randomness.\nThe minimum step size can be defined \ by the 'offs' parameter.\nRange: (0..1)"; - pub const offs : &'static str = + pub const offs: &'static str = "RndWk offs\nThe minimum step size and direction that is done on each 'trig'.\ Depending on the size of the 'offs' and the 'min'/'max' range, \ this might result in the output value being close to the limits \ of that range.\nRange: (-1..1)"; - pub const min : &'static str = + pub const min: &'static str = "RndWk min\nThe minimum of the new target value. If a value is drawn \ that is outside of this range, it will be reflected back into it.\ \nRange: (0..1)"; - pub const max : &'static str = + pub const max: &'static str = "RndWk max\nThe maximum of the new target value. If a value is drawn \ that is outside of this range, it will be reflected back into it.\ \nRange: (0..1)"; - pub const slew : &'static str = + pub const slew: &'static str = "RndWk slew\nThe slew rate limiting time. Thats the time it takes to \ get to 1.0 from 0.0. Useful for smoothing modulation of audio signals. \ The higher the time, the smoother/slower the transition to new \ target values will be.\nRange: (0..1)"; - pub const sig : &'static str = - "RndWk sig\nOscillator output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Random Walker + pub const sig: &'static str = "RndWk sig\nOscillator output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Random Walker This modulator generates a random number by walking a pre defined maximum random 'step' width. For smoother transitions a slew rate limiter is integrated. "#; - pub const HELP : &'static str = -r#"RndWk - Random Walker + pub const HELP: &'static str = r#"RndWk - Random Walker This modulator generates a random number by walking a pre defined maximum random 'step' width. The newly generated target value will always @@ -82,11 +68,12 @@ Tip: Interesting and smooth results can be achieved if you set 'slew' to a (way) longer time than the 'trig' interval. It will smooth off the step widths and the overall motion even more. "#; - } impl DspNode for RndWk { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.slew_val.set_sample_rate(srate as f64); @@ -100,27 +87,31 @@ impl DspNode for RndWk { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{denorm, inp, out}; - let trig = inp::RndWk::trig(inputs); - let step = inp::RndWk::step(inputs); - let offs = inp::RndWk::offs(inputs); - let min = inp::RndWk::min(inputs); - let max = inp::RndWk::max(inputs); - let slew = inp::RndWk::slew(inputs); - let out = out::RndWk::sig(outputs); + let trig = inp::RndWk::trig(inputs); + let step = inp::RndWk::step(inputs); + let offs = inp::RndWk::offs(inputs); + let min = inp::RndWk::min(inputs); + let max = inp::RndWk::max(inputs); + let slew = inp::RndWk::slew(inputs); + let out = out::RndWk::sig(outputs); for frame in 0..ctx.nframes() { if self.trig.check_trigger(denorm::RndWk::trig(trig, frame)) { let mut min = denorm::RndWk::min(min, frame).clamp(0.0, 1.0); let mut max = denorm::RndWk::max(max, frame).clamp(0.0, 1.0); if min > max { - std::mem::swap(&mut min, &mut max); + std::mem::swap(&mut min, &mut max); } let delta = (max - min).clamp(0.0001, 1.0); @@ -128,58 +119,56 @@ impl DspNode for RndWk { let offs = denorm::RndWk::offs(offs, frame).clamp(-1.0, 1.0); let mut target = - self.slew_val.value() as f32 - + ((self.rng.next() * 2.0 * step) - step) - + offs; + self.slew_val.value() as f32 + ((self.rng.next() * 2.0 * step) - step) + offs; // println!("{:8.6} {:8.6} {:8.6}", min, max, target); // clamp target into a range we can reflect target = target.clamp(min - (delta * 0.99), max + (delta * 0.99)); // reflect back the overshoots: - if target > max { target = max - (max - target).abs(); } - if target < min { target = min + (min - target).abs(); } + if target > max { + target = max - (max - target).abs(); + } + if target < min { + target = min + (min - target).abs(); + } self.target = target as f64; } let slew_time_ms = denorm::RndWk::slew(slew, frame); - out.write( - frame, - self.slew_val.next( - self.target, - slew_time_ms as f64) as f32); + out.write(frame, self.slew_val.next(self.target, slew_time_ms as f64) as f32); } ctx_vals[0].set(out.read(ctx.nframes() - 1)); } -// fn graph_fun() -> Option { -// let mut osc = VPSOscillator::new(0.0); -// let israte = 1.0 / 128.0; -// -// Some(Box::new(move |gd: &dyn GraphAtomData, init: bool, _x: f32, _xn: f32| -> f32 { -// if init { -// osc.reset(); -// } -// -// let v = NodeId::RndWk(0).inp_param("v").unwrap().inp(); -// let vs = NodeId::RndWk(0).inp_param("vs").unwrap().inp(); -// let d = NodeId::RndWk(0).inp_param("d").unwrap().inp(); -// let damt = NodeId::RndWk(0).inp_param("damt").unwrap().inp(); -// let dist = NodeId::RndWk(0).inp_param("dist").unwrap().inp(); -// -// let v = gd.get_denorm(v as u32).clamp(0.0, 1.0); -// let d = gd.get_denorm(d as u32).clamp(0.0, 1.0); -// let vs = gd.get_denorm(vs as u32).clamp(0.0, 20.0); -// let damt = gd.get_denorm(damt as u32); -// let dist = gd.get(dist as u32).map(|a| a.i()).unwrap_or(0); -// -// let v = VPSOscillator::limit_v(d, v + vs); -// let s = osc.next(1.0, israte, d, v); -// let s = apply_distortion(s, damt, dist as u8); -// -// (s + 1.0) * 0.5 -// })) -// } + // fn graph_fun() -> Option { + // let mut osc = VPSOscillator::new(0.0); + // let israte = 1.0 / 128.0; + // + // Some(Box::new(move |gd: &dyn GraphAtomData, init: bool, _x: f32, _xn: f32| -> f32 { + // if init { + // osc.reset(); + // } + // + // let v = NodeId::RndWk(0).inp_param("v").unwrap().inp(); + // let vs = NodeId::RndWk(0).inp_param("vs").unwrap().inp(); + // let d = NodeId::RndWk(0).inp_param("d").unwrap().inp(); + // let damt = NodeId::RndWk(0).inp_param("damt").unwrap().inp(); + // let dist = NodeId::RndWk(0).inp_param("dist").unwrap().inp(); + // + // let v = gd.get_denorm(v as u32).clamp(0.0, 1.0); + // let d = gd.get_denorm(d as u32).clamp(0.0, 1.0); + // let vs = gd.get_denorm(vs as u32).clamp(0.0, 20.0); + // let damt = gd.get_denorm(damt as u32); + // let dist = gd.get(dist as u32).map(|a| a.i()).unwrap_or(0); + // + // let v = VPSOscillator::limit_v(d, v + vs); + // let s = osc.next(1.0, israte, d, v); + // let s = apply_distortion(s, damt, dist as u8); + // + // (s + 1.0) * 0.5 + // })) + // } } diff --git a/src/dsp/node_sampl.rs b/src/dsp/node_sampl.rs index 6e93477..176d25c 100644 --- a/src/dsp/node_sampl.rs +++ b/src/dsp/node_sampl.rs @@ -2,113 +2,110 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -use crate::dsp::{out, at, inp, denorm, denorm_offs}; //, inp, denorm, denorm_v, inp_dir, at}; use super::helpers::Trigger; +use crate::dsp::{at, denorm, denorm_offs, inp, out}; //, inp, denorm, denorm_v, inp_dir, at}; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_sampl_dir { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Forward", - 1 => "Reverse", - _ => "?", +macro_rules! fa_sampl_dir { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Forward", + 1 => "Reverse", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[macro_export] -macro_rules! fa_sampl_dclick { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Off", - 1 => "On", - _ => "?", +macro_rules! fa_sampl_dclick { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Off", + 1 => "On", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[macro_export] -macro_rules! fa_sampl_pmode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Loop", - 1 => "OneShot", - _ => "?", +macro_rules! fa_sampl_pmode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Loop", + 1 => "OneShot", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct Sampl { - phase: f64, - srate: f64, - trig: Trigger, - is_playing: bool, - last_sample: f32, - decaying: f32, + phase: f64, + srate: f64, + trig: Trigger, + is_playing: bool, + last_sample: f32, + decaying: f32, } impl Sampl { pub fn new(_nid: &NodeId) -> Self { Self { - phase: 0.0, - srate: 44100.0, - trig: Trigger::new(), - is_playing: false, - last_sample: 0.0, - decaying: 0.0, + phase: 0.0, + srate: 44100.0, + trig: Trigger::new(), + is_playing: false, + last_sample: 0.0, + decaying: 0.0, } } - pub const freq : &'static str = + pub const freq: &'static str = "Sampl freq\nPitch input for the sampler, giving the playback speed of the \ sample.\nRange: (-1..1)\n"; - pub const trig : &'static str = + pub const trig: &'static str = "Sampl trig\nThe trigger input causes a resync of the playback phase \ and triggers the playback if the 'pmode' is 'OneShot'"; - pub const offs : &'static str = - "Sampl offs\nStart position offset.\nRange: (0..1)\n"; - pub const len : &'static str = + pub const offs: &'static str = "Sampl offs\nStart position offset.\nRange: (0..1)\n"; + pub const len: &'static str = "Sampl len\nAdjusts the playback length of the sample in relation \ to the original length of the sample.\nRange: (0..1)\n"; - pub const dcms : &'static str = + pub const dcms: &'static str = "Sampl dcms\nDeclick fade time in milliseconds.\nNot audio rate!\nRange: (0..1)\n"; - pub const det : &'static str = - "Sin det\nDetune the oscillator in semitones and cents. \ + pub const det: &'static str = "Sin det\nDetune the oscillator in semitones and cents. \ the input of this value is rounded to semitones on coarse input. \ Fine input lets you detune in cents (rounded). \ A signal sent to this port is not rounded.\n\ Note: The signal input allows detune +-10 octaves.\ \nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n"; - pub const sample : &'static str = + pub const sample: &'static str = "Sampl sample\nThe audio sample that is played back.\nRange: (-1..1)\n"; - pub const pmode : &'static str = - "Sampl pmode\nThe playback mode of the sampler.\n\ + pub const pmode: &'static str = "Sampl pmode\nThe playback mode of the sampler.\n\ - 'Loop' constantly plays back the sample. You can reset/sync the phase \ using the 'trig' input in this case.\n\ - 'OneShot' plays back the sample if a trigger is received on 'trig' input.\n"; - pub const dclick : &'static str = + pub const dclick: &'static str = "Sampl dclick\nIf this is enabled it will enable short fade in and out ramps.\n\ This if useful if you don't want to add an envelope just for \ getting rid of the clicks if spos and epos are modulated."; - pub const dir : &'static str = + pub const dir: &'static str = "Sampl dir\nSets the direction of the playhead, plays the sample \ forwards or backwards."; - pub const sig : &'static str = - "Sampl sig\nSampler audio output\nRange: (-1..1)\n"; + pub const sig: &'static str = "Sampl sig\nSampler audio output\nRange: (-1..1)\n"; - pub const DESC : &'static str = - "Sample Player\n\n\ + pub const DESC: &'static str = "Sample Player\n\n\ Provides a simple sample player that you can load a single audio \ sample from a WAV file into."; - pub const HELP : &'static str = -r#"Sample Player + pub const HELP: &'static str = r#"Sample Player Provides a simple sample player for playing back one loaded audio sample. It can be used for purposes like: @@ -147,7 +144,9 @@ impl Sampl { #[inline] fn next_sample_rev(&mut self, sr_factor: f64, speed: f64, sample_data: &[f32]) -> f32 { let sd_len = sample_data.len(); - if sd_len < 1 { return 0.0; } + if sd_len < 1 { + return 0.0; + } let j = self.phase.floor() as usize % sd_len; let i = ((sd_len - 1) - j) + sd_len; @@ -155,7 +154,7 @@ impl Sampl { let f = self.phase.fract(); self.phase = j as f64 + f + sr_factor * speed; - // Hermite interpolation, take from + // Hermite interpolation, take from // https://github.com/eric-wood/delay/blob/main/src/delay.rs#L52 // // Thanks go to Eric Wood! @@ -163,14 +162,14 @@ impl Sampl { // For the interpolation code: // MIT License, Copyright (c) 2021 Eric Wood let xm1 = sample_data[(i + 1) % sd_len]; - let x0 = sample_data[i % sd_len]; - let x1 = sample_data[(i - 1) % sd_len]; - let x2 = sample_data[(i - 2) % sd_len]; + let x0 = sample_data[i % sd_len]; + let x1 = sample_data[(i - 1) % sd_len]; + let x2 = sample_data[(i - 2) % sd_len]; - let c = (x1 - xm1) * 0.5; - let v = x0 - x1; - let w = c + v; - let a = w + v + (x2 - x0) * 0.5; + let c = (x1 - xm1) * 0.5; + let v = x0 - x1; + let w = c + v; + let a = w + v + (x2 - x0) * 0.5; let b_neg = w + a; let f = (1.0 - f) as f32; @@ -181,13 +180,15 @@ impl Sampl { #[inline] fn next_sample(&mut self, sr_factor: f64, speed: f64, sample_data: &[f32]) -> f32 { let sd_len = sample_data.len(); - if sd_len < 1 { return 0.0; } + if sd_len < 1 { + return 0.0; + } let i = self.phase.floor() as usize + sd_len; let f = self.phase.fract(); self.phase = (i % sd_len) as f64 + f + sr_factor * speed; - // Hermite interpolation, take from + // Hermite interpolation, take from // https://github.com/eric-wood/delay/blob/main/src/delay.rs#L52 // // Thanks go to Eric Wood! @@ -195,14 +196,14 @@ impl Sampl { // For the interpolation code: // MIT License, Copyright (c) 2021 Eric Wood let xm1 = sample_data[(i - 1) % sd_len]; - let x0 = sample_data[i % sd_len]; - let x1 = sample_data[(i + 1) % sd_len]; - let x2 = sample_data[(i + 2) % sd_len]; + let x0 = sample_data[i % sd_len]; + let x1 = sample_data[(i + 1) % sd_len]; + let x2 = sample_data[(i + 2) % sd_len]; - let c = (x1 - xm1) * 0.5; - let v = x0 - x1; - let w = c + v; - let a = w + v + (x2 - x0) * 0.5; + let c = (x1 - xm1) * 0.5; + let v = x0 - x1; + let w = c + v; + let a = w + v + (x2 - x0) * 0.5; let b_neg = w + a; let f = f as f32; @@ -211,24 +212,30 @@ impl Sampl { #[allow(clippy::float_cmp)] #[inline] - fn play(&mut self, inputs: &[ProcBuf], nframes: usize, - sample_data: &[f32], out: &mut ProcBuf, do_loop: bool, - declick: bool, reverse: bool) - { - let freq = inp::Sampl::freq(inputs); - let trig = inp::Sampl::trig(inputs); - let offs = inp::Sampl::offs(inputs); - let len = inp::Sampl::len(inputs); - let dcms = inp::Sampl::dcms(inputs); - let det = inp::Sampl::det(inputs); + fn play( + &mut self, + inputs: &[ProcBuf], + nframes: usize, + sample_data: &[f32], + out: &mut ProcBuf, + do_loop: bool, + declick: bool, + reverse: bool, + ) { + let freq = inp::Sampl::freq(inputs); + let trig = inp::Sampl::trig(inputs); + let offs = inp::Sampl::offs(inputs); + let len = inp::Sampl::len(inputs); + let dcms = inp::Sampl::dcms(inputs); + let det = inp::Sampl::det(inputs); let sample_srate = sample_data[0] as f64; - let sample_data = &sample_data[1..]; - let sr_factor = sample_srate / self.srate; + let sample_data = &sample_data[1..]; + let sr_factor = sample_srate / self.srate; - let ramp_time = denorm::Sampl::dcms(dcms, 0) as f64 * self.srate; + let ramp_time = denorm::Sampl::dcms(dcms, 0) as f64 * self.srate; let ramp_sample_count = (ramp_time / 1000.0).ceil() as usize; - let ramp_inc = 1000.0 / ramp_time; + let ramp_inc = 1000.0 / ramp_time; let mut is_playing = self.is_playing; @@ -236,10 +243,10 @@ impl Sampl { is_playing = true; } - let mut prev_offs = -10.0; - let mut prev_len = -10.0; + let mut prev_offs = -10.0; + let mut prev_len = -10.0; - let mut start_idx = 0; + let mut start_idx = 0; let mut end_idx_plus1 = sample_data.len(); for frame in 0..nframes { @@ -252,133 +259,118 @@ impl Sampl { is_playing = true; } - let s = - if is_playing { - let freq = - denorm_offs::Sampl::freq( - freq, det.read(frame), frame); - let playback_speed = freq / 440.0; + let s = if is_playing { + let freq = denorm_offs::Sampl::freq(freq, det.read(frame), frame); + let playback_speed = freq / 440.0; - let prev_phase = self.phase; + let prev_phase = self.phase; - let sd_len = sample_data.len(); + let sd_len = sample_data.len(); - let cur_offs = - denorm::Sampl::offs(offs, frame).abs().min(0.999999) - as f64; - let recalc_end = - if prev_offs != cur_offs { - start_idx = - ((sd_len as f64 * cur_offs) - .floor() as usize).min(sd_len); - prev_offs = cur_offs; - true - } else { - false - }; - - let cur_len = - denorm::Sampl::len(len, frame).abs().min(1.0) as f64; - if recalc_end || prev_len != cur_len { - let max_sd_len = - (sd_len as f64 * cur_len as f64).round() as usize; - - let remain_s_len = - if start_idx <= sd_len { - (sd_len - start_idx).min(max_sd_len) - } else { 0 }; - - end_idx_plus1 = remain_s_len; - - prev_len = cur_len; - } - - let sample_slice = - &sample_data[start_idx..(start_idx + end_idx_plus1)]; - - // next_sample mutates self.phase, so we need the current phase - // that is used for looking up the sample from the audio data. - let sample_idx = self.phase.floor() as usize; - - let mut s = - if reverse { - self.next_sample_rev( - sr_factor, - playback_speed as f64, - sample_slice) - } else { - self.next_sample( - sr_factor, - playback_speed as f64, - sample_slice) - }; - - if declick { - let samples_to_end = sample_slice.len() - sample_idx; - - let ramp_atten_factor = - if sample_idx < ramp_sample_count { - sample_idx as f64 * ramp_inc - } else if samples_to_end < ramp_sample_count { - samples_to_end as f64 * ramp_inc - } else { - 1.0 - }; - - s *= ramp_atten_factor as f32; - } - - self.last_sample = s; - out.write(frame, s); - - if !do_loop && prev_phase > self.phase { - // played past end => stop playing. - is_playing = false; - } - - s + let cur_offs = denorm::Sampl::offs(offs, frame).abs().min(0.999999) as f64; + let recalc_end = if prev_offs != cur_offs { + start_idx = ((sd_len as f64 * cur_offs).floor() as usize).min(sd_len); + prev_offs = cur_offs; + true } else { - 0.0 + false }; - let s = - if !declick || self.decaying.abs() < 0.00001 { - self.decaying = 0.0; - s + let cur_len = denorm::Sampl::len(len, frame).abs().min(1.0) as f64; + if recalc_end || prev_len != cur_len { + let max_sd_len = (sd_len as f64 * cur_len as f64).round() as usize; + + let remain_s_len = + if start_idx <= sd_len { (sd_len - start_idx).min(max_sd_len) } else { 0 }; + + end_idx_plus1 = remain_s_len; + + prev_len = cur_len; + } + + let sample_slice = &sample_data[start_idx..(start_idx + end_idx_plus1)]; + + // next_sample mutates self.phase, so we need the current phase + // that is used for looking up the sample from the audio data. + let sample_idx = self.phase.floor() as usize; + + let mut s = if reverse { + self.next_sample_rev(sr_factor, playback_speed as f64, sample_slice) } else { - self.decaying *= 0.98; - (s + self.decaying).clamp(-1.0, 1.0) + self.next_sample(sr_factor, playback_speed as f64, sample_slice) }; + if declick { + let samples_to_end = sample_slice.len() - sample_idx; + + let ramp_atten_factor = if sample_idx < ramp_sample_count { + sample_idx as f64 * ramp_inc + } else if samples_to_end < ramp_sample_count { + samples_to_end as f64 * ramp_inc + } else { + 1.0 + }; + + s *= ramp_atten_factor as f32; + } + + self.last_sample = s; + out.write(frame, s); + + if !do_loop && prev_phase > self.phase { + // played past end => stop playing. + is_playing = false; + } + + s + } else { + 0.0 + }; + + let s = if !declick || self.decaying.abs() < 0.00001 { + self.decaying = 0.0; + s + } else { + self.decaying *= 0.98; + (s + self.decaying).clamp(-1.0, 1.0) + }; + self.last_sample = s; out.write(frame, s); } self.is_playing = is_playing; } - } impl DspNode for Sampl { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, srate: f32) { self.srate = srate.into(); } + fn set_sample_rate(&mut self, srate: f32) { + self.srate = srate.into(); + } fn reset(&mut self) { self.trig.reset(); } #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { let sample = at::Sampl::sample(atoms); - let pmode = at::Sampl::pmode(atoms); + let pmode = at::Sampl::pmode(atoms); let dclick = at::Sampl::dclick(atoms); - let dir = at::Sampl::dir(atoms); - let out = out::Sampl::sig(outputs); + let dir = at::Sampl::dir(atoms); + let out = out::Sampl::sig(outputs); if let SAtom::AudioSample((_, Some(sample_data))) = sample { // 3 is for sample-sample-rate and at least 2 audio samples. @@ -397,7 +389,8 @@ impl DspNode for Sampl { out, pmode.i() == 0, dclick.i() == 1, - dir.i() == 1); + dir.i() == 1, + ); } else { for frame in 0..ctx.nframes() { out.write(frame, 0.0); diff --git a/src/dsp/node_sfilter.rs b/src/dsp/node_sfilter.rs index 9b25792..20c3f08 100644 --- a/src/dsp/node_sfilter.rs +++ b/src/dsp/node_sfilter.rs @@ -2,88 +2,70 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; use crate::dsp::helpers::{ - process_1pole_lowpass, - process_1pole_highpass, - process_1pole_tpt_lowpass, - process_1pole_tpt_highpass, - process_hal_chamberlin_svf, - process_simper_svf, + process_1pole_highpass, process_1pole_lowpass, process_1pole_tpt_highpass, + process_1pole_tpt_lowpass, process_hal_chamberlin_svf, process_simper_svf, process_stilson_moog, }; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_sfilter_type { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "LP 1p", - 1 => "LP 1pt", - 2 => "HP 1p", - 3 => "HP 1pt", - 4 => "LP 12c", - 5 => "HP 12c", - 6 => "BP 12c", - 7 => "NO 12c", - 8 => "LP 12s", - 9 => "HP 12s", - 10 => "BP 12s", - 11 => "NO 12s", - 12 => "PK 12s", - 13 => "LP 24m", - _ => "?", +macro_rules! fa_sfilter_type { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "LP 1p", + 1 => "LP 1pt", + 2 => "HP 1p", + 3 => "HP 1pt", + 4 => "LP 12c", + 5 => "HP 12c", + 6 => "BP 12c", + 7 => "NO 12c", + 8 => "LP 12s", + 9 => "HP 12s", + 10 => "BP 12s", + 11 => "NO 12s", + 12 => "PK 12s", + 13 => "LP 24m", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct SFilter { israte: f32, - z: f32, - y: f32, - k: f32, - h: f32, - delay: [f32; 4], - otype: i8, + z: f32, + y: f32, + k: f32, + h: f32, + delay: [f32; 4], + otype: i8, } impl SFilter { pub fn new(_nid: &NodeId) -> Self { - Self { - israte: 1.0 / 44100.0, - z: 0.0, - y: 0.0, - k: 0.0, - h: 0.0, - delay: [0.0; 4], - otype: -1, - } + Self { israte: 1.0 / 44100.0, z: 0.0, y: 0.0, k: 0.0, h: 0.0, delay: [0.0; 4], otype: -1 } } - pub const inp : &'static str = - "SFilter inp\nSignal input\nRange: (-1..1)\n"; - pub const freq : &'static str = - "SFilter freq\nFilter cutoff frequency.\nRange: (-1..1)\n"; - pub const res : &'static str = - "SFilter res\nFilter resonance.\nRange: (0..1)\n"; - pub const ftype : &'static str = - "SFilter ftype\nThe filter type, there are varying types of \ + pub const inp: &'static str = "SFilter inp\nSignal input\nRange: (-1..1)\n"; + pub const freq: &'static str = "SFilter freq\nFilter cutoff frequency.\nRange: (-1..1)\n"; + pub const res: &'static str = "SFilter res\nFilter resonance.\nRange: (0..1)\n"; + pub const ftype: &'static str = "SFilter ftype\nThe filter type, there are varying types of \ filters available. Please consult the node documentation for \ a complete list.\n\ Types: 1p/1pt=one poles, 12c=Hal Chamberlin SVF,\n\ 12s=Simper SVF, 24m=Moog\n\ Outputs: LP=Low-,HP=High-,BP=Band-Pass,NO=Notch,PK=Peak"; - pub const sig : &'static str = - "SFilter sig\nFiltered signal output.\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Simple Filter + pub const sig: &'static str = "SFilter sig\nFiltered signal output.\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Simple Filter This is a collection of more or less simple filters. There are only two parameters: Filter cutoff 'freq' and the 'res'onance. "#; - pub const HELP : &'static str = -r#"SFilter - Simple Audio Filter Collection + pub const HELP: &'static str = r#"SFilter - Simple Audio Filter Collection This is a collection of a few more or less simple filters of varying types. There are only few parameters for you to change: 'freq' @@ -129,132 +111,137 @@ as it can become quite unstable. macro_rules! process_filter_fun32 { ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => { { + $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame); - let $freq = denorm::SFilter::freq($freq, frame); - let $freq = $freq.clamp($minfreq, $maxfreq); - let $res = denorm::SFilter::res($res, frame); - let $res = $res.clamp(0.0, 0.99); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp($minfreq, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, 0.99); let s = $block; $out.write(frame, s); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $input: ident, $maxfreq: expr, $block: block) => { { + $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame); - let $freq = denorm::SFilter::freq($freq, frame); - let $freq = $freq.clamp(1.0, $maxfreq); - let $res = denorm::SFilter::res($res, frame); - let $res = $res.clamp(0.0, 0.99); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, 0.99); let s = $block; $out.write(frame, s); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $maxres: expr, $input: ident, $maxfreq: expr, $block: block) => { { + $maxres: expr, $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame); - let $freq = denorm::SFilter::freq($freq, frame); - let $freq = $freq.clamp(1.0, $maxfreq); - let $res = denorm::SFilter::res($res, frame); - let $res = $res.clamp(0.0, $maxres); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame); + let $res = $res.clamp(0.0, $maxres); let s = $block; $out.write(frame, s); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, - $input: ident, $maxfreq: expr, $block: block) => { { + $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame); - let $freq = denorm::SFilter::freq($freq, frame); - let $freq = $freq.clamp(1.0, $maxfreq); + let $freq = denorm::SFilter::freq($freq, frame); + let $freq = $freq.clamp(1.0, $maxfreq); let s = $block; $out.write(frame, s); } - } } + }}; } - macro_rules! process_filter_fun { ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => { { + $input: ident, $minfreq: expr, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame) as f64; - let $freq = denorm::SFilter::freq($freq, frame) as f64; - let $freq = $freq.clamp($minfreq, $maxfreq); - let $res = denorm::SFilter::res($res, frame) as f64; - let $res = $res.clamp(0.0, 0.99); + let $freq = denorm::SFilter::freq($freq, frame) as f64; + let $freq = $freq.clamp($minfreq, $maxfreq); + let $res = denorm::SFilter::res($res, frame) as f64; + let $res = $res.clamp(0.0, 0.99); let s = $block; $out.write(frame, s as f32); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $input: ident, $maxfreq: expr, $block: block) => { { + $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame) as f64; - let $freq = denorm::SFilter::freq($freq, frame) as f64; - let $freq = $freq.clamp(1.0, $maxfreq); - let $res = denorm::SFilter::res($res, frame) as f64; - let $res = $res.clamp(0.0, 0.99); + let $freq = denorm::SFilter::freq($freq, frame) as f64; + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame) as f64; + let $res = $res.clamp(0.0, 0.99); let s = $block; $out.write(frame, s as f32); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, $res: ident, - $maxres: expr, $input: ident, $maxfreq: expr, $block: block) => { { + $maxres: expr, $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame) as f64; - let $freq = denorm::SFilter::freq($freq, frame) as f64; - let $freq = $freq.clamp(1.0, $maxfreq); - let $res = denorm::SFilter::res($res, frame) as f64; - let $res = $res.clamp(0.0, $maxres); + let $freq = denorm::SFilter::freq($freq, frame) as f64; + let $freq = $freq.clamp(1.0, $maxfreq); + let $res = denorm::SFilter::res($res, frame) as f64; + let $res = $res.clamp(0.0, $maxres); let s = $block; $out.write(frame, s as f32); } - } }; + }}; ($nframes: expr, $inp: expr, $out: ident, $freq: ident, - $input: ident, $maxfreq: expr, $block: block) => { { + $input: ident, $maxfreq: expr, $block: block) => {{ for frame in 0..$nframes { let $input = $inp.read(frame) as f64; - let $freq = denorm::SFilter::freq($freq, frame) as f64; - let $freq = $freq.clamp(1.0, $maxfreq); + let $freq = denorm::SFilter::freq($freq, frame) as f64; + let $freq = $freq.clamp(1.0, $maxfreq); let s = $block; $out.write(frame, s as f32); } - } } + }}; } impl DspNode for SFilter { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.israte = 1.0 / srate; } fn reset(&mut self) { - self.z = 0.0; - self.y = 0.0; - self.k = 0.0; - self.h = 0.0; + self.z = 0.0; + self.y = 0.0; + self.k = 0.0; + self.h = 0.0; self.delay = [0.0; 4]; self.otype = -1; } #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; - let inp = inp::SFilter::inp(inputs); - let freq = inp::SFilter::freq(inputs); - let res = inp::SFilter::res(inputs); + let inp = inp::SFilter::inp(inputs); + let freq = inp::SFilter::freq(inputs); + let res = inp::SFilter::res(inputs); let ftype = at::SFilter::ftype(atoms); - let out = out::SFilter::sig(outputs); + let out = out::SFilter::sig(outputs); let ftype = ftype.i() as i8; @@ -268,137 +255,146 @@ impl DspNode for SFilter { } match ftype { - 0 => { // Lowpass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, input, 22000.0, { - process_1pole_lowpass( - input, freq, self.israte, &mut self.z) - }) - }, - 1 => { // Lowpass TPT - process_filter_fun32!( - ctx.nframes(), inp, out, freq, input, 22000.0, { - process_1pole_tpt_lowpass( - input, freq, self.israte, &mut self.z) - }) - }, - 2 => { // Highpass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, input, 22000.0, { - process_1pole_highpass( - input, freq, self.israte, &mut self.z, &mut self.y) - }) - }, - 3 => { // Highpass TPT - process_filter_fun32!( - ctx.nframes(), inp, out, freq, input, 22000.0, { - process_1pole_tpt_highpass( - input, freq, self.israte, &mut self.z) - }) - }, - 4 => { // Low Pass Hal Chamberlin SVF - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, input, 2.0, 16000.0, { - let (_high, _notch) = - process_hal_chamberlin_svf( - input, freq, res, self.israte, - &mut self.z, &mut self.y); - self.y - }); - }, - 5 => { // High Pass Hal Chamberlin SVF - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, input, 16000.0, { - let (high, _notch) = - process_hal_chamberlin_svf( - input, freq, res, self.israte, - &mut self.z, &mut self.y); - high - }); - }, - 6 => { // Band Pass Hal Chamberlin SVF - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, input, 16000.0, { - let (_high, _notch) = - process_hal_chamberlin_svf( - input, freq, res, self.israte, - &mut self.z, &mut self.y); - self.z - }); - }, - 7 => { // Notch Hal Chamberlin SVF - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, input, 16000.0, { - let (_high, notch) = - process_hal_chamberlin_svf( - input, freq, res, self.israte, - &mut self.z, &mut self.y); - notch - }); - }, - 8 => { // Simper SVF Low Pass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { - let (low, _band, _high) = - process_simper_svf( - input, freq, res, self.israte, - &mut self.k, &mut self.h); - low - }); - }, - 9 => { // Simper SVF High Pass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { - let (_low, _band, high) = - process_simper_svf( - input, freq, res, self.israte, - &mut self.k, &mut self.h); - high - }); - }, - 10 => { // Simper SVF Band Pass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { - let (_low, band, _high) = - process_simper_svf( - input, freq, res, self.israte, - &mut self.k, &mut self.h); - band - }); - }, - 11 => { // Simper SVF Notch - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { - let (low, _band, high) = - process_simper_svf( - input, freq, res, self.israte, - &mut self.k, &mut self.h); - low + high - }); - }, - 12 => { // Simper SVF Peak - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { - let (low, _band, high) = - process_simper_svf( - input, freq, res, self.israte, - &mut self.k, &mut self.h); - low - high - }); - }, - 13 => { // Stilson/Moog Low Pass - process_filter_fun32!( - ctx.nframes(), inp, out, freq, res, 1.0, input, 20000.0, { - // Clip here, to prevent blowups, because the - // moog filter is quite touchy... - let input = input.clamp(-1.0, 1.0); - process_stilson_moog( - input, freq, res, self.israte, - &mut self.z, &mut self.y, &mut self.k, - &mut self.h, &mut self.delay) - }); - }, - _ => {}, + 0 => { + // Lowpass + process_filter_fun32!(ctx.nframes(), inp, out, freq, input, 22000.0, { + process_1pole_lowpass(input, freq, self.israte, &mut self.z) + }) + } + 1 => { + // Lowpass TPT + process_filter_fun32!(ctx.nframes(), inp, out, freq, input, 22000.0, { + process_1pole_tpt_lowpass(input, freq, self.israte, &mut self.z) + }) + } + 2 => { + // Highpass + process_filter_fun32!(ctx.nframes(), inp, out, freq, input, 22000.0, { + process_1pole_highpass(input, freq, self.israte, &mut self.z, &mut self.y) + }) + } + 3 => { + // Highpass TPT + process_filter_fun32!(ctx.nframes(), inp, out, freq, input, 22000.0, { + process_1pole_tpt_highpass(input, freq, self.israte, &mut self.z) + }) + } + 4 => { + // Low Pass Hal Chamberlin SVF + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, input, 2.0, 16000.0, { + let (_high, _notch) = process_hal_chamberlin_svf( + input, + freq, + res, + self.israte, + &mut self.z, + &mut self.y, + ); + self.y + }); + } + 5 => { + // High Pass Hal Chamberlin SVF + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, input, 16000.0, { + let (high, _notch) = process_hal_chamberlin_svf( + input, + freq, + res, + self.israte, + &mut self.z, + &mut self.y, + ); + high + }); + } + 6 => { + // Band Pass Hal Chamberlin SVF + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, input, 16000.0, { + let (_high, _notch) = process_hal_chamberlin_svf( + input, + freq, + res, + self.israte, + &mut self.z, + &mut self.y, + ); + self.z + }); + } + 7 => { + // Notch Hal Chamberlin SVF + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, input, 16000.0, { + let (_high, notch) = process_hal_chamberlin_svf( + input, + freq, + res, + self.israte, + &mut self.z, + &mut self.y, + ); + notch + }); + } + 8 => { + // Simper SVF Low Pass + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { + let (low, _band, _high) = + process_simper_svf(input, freq, res, self.israte, &mut self.k, &mut self.h); + low + }); + } + 9 => { + // Simper SVF High Pass + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { + let (_low, _band, high) = + process_simper_svf(input, freq, res, self.israte, &mut self.k, &mut self.h); + high + }); + } + 10 => { + // Simper SVF Band Pass + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { + let (_low, band, _high) = + process_simper_svf(input, freq, res, self.israte, &mut self.k, &mut self.h); + band + }); + } + 11 => { + // Simper SVF Notch + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { + let (low, _band, high) = + process_simper_svf(input, freq, res, self.israte, &mut self.k, &mut self.h); + low + high + }); + } + 12 => { + // Simper SVF Peak + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 22000.0, { + let (low, _band, high) = + process_simper_svf(input, freq, res, self.israte, &mut self.k, &mut self.h); + low - high + }); + } + 13 => { + // Stilson/Moog Low Pass + process_filter_fun32!(ctx.nframes(), inp, out, freq, res, 1.0, input, 20000.0, { + // Clip here, to prevent blowups, because the + // moog filter is quite touchy... + let input = input.clamp(-1.0, 1.0); + process_stilson_moog( + input, + freq, + res, + self.israte, + &mut self.z, + &mut self.y, + &mut self.k, + &mut self.h, + &mut self.delay, + ) + }); + } + _ => {} } ctx_vals[0].set(out.read(ctx.nframes() - 1)); diff --git a/src/dsp/node_sin.rs b/src/dsp/node_sin.rs index 0b7870c..9fe362a 100644 --- a/src/dsp/node_sin.rs +++ b/src/dsp/node_sin.rs @@ -2,12 +2,11 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, denorm_offs, - out, inp, DspNode, LedPhaseVals, NodeContext -}; use crate::dsp::helpers::fast_sin; +use crate::dsp::{ + denorm_offs, inp, out, DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, +}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; /// A sine oscillator #[derive(Debug, Clone)] @@ -20,38 +19,29 @@ pub struct Sin { init_phase: f32, } -const TWOPI : f32 = 2.0 * std::f32::consts::PI; +const TWOPI: f32 = 2.0 * std::f32::consts::PI; impl Sin { pub fn new(nid: &NodeId) -> Self { let init_phase = nid.init_phase(); - Self { - srate: 44100.0, - phase: init_phase, - init_phase, - } + Self { srate: 44100.0, phase: init_phase, init_phase } } - pub const freq : &'static str = - "Sin freq\nFrequency of the oscillator.\n\nRange: (-1..1)\n"; - pub const det : &'static str = - "Sin det\nDetune the oscillator in semitones and cents. \ + pub const freq: &'static str = "Sin freq\nFrequency of the oscillator.\n\nRange: (-1..1)\n"; + pub const det: &'static str = "Sin det\nDetune the oscillator in semitones and cents. \ the input of this value is rounded to semitones on coarse input. \ Fine input lets you detune in cents (rounded). \ A signal sent to this port is not rounded.\n\ Note: The signal input allows detune +-10 octaves.\ \nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n"; - pub const sig : &'static str = - "Sin sig\nOscillator signal output.\n\nRange: (-1..1)\n"; + pub const sig: &'static str = "Sin sig\nOscillator signal output.\n\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Sine Oscillator + pub const DESC: &'static str = r#"Sine Oscillator This is a very simple oscillator that generates a sine wave. "#; - pub const HELP : &'static str = -r#"Sin - A Sine Oscillator + pub const HELP: &'static str = r#"Sin - A Sine Oscillator This is a very simple oscillator that generates a sine wave. The 'freq' paramter specifies the frequency, and the 'det' parameter @@ -68,7 +58,9 @@ nodes available. } impl DspNode for Sin { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.srate = srate; @@ -80,15 +72,19 @@ impl DspNode for Sin { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - let o = out::Sin::sig(outputs); + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + let o = out::Sin::sig(outputs); let freq = inp::Sin::freq(inputs); - let det = inp::Sin::det(inputs); - let isr = 1.0 / self.srate; + let det = inp::Sin::det(inputs); + let isr = 1.0 / self.srate; let mut last_val = 0.0; for frame in 0..ctx.nframes() { diff --git a/src/dsp/node_smap.rs b/src/dsp/node_smap.rs index f26843e..cb69fb4 100644 --- a/src/dsp/node_smap.rs +++ b/src/dsp/node_smap.rs @@ -2,70 +2,63 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; #[macro_export] -macro_rules! fa_smap_clip { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Off", - 1 => "Clip", - _ => "?", +macro_rules! fa_smap_clip { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Off", + 1 => "Clip", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} #[macro_export] -macro_rules! fa_smap_mode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Unipolar", - 1 => "Bipolar", - 2 => "UniInv", - 3 => "BiInv", - _ => "", +macro_rules! fa_smap_mode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Unipolar", + 1 => "Bipolar", + 2 => "UniInv", + 3 => "BiInv", + _ => "", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} /// A simple amplifier #[derive(Debug, Clone)] -pub struct SMap { -} +pub struct SMap {} impl SMap { pub fn new(_nid: &NodeId) -> Self { - Self { - } + Self {} } - pub const inp : &'static str = - "SMap inp\nSignal input\nRange: (-1..1)\n"; - pub const min : &'static str = - "SMap min\nMinimum of the output signal range.\nRange: (0..1)\n"; - pub const max : &'static str = - "SMap max\nMaximum of the output signal range.\nRange: (0..1)\n"; - pub const clip : &'static str = - "SMap clip\nThe 'clip' mode allows you to limit the output \ + pub const inp: &'static str = "SMap inp\nSignal input\nRange: (-1..1)\n"; + pub const min: &'static str = "SMap min\nMinimum of the output signal range.\nRange: (0..1)\n"; + pub const max: &'static str = "SMap max\nMaximum of the output signal range.\nRange: (0..1)\n"; + pub const clip: &'static str = "SMap clip\nThe 'clip' mode allows you to limit the output \ exactly to the 'min'/'max' range. If this is off, the output \ may be outside the output signal range."; - pub const mode : &'static str = + pub const mode: &'static str = "SMap mode\nThis mode defines what kind of input signal is expected \ and how it will be mapped to the output 'min'/'max' range. \ These modes are available:\ \nUnipolar (0..1) / Bipolar (-1..1)\ \nUniInv (1..0) / BiInv (1..-1)"; - pub const sig : &'static str = - "SMap sig\nMapped signal output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"Simple Range Mapper + pub const sig: &'static str = "SMap sig\nMapped signal output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"Simple Range Mapper This node allows to map an unipolar (0..1) or bipolar signal (-1..1) to a defined 'min'/'max' signal range. See also the 'Map' node for a more sophisticated version of this. "#; - pub const HELP : &'static str = -r#"SMap - Simple Range Mapper + pub const HELP: &'static str = r#"SMap - Simple Range Mapper This node allows to map an unipolar (0..1) or bipolar signal (-1..1) to a defined 'min'/'max' signal range. @@ -86,28 +79,33 @@ And 1 to 'min' and -1 to 'max' for 'BiInv'. For a more sophisticated version of this node see also 'Map'. "#; - } impl DspNode for SMap { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } - fn set_sample_rate(&mut self, _srate: f32) { } - fn reset(&mut self) { } + fn set_sample_rate(&mut self, _srate: f32) {} + fn reset(&mut self) {} #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, inp, out}; - let inp = inp::SMap::inp(inputs); - let min = inp::SMap::min(inputs); - let max = inp::SMap::max(inputs); - let out = out::SMap::sig(outputs); + let inp = inp::SMap::inp(inputs); + let min = inp::SMap::min(inputs); + let max = inp::SMap::max(inputs); + let out = out::SMap::sig(outputs); let clip = at::SMap::clip(atoms); let mode = at::SMap::mode(atoms); @@ -117,80 +115,80 @@ impl DspNode for SMap { match (mode.i(), clip.i()) { (0, 0) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); last_val = s; out.write(frame, min + (max - min) * s); } - }, + } (0, 1) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); let s = s.clamp(0.0, 1.0); last_val = s; out.write(frame, min + (max - min) * s); } - }, + } (1, 0) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); let s = (s + 1.0) * 0.5; out.write(frame, min + (max - min) * s); } - }, + } (1, 1) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); let s = ((s + 1.0) * 0.5).clamp(0.0, 1.0); out.write(frame, min + (max - min) * s); } - }, + } (2, 0) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); - let s = 1.0 - s; + let s = 1.0 - s; last_val = s; out.write(frame, min + (max - min) * s); } - }, + } (2, 1) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); - let s = 1.0 - s.clamp(0.0, 1.0); + let s = 1.0 - s.clamp(0.0, 1.0); last_val = s; out.write(frame, min + (max - min) * s); } - }, + } (3, 0) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); let s = 1.0 - ((s + 1.0) * 0.5); out.write(frame, min + (max - min) * s); } - }, + } (3, 1) => { for frame in 0..ctx.nframes() { - let s = inp.read(frame); + let s = inp.read(frame); let min = min.read(frame); let max = max.read(frame); let s = 1.0 - ((s + 1.0) * 0.5).clamp(0.0, 1.0); out.write(frame, min + (max - min) * s); } - }, - _ => {}, + } + _ => {} } ctx_vals[0].set(last_val); diff --git a/src/dsp/node_test.rs b/src/dsp/node_test.rs index da85733..5b36563 100644 --- a/src/dsp/node_test.rs +++ b/src/dsp/node_test.rs @@ -2,65 +2,67 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; +use crate::dsp::helpers::TrigSignal; use crate::dsp::{ - NodeId, SAtom, ProcBuf, GraphFun, GraphAtomData, DspNode, LedPhaseVals, - NodeContext + DspNode, GraphAtomData, GraphFun, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, }; -use crate::dsp::helpers::{TrigSignal}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_test_s { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Zero", - 1 => "One", - 2 => "Two", - 3 => "Three", - 4 => "Four", - 5 => "Five", - 6 => "Six", - 7 => "Seven", - 8 => "Eigth", - 9 => "Nine", - 10 => "Ten", - _ => "?", - }; +macro_rules! fa_test_s { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Zero", + 1 => "One", + 2 => "Two", + 3 => "Three", + 4 => "Four", + 5 => "Five", + 6 => "Six", + 7 => "Seven", + 8 => "Eigth", + 9 => "Nine", + 10 => "Ten", + _ => "?", + }; write!($formatter, "{}", s) -} } } + }}; +} /// A simple amplifier #[derive(Debug, Clone)] pub struct Test { - trig_sig: TrigSignal, - trigger: bool, + trig_sig: TrigSignal, + trigger: bool, } impl Test { pub fn new(_nid: &NodeId) -> Self { - Self { - trigger: false, - trig_sig: TrigSignal::new(), - } + Self { trigger: false, trig_sig: TrigSignal::new() } } - pub const f : &'static str = "F Test"; - pub const p : &'static str = "Test p\nAn unsmoothed parameter for automated tests."; + pub const f: &'static str = "F Test"; + pub const p: &'static str = "Test p\nAn unsmoothed parameter for automated tests."; pub const trig: &'static str = "Test trig\nA trigger input, that will create a short pulse on the 'tsig' output.\nRange: (-1..1)"; - pub const sig : &'static str = "Test sig\nThe output of p as signal"; - pub const tsig : &'static str = "Test tsig\nA short trigger pulse will be generated when the 'trig' input is triggered."; - pub const out2 : &'static str = "Test out2\nA test output that will emit 1.0 if output 'sig' is connected."; - pub const out3 : &'static str = "Test out3\nA test output that will emit 1.0 if input 'f' is connected."; - pub const out4 : &'static str = "Test out4\n"; - pub const outc : &'static str = "Test outc\nEmits a number that defines the out_connected bitmask. Used only for testing!"; - - pub const DESC : &'static str = r#""#; - pub const HELP : &'static str = r#""#; + pub const sig: &'static str = "Test sig\nThe output of p as signal"; + pub const tsig: &'static str = + "Test tsig\nA short trigger pulse will be generated when the 'trig' input is triggered."; + pub const out2: &'static str = + "Test out2\nA test output that will emit 1.0 if output 'sig' is connected."; + pub const out3: &'static str = + "Test out3\nA test output that will emit 1.0 if input 'f' is connected."; + pub const out4: &'static str = "Test out4\n"; + pub const outc: &'static str = + "Test outc\nEmits a number that defines the out_connected bitmask. Used only for testing!"; + pub const DESC: &'static str = r#""#; + pub const HELP: &'static str = r#""#; } impl DspNode for Test { - fn outputs() -> usize { 2 } + fn outputs() -> usize { + 2 + } fn set_sample_rate(&mut self, srate: f32) { self.trig_sig.set_sample_rate(srate); @@ -72,32 +74,34 @@ impl DspNode for Test { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, nctx: &NodeContext, - atoms: &[SAtom], _inputs: &[ProcBuf], - outputs: &mut [ProcBuf], _led: LedPhaseVals) - { - use crate::dsp::{out_idx, at, is_out_con, out_buf, is_in_con}; + atoms: &[SAtom], + _inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + _led: LedPhaseVals, + ) { + use crate::dsp::{at, is_in_con, is_out_con, out_buf, out_idx}; - let p = at::Test::p(atoms); - let trig = at::Test::trig(atoms); - let tsig = out_idx::Test::tsig(); + let p = at::Test::p(atoms); + let trig = at::Test::trig(atoms); + let tsig = out_idx::Test::tsig(); - let mut out2 = out_buf::Test::out2(outputs); - let mut out3 = out_buf::Test::out3(outputs); - let mut outc = out_buf::Test::outc(outputs); + let mut out2 = out_buf::Test::out2(outputs); + let mut out3 = out_buf::Test::out3(outputs); + let mut outc = out_buf::Test::outc(outputs); let (out, tsig) = outputs.split_at_mut(tsig); - let out = &mut out[0]; + let out = &mut out[0]; let tsig = &mut tsig[0]; let mut trigger = trig.i(); if !self.trigger && trigger > 0 { self.trigger = true; - } else if !self.trigger && trigger == 0 { self.trigger = false; - } else if self.trigger { trigger = 0; } @@ -112,17 +116,13 @@ impl DspNode for Test { let t = self.trig_sig.next(); tsig.write(frame, t); - out2.write(frame, - if is_out_con::Test::sig(nctx) { 1.0 } else { 0.0 }); - out3.write(frame, - if is_in_con::Test::f(nctx) { 1.0 } else { 0.0 }); + out2.write(frame, if is_out_con::Test::sig(nctx) { 1.0 } else { 0.0 }); + out3.write(frame, if is_in_con::Test::f(nctx) { 1.0 } else { 0.0 }); outc.write(frame, nctx.out_connected as f32); } } fn graph_fun() -> Option { - Some(Box::new(|_gd: &dyn GraphAtomData, _init: bool, x: f32, _xn: f32| -> f32 { - x - })) + Some(Box::new(|_gd: &dyn GraphAtomData, _init: bool, x: f32, _xn: f32| -> f32 { x })) } } diff --git a/src/dsp/node_tseq.rs b/src/dsp/node_tseq.rs index b359a8e..215cee1 100644 --- a/src/dsp/node_tseq.rs +++ b/src/dsp/node_tseq.rs @@ -2,53 +2,52 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::helpers::{TriggerPhaseClock, Trigger}; -use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; +use crate::dsp::helpers::{Trigger, TriggerPhaseClock}; use crate::dsp::tracker::TrackerBackend; +use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::dsp::MAX_BLOCK_SIZE; #[macro_export] -macro_rules! fa_tseq_cmode { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "RowT", - 1 => "PatT", - 2 => "Phase", - _ => "?", +macro_rules! fa_tseq_cmode { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "RowT", + 1 => "PatT", + 2 => "Phase", + _ => "?", }; - write!($formatter, "{}", s) -} } } - + write!($formatter, "{}", s) + }}; +} #[derive(Debug)] pub struct TSeqTime { - clock: TriggerPhaseClock, - trigger: Trigger, + clock: TriggerPhaseClock, + trigger: Trigger, } /// A tracker based sequencer #[derive(Debug)] pub struct TSeq { - backend: Option>, - srate: f64, - time: Box, + backend: Option>, + srate: f64, + time: Box, } impl Clone for TSeq { - fn clone(&self) -> Self { Self::new(&NodeId::Nop) } + fn clone(&self) -> Self { + Self::new(&NodeId::Nop) + } } impl TSeq { pub fn new(_nid: &NodeId) -> Self { Self { - backend: None, - srate: 48000.0, - time: Box::new(TSeqTime { - clock: TriggerPhaseClock::new(), - trigger: Trigger::new(), - }), + backend: None, + srate: 48000.0, + time: Box::new(TSeqTime { clock: TriggerPhaseClock::new(), trigger: Trigger::new() }), } } @@ -56,49 +55,33 @@ impl TSeq { self.backend = Some(Box::new(backend)); } - pub const clock : &'static str = - "TSeq clock\nClock input\nRange: (0..1)\n"; - pub const trig : &'static str = + pub const clock: &'static str = "TSeq clock\nClock input\nRange: (0..1)\n"; + pub const trig: &'static str = "TSeq trig\nSynchronization trigger which restarts the sequence.\nRange: (-1..1)\n"; - pub const cmode : &'static str = - "TSeq cmode\n'clock' input signal mode:\n\ + pub const cmode: &'static str = "TSeq cmode\n'clock' input signal mode:\n\ - RowT: Trigger = advance row\n\ - PatT: Trigger = pattern rate\n\ - Phase: Phase to pattern index\n\ \n"; - pub const trk1 : &'static str = - "TSeq trk1\nTrack 1 signal output\nRange: (-1..1)\n"; - pub const trk2 : &'static str = - "TSeq trk2\nTrack 2 signal output\nRange: (-1..1)\n"; - pub const trk3 : &'static str = - "TSeq trk3\nTrack 3 signal output\nRange: (-1..1)\n"; - pub const trk4 : &'static str = - "TSeq trk4\nTrack 4 signal output\nRange: (-1..1)\n"; - pub const trk5 : &'static str = - "TSeq trk5\nTrack 5 signal output\nRange: (-1..1)\n"; - pub const trk6 : &'static str = - "TSeq trk6\nTrack 6 signal output\nRange: (-1..1)\n"; + pub const trk1: &'static str = "TSeq trk1\nTrack 1 signal output\nRange: (-1..1)\n"; + pub const trk2: &'static str = "TSeq trk2\nTrack 2 signal output\nRange: (-1..1)\n"; + pub const trk3: &'static str = "TSeq trk3\nTrack 3 signal output\nRange: (-1..1)\n"; + pub const trk4: &'static str = "TSeq trk4\nTrack 4 signal output\nRange: (-1..1)\n"; + pub const trk5: &'static str = "TSeq trk5\nTrack 5 signal output\nRange: (-1..1)\n"; + pub const trk6: &'static str = "TSeq trk6\nTrack 6 signal output\nRange: (-1..1)\n"; - pub const gat1 : &'static str = - "TSeq gat1\nTrack 1 gate output\nRange: (-1..1)\n"; - pub const gat2 : &'static str = - "TSeq gat2\nTrack 2 gate output\nRange: (-1..1)\n"; - pub const gat3 : &'static str = - "TSeq gat3\nTrack 3 gate output\nRange: (-1..1)\n"; - pub const gat4 : &'static str = - "TSeq gat4\nTrack 4 gate output\nRange: (-1..1)\n"; - pub const gat5 : &'static str = - "TSeq gat5\nTrack 5 gate output\nRange: (-1..1)\n"; - pub const gat6 : &'static str = - "TSeq gat6\nTrack 6 gate output\nRange: (-1..1)\n"; + pub const gat1: &'static str = "TSeq gat1\nTrack 1 gate output\nRange: (-1..1)\n"; + pub const gat2: &'static str = "TSeq gat2\nTrack 2 gate output\nRange: (-1..1)\n"; + pub const gat3: &'static str = "TSeq gat3\nTrack 3 gate output\nRange: (-1..1)\n"; + pub const gat4: &'static str = "TSeq gat4\nTrack 4 gate output\nRange: (-1..1)\n"; + pub const gat5: &'static str = "TSeq gat5\nTrack 5 gate output\nRange: (-1..1)\n"; + pub const gat6: &'static str = "TSeq gat6\nTrack 6 gate output\nRange: (-1..1)\n"; - pub const DESC : &'static str = - "Tracker Sequencer\n\n\ + pub const DESC: &'static str = "Tracker Sequencer\n\n\ This node implements a sequencer that can be programmed \ using the tracker interface in HexoSynth on the right.\n\ It provides 6 control signals and 6 gate outputs."; - pub const HELP : &'static str = -r#"Tracker (based) Sequencer + pub const HELP: &'static str = r#"Tracker (based) Sequencer This sequencer gets it's speed from the clock source. The 'clock' signal can be interpreted in different modes. But if you want to @@ -179,7 +162,9 @@ Tip: } impl DspNode for TSeq { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.srate = srate as f64; @@ -193,60 +178,58 @@ impl DspNode for TSeq { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, at, denorm}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, inp, out}; let clock = inp::TSeq::clock(inputs); - let trig = inp::TSeq::trig(inputs); + let trig = inp::TSeq::trig(inputs); let cmode = at::TSeq::cmode(atoms); - let backend = - if let Some(backend) = &mut self.backend { - backend - } else { return; }; + let backend = if let Some(backend) = &mut self.backend { + backend + } else { + return; + }; backend.check_updates(); - let mut phase_out : [f32; MAX_BLOCK_SIZE] = - [0.0; MAX_BLOCK_SIZE]; + let mut phase_out: [f32; MAX_BLOCK_SIZE] = [0.0; MAX_BLOCK_SIZE]; let cmode = cmode.i(); - let plen = backend.pattern_len().max(1) as f64; + let plen = backend.pattern_len().max(1) as f64; let time = &mut self.time; for frame in 0..ctx.nframes() { - if time.trigger.check_trigger( - denorm::TSeq::trig(trig, frame)) - { + if time.trigger.check_trigger(denorm::TSeq::trig(trig, frame)) { time.clock.sync(); println!("CLOCK SYNC"); } - let phase = - match cmode { - 0 => time.clock.next_phase(plen, clock.read(frame)) / plen, - 1 => time.clock.next_phase(1.0, clock.read(frame)), - 2 | _ => (clock.read(frame).abs() as f64).fract(), - }; + let phase = match cmode { + 0 => time.clock.next_phase(plen, clock.read(frame)) / plen, + 1 => time.clock.next_phase(1.0, clock.read(frame)), + 2 | _ => (clock.read(frame).abs() as f64).fract(), + }; phase_out[frame] = phase as f32; } - let mut col_out : [f32; MAX_BLOCK_SIZE] = - [0.0; MAX_BLOCK_SIZE]; - let mut col_out_gate : [f32; MAX_BLOCK_SIZE] = - [0.0; MAX_BLOCK_SIZE]; - let col_out_slice = &mut col_out[ 0..ctx.nframes()]; - let col_out_gate_slice = &mut col_out_gate[0..ctx.nframes()]; - let phase_out_slice = &phase_out[ 0..ctx.nframes()]; + let mut col_out: [f32; MAX_BLOCK_SIZE] = [0.0; MAX_BLOCK_SIZE]; + let mut col_out_gate: [f32; MAX_BLOCK_SIZE] = [0.0; MAX_BLOCK_SIZE]; + let col_out_slice = &mut col_out[0..ctx.nframes()]; + let col_out_gate_slice = &mut col_out_gate[0..ctx.nframes()]; + let phase_out_slice = &phase_out[0..ctx.nframes()]; let out_t1 = out::TSeq::trk1(outputs); - backend.get_col_at_phase( - 0, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(0, phase_out_slice, col_out_slice, col_out_gate_slice); out_t1.write_from(col_out_slice); let out_g1 = out::TSeq::gat1(outputs); @@ -255,40 +238,35 @@ impl DspNode for TSeq { ctx_vals[0].set(col_out_slice[col_out_slice.len() - 1]); let out_t2 = out::TSeq::trk2(outputs); - backend.get_col_at_phase( - 1, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(1, phase_out_slice, col_out_slice, col_out_gate_slice); out_t2.write_from(col_out_slice); let out_g2 = out::TSeq::gat2(outputs); out_g2.write_from(col_out_gate_slice); let out_t3 = out::TSeq::trk3(outputs); - backend.get_col_at_phase( - 2, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(2, phase_out_slice, col_out_slice, col_out_gate_slice); out_t3.write_from(col_out_slice); let out_g3 = out::TSeq::gat3(outputs); out_g3.write_from(col_out_gate_slice); let out_t4 = out::TSeq::trk4(outputs); - backend.get_col_at_phase( - 3, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(3, phase_out_slice, col_out_slice, col_out_gate_slice); out_t4.write_from(col_out_slice); let out_g4 = out::TSeq::gat4(outputs); out_g4.write_from(col_out_gate_slice); let out_t5 = out::TSeq::trk5(outputs); - backend.get_col_at_phase( - 4, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(4, phase_out_slice, col_out_slice, col_out_gate_slice); out_t5.write_from(col_out_slice); let out_g5 = out::TSeq::gat5(outputs); out_g5.write_from(col_out_gate_slice); let out_t6 = out::TSeq::trk6(outputs); - backend.get_col_at_phase( - 5, phase_out_slice, col_out_slice, col_out_gate_slice); + backend.get_col_at_phase(5, phase_out_slice, col_out_slice, col_out_gate_slice); out_t6.write_from(col_out_slice); let out_g6 = out::TSeq::gat6(outputs); diff --git a/src/dsp/node_tslfo.rs b/src/dsp/node_tslfo.rs index 436f600..eff09d5 100644 --- a/src/dsp/node_tslfo.rs +++ b/src/dsp/node_tslfo.rs @@ -2,48 +2,41 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; -use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, - GraphAtomData, GraphFun, NodeContext, -}; use super::helpers::{TriSawLFO, Trigger}; +use crate::dsp::{ + DspNode, GraphAtomData, GraphFun, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, +}; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[derive(Debug, Clone)] pub struct TsLFO { - lfo: Box>, - trig: Trigger, + lfo: Box>, + trig: Trigger, } impl TsLFO { pub fn new(_nid: &NodeId) -> Self { - Self { - lfo: Box::new(TriSawLFO::new()), - trig: Trigger::new(), - } + Self { lfo: Box::new(TriSawLFO::new()), trig: Trigger::new() } } - pub const time : &'static str = + pub const time: &'static str = "TsLFO time\nThe frequency or period time of the LFO, goes all the \ way from 0.1ms up to 30s. Please note, that the text entry is always \ in milliseconds.\nRange: (0..1)\n"; - pub const trig : &'static str = + pub const trig: &'static str = "TsLFO trig\nTriggers a phase reset of the LFO.\nRange: (0..1)\n"; - pub const rev : &'static str = + pub const rev: &'static str = "TsLFO rev\nThe reverse point of the LFO waveform. At 0.5 the LFO \ will follow a triangle waveform. At 0.0 or 1.0 the LFO waveform will \ be (almost) a (reversed) saw tooth. Node: A perfect sawtooth can not be \ achieved with this oscillator, as there will always be a minimal \ rise/fall time.\nRange: (0..1)\n"; - pub const sig : &'static str = - "TsLFO sig\nThe LFO output.\nRange: (0..1)"; - pub const DESC : &'static str = -r#"TriSaw LFO + pub const sig: &'static str = "TsLFO sig\nThe LFO output.\nRange: (0..1)"; + pub const DESC: &'static str = r#"TriSaw LFO This simple LFO has a configurable waveform. You can blend between triangular to sawtooth waveforms using the 'rev' parameter. "#; - pub const HELP : &'static str = -r#"TsLFO - TriSaw LFO + pub const HELP: &'static str = r#"TsLFO - TriSaw LFO This simple LFO has a configurable waveform. You can blend between triangular to sawtooth waveforms using the 'rev' parameter. @@ -51,11 +44,12 @@ triangular to sawtooth waveforms using the 'rev' parameter. Using the 'trig' input you can reset the LFO phase, which allows to use it kind of like an envelope. "#; - } impl DspNode for TsLFO { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.lfo.set_sample_rate(srate as f64); @@ -68,17 +62,21 @@ impl DspNode for TsLFO { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - _atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm}; + _atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{denorm, inp, out}; let time = inp::TsLFO::time(inputs); let trig = inp::TsLFO::trig(inputs); - let rev = inp::TsLFO::rev(inputs); - let out = out::TsLFO::sig(outputs); + let rev = inp::TsLFO::rev(inputs); + let out = out::TsLFO::sig(outputs); let lfo = &mut *self.lfo; @@ -89,9 +87,7 @@ impl DspNode for TsLFO { let time_ms = denorm::TsLFO::time(time, frame).clamp(0.1, 300000.0); - lfo.set( - (1000.0 / time_ms) as f64, - denorm::TsLFO::rev(rev, frame) as f64); + lfo.set((1000.0 / time_ms) as f64, denorm::TsLFO::rev(rev, frame) as f64); out.write(frame, lfo.next_unipolar() as f32); } @@ -107,10 +103,10 @@ impl DspNode for TsLFO { if init { lfo.reset(); let time_idx = NodeId::TsLFO(0).inp_param("time").unwrap().inp(); - let rev_idx = NodeId::TsLFO(0).inp_param("rev").unwrap().inp(); + let rev_idx = NodeId::TsLFO(0).inp_param("rev").unwrap().inp(); let time = gd.get_norm(time_idx as u32).sqrt(); - let rev = gd.get_norm(rev_idx as u32); + let rev = gd.get_norm(rev_idx as u32); lfo.set(5.0 * (1.0 - time) + time * 1.0, rev); } diff --git a/src/dsp/node_vosc.rs b/src/dsp/node_vosc.rs index 9503733..1f04bdc 100644 --- a/src/dsp/node_vosc.rs +++ b/src/dsp/node_vosc.rs @@ -2,32 +2,32 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::dsp::biquad::Oversampling; -use crate::dsp::helpers::{VPSOscillator, apply_distortion}; +use crate::dsp::helpers::{apply_distortion, VPSOscillator}; use crate::dsp::{ - NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, - GraphAtomData, GraphFun, + DspNode, GraphAtomData, GraphFun, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom, }; +use crate::nodes::{NodeAudioContext, NodeExecContext}; #[macro_export] -macro_rules! fa_vosc_ovrsmpl { ($formatter: expr, $v: expr, $denorm_v: expr) => { { - let s = - match ($v.round() as usize) { - 0 => "Off", - 1 => "On", - _ => "?", +macro_rules! fa_vosc_ovrsmpl { + ($formatter: expr, $v: expr, $denorm_v: expr) => {{ + let s = match ($v.round() as usize) { + 0 => "Off", + 1 => "On", + _ => "?", }; - write!($formatter, "{}", s) -} } } + write!($formatter, "{}", s) + }}; +} -const OVERSAMPLING : usize = 4; +const OVERSAMPLING: usize = 4; /// A simple amplifier #[derive(Debug, Clone)] pub struct VOsc { israte: f32, - osc: VPSOscillator, + osc: VPSOscillator, oversampling: Box>, } @@ -36,61 +36,54 @@ impl VOsc { let init_phase = nid.init_phase(); Self { - israte: 1.0 / 44100.0, - osc: VPSOscillator::new(init_phase), + israte: 1.0 / 44100.0, + osc: VPSOscillator::new(init_phase), oversampling: Box::new(Oversampling::new()), } } - pub const freq : &'static str = + pub const freq: &'static str = "VOsc freq\nBase frequency of the oscillator.\n\nRange: (-1..1)\n"; - pub const det : &'static str = - "VOsc det\nDetune the oscillator in semitones and cents. \ + pub const det: &'static str = "VOsc det\nDetune the oscillator in semitones and cents. \ the input of this value is rounded to semitones on coarse input. \ Fine input lets you detune in cents (rounded). \ A signal sent to this port is not rounded.\n\ Note: The signal input allows detune +-10 octaves.\ \nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n"; - pub const d : &'static str = - "VOsc d\nThis is the horzontal bending point of the waveform. \ + pub const d: &'static str = "VOsc d\nThis is the horzontal bending point of the waveform. \ It has a similar effect that pulse width settings have on other \ oscillators. Make sure to try modulating this parameter at audio rate!\ \nRange: (0..1)\n"; - pub const v : &'static str = - "VOsc v\nThis is the vertical bending point of the waveform. \ + pub const v: &'static str = "VOsc v\nThis is the vertical bending point of the waveform. \ You can adjust the effect that 'd' has on the waveform with this \ parameter. Make sure to try to modulate this parameter at audio rate!\ \nRange: (0..1)\n"; - pub const vs : &'static str = + pub const vs: &'static str = "VOsc vs\nScaling factor for 'v'. If you increase this beyond 1.0, \ you will hear formant like sounds from the oscillator. Try adjusting \ 'd' to move the formants around.\nRange: (0..1)\n"; - pub const dist : &'static str = + pub const dist: &'static str = "VOsc dist\nA collection of waveshaper/distortions to choose from."; - pub const damt : &'static str = - "VOsc damt\nDistortion amount.\nRange: (0..1)\n"; - pub const ovrsmpl : &'static str = - "VOsc ovrsmpl\nEnable/Disable oversampling."; - pub const sig : &'static str = - "VOsc sig\nOscillator output\nRange: (-1..1)\n"; - pub const DESC : &'static str = -r#"V Oscillator + pub const damt: &'static str = "VOsc damt\nDistortion amount.\nRange: (0..1)\n"; + pub const ovrsmpl: &'static str = "VOsc ovrsmpl\nEnable/Disable oversampling."; + pub const sig: &'static str = "VOsc sig\nOscillator output\nRange: (-1..1)\n"; + pub const DESC: &'static str = r#"V Oscillator A vector phase shaping oscillator, to create interesting waveforms and ways to manipulate them. It has two parameters ('v' and 'd') to shape the phase of the sinusoid wave, and a 'vs' parameter to add extra spice. Distortion can beef up the oscillator output and you can apply oversampling. "#; - pub const HELP : &'static str = -r#"VOsc - Vector Phase Shaping Oscillator + pub const HELP: &'static str = r#"VOsc - Vector Phase Shaping Oscillator A vector phase shaping oscillator, to create interesting waveforms and ways to manipulate them. It has two parameters ('v' and 'd') to shape the phase of the sinusoid wave, and a third parameter 'vs' to add extra spice. With distortion you can beef up the oscillator output even more and to make it more harmonic you can apply oversampling. "#; - } impl DspNode for VOsc { - fn outputs() -> usize { 1 } + fn outputs() -> usize { + 1 + } fn set_sample_rate(&mut self, srate: f32) { self.israte = 1.0 / (srate * (OVERSAMPLING as f32)); @@ -104,26 +97,30 @@ impl DspNode for VOsc { #[inline] fn process( - &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + &mut self, + ctx: &mut T, + _ectx: &mut NodeExecContext, _nctx: &NodeContext, - atoms: &[SAtom], inputs: &[ProcBuf], - outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) - { - use crate::dsp::{out, inp, denorm, denorm_offs, at}; + atoms: &[SAtom], + inputs: &[ProcBuf], + outputs: &mut [ProcBuf], + ctx_vals: LedPhaseVals, + ) { + use crate::dsp::{at, denorm, denorm_offs, inp, out}; - let freq = inp::VOsc::freq(inputs); - let det = inp::VOsc::det(inputs); - let d = inp::VOsc::d(inputs); - let v = inp::VOsc::v(inputs); - let vs = inp::VOsc::vs(inputs); - let damt = inp::VOsc::damt(inputs); - let out = out::VOsc::sig(outputs); + let freq = inp::VOsc::freq(inputs); + let det = inp::VOsc::det(inputs); + let d = inp::VOsc::d(inputs); + let v = inp::VOsc::v(inputs); + let vs = inp::VOsc::vs(inputs); + let damt = inp::VOsc::damt(inputs); + let out = out::VOsc::sig(outputs); let ovrsmpl = at::VOsc::ovrsmpl(atoms); - let dist = at::VOsc::dist(atoms); + let dist = at::VOsc::dist(atoms); let israte = self.israte; - let dist = dist.i() as u8; + let dist = dist.i() as u8; let oversample = ovrsmpl.i() == 1; let osc = &mut self.osc; @@ -131,9 +128,9 @@ impl DspNode for VOsc { if oversample { for frame in 0..ctx.nframes() { let freq = denorm_offs::VOsc::freq(freq, det.read(frame), frame); - let v = denorm::VOsc::v(v, frame).clamp(0.0, 1.0); - let d = denorm::VOsc::d(d, frame).clamp(0.0, 1.0); - let vs = denorm::VOsc::vs(vs, frame).clamp(0.0, 20.0); + let v = denorm::VOsc::v(v, frame).clamp(0.0, 1.0); + let d = denorm::VOsc::d(d, frame).clamp(0.0, 1.0); + let vs = denorm::VOsc::vs(vs, frame).clamp(0.0, 20.0); let damt = denorm::VOsc::damt(damt, frame).clamp(0.0, 1.0); let v = VPSOscillator::limit_v(d, v + vs); @@ -146,13 +143,12 @@ impl DspNode for VOsc { out.write(frame, self.oversampling.downsample()); } - } else { for frame in 0..ctx.nframes() { let freq = denorm_offs::VOsc::freq(freq, det.read(frame), frame); - let v = denorm::VOsc::v(v, frame).clamp(0.0, 1.0); - let d = denorm::VOsc::d(d, frame).clamp(0.0, 1.0); - let vs = denorm::VOsc::vs(vs, frame).clamp(0.0, 20.0); + let v = denorm::VOsc::v(v, frame).clamp(0.0, 1.0); + let d = denorm::VOsc::d(d, frame).clamp(0.0, 1.0); + let vs = denorm::VOsc::vs(vs, frame).clamp(0.0, 20.0); let damt = denorm::VOsc::damt(damt, frame).clamp(0.0, 1.0); let v = VPSOscillator::limit_v(d, v + vs); @@ -175,17 +171,17 @@ impl DspNode for VOsc { osc.reset(); } - let v = NodeId::VOsc(0).inp_param("v").unwrap().inp(); - let vs = NodeId::VOsc(0).inp_param("vs").unwrap().inp(); - let d = NodeId::VOsc(0).inp_param("d").unwrap().inp(); - let damt = NodeId::VOsc(0).inp_param("damt").unwrap().inp(); - let dist = NodeId::VOsc(0).inp_param("dist").unwrap().inp(); + let v = NodeId::VOsc(0).inp_param("v").unwrap().inp(); + let vs = NodeId::VOsc(0).inp_param("vs").unwrap().inp(); + let d = NodeId::VOsc(0).inp_param("d").unwrap().inp(); + let damt = NodeId::VOsc(0).inp_param("damt").unwrap().inp(); + let dist = NodeId::VOsc(0).inp_param("dist").unwrap().inp(); - let v = gd.get_denorm(v as u32).clamp(0.0, 1.0); - let d = gd.get_denorm(d as u32).clamp(0.0, 1.0); - let vs = gd.get_denorm(vs as u32).clamp(0.0, 20.0); - let damt = gd.get_denorm(damt as u32); - let dist = gd.get(dist as u32).map(|a| a.i()).unwrap_or(0); + let v = gd.get_denorm(v as u32).clamp(0.0, 1.0); + let d = gd.get_denorm(d as u32).clamp(0.0, 1.0); + let vs = gd.get_denorm(vs as u32).clamp(0.0, 20.0); + let damt = gd.get_denorm(damt as u32); + let dist = gd.get(dist as u32).map(|a| a.i()).unwrap_or(0); let v = VPSOscillator::limit_v(d, v + vs); let s = osc.next(1.0, israte, d, v); diff --git a/src/dsp/satom.rs b/src/dsp/satom.rs index d437bca..66507dc 100644 --- a/src/dsp/satom.rs +++ b/src/dsp/satom.rs @@ -12,10 +12,18 @@ pub enum SAtom { } impl SAtom { - pub fn str(s: &str) -> Self { SAtom::Str(s.to_string()) } - pub fn setting(s: i64) -> Self { SAtom::Setting(s) } - pub fn param(p: f32) -> Self { SAtom::Param(p) } - pub fn micro(m: &[f32]) -> Self { SAtom::MicroSample(m.to_vec()) } + pub fn str(s: &str) -> Self { + SAtom::Str(s.to_string()) + } + pub fn setting(s: i64) -> Self { + SAtom::Setting(s) + } + pub fn param(p: f32) -> Self { + SAtom::Param(p) + } + pub fn micro(m: &[f32]) -> Self { + SAtom::MicroSample(m.to_vec()) + } pub fn audio(s: &str, m: std::sync::Arc>) -> Self { SAtom::AudioSample((s.to_string(), Some(m))) } @@ -26,61 +34,66 @@ impl SAtom { pub fn default_of(&self) -> Self { match self { - SAtom::Str(_) => SAtom::Str("".to_string()), + SAtom::Str(_) => SAtom::Str("".to_string()), SAtom::MicroSample(_) => SAtom::MicroSample(vec![]), SAtom::AudioSample(_) => SAtom::AudioSample(("".to_string(), None)), - SAtom::Setting(_) => SAtom::Setting(0), - SAtom::Param(_) => SAtom::Param(0.0), + SAtom::Setting(_) => SAtom::Setting(0), + SAtom::Param(_) => SAtom::Param(0.0), } } pub fn is_continous(&self) -> bool { - if let SAtom::Param(_) = self { true } - else { false } + if let SAtom::Param(_) = self { + true + } else { + false + } } pub fn i(&self) -> i64 { match self { SAtom::Setting(i) => *i, - SAtom::Param(i) => *i as i64, - _ => 0, + SAtom::Param(i) => *i as i64, + _ => 0, } } pub fn s(&self) -> String { match self { SAtom::Str(s) => s.clone(), - _ => "".to_string(), + _ => "".to_string(), } } pub fn f(&self) -> f32 { match self { SAtom::Setting(i) => *i as f32, - SAtom::Param(i) => *i, - _ => 0.0, + SAtom::Param(i) => *i, + _ => 0.0, } } pub fn v_ref(&self) -> Option<&[f32]> { match self { - SAtom::MicroSample(v) => Some(&v[..]), + SAtom::MicroSample(v) => Some(&v[..]), SAtom::AudioSample((_, Some(v))) => Some(&v[..]), - _ => None, + _ => None, } } pub fn type_str(&self) -> &str { match self { - SAtom::Str(_) => "str", + SAtom::Str(_) => "str", SAtom::MicroSample(_) => "micro_sample", SAtom::AudioSample(_) => "audio_sample", - SAtom::Setting(_) => "setting", - SAtom::Param(_) => "param", + SAtom::Setting(_) => "setting", + SAtom::Param(_) => "param", } } } impl From for SAtom { - fn from(n: f32) -> Self { SAtom::Param(n) } + fn from(n: f32) -> Self { + SAtom::Param(n) + } } diff --git a/src/dsp/tracker/mod.rs b/src/dsp/tracker/mod.rs index c2cf739..d3a7ac1 100644 --- a/src/dsp/tracker/mod.rs +++ b/src/dsp/tracker/mod.rs @@ -5,13 +5,13 @@ mod pattern; mod sequencer; -use ringbuf::{RingBuffer, Producer, Consumer}; +use ringbuf::{Consumer, Producer, RingBuffer}; use std::sync::{Arc, Mutex}; -pub const MAX_COLS : usize = 6; -pub const MAX_PATTERN_LEN : usize = 256; -pub const MAX_RINGBUF_SIZE : usize = 64; +pub const MAX_COLS: usize = 6; +pub const MAX_PATTERN_LEN: usize = 256; +pub const MAX_RINGBUF_SIZE: usize = 64; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum PatternColType { @@ -27,38 +27,39 @@ pub use sequencer::PatternSequencer; #[derive(Debug, Clone, Copy)] pub enum PatternUpdateMsg { UpdateColumn { - col: usize, - col_type: PatternColType, + col: usize, + col_type: PatternColType, pattern_len: usize, - data: [(f32, u8); MAX_PATTERN_LEN] + data: [(f32, u8); MAX_PATTERN_LEN], }, } pub struct Tracker { - data: Arc>, + data: Arc>, data_prod: Producer, - seq: Option, - seq_cons: Option>, + seq: Option, + seq_cons: Option>, } impl Clone for Tracker { - fn clone(&self) -> Self { Tracker::new() } + fn clone(&self) -> Self { + Tracker::new() + } } - pub struct TrackerBackend { - seq: PatternSequencer, - seq_cons: Consumer, - col_types: [PatternColType; MAX_COLS], + seq: PatternSequencer, + seq_cons: Consumer, + col_types: [PatternColType; MAX_COLS], } impl std::fmt::Debug for TrackerBackend { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Tracker") - .field("col_types", &self.col_types) - .field("seq", &"PatternSequencer") - .field("seq_cons", &"RingbufConsumer") - .finish() + .field("col_types", &self.col_types) + .field("seq", &"PatternSequencer") + .field("seq_cons", &"RingbufConsumer") + .finish() } } @@ -68,14 +69,16 @@ impl Tracker { let (prod, con) = rb.split(); Self { - data: Arc::new(Mutex::new(PatternData::new(MAX_PATTERN_LEN))), + data: Arc::new(Mutex::new(PatternData::new(MAX_PATTERN_LEN))), data_prod: prod, - seq: Some(PatternSequencer::new(MAX_PATTERN_LEN)), - seq_cons: Some(con), + seq: Some(PatternSequencer::new(MAX_PATTERN_LEN)), + seq_cons: Some(con), } } - pub fn data(&self) -> Arc> { self.data.clone() } + pub fn data(&self) -> Arc> { + self.data.clone() + } pub fn send_one_update(&mut self) -> bool { let mut data = self.data.lock().unwrap(); @@ -84,13 +87,12 @@ impl Tracker { if data.col_is_modified_reset(col) { data.sync_out_data(col); let out_data = data.get_out_data(); - let msg = - PatternUpdateMsg::UpdateColumn { - col_type: data.col_type(col), - pattern_len: data.rows(), - data: out_data[col], - col, - }; + let msg = PatternUpdateMsg::UpdateColumn { + col_type: data.col_type(col), + pattern_len: data.rows(), + data: out_data[col], + col, + }; let _ = self.data_prod.push(msg); @@ -106,19 +108,15 @@ impl Tracker { let rb = RingBuffer::new(MAX_RINGBUF_SIZE); let (prod, con) = rb.split(); - self.seq = Some(PatternSequencer::new(MAX_PATTERN_LEN)); - self.data_prod = prod; - self.seq_cons = Some(con); + self.seq = Some(PatternSequencer::new(MAX_PATTERN_LEN)); + self.data_prod = prod; + self.seq_cons = Some(con); } - let seq = self.seq.take().unwrap(); + let seq = self.seq.take().unwrap(); let seq_cons = self.seq_cons.take().unwrap(); - TrackerBackend { - seq, - seq_cons, - col_types: [PatternColType::Value; MAX_COLS], - } + TrackerBackend { seq, seq_cons, col_types: [PatternColType::Value; MAX_COLS] } } } @@ -130,33 +128,36 @@ impl TrackerBackend { self.col_types[col] = col_type; self.seq.set_rows(pattern_len); self.seq.set_col(col, &data); - }, + } } true - } else { false } } - pub fn pattern_len(&self) -> usize { self.seq.rows() } + pub fn pattern_len(&self) -> usize { + self.seq.rows() + } pub fn get_col_at_phase( - &mut self, col: usize, phase: &[f32], - out: &mut [f32], out_gate: &mut [f32]) - { + &mut self, + col: usize, + phase: &[f32], + out: &mut [f32], + out_gate: &mut [f32], + ) { if self.seq.rows() == 0 { return; } match self.col_types[col] { - PatternColType::Note | PatternColType::Step => - self.seq.col_get_at_phase( col, phase, out, out_gate), - PatternColType::Value => - self.seq.col_interpolate_at_phase(col, phase, out, out_gate), - PatternColType::Gate => - self.seq.col_gate_at_phase( col, phase, out, out_gate), + PatternColType::Note | PatternColType::Step => { + self.seq.col_get_at_phase(col, phase, out, out_gate) + } + PatternColType::Value => self.seq.col_interpolate_at_phase(col, phase, out, out_gate), + PatternColType::Gate => self.seq.col_gate_at_phase(col, phase, out, out_gate), } } } @@ -168,11 +169,14 @@ mod tests { macro_rules! assert_float_eq { ($a:expr, $b:expr) => { if ($a - $b).abs() > 0.0001 { - panic!(r#"assertion failed: `(left == right)` + panic!( + r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`"#, $a, $b) + right: `{:?}`"#, + $a, $b + ) } - } + }; } #[test] @@ -182,18 +186,17 @@ mod tests { t.data().lock().unwrap().set_rows(16); t.data().lock().unwrap().set_col_step_type(0); - t.data().lock().unwrap().set_cell_value(0, 0, 0xFFF); - t.data().lock().unwrap().set_cell_value(7, 0, 0x777); + t.data().lock().unwrap().set_cell_value(0, 0, 0xFFF); + t.data().lock().unwrap().set_cell_value(7, 0, 0x777); t.data().lock().unwrap().set_cell_value(15, 0, 0x000); - while t.send_one_update() { } - while backend.check_updates() { } + while t.send_one_update() {} + while backend.check_updates() {} - let mut out = [0.0; 16]; + let mut out = [0.0; 16]; let mut out_gate = [0.0; 16]; - backend.get_col_at_phase( - 0, &[0.2, 0.5, 0.99], &mut out[..], &mut out_gate[..]); + backend.get_col_at_phase(0, &[0.2, 0.5, 0.99], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 1.0); assert_float_eq!(out[1], 0.46666666); @@ -210,18 +213,17 @@ mod tests { t.data().lock().unwrap().set_rows(16); t.data().lock().unwrap().set_col_value_type(0); - t.data().lock().unwrap().set_cell_value(0, 0, 0xFFF); - t.data().lock().unwrap().set_cell_value(7, 0, 0x777); + t.data().lock().unwrap().set_cell_value(0, 0, 0xFFF); + t.data().lock().unwrap().set_cell_value(7, 0, 0x777); t.data().lock().unwrap().set_cell_value(15, 0, 0x000); - while t.send_one_update() { } - while backend.check_updates() { } + while t.send_one_update() {} + while backend.check_updates() {} - let mut out = [0.0; 16]; + let mut out = [0.0; 16]; let mut out_gate = [0.0; 16]; - backend.get_col_at_phase( - 0, &[0.2, 0.5, 0.999999], &mut out[..], &mut out_gate[..]); + backend.get_col_at_phase(0, &[0.2, 0.5, 0.999999], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.83238); assert_float_eq!(out[1], 0.46666666); assert_float_eq!(out[2], 0.0); @@ -237,15 +239,15 @@ mod tests { t.data().lock().unwrap().set_rows(4); t.data().lock().unwrap().set_col_gate_type(0); - t.data().lock().unwrap().set_cell_value(0, 0, 0xFF7); + t.data().lock().unwrap().set_cell_value(0, 0, 0xFF7); t.data().lock().unwrap().clear_cell(1, 0); - t.data().lock().unwrap().set_cell_value(2, 0, 0xFF0); - t.data().lock().unwrap().set_cell_value(3, 0, 0xFFF); + t.data().lock().unwrap().set_cell_value(2, 0, 0xFF0); + t.data().lock().unwrap().set_cell_value(3, 0, 0xFFF); - while t.send_one_update() { } - while backend.check_updates() { } + while t.send_one_update() {} + while backend.check_updates() {} - let mut out = [0.0; 64]; + let mut out = [0.0; 64]; let mut out_gate = [0.0; 64]; let mut phase = [0.0; 64]; @@ -254,23 +256,22 @@ mod tests { } //d// println!("----"); - backend.get_col_at_phase( - 0, &phase[..], &mut out[..], &mut out_gate[..]); + backend.get_col_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); //d// println!("out: {:?}", &out[16..32]); - assert_eq!(out[0..8], [1.0; 8]); + assert_eq!(out[0..8], [1.0; 8]); assert_eq!(out[8..16], [0.0; 8]); - assert_eq!(out[16..32],[0.0; 16]); - assert_eq!(out_gate[0..8], [1.0; 8]); + assert_eq!(out[16..32], [0.0; 16]); + assert_eq!(out_gate[0..8], [1.0; 8]); assert_eq!(out_gate[8..16], [1.0; 8]); - assert_eq!(out_gate[16..32],[0.0; 16]); + assert_eq!(out_gate[16..32], [0.0; 16]); assert_float_eq!(out[32], 1.0); - assert_eq!(out[33..48],[0.0; 15]); + assert_eq!(out[33..48], [0.0; 15]); assert_float_eq!(out_gate[32], 1.0); - assert_eq!(out_gate[33..48],[1.0; 15]); + assert_eq!(out_gate[33..48], [1.0; 15]); - assert_eq!(out[48..64],[1.0; 16]); - assert_eq!(out_gate[48..64],[1.0; 16]); + assert_eq!(out[48..64], [1.0; 16]); + assert_eq!(out_gate[48..64], [1.0; 16]); } } diff --git a/src/dsp/tracker/pattern.rs b/src/dsp/tracker/pattern.rs index a4a3d31..a91eaa5 100644 --- a/src/dsp/tracker/pattern.rs +++ b/src/dsp/tracker/pattern.rs @@ -3,33 +3,33 @@ // See README.md and COPYING for details. use super::PatternColType; -use super::MAX_PATTERN_LEN; use super::MAX_COLS; +use super::MAX_PATTERN_LEN; use crate::matrix_repr::PatternRepr; #[derive(Debug)] pub struct PatternData { - col_types: [PatternColType; MAX_COLS], - data: Vec>>, - out_data: Vec<[(f32, u8); MAX_PATTERN_LEN]>, - strings: Vec>>, - cursor: (usize, usize), - rows: usize, - edit_step: usize, - dirty_col: [bool; MAX_COLS], + col_types: [PatternColType; MAX_COLS], + data: Vec>>, + out_data: Vec<[(f32, u8); MAX_PATTERN_LEN]>, + strings: Vec>>, + cursor: (usize, usize), + rows: usize, + edit_step: usize, + dirty_col: [bool; MAX_COLS], generation: usize, } impl PatternData { pub fn new(rows: usize) -> Self { Self { - col_types: [PatternColType::Value; MAX_COLS], - data: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], - out_data: vec![[(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], - strings: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], - cursor: (2, 2), - edit_step: 4, - dirty_col: [true; MAX_COLS], + col_types: [PatternColType::Value; MAX_COLS], + data: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], + out_data: vec![[(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], + strings: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], + cursor: (2, 2), + edit_step: 4, + dirty_col: [true; MAX_COLS], generation: 0, rows, } @@ -39,12 +39,16 @@ impl PatternData { impl PatternData { pub fn is_unset(&self) -> bool { for ct in self.col_types.iter() { - if *ct != PatternColType::Value { return false; } + if *ct != PatternColType::Value { + return false; + } } for rows in self.data.iter() { for col in rows.iter() { - if col.is_some() { return false; } + if col.is_some() { + return false; + } } } @@ -54,58 +58,52 @@ impl PatternData { pub fn to_repr(&self) -> PatternRepr { let mut col_types = [0; MAX_COLS]; for (i, ct) in self.col_types.iter().enumerate() { - col_types[i] = - match ct { - PatternColType::Value => 0, - PatternColType::Note => 1, - PatternColType::Step => 2, - PatternColType::Gate => 3, - }; + col_types[i] = match ct { + PatternColType::Value => 0, + PatternColType::Note => 1, + PatternColType::Step => 2, + PatternColType::Gate => 3, + }; } let mut data = vec![vec![-1; MAX_COLS]; MAX_PATTERN_LEN]; for (row_idx, row) in self.data.iter().enumerate() { for (col_idx, cell) in row.iter().enumerate() { - data[row_idx][col_idx] = - if let Some(c) = cell { *c as i32 } - else { -1 }; + data[row_idx][col_idx] = if let Some(c) = cell { *c as i32 } else { -1 }; } } PatternRepr { col_types, data, - rows: self.rows, + rows: self.rows, edit_step: self.edit_step, - cursor: self.cursor, + cursor: self.cursor, } } pub fn from_repr(&mut self, repr: &PatternRepr) { for (i, ct) in repr.col_types.iter().enumerate() { - self.col_types[i] = - match *ct { - 0 => PatternColType::Value, - 1 => PatternColType::Note, - 2 => PatternColType::Step, - 3 => PatternColType::Gate, - _ => PatternColType::Value, - }; + self.col_types[i] = match *ct { + 0 => PatternColType::Value, + 1 => PatternColType::Note, + 2 => PatternColType::Step, + 3 => PatternColType::Gate, + _ => PatternColType::Value, + }; self.modified_col(i); } for (row_idx, row) in repr.data.iter().enumerate() { for (col_idx, cell) in row.iter().enumerate() { - self.data[row_idx][col_idx] = - if *cell < 0 { None } - else { Some(*cell as u16) }; + self.data[row_idx][col_idx] = if *cell < 0 { None } else { Some(*cell as u16) }; } } - self.rows = repr.rows; + self.rows = repr.rows; self.edit_step = repr.edit_step; - self.cursor = repr.cursor; + self.cursor = repr.cursor; self.generation += 1; } @@ -143,85 +141,74 @@ impl PatternData { match self.col_types[col] { PatternColType::Value => { let mut start_value = 0.0; - let mut start_idx = 0; - let mut end_idx = 0; + let mut start_idx = 0; + let mut end_idx = 0; while end_idx <= out_col.len() { let mut break_after_write = false; - let cur_value = - if end_idx == self.rows { - end_idx -= 1; - break_after_write = true; - Some(self.data[end_idx][col] + let cur_value = if end_idx == self.rows { + end_idx -= 1; + break_after_write = true; + Some( + self.data[end_idx][col] .map(|v| ((v & 0xFFF) as f32) / (0xFFF as f32)) - .unwrap_or(0.0)) - } else { - self.data[end_idx][col].map(|v| - ((v & 0xFFF) as f32) / (0xFFF as f32)) - }; + .unwrap_or(0.0), + ) + } else { + self.data[end_idx][col].map(|v| ((v & 0xFFF) as f32) / (0xFFF as f32)) + }; if let Some(end_value) = cur_value { out_col[start_idx] = (start_value, 0); - out_col[end_idx] = (end_value, 1); + out_col[end_idx] = (end_value, 1); let delta_rows = end_idx - start_idx; if delta_rows > 1 { for idx in (start_idx + 1)..end_idx { - let x = - (idx - start_idx) as f32 - / (delta_rows as f32); - out_col[idx] = - (start_value * (1.0 - x) + end_value * x, 0); + let x = (idx - start_idx) as f32 / (delta_rows as f32); + out_col[idx] = (start_value * (1.0 - x) + end_value * x, 0); } } start_value = end_value; - start_idx = end_idx; - end_idx = end_idx + 1; + start_idx = end_idx; + end_idx = end_idx + 1; if break_after_write { break; } - } else { end_idx += 1; } } - }, + } PatternColType::Note => { let mut cur_value = (0.0, 0); for row in 0..out_col.len() { if let Some(new_value) = self.data[row][col] { - cur_value = ( - ((new_value as i32 - 69) as f32 * 0.1) / 12.0, - 1 - ); + cur_value = (((new_value as i32 - 69) as f32 * 0.1) / 12.0, 1); } else { cur_value.1 = 0; } - out_col[row] = - (cur_value.0.clamp(-1.0, 1.0), cur_value.1); + out_col[row] = (cur_value.0.clamp(-1.0, 1.0), cur_value.1); } - }, + } PatternColType::Step => { let mut cur_value = (0.0, 0); for row in 0..out_col.len() { if let Some(new_value) = self.data[row][col] { - cur_value = ( - ((new_value & 0xFFF) as f32) / (0xFFF as f32), - 1 - ); + cur_value = (((new_value & 0xFFF) as f32) / (0xFFF as f32), 1); } else { cur_value.1 = 0; } out_col[row] = cur_value; } - }, + } PatternColType::Gate => { // XXX: We need to iterate over all rows, even if // self.rows < out_col.len(), because empty cells @@ -229,14 +216,13 @@ impl PatternData { // this internal format!? But in either case we transmit // a full row to the backend anyways. for row in 0..out_col.len() { - out_col[row] = - if let Some(new_value) = self.data[row][col] { - (f32::from_bits(new_value as u32), 1) - } else { - (f32::from_bits(0xF000 as u32), 0) - }; + out_col[row] = if let Some(new_value) = self.data[row][col] { + (f32::from_bits(new_value as u32), 1) + } else { + (f32::from_bits(0xF000 as u32), 0) + }; } - }, + } } } } @@ -278,8 +264,12 @@ pub trait UIPatternModel: std::fmt::Debug { impl UIPatternModel for PatternData { fn get_cell(&mut self, row: usize, col: usize) -> Option<&str> { - if row >= self.data.len() { return None; } - if col >= self.data[0].len() { return None; } + if row >= self.data.len() { + return None; + } + if col >= self.data[0].len() { + return None; + } if self.strings[row][col].is_none() { if let Some(v) = self.data[row][col] { @@ -293,27 +283,39 @@ impl UIPatternModel for PatternData { } fn clear_cell(&mut self, row: usize, col: usize) { - if row >= self.data.len() { return; } - if col >= self.data[0].len() { return; } + if row >= self.data.len() { + return; + } + if col >= self.data[0].len() { + return; + } - self.data[row][col] = None; + self.data[row][col] = None; self.strings[row][col] = None; self.modified_col(col); self.generation += 1; } fn get_cell_value(&mut self, row: usize, col: usize) -> u16 { - if row >= self.data.len() { return 0; } - if col >= self.data[0].len() { return 0; } + if row >= self.data.len() { + return 0; + } + if col >= self.data[0].len() { + return 0; + } self.data[row][col].unwrap_or(0) } fn set_cell_value(&mut self, row: usize, col: usize, val: u16) { - if row >= self.data.len() { return; } - if col >= self.data[0].len() { return; } + if row >= self.data.len() { + return; + } + if col >= self.data[0].len() { + return; + } - self.data[row][col] = Some(val); + self.data[row][col] = Some(val); self.strings[row][col] = None; self.modified_col(col); self.generation += 1; @@ -343,9 +345,13 @@ impl UIPatternModel for PatternData { } } - fn cols(&self) -> usize { self.data[0].len() } + fn cols(&self) -> usize { + self.data[0].len() + } - fn rows(&self) -> usize { self.rows } + fn rows(&self) -> usize { + self.rows + } fn set_rows(&mut self, rows: usize) { self.rows = rows.min(self.data.len()); @@ -354,28 +360,36 @@ impl UIPatternModel for PatternData { } fn set_col_note_type(&mut self, col: usize) { - if col >= self.col_types.len() { return; } + if col >= self.col_types.len() { + return; + } self.col_types[col] = PatternColType::Note; self.modified_col(col); self.generation += 1; } fn set_col_step_type(&mut self, col: usize) { - if col >= self.col_types.len() { return; } + if col >= self.col_types.len() { + return; + } self.col_types[col] = PatternColType::Step; self.modified_col(col); self.generation += 1; } fn set_col_value_type(&mut self, col: usize) { - if col >= self.col_types.len() { return; } + if col >= self.col_types.len() { + return; + } self.col_types[col] = PatternColType::Value; self.modified_col(col); self.generation += 1; } fn set_col_gate_type(&mut self, col: usize) { - if col >= self.col_types.len() { return; } + if col >= self.col_types.len() { + return; + } self.col_types[col] = PatternColType::Gate; self.modified_col(col); self.generation += 1; @@ -385,17 +399,22 @@ impl UIPatternModel for PatternData { self.cursor = (row, col); self.generation += 1; } - fn get_cursor(&self) -> (usize, usize) { self.cursor } + fn get_cursor(&self) -> (usize, usize) { + self.cursor + } fn set_edit_step(&mut self, es: usize) { self.edit_step = es; self.generation += 1; } - fn get_edit_step(&mut self) -> usize { self.edit_step } + fn get_edit_step(&mut self) -> usize { + self.edit_step + } - fn get_generation(&self) -> usize { self.generation } + fn get_generation(&self) -> usize { + self.generation + } } - #[cfg(test)] mod tests { use super::*; @@ -403,11 +422,14 @@ mod tests { macro_rules! assert_float_eq { ($a:expr, $b:expr) => { if ($a - $b).abs() > 0.0001 { - panic!(r#"assertion failed: `(left == right)` + panic!( + r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`"#, $a, $b) + right: `{:?}`"#, + $a, $b + ) } - } + }; } #[test] @@ -424,9 +446,7 @@ mod tests { let inc = 1.0 / 2.0; for i in 1..2 { - let delta = - out_data[col][i].0 - - out_data[col][i - 1].0; + let delta = out_data[col][i].0 - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -446,9 +466,7 @@ mod tests { let inc = 1.0 / 3.0; for i in 1..3 { - let delta = - out_data[col][i].0 - - out_data[col][i - 1].0; + let delta = out_data[col][i].0 - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -460,7 +478,7 @@ mod tests { for col in 0..MAX_COLS { pats.set_col_value_type(col); - pats.set_cell_value(0, col, 0); + pats.set_cell_value(0, col, 0); pats.set_cell_value(15, col, 0xFFF); pats.sync_out_data(col); @@ -470,9 +488,7 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 1..16 { - let delta = - out_data[col][i].0 - - out_data[col][i - 1].0; + let delta = out_data[col][i].0 - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -492,9 +508,7 @@ mod tests { let inc = 1.0 / 15.0; for i in 1..16 { - let delta = - out_data[col][i].0 - - out_data[col][i - 1].0; + let delta = out_data[col][i].0 - out_data[col][i - 1].0; assert_float_eq!(delta.abs(), inc); } } @@ -514,9 +528,7 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { - assert_float_eq!( - out_data[col][i].0, - out_data[col][15 - i].0); + assert_float_eq!(out_data[col][i].0, out_data[col][15 - i].0); } } } @@ -535,9 +547,7 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { - assert_float_eq!( - out_data[col][i].0, - out_data[col][15 - i].0); + assert_float_eq!(out_data[col][i].0, out_data[col][15 - i].0); } } } @@ -558,9 +568,7 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { - assert_float_eq!( - out_data[col][i].0, - out_data[col][15 - i].0); + assert_float_eq!(out_data[col][i].0, out_data[col][15 - i].0); } } } @@ -585,9 +593,7 @@ mod tests { assert_float_eq!(0.5, out_data[col][9].0); for i in 0..8 { - assert_float_eq!( - out_data[col][i].0, - out_data[col][15 - i].0); + assert_float_eq!(out_data[col][i].0, out_data[col][15 - i].0); } } } @@ -598,20 +604,20 @@ mod tests { for col in 0..MAX_COLS { pats.set_col_step_type(col); - pats.set_cell_value(4, col, 0x450); - pats.set_cell_value(5, col, 0x0); - pats.set_cell_value(7, col, 0x7ff); - pats.set_cell_value(9, col, 0x800); + pats.set_cell_value(4, col, 0x450); + pats.set_cell_value(5, col, 0x0); + pats.set_cell_value(7, col, 0x7ff); + pats.set_cell_value(9, col, 0x800); pats.set_cell_value(10, col, 0xfff); pats.sync_out_data(col); let out_data = pats.get_out_data(); - assert_float_eq!(out_data[col][0].0, 0.0); - assert_float_eq!(out_data[col][4].0, 0.26959708); - assert_float_eq!(out_data[col][5].0, 0.0); - assert_float_eq!(out_data[col][7].0, 0.4998779); - assert_float_eq!(out_data[col][8].0, 0.4998779); - assert_float_eq!(out_data[col][9].0, 0.50012213); + assert_float_eq!(out_data[col][0].0, 0.0); + assert_float_eq!(out_data[col][4].0, 0.26959708); + assert_float_eq!(out_data[col][5].0, 0.0); + assert_float_eq!(out_data[col][7].0, 0.4998779); + assert_float_eq!(out_data[col][8].0, 0.4998779); + assert_float_eq!(out_data[col][9].0, 0.50012213); assert_float_eq!(out_data[col][10].0, 1.0); assert_float_eq!(out_data[col][15].0, 1.0); } @@ -630,8 +636,8 @@ mod tests { pats.sync_out_data(col); let out_data = pats.get_out_data(); - assert_float_eq!(out_data[col][0].0, 0.0); - assert_float_eq!(out_data[col][4].0, 0.0); + assert_float_eq!(out_data[col][0].0, 0.0); + assert_float_eq!(out_data[col][4].0, 0.0); assert_float_eq!(out_data[col][5].0, -0.575); assert_float_eq!(out_data[col][7].0, -0.1); assert_float_eq!(out_data[col][9].0, -0.1); diff --git a/src/dsp/tracker/sequencer.rs b/src/dsp/tracker/sequencer.rs index 66c67be..194ffa1 100644 --- a/src/dsp/tracker/sequencer.rs +++ b/src/dsp/tracker/sequencer.rs @@ -2,18 +2,18 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use super::MAX_PATTERN_LEN; use super::MAX_COLS; +use super::MAX_PATTERN_LEN; use crate::dsp::helpers::SplitMix64; pub struct PatternSequencer { - rows: usize, - data: Vec>, - rng: SplitMix64, - rand_vals: [(usize, f64); MAX_COLS], + rows: usize, + data: Vec>, + rng: SplitMix64, + rand_vals: [(usize, f64); MAX_COLS], } -const FRACT_16THS : [f32; 16] = [ +const FRACT_16THS: [f32; 16] = [ 1.0 / 16.0, 2.0 / 16.0, 3.0 / 16.0, @@ -23,38 +23,35 @@ const FRACT_16THS : [f32; 16] = [ 7.0 / 16.0, 8.0 / 16.0, 9.0 / 16.0, - 10.0 / 16.0, - 11.0 / 16.0, - 12.0 / 16.0, - 13.0 / 16.0, - 14.0 / 16.0, - 15.0 / 16.0, - 1.0 + 10.0 / 16.0, + 11.0 / 16.0, + 12.0 / 16.0, + 13.0 / 16.0, + 14.0 / 16.0, + 15.0 / 16.0, + 1.0, ]; impl PatternSequencer { pub fn new_default_seed(rows: usize) -> Self { Self { rows, - data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], - rng: SplitMix64::new(0x91234), + data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], + rng: SplitMix64::new(0x91234), rand_vals: [(99999, 0.0); MAX_COLS], } } pub fn new(rows: usize) -> Self { use std::time::SystemTime; - let seed = - match SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - { - Ok(n) => n.as_nanos() as i64, - Err(_) => 1_234_567_890, - }; + let seed = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { + Ok(n) => n.as_nanos() as i64, + Err(_) => 1_234_567_890, + }; Self { rows, - data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], - rng: SplitMix64::new_from_i64(seed), + data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], + rng: SplitMix64::new_from_i64(seed), rand_vals: [(99999, 0.0); MAX_COLS], } } @@ -63,35 +60,33 @@ impl PatternSequencer { self.rows = rows; } - pub fn rows(&self) -> usize { self.rows } + pub fn rows(&self) -> usize { + self.rows + } pub fn set_col(&mut self, col: usize, col_data: &[(f32, u8)]) { - for (out_cell, in_cell) in - self.data[col] - .iter_mut() - .zip(col_data.iter()) - { + for (out_cell, in_cell) in self.data[col].iter_mut().zip(col_data.iter()) { *out_cell = *in_cell; } } pub fn col_interpolate_at_phase( - &self, col: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) - { + &self, + col: usize, + phase: &[f32], + out: &mut [f32], + out_gate: &mut [f32], + ) { let col = &self.data[col][..]; - let last_row_idx : f32 = (self.rows as f32) - 0.00001; + let last_row_idx: f32 = (self.rows as f32) - 0.00001; let rows = self.rows; - for ((phase, out), out_gate) in - phase.iter() - .zip(out.iter_mut()) - .zip(out_gate.iter_mut()) - { - let row_phase = phase * last_row_idx; + for ((phase, out), out_gate) in phase.iter().zip(out.iter_mut()).zip(out_gate.iter_mut()) { + let row_phase = phase * last_row_idx; let phase_frac = row_phase.fract(); - let line = row_phase.floor() as usize % rows; - let prev_line = if line == 0 { self.rows - 1 } else { line - 1 }; + let line = row_phase.floor() as usize % rows; + let prev_line = if line == 0 { self.rows - 1 } else { line - 1 }; let prev = col[prev_line].0; let next = col[line].0; @@ -102,66 +97,66 @@ impl PatternSequencer { // line, next, // phase_frac); - *out = prev * (1.0 - phase_frac) + next * phase_frac; + *out = prev * (1.0 - phase_frac) + next * phase_frac; *out_gate = gate as f32; } } pub fn col_get_at_phase( - &self, col: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) - { + &self, + col: usize, + phase: &[f32], + out: &mut [f32], + out_gate: &mut [f32], + ) { let col = &self.data[col][..]; - let last_row_idx : f32 = (self.rows as f32) - 0.00001; + let last_row_idx: f32 = (self.rows as f32) - 0.00001; let rows = self.rows; - for ((phase, out), out_gate) in - phase.iter() - .zip(out.iter_mut()) - .zip(out_gate.iter_mut()) - { - let row_phase = phase * last_row_idx; - let line = row_phase.floor() as usize % rows; + for ((phase, out), out_gate) in phase.iter().zip(out.iter_mut()).zip(out_gate.iter_mut()) { + let row_phase = phase * last_row_idx; + let line = row_phase.floor() as usize % rows; let (val, gate) = col[line]; - *out = val; + *out = val; *out_gate = gate as f32; } } pub fn col_gate_at_phase( - &mut self, col_idx: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) - { + &mut self, + col_idx: usize, + phase: &[f32], + out: &mut [f32], + out_gate: &mut [f32], + ) { let col = &self.data[col_idx][..]; - let last_row_idx : f32 = (self.rows as f32) - 0.00001; + let last_row_idx: f32 = (self.rows as f32) - 0.00001; let rows = self.rows; - for ((phase, out), out_gate) in - phase.iter() - .zip(out.iter_mut()) - .zip(out_gate.iter_mut()) - { - let row_phase = phase.clamp(0.0, 1.0) * last_row_idx; - let line = row_phase.floor() as usize % rows; + for ((phase, out), out_gate) in phase.iter().zip(out.iter_mut()).zip(out_gate.iter_mut()) { + let row_phase = phase.clamp(0.0, 1.0) * last_row_idx; + let line = row_phase.floor() as usize % rows; let phase_frac = row_phase.fract(); - let gate : u32 = col[line].0.to_bits(); - let ggate : u8 = col[line].1; + let gate: u32 = col[line].0.to_bits(); + let ggate: u8 = col[line].1; // pulse_width: // 0xF - Gate is on for full row // 0x0 - Gate is on for a very short burst - let pulse_width : f32 = FRACT_16THS[(gate & 0x00F) as usize]; + let pulse_width: f32 = FRACT_16THS[(gate & 0x00F) as usize]; // row_div: // 0xF - Row has 1 Gate // 0x0 - Row is divided up into 16 Gates - let row_div : f32 = (16 - ((gate & 0x0F0) >> 4)) as f32; + let row_div: f32 = (16 - ((gate & 0x0F0) >> 4)) as f32; // probability: // 0xF - Row is always triggered // 0x7 - Row fires only in 50% of the cases // 0x0 - Row fires only in ~6% of the cases - let probability : u8 = ((gate & 0xF00) >> 8) as u8; + let probability: u8 = ((gate & 0xF00) >> 8) as u8; let sub_frac = (phase_frac * row_div).fract(); //d// println!( @@ -169,14 +164,13 @@ impl PatternSequencer { //d// row_div, pulse_width, sub_frac, phase_frac); if probability < 0xF { - let rand_val = - if self.rand_vals[col_idx].0 != line { - let new_rand_val = self.rng.next_open01(); - self.rand_vals[col_idx] = (line, new_rand_val); - new_rand_val - } else { - self.rand_vals[col_idx].1 - }; + let rand_val = if self.rand_vals[col_idx].0 != line { + let new_rand_val = self.rng.next_open01(); + self.rand_vals[col_idx] = (line, new_rand_val); + new_rand_val + } else { + self.rand_vals[col_idx].1 + }; //d// println!("RANDVAL: {:?} | {:9.7}", self.rand_vals[col_idx], FRACT_16THS[probability as usize]); if rand_val > (FRACT_16THS[probability as usize] as f64) { @@ -191,10 +185,10 @@ impl PatternSequencer { } if (gate & 0xF000) > 0 { - *out = 0.0; + *out = 0.0; *out_gate = 0.0; } else { - *out = if sub_frac <= pulse_width { 1.0 } else { 0.0 }; + *out = if sub_frac <= pulse_width { 1.0 } else { 0.0 }; *out_gate = ggate as f32; } } @@ -208,11 +202,14 @@ mod tests { macro_rules! assert_float_eq { ($a:expr, $b:expr) => { if ($a - $b).abs() > 0.0001 { - panic!(r#"assertion failed: `(left == right)` + panic!( + r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`"#, $a, $b) + right: `{:?}`"#, + $a, $b + ) } - } + }; } #[test] @@ -220,11 +217,14 @@ mod tests { let mut ps = PatternSequencer::new(2); ps.set_col(0, &[(0.0, 0), (1.0, 1)]); - let mut out = [0.0; 6]; + let mut out = [0.0; 6]; let mut out_gate = [0.0; 6]; ps.col_interpolate_at_phase( - 0, &[0.0, 0.1, 0.50, 0.51, 0.9, 0.99999], - &mut out[..], &mut out_gate[..]); + 0, + &[0.0, 0.1, 0.50, 0.51, 0.9, 0.99999], + &mut out[..], + &mut out_gate[..], + ); assert_float_eq!(out[0], 1.0); assert_float_eq!(out[1], 0.8); assert_float_eq!(out[2], 0.0); @@ -245,25 +245,22 @@ mod tests { let mut ps = PatternSequencer::new(256); ps.set_col(0, &[(f32::from_bits(0xF000), 0); 256]); - let mut out = [0.0; 1]; + let mut out = [0.0; 1]; let mut out_gate = [0.0; 1]; - ps.col_gate_at_phase( - 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); - assert_float_eq!(out[0], 0.0); + ps.col_gate_at_phase(0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); assert_float_eq!(out_gate[0], 0.0); let mut ps = PatternSequencer::new(256); ps.set_col(0, &[(0.0, 0); 256]); - ps.col_get_at_phase( - 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); - assert_float_eq!(out[0], 0.0); - assert_float_eq!(out_gate[0], 0.0); + ps.col_get_at_phase(0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); + assert_float_eq!(out_gate[0], 0.0); - ps.col_interpolate_at_phase( - 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); - assert_float_eq!(out[0], 0.0); - assert_float_eq!(out_gate[0], 0.0); + ps.col_interpolate_at_phase(0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); + assert_float_eq!(out_gate[0], 0.0); } #[test] @@ -271,10 +268,9 @@ mod tests { let mut ps = PatternSequencer::new(2); ps.set_col(0, &[(0.0, 0), (1.0, 1)]); - let mut out = [0.0; 3]; + let mut out = [0.0; 3]; let mut out_gate = [0.0; 3]; - ps.col_get_at_phase( - 0, &[0.1, 0.51, 0.9], &mut out[..], &mut out_gate[..]); + ps.col_get_at_phase(0, &[0.1, 0.51, 0.9], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.0); assert_float_eq!(out[1], 1.0); assert_float_eq!(out[2], 1.0); @@ -288,11 +284,9 @@ mod tests { let mut ps = PatternSequencer::new(3); ps.set_col(0, &[(0.0, 0), (0.3, 1), (1.0, 1)]); - let mut out = [0.0; 6]; + let mut out = [0.0; 6]; let mut out_gate = [0.0; 6]; - ps.col_get_at_phase( - 0, &[0.1, 0.5, 0.51, 0.6, 0.9, 0.99], - &mut out[..], &mut out_gate[..]); + ps.col_get_at_phase(0, &[0.1, 0.5, 0.51, 0.6, 0.9, 0.99], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.0); assert_float_eq!(out[1], 0.3); assert_float_eq!(out[2], 0.3); @@ -311,16 +305,16 @@ mod tests { #[test] fn check_seq_gate_1() { let mut ps = PatternSequencer::new(2); - ps.set_col(0, &[ - (f32::from_bits(0x0FFF), 1), - (f32::from_bits(0xF000), 0), - ]); + ps.set_col(0, &[(f32::from_bits(0x0FFF), 1), (f32::from_bits(0xF000), 0)]); - let mut out = [0.0; 6]; + let mut out = [0.0; 6]; let mut out_gate = [0.0; 6]; ps.col_gate_at_phase( - 0, &[0.1, 0.5, 0.5001, 0.6, 0.9, 0.99], - &mut out[..], &mut out_gate[..]); + 0, + &[0.1, 0.5, 0.5001, 0.6, 0.9, 0.99], + &mut out[..], + &mut out_gate[..], + ); //d// println!("out: {:?}", out); assert_float_eq!(out[0], 1.0); @@ -341,7 +335,9 @@ mod tests { fn count_high(slice: &[f32]) -> usize { let mut sum = 0; for p in slice.iter() { - if *p > 0.5 { sum += 1; } + if *p > 0.5 { + sum += 1; + } } sum } @@ -361,11 +357,14 @@ mod tests { #[test] fn check_seq_gate_2() { let mut ps = PatternSequencer::new(3); - ps.set_col(0, &[ - (f32::from_bits(0x0FF0), 1), - (f32::from_bits(0x0FF7), 0), - (f32::from_bits(0x0FFF), 1), - ]); + ps.set_col( + 0, + &[ + (f32::from_bits(0x0FF0), 1), + (f32::from_bits(0x0FF7), 0), + (f32::from_bits(0x0FFF), 1), + ], + ); let mut phase = vec![0.0; 96]; let inc = 1.0 / (96.0 - 1.0); @@ -377,35 +376,37 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 96]; + let mut out = [0.0; 96]; let mut out_gate = [0.0; 96]; - ps.col_gate_at_phase( - 0, &phase[..], &mut out[..], &mut out_gate[..]); + ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); //d// println!("out: {:?}", &out[0..32]); - assert_eq!(count_high(&out[0..32]), 2); + assert_eq!(count_high(&out[0..32]), 2); assert_eq!(count_high(&out[32..64]), 16); assert_eq!(count_high(&out[64..96]), 32); - assert_eq!(count_high(&out_gate[0..32]), 32); - assert_eq!(count_high(&out_gate[32..64]), 0); + assert_eq!(count_high(&out_gate[0..32]), 32); + assert_eq!(count_high(&out_gate[32..64]), 0); assert_eq!(count_high(&out_gate[64..96]), 32); - assert_eq!(count_up(&out[0..32]), 1); - assert_eq!(count_up(&out[32..64]), 1); - assert_eq!(count_up(&out[64..96]), 1); - assert_eq!(count_up(&out_gate[0..32]), 1); - assert_eq!(count_up(&out_gate[32..64]), 0); - assert_eq!(count_up(&out_gate[64..96]), 1); + assert_eq!(count_up(&out[0..32]), 1); + assert_eq!(count_up(&out[32..64]), 1); + assert_eq!(count_up(&out[64..96]), 1); + assert_eq!(count_up(&out_gate[0..32]), 1); + assert_eq!(count_up(&out_gate[32..64]), 0); + assert_eq!(count_up(&out_gate[64..96]), 1); } #[test] fn check_seq_gate_div_1() { let mut ps = PatternSequencer::new(3); - ps.set_col(0, &[ - (f32::from_bits(0x0F80), 1), - (f32::from_bits(0x0F87), 0), - (f32::from_bits(0x0F8F), 1), - ]); + ps.set_col( + 0, + &[ + (f32::from_bits(0x0F80), 1), + (f32::from_bits(0x0F87), 0), + (f32::from_bits(0x0F8F), 1), + ], + ); let mut phase = vec![0.0; 3 * 64]; let inc = 1.0 / ((3.0 * 64.0) - 1.0); @@ -417,35 +418,37 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 3 * 64]; + let mut out = [0.0; 3 * 64]; let mut out_gate = [0.0; 3 * 64]; - ps.col_gate_at_phase( - 0, &phase[..], &mut out[..], &mut out_gate[..]); + ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); - assert_eq!(count_high(&out[0..64]), 8); - assert_eq!(count_up( &out[0..64]), 8); - assert_eq!(count_high(&out_gate[0..64]), 64); - assert_eq!(count_up( &out_gate[0..64]), 1); + assert_eq!(count_high(&out[0..64]), 8); + assert_eq!(count_up(&out[0..64]), 8); + assert_eq!(count_high(&out_gate[0..64]), 64); + assert_eq!(count_up(&out_gate[0..64]), 1); assert_eq!(count_high(&out[64..128]), 32); - assert_eq!(count_up( &out[64..128]), 8); - assert_eq!(count_high(&out_gate[64..128]), 0); - assert_eq!(count_up( &out_gate[64..128]), 0); + assert_eq!(count_up(&out[64..128]), 8); + assert_eq!(count_high(&out_gate[64..128]), 0); + assert_eq!(count_up(&out_gate[64..128]), 0); assert_eq!(count_high(&out[128..192]), 64); - assert_eq!(count_up( &out[128..192]), 1); + assert_eq!(count_up(&out[128..192]), 1); assert_eq!(count_high(&out_gate[128..192]), 64); - assert_eq!(count_up( &out_gate[128..192]), 1); + assert_eq!(count_up(&out_gate[128..192]), 1); } #[test] fn check_seq_gate_div_2() { let mut ps = PatternSequencer::new(3); - ps.set_col(0, &[ - (f32::from_bits(0x0F00), 1), - (f32::from_bits(0x0F07), 0), - (f32::from_bits(0x0F0F), 1), - ]); + ps.set_col( + 0, + &[ + (f32::from_bits(0x0F00), 1), + (f32::from_bits(0x0F07), 0), + (f32::from_bits(0x0F0F), 1), + ], + ); let mut phase = vec![0.0; 6 * 64]; let inc = 1.0 / ((6.0 * 64.0) - 1.0); @@ -457,34 +460,37 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 6 * 64]; + let mut out = [0.0; 6 * 64]; let mut out_gate = [0.0; 6 * 64]; ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); assert_eq!(count_high(&out[0..128]), 16); - assert_eq!(count_up( &out[0..128]), 16); + assert_eq!(count_up(&out[0..128]), 16); assert_eq!(count_high(&out_gate[0..128]), 128); - assert_eq!(count_up( &out_gate[0..128]), 1); + assert_eq!(count_up(&out_gate[0..128]), 1); assert_eq!(count_high(&out[128..256]), 64); - assert_eq!(count_up( &out[128..256]), 16); + assert_eq!(count_up(&out[128..256]), 16); assert_eq!(count_high(&out_gate[128..256]), 0); - assert_eq!(count_up( &out_gate[128..256]), 0); + assert_eq!(count_up(&out_gate[128..256]), 0); assert_eq!(count_high(&out[256..384]), 128); - assert_eq!(count_up( &out[256..384]), 1); + assert_eq!(count_up(&out[256..384]), 1); assert_eq!(count_high(&out_gate[256..384]), 128); - assert_eq!(count_up( &out_gate[256..384]), 1); + assert_eq!(count_up(&out_gate[256..384]), 1); } #[test] fn check_seq_gate_div_3() { let mut ps = PatternSequencer::new(3); - ps.set_col(0, &[ - (f32::from_bits(0x0FE0), 1), - (f32::from_bits(0x0FE7), 0), - (f32::from_bits(0x0FEF), 1), - ]); + ps.set_col( + 0, + &[ + (f32::from_bits(0x0FE0), 1), + (f32::from_bits(0x0FE7), 0), + (f32::from_bits(0x0FEF), 1), + ], + ); let mut phase = vec![0.0; 6 * 64]; let inc = 1.0 / ((6.0 * 64.0) - 1.0); @@ -496,24 +502,24 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 6 * 64]; + let mut out = [0.0; 6 * 64]; let mut out_gate = [0.0; 6 * 64]; ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); - assert_eq!(count_high(&out[0..128]), 8); - assert_eq!(count_up( &out[0..128]), 2); - assert_eq!(count_high(&out_gate[0..128]), 128); - assert_eq!(count_up( &out_gate[0..128]), 1); + assert_eq!(count_high(&out[0..128]), 8); + assert_eq!(count_up(&out[0..128]), 2); + assert_eq!(count_high(&out_gate[0..128]), 128); + assert_eq!(count_up(&out_gate[0..128]), 1); assert_eq!(count_high(&out[128..256]), 64); - assert_eq!(count_up( &out[128..256]), 2); + assert_eq!(count_up(&out[128..256]), 2); assert_eq!(count_high(&out_gate[128..256]), 0); - assert_eq!(count_up( &out_gate[128..256]), 0); + assert_eq!(count_up(&out_gate[128..256]), 0); assert_eq!(count_high(&out[256..384]), 128); - assert_eq!(count_up( &out[256..384]), 1); + assert_eq!(count_up(&out[256..384]), 1); assert_eq!(count_high(&out_gate[256..384]), 128); - assert_eq!(count_up( &out_gate[256..384]), 1); + assert_eq!(count_up(&out_gate[256..384]), 1); } fn run_probability_test_for(prob: u32) -> (usize, usize) { @@ -535,7 +541,7 @@ mod tests { phase_run += inc; } - let mut out = vec![0.0; samples]; + let mut out = vec![0.0; samples]; let mut out_gate = vec![0.0; samples]; ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); @@ -546,7 +552,7 @@ mod tests { fn check_seq_gate_div_rng() { // XXX: The result numbers are highly dependent on the // sampling rate inside run_probability_test_for(). - assert_eq!(run_probability_test_for(0x000), (5, 5)); + assert_eq!(run_probability_test_for(0x000), (5, 5)); assert_eq!(run_probability_test_for(0x100), (12, 11)); assert_eq!(run_probability_test_for(0x200), (20, 18)); assert_eq!(run_probability_test_for(0x300), (26, 23)); @@ -559,8 +565,8 @@ mod tests { assert_eq!(run_probability_test_for(0xA00), (70, 22)); assert_eq!(run_probability_test_for(0xB00), (79, 18)); assert_eq!(run_probability_test_for(0xC00), (84, 13)); - assert_eq!(run_probability_test_for(0xD00), (93, 7)); - assert_eq!(run_probability_test_for(0xE00), (96, 5)); + assert_eq!(run_probability_test_for(0xD00), (93, 7)); + assert_eq!(run_probability_test_for(0xE00), (96, 5)); assert_eq!(run_probability_test_for(0xF00), (100, 1)); } } diff --git a/src/lib.rs b/src/lib.rs index c41ba54..5ea9202 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -246,35 +246,37 @@ projects and authors, I can't relicense it. */ -pub mod nodes; +pub mod cell_dir; #[allow(unused_macros, non_snake_case)] pub mod dsp; +pub mod log; pub mod matrix; -pub mod cell_dir; -pub mod monitor; pub mod matrix_repr; +pub mod monitor; +pub mod nodes; pub mod sample_lib; mod util; -pub mod log; -pub use log::log; -pub use nodes::{new_node_engine, NodeConfigurator, NodeExecutor}; pub use cell_dir::CellDir; -pub use matrix::{Matrix, Cell}; -pub use dsp::{NodeId, ParamId, SAtom, NodeInfo}; +pub use dsp::{NodeId, NodeInfo, ParamId, SAtom}; +pub use log::log; +pub use matrix::{Cell, Matrix}; pub use matrix_repr::load_patch_from_file; pub use matrix_repr::save_patch_to_file; +pub use nodes::{new_node_engine, NodeConfigurator, NodeExecutor}; pub use sample_lib::{SampleLibrary, SampleLoadError}; pub struct Context<'a, 'b, 'c, 'd> { - pub nframes: usize, - pub output: &'a mut [&'b mut [f32]], - pub input: &'c [&'d [f32]], + pub nframes: usize, + pub output: &'a mut [&'b mut [f32]], + pub input: &'c [&'d [f32]], } impl<'a, 'b, 'c, 'd> nodes::NodeAudioContext for Context<'a, 'b, 'c, 'd> { #[inline] - fn nframes(&self) -> usize { self.nframes } + fn nframes(&self) -> usize { + self.nframes + } #[inline] fn output(&mut self, channel: usize, frame: usize, v: f32) { @@ -287,7 +289,6 @@ impl<'a, 'b, 'c, 'd> nodes::NodeAudioContext for Context<'a, 'b, 'c, 'd> { } } - pub fn test() -> bool { true } diff --git a/src/log.rs b/src/log.rs index eb26954..95b86a3 100644 --- a/src/log.rs +++ b/src/log.rs @@ -2,16 +2,14 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use std::cell::RefCell; -use ringbuf::{RingBuffer, Producer, Consumer}; use lazy_static::lazy_static; +use ringbuf::{Consumer, Producer, RingBuffer}; +use std::cell::RefCell; use std::sync::{Arc, Mutex}; lazy_static! { - static ref LOG_RECV: Arc> = { - Arc::new(Mutex::new(LogReceiver::new())) - }; + static ref LOG_RECV: Arc> = { Arc::new(Mutex::new(LogReceiver::new())) }; } thread_local! { @@ -47,17 +45,15 @@ pub fn log)>(f: F) { }); } -const MAX_LOG_BUFFER : usize = 4096; +const MAX_LOG_BUFFER: usize = 4096; pub struct LogReceiver { - consumers: Vec<(&'static str, Consumer)>, + consumers: Vec<(&'static str, Consumer)>, } impl LogReceiver { pub fn new() -> Self { - Self { - consumers: vec![], - } + Self { consumers: vec![] } } pub fn retrieve_messages(&mut self, mut f: F) { @@ -82,10 +78,7 @@ impl LogReceiver { let (producer, con) = rb.split(); self.consumers.push((name, con)); - Log { - producer, - buf: [0; 512], - } + Log { producer, buf: [0; 512] } } #[inline] @@ -99,7 +92,7 @@ impl LogReceiver { pub struct Log { producer: Producer, - buf: [u8; 512], + buf: [u8; 512], } impl Log { @@ -141,8 +134,7 @@ mod tests { let mut msgs = vec![]; for _ in 0..100 { - std::thread::sleep( - std::time::Duration::from_millis(100)); + std::thread::sleep(std::time::Duration::from_millis(100)); retrieve_log_messages(|name, s| msgs.push(name.to_string() + "/" + s)); @@ -151,6 +143,6 @@ mod tests { assert_eq!(msgs[1], "tstlog/Test Log2!"); break; } - }; + } } } diff --git a/src/matrix.rs b/src/matrix.rs index b89dad0..cea1c89 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -2,18 +2,13 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::nodes::{ - NodeConfigurator, - NodeGraphOrdering, - NodeProg, - MAX_ALLOCATED_NODES -}; -use crate::dsp::{NodeInfo, NodeId, ParamId, SAtom}; -pub use crate::CellDir; -pub use crate::nodes::MinMaxMonitorSamples; -pub use crate::monitor::MON_SIG_CNT; -use crate::matrix_repr::*; use crate::dsp::tracker::PatternData; +use crate::dsp::{NodeId, NodeInfo, ParamId, SAtom}; +use crate::matrix_repr::*; +pub use crate::monitor::MON_SIG_CNT; +pub use crate::nodes::MinMaxMonitorSamples; +use crate::nodes::{NodeConfigurator, NodeGraphOrdering, NodeProg, MAX_ALLOCATED_NODES}; +pub use crate::CellDir; use std::collections::{HashMap, HashSet}; @@ -38,21 +33,21 @@ use std::collections::{HashMap, HashSet}; ///``` #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] pub struct Cell { - node_id: NodeId, - x: u8, - y: u8, + node_id: NodeId, + x: u8, + y: u8, /// Top-Right output - out1: Option, + out1: Option, /// Bottom-Right output - out2: Option, + out2: Option, /// Bottom output - out3: Option, + out3: Option, /// Top input - in1: Option, + in1: Option, /// Top-Left input - in2: Option, + in2: Option, /// Bottom-Left input - in3: Option, + in3: Option, } impl Cell { @@ -76,17 +71,7 @@ impl Cell { /// This is an alternative constructor, in case you know the position of the /// cell before you got it from the Matrix. pub fn empty_at(node_id: NodeId, x: u8, y: u8) -> Self { - Self { - node_id, - x, - y, - out1: None, - out2: None, - out3: None, - in1: None, - in2: None, - in3: None, - } + Self { node_id, x, y, out1: None, out2: None, out3: None, in1: None, in2: None, in3: None } } /// Returns a serializable representation of this [Matrix] [Cell]. @@ -114,12 +99,12 @@ impl Cell { out: [ self.out1.map(|v| v as i16).unwrap_or(-1), self.out2.map(|v| v as i16).unwrap_or(-1), - self.out3.map(|v| v as i16).unwrap_or(-1) + self.out3.map(|v| v as i16).unwrap_or(-1), ], inp: [ self.in1.map(|v| v as i16).unwrap_or(-1), self.in2.map(|v| v as i16).unwrap_or(-1), - self.in3.map(|v| v as i16).unwrap_or(-1) + self.in3.map(|v| v as i16).unwrap_or(-1), ], } } @@ -127,33 +112,31 @@ impl Cell { pub fn from_repr(repr: &CellRepr) -> Self { Self { node_id: repr.node_id, - x: repr.x as u8, - y: repr.y as u8, - out1: if repr.out[0] < 0 { None } - else { Some(repr.out[0] as u8) }, - out2: if repr.out[1] < 0 { None } - else { Some(repr.out[1] as u8) }, - out3: if repr.out[2] < 0 { None } - else { Some(repr.out[2] as u8) }, - in1: if repr.inp[0] < 0 { None } - else { Some(repr.inp[0] as u8) }, - in2: if repr.inp[1] < 0 { None } - else { Some(repr.inp[1] as u8) }, - in3: if repr.inp[2] < 0 { None } - else { Some(repr.inp[2] as u8) }, + x: repr.x as u8, + y: repr.y as u8, + out1: if repr.out[0] < 0 { None } else { Some(repr.out[0] as u8) }, + out2: if repr.out[1] < 0 { None } else { Some(repr.out[1] as u8) }, + out3: if repr.out[2] < 0 { None } else { Some(repr.out[2] as u8) }, + in1: if repr.inp[0] < 0 { None } else { Some(repr.inp[0] as u8) }, + in2: if repr.inp[1] < 0 { None } else { Some(repr.inp[1] as u8) }, + in3: if repr.inp[2] < 0 { None } else { Some(repr.inp[2] as u8) }, } } pub fn with_pos_of(&self, other: Cell) -> Self { - let mut new = *self; - new.x = other.x; - new.y = other.y; - new + let mut new = *self; + new.x = other.x; + new.y = other.y; + new } - pub fn is_empty(&self) -> bool { self.node_id == NodeId::Nop } + pub fn is_empty(&self) -> bool { + self.node_id == NodeId::Nop + } - pub fn node_id(&self) -> NodeId { self.node_id } + pub fn node_id(&self) -> NodeId { + self.node_id + } pub fn set_node_id(&mut self, new_id: NodeId) { self.node_id = new_id; @@ -174,15 +157,13 @@ impl Cell { return None; } -// let node_info = infoh.from_node_id(self.node_id); + // let node_info = infoh.from_node_id(self.node_id); match write!(cur, "{}", self.node_id) { - Ok(_) => { + Ok(_) => { let len = cur.position() as usize; - Some( - std::str::from_utf8(&(cur.into_inner())[0..len]) - .unwrap()) - }, + Some(std::str::from_utf8(&(cur.into_inner())[0..len]).unwrap()) + } Err(_) => None, } } @@ -192,15 +173,11 @@ impl Cell { } pub fn offs_dir(&mut self, dir: CellDir) -> bool { - if let Some(new_pos) = - dir.offs_pos((self.x as usize, self.y as usize)) - { + if let Some(new_pos) = dir.offs_pos((self.x as usize, self.y as usize)) { self.x = new_pos.0 as u8; self.y = new_pos.1 as u8; true - } - else - { + } else { false } } @@ -209,54 +186,78 @@ impl Cell { match dir { CellDir::TR => self.out1.is_some(), CellDir::BR => self.out2.is_some(), - CellDir::B => self.out3.is_some(), + CellDir::B => self.out3.is_some(), CellDir::BL => self.in3.is_some(), CellDir::TL => self.in2.is_some(), - CellDir::T => self.in1.is_some(), - CellDir::C => false, + CellDir::T => self.in1.is_some(), + CellDir::C => false, } } pub fn local_port_idx(&self, dir: CellDir) -> Option { match dir { - CellDir::TR => { self.out1 }, - CellDir::BR => { self.out2 }, - CellDir::B => { self.out3 }, - CellDir::BL => { self.in3 }, - CellDir::TL => { self.in2 }, - CellDir::T => { self.in1 }, - CellDir::C => None, + CellDir::TR => self.out1, + CellDir::BR => self.out2, + CellDir::B => self.out3, + CellDir::BL => self.in3, + CellDir::TL => self.in2, + CellDir::T => self.in1, + CellDir::C => None, } } pub fn clear_io_dir(&mut self, dir: CellDir) { match dir { - CellDir::TR => { self.out1 = None; }, - CellDir::BR => { self.out2 = None; }, - CellDir::B => { self.out3 = None; }, - CellDir::BL => { self.in3 = None; }, - CellDir::TL => { self.in2 = None; }, - CellDir::T => { self.in1 = None; }, - CellDir::C => { + CellDir::TR => { + self.out1 = None; + } + CellDir::BR => { + self.out2 = None; + } + CellDir::B => { + self.out3 = None; + } + CellDir::BL => { + self.in3 = None; + } + CellDir::TL => { + self.in2 = None; + } + CellDir::T => { + self.in1 = None; + } + CellDir::C => { self.out1 = None; self.out2 = None; self.out3 = None; - self.in1 = None; - self.in2 = None; - self.in3 = None; - }, + self.in1 = None; + self.in2 = None; + self.in3 = None; + } } } pub fn set_io_dir(&mut self, dir: CellDir, idx: usize) { match dir { - CellDir::TR => { self.out1 = Some(idx as u8); }, - CellDir::BR => { self.out2 = Some(idx as u8); }, - CellDir::B => { self.out3 = Some(idx as u8); }, - CellDir::BL => { self.in3 = Some(idx as u8); }, - CellDir::TL => { self.in2 = Some(idx as u8); }, - CellDir::T => { self.in1 = Some(idx as u8); }, - CellDir::C => {}, + CellDir::TR => { + self.out1 = Some(idx as u8); + } + CellDir::BR => { + self.out2 = Some(idx as u8); + } + CellDir::B => { + self.out3 = Some(idx as u8); + } + CellDir::BL => { + self.in3 = Some(idx as u8); + } + CellDir::TL => { + self.in2 = Some(idx as u8); + } + CellDir::T => { + self.in1 = Some(idx as u8); + } + CellDir::C => {} } } @@ -278,27 +279,24 @@ impl Cell { /// has an assigned input, that edge is returned. /// With `dir` you can specify input with `CellDir::T`, output with `CellDir::B` /// and any with `CellDir::C`. - pub fn find_first_adjacent_free(&self, m: &mut Matrix, dir: CellDir) -> Option<(CellDir, Option)> { + pub fn find_first_adjacent_free( + &self, + m: &mut Matrix, + dir: CellDir, + ) -> Option<(CellDir, Option)> { let mut free_ports = vec![]; - let options : &[CellDir] = - if dir == CellDir::C { - &[CellDir::T, CellDir::TL, CellDir::BL, - CellDir::TR, CellDir::BR, CellDir::B] - - } else if dir.is_input() { - &[CellDir::T, CellDir::TL, CellDir::BL] - - } else { - &[CellDir::TR, CellDir::BR, CellDir::B] - }; + let options: &[CellDir] = if dir == CellDir::C { + &[CellDir::T, CellDir::TL, CellDir::BL, CellDir::TR, CellDir::BR, CellDir::B] + } else if dir.is_input() { + &[CellDir::T, CellDir::TL, CellDir::BL] + } else { + &[CellDir::TR, CellDir::BR, CellDir::B] + }; for dir in options { if let Some(pos) = dir.offs_pos((self.x as usize, self.y as usize)) { - if m.get(pos.0, pos.1) - .map(|c| c.is_empty()) - .unwrap_or(false) - { + if m.get(pos.0, pos.1).map(|c| c.is_empty()).unwrap_or(false) { free_ports.push(dir); } } @@ -320,27 +318,24 @@ impl Cell { /// Finds the all adjacent free places around the current cell. /// With `dir` you can specify input with `CellDir::T`, output with `CellDir::B` /// and any with `CellDir::C`. - pub fn find_all_adjacent_free(&self, m: &mut Matrix, dir: CellDir) -> Vec<(CellDir, (usize, usize))> { + pub fn find_all_adjacent_free( + &self, + m: &mut Matrix, + dir: CellDir, + ) -> Vec<(CellDir, (usize, usize))> { let mut free_ports = vec![]; - let options : &[CellDir] = - if dir == CellDir::C { - &[CellDir::T, CellDir::TL, CellDir::BL, - CellDir::TR, CellDir::BR, CellDir::B] - - } else if dir.is_input() { - &[CellDir::T, CellDir::TL, CellDir::BL] - - } else { - &[CellDir::TR, CellDir::BR, CellDir::B] - }; + let options: &[CellDir] = if dir == CellDir::C { + &[CellDir::T, CellDir::TL, CellDir::BL, CellDir::TR, CellDir::BR, CellDir::B] + } else if dir.is_input() { + &[CellDir::T, CellDir::TL, CellDir::BL] + } else { + &[CellDir::TR, CellDir::BR, CellDir::B] + }; for dir in options { if let Some(pos) = dir.offs_pos((self.x as usize, self.y as usize)) { - if m.get(pos.0, pos.1) - .map(|c| c.is_empty()) - .unwrap_or(false) - { + if m.get(pos.0, pos.1).map(|c| c.is_empty()).unwrap_or(false) { free_ports.push((*dir, pos)); } } @@ -352,9 +347,7 @@ impl Cell { /// If the port is connected, it will return the position of the other cell. pub fn is_port_dir_connected(&self, m: &mut Matrix, dir: CellDir) -> Option<(usize, usize)> { if self.has_dir_set(dir) { - if let Some(new_pos) = - dir.offs_pos((self.x as usize, self.y as usize)) - { + if let Some(new_pos) = dir.offs_pos((self.x as usize, self.y as usize)) { if let Some(dst_cell) = m.get(new_pos.0, new_pos.1) { if dst_cell.has_dir_set(dir.flip()) { return Some(new_pos); @@ -373,21 +366,18 @@ use std::sync::{Arc, Mutex}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum MatrixError { CycleDetected, - DuplicatedInput { - output1: (NodeId, u8), - output2: (NodeId, u8), - }, + DuplicatedInput { output1: (NodeId, u8), output2: (NodeId, u8) }, NonEmptyCell { cell: Cell }, - PosOutOfRange + PosOutOfRange, } /// An intermediate data structure to store a single edge in the [Matrix]. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct Edge { - from: NodeId, - from_out: u8, - to: NodeId, - to_input: u8, + from: NodeId, + from_out: u8, + to: NodeId, + to_input: u8, } /// This trait can be passed into [Matrix] as trait object @@ -418,13 +408,13 @@ pub trait MatrixObserver { pub struct Matrix { /// The node configurator to control the backend. - config: NodeConfigurator, + config: NodeConfigurator, /// Holds the actual 2 dimensional matrix cells in one big vector. - matrix: Vec, + matrix: Vec, /// Width of the matrix. - w: usize, + w: usize, /// Height of the matrix. - h: usize, + h: usize, /// The retained data structure of the graph topology. /// This is used by `sync()` and `check()` to determine the @@ -470,18 +460,18 @@ unsafe impl Send for Matrix {} impl Matrix { pub fn new(config: NodeConfigurator, w: usize, h: usize) -> Self { - let mut matrix : Vec = Vec::new(); + let mut matrix: Vec = Vec::new(); matrix.resize(w * h, Cell::empty(NodeId::Nop)); Self { - monitored_cell: Cell::empty(NodeId::Nop), - gen_counter: 0, - saved_matrix: None, - graph_ordering: NodeGraphOrdering::new(), - edges: Vec::with_capacity(MAX_ALLOCATED_NODES * 2), + monitored_cell: Cell::empty(NodeId::Nop), + gen_counter: 0, + saved_matrix: None, + graph_ordering: NodeGraphOrdering::new(), + edges: Vec::with_capacity(MAX_ALLOCATED_NODES * 2), assigned_inputs: HashSet::new(), - properties: HashMap::new(), - observer: None, + properties: HashMap::new(), + observer: None, config, w, h, @@ -494,7 +484,9 @@ impl Matrix { self.observer = Some(obs); } - pub fn size(&self) -> (usize, usize) { (self.w, self.h) } + pub fn size(&self) -> (usize, usize) { + (self.w, self.h) + } pub fn unique_index_for(&self, node_id: &NodeId) -> Option { self.config.unique_index_for(node_id) @@ -524,9 +516,7 @@ impl Matrix { self.config.filtered_out_fb_for(ni, out) } - pub fn get_pattern_data(&self, tracker_id: usize) - -> Option>> - { + pub fn get_pattern_data(&self, tracker_id: usize) -> Option>> { self.config.get_pattern_data(tracker_id) } @@ -583,9 +573,9 @@ impl Matrix { /// // a cycle: /// assert!(res.is_err()); ///``` - pub fn change_matrix(&mut self, mut f: F) - -> Result<(), MatrixError> - where F: FnMut(&mut Self) + pub fn change_matrix(&mut self, mut f: F) -> Result<(), MatrixError> + where + F: FnMut(&mut Self), { self.save_matrix(); @@ -601,9 +591,9 @@ impl Matrix { /// Like [Matrix::change_matrix] but the function passed to this /// needs to return a `Result<(), MatrixError>`. - pub fn change_matrix_err(&mut self, mut f: F) - -> Result<(), MatrixError> - where F: FnMut(&mut Self) -> Result<(), MatrixError> + pub fn change_matrix_err(&mut self, mut f: F) -> Result<(), MatrixError> + where + F: FnMut(&mut Self) -> Result<(), MatrixError>, { self.save_matrix(); @@ -699,7 +689,9 @@ impl Matrix { self.monitor_cell(Cell::empty(NodeId::Nop)); let _ = self.sync(); - if let Some(obs) = &self.observer { obs.update_all(); } + if let Some(obs) = &self.observer { + obs.update_all(); + } } /// Iterates through all atoms. This is useful for reading @@ -716,7 +708,9 @@ impl Matrix { /// graph. Such as parameter values. /// /// HexoSynth for instance updates the UI by tracking this value. - pub fn get_generation(&self) -> usize { self.gen_counter } + pub fn get_generation(&self) -> usize { + self.gen_counter + } /// Returns a serializable representation of the matrix. /// This representation contains all parameters, @@ -747,36 +741,28 @@ impl Matrix { pub fn to_repr(&self) -> MatrixRepr { let (params, atoms) = self.config.dump_param_values(); - let mut cells : Vec = vec![]; - self.for_each(|_x, _y, cell| + let mut cells: Vec = vec![]; + self.for_each(|_x, _y, cell| { if cell.node_id() != NodeId::Nop { cells.push(cell.to_repr()) - }); + } + }); - let mut patterns : Vec> = vec![]; + let mut patterns: Vec> = vec![]; let mut tracker_id = 0; while let Some(pdata) = self.get_pattern_data(tracker_id) { - patterns.push( - if pdata.lock().unwrap().is_unset() { None } - else { Some(pdata.lock().unwrap().to_repr()) }); + patterns.push(if pdata.lock().unwrap().is_unset() { + None + } else { + Some(pdata.lock().unwrap().to_repr()) + }); tracker_id += 1; } - let properties = - self.properties - .iter() - .map(|(k, v)| (k.to_string(), v.clone())) - .collect(); + let properties = self.properties.iter().map(|(k, v)| (k.to_string(), v.clone())).collect(); - MatrixRepr { - cells, - params, - atoms, - patterns, - properties, - version: 2, - } + MatrixRepr { cells, params, atoms, patterns, properties, version: 2 } } /// Loads the matrix from a previously my [Matrix::to_repr] @@ -789,10 +775,7 @@ impl Matrix { let normalize_params = repr.version > 1; - self.config.load_dumped_param_values( - &repr.params[..], - &repr.atoms[..], - normalize_params); + self.config.load_dumped_param_values(&repr.params[..], &repr.atoms[..], normalize_params); for (key, val) in repr.properties.iter() { self.properties.insert(key.to_string(), val.clone()); @@ -813,7 +796,9 @@ impl Matrix { let ret = self.sync(); - if let Some(obs) = &self.observer { obs.update_all(); } + if let Some(obs) = &self.observer { + obs.update_all(); + } ret } @@ -843,7 +828,9 @@ impl Matrix { pub fn set_prop(&mut self, key: &str, val: SAtom) { self.gen_counter += 1; self.properties.insert(key.to_string(), val); - if let Some(obs) = &self.observer { obs.update_prop(key); } + if let Some(obs) = &self.observer { + obs.update_prop(key); + } } /// Retrieves a matrix property. See also [Matrix::set_prop] for an @@ -861,7 +848,9 @@ impl Matrix { } /// Returns the currently monitored cell. - pub fn monitored_cell(&self) -> &Cell { &self.monitored_cell } + pub fn monitored_cell(&self) -> &Cell { + &self.monitored_cell + } /// Sets the cell to monitor next. Please bear in mind, that you need to /// call `sync` before retrieving the cell from the matrix, otherwise @@ -870,20 +859,14 @@ impl Matrix { pub fn monitor_cell(&mut self, cell: Cell) { self.monitored_cell = cell; - let inputs = [ - cell.in1, - cell.in2, - cell.in3, - ]; - let outputs = [ - cell.out1, - cell.out2, - cell.out3, - ]; + let inputs = [cell.in1, cell.in2, cell.in3]; + let outputs = [cell.out1, cell.out2, cell.out3]; self.config.monitor(&cell.node_id, &inputs, &outputs); - if let Some(obs) = &self.observer { obs.update_monitor(&self.monitored_cell); } + if let Some(obs) = &self.observer { + obs.update_monitor(&self.monitored_cell); + } } /// Is called by [Matrix::sync] to refresh the monitored cell. @@ -912,7 +895,9 @@ impl Matrix { pub fn set_param(&mut self, param: ParamId, at: SAtom) { self.config.set_param(param.clone(), at); self.gen_counter += 1; - if let Some(obs) = &self.observer { obs.update_param(¶m); } + if let Some(obs) = &self.observer { + obs.update_param(¶m); + } } /// Retrieve the modulation amount of the input parameter. @@ -921,11 +906,15 @@ impl Matrix { } /// Assign or remove modulation of an input parameter. - pub fn set_param_modamt(&mut self, param: ParamId, modamt: Option) - -> Result<(), MatrixError> - { + pub fn set_param_modamt( + &mut self, + param: ParamId, + modamt: Option, + ) -> Result<(), MatrixError> { if self.config.set_param_modamt(param.clone(), modamt) { - if let Some(obs) = &self.observer { obs.update_param(¶m); } + if let Some(obs) = &self.observer { + obs.update_param(¶m); + } // XXX: Remove the observer from the matrix, so the sync() does not // generate a matrix graph update! There is no structural change! @@ -940,9 +929,7 @@ impl Matrix { } } - pub fn get_adjacent_output(&self, x: usize, y: usize, dir: CellDir) - -> Option<(NodeId, u8)> - { + pub fn get_adjacent_output(&self, x: usize, y: usize, dir: CellDir) -> Option<(NodeId, u8)> { if dir.is_output() { return None; } @@ -953,19 +940,20 @@ impl Matrix { return None; } - let cell_out = - match dir { - CellDir::T => cell.out3?, - CellDir::TL => cell.out2?, - CellDir::BL => cell.out1?, - _ => { return None; } - }; + let cell_out = match dir { + CellDir::T => cell.out3?, + CellDir::TL => cell.out2?, + CellDir::BL => cell.out1?, + _ => { + return None; + } + }; Some((cell.node_id, cell_out)) } pub fn get_adjacent(&self, x: usize, y: usize, dir: CellDir) -> Option<&Cell> { - let offs : (i32, i32) = dir.as_offs(x); + let offs: (i32, i32) = dir.as_offs(x); let x = x as i32 + offs.0; let y = y as i32 + offs.1; @@ -982,7 +970,7 @@ impl Matrix { match edge { CellDir::TR => cell.in3.is_some(), CellDir::BR => cell.in2.is_some(), - CellDir::B => cell.in1.is_some(), + CellDir::B => cell.in1.is_some(), _ => false, } } else { @@ -999,7 +987,12 @@ impl Matrix { } } - pub fn edge_label<'a>(&self, cell: &Cell, edge: CellDir, buf: &'a mut [u8]) -> Option<(&'a str, bool)> { + pub fn edge_label<'a>( + &self, + cell: &Cell, + edge: CellDir, + buf: &'a mut [u8], + ) -> Option<(&'a str, bool)> { use std::io::Write; let mut cur = std::io::Cursor::new(buf); @@ -1007,51 +1000,42 @@ impl Matrix { return None; } - let out_idx = - match edge { - CellDir::TR => Some(cell.out1), - CellDir::BR => Some(cell.out2), - CellDir::B => Some(cell.out3), - _ => None, - }; - let in_idx = - match edge { - CellDir::BL => Some(cell.in3), - CellDir::TL => Some(cell.in2), - CellDir::T => Some(cell.in1), - _ => None, - }; + let out_idx = match edge { + CellDir::TR => Some(cell.out1), + CellDir::BR => Some(cell.out2), + CellDir::B => Some(cell.out3), + _ => None, + }; + let in_idx = match edge { + CellDir::BL => Some(cell.in3), + CellDir::TL => Some(cell.in2), + CellDir::T => Some(cell.in1), + _ => None, + }; let info = self.info_for(&cell.node_id)?; let mut is_connected_edge = false; - let edge_str = - if let Some(out_idx) = out_idx { - //d// println!(" CHECK ADJ EDGE {},{} @ {:?}", cell.x, cell.y, edge); - is_connected_edge = - self.adjacent_edge_has_input( - cell.x as usize, cell.y as usize, edge); + let edge_str = if let Some(out_idx) = out_idx { + //d// println!(" CHECK ADJ EDGE {},{} @ {:?}", cell.x, cell.y, edge); + is_connected_edge = + self.adjacent_edge_has_input(cell.x as usize, cell.y as usize, edge); - info.out_name(out_idx? as usize) - - } else if let Some(in_idx) = in_idx { - info.in_name(in_idx? as usize) - - } else { - None - }; + info.out_name(out_idx? as usize) + } else if let Some(in_idx) = in_idx { + info.in_name(in_idx? as usize) + } else { + None + }; let edge_str = edge_str?; match write!(cur, "{}", edge_str) { - Ok(_) => { + Ok(_) => { let len = cur.position() as usize; - Some(( - std::str::from_utf8(&(cur.into_inner())[0..len]) - .unwrap(), - is_connected_edge)) - }, + Some((std::str::from_utf8(&(cur.into_inner())[0..len]).unwrap(), is_connected_edge)) + } Err(_) => None, } } @@ -1100,20 +1084,16 @@ impl Matrix { // - check if the previous node exist, if not, // create them on the fly now: for inst in 0..cell.node_id.instance() { - let new_hole_filler_node_id = - cell.node_id.to_instance(inst); + let new_hole_filler_node_id = cell.node_id.to_instance(inst); - if self.config - .unique_index_for(&new_hole_filler_node_id) - .is_none() - { - self.config.create_node(new_hole_filler_node_id) + if self.config.unique_index_for(&new_hole_filler_node_id).is_none() { + self.config + .create_node(new_hole_filler_node_id) .expect("NodeInfo existent in Matrix"); } } - self.config.create_node(cell.node_id) - .expect("NodeInfo existent in Matrix"); + self.config.create_node(cell.node_id).expect("NodeInfo existent in Matrix"); } } } @@ -1140,43 +1120,40 @@ impl Matrix { match (cell.in1, in1_output) { (Some(in1_idx), Some(in1_output)) => { self.edges.push(Edge { - to: cell.node_id, + to: cell.node_id, to_input: in1_idx, - from: in1_output.0, + from: in1_output.0, from_out: in1_output.1, }); - self.graph_ordering.add_edge( - in1_output.0, cell.node_id); - }, - _ => {}, + self.graph_ordering.add_edge(in1_output.0, cell.node_id); + } + _ => {} } match (cell.in2, in2_output) { (Some(in2_idx), Some(in2_output)) => { self.edges.push(Edge { - to: cell.node_id, + to: cell.node_id, to_input: in2_idx, - from: in2_output.0, + from: in2_output.0, from_out: in2_output.1, }); - self.graph_ordering.add_edge( - in2_output.0, cell.node_id); - }, - _ => {}, + self.graph_ordering.add_edge(in2_output.0, cell.node_id); + } + _ => {} } match (cell.in3, in3_output) { (Some(in3_idx), Some(in3_output)) => { self.edges.push(Edge { - to: cell.node_id, + to: cell.node_id, to_input: in3_idx, - from: in3_output.0, + from: in3_output.0, from_out: in3_output.1, }); - self.graph_ordering.add_edge( - in3_output.0, cell.node_id); - }, - _ => {}, + self.graph_ordering.add_edge(in3_output.0, cell.node_id); + } + _ => {} } } } @@ -1209,7 +1186,8 @@ impl Matrix { self.config.set_prog_node_exec_connection( &mut prog, (edge.to, edge.to_input), - (edge.from, edge.from_out)); + (edge.from, edge.from_out), + ); } Ok(prog) @@ -1266,9 +1244,7 @@ impl Matrix { output2: (edge.from, edge.from_out), }); } else { - edge_map.insert( - (edge.to, edge.to_input), - (edge.from, edge.from_out)); + edge_map.insert((edge.to, edge.to_input), (edge.from, edge.from_out)); } } @@ -1307,7 +1283,9 @@ impl Matrix { // just in case something has changed with that monitored cell. self.remonitor_cell(); - if let Some(obs) = &self.observer { obs.update_matrix(); } + if let Some(obs) = &self.observer { + obs.update_matrix(); + } Ok(()) } @@ -1341,16 +1319,13 @@ mod tests { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Sin(1)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.place(1, 1, - Cell::empty(NodeId::Sin(2)) - .input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Sin(1)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.place(1, 1, Cell::empty(NodeId::Sin(2)).input(Some(0), None, None)); matrix.sync().unwrap(); node_exec.process_graph_updates(); @@ -1362,8 +1337,14 @@ mod tests { let prog = node_exec.get_prog(); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2|0) at=(0-0) mod=(0-0))"); - assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(0-0) cpy=(o0 => i2))"); - assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3|0) in=(4-6|1) at=(0-0) mod=(0-0) cpy=(o1 => i4))"); + assert_eq!( + prog.prog[1].to_string(), + "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(0-0) cpy=(o0 => i2))" + ); + assert_eq!( + prog.prog[2].to_string(), + "Op(i=2 out=(2-3|0) in=(4-6|1) at=(0-0) mod=(0-0) cpy=(o1 => i4))" + ); } #[test] @@ -1373,40 +1354,29 @@ mod tests { let (node_conf, _node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Sin(1)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.place(1, 1, - Cell::empty(NodeId::Sin(2)) - .input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Sin(1)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.place(1, 1, Cell::empty(NodeId::Sin(2)).input(Some(0), None, None)); matrix.sync().unwrap(); - assert!( - matrix.param_input_is_used( - NodeId::Sin(1).inp_param("freq").unwrap())); - assert!( - !matrix.param_input_is_used( - NodeId::Sin(0).inp_param("freq").unwrap())); + assert!(matrix.param_input_is_used(NodeId::Sin(1).inp_param("freq").unwrap())); + assert!(!matrix.param_input_is_used(NodeId::Sin(0).inp_param("freq").unwrap())); matrix.place(1, 0, Cell::empty(NodeId::Nop)); matrix.sync().unwrap(); - assert!( - !matrix.param_input_is_used( - NodeId::Sin(1).inp_param("freq").unwrap())); - assert!( - !matrix.param_input_is_used( - NodeId::Sin(2).inp_param("freq").unwrap())); + assert!(!matrix.param_input_is_used(NodeId::Sin(1).inp_param("freq").unwrap())); + assert!(!matrix.param_input_is_used(NodeId::Sin(2).inp_param("freq").unwrap())); } #[test] fn check_matrix_filled() { + use crate::dsp::{Node, NodeId}; use crate::nodes::new_node_engine; - use crate::dsp::{NodeId, Node}; let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 9, 9); @@ -1423,8 +1393,7 @@ mod tests { node_exec.process_graph_updates(); let nodes = node_exec.get_nodes(); - let ex_nodes : Vec<&Node> = - nodes.iter().filter(|n| n.to_id(0) != NodeId::Nop).collect(); + let ex_nodes: Vec<&Node> = nodes.iter().filter(|n| n.to_id(0) != NodeId::Nop).collect(); assert_eq!(ex_nodes.len(), 9 * 9 + 1); } @@ -1435,13 +1404,12 @@ mod tests { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); matrix.sync().unwrap(); node_exec.set_sample_rate(44100.0); @@ -1454,7 +1422,10 @@ mod tests { let prog = node_exec.get_prog(); assert_eq!(prog.prog.len(), 2); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2|0) at=(0-0) mod=(0-0))"); - assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-1|0) in=(2-5|1) at=(0-1) mod=(0-0) cpy=(o0 => i2))"); + assert_eq!( + prog.prog[1].to_string(), + "Op(i=1 out=(1-1|0) in=(2-5|1) at=(0-1) mod=(0-0) cpy=(o0 => i2))" + ); } #[test] @@ -1464,13 +1435,12 @@ mod tests { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(2)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 0, Cell::empty(NodeId::Sin(2)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); matrix.sync().unwrap(); node_exec.set_sample_rate(44100.0); @@ -1485,7 +1455,10 @@ mod tests { let prog = node_exec.get_prog(); assert_eq!(prog.prog.len(), 2); assert_eq!(prog.prog[0].to_string(), "Op(i=2 out=(2-3|1) in=(4-6|0) at=(0-0) mod=(0-0))"); - assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-3|0) in=(6-9|1) at=(0-1) mod=(0-0) cpy=(o2 => i6))"); + assert_eq!( + prog.prog[1].to_string(), + "Op(i=3 out=(3-3|0) in=(6-9|1) at=(0-1) mod=(0-0) cpy=(o2 => i6))" + ); } #[test] @@ -1496,20 +1469,15 @@ mod tests { let mut matrix = Matrix::new(node_conf, 3, 3); matrix.save_matrix(); - matrix.place(0, 1, - Cell::empty(NodeId::Sin(1)) - .input(Some(0), None, None)); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(1)) - .out(None, None, Some(0))); - let error = - if let Err(_) = matrix.check() { - matrix.restore_matrix(); - true - } else { - matrix.sync().unwrap(); - false - }; + matrix.place(0, 1, Cell::empty(NodeId::Sin(1)).input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(1)).out(None, None, Some(0))); + let error = if let Err(_) = matrix.check() { + matrix.restore_matrix(); + true + } else { + matrix.sync().unwrap(); + false + }; // In this examples case there is an error, as we created // a cycle: @@ -1524,24 +1492,19 @@ mod tests { let mut matrix = Matrix::new(node_conf, 5, 5); matrix.save_matrix(); - matrix.place(0, 1, - Cell::empty(NodeId::Sin(0)) - .input(Some(0), None, None)); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(1)) - .out(None, None, Some(0))); + matrix.place(0, 1, Cell::empty(NodeId::Sin(0)).input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(1)).out(None, None, Some(0))); - matrix.place(0, 3, - Cell::empty(NodeId::Sin(0)) - .input(Some(0), None, None)); - matrix.place(0, 2, - Cell::empty(NodeId::Sin(2)) - .out(None, None, Some(0))); + matrix.place(0, 3, Cell::empty(NodeId::Sin(0)).input(Some(0), None, None)); + matrix.place(0, 2, Cell::empty(NodeId::Sin(2)).out(None, None, Some(0))); - assert_eq!(matrix.check(), Err(MatrixError::DuplicatedInput { - output1: (NodeId::Sin(1), 0), - output2: (NodeId::Sin(2), 0), - })); + assert_eq!( + matrix.check(), + Err(MatrixError::DuplicatedInput { + output1: (NodeId::Sin(1), 0), + output2: (NodeId::Sin(2), 0), + }) + ); } #[test] @@ -1551,35 +1514,23 @@ mod tests { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Sin(1)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.place(0, 1, - Cell::empty(NodeId::Sin(3)) - .input(None, None, None) - .out(None, Some(0), None)); - matrix.place(1, 1, - Cell::empty(NodeId::Sin(2)) - .input(Some(0), Some(1), None)); - matrix.set_param_modamt( - NodeId::Sin(1).param_by_idx(0).unwrap(), - Some(0.5)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(1).param_by_idx(1).unwrap(), - Some(0.33)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(0).param_by_idx(0).unwrap(), - Some(0.25)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(2).param_by_idx(0).unwrap(), - Some(0.75)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(2).param_by_idx(1).unwrap(), - Some(-0.75)).unwrap(); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Sin(1)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.place( + 0, + 1, + Cell::empty(NodeId::Sin(3)).input(None, None, None).out(None, Some(0), None), + ); + matrix.place(1, 1, Cell::empty(NodeId::Sin(2)).input(Some(0), Some(1), None)); + matrix.set_param_modamt(NodeId::Sin(1).param_by_idx(0).unwrap(), Some(0.5)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(1).param_by_idx(1).unwrap(), Some(0.33)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(0).param_by_idx(0).unwrap(), Some(0.25)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(2).param_by_idx(0).unwrap(), Some(0.75)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(2).param_by_idx(1).unwrap(), Some(-0.75)).unwrap(); matrix.sync().unwrap(); node_exec.process_graph_updates(); @@ -1587,7 +1538,10 @@ mod tests { let prog = node_exec.get_prog(); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2|0) at=(0-0) mod=(0-1))"); assert_eq!(prog.prog[1].to_string(), "Op(i=3 out=(3-4|1) in=(6-8|0) at=(0-0) mod=(5-5))"); - assert_eq!(prog.prog[2].to_string(), "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)"); + assert_eq!( + prog.prog[2].to_string(), + "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)" + ); assert_eq!(prog.prog[3].to_string(), "Op(i=2 out=(2-3|0) in=(4-6|3) at=(0-0) mod=(3-5) cpy=(o1 => i4) cpy=(o3 => i5) mod=3 mod=4)"); } @@ -1598,33 +1552,30 @@ mod tests { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - matrix.place(0, 0, - Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Sin(1)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.place(1, 1, - Cell::empty(NodeId::Sin(2)) - .input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Sin(1)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.place(1, 1, Cell::empty(NodeId::Sin(2)).input(Some(0), None, None)); matrix.sync().unwrap(); - matrix.set_param_modamt( - NodeId::Sin(1).param_by_idx(0).unwrap(), - Some(0.5)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(1).param_by_idx(1).unwrap(), - Some(0.33)).unwrap(); - matrix.set_param_modamt( - NodeId::Sin(0).param_by_idx(0).unwrap(), - Some(0.25)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(1).param_by_idx(0).unwrap(), Some(0.5)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(1).param_by_idx(1).unwrap(), Some(0.33)).unwrap(); + matrix.set_param_modamt(NodeId::Sin(0).param_by_idx(0).unwrap(), Some(0.25)).unwrap(); node_exec.process_graph_updates(); let prog = node_exec.get_prog(); assert_eq!(prog.prog[0].to_string(), "Op(i=0 out=(0-1|1) in=(0-2|0) at=(0-0) mod=(0-1))"); - assert_eq!(prog.prog[1].to_string(), "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)"); - assert_eq!(prog.prog[2].to_string(), "Op(i=2 out=(2-3|0) in=(4-6|1) at=(0-0) mod=(3-3) cpy=(o1 => i4))"); + assert_eq!( + prog.prog[1].to_string(), + "Op(i=1 out=(1-2|1) in=(2-4|1) at=(0-0) mod=(1-3) cpy=(o0 => i2) mod=1)" + ); + assert_eq!( + prog.prog[2].to_string(), + "Op(i=2 out=(2-3|0) in=(4-6|1) at=(0-0) mod=(3-3) cpy=(o1 => i4))" + ); } #[test] diff --git a/src/matrix_repr.rs b/src/matrix_repr.rs index 2f10962..93866d5 100644 --- a/src/matrix_repr.rs +++ b/src/matrix_repr.rs @@ -3,25 +3,21 @@ // See README.md and COPYING for details. use crate::dsp::{NodeId, ParamId, SAtom}; -use serde_json::{Value, json}; +use serde_json::{json, Value}; #[derive(Debug, Clone, Copy)] pub struct CellRepr { pub node_id: NodeId, - pub x: usize, - pub y: usize, - pub inp: [i16; 3], - pub out: [i16; 3], + pub x: usize, + pub y: usize, + pub inp: [i16; 3], + pub out: [i16; 3], } -fn deserialize_node_id(v: &Value, i1: usize, i2: usize) - -> Result -{ +fn deserialize_node_id(v: &Value, i1: usize, i2: usize) -> Result { let nid = NodeId::from_str(v[i1].as_str().unwrap_or("???")); if nid == NodeId::Nop { - return Err( - MatrixDeserError::UnknownNode( - v[i1].as_str().unwrap_or("???").to_string())); + return Err(MatrixDeserError::UnknownNode(v[i1].as_str().unwrap_or("???").to_string())); } Ok(nid.to_instance(v[i2].as_i64().unwrap_or(0) as usize)) @@ -30,22 +26,20 @@ fn deserialize_node_id(v: &Value, i1: usize, i2: usize) fn inp2idx(node_id: NodeId, v: &Value) -> i16 { let inp = v.as_i64().unwrap_or(-2) as i16; - if inp > -2 { inp } - else { - v.as_str() - .map(|s| node_id.inp(s).map(|i| i as i16).unwrap_or(-1)) - .unwrap_or(-1) + if inp > -2 { + inp + } else { + v.as_str().map(|s| node_id.inp(s).map(|i| i as i16).unwrap_or(-1)).unwrap_or(-1) } } fn out2idx(node_id: NodeId, v: &Value) -> i16 { let out = v.as_i64().unwrap_or(-2) as i16; - if out > -2 { out } - else { - v.as_str() - .map(|s| node_id.out(s).map(|i| i as i16).unwrap_or(-1)) - .unwrap_or(-1) + if out > -2 { + out + } else { + v.as_str().map(|s| node_id.out(s).map(|i| i as i16).unwrap_or(-1)).unwrap_or(-1) } } @@ -53,9 +47,7 @@ fn inp_idx2value(node_id: NodeId, idx: i16) -> Value { if idx == -1 { json!(-1) } else { - node_id.inp_name_by_idx(idx as u8) - .map(|n| json!(n)) - .unwrap_or_else(|| json!(-1)) + node_id.inp_name_by_idx(idx as u8).map(|n| json!(n)).unwrap_or_else(|| json!(-1)) } } @@ -63,13 +55,10 @@ fn out_idx2value(node_id: NodeId, idx: i16) -> Value { if idx == -1 { json!(-1) } else { - node_id.out_name_by_idx(idx as u8) - .map(|n| json!(n)) - .unwrap_or_else(|| json!(-1)) + node_id.out_name_by_idx(idx as u8).map(|n| json!(n)).unwrap_or_else(|| json!(-1)) } } - impl CellRepr { pub fn serialize(&self) -> Value { json!([ @@ -77,12 +66,16 @@ impl CellRepr { self.node_id.instance(), self.x, self.y, - [inp_idx2value(self.node_id, self.inp[0]), - inp_idx2value(self.node_id, self.inp[1]), - inp_idx2value(self.node_id, self.inp[2])], - [out_idx2value(self.node_id, self.out[0]), - out_idx2value(self.node_id, self.out[1]), - out_idx2value(self.node_id, self.out[2])], + [ + inp_idx2value(self.node_id, self.inp[0]), + inp_idx2value(self.node_id, self.inp[1]), + inp_idx2value(self.node_id, self.inp[2]) + ], + [ + out_idx2value(self.node_id, self.out[0]), + out_idx2value(self.node_id, self.out[1]), + out_idx2value(self.node_id, self.out[2]) + ], ]) } @@ -91,31 +84,31 @@ impl CellRepr { Ok(Self { node_id, - x: v[2].as_i64().unwrap_or(0) as usize, - y: v[3].as_i64().unwrap_or(0) as usize, + x: v[2].as_i64().unwrap_or(0) as usize, + y: v[3].as_i64().unwrap_or(0) as usize, inp: [ inp2idx(node_id, &v[4][0]), inp2idx(node_id, &v[4][1]), - inp2idx(node_id, &v[4][2]) + inp2idx(node_id, &v[4][2]), ], out: [ out2idx(node_id, &v[5][0]), out2idx(node_id, &v[5][1]), - out2idx(node_id, &v[5][2]) + out2idx(node_id, &v[5][2]), ], }) } } -use crate::dsp::tracker::{MAX_PATTERN_LEN, MAX_COLS}; +use crate::dsp::tracker::{MAX_COLS, MAX_PATTERN_LEN}; #[derive(Debug, Clone)] pub struct PatternRepr { pub col_types: [u8; MAX_COLS], - pub data: Vec>, - pub rows: usize, + pub data: Vec>, + pub rows: usize, pub edit_step: usize, - pub cursor: (usize, usize), + pub cursor: (usize, usize), } impl PatternRepr { @@ -177,25 +170,24 @@ impl PatternRepr { Ok(Self { col_types, data, - rows: v["rows"] .as_i64().unwrap_or(0) as usize, - edit_step: v["edit_step"].as_i64().unwrap_or(0) as usize, + rows: v["rows"].as_i64().unwrap_or(0) as usize, + edit_step: v["edit_step"].as_i64().unwrap_or(0) as usize, cursor: ( v["cursor_row"].as_i64().unwrap_or(0) as usize, - v["cursor_col"].as_i64().unwrap_or(0) as usize + v["cursor_col"].as_i64().unwrap_or(0) as usize, ), }) } } - #[derive(Debug, Clone)] pub struct MatrixRepr { - pub cells: Vec, - pub params: Vec<(ParamId, f32, Option)>, - pub atoms: Vec<(ParamId, SAtom)>, - pub patterns: Vec>, + pub cells: Vec, + pub params: Vec<(ParamId, f32, Option)>, + pub atoms: Vec<(ParamId, SAtom)>, + pub patterns: Vec>, pub properties: Vec<(String, SAtom)>, - pub version: i64, + pub version: i64, } #[derive(Debug, Clone)] @@ -236,23 +228,35 @@ impl From for MatrixDeserError { fn deserialize_atom(v: &Value) -> Result { match v[0].as_str().unwrap_or("?") { "i" => { - if let Some(v) = v[1].as_i64() { Ok(SAtom::setting(v)) } - else { Err(MatrixDeserError::InvalidAtom(v.to_string())) } - }, + if let Some(v) = v[1].as_i64() { + Ok(SAtom::setting(v)) + } else { + Err(MatrixDeserError::InvalidAtom(v.to_string())) + } + } "p" => { - if let Some(v) = v[1].as_f64() { Ok(SAtom::param(v as f32)) } - else { Err(MatrixDeserError::InvalidAtom(v.to_string())) } - }, + if let Some(v) = v[1].as_f64() { + Ok(SAtom::param(v as f32)) + } else { + Err(MatrixDeserError::InvalidAtom(v.to_string())) + } + } "s" => { - if let Some(v) = v[1].as_str() { Ok(SAtom::str(v)) } - else { Err(MatrixDeserError::InvalidAtom(v.to_string())) } - }, + if let Some(v) = v[1].as_str() { + Ok(SAtom::str(v)) + } else { + Err(MatrixDeserError::InvalidAtom(v.to_string())) + } + } "as" => { - if let Some(v) = v[1].as_str() { Ok(SAtom::audio_unloaded(v)) } - else { Err(MatrixDeserError::InvalidAtom(v.to_string())) } - }, + if let Some(v) = v[1].as_str() { + Ok(SAtom::audio_unloaded(v)) + } else { + Err(MatrixDeserError::InvalidAtom(v.to_string())) + } + } "ms" => { - let mut buf : [f32; 8] = [0.0; 8]; + let mut buf: [f32; 8] = [0.0; 8]; for i in 0..8 { if let Some(v) = v[i + 1].as_f64() { @@ -263,44 +267,35 @@ fn deserialize_atom(v: &Value) -> Result { } Ok(SAtom::micro(&buf)) - }, + } _ => Err(MatrixDeserError::InvalidAtom(v.to_string())), } } fn serialize_atom(atom: &SAtom) -> Value { match atom { - SAtom::MicroSample(s) => json!(["ms", - s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], - ]), - SAtom::Str(s) => json!(["s", s]), + SAtom::MicroSample(s) => json!(["ms", s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7],]), + SAtom::Str(s) => json!(["s", s]), SAtom::AudioSample((s, _)) => json!(["as", s]), - SAtom::Setting(i) => json!(["i", i]), - SAtom::Param(p) => json!(["p", p]), + SAtom::Setting(i) => json!(["i", i]), + SAtom::Param(p) => json!(["p", p]), } } impl MatrixRepr { pub fn empty() -> Self { - let cells = vec![]; - let params = vec![]; - let atoms = vec![]; - let patterns = vec![]; + let cells = vec![]; + let params = vec![]; + let atoms = vec![]; + let patterns = vec![]; let properties = vec![]; - Self { - cells, - params, - atoms, - patterns, - properties, - version: 2, - } + Self { cells, params, atoms, patterns, properties, version: 2 } } pub fn write_to_file(&mut self, filepath: &str) -> std::io::Result<()> { - use std::io::prelude::*; use std::fs::OpenOptions; + use std::io::prelude::*; let tmp_filepath = format!("{}~", filepath); @@ -308,29 +303,20 @@ impl MatrixRepr { ser.push('\n'); let mut file = - OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(&tmp_filepath)?; - file.write_all(ser.as_bytes())?; - std::fs::rename(&tmp_filepath, &filepath)?; + OpenOptions::new().create(true).write(true).truncate(true).open(&tmp_filepath)?; + file.write_all(ser.as_bytes())?; + std::fs::rename(&tmp_filepath, &filepath)?; - Ok(()) + Ok(()) } pub fn read_from_file(filepath: &str) -> Result { - use std::io::prelude::*; use std::fs::OpenOptions; + use std::io::prelude::*; - let mut file = - OpenOptions::new() - .write(false) - .create(false) - .read(true) - .open(&filepath)?; + let mut file = OpenOptions::new().write(false).create(false).read(true).open(&filepath)?; - let mut contents : Vec = Vec::new(); + let mut contents: Vec = Vec::new(); file.read_to_end(&mut contents)?; let s = std::str::from_utf8(&contents)?; @@ -339,12 +325,12 @@ impl MatrixRepr { } pub fn deserialize(s: &str) -> Result { - let v : Value = serde_json::from_str(s)?; + let v: Value = serde_json::from_str(s)?; let mut m = MatrixRepr::empty(); if let Some(version) = v.get("VERSION") { - let version : i64 = version.as_i64().unwrap_or(0); + let version: i64 = version.as_i64().unwrap_or(0); if version > 2 { return Err(MatrixDeserError::BadVersion); @@ -367,13 +353,13 @@ impl MatrixRepr { let param_id = node_id.inp_param(v[2].as_str().unwrap_or("")); if let Some(param_id) = param_id { - m.params.push( - (param_id, - v[3].as_f64().unwrap_or(0.0) as f32, - v[4].as_f64().map(|v| v as f32))); + m.params.push(( + param_id, + v[3].as_f64().unwrap_or(0.0) as f32, + v[4].as_f64().map(|v| v as f32), + )); } else { - return Err( - MatrixDeserError::UnknownParamId(v.to_string())); + return Err(MatrixDeserError::UnknownParamId(v.to_string())); } } } @@ -386,9 +372,9 @@ impl MatrixRepr { if let Some(param_id) = param_id { m.atoms.push((param_id, deserialize_atom(&v[3])?)) - //d// } else { - //d// return Err( - //d// MatrixDeserError::UnknownParamId(v.to_string())); + //d// } else { + //d// return Err( + //d// MatrixDeserError::UnknownParamId(v.to_string())); } } } @@ -397,18 +383,18 @@ impl MatrixRepr { if let Value::Array(props) = props { for v in props.iter() { let key = v[0].as_str().unwrap_or(""); - m.properties.push( - (key.to_string(), deserialize_atom(&v[1])?)); + m.properties.push((key.to_string(), deserialize_atom(&v[1])?)); } } let patterns = &v["patterns"]; if let Value::Array(patterns) = patterns { for p in patterns.iter() { - m.patterns.push( - if p.is_object() { - Some(PatternRepr::deserialize(&p)?) - } else { None }); + m.patterns.push(if p.is_object() { + Some(PatternRepr::deserialize(&p)?) + } else { + None + }); } } @@ -427,12 +413,7 @@ impl MatrixRepr { let mut params = json!([]); if let Value::Array(params) = &mut params { for (p, v, ma) in self.params.iter() { - let mut param_v = json!([ - p.node_id().name(), - p.node_id().instance(), - p.name(), - v, - ]); + let mut param_v = json!([p.node_id().name(), p.node_id().instance(), p.name(), v,]); if let Value::Array(param_v) = &mut param_v { if let Some(ma) = ma { @@ -449,13 +430,12 @@ impl MatrixRepr { let mut atoms = json!([]); if let Value::Array(atoms) = &mut atoms { for (p, v) in self.atoms.iter() { - atoms.push( - json!([ - p.node_id().name(), - p.node_id().instance(), - p.name(), - serialize_atom(v), - ])); + atoms.push(json!([ + p.node_id().name(), + p.node_id().instance(), + p.name(), + serialize_atom(v), + ])); } } @@ -482,9 +462,7 @@ impl MatrixRepr { let mut patterns = json!([]); if let Value::Array(patterns) = &mut patterns { for p in self.patterns.iter() { - patterns.push( - if let Some(p) = p { p.serialize() } - else { Value::Null }); + patterns.push(if let Some(p) = p { p.serialize() } else { Value::Null }); } } @@ -494,17 +472,19 @@ impl MatrixRepr { } } -pub fn load_patch_from_file(matrix: &mut crate::matrix::Matrix, filepath: &str) - -> Result<(), MatrixDeserError> -{ +pub fn load_patch_from_file( + matrix: &mut crate::matrix::Matrix, + filepath: &str, +) -> Result<(), MatrixDeserError> { let mr = MatrixRepr::read_from_file(filepath)?; matrix.from_repr(&mr)?; Ok(()) } -pub fn save_patch_to_file(matrix: &mut crate::matrix::Matrix, filepath: &str) - -> std::io::Result<()> -{ +pub fn save_patch_to_file( + matrix: &mut crate::matrix::Matrix, + filepath: &str, +) -> std::io::Result<()> { let mut mr = matrix.to_repr(); mr.write_to_file(filepath) } @@ -513,7 +493,7 @@ pub fn save_patch_to_file(matrix: &mut crate::matrix::Matrix, filepath: &str) mod tests { use super::*; - use crate::matrix::{Matrix, Cell}; + use crate::matrix::{Cell, Matrix}; #[test] fn check_empty_repr_serialization() { @@ -521,8 +501,10 @@ mod tests { let s = matrix_repr.serialize(); - assert_eq!(s, - "{\"VERSION\":2,\"atoms\":[],\"cells\":[],\"params\":[],\"patterns\":[],\"props\":[]}"); + assert_eq!( + s, + "{\"VERSION\":2,\"atoms\":[],\"cells\":[],\"params\":[],\"patterns\":[],\"props\":[]}" + ); assert!(MatrixRepr::deserialize(&s).is_ok()); } @@ -535,13 +517,12 @@ mod tests { let sin = NodeId::Sin(2); - matrix.place(0, 0, - Cell::empty(sin) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -577,18 +558,15 @@ mod tests { let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string(); assert_eq!(s, v.to_string()); - let v = - serialize_atom( - &SAtom::micro(&[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0])); + let v = serialize_atom(&SAtom::micro(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0])); assert_eq!(v.to_string(), "[\"ms\",1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]"); let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string(); assert_eq!(s, v.to_string()); - let v = - serialize_atom( - &SAtom::audio( - "lol.wav", - std::sync::Arc::new(vec![1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0]))); + let v = serialize_atom(&SAtom::audio( + "lol.wav", + std::sync::Arc::new(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]), + )); assert_eq!(v.to_string(), "[\"as\",\"lol.wav\"]"); let s = serialize_atom(&deserialize_atom(&v).unwrap()).to_string(); assert_eq!(s, v.to_string()); @@ -596,15 +574,16 @@ mod tests { #[test] fn check_cell_repr() { - let cell = - Cell::empty(NodeId::Out(2)) - .input(Some(2), Some(0), Some(1)) - .out(Some(11), Some(4), Some(1)); + let cell = Cell::empty(NodeId::Out(2)).input(Some(2), Some(0), Some(1)).out( + Some(11), + Some(4), + Some(1), + ); let cr = cell.to_repr(); let s = cr.serialize().to_string(); - let v : Value = serde_json::from_str(&s).unwrap(); + let v: Value = serde_json::from_str(&s).unwrap(); let cr2 = CellRepr::deserialize(&v).unwrap(); let s2 = cr2.serialize().to_string(); @@ -621,13 +600,12 @@ mod tests { let sin = NodeId::Sin(2); - matrix.place(0, 0, - Cell::empty(sin) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -636,8 +614,7 @@ mod tests { let mut mr = matrix.to_repr(); let s2 = mr.serialize().to_string(); - save_patch_to_file( - &mut matrix, "hexosynth_test_patch.hxy").unwrap(); + save_patch_to_file(&mut matrix, "hexosynth_test_patch.hxy").unwrap(); s2 }; @@ -648,8 +625,7 @@ mod tests { let (node_conf, mut _node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - load_patch_from_file( - &mut matrix, "hexosynth_test_patch.hxy").unwrap(); + load_patch_from_file(&mut matrix, "hexosynth_test_patch.hxy").unwrap(); let mut mr = matrix.to_repr(); let s = mr.serialize().to_string(); @@ -670,9 +646,7 @@ mod tests { let ts = NodeId::TSeq(0); - matrix.place(0, 0, - Cell::empty(ts) - .out(None, Some(0), None)); + matrix.place(0, 0, Cell::empty(ts).out(None, Some(0), None)); matrix.sync().unwrap(); { @@ -694,8 +668,7 @@ mod tests { let mut mr = matrix.to_repr(); let s2 = mr.serialize().to_string(); - save_patch_to_file( - &mut matrix, "hexosynth_test_patch_2.hxy").unwrap(); + save_patch_to_file(&mut matrix, "hexosynth_test_patch_2.hxy").unwrap(); s2 }; @@ -706,8 +679,7 @@ mod tests { let (node_conf, mut _node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - load_patch_from_file( - &mut matrix, "hexosynth_test_patch_2.hxy").unwrap(); + load_patch_from_file(&mut matrix, "hexosynth_test_patch_2.hxy").unwrap(); let mut mr = matrix.to_repr(); let s = mr.serialize().to_string(); @@ -748,7 +720,8 @@ mod tests { matrix.for_each_atom(|unique_idx, param_id, atom, _modamt| { v.insert( format!("{}_{}", unique_idx, param_id.name().to_string()), - param_id.denorm(atom.f())); + param_id.denorm(atom.f()), + ); }); assert_eq!(*v.get("0_freq").unwrap(), 440.0); @@ -776,7 +749,8 @@ mod tests { matrix.for_each_atom(|unique_idx, param_id, atom, _modamt| { v.insert( format!("{}_{}", unique_idx, param_id.name().to_string()), - param_id.denorm(atom.f())); + param_id.denorm(atom.f()), + ); }); assert_eq!(*v.get("0_freq").unwrap(), 440.0); @@ -796,19 +770,16 @@ mod tests { let sin = NodeId::Sin(0); - matrix.place(0, 0, - Cell::empty(sin) - .out(None, Some(0), None)); - matrix.place(1, 0, - Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.set_param_modamt( - sin.inp_param("det").unwrap(), Some(-0.6)).unwrap(); + matrix.place(0, 0, Cell::empty(sin).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.set_param_modamt(sin.inp_param("det").unwrap(), Some(-0.6)).unwrap(); matrix.sync().unwrap(); - matrix.set_param_modamt( - sin.inp_param("freq").unwrap(), Some(0.6)).unwrap(); + matrix.set_param_modamt(sin.inp_param("freq").unwrap(), Some(0.6)).unwrap(); let mut mr = matrix.to_repr(); mr.serialize().to_string() @@ -858,8 +829,7 @@ mod tests { #[test] fn check_matrix_repr_old_format2new() { - let old_format = - "{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\ + let old_format = "{\"VERSION\":1,\"atoms\":[[\"out\",0,\"mono\",[\"i\",0]]],\ \"cells\":[[\"sin\",2,0,0,[-1,-1,-1],[-1,0,-1]],[\"out\",0,1,0,\ [-1,0,-1],[-1,-1,0]]],\"params\":[[\"out\",0,\"ch1\",0.0],\ [\"out\",0,\"ch2\",0.0],[\"sin\",0,\"det\",0.0],[\"sin\",1,\ diff --git a/src/monitor.rs b/src/monitor.rs index c85f53d..52e7f06 100644 --- a/src/monitor.rs +++ b/src/monitor.rs @@ -3,25 +3,25 @@ // See README.md and COPYING for details. use crate::dsp::MAX_BLOCK_SIZE; -use ringbuf::{RingBuffer, Producer, Consumer}; +use ringbuf::{Consumer, Producer, RingBuffer}; -use std::sync::{Arc, Mutex}; use std::sync::atomic::AtomicBool; +use std::sync::{Arc, Mutex}; use std::thread::JoinHandle; use crate::util::PerfTimer; /// 3 inputs, 3 outputs of signal monitors. -pub const MON_SIG_CNT : usize = 6; +pub const MON_SIG_CNT: usize = 6; /// Just some base to determine the monitor buffer sizes. -const IMAGINARY_MAX_SAMPLE_RATE : usize = 48000; +const IMAGINARY_MAX_SAMPLE_RATE: usize = 48000; /// The number of minmax samples to hold. -pub const MONITOR_MINMAX_SAMPLES : usize = 160; +pub const MONITOR_MINMAX_SAMPLES: usize = 160; /// The length in seconds of the MONITOR_MINMAX_SAMPLES -const MONITOR_MINMAX_LEN_S : usize = 3; +const MONITOR_MINMAX_LEN_S: usize = 3; /// The sleep time of the thread that receives monitoring data /// from the backend/audio thread. @@ -29,28 +29,27 @@ const MONITOR_MINMAX_LEN_S : usize = 3; /// smooth updates. The maximum is thus about 16ms. /// The processing of the audio buffer is somewhere in the us /// area. -const MONITOR_PROC_THREAD_INTERVAL_MS : u64 = 10; +const MONITOR_PROC_THREAD_INTERVAL_MS: u64 = 10; // TODO / FIXME: We should recalculate this on the basis of the // real actual sample rate, otherwise the monitor scope // is going to be too fast. /// The number of audio samples over which to calculate /// one min/max sample. Typically something around 750. -const MONITOR_INPUT_LEN_PER_SAMPLE : usize = - (MONITOR_MINMAX_LEN_S * IMAGINARY_MAX_SAMPLE_RATE) - / MONITOR_MINMAX_SAMPLES; +const MONITOR_INPUT_LEN_PER_SAMPLE: usize = + (MONITOR_MINMAX_LEN_S * IMAGINARY_MAX_SAMPLE_RATE) / MONITOR_MINMAX_SAMPLES; /// Maximum number of monitor buffers to hold in the backend. /// Typically there are only 16-32ms of monitor content floating /// around, as the monitor processing thread regularily /// processes the monitor. -const MONITOR_BUF_COUNT : usize = -// 2 for safety margin +const MONITOR_BUF_COUNT: usize = + // 2 for safety margin 2 * (IMAGINARY_MAX_SAMPLE_RATE / MAX_BLOCK_SIZE); pub struct MonitorBackend { - rb_mon_prod: Producer, - rb_recycle_con: Consumer, + rb_mon_prod: Producer, + rb_recycle_con: Consumer, /// Holds enough monitor buffers to hold about 1-2 seconds /// of data. The [MonitorBuf] boxes are written in the @@ -85,7 +84,7 @@ impl MonitorBackend { /// Sends a [MonitorBuf] to the [MonitorProcessor]. pub fn send_mon_buf(&mut self, buf: MonitorBufPtr) { match self.rb_mon_prod.push(buf) { - Ok(_) => (), + Ok(_) => (), Err(buf) => self.unused_monitor_buffers.push(buf), } } @@ -94,27 +93,27 @@ impl MonitorBackend { /// Implements the logic for min/maxing a single signal channel/line. pub struct MonitorMinMax { /// Index of the signal in the [MonitorBuf] - sig_idx: usize, + sig_idx: usize, /// A ring buffer of min/max samples, written to by `buf_write_ptr`. - buf: [(f32, f32); MONITOR_MINMAX_SAMPLES], + buf: [(f32, f32); MONITOR_MINMAX_SAMPLES], /// The pointer/index into `buf` to the next update to write. - buf_write_ptr: usize, + buf_write_ptr: usize, /// Holds the currently accumulated min/max values and the length /// of so far processed audio rate samples. Once MONITOR_INPUT_LEN_PER_SAMPLE /// is reached, this will be written into `buf`. - cur_min_max: (f32, f32, usize), + cur_min_max: (f32, f32, usize), } impl MonitorMinMax { pub fn new(sig_idx: usize) -> Self { Self { sig_idx, - buf: [(0.0, 0.0); MONITOR_MINMAX_SAMPLES], + buf: [(0.0, 0.0); MONITOR_MINMAX_SAMPLES], buf_write_ptr: 0, - cur_min_max: (100.0, -100.0, 0), + cur_min_max: (100.0, -100.0, 0), } } @@ -123,23 +122,18 @@ impl MonitorMinMax { pub fn process(&mut self, mon_buf: &mut MonitorBufPtr) -> bool { let mut new_data = false; - while let Some(sample) = - mon_buf.next_sample_for_signal(self.sig_idx) - { + while let Some(sample) = mon_buf.next_sample_for_signal(self.sig_idx) { self.cur_min_max.0 = self.cur_min_max.0.min(sample); self.cur_min_max.1 = self.cur_min_max.1.max(sample); self.cur_min_max.2 += 1; if self.cur_min_max.2 >= MONITOR_INPUT_LEN_PER_SAMPLE { - self.buf[self.buf_write_ptr] = ( - self.cur_min_max.0, - self.cur_min_max.1 - ); + self.buf[self.buf_write_ptr] = (self.cur_min_max.0, self.cur_min_max.1); new_data = true; self.buf_write_ptr = (self.buf_write_ptr + 1) % self.buf.len(); - self.cur_min_max.0 = 100.0; + self.cur_min_max.0 = 100.0; self.cur_min_max.1 = -100.0; self.cur_min_max.2 = 0; } @@ -160,10 +154,7 @@ pub struct MinMaxMonitorSamples { impl MinMaxMonitorSamples { pub fn new() -> Self { - Self { - samples: [(0.0, 0.0); MONITOR_MINMAX_SAMPLES], - buf_ptr: 0, - } + Self { samples: [(0.0, 0.0); MONITOR_MINMAX_SAMPLES], buf_ptr: 0 } } fn copy_from(&mut self, min_max_slice: (usize, &[(f32, f32)])) { @@ -182,13 +173,19 @@ impl MinMaxMonitorSamples { &self.samples[idx] } - pub fn len(&self) -> usize { MONITOR_MINMAX_SAMPLES } + pub fn len(&self) -> usize { + MONITOR_MINMAX_SAMPLES + } - pub fn is_empty(&self) -> bool { false } + pub fn is_empty(&self) -> bool { + false + } } impl Default for MinMaxMonitorSamples { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } impl std::ops::Index for MinMaxMonitorSamples { @@ -208,29 +205,27 @@ impl std::ops::Index for MinMaxMonitorSamples { /// Just call [Monitor::get_minmax_monitor_samples] and you will always get /// the most current data. pub struct Monitor { - terminate_proc: Arc, - proc_thread: Option>, + terminate_proc: Arc, + proc_thread: Option>, - new_data: Arc, - monitor_samples: Arc>, - monitor_samples_copy: [MinMaxMonitorSamples; MON_SIG_CNT], + new_data: Arc, + monitor_samples: Arc>, + monitor_samples_copy: [MinMaxMonitorSamples; MON_SIG_CNT], } impl Monitor { - pub fn new(rb_mon_con: Consumer, - rb_recycle_prod: Producer) - -> Self - { + pub fn new( + rb_mon_con: Consumer, + rb_recycle_prod: Producer, + ) -> Self { let terminate_proc = Arc::new(AtomicBool::new(false)); - let th_terminate = terminate_proc.clone(); + let th_terminate = terminate_proc.clone(); - let monitor_samples = - Arc::new(Mutex::new( - [MinMaxMonitorSamples::new(); MON_SIG_CNT])); + let monitor_samples = Arc::new(Mutex::new([MinMaxMonitorSamples::new(); MON_SIG_CNT])); let th_mon_samples = monitor_samples.clone(); - let new_data = Arc::new(AtomicBool::new(false)); - let th_new_data = new_data.clone(); + let new_data = Arc::new(AtomicBool::new(false)); + let th_new_data = new_data.clone(); let th = std::thread::spawn(move || { let mut proc = MonitorProcessor::new(rb_mon_con, rb_recycle_prod); @@ -246,8 +241,7 @@ impl Monitor { if proc.check_new_data() { let mut ms = - th_mon_samples.lock() - .expect("Unpoisoned Lock for monitor_samples"); + th_mon_samples.lock().expect("Unpoisoned Lock for monitor_samples"); for i in 0..MON_SIG_CNT { ms[i].copy_from(proc.minmax_slice_for_signal(i)); } @@ -258,9 +252,9 @@ impl Monitor { // let ta = std::time::Instant::now().duration_since(ta); // println!("txx Elapsed: {:?} | {:?}", t0, ta); - std::thread::sleep( - std::time::Duration::from_millis( - MONITOR_PROC_THREAD_INTERVAL_MS)); + std::thread::sleep(std::time::Duration::from_millis( + MONITOR_PROC_THREAD_INTERVAL_MS, + )); } }); @@ -281,15 +275,12 @@ impl Monitor { let mut pt = PerfTimer::new("MMMSamp").off(); if self.new_data.load(std::sync::atomic::Ordering::Relaxed) { - let ms = - self.monitor_samples.lock() - .expect("Unpoisoned Lock for monitor_samples"); + let ms = self.monitor_samples.lock().expect("Unpoisoned Lock for monitor_samples"); pt.print("XXX"); for i in 0..MON_SIG_CNT { - ms[i].copy_to( - &mut self.monitor_samples_copy[i]); + ms[i].copy_to(&mut self.monitor_samples_copy[i]); } self.new_data.store(false, std::sync::atomic::Ordering::Relaxed); @@ -309,8 +300,8 @@ impl Drop for Monitor { /// Coordinates the processing of incoming MonitorBufs. pub struct MonitorProcessor { - rb_mon_con: Consumer, - rb_recycle_prod: Producer, + rb_mon_con: Consumer, + rb_recycle_prod: Producer, new_data: bool, @@ -318,21 +309,16 @@ pub struct MonitorProcessor { } impl MonitorProcessor { - pub fn new(rb_mon_con: Consumer, - rb_recycle_prod: Producer) - -> Self - { + pub fn new( + rb_mon_con: Consumer, + rb_recycle_prod: Producer, + ) -> Self { let mut procs = vec![]; for i in 0..MON_SIG_CNT { procs.push(MonitorMinMax::new(i)); } - Self { - rb_mon_con, - rb_recycle_prod, - procs, - new_data: false, - } + Self { rb_mon_con, rb_recycle_prod, procs, new_data: false } } /// Helper function for tests, to access the current state of @@ -374,10 +360,10 @@ impl MonitorProcessor { /// Creates a pair of interconnected MonitorBackend and MonitorProcessor /// instances, to be sent to different threads. pub fn new_monitor_processor() -> (MonitorBackend, Monitor) { - let rb_monitor = RingBuffer::new(MONITOR_BUF_COUNT); - let rb_recycle = RingBuffer::new(MONITOR_BUF_COUNT); + let rb_monitor = RingBuffer::new(MONITOR_BUF_COUNT); + let rb_recycle = RingBuffer::new(MONITOR_BUF_COUNT); - let (rb_mon_prod, rb_mon_con) = rb_monitor.split(); + let (rb_mon_prod, rb_mon_con) = rb_monitor.split(); let (rb_recycle_prod, rb_recycle_con) = rb_recycle.split(); let mut unused_monitor_buffers = Vec::with_capacity(MONITOR_BUF_COUNT); @@ -386,11 +372,7 @@ pub fn new_monitor_processor() -> (MonitorBackend, Monitor) { unused_monitor_buffers.push(MonitorBuf::alloc()); } - let backend = MonitorBackend { - rb_mon_prod, - rb_recycle_con, - unused_monitor_buffers, - }; + let backend = MonitorBackend { rb_mon_prod, rb_recycle_con, unused_monitor_buffers }; let frontend = Monitor::new(rb_mon_con, rb_recycle_prod); @@ -406,10 +388,10 @@ pub struct MonitorBuf { sig_blocks: [f32; MON_SIG_CNT * MAX_BLOCK_SIZE], /// Holds the lengths of the individual signal data blocks in `sig_blocks`. - len: [usize; MON_SIG_CNT], + len: [usize; MON_SIG_CNT], /// Holds the lengths of the individual signal data blocks in `sig_blocks`. - read_idx: [usize; MON_SIG_CNT], + read_idx: [usize; MON_SIG_CNT], } /// A trait that represents any kind of monitorable sources @@ -429,13 +411,13 @@ impl MonitorBuf { pub fn alloc() -> MonitorBufPtr { Box::new(Self { sig_blocks: [0.0; MON_SIG_CNT * MAX_BLOCK_SIZE], - len: [0; MON_SIG_CNT], - read_idx: [0; MON_SIG_CNT], + len: [0; MON_SIG_CNT], + read_idx: [0; MON_SIG_CNT], }) } pub fn reset(&mut self) { - self.len = [0; MON_SIG_CNT]; + self.len = [0; MON_SIG_CNT]; self.read_idx = [0; MON_SIG_CNT]; } @@ -453,7 +435,8 @@ impl MonitorBuf { } pub fn feed(&mut self, idx: usize, len: usize, data: T) - where T: MonitorSource + where + T: MonitorSource, { let sb_idx = idx * MAX_BLOCK_SIZE; data.copy_to(len, &mut self.sig_blocks[sb_idx..(sb_idx + len)]); @@ -469,13 +452,11 @@ pub type MonitorBufPtr = Box; mod tests { use super::*; - fn send_n_monitor_bufs(backend: &mut MonitorBackend, - first: f32, last: f32, count: usize) - { + fn send_n_monitor_bufs(backend: &mut MonitorBackend, first: f32, last: f32, count: usize) { for _ in 0..count { let mut mon = backend.get_unused_mon_buf().unwrap(); - let mut samples : Vec = vec![]; + let mut samples: Vec = vec![]; for _ in 0..MAX_BLOCK_SIZE { samples.push(0.0); } @@ -491,19 +472,15 @@ mod tests { fn wait_for_monitor_process() { // FIXME: This could in theory do some spin waiting for // the new_data flag! - std::thread::sleep( - std::time::Duration::from_millis( - 3 * MONITOR_PROC_THREAD_INTERVAL_MS)); + std::thread::sleep(std::time::Duration::from_millis(3 * MONITOR_PROC_THREAD_INTERVAL_MS)); } #[test] fn check_monitor_proc() { let (mut backend, mut frontend) = new_monitor_processor(); - let count1 = - (MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1; - let count2 = - 2 * ((MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1); + let count1 = (MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1; + let count2 = 2 * ((MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1); send_n_monitor_bufs(&mut backend, -0.9, 0.8, count1); @@ -517,15 +494,11 @@ mod tests { assert_eq!(sl[MONITOR_MINMAX_SAMPLES - 2], (-0.7, 0.8)); assert_eq!(sl[MONITOR_MINMAX_SAMPLES - 3], (-0.9, 0.8)); - assert_eq!( - backend.count_unused_mon_bufs(), - MONITOR_BUF_COUNT - count1 - count2); + assert_eq!(backend.count_unused_mon_bufs(), MONITOR_BUF_COUNT - count1 - count2); backend.check_recycle(); - assert_eq!( - backend.count_unused_mon_bufs(), - MONITOR_BUF_COUNT); + assert_eq!(backend.count_unused_mon_bufs(), MONITOR_BUF_COUNT); } #[test] @@ -566,12 +539,12 @@ mod tests { let mut mon = backend.get_unused_mon_buf().unwrap(); - let mut samples : Vec = vec![]; + let mut samples: Vec = vec![]; let part1_len = rest - 1; for _ in 0..part1_len { samples.push(0.0); } - samples[0] = -0.9; + samples[0] = -0.9; samples[part1_len - 1] = -0.95; mon.feed(0, part1_len, &samples[..]); @@ -596,16 +569,14 @@ mod tests { fn check_monitor_wrap_buf() { let (mut backend, mut frontend) = new_monitor_processor(); - let count1 = - (MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1; + let count1 = (MONITOR_INPUT_LEN_PER_SAMPLE / MAX_BLOCK_SIZE) + 1; for i in 0..MONITOR_MINMAX_SAMPLES { let v = i as f32 / MONITOR_MINMAX_SAMPLES as f32; send_n_monitor_bufs(&mut backend, -0.9, v, count1); // Give the MonitorProcessor some time to work on the buffers. - std::thread::sleep( - std::time::Duration::from_millis(5)); + std::thread::sleep(std::time::Duration::from_millis(5)); backend.check_recycle(); } wait_for_monitor_process(); @@ -613,12 +584,8 @@ mod tests { let sl = frontend.get_minmax_monitor_samples(0); - assert_eq!( - (sl[MONITOR_MINMAX_SAMPLES - 1].1 * 10000.0).floor() as u32, - 9937); + assert_eq!((sl[MONITOR_MINMAX_SAMPLES - 1].1 * 10000.0).floor() as u32, 9937); - assert_eq!( - backend.count_unused_mon_bufs(), - MONITOR_BUF_COUNT); + assert_eq!(backend.count_unused_mon_bufs(), MONITOR_BUF_COUNT); } } diff --git a/src/nodes/drop_thread.rs b/src/nodes/drop_thread.rs index 3dd5b3f..df54955 100644 --- a/src/nodes/drop_thread.rs +++ b/src/nodes/drop_thread.rs @@ -10,13 +10,12 @@ use ringbuf::Consumer; /// thread and dropping them. pub(crate) struct DropThread { terminate: std::sync::Arc, - th: Option>, + th: Option>, } impl DropThread { pub(crate) fn new(mut graph_drop_con: Consumer) -> Self { - let terminate = - std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); + let terminate = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)); let th_terminate = terminate.clone(); let th = std::thread::spawn(move || { @@ -34,10 +33,7 @@ impl DropThread { } }); - Self { - th: Some(th), - terminate, - } + Self { th: Some(th), terminate } } } diff --git a/src/nodes/feedback_filter.rs b/src/nodes/feedback_filter.rs index 2f17bfb..c97ff45 100644 --- a/src/nodes/feedback_filter.rs +++ b/src/nodes/feedback_filter.rs @@ -2,38 +2,28 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -use crate::dsp::NodeId; use super::VisualSamplingFilter; +use crate::dsp::NodeId; use std::collections::HashMap; pub struct FeedbackFilter { - led_filters: HashMap, - out_filters: HashMap<(NodeId, u8), VisualSamplingFilter>, - recalc_state: bool, + led_filters: HashMap, + out_filters: HashMap<(NodeId, u8), VisualSamplingFilter>, + recalc_state: bool, } impl FeedbackFilter { pub fn new() -> Self { - Self { - led_filters: HashMap::new(), - out_filters: HashMap::new(), - recalc_state: true, - } + Self { led_filters: HashMap::new(), out_filters: HashMap::new(), recalc_state: true } } - fn get_out_filter_for_node(&mut self, node_id: &NodeId, out: u8) - -> &mut VisualSamplingFilter - { - self.out_filters - .entry((*node_id, out)) - .or_insert_with(|| VisualSamplingFilter::new()) + fn get_out_filter_for_node(&mut self, node_id: &NodeId, out: u8) -> &mut VisualSamplingFilter { + self.out_filters.entry((*node_id, out)).or_insert_with(|| VisualSamplingFilter::new()) } fn get_led_filter_for_node(&mut self, node_id: &NodeId) -> &mut VisualSamplingFilter { - self.led_filters - .entry(*node_id) - .or_insert_with(|| VisualSamplingFilter::new()) + self.led_filters.entry(*node_id).or_insert_with(|| VisualSamplingFilter::new()) } pub fn trigger_recalc(&mut self) { diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs index 9b67f28..9726334 100644 --- a/src/nodes/mod.rs +++ b/src/nodes/mod.rs @@ -2,36 +2,35 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -pub const MAX_ALLOCATED_NODES : usize = 256; -pub const MAX_INPUTS : usize = 32; -pub const MAX_SMOOTHERS : usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs -pub const MAX_AVAIL_TRACKERS : usize = 128; -pub const MAX_FB_DELAYS : usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM -pub const FB_DELAY_TIME_US : usize = 3140; // 3.14ms (should be enough for MAX_BLOCK_SIZE) -// This means, until 384000 sample rate the times are accurate. -pub const MAX_FB_DELAY_SRATE : usize = 48000 * 8; -pub const MAX_FB_DELAY_SIZE : usize = - (MAX_FB_DELAY_SRATE * FB_DELAY_TIME_US) / 1000000; +pub const MAX_ALLOCATED_NODES: usize = 256; +pub const MAX_INPUTS: usize = 32; +pub const MAX_SMOOTHERS: usize = 36 + 4; // 6 * 6 modulator inputs + 4 UI Knobs +pub const MAX_AVAIL_TRACKERS: usize = 128; +pub const MAX_FB_DELAYS: usize = 256; // 256 feedback delays, thats roughly 1.2MB RAM +pub const FB_DELAY_TIME_US: usize = 3140; // 3.14ms (should be enough for MAX_BLOCK_SIZE) + // This means, until 384000 sample rate the times are accurate. +pub const MAX_FB_DELAY_SRATE: usize = 48000 * 8; +pub const MAX_FB_DELAY_SIZE: usize = (MAX_FB_DELAY_SRATE * FB_DELAY_TIME_US) / 1000000; -mod node_prog; -mod node_exec; -mod node_conf; mod drop_thread; -mod node_graph_ordering; -pub mod visual_sampling_filter; mod feedback_filter; +mod node_conf; +mod node_exec; +mod node_graph_ordering; +mod node_prog; +pub mod visual_sampling_filter; pub(crate) use visual_sampling_filter::*; -pub use node_exec::*; -pub use node_prog::*; -pub use node_conf::*; pub use feedback_filter::*; +pub use node_conf::*; +pub use node_exec::*; pub use node_graph_ordering::NodeGraphOrdering; +pub use node_prog::*; +use crate::dsp::{Node, SAtom}; pub use crate::monitor::MinMaxMonitorSamples; use crate::monitor::MON_SIG_CNT; -use crate::dsp::{Node, SAtom}; #[derive(Debug)] #[allow(dead_code)] @@ -48,21 +47,32 @@ pub(crate) enum DropMsg { pub enum GraphMessage { NewNode { index: u8, node: Node }, NewProg { prog: NodeProg, copy_old_out: bool }, - Clear { prog: NodeProg }, + Clear { prog: NodeProg }, } /// Messages for small updates between the NodeExecutor thread /// and the NodeConfigurator. #[derive(Debug)] pub enum QuickMessage { - AtomUpdate { at_idx: usize, value: SAtom }, - ParamUpdate { input_idx: usize, value: f32 }, - ModamtUpdate { mod_idx: usize, modamt: f32 }, + AtomUpdate { + at_idx: usize, + value: SAtom, + }, + ParamUpdate { + input_idx: usize, + value: f32, + }, + ModamtUpdate { + mod_idx: usize, + modamt: f32, + }, /// Sets the buffer indices to monitor with the FeedbackProcessor. - SetMonitor { bufs: [usize; MON_SIG_CNT], }, + SetMonitor { + bufs: [usize; MON_SIG_CNT], + }, } -pub const UNUSED_MONITOR_IDX : usize = 99999; +pub const UNUSED_MONITOR_IDX: usize = 99999; /// Creates a NodeConfigurator and a NodeExecutor which are interconnected /// by ring buffers. @@ -76,4 +86,3 @@ pub fn new_node_engine() -> (NodeConfigurator, NodeExecutor) { (nc, ne) } - diff --git a/src/nodes/node_conf.rs b/src/nodes/node_conf.rs index 36a1dad..890a2d9 100644 --- a/src/nodes/node_conf.rs +++ b/src/nodes/node_conf.rs @@ -3,26 +3,19 @@ // See README.md and COPYING for details. use super::{ - GraphMessage, QuickMessage, - NodeProg, NodeOp, - FeedbackFilter, - MAX_ALLOCATED_NODES, - MAX_INPUTS, - MAX_AVAIL_TRACKERS, - UNUSED_MONITOR_IDX + FeedbackFilter, GraphMessage, NodeOp, NodeProg, QuickMessage, MAX_ALLOCATED_NODES, + MAX_AVAIL_TRACKERS, MAX_INPUTS, UNUSED_MONITOR_IDX, }; +use crate::dsp::tracker::{PatternData, Tracker}; +use crate::dsp::{node_factory, Node, NodeId, NodeInfo, ParamId, SAtom}; +use crate::monitor::{new_monitor_processor, MinMaxMonitorSamples, Monitor, MON_SIG_CNT}; use crate::nodes::drop_thread::DropThread; -use crate::dsp::{NodeId, ParamId, NodeInfo, Node, SAtom, node_factory}; -use crate::{SampleLibrary}; use crate::util::AtomicFloat; -use crate::monitor::{ - Monitor, MON_SIG_CNT, new_monitor_processor, MinMaxMonitorSamples -}; -use crate::dsp::tracker::{Tracker, PatternData}; +use crate::SampleLibrary; -use ringbuf::{RingBuffer, Producer}; -use std::sync::{Arc, Mutex}; +use ringbuf::{Producer, RingBuffer}; use std::collections::HashMap; +use std::sync::{Arc, Mutex}; use triple_buffer::Output; @@ -30,17 +23,17 @@ use triple_buffer::Output; /// and holds other important house keeping information for the [NodeConfigurator]. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NodeInstance { - id: NodeId, - in_use: bool, - prog_idx: usize, - out_start: usize, - out_end: usize, - in_start: usize, - in_end: usize, - at_start: usize, - at_end: usize, - mod_start: usize, - mod_end: usize, + id: NodeId, + in_use: bool, + prog_idx: usize, + out_start: usize, + out_end: usize, + in_start: usize, + in_end: usize, + at_start: usize, + at_end: usize, + mod_start: usize, + mod_end: usize, /// A mapping array, to map from input index of the node /// to the modulator index. Because not every input has an /// associated modulator. @@ -54,33 +47,37 @@ impl NodeInstance { pub fn new(id: NodeId) -> Self { Self { id, - in_use: false, - prog_idx: 0, - out_start: 0, - out_end: 0, - in_start: 0, - in_end: 0, - at_start: 0, - at_end: 0, - mod_start: 0, - mod_end: 0, - in2mod_map: [None; MAX_INPUTS], + in_use: false, + prog_idx: 0, + out_start: 0, + out_end: 0, + in_start: 0, + in_end: 0, + at_start: 0, + at_end: 0, + mod_start: 0, + mod_end: 0, + in2mod_map: [None; MAX_INPUTS], } } - pub fn mark_used(&mut self) { self.in_use = true; } - pub fn is_used(&self) -> bool { self.in_use } + pub fn mark_used(&mut self) { + self.in_use = true; + } + pub fn is_used(&self) -> bool { + self.in_use + } pub fn as_op(&self) -> NodeOp { NodeOp { - idx: self.prog_idx as u8, - out_idxlen: (self.out_start, self.out_end), - in_idxlen: (self.in_start, self.in_end), - at_idxlen: (self.at_start, self.at_end), - mod_idxlen: (self.mod_start, self.mod_end), - out_connected: 0x0, - in_connected: 0x0, - inputs: vec![], + idx: self.prog_idx as u8, + out_idxlen: (self.out_start, self.out_end), + in_idxlen: (self.in_start, self.in_end), + at_idxlen: (self.at_start, self.at_end), + mod_idxlen: (self.mod_start, self.mod_end), + out_connected: 0x0, + in_connected: 0x0, + inputs: vec![], } } @@ -93,14 +90,20 @@ impl NodeInstance { pub fn in_local2global(&self, idx: u8) -> Option { let idx = self.in_start + idx as usize; - if idx < self.in_end { Some(idx) } - else { None } + if idx < self.in_end { + Some(idx) + } else { + None + } } pub fn out_local2global(&self, idx: u8) -> Option { let idx = self.out_start + idx as usize; - if idx < self.out_end { Some(idx) } - else { None } + if idx < self.out_end { + Some(idx) + } else { + None + } } pub fn set_index(&mut self, idx: usize) -> &mut Self { @@ -110,23 +113,23 @@ impl NodeInstance { pub fn set_output(&mut self, s: usize, e: usize) -> &mut Self { self.out_start = s; - self.out_end = e; + self.out_end = e; self } pub fn set_input(&mut self, s: usize, e: usize) -> &mut Self { self.in_start = s; - self.in_end = e; + self.in_end = e; self } pub fn set_mod(&mut self, s: usize, e: usize) -> &mut Self { self.mod_start = s; - self.mod_end = e; + self.mod_end = e; self } - /// Sets the modulator index mapping: `idx` is the + /// Sets the modulator index mapping: `idx` is the /// index of the parameter like in [NodeId::inp_param_by_idx], /// and `i` is the absolute index of the modulator that belongs /// to this parameter. @@ -137,24 +140,24 @@ impl NodeInstance { pub fn set_atom(&mut self, s: usize, e: usize) -> &mut Self { self.at_start = s; - self.at_end = e; + self.at_end = e; self } } #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] struct NodeInputParam { - param_id: ParamId, - input_idx: usize, - value: f32, - modamt: Option<(usize, f32)>, + param_id: ParamId, + input_idx: usize, + value: f32, + modamt: Option<(usize, f32)>, } #[derive(Debug, Clone)] struct NodeInputAtom { - param_id: ParamId, - at_idx: usize, - value: SAtom, + param_id: ParamId, + at_idx: usize, + value: SAtom, } /// This struct holds the frontend node configuration. @@ -188,15 +191,15 @@ pub struct NodeConfigurator { errors: Vec, /// Contains (automateable) parameters - params: std::collections::HashMap, + params: std::collections::HashMap, /// Stores the most recently set parameter values - param_values: std::collections::HashMap, + param_values: std::collections::HashMap, /// Stores the modulation amount of a parameter - param_modamt: std::collections::HashMap>, + param_modamt: std::collections::HashMap>, /// Contains non automateable atom data for the nodes - atoms: std::collections::HashMap, + atoms: std::collections::HashMap, /// Stores the most recently set atoms - atom_values: std::collections::HashMap, + atom_values: std::collections::HashMap, /// Holds a copy of the most recently updated output port feedback /// values. Update this by calling [NodeConfigurator::update_output_feedback]. @@ -204,62 +207,63 @@ pub struct NodeConfigurator { /// Holds the channel to the backend that sends output port feedback. /// This is queried by [NodeConfigurator::update_output_feedback]. - output_fb_cons: Option>>, + output_fb_cons: Option>>, } pub(crate) struct SharedNodeConf { /// Holds the LED values of the nodes - pub(crate) node_ctx_values: Vec>, + pub(crate) node_ctx_values: Vec>, /// For updating the NodeExecutor with graph updates. - pub(crate) graph_update_prod: Producer, + pub(crate) graph_update_prod: Producer, /// For quick updates like UI paramter changes. - pub(crate) quick_update_prod: Producer, + pub(crate) quick_update_prod: Producer, /// For receiving monitor data from the backend thread. - pub(crate) monitor: Monitor, + pub(crate) monitor: Monitor, /// Handles deallocation of dead nodes from the backend. #[allow(dead_code)] - pub(crate) drop_thread: DropThread, + pub(crate) drop_thread: DropThread, } use super::node_exec::SharedNodeExec; impl SharedNodeConf { pub(crate) fn new() -> (Self, SharedNodeExec) { - let rb_graph = RingBuffer::new(MAX_ALLOCATED_NODES * 2); - let rb_quick = RingBuffer::new(MAX_ALLOCATED_NODES * 8); - let rb_drop = RingBuffer::new(MAX_ALLOCATED_NODES * 2); + let rb_graph = RingBuffer::new(MAX_ALLOCATED_NODES * 2); + let rb_quick = RingBuffer::new(MAX_ALLOCATED_NODES * 8); + let rb_drop = RingBuffer::new(MAX_ALLOCATED_NODES * 2); let (rb_graph_prod, rb_graph_con) = rb_graph.split(); let (rb_quick_prod, rb_quick_con) = rb_quick.split(); - let (rb_drop_prod, rb_drop_con) = rb_drop.split(); + let (rb_drop_prod, rb_drop_con) = rb_drop.split(); let drop_thread = DropThread::new(rb_drop_con); let (monitor_backend, monitor) = new_monitor_processor(); let mut node_ctx_values = Vec::new(); - node_ctx_values.resize_with( - 2 * MAX_ALLOCATED_NODES, - || Arc::new(AtomicFloat::new(0.0))); + node_ctx_values.resize_with(2 * MAX_ALLOCATED_NODES, || Arc::new(AtomicFloat::new(0.0))); let mut exec_node_ctx_vals = Vec::new(); for ctx_val in node_ctx_values.iter() { exec_node_ctx_vals.push(ctx_val.clone()); } - (Self { - node_ctx_values, - graph_update_prod: rb_graph_prod, - quick_update_prod: rb_quick_prod, - monitor, - drop_thread, - }, SharedNodeExec { - node_ctx_values: exec_node_ctx_vals, - graph_update_con: rb_graph_con, - quick_update_con: rb_quick_con, - graph_drop_prod: rb_drop_prod, - monitor_backend, - }) + ( + Self { + node_ctx_values, + graph_update_prod: rb_graph_prod, + quick_update_prod: rb_quick_prod, + monitor, + drop_thread, + }, + SharedNodeExec { + node_ctx_values: exec_node_ctx_vals, + graph_update_con: rb_graph_con, + quick_update_con: rb_quick_con, + graph_drop_prod: rb_drop_prod, + monitor_backend, + }, + ) } } @@ -270,45 +274,48 @@ impl NodeConfigurator { let (shared, shared_exec) = SharedNodeConf::new(); - (NodeConfigurator { - nodes, - shared, - errors: vec![], - sample_lib: SampleLibrary::new(), - feedback_filter: FeedbackFilter::new(), - output_fb_values: vec![], - output_fb_cons: None, - params: std::collections::HashMap::new(), - param_values: std::collections::HashMap::new(), - param_modamt: std::collections::HashMap::new(), - atoms: std::collections::HashMap::new(), - atom_values: std::collections::HashMap::new(), - node2idx: HashMap::new(), - trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS], - }, shared_exec) + ( + NodeConfigurator { + nodes, + shared, + errors: vec![], + sample_lib: SampleLibrary::new(), + feedback_filter: FeedbackFilter::new(), + output_fb_values: vec![], + output_fb_cons: None, + params: std::collections::HashMap::new(), + param_values: std::collections::HashMap::new(), + param_modamt: std::collections::HashMap::new(), + atoms: std::collections::HashMap::new(), + atom_values: std::collections::HashMap::new(), + node2idx: HashMap::new(), + trackers: vec![Tracker::new(); MAX_AVAIL_TRACKERS], + }, + shared_exec, + ) } -// FIXME: We can't drop nodes at runtime! -// We need to reinitialize the whole engine for this. -// There are too many things relying on the node index (UI). -// -// pub fn drop_node(&mut self, idx: usize) { -// if idx >= self.nodes.len() { -// return; -// } -// -// match self.nodes[idx] { -// NodeInfo::Nop => { return; }, -// _ => {}, -// } -// -// self.nodes[idx] = NodeInfo::Nop; -// let _ = -// self.graph_update_prod.push( -// GraphMessage::NewNode { -// index: idx as u8, -// node: Node::Nop, -// }); -// } + // FIXME: We can't drop nodes at runtime! + // We need to reinitialize the whole engine for this. + // There are too many things relying on the node index (UI). + // + // pub fn drop_node(&mut self, idx: usize) { + // if idx >= self.nodes.len() { + // return; + // } + // + // match self.nodes[idx] { + // NodeInfo::Nop => { return; }, + // _ => {}, + // } + // + // self.nodes[idx] = NodeInfo::Nop; + // let _ = + // self.graph_update_prod.push( + // GraphMessage::NewNode { + // index: idx as u8, + // node: Node::Nop, + // }); + // } pub fn for_each(&self, mut f: F) { for (i, n) in self.nodes.iter().enumerate() { @@ -359,34 +366,30 @@ impl NodeConfigurator { if let Some(nparam) = self.params.get_mut(¶m) { if let Some(modamt) = &mut nparam.modamt { - mod_idx = Some(modamt.0); + mod_idx = Some(modamt.0); modamt.1 = v.unwrap_or(0.0); } } - // Check if the modulation amount was already set, if not, the caller // needs to reconstruct the graph and upload an updated NodeProg. - if let Some(_old_modamt) = - self.param_modamt.get(¶m).copied().flatten() - { + if let Some(_old_modamt) = self.param_modamt.get(¶m).copied().flatten() { if v.is_none() { self.param_modamt.insert(param, v); true - } else { let modamt = v.unwrap(); self.param_modamt.insert(param, v); if let Some(mod_idx) = mod_idx { - let _ = - self.shared.quick_update_prod.push( - QuickMessage::ModamtUpdate { mod_idx, modamt }); + let _ = self + .shared + .quick_update_prod + .push(QuickMessage::ModamtUpdate { mod_idx, modamt }); } false } - } else { self.param_modamt.insert(param, v); true @@ -409,26 +412,25 @@ impl NodeConfigurator { /// then the value will be remembered until [NodeConfigurator::rebuild_node_ports] is called. pub fn set_param(&mut self, param: ParamId, at: SAtom) { if param.is_atom() { - let at = - if let SAtom::AudioSample((path, None)) = at.clone() { - if !path.is_empty() { - match self.sample_lib.load(&path) { - Ok(sample) => sample.clone(), - Err(e) => { - self.errors.push( - format!( - "Sample Loading Error\n\ + let at = if let SAtom::AudioSample((path, None)) = at.clone() { + if !path.is_empty() { + match self.sample_lib.load(&path) { + Ok(sample) => sample.clone(), + Err(e) => { + self.errors.push(format!( + "Sample Loading Error\n\ Couldn't load sample '{}':\n{:?}", - path, e)); - at - }, + path, e + )); + at } - } else { - at } } else { at - }; + } + } else { + at + }; self.atom_values.insert(param, at.clone()); @@ -436,9 +438,10 @@ impl NodeConfigurator { nparam.value = at.clone(); let at_idx = nparam.at_idx; - let _ = - self.shared.quick_update_prod.push( - QuickMessage::AtomUpdate { at_idx, value: at }); + let _ = self + .shared + .quick_update_prod + .push(QuickMessage::AtomUpdate { at_idx, value: at }); } } else { self.param_values.insert(param, at.f()); @@ -448,9 +451,10 @@ impl NodeConfigurator { nparam.value = value; let input_idx = nparam.input_idx; - let _ = - self.shared.quick_update_prod.push( - QuickMessage::ParamUpdate { input_idx, value }); + let _ = self + .shared + .quick_update_prod + .push(QuickMessage::ParamUpdate { input_idx, value }); } } } @@ -458,26 +462,21 @@ impl NodeConfigurator { /// Dumps all set parameters (inputs and atoms). /// Most useful for serialization and saving patches. #[allow(clippy::type_complexity)] - pub fn dump_param_values(&self) - -> (Vec<(ParamId, f32, Option)>, Vec<(ParamId, SAtom)>) - { - let params : Vec<(ParamId, f32, Option)> = - self.param_values - .iter() - .map(|(param_id, value)| - (*param_id, - param_id.denorm(*value), - self.param_modamt - .get(param_id) - .copied() - .flatten())) - .collect(); + pub fn dump_param_values(&self) -> (Vec<(ParamId, f32, Option)>, Vec<(ParamId, SAtom)>) { + let params: Vec<(ParamId, f32, Option)> = self + .param_values + .iter() + .map(|(param_id, value)| { + ( + *param_id, + param_id.denorm(*value), + self.param_modamt.get(param_id).copied().flatten(), + ) + }) + .collect(); - let atoms : Vec<(ParamId, SAtom)> = - self.atom_values - .iter() - .map(|(param_id, value)| (*param_id, value.clone())) - .collect(); + let atoms: Vec<(ParamId, SAtom)> = + self.atom_values.iter().map(|(param_id, value)| (*param_id, value.clone())).collect(); (params, atoms) } @@ -488,12 +487,10 @@ impl NodeConfigurator { &mut self, params: &[(ParamId, f32, Option)], atoms: &[(ParamId, SAtom)], - normalize_params: bool) - { + normalize_params: bool, + ) { for (param_id, val, modamt) in params.iter() { - let val = - if normalize_params { param_id.norm(*val) } - else { *val }; + let val = if normalize_params { param_id.norm(*val) } else { *val }; self.set_param(*param_id, val.into()); self.set_param_modamt(*param_id, *modamt); } @@ -507,26 +504,16 @@ impl NodeConfigurator { /// it's current value. pub fn for_each_param)>(&self, mut f: F) { for (_, node_input) in self.atoms.iter() { - if let Some(unique_idx) = - self.unique_index_for(&node_input.param_id.node_id()) - { + if let Some(unique_idx) = self.unique_index_for(&node_input.param_id.node_id()) { f(unique_idx, node_input.param_id, &node_input.value, None); } } for (_, node_input) in self.params.iter() { - if let Some(unique_idx) = - self.unique_index_for(&node_input.param_id.node_id()) - { - let modamt = - self.param_modamt - .get(&node_input.param_id) - .copied() - .flatten(); + if let Some(unique_idx) = self.unique_index_for(&node_input.param_id.node_id()) { + let modamt = self.param_modamt.get(&node_input.param_id).copied().flatten(); - f(unique_idx, node_input.param_id, - &SAtom::param(node_input.value), - modamt); + f(unique_idx, node_input.param_id, &SAtom::param(node_input.value), modamt); } } } @@ -562,7 +549,7 @@ impl NodeConfigurator { /// This function internally calls [NodeConfigurator::update_output_feedback] /// for you, so you don't need to call it yourself. /// - /// See also [NodeConfigurator::filtered_led_for] + /// See also [NodeConfigurator::filtered_led_for] /// and [NodeConfigurator::filtered_out_fb_for]. pub fn update_filters(&mut self) { self.update_output_feedback(); @@ -624,9 +611,7 @@ impl NodeConfigurator { /// /// For an example on how to use see [NodeConfigurator::filtered_led_for] /// which has the same semantics as this function. - pub fn filtered_out_fb_for(&mut self, node_id: &NodeId, out: u8) - -> (f32, f32) - { + pub fn filtered_out_fb_for(&mut self, node_id: &NodeId, out: u8) -> (f32, f32) { let out_value = self.out_fb_for(node_id, out).unwrap_or(0.0); self.feedback_filter.get_out(node_id, out, out_value) } @@ -635,22 +620,14 @@ impl NodeConfigurator { /// /// The monitor data can be retrieved using /// [NodeConfigurator::get_minmax_monitor_samples]. - pub fn monitor(&mut self, - node_id: &NodeId, - inputs: &[Option], - outputs: &[Option]) - { + pub fn monitor(&mut self, node_id: &NodeId, inputs: &[Option], outputs: &[Option]) { let mut bufs = [UNUSED_MONITOR_IDX; MON_SIG_CNT]; - if let Some((_node_info, Some(node_instance))) = - self.node_by_id(node_id) - { + if let Some((_node_info, Some(node_instance))) = self.node_by_id(node_id) { let mut i = 0; for inp_idx in inputs.iter().take(MON_SIG_CNT / 2) { if let Some(inp_idx) = inp_idx { - if let Some(global_idx) - = node_instance.in_local2global(*inp_idx) - { + if let Some(global_idx) = node_instance.in_local2global(*inp_idx) { bufs[i] = global_idx; } } @@ -660,9 +637,7 @@ impl NodeConfigurator { for out_idx in outputs.iter().take(MON_SIG_CNT / 2) { if let Some(out_idx) = out_idx { - if let Some(global_idx) - = node_instance.out_local2global(*out_idx) - { + if let Some(global_idx) = node_instance.out_local2global(*out_idx) { bufs[i] = global_idx; } } @@ -670,15 +645,11 @@ impl NodeConfigurator { i += 1; } - let _ = - self.shared.quick_update_prod.push( - QuickMessage::SetMonitor { bufs }); + let _ = self.shared.quick_update_prod.push(QuickMessage::SetMonitor { bufs }); } } - pub fn get_pattern_data(&self, tracker_id: usize) - -> Option>> - { + pub fn get_pattern_data(&self, tracker_id: usize) -> Option>> { if tracker_id >= self.trackers.len() { return None; } @@ -697,20 +668,18 @@ impl NodeConfigurator { pub fn delete_nodes(&mut self) { self.node2idx.clear(); self.nodes.fill_with(|| (NodeInfo::from_node_id(NodeId::Nop), None)); - self.params .clear(); + self.params.clear(); self.param_values.clear(); self.param_modamt.clear(); - self.atoms .clear(); - self.atom_values .clear(); + self.atoms.clear(); + self.atom_values.clear(); - let _ = - self.shared.graph_update_prod.push( - GraphMessage::Clear { prog: NodeProg::empty() }); + let _ = self.shared.graph_update_prod.push(GraphMessage::Clear { prog: NodeProg::empty() }); } pub fn create_node(&mut self, ni: NodeId) -> Option<(&NodeInfo, u8)> { if let Some((mut node, info)) = node_factory(ni) { - let mut index : Option = None; + let mut index: Option = None; if let Node::TSeq { node } = &mut node { let tracker_idx = ni.instance(); @@ -723,7 +692,6 @@ impl NodeConfigurator { if let NodeId::Nop = self.nodes[i].0.to_id() { index = Some(i); break; - } else if ni == self.nodes[i].0.to_id() { return Some((&self.nodes[i].0, i as u8)); } @@ -734,30 +702,25 @@ impl NodeConfigurator { self.nodes[index] = (info, None); - let _ = - self.shared.graph_update_prod.push( - GraphMessage::NewNode { - index: index as u8, - node, - }); + let _ = self + .shared + .graph_update_prod + .push(GraphMessage::NewNode { index: index as u8, node }); Some((&self.nodes[index].0, index as u8)) - } else { let index = self.nodes.len(); self.node2idx.insert(ni, index); - self.nodes.resize_with( - (self.nodes.len() + 1) * 2, - || (NodeInfo::from_node_id(NodeId::Nop), None)); + self.nodes.resize_with((self.nodes.len() + 1) * 2, || { + (NodeInfo::from_node_id(NodeId::Nop), None) + }); self.nodes[index] = (info, None); - let _ = - self.shared.graph_update_prod.push( - GraphMessage::NewNode { - index: index as u8, - node, - }); + let _ = self + .shared + .graph_update_prod + .push(GraphMessage::NewNode { index: index as u8, node }); Some((&self.nodes[index].0, index as u8)) } @@ -803,13 +766,11 @@ impl NodeConfigurator { self.atoms.clear(); let mut out_len = 0; - let mut in_len = 0; - let mut at_len = 0; + let mut in_len = 0; + let mut at_len = 0; let mut mod_len = 0; - for (i, (node_info, node_instance)) - in self.nodes.iter_mut().enumerate() - { + for (i, (node_info, node_instance)) in self.nodes.iter_mut().enumerate() { let id = node_info.to_id(); // - calculate size of output vector. @@ -833,9 +794,9 @@ impl NodeConfigurator { let mut ni = NodeInstance::new(id); ni.set_index(i) - .set_output(out_idx, out_len) - .set_input(in_idx, in_len) - .set_atom(at_idx, at_len); + .set_output(out_idx, out_len) + .set_input(in_idx, in_len) + .set_atom(at_idx, at_len); // - save offset and length of each node's // allocation in the output vector. @@ -850,36 +811,29 @@ impl NodeConfigurator { let input_idx = param_idx - in_idx; if let Some(param_id) = id.inp_param_by_idx(input_idx) { - let value = - if let Some(value) = self.param_values.get(¶m_id) { - *value - } else { - param_id.norm_def() - }; + let value = if let Some(value) = self.param_values.get(¶m_id) { + *value + } else { + param_id.norm_def() + }; // If we have a modulation, store the absolute // index of it in the [NodeProg::modops] vector later: let ma = self.param_modamt.get(¶m_id).copied().flatten(); - let modamt = - if ma.is_some() { - let mod_idx = mod_len; - node_instance - .as_mut() - .unwrap() - .set_mod_idx(input_idx, mod_idx); - mod_len += 1; - Some((mod_idx, ma.unwrap())) - } else { - None - }; + let modamt = if ma.is_some() { + let mod_idx = mod_len; + node_instance.as_mut().unwrap().set_mod_idx(input_idx, mod_idx); + mod_len += 1; + Some((mod_idx, ma.unwrap())) + } else { + None + }; self.param_values.insert(param_id, value); - self.params.insert(param_id, NodeInputParam { + self.params.insert( param_id, - value, - input_idx: param_idx, - modamt, - }); + NodeInputParam { param_id, value, input_idx: param_idx, modamt }, + ); } } @@ -893,21 +847,15 @@ impl NodeConfigurator { // XXX: See also the documentation of atom_param_by_idx about the // little param_id for an Atom weirdness here. if let Some(param_id) = id.atom_param_by_idx(atom_idx - at_idx) { - let value = - if let Some(atom) = - self.atom_values.get(¶m_id) - { - atom.clone() - } else { - param_id.as_atom_def() - }; + let value = if let Some(atom) = self.atom_values.get(¶m_id) { + atom.clone() + } else { + param_id.as_atom_def() + }; self.atom_values.insert(param_id, value.clone()); - self.atoms.insert(param_id, NodeInputAtom { - param_id, - value, - at_idx: atom_idx, - }); + self.atoms + .insert(param_id, NodeInputAtom { param_id, value, at_idx: atom_idx }); } } } @@ -921,9 +869,7 @@ impl NodeConfigurator { /// [NodeConfigurator::rebuild_node_ports] was not called before. So make sure this is the /// case or don't expect the node and input to be executed. pub fn add_prog_node(&mut self, prog: &mut NodeProg, node_id: &NodeId) { - if let Some((_node_info, Some(node_instance))) - = self.node_by_id_mut(node_id) - { + if let Some((_node_info, Some(node_instance))) = self.node_by_id_mut(node_id) { node_instance.mark_used(); let op = node_instance.as_op(); prog.append_op(op); @@ -940,35 +886,26 @@ impl NodeConfigurator { /// [NodeConfigurator::rebuild_node_ports] was not called before. So make sure this is the /// case or don't expect the node and input to be executed. pub fn set_prog_node_exec_connection( - &mut self, prog: &mut NodeProg, + &mut self, + prog: &mut NodeProg, node_input: (NodeId, u8), - adjacent_output: (NodeId, u8)) - { + adjacent_output: (NodeId, u8), + ) { let output_index = - if let Some((_, Some(node_instance))) - = self.node_by_id(&adjacent_output.0) - { + if let Some((_, Some(node_instance))) = self.node_by_id(&adjacent_output.0) { node_instance.out_local2global(adjacent_output.1) } else { return; }; - if let Some((_node_info, Some(node_instance))) - = self.node_by_id_mut(&node_input.0) - { + if let Some((_node_info, Some(node_instance))) = self.node_by_id_mut(&node_input.0) { node_instance.mark_used(); let op = node_instance.as_op(); let input_index = node_instance.in_local2global(node_input.1); - let mod_index = node_instance.mod_in_local2global(node_input.1); - if let (Some(input_index), Some(output_index)) = - (input_index, output_index) - { - prog.append_edge( - op, - input_index, - output_index, - mod_index); + let mod_index = node_instance.mod_in_local2global(node_input.1); + if let (Some(input_index), Some(output_index)) = (input_index, output_index) { + prog.append_edge(op, input_index, output_index, mod_index); } } } @@ -1028,9 +965,7 @@ impl NodeConfigurator { self.output_fb_cons = prog.take_feedback_consumer(); - let _ = - self.shared.graph_update_prod.push( - GraphMessage::NewProg { prog, copy_old_out }); + let _ = self.shared.graph_update_prod.push(GraphMessage::NewProg { prog, copy_old_out }); } /// Retrieves the feedback value for a specific output port of the @@ -1042,8 +977,7 @@ impl NodeConfigurator { /// filtered variant suitable for UI usage. pub fn out_fb_for(&self, node_id: &NodeId, out: u8) -> Option { if let Some((_, Some(node_instance))) = self.node_by_id(node_id) { - self.output_fb_values.get( - node_instance.out_local2global(out)?).copied() + self.output_fb_values.get(node_instance.out_local2global(out)?).copied() } else { None } diff --git a/src/nodes/node_exec.rs b/src/nodes/node_exec.rs index bffc2aa..3f58a10 100644 --- a/src/nodes/node_exec.rs +++ b/src/nodes/node_exec.rs @@ -3,25 +3,24 @@ // See README.md and COPYING for details. use super::{ - GraphMessage, QuickMessage, DropMsg, NodeProg, - UNUSED_MONITOR_IDX, MAX_ALLOCATED_NODES, MAX_SMOOTHERS, - MAX_FB_DELAY_SIZE, FB_DELAY_TIME_US + DropMsg, GraphMessage, NodeProg, QuickMessage, FB_DELAY_TIME_US, MAX_ALLOCATED_NODES, + MAX_FB_DELAY_SIZE, MAX_SMOOTHERS, UNUSED_MONITOR_IDX, }; -use crate::dsp::{NodeId, Node, NodeContext, MAX_BLOCK_SIZE}; -use crate::util::{Smoother, AtomicFloat}; +use crate::dsp::{Node, NodeContext, NodeId, MAX_BLOCK_SIZE}; use crate::monitor::{MonitorBackend, MON_SIG_CNT}; +use crate::util::{AtomicFloat, Smoother}; -use std::io::Write; use crate::log; +use std::io::Write; -use ringbuf::{Producer, Consumer}; +use ringbuf::{Consumer, Producer}; use std::sync::Arc; use core::arch::x86_64::{ _MM_FLUSH_ZERO_ON, -// _MM_FLUSH_ZERO_OFF, + // _MM_FLUSH_ZERO_OFF, _MM_SET_FLUSH_ZERO_MODE, -// _MM_GET_FLUSH_ZERO_MODE + // _MM_GET_FLUSH_ZERO_MODE }; /// Holds the complete allocation of nodes and @@ -77,13 +76,13 @@ pub(crate) struct SharedNodeExec { /// phase might be used to display an envelope's play position. pub(crate) node_ctx_values: Vec>, /// For receiving Node and NodeProg updates - pub(crate) graph_update_con: Consumer, + pub(crate) graph_update_con: Consumer, /// For quick updates like UI paramter changes. - pub(crate) quick_update_con: Consumer, + pub(crate) quick_update_con: Consumer, /// For receiving deleted/overwritten nodes from the backend thread. - pub(crate) graph_drop_prod: Producer, + pub(crate) graph_drop_prod: Producer, /// For sending feedback to the frontend thread. - pub(crate) monitor_backend: MonitorBackend, + pub(crate) monitor_backend: MonitorBackend, } /// Contains audio driver context informations. Such as the number @@ -104,20 +103,20 @@ pub trait NodeAudioContext { /// See also `sample_count` field. pub struct FeedbackBuffer { /// The feedback buffer that holds the samples of the previous period. - buffer: [f32; MAX_FB_DELAY_SIZE], + buffer: [f32; MAX_FB_DELAY_SIZE], /// The write pointer. - write_ptr: usize, + write_ptr: usize, /// Read pointer, is always behind write_ptr by an initial amount - read_ptr: usize, + read_ptr: usize, } impl FeedbackBuffer { pub fn new() -> Self { let delay_sample_count = (44100.0 as usize * FB_DELAY_TIME_US) / 1000000; Self { - buffer: [0.0; MAX_FB_DELAY_SIZE], - write_ptr: delay_sample_count % MAX_FB_DELAY_SIZE, - read_ptr: 0, + buffer: [0.0; MAX_FB_DELAY_SIZE], + write_ptr: delay_sample_count % MAX_FB_DELAY_SIZE, + read_ptr: 0, } } @@ -126,7 +125,7 @@ impl FeedbackBuffer { } pub fn set_sample_rate(&mut self, sr: f32) { - self.buffer = [0.0; MAX_FB_DELAY_SIZE]; + self.buffer = [0.0; MAX_FB_DELAY_SIZE]; // The delay sample count maximum is defined by MAX_FB_DELAY_SRATE, // after that the feedback delays become shorter than they should be // and things won't sound the same at sample rate @@ -140,8 +139,8 @@ impl FeedbackBuffer { // be used before FbWr or after FbRd. let delay_sample_count = (sr as usize * FB_DELAY_TIME_US) / 1000000; - self.write_ptr = delay_sample_count % MAX_FB_DELAY_SIZE; - self.read_ptr = 0; + self.write_ptr = delay_sample_count % MAX_FB_DELAY_SIZE; + self.read_ptr = 0; } #[inline] @@ -162,22 +161,22 @@ impl FeedbackBuffer { } impl Default for FeedbackBuffer { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } /// Contains global state that all nodes can access. /// This is used for instance to implement the feedbackd delay nodes. pub struct NodeExecContext { - pub feedback_delay_buffers: Vec, + pub feedback_delay_buffers: Vec, } impl NodeExecContext { fn new() -> Self { let mut fbdb = vec![]; fbdb.resize_with(MAX_ALLOCATED_NODES, FeedbackBuffer::new); - Self { - feedback_delay_buffers: fbdb, - } + Self { feedback_delay_buffers: fbdb } } fn set_sample_rate(&mut self, srate: f32) { @@ -207,11 +206,11 @@ impl NodeExecutor { nodes, smoothers, target_refresh, - sample_rate: 44100.0, - prog: NodeProg::empty(), + sample_rate: 44100.0, + prog: NodeProg::empty(), monitor_signal_cur_inp_indices: [UNUSED_MONITOR_IDX; MON_SIG_CNT], - exec_ctx: NodeExecContext::new(), - dsp_log_init: false, + exec_ctx: NodeExecContext::new(), + dsp_log_init: false, shared, } } @@ -226,51 +225,42 @@ impl NodeExecutor { match upd { GraphMessage::NewNode { index, mut node } => { node.set_sample_rate(self.sample_rate); - let prev_node = - std::mem::replace( - &mut self.nodes[index as usize], - node); + let prev_node = std::mem::replace(&mut self.nodes[index as usize], node); log(|w| { - let _ = write!(w, "[dbg] Create node index={}", index); }); + let _ = write!(w, "[dbg] Create node index={}", index); + }); - let _ = - self.shared.graph_drop_prod.push( - DropMsg::Node { node: prev_node }); - }, + let _ = self.shared.graph_drop_prod.push(DropMsg::Node { node: prev_node }); + } GraphMessage::Clear { prog } => { for n in self.nodes.iter_mut() { if n.to_id(0) != NodeId::Nop { let prev_node = std::mem::replace(n, Node::Nop); let _ = - self.shared.graph_drop_prod.push( - DropMsg::Node { node: prev_node }); + self.shared.graph_drop_prod.push(DropMsg::Node { node: prev_node }); } } self.exec_ctx.clear(); - self.monitor_signal_cur_inp_indices = - [UNUSED_MONITOR_IDX; MON_SIG_CNT]; + self.monitor_signal_cur_inp_indices = [UNUSED_MONITOR_IDX; MON_SIG_CNT]; log(|w| { - let _ = write!(w, - "[dbg] Cleared graph ({} nodes)", - self.prog.prog.len()); }); + let _ = write!(w, "[dbg] Cleared graph ({} nodes)", self.prog.prog.len()); + }); let prev_prog = std::mem::replace(&mut self.prog, prog); - let _ = - self.shared.graph_drop_prod.push( - DropMsg::Prog { prog: prev_prog }); - - }, + let _ = self.shared.graph_drop_prod.push(DropMsg::Prog { prog: prev_prog }); + } GraphMessage::NewProg { prog, copy_old_out } => { let mut prev_prog = std::mem::replace(&mut self.prog, prog); - unsafe { _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); } + unsafe { + _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); + } - self.monitor_signal_cur_inp_indices = - [UNUSED_MONITOR_IDX; MON_SIG_CNT]; + self.monitor_signal_cur_inp_indices = [UNUSED_MONITOR_IDX; MON_SIG_CNT]; // XXX: Copying from the old vector works, because we only // append nodes to the _end_ of the node instance vector. @@ -278,7 +268,7 @@ impl NodeExecutor { // // XXX: Also, we need to initialize the input parameter // vector, because we don't know if they are updated from - // the new program outputs anymore. So we need to + // the new program outputs anymore. So we need to // copy the old paramters to the inputs. // // => This does not apply to atom data, because that @@ -322,15 +312,16 @@ impl NodeExecutor { self.prog.assign_outputs(); - let _ = - self.shared.graph_drop_prod.push( - DropMsg::Prog { prog: prev_prog }); + let _ = self.shared.graph_drop_prod.push(DropMsg::Prog { prog: prev_prog }); - log(|w| { let _ = - write!(w, + log(|w| { + let _ = write!( + w, "[dbg] Created new graph (node count={})", - self.prog.prog.len()); }); - }, + self.prog.prog.len() + ); + }); + } } } } @@ -348,10 +339,14 @@ impl NodeExecutor { } #[inline] - pub fn get_nodes(&self) -> &Vec { &self.nodes } + pub fn get_nodes(&self) -> &Vec { + &self.nodes + } #[inline] - pub fn get_prog(&self) -> &NodeProg { &self.prog } + pub fn get_prog(&self) -> &NodeProg { + &self.prog + } #[inline] fn set_modamt(&mut self, mod_idx: usize, modamt: f32) { @@ -369,11 +364,7 @@ impl NodeExecutor { } // First check if we already have a running smoother for this param: - for (sm_inp_idx, smoother) in - self.smoothers - .iter_mut() - .filter(|s| !s.1.is_done()) - { + for (sm_inp_idx, smoother) in self.smoothers.iter_mut().filter(|s| !s.1.is_done()) { if *sm_inp_idx == input_idx { smoother.set(prog.params[input_idx], value); //d// println!("RE-SET SMOOTHER {} {:6.3} (old = {:6.3})", @@ -393,20 +384,14 @@ impl NodeExecutor { #[inline] fn process_smoothers(&mut self, nframes: usize) { - let prog = &mut self.prog; + let prog = &mut self.prog; while let Some((idx, v)) = self.target_refresh.pop() { prog.inp[idx].fill(v); } - for (idx, smoother) in - self.smoothers - .iter_mut() - .filter(|s| - !s.1.is_done()) - { - - let inp = &mut prog.inp[*idx]; + for (idx, smoother) in self.smoothers.iter_mut().filter(|s| !s.1.is_done()) { + let inp = &mut prog.inp[*idx]; let mut last_v = 0.0; for frame in 0..nframes { @@ -419,7 +404,6 @@ impl NodeExecutor { prog.params[*idx] = last_v; self.target_refresh.push((*idx, last_v)); } - } #[inline] @@ -428,24 +412,19 @@ impl NodeExecutor { match upd { QuickMessage::AtomUpdate { at_idx, value } => { let prog = &mut self.prog; - let garbage = - std::mem::replace( - &mut prog.atoms[at_idx], - value); + let garbage = std::mem::replace(&mut prog.atoms[at_idx], value); - let _ = - self.shared.graph_drop_prod.push( - DropMsg::Atom { atom: garbage }); - }, + let _ = self.shared.graph_drop_prod.push(DropMsg::Atom { atom: garbage }); + } QuickMessage::ParamUpdate { input_idx, value } => { self.set_param(input_idx, value); - }, + } QuickMessage::ModamtUpdate { mod_idx, modamt } => { self.set_modamt(mod_idx, modamt); - }, + } QuickMessage::SetMonitor { bufs } => { self.monitor_signal_cur_inp_indices = bufs; - }, + } } } @@ -456,19 +435,18 @@ impl NodeExecutor { pub fn process(&mut self, ctx: &mut T) { // let tb = std::time::Instant::now(); - if !self.dsp_log_init - && crate::log::init_thread_logger("dsp") - { + if !self.dsp_log_init && crate::log::init_thread_logger("dsp") { self.dsp_log_init = true; crate::log(|w| { - let _ = write!(w, "DSP thread logger initialized"); }); + let _ = write!(w, "DSP thread logger initialized"); + }); } self.process_param_updates(ctx.nframes()); - let nodes = &mut self.nodes; + let nodes = &mut self.nodes; let ctx_vals = &mut self.shared.node_ctx_values; - let prog = &mut self.prog; + let prog = &mut self.prog; let exec_ctx = &mut self.exec_ctx; let prog_out_fb = prog.out_feedback.input_buffer(); @@ -476,35 +454,32 @@ impl NodeExecutor { let nframes = ctx.nframes(); for op in prog.prog.iter() { - let out = op.out_idxlen; - let inp = op.in_idxlen; - let at = op.at_idxlen; - let md = op.mod_idxlen; + let out = op.out_idxlen; + let inp = op.in_idxlen; + let at = op.at_idxlen; + let md = op.mod_idxlen; let ctx_idx = op.idx as usize * 2; for modop in prog.modops[md.0..md.1].iter_mut() { modop.process(nframes); } - nodes[op.idx as usize] - .process( - ctx, - exec_ctx, - &NodeContext { - out_connected: op.out_connected, - in_connected: op.in_connected, - params: &prog.inp[inp.0..inp.1], - }, - &prog.atoms[at.0..at.1], - &prog.cur_inp[inp.0..inp.1], - &mut prog.out[out.0..out.1], - &ctx_vals[ctx_idx..ctx_idx + 2]); + nodes[op.idx as usize].process( + ctx, + exec_ctx, + &NodeContext { + out_connected: op.out_connected, + in_connected: op.in_connected, + params: &prog.inp[inp.0..inp.1], + }, + &prog.atoms[at.0..at.1], + &prog.cur_inp[inp.0..inp.1], + &mut prog.out[out.0..out.1], + &ctx_vals[ctx_idx..ctx_idx + 2], + ); let last_frame_idx = nframes - 1; - for (pb, out_buf_idx) in - prog.out[out.0..out.1].iter() - .zip(out.0..out.1) - { + for (pb, out_buf_idx) in prog.out[out.0..out.1].iter().zip(out.0..out.1) { prog_out_fb[out_buf_idx] = pb.read(last_frame_idx); } } @@ -551,13 +526,13 @@ impl NodeExecutor { /// You can use it's source as reference for your own audio /// DSP thread processing function. pub fn test_run(&mut self, seconds: f32, realtime: bool) -> (Vec, Vec) { - const SAMPLE_RATE : f32 = 44100.0; + const SAMPLE_RATE: f32 = 44100.0; self.set_sample_rate(SAMPLE_RATE); self.process_graph_updates(); let mut nframes = (seconds * SAMPLE_RATE) as usize; - let input = vec![0.0; nframes]; + let input = vec![0.0; nframes]; let mut output_l = vec![0.0; nframes]; let mut output_r = vec![0.0; nframes]; @@ -567,29 +542,23 @@ impl NodeExecutor { } let mut offs = 0; while nframes > 0 { - let cur_nframes = - if nframes >= MAX_BLOCK_SIZE { - MAX_BLOCK_SIZE - } else { - nframes - }; + let cur_nframes = if nframes >= MAX_BLOCK_SIZE { MAX_BLOCK_SIZE } else { nframes }; nframes -= cur_nframes; let mut context = crate::Context { nframes: cur_nframes, - output: &mut [&mut output_l[offs..(offs + cur_nframes)], - &mut output_r[offs..(offs + cur_nframes)]], - input: &[&input[offs..(offs + cur_nframes)]], + output: &mut [ + &mut output_l[offs..(offs + cur_nframes)], + &mut output_r[offs..(offs + cur_nframes)], + ], + input: &[&input[offs..(offs + cur_nframes)]], }; self.process(&mut context); if realtime { - let micros = - ((MAX_BLOCK_SIZE as u64) * 1000000) - / (SAMPLE_RATE as u64); - std::thread::sleep( - std::time::Duration::from_micros(micros)); + let micros = ((MAX_BLOCK_SIZE as u64) * 1000000) / (SAMPLE_RATE as u64); + std::thread::sleep(std::time::Duration::from_micros(micros)); } offs += cur_nframes; @@ -597,5 +566,4 @@ impl NodeExecutor { (output_l, output_r) } - } diff --git a/src/nodes/node_graph_ordering.rs b/src/nodes/node_graph_ordering.rs index f4b63a8..443e6f1 100644 --- a/src/nodes/node_graph_ordering.rs +++ b/src/nodes/node_graph_ordering.rs @@ -7,31 +7,27 @@ use crate::nodes::MAX_ALLOCATED_NODES; use std::collections::HashMap; use std::collections::HashSet; -pub const MAX_NODE_EDGES : usize = 64; -pub const UNUSED_NODE_EDGE : usize = 999999; +pub const MAX_NODE_EDGES: usize = 64; +pub const UNUSED_NODE_EDGE: usize = 999999; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct Node { /// The [NodeId] of this node. - node_id: NodeId, + node_id: NodeId, /// The output edges of this node. - edges: [usize; MAX_NODE_EDGES], + edges: [usize; MAX_NODE_EDGES], /// The first unused index in the `edges` array. unused_idx: usize, } impl Node { pub fn new() -> Self { - Self { - node_id: NodeId::Nop, - edges: [UNUSED_NODE_EDGE; MAX_NODE_EDGES], - unused_idx: 0, - } + Self { node_id: NodeId::Nop, edges: [UNUSED_NODE_EDGE; MAX_NODE_EDGES], unused_idx: 0 } } pub fn clear(&mut self) { - self.node_id = NodeId::Nop; - self.edges = [UNUSED_NODE_EDGE; MAX_NODE_EDGES]; + self.node_id = NodeId::Nop; + self.edges = [UNUSED_NODE_EDGE; MAX_NODE_EDGES]; self.unused_idx = 0; } @@ -49,9 +45,9 @@ impl Node { #[derive(Debug, Clone)] pub struct NodeGraphOrdering { - node2idx: HashMap, + node2idx: HashMap, node_count: usize, - nodes: [Node; MAX_ALLOCATED_NODES], + nodes: [Node; MAX_ALLOCATED_NODES], in_degree: [usize; MAX_ALLOCATED_NODES], } @@ -59,10 +55,10 @@ pub struct NodeGraphOrdering { impl NodeGraphOrdering { pub fn new() -> Self { Self { - node2idx: HashMap::new(), + node2idx: HashMap::new(), node_count: 0, - nodes: [Node::new(); MAX_ALLOCATED_NODES], - in_degree: [0; MAX_ALLOCATED_NODES], + nodes: [Node::new(); MAX_ALLOCATED_NODES], + in_degree: [0; MAX_ALLOCATED_NODES], } } @@ -74,7 +70,6 @@ impl NodeGraphOrdering { pub fn add_node(&mut self, node_id: NodeId) -> usize { if let Some(idx) = self.node2idx.get(&node_id) { *idx - } else { let idx = self.node_count; self.node_count += 1; @@ -106,8 +101,7 @@ impl NodeGraphOrdering { } pub fn has_path(&self, from_node_id: NodeId, to_node_id: NodeId) -> Option { - let mut visited_set : HashSet = - HashSet::with_capacity(MAX_ALLOCATED_NODES); + let mut visited_set: HashSet = HashSet::with_capacity(MAX_ALLOCATED_NODES); let mut node_stack = Vec::with_capacity(MAX_ALLOCATED_NODES); node_stack.push(from_node_id); @@ -139,8 +133,7 @@ impl NodeGraphOrdering { /// and no proper order can be computed. `out` will be cleared /// in this case. pub fn calculate_order(&mut self, out: &mut Vec) -> bool { - let mut deq = - std::collections::VecDeque::with_capacity(MAX_ALLOCATED_NODES); + let mut deq = std::collections::VecDeque::with_capacity(MAX_ALLOCATED_NODES); for indeg in self.in_degree.iter_mut() { *indeg = 0; @@ -186,7 +179,9 @@ impl NodeGraphOrdering { } impl Default for NodeGraphOrdering { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[cfg(test)] @@ -242,14 +237,17 @@ mod tests { let mut out = vec![]; assert!(ng.calculate_order(&mut out)); - assert_eq!(out[..], [ - NodeId::Sin(2), - NodeId::Out(0), - NodeId::Amp(0), - NodeId::Amp(1), - NodeId::Sin(0), - NodeId::Sin(1) - ]); + assert_eq!( + out[..], + [ + NodeId::Sin(2), + NodeId::Out(0), + NodeId::Amp(0), + NodeId::Amp(1), + NodeId::Sin(0), + NodeId::Sin(1) + ] + ); } #[test] @@ -278,14 +276,17 @@ mod tests { let mut out = vec![]; assert!(ng.calculate_order(&mut out)); - assert_eq!(out[..], [ - NodeId::Sin(2), - NodeId::Amp(0), - NodeId::Amp(1), - NodeId::Sin(0), - NodeId::Sin(1), - NodeId::Out(0), - ]); + assert_eq!( + out[..], + [ + NodeId::Sin(2), + NodeId::Amp(0), + NodeId::Amp(1), + NodeId::Sin(0), + NodeId::Sin(1), + NodeId::Out(0), + ] + ); } #[test] @@ -310,14 +311,17 @@ mod tests { let mut out = vec![]; assert!(ng.calculate_order(&mut out)); - assert_eq!(out[..], [ - NodeId::Sin(2), - NodeId::Amp(1), - NodeId::Sin(1), - NodeId::Amp(0), - NodeId::Out(0), - NodeId::Sin(0), - ]); + assert_eq!( + out[..], + [ + NodeId::Sin(2), + NodeId::Amp(1), + NodeId::Sin(1), + NodeId::Amp(0), + NodeId::Out(0), + NodeId::Sin(0), + ] + ); } #[test] @@ -331,9 +335,7 @@ mod tests { ng.add_edge(NodeId::Sin(0), NodeId::Sin(1)); ng.add_edge(NodeId::Sin(0), NodeId::Sin(2)); - assert!( - ng.has_path(NodeId::Sin(2), NodeId::Sin(1)) - .is_none()); + assert!(ng.has_path(NodeId::Sin(2), NodeId::Sin(1)).is_none()); let mut out = vec![]; assert!(!ng.calculate_order(&mut out)); diff --git a/src/nodes/node_prog.rs b/src/nodes/node_prog.rs index a3a9f7a..30fe34c 100644 --- a/src/nodes/node_prog.rs +++ b/src/nodes/node_prog.rs @@ -7,10 +7,10 @@ use triple_buffer::{Input, Output, TripleBuffer}; #[derive(Debug, Clone)] pub struct ModOp { - amount: f32, - modbuf: ProcBuf, - outbuf: ProcBuf, - inbuf: ProcBuf, + amount: f32, + modbuf: ProcBuf, + outbuf: ProcBuf, + inbuf: ProcBuf, } impl Drop for ModOp { @@ -25,7 +25,7 @@ impl ModOp { amount: 0.0, modbuf: ProcBuf::new(), outbuf: ProcBuf::null(), - inbuf: ProcBuf::null(), + inbuf: ProcBuf::null(), } } @@ -34,20 +34,20 @@ impl ModOp { } pub fn lock(&mut self, inbuf: ProcBuf, outbuf: ProcBuf) -> ProcBuf { - self.inbuf = inbuf; + self.inbuf = inbuf; self.outbuf = outbuf; self.modbuf } pub fn unlock(&mut self) { self.outbuf = ProcBuf::null(); - self.inbuf = ProcBuf::null(); + self.inbuf = ProcBuf::null(); } #[inline] pub fn process(&mut self, nframes: usize) { let modbuf = &mut self.modbuf; - let inbuf = &mut self.inbuf; + let inbuf = &mut self.inbuf; let outbuf = &mut self.outbuf; if inbuf.is_null() { @@ -55,9 +55,7 @@ impl ModOp { } for frame in 0..nframes { - modbuf.write(frame, - inbuf.read(frame) - + (self.amount * outbuf.read(frame))); + modbuf.write(frame, inbuf.read(frame) + (self.amount * outbuf.read(frame))); } } } @@ -67,7 +65,7 @@ impl ModOp { #[derive(Debug, Clone)] pub struct NodeOp { /// Stores the index of the node - pub idx: u8, + pub idx: u8, /// Output index and length of the node: pub out_idxlen: (usize, usize), /// Input index and length of the node: @@ -90,8 +88,7 @@ pub struct NodeOp { impl NodeOp { pub fn in_idx_belongs_to_nodeop(&self, idx: usize) -> bool { - idx >= self.in_idxlen.0 - && idx < self.in_idxlen.1 + idx >= self.in_idxlen.0 && idx < self.in_idxlen.1 } pub fn set_in_idx_connected_flag(&mut self, global_idx: usize) { @@ -104,8 +101,7 @@ impl NodeOp { } pub fn out_idx_belongs_to_nodeop(&self, idx: usize) -> bool { - idx >= self.out_idxlen.0 - && idx < self.out_idxlen.1 + idx >= self.out_idxlen.0 && idx < self.out_idxlen.1 } pub fn set_out_idx_connected_flag(&mut self, global_idx: usize) { @@ -120,18 +116,21 @@ impl NodeOp { impl std::fmt::Display for NodeOp { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Op(i={} out=({}-{}|{:x}) in=({}-{}|{:x}) at=({}-{}) mod=({}-{})", - self.idx, - self.out_idxlen.0, - self.out_idxlen.1, - self.out_connected, - self.in_idxlen.0, - self.in_idxlen.1, - self.in_connected, - self.at_idxlen.0, - self.at_idxlen.1, - self.mod_idxlen.0, - self.mod_idxlen.1)?; + write!( + f, + "Op(i={} out=({}-{}|{:x}) in=({}-{}|{:x}) at=({}-{}) mod=({}-{})", + self.idx, + self.out_idxlen.0, + self.out_idxlen.1, + self.out_connected, + self.in_idxlen.0, + self.in_idxlen.1, + self.in_connected, + self.at_idxlen.0, + self.at_idxlen.1, + self.mod_idxlen.0, + self.mod_idxlen.1 + )?; for i in self.inputs.iter() { write!(f, " cpy=(o{} => i{})", i.0, i.1)?; @@ -154,14 +153,14 @@ pub struct NodeProg { /// The input vector stores the smoothed values of the params. /// It is not used directly, but will be merged into the `cur_inp` /// field together with the assigned outputs. - pub inp: Vec, + pub inp: Vec, /// The temporary input vector that is initialized from `inp` /// and is then merged with the associated outputs. pub cur_inp: Vec, /// The output vector, holding all the node outputs. - pub out: Vec, + pub out: Vec, /// The param vector, holding all parameter inputs of the /// nodes, such as knob settings. @@ -169,11 +168,11 @@ pub struct NodeProg { /// The atom vector, holding all non automatable parameter inputs /// of the nodes, such as samples or integer settings. - pub atoms: Vec, + pub atoms: Vec, /// The node operations that are executed in the order they appear in this /// vector. - pub prog: Vec, + pub prog: Vec, /// The modulators for the input parameters. pub modops: Vec, @@ -210,15 +209,15 @@ impl NodeProg { let tb = TripleBuffer::new(out_fb); let (input_fb, output_fb) = tb.split(); Self { - out: vec![], - inp: vec![], + out: vec![], + inp: vec![], cur_inp: vec![], - params: vec![], - atoms: vec![], - prog: vec![], - modops: vec![], - out_feedback: input_fb, - out_fb_cons: Some(output_fb), + params: vec![], + atoms: vec![], + prog: vec![], + modops: vec![], + out_feedback: input_fb, + out_fb_cons: Some(output_fb), locked_buffers: false, } } @@ -250,9 +249,9 @@ impl NodeProg { params, atoms, modops, - prog: vec![], - out_feedback: input_fb, - out_fb_cons: Some(output_fb), + prog: vec![], + out_feedback: input_fb, + out_fb_cons: Some(output_fb), locked_buffers: false, } } @@ -281,7 +280,7 @@ impl NodeProg { } node_op.out_connected = 0x0; - node_op.in_connected = 0x0; + node_op.in_connected = 0x0; self.prog.push(node_op); } @@ -290,8 +289,8 @@ impl NodeProg { node_op: NodeOp, inp_index: usize, out_index: usize, - mod_index: Option) - { + mod_index: Option, + ) { for n_op in self.prog.iter_mut() { if n_op.out_idx_belongs_to_nodeop(out_index) { n_op.set_out_idx_connected_flag(out_index); @@ -328,10 +327,7 @@ impl NodeProg { // XXX: Swapping is now safe, because the `cur_inp` field // no longer references to the buffers in `inp` or `out`. - for (old_inp_pb, new_inp_pb) in - prev_prog.inp.iter_mut().zip( - self.inp.iter_mut()) - { + for (old_inp_pb, new_inp_pb) in prev_prog.inp.iter_mut().zip(self.inp.iter_mut()) { std::mem::swap(old_inp_pb, new_inp_pb); } } @@ -364,21 +360,19 @@ impl NodeProg { // This might lead to unexpected effects inside the process() // call of the nodes. let input_bufs = &mut self.cur_inp; - let out_bufs = &mut self.out; + let out_bufs = &mut self.out; let inp = op.in_idxlen; // First step (refresh inputs): - input_bufs[inp.0..inp.1] - .copy_from_slice(&self.inp[inp.0..inp.1]); + input_bufs[inp.0..inp.1].copy_from_slice(&self.inp[inp.0..inp.1]); // Second step (assign outputs): for io in op.inputs.iter() { input_bufs[io.1] = out_bufs[io.0]; if let Some(idx) = io.2 { - input_bufs[io.1] = - self.modops[idx].lock(self.inp[io.1], out_bufs[io.0]); + input_bufs[io.1] = self.modops[idx].lock(self.inp[io.1], out_bufs[io.0]); } } } @@ -386,4 +380,3 @@ impl NodeProg { self.locked_buffers = true; } } - diff --git a/src/nodes/visual_sampling_filter.rs b/src/nodes/visual_sampling_filter.rs index 4076bf5..f394620 100644 --- a/src/nodes/visual_sampling_filter.rs +++ b/src/nodes/visual_sampling_filter.rs @@ -2,7 +2,7 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. -const VALUE_SAMPLING_FILTER_SIZE : usize = 10; +const VALUE_SAMPLING_FILTER_SIZE: usize = 10; /// Accumulates the values for a single visible feedback value, /// like an LED ([crate::Matrix::led_value_for]) or the @@ -11,27 +11,27 @@ const VALUE_SAMPLING_FILTER_SIZE : usize = 10; pub struct VisualSamplingFilter { /// Holds a state bit, that is used to check if this /// filter needs to recalculate or not. - recalc_state: bool, + recalc_state: bool, /// Current write head into the sample buffer. - write_ptr: usize, + write_ptr: usize, /// Holds a set of the most recent samples to calculate /// the output. - sample_buffer: [f32; VALUE_SAMPLING_FILTER_SIZE], + sample_buffer: [f32; VALUE_SAMPLING_FILTER_SIZE], /// Holds the last output, will only be recalculated /// when necessary. - last_output: (f32, f32), + last_output: (f32, f32), } impl VisualSamplingFilter { pub fn new() -> Self { Self { - recalc_state: false, - write_ptr: 0, - sample_buffer: [0.0; VALUE_SAMPLING_FILTER_SIZE], - last_output: (0.0, 0.0), + recalc_state: false, + write_ptr: 0, + sample_buffer: [0.0; VALUE_SAMPLING_FILTER_SIZE], + last_output: (0.0, 0.0), } } @@ -69,14 +69,13 @@ impl VisualSamplingFilter { ///``` pub fn get(&mut self, recalc_value: bool, sample: f32) -> (f32, f32) { if self.needs_recalc(recalc_value) { - let write_ptr = - (self.write_ptr + 1) % self.sample_buffer.len(); + let write_ptr = (self.write_ptr + 1) % self.sample_buffer.len(); self.write_ptr = write_ptr; self.sample_buffer[write_ptr] = sample; - let mut neg_max : f32 = 0.0; - let mut pos_max : f32 = 0.0; + let mut neg_max: f32 = 0.0; + let mut pos_max: f32 = 0.0; for v in self.sample_buffer.iter() { if *v >= 0.0 { @@ -92,4 +91,3 @@ impl VisualSamplingFilter { self.last_output } } - diff --git a/src/sample_lib.rs b/src/sample_lib.rs index 64c6034..310d8ba 100644 --- a/src/sample_lib.rs +++ b/src/sample_lib.rs @@ -27,9 +27,7 @@ pub struct SampleLibrary { impl SampleLibrary { pub fn new() -> Self { - Self { - loaded_samples: HashMap::new(), - } + Self { loaded_samples: HashMap::new() } } /// Synchronous/blocking loading of a sample from `path`. @@ -42,11 +40,10 @@ impl SampleLibrary { return Ok(self.loaded_samples.get(path).unwrap()); } - let mut rd = - match hound::WavReader::open(path) { - Err(e) => return Err(SampleLoadError::LoadError(e)), - Ok(rd) => rd, - }; + let mut rd = match hound::WavReader::open(path) { + Err(e) => return Err(SampleLoadError::LoadError(e)), + Ok(rd) => rd, + }; let channels = rd.spec().channels as usize; @@ -57,7 +54,7 @@ impl SampleLibrary { for s in rd.samples::().step_by(channels) { v.push(s?); } - }, + } // http://blog.bjornroche.com/2009/12/int-float-int-its-jungle-out-there.html hound::SampleFormat::Int => { for s in rd.samples::().step_by(channels) { @@ -65,7 +62,7 @@ impl SampleLibrary { let s = s as f32 / (0x8000 as f32); v.push(s); } - }, + } }; let atom = SAtom::audio(path, std::sync::Arc::new(v)); @@ -76,7 +73,9 @@ impl SampleLibrary { } impl Default for SampleLibrary { - fn default() -> Self { Self::new() } + fn default() -> Self { + Self::new() + } } #[cfg(test)] @@ -85,10 +84,10 @@ mod tests { fn save_wav(name: &str, buf: &[f32]) { let spec = hound::WavSpec { - channels: 1, - sample_rate: 44100, + channels: 1, + sample_rate: 44100, bits_per_sample: 16, - sample_format: hound::SampleFormat::Int, + sample_format: hound::SampleFormat::Int, }; let mut writer = hound::WavWriter::create(name, spec).unwrap(); diff --git a/src/util.rs b/src/util.rs index a2515c6..4ae966d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -4,27 +4,20 @@ use std::sync::atomic::{AtomicU32, Ordering}; -const SMOOTHING_TIME_MS : f32 = 10.0; +const SMOOTHING_TIME_MS: f32 = 10.0; pub struct Smoother { - slope_samples: usize, - value: f32, - inc: f32, - target: f32, - count: usize, - done: bool, + slope_samples: usize, + value: f32, + inc: f32, + target: f32, + count: usize, + done: bool, } impl Smoother { pub fn new() -> Self { - Self { - slope_samples: 0, - value: 0.0, - inc: 0.0, - count: 0, - target: 0.0, - done: true, - } + Self { slope_samples: 0, value: 0.0, inc: 0.0, count: 0, target: 0.0, done: true } } pub fn set_sample_rate(&mut self, sr: f32) { @@ -32,19 +25,23 @@ impl Smoother { } #[inline] - pub fn is_done(&self) -> bool { self.done } + pub fn is_done(&self) -> bool { + self.done + } #[inline] #[allow(dead_code)] - pub fn stop(&mut self) { self.done = true; } + pub fn stop(&mut self) { + self.done = true; + } #[inline] pub fn set(&mut self, current: f32, target: f32) { - self.value = current; - self.count = self.slope_samples; - self.inc = (target - current) / (self.count as f32); + self.value = current; + self.count = self.slope_samples; + self.inc = (target - current) / (self.count as f32); self.target = target; - self.done = false; + self.done = false; } #[inline] @@ -66,13 +63,13 @@ impl Smoother { } pub struct PerfTimer { - lbl: &'static str, - i: std::time::Instant, - off: bool, - // let tb = std::time::Instant::now(); - // let ta = std::time::Instant::now().duration_since(ta); - // let tb = std::time::Instant::now().duration_since(tb); - // println!("ta Elapsed: {:?}", ta); + lbl: &'static str, + i: std::time::Instant, + off: bool, + // let tb = std::time::Instant::now(); + // let ta = std::time::Instant::now().duration_since(ta); + // let tb = std::time::Instant::now().duration_since(tb); + // println!("ta Elapsed: {:?}", ta); } impl PerfTimer { @@ -82,19 +79,16 @@ impl PerfTimer { self } - #[inline] pub fn new(lbl: &'static str) -> Self { - Self { - lbl, - i: std::time::Instant::now(), - off: false, - } + Self { lbl, i: std::time::Instant::now(), off: false } } #[inline] pub fn print(&mut self, lbl2: &str) { - if self.off { return; } + if self.off { + return; + } let t = std::time::Instant::now().duration_since(self.i); println!("*** PERF[{}/{}] {:?}", self.lbl, lbl2, t); @@ -102,7 +96,7 @@ impl PerfTimer { } } -// Implementation from vst-rs +// Implementation from vst-rs // https://github.com/RustAudio/vst-rs/blob/master/src/util/atomic_float.rs // Under MIT License // Copyright (c) 2015 Marko Mijalkovic @@ -113,9 +107,7 @@ pub struct AtomicFloat { impl AtomicFloat { /// New atomic float with initial value `value`. pub fn new(value: f32) -> AtomicFloat { - AtomicFloat { - atomic: AtomicU32::new(value.to_bits()), - } + AtomicFloat { atomic: AtomicU32::new(value.to_bits()) } } /// Get the current value of the atomic float. diff --git a/tests/basics.rs b/tests/basics.rs index d153eb7..e3c6791 100644 --- a/tests/basics.rs +++ b/tests/basics.rs @@ -12,16 +12,14 @@ fn check_matrix_sine() { let sin = NodeId::Sin(2); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, sin.out("sig"), None)); - matrix.place(1, 0, Cell::empty(out) - .input(None, out.inp("ch1"), None)); + matrix.place(0, 0, Cell::empty(sin).out(None, sin.out("sig"), None)); + matrix.place(1, 0, Cell::empty(out).input(None, out.inp("ch1"), None)); matrix.sync().unwrap(); let (mut out_l, out_r) = run_no_input(&mut node_exec, 4.0); - let sum_l : f32 = out_l.iter().map(|v| v.abs()).sum(); - let sum_r : f32 = out_r.iter().map(|v| v.abs()).sum(); + let sum_l: f32 = out_l.iter().map(|v| v.abs()).sum(); + let sum_r: f32 = out_r.iter().map(|v| v.abs()).sum(); assert_float_eq!(sum_l.floor(), 112301.0); assert_float_eq!(sum_r, 0.0); @@ -60,10 +58,8 @@ fn check_matrix_atom_set() { let sin = NodeId::Sin(2); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, sin.out("sig"), None)); - matrix.place(1, 0, Cell::empty(out) - .input(None, out.inp("ch1"), None)); + matrix.place(0, 0, Cell::empty(sin).out(None, sin.out("sig"), None)); + matrix.place(1, 0, Cell::empty(out).input(None, out.inp("ch1"), None)); matrix.sync().unwrap(); let mono_param = out.inp_param("mono").unwrap(); @@ -72,8 +68,8 @@ fn check_matrix_atom_set() { let (out_l, out_r) = run_no_input(&mut node_exec, 4.0); - let sum_l : f32 = out_l.iter().map(|v| v.abs()).sum(); - let sum_r : f32 = out_r.iter().map(|v| v.abs()).sum(); + let sum_l: f32 = out_l.iter().map(|v| v.abs()).sum(); + let sum_r: f32 = out_r.iter().map(|v| v.abs()).sum(); assert_float_eq!(sum_l.floor(), 112301.0); assert_float_eq!(sum_r.floor(), 112301.0); @@ -92,7 +88,6 @@ fn check_matrix_atom_set() { } } - #[test] fn check_sine_pitch_change() { let (node_conf, mut node_exec) = new_node_engine(); @@ -100,10 +95,8 @@ fn check_sine_pitch_change() { let sin = NodeId::Sin(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, sin.out("sig"), None)); - matrix.place(1, 0, Cell::empty(out) - .input(None, out.inp("ch1"), None)); + matrix.place(0, 0, Cell::empty(sin).out(None, sin.out("sig"), None)); + matrix.place(1, 0, Cell::empty(out).input(None, out.inp("ch1"), None)); matrix.sync().unwrap(); let (mut out_l, _out_r) = run_no_input(&mut node_exec, 0.2); @@ -116,9 +109,7 @@ fn check_sine_pitch_change() { let freq_param = sin.inp_param("freq").unwrap(); - matrix.set_param( - freq_param, - SAtom::param(freq_param.norm(4400.0))); + matrix.set_param(freq_param, SAtom::param(freq_param.norm(4400.0))); let (mut out_l, _out_r) = run_no_input(&mut node_exec, 1.0); @@ -144,10 +135,10 @@ fn check_sine_pitch_change() { #[test] fn check_detune_parameter() { let sin = NodeId::Sin(0); - let det_param = sin.inp_param("det").unwrap(); - assert_float_eq!(det_param.norm(12.0), 0.1); + let det_param = sin.inp_param("det").unwrap(); + assert_float_eq!(det_param.norm(12.0), 0.1); assert_float_eq!(det_param.norm(-12.0), -0.1); - assert_float_eq!(det_param.norm(24.0), 0.2); + assert_float_eq!(det_param.norm(24.0), 0.2); assert_float_eq!(det_param.norm(-24.0), -0.2); } @@ -158,14 +149,12 @@ fn check_sine_freq_detune() { let sin = NodeId::Sin(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, sin.out("sig"), None)); - matrix.place(1, 0, Cell::empty(out) - .input(None, out.inp("ch1"), None)); + matrix.place(0, 0, Cell::empty(sin).out(None, sin.out("sig"), None)); + matrix.place(1, 0, Cell::empty(out).input(None, out.inp("ch1"), None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); - let det_param = sin.inp_param("det").unwrap(); + let det_param = sin.inp_param("det").unwrap(); run_no_input(&mut node_exec, 50.0); @@ -211,11 +200,16 @@ fn check_matrix_monitor() { let sin = NodeId::Sin(2); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .input(sin.inp("freq"), sin.inp("freq"), sin.inp("freq")) - .out(sin.out("sig"), sin.out("sig"), sin.out("sig"))); - matrix.place(1, 0, Cell::empty(out) - .input(None, out.inp("ch1"), None)); + matrix.place( + 0, + 0, + Cell::empty(sin).input(sin.inp("freq"), sin.inp("freq"), sin.inp("freq")).out( + sin.out("sig"), + sin.out("sig"), + sin.out("sig"), + ), + ); + matrix.place(1, 0, Cell::empty(out).input(None, out.inp("ch1"), None)); matrix.sync().unwrap(); // Go to 220Hz @@ -224,25 +218,24 @@ fn check_matrix_monitor() { matrix.monitor_cell(*matrix.get(0, 0).unwrap()); - let (mut out_l, _out_r) = - run_realtime_no_input(&mut node_exec, 0.3, true); + let (mut out_l, _out_r) = run_realtime_no_input(&mut node_exec, 0.3, true); // Give the MonitorProcessor some time to work on the buffers. std::thread::sleep(std::time::Duration::from_millis(100)); -//assert!(false); + //assert!(false); for i in 0..3 { let sl = matrix.get_minmax_monitor_samples(i); //d// println!("SL={:?}", sl); //d// println!("=> {}", i); - assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -1000); - assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, -1000); + assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -1000); + assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, -1000); assert_eq!((sl[sl.len() - 13].0 * 10000.0) as i64, -1000); // Here we see that the paramter is smoothed in: - assert_eq!((sl[sl.len() - 14].1 * 10000.0) as i64, -2); - assert_eq!((sl[sl.len() - 15].0 * 10000.0) as i64, 0); - assert_eq!((sl[sl.len() - 15].1 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 14].1 * 10000.0) as i64, -2); + assert_eq!((sl[sl.len() - 15].0 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 15].1 * 10000.0) as i64, 0); } for i in 3..6 { @@ -250,12 +243,12 @@ fn check_matrix_monitor() { //d// println!("SL={:?}", sl); //d// println!("=> {}", i); - assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -9999); - assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 9999); + assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -9999); + assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 9999); assert_eq!((sl[sl.len() - 14].0 * 10000.0) as i64, -9999); - assert_eq!((sl[sl.len() - 14].1 * 10000.0) as i64, 9999); - assert_eq!((sl[sl.len() - 15].0 * 10000.0) as i64, 0); - assert_eq!((sl[sl.len() - 15].1 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 14].1 * 10000.0) as i64, 9999); + assert_eq!((sl[sl.len() - 15].0 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 15].1 * 10000.0) as i64, 0); } let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 50.0); @@ -272,7 +265,6 @@ fn check_matrix_monitor() { // 220Hz is one Octave below 440Hz assert_eq!(fft_res[0], (215, 253)); - } #[test] @@ -282,30 +274,30 @@ fn check_matrix_monitor_bug_1() { let sin = NodeId::Sin(0); let amp = NodeId::Amp(1); - matrix.place(0, 0, Cell::empty(sin) - .out(None, sin.out("sig"), None)); - matrix.place(1, 0, Cell::empty(amp) - .out(None, None, amp.out("sig")) - .input(None, amp.inp("inp"), None)); + matrix.place(0, 0, Cell::empty(sin).out(None, sin.out("sig"), None)); + matrix.place( + 1, + 0, + Cell::empty(amp).out(None, None, amp.out("sig")).input(None, amp.inp("inp"), None), + ); matrix.sync().unwrap(); matrix.monitor_cell(*matrix.get(1, 0).unwrap()); - let (_out_l, _out_r) = - run_realtime_no_input(&mut node_exec, 0.2, true); + let (_out_l, _out_r) = run_realtime_no_input(&mut node_exec, 0.2, true); std::thread::sleep(std::time::Duration::from_millis(100)); for i in [0, 2, 3, 4].iter() { let sl = matrix.get_minmax_monitor_samples(*i); - assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, 0); - assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, 0); + assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 0); } for i in [1, 5].iter() { let sl = matrix.get_minmax_monitor_samples(*i); - assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -9999); - assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 9999); + assert_eq!((sl[sl.len() - 1].0 * 10000.0) as i64, -9999); + assert_eq!((sl[sl.len() - 1].1 * 10000.0) as i64, 9999); } } @@ -314,20 +306,24 @@ fn check_matrix_out_config_bug1() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - matrix.place(0, 0, Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); - matrix.place(0, 1, Cell::empty(NodeId::Sin(1)) - .out(None, Some(0), None)); - matrix.place(1, 2, Cell::empty(NodeId::Sin(0)) - .input(None, Some(0), None) - .out(None, None, Some(0))); - matrix.place(1, 1, Cell::empty(NodeId::Out(0)) - .input(Some(1), Some(0), None) - .out(None, None, Some(0))); + matrix.place(0, 1, Cell::empty(NodeId::Sin(1)).out(None, Some(0), None)); + matrix.place( + 1, + 2, + Cell::empty(NodeId::Sin(0)).input(None, Some(0), None).out(None, None, Some(0)), + ); + matrix.place( + 1, + 1, + Cell::empty(NodeId::Out(0)).input(Some(1), Some(0), None).out(None, None, Some(0)), + ); assert!(matrix.sync().is_err()); @@ -339,12 +335,16 @@ fn check_matrix_out_config_bug1_reduced() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .input(Some(0), None, None) - .out(None, None, Some(0))); - matrix.place(1, 2, Cell::empty(NodeId::Out(0)) - .input(Some(0), None, None) - .out(None, None, None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(Some(0), None, None).out(None, None, Some(0)), + ); + matrix.place( + 1, + 2, + Cell::empty(NodeId::Out(0)).input(Some(0), None, None).out(None, None, None), + ); matrix.sync().unwrap(); @@ -356,10 +356,8 @@ fn check_matrix_out_config_bug1b_reduced() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .out(None, None, Some(0))); - matrix.place(1, 1, Cell::empty(NodeId::Out(0)) - .input(Some(0), None, None)); + matrix.place(1, 0, Cell::empty(NodeId::Out(0)).out(None, None, Some(0))); + matrix.place(1, 1, Cell::empty(NodeId::Out(0)).input(Some(0), None, None)); assert!(matrix.sync().is_err()); @@ -371,10 +369,8 @@ fn check_matrix_out_config_bug1c_reduced() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - matrix.place(1, 0, Cell::empty(NodeId::Sin(0)) - .out(None, None, Some(0))); - matrix.place(1, 1, Cell::empty(NodeId::Out(0)) - .input(Some(9), None, None)); + matrix.place(1, 0, Cell::empty(NodeId::Sin(0)).out(None, None, Some(0))); + matrix.place(1, 1, Cell::empty(NodeId::Out(0)).input(Some(9), None, None)); matrix.sync().unwrap(); @@ -396,71 +392,57 @@ macro_rules! simple_sine_output_test { assert_float_eq!(rms_mimax[0].0, 0.5); assert_float_eq!(rms_mimax[0].1, -0.9999999); assert_float_eq!(rms_mimax[0].2, 0.9999999); - } + }; } #[test] fn check_matrix_connect_even_top_left() { simple_sine_output_test!(matrix, { - matrix.place(1, 0, Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(2, 1, Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None)); + matrix.place(1, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place(2, 1, Cell::empty(NodeId::Out(0)).input(None, Some(0), None)); }); } - #[test] fn check_matrix_connect_even_bottom_left() { simple_sine_output_test!(matrix, { - matrix.place(1, 1, Cell::empty(NodeId::Sin(0)) - .out(Some(0), None, None)); - matrix.place(2, 1, Cell::empty(NodeId::Out(0)) - .input(None, None, Some(0))); + matrix.place(1, 1, Cell::empty(NodeId::Sin(0)).out(Some(0), None, None)); + matrix.place(2, 1, Cell::empty(NodeId::Out(0)).input(None, None, Some(0))); }); } #[test] fn check_matrix_connect_even_top() { simple_sine_output_test!(matrix, { - matrix.place(0, 0, Cell::empty(NodeId::Sin(0)) - .out(None, None, Some(0))); - matrix.place(0, 1, Cell::empty(NodeId::Out(0)) - .input(Some(0), None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, None, Some(0))); + matrix.place(0, 1, Cell::empty(NodeId::Out(0)).input(Some(0), None, None)); }); } #[test] fn check_matrix_connect_odd_top_left() { simple_sine_output_test!(matrix, { - matrix.place(0, 0, Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .input(None, Some(0), None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place(1, 0, Cell::empty(NodeId::Out(0)).input(None, Some(0), None)); }); } #[test] fn check_matrix_connect_odd_bottom_left() { simple_sine_output_test!(matrix, { - matrix.place(0, 1, Cell::empty(NodeId::Sin(0)) - .out(Some(0), None, None)); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .input(None, None, Some(0))); + matrix.place(0, 1, Cell::empty(NodeId::Sin(0)).out(Some(0), None, None)); + matrix.place(1, 0, Cell::empty(NodeId::Out(0)).input(None, None, Some(0))); }); } #[test] fn check_matrix_connect_odd_top() { simple_sine_output_test!(matrix, { - matrix.place(1, 0, Cell::empty(NodeId::Sin(0)) - .out(None, None, Some(0))); - matrix.place(1, 1, Cell::empty(NodeId::Out(0)) - .input(Some(0), None, None)); + matrix.place(1, 0, Cell::empty(NodeId::Sin(0)).out(None, None, Some(0))); + matrix.place(1, 1, Cell::empty(NodeId::Out(0)).input(Some(0), None, None)); }); } - #[test] fn check_matrix_adj_odd() { let (node_conf, _node_exec) = new_node_engine(); @@ -489,46 +471,29 @@ fn check_matrix_adj_odd() { \___/ \___/ */ - matrix.place(1, 1, Cell::empty(NodeId::Sin(0)) - .out(Some(0), Some(0), Some(0)) - .input(Some(0), Some(0), Some(0))); + matrix.place( + 1, + 1, + Cell::empty(NodeId::Sin(0)).out(Some(0), Some(0), Some(0)).input(Some(0), Some(0), Some(0)), + ); - matrix.place(0, 1, Cell::empty(NodeId::Sin(1)) - .out(None, Some(0), None)); - matrix.place(1, 0, Cell::empty(NodeId::Sin(2)) - .out(None, None, Some(0))); - matrix.place(2, 1, Cell::empty(NodeId::Sin(3)) - .input(None, None, Some(0))); - matrix.place(2, 2, Cell::empty(NodeId::Sin(4)) - .input(None, Some(0), None)); - matrix.place(1, 2, Cell::empty(NodeId::Sin(5)) - .input(Some(0), None, None)); - matrix.place(0, 2, Cell::empty(NodeId::Sin(6)) - .out(Some(0), None, None)); + matrix.place(0, 1, Cell::empty(NodeId::Sin(1)).out(None, Some(0), None)); + matrix.place(1, 0, Cell::empty(NodeId::Sin(2)).out(None, None, Some(0))); + matrix.place(2, 1, Cell::empty(NodeId::Sin(3)).input(None, None, Some(0))); + matrix.place(2, 2, Cell::empty(NodeId::Sin(4)).input(None, Some(0), None)); + matrix.place(1, 2, Cell::empty(NodeId::Sin(5)).input(Some(0), None, None)); + matrix.place(0, 2, Cell::empty(NodeId::Sin(6)).out(Some(0), None, None)); matrix.sync().unwrap(); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::B).unwrap().node_id(), - NodeId::Sin(5)); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::BR).unwrap().node_id(), - NodeId::Sin(4)); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::TR).unwrap().node_id(), - NodeId::Sin(3)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::B).unwrap().node_id(), NodeId::Sin(5)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::BR).unwrap().node_id(), NodeId::Sin(4)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::TR).unwrap().node_id(), NodeId::Sin(3)); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::T).unwrap().node_id(), - NodeId::Sin(2)); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::TL).unwrap().node_id(), - NodeId::Sin(1)); - assert_eq!( - matrix.get_adjacent(1, 1, CellDir::BL).unwrap().node_id(), - NodeId::Sin(6)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::T).unwrap().node_id(), NodeId::Sin(2)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::TL).unwrap().node_id(), NodeId::Sin(1)); + assert_eq!(matrix.get_adjacent(1, 1, CellDir::BL).unwrap().node_id(), NodeId::Sin(6)); } - #[test] fn check_matrix_adj_even() { let (node_conf, _node_exec) = new_node_engine(); @@ -557,43 +522,27 @@ fn check_matrix_adj_even() { \___/ \___/ */ - matrix.place(2, 1, Cell::empty(NodeId::Sin(0)) - .out(Some(0), Some(0), Some(0)) - .input(Some(0), Some(0), Some(0))); + matrix.place( + 2, + 1, + Cell::empty(NodeId::Sin(0)).out(Some(0), Some(0), Some(0)).input(Some(0), Some(0), Some(0)), + ); - matrix.place(1, 0, Cell::empty(NodeId::Sin(1)) - .out(None, Some(0), None)); - matrix.place(2, 0, Cell::empty(NodeId::Sin(2)) - .out(None, None, Some(0))); - matrix.place(3, 0, Cell::empty(NodeId::Sin(3)) - .input(None, None, Some(0))); - matrix.place(3, 1, Cell::empty(NodeId::Sin(4)) - .input(None, Some(0), None)); - matrix.place(2, 2, Cell::empty(NodeId::Sin(5)) - .input(Some(0), None, None)); - matrix.place(1, 1, Cell::empty(NodeId::Sin(6)) - .out(Some(0), None, None)); + matrix.place(1, 0, Cell::empty(NodeId::Sin(1)).out(None, Some(0), None)); + matrix.place(2, 0, Cell::empty(NodeId::Sin(2)).out(None, None, Some(0))); + matrix.place(3, 0, Cell::empty(NodeId::Sin(3)).input(None, None, Some(0))); + matrix.place(3, 1, Cell::empty(NodeId::Sin(4)).input(None, Some(0), None)); + matrix.place(2, 2, Cell::empty(NodeId::Sin(5)).input(Some(0), None, None)); + matrix.place(1, 1, Cell::empty(NodeId::Sin(6)).out(Some(0), None, None)); matrix.sync().unwrap(); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::B).unwrap().node_id(), - NodeId::Sin(5)); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::BR).unwrap().node_id(), - NodeId::Sin(4)); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::TR).unwrap().node_id(), - NodeId::Sin(3)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::B).unwrap().node_id(), NodeId::Sin(5)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::BR).unwrap().node_id(), NodeId::Sin(4)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::TR).unwrap().node_id(), NodeId::Sin(3)); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::T).unwrap().node_id(), - NodeId::Sin(2)); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::TL).unwrap().node_id(), - NodeId::Sin(1)); - assert_eq!( - matrix.get_adjacent(2, 1, CellDir::BL).unwrap().node_id(), - NodeId::Sin(6)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::T).unwrap().node_id(), NodeId::Sin(2)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::TL).unwrap().node_id(), NodeId::Sin(1)); + assert_eq!(matrix.get_adjacent(2, 1, CellDir::BL).unwrap().node_id(), NodeId::Sin(6)); } #[test] @@ -601,18 +550,17 @@ fn check_matrix_out_twice_assignment() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - matrix.place(0, 0, Cell::empty(NodeId::Sin(0)) - .out(None, Some(0), None)); - matrix.place(0, 1, Cell::empty(NodeId::Sin(0)) - .out(Some(0), None, None)); - matrix.place(1, 0, Cell::empty(NodeId::Out(0)) - .input(None, Some(0), Some(0)) - .out(None, None, None)); + matrix.place(0, 0, Cell::empty(NodeId::Sin(0)).out(None, Some(0), None)); + matrix.place(0, 1, Cell::empty(NodeId::Sin(0)).out(Some(0), None, None)); + matrix.place( + 1, + 0, + Cell::empty(NodeId::Out(0)).input(None, Some(0), Some(0)).out(None, None, None), + ); matrix.sync().unwrap(); let (_out_l, _out_r) = run_no_input(&mut node_exec, 0.2); - } #[test] @@ -623,16 +571,16 @@ fn check_matrix_amp() { let sin = NodeId::Sin(0); let amp = NodeId::Amp(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(amp) - .input(out.inp("ch1"), None, None) - .out(None, None, sin.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(amp).input(out.inp("ch1"), None, None).out(None, None, sin.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); - let att_param = amp.inp_param("att").unwrap(); + let att_param = amp.inp_param("att").unwrap(); matrix.set_param(att_param, SAtom::param(0.5)); let (rms, _, _) = run_and_get_l_rms_mimax(&mut node_exec, 50.0); @@ -663,10 +611,8 @@ fn check_matrix_clear() { let sin = NodeId::Sin(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -685,17 +631,14 @@ fn check_matrix_clear() { let fft = run_and_get_fft4096(&mut node_exec, 1, 50.0); assert_eq!(fft.len(), 0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let fft = run_and_get_fft4096(&mut node_exec, 800, 50.0); assert_eq!(fft[0], (441, 1012)); } - #[test] fn check_matrix_serialize() { { @@ -704,10 +647,8 @@ fn check_matrix_serialize() { let sin = NodeId::Sin(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -716,16 +657,14 @@ fn check_matrix_serialize() { let fft = run_and_get_fft4096(&mut node_exec, 800, 10.0); assert_eq!(fft[0], (108, 993)); - hexodsp::save_patch_to_file(&mut matrix, "check_matrix_serialize.hxy") - .unwrap(); + hexodsp::save_patch_to_file(&mut matrix, "check_matrix_serialize.hxy").unwrap(); } { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - hexodsp::load_patch_from_file( - &mut matrix, "check_matrix_serialize.hxy").unwrap(); + hexodsp::load_patch_from_file(&mut matrix, "check_matrix_serialize.hxy").unwrap(); let fft = run_and_get_fft4096(&mut node_exec, 800, 10.0); assert_eq!(fft[0], (108, 993)); @@ -742,13 +681,13 @@ fn check_matrix_tseq() { let sin = NodeId::Sin(0); let tsq = NodeId::TSeq(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(tsq) - .input(tsq.inp("clock"), None, None) - .out(None, None, tsq.out("trk1"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tsq).input(tsq.inp("clock"), None, None).out(None, None, tsq.out("trk1")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, sin, "freq", -0.978); @@ -758,7 +697,7 @@ fn check_matrix_tseq() { { let mut pr = pat.lock().unwrap(); pr.set_rows(16); - pr.set_cell_value(0, 0, 0xFFF); + pr.set_cell_value(0, 0, 0xFFF); pr.set_cell_value(15, 0, 0x000); } @@ -772,19 +711,28 @@ fn check_matrix_tseq() { // Take some real samples: let samples = run_and_undersample(&mut node_exec, 2000.0, 10); - assert_vec_feq!(samples, vec![ - 0.5322106, 0.4255343, 0.318858, 0.21218172, 0.105505496, 0.017571526, - // then start at the beginning: - 0.958819, 0.8521427, 0.7454664, 0.63879013 - ]); + assert_vec_feq!( + samples, + vec![ + 0.5322106, + 0.4255343, + 0.318858, + 0.21218172, + 0.105505496, + 0.017571526, + // then start at the beginning: + 0.958819, + 0.8521427, + 0.7454664, + 0.63879013 + ] + ); // switch to row trigger: pset_s(&mut matrix, tsq, "cmode", 0); let samples = run_and_undersample(&mut node_exec, 2000.0, 5); - assert_vec_feq!(samples, vec![ - 0.5011433, 0.7011613, 0.9011793, 0.9932535, 0.97991896 - ]); + assert_vec_feq!(samples, vec![0.5011433, 0.7011613, 0.9011793, 0.9932535, 0.97991896]); // set to phase mode: pset_s(&mut matrix, tsq, "cmode", 2); @@ -807,13 +755,13 @@ fn check_matrix_tseq_trig() { let sin = NodeId::Sin(0); let tsq = NodeId::TSeq(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(tsq) - .input(tsq.inp("clock"), None, None) - .out(None, None, tsq.out("trk1"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tsq).input(tsq.inp("clock"), None, None).out(None, None, tsq.out("trk1")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, sin, "freq", -0.978); @@ -823,7 +771,7 @@ fn check_matrix_tseq_trig() { { let mut pr = pat.lock().unwrap(); pr.set_rows(16); - pr.set_cell_value(0, 0, 0xFFF); + pr.set_cell_value(0, 0, 0xFFF); pr.set_cell_value(15, 0, 0x000); } @@ -837,22 +785,43 @@ fn check_matrix_tseq_trig() { // Take some real samples: let samples = run_and_undersample(&mut node_exec, 2000.0, 10); - assert_vec_feq!(samples, vec![ - 0.5322106, 0.4255343, 0.318858, 0.21218172, 0.105505496, - 0.017571526, 0.958819, 0.8521427, 0.7454664, 0.63879013 - ]); + assert_vec_feq!( + samples, + vec![ + 0.5322106, + 0.4255343, + 0.318858, + 0.21218172, + 0.105505496, + 0.017571526, + 0.958819, + 0.8521427, + 0.7454664, + 0.63879013 + ] + ); pset_n(&mut matrix, tsq, "trig", 1.0); // Take some real samples: let samples = run_and_undersample(&mut node_exec, 2000.0, 10); - assert_vec_feq!(samples, vec![ - 0.5321138, - // Then trigger happens: - 0.96263915, 0.8559629, 0.74928665, 0.6426103, 0.53593403, 0.42925775, - 0.32258147, 0.21590519, 0.109228894 - ]); + assert_vec_feq!( + samples, + vec![ + 0.5321138, + // Then trigger happens: + 0.96263915, + 0.8559629, + 0.74928665, + 0.6426103, + 0.53593403, + 0.42925775, + 0.32258147, + 0.21590519, + 0.109228894 + ] + ); } #[test] @@ -865,13 +834,13 @@ fn check_matrix_tseq_gate() { let sin = NodeId::Sin(0); let tsq = NodeId::TSeq(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(tsq) - .input(tsq.inp("clock"), None, None) - .out(None, None, tsq.out("trk1"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tsq).input(tsq.inp("clock"), None, None).out(None, None, tsq.out("trk1")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -910,14 +879,23 @@ fn check_matrix_tseq_gate() { let samples = run_and_undersample(&mut node_exec, 2000.0, 2000); let changes = collect_gates(&samples[..]); - assert_eq!(changes, vec![ - (524, 126), (775, 8), - (1033, 1), (1041, 1), (1049, 1), (1080, 1), - (1088, 1), (1119, 1), (1127, 1), (1135, 1) - ]); + assert_eq!( + changes, + vec![ + (524, 126), + (775, 8), + (1033, 1), + (1041, 1), + (1049, 1), + (1080, 1), + (1088, 1), + (1119, 1), + (1127, 1), + (1135, 1) + ] + ); } - #[test] fn check_matrix_tseq_2col_gate_bug() { use hexodsp::dsp::tracker::UIPatternModel; @@ -928,13 +906,13 @@ fn check_matrix_tseq_2col_gate_bug() { let sin = NodeId::Sin(0); let tsq = NodeId::TSeq(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(tsq) - .input(tsq.inp("clock"), None, None) - .out(None, None, tsq.out("trk2"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tsq).input(tsq.inp("clock"), None, None).out(None, None, tsq.out("trk2")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); @@ -975,13 +953,14 @@ fn check_matrix_tseq_2col_gate_bug() { let mut any_non_zero = false; for s in samples.iter() { - if *s > 0.0 { any_non_zero = true; } + if *s > 0.0 { + any_non_zero = true; + } } assert!(any_non_zero); } - #[test] fn check_matrix_output_feedback() { let (node_conf, mut node_exec) = new_node_engine(); @@ -989,10 +968,8 @@ fn check_matrix_output_feedback() { let sin = NodeId::Sin(0); let amp = NodeId::Amp(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(amp) - .input(amp.inp("inp"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place(0, 1, Cell::empty(amp).input(amp.inp("inp"), None, None)); matrix.sync().unwrap(); let gain_p = amp.inp_param("gain").unwrap(); @@ -1024,23 +1001,23 @@ fn check_matrix_node_feedback() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 7, 7); - let sin = NodeId::Sin(0); + let sin = NodeId::Sin(0); let sin2 = NodeId::Sin(1); - let wr = NodeId::FbWr(0); - let rd = NodeId::FbRd(0); - let wr2 = NodeId::FbWr(1); - let rd2 = NodeId::FbRd(1); - let out = NodeId::Out(0); + let wr = NodeId::FbWr(0); + let rd = NodeId::FbRd(0); + let wr2 = NodeId::FbWr(1); + let rd2 = NodeId::FbRd(1); + let out = NodeId::Out(0); matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(wr) .input(wr.inp("inp"), None, None)); - matrix.place(1, 0, Cell::empty(rd) .out(None, None, rd.out("sig"))); + matrix.place(0, 1, Cell::empty(wr).input(wr.inp("inp"), None, None)); + matrix.place(1, 0, Cell::empty(rd).out(None, None, rd.out("sig"))); matrix.place(1, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.place(0, 2, Cell::empty(sin2).out(None, None, sin2.out("sig"))); - matrix.place(0, 3, Cell::empty(wr2) .input(wr2.inp("inp"), None, None)); - matrix.place(1, 2, Cell::empty(rd2) .out(None, None, rd2.out("sig"))); - matrix.place(1, 3, Cell::empty(out) .input(out.inp("ch2"), None, None)); + matrix.place(0, 3, Cell::empty(wr2).input(wr2.inp("inp"), None, None)); + matrix.place(1, 2, Cell::empty(rd2).out(None, None, rd2.out("sig"))); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch2"), None, None)); matrix.sync().unwrap(); let freq_param = sin2.inp_param("freq").unwrap(); @@ -1048,23 +1025,81 @@ fn check_matrix_node_feedback() { let (out_l, out_r) = run_for_ms(&mut node_exec, 10.0); assert_decimated_feq!( - out_l, 15, vec![ + out_l, + 15, + vec![ // The initial zeros are the feedback delays: - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.68328893, 0.9925844, 0.48698083, -0.4184115, -0.9803018, - -0.73738277, 0.110905044, 0.8681419, 0.9126584, 0.20790927, - -0.6675302, -0.99494797, -0.50553185, 0.39891028, 0.97586703, - 0.7516482, -0.089641616, -0.8573498, -0.9211795, -0.22875604 ]); + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.68328893, + 0.9925844, + 0.48698083, + -0.4184115, + -0.9803018, + -0.73738277, + 0.110905044, + 0.8681419, + 0.9126584, + 0.20790927, + -0.6675302, + -0.99494797, + -0.50553185, + 0.39891028, + 0.97586703, + 0.7516482, + -0.089641616, + -0.8573498, + -0.9211795, + -0.22875604 + ] + ); assert_decimated_feq!( - out_r, 15, vec![ + out_r, + 15, + vec![ // The initial zeros are the feedback delays: // The frequency will be established a bit later because // the parameter setting of 880 Hz will be smoothed: - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.8791775, 0.8898413, 0.10330327, -0.79178804, -0.92698133, - -0.11967586, 0.8259115, 0.86836, -0.09246742, -0.9534301, - -0.62676203, 0.5235326, 0.9718173, 0.04517236, -0.9560416, - -0.49554884, 0.7601789, 0.75973713, -0.5529301, -0.8783003 ]); + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.8791775, + 0.8898413, + 0.10330327, + -0.79178804, + -0.92698133, + -0.11967586, + 0.8259115, + 0.86836, + -0.09246742, + -0.9534301, + -0.62676203, + 0.5235326, + 0.9718173, + 0.04517236, + -0.9560416, + -0.49554884, + 0.7601789, + 0.75973713, + -0.5529301, + -0.8783003 + ] + ); // Let the frequency settle... run_for_ms(&mut node_exec, 80.0); @@ -1079,7 +1114,6 @@ fn check_matrix_node_feedback() { assert_eq!(fft_res_r[1], (904, 206)); } - #[test] fn check_matrix_tseq_perf() { use hexodsp::dsp::tracker::UIPatternModel; @@ -1090,21 +1124,21 @@ fn check_matrix_tseq_perf() { let sin = NodeId::Sin(0); let tsq = NodeId::TSeq(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(tsq) - .input(tsq.inp("clock"), None, None) - .out(None, None, tsq.out("trk1"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tsq).input(tsq.inp("clock"), None, None).out(None, None, tsq.out("trk1")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let freq_param = sin.inp_param("freq").unwrap(); -// matrix.set_param(freq_param, SAtom::param(-0.978)); + // matrix.set_param(freq_param, SAtom::param(-0.978)); matrix.set_param(freq_param, SAtom::param(0.0)); let cmode_param = tsq.inp_param("cmode").unwrap(); matrix.set_param(cmode_param, SAtom::setting(0)); -// matrix.set_param(cmode_param, SAtom::setting(2)); + // matrix.set_param(cmode_param, SAtom::setting(2)); let pat = matrix.get_pattern_data(0).unwrap(); { @@ -1114,21 +1148,21 @@ fn check_matrix_tseq_perf() { pr.set_col_gate_type(1); pr.set_col_gate_type(2); - pr.set_cell_value(0, 0, 0x0F7); - pr.set_cell_value(4, 0, 0x100); - pr.set_cell_value(8, 0, 0x10F); + pr.set_cell_value(0, 0, 0x0F7); + pr.set_cell_value(4, 0, 0x100); + pr.set_cell_value(8, 0, 0x10F); pr.set_cell_value(12, 0, 0x0F7); - pr.set_cell_value(0, 1, 0xFF1); - pr.set_cell_value(4, 1, 0xFF1); - pr.set_cell_value(8, 1, 0xFF1); + pr.set_cell_value(0, 1, 0xFF1); + pr.set_cell_value(4, 1, 0xFF1); + pr.set_cell_value(8, 1, 0xFF1); pr.set_cell_value(12, 1, 0xFF1); - pr.set_cell_value(0, 2, 0xFF1); - pr.set_cell_value(2, 2, 0xFF1); - pr.set_cell_value(4, 2, 0xFF1); - pr.set_cell_value(6, 2, 0xFF1); - pr.set_cell_value(8, 2, 0xFF1); + pr.set_cell_value(0, 2, 0xFF1); + pr.set_cell_value(2, 2, 0xFF1); + pr.set_cell_value(4, 2, 0xFF1); + pr.set_cell_value(6, 2, 0xFF1); + pr.set_cell_value(8, 2, 0xFF1); pr.set_cell_value(10, 2, 0xFF1); pr.set_cell_value(12, 2, 0xFF1); pr.set_cell_value(14, 2, 0xFF1); @@ -1138,15 +1172,17 @@ fn check_matrix_tseq_perf() { matrix.check_pattern_data(0); } - let mut prev : i64 = 0; - let mut first : i64 = 0; + let mut prev: i64 = 0; + let mut first: i64 = 0; for _ in 0..10 { let ta = std::time::Instant::now(); run_for_ms(&mut node_exec, 10000.0); let dur = std::time::Instant::now().duration_since(ta); if prev > 0 { let now = dur.as_millis() as i64; - if first <= 0 { first = now; } + if first <= 0 { + first = now; + } //d// println!("{},{}", prev, now); assert!((first - now).abs() < (first / 2)); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 93b9fad..0b1a3af 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,122 +2,156 @@ // This file is a part of HexoDSP. Released under GPL-3.0-or-later. // See README.md and COPYING for details. +pub use hexodsp::dsp::*; pub use hexodsp::matrix::*; pub use hexodsp::nodes::new_node_engine; -pub use hexodsp::dsp::*; pub use hexodsp::NodeExecutor; use hound; -pub const SAMPLE_RATE : f32 = 44100.0; +pub const SAMPLE_RATE: f32 = 44100.0; #[allow(dead_code)] -pub const SAMPLE_RATE_US : usize = 44100; +pub const SAMPLE_RATE_US: usize = 44100; #[macro_export] macro_rules! init_test { ($matrix: ident, $node_exec: ident, $size: expr) => { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, $size, $size); - let $matrix = &mut matrix; + let $matrix = &mut matrix; let $node_exec = &mut node_exec; - } + }; } #[macro_export] macro_rules! assert_float_eq { ($a:expr, $b:expr) => { if ($a - $b).abs() > 0.0001 { - panic!(r#"assertion failed: `(left == right)` + panic!( + r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`"#, $a, $b) + right: `{:?}`"#, + $a, $b + ) } - } + }; } #[macro_export] macro_rules! assert_fpair_eq { ($a:expr, $b:expr) => { if ($a.0 - $b.0).abs() > 0.0001 { - panic!(r#"assertion failed: `(left.0 == right.0)` + panic!( + r#"assertion failed: `(left.0 == right.0)` left: `{:?}`, - right: `{:?}`"#, $a.0, $b.0) + right: `{:?}`"#, + $a.0, $b.0 + ) } if ($a.1 - $b.1).abs() > 0.0001 { - panic!(r#"assertion failed: `(left.1 == right.1)` + panic!( + r#"assertion failed: `(left.1 == right.1)` left: `{:?}`, - right: `{:?}`"#, $a.1, $b.1) + right: `{:?}`"#, + $a.1, $b.1 + ) } - } + }; } #[macro_export] macro_rules! assert_f3tupl_eq { ($a:expr, $b:expr) => { if ($a.0 - $b.0).abs() > 0.0001 { - panic!(r#"assertion failed: `(left.0 == right.0)` + panic!( + r#"assertion failed: `(left.0 == right.0)` left.0: `{:?}`, - right.0: `{:?}`"#, $a.0, $b.0) + right.0: `{:?}`"#, + $a.0, $b.0 + ) } if ($a.1 - $b.1).abs() > 0.0001 { - panic!(r#"assertion failed: `(left.1 == right.1)` + panic!( + r#"assertion failed: `(left.1 == right.1)` left.1: `{:?}`, - right.1: `{:?}`"#, $a.1, $b.1) + right.1: `{:?}`"#, + $a.1, $b.1 + ) } if ($a.2 - $b.2).abs() > 0.0001 { - panic!(r#"assertion failed: `(left.2 == right.2)` + panic!( + r#"assertion failed: `(left.2 == right.2)` left.2: `{:?}`, - right.2: `{:?}`"#, $a.2, $b.2) + right.2: `{:?}`"#, + $a.2, $b.2 + ) } - } + }; } #[macro_export] macro_rules! assert_vec_feq { ($vec:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let res : Vec = $vec.iter().copied().collect(); + let res: Vec = $vec.iter().copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.0001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } #[macro_export] macro_rules! assert_decimated_feq { ($vec:expr, $decimate:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let res : Vec = $vec.iter().step_by($decimate).copied().collect(); + let res: Vec = $vec.iter().step_by($decimate).copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.0001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } #[macro_export] macro_rules! assert_slope_feq { ($vec:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let mut res : Vec = vec![]; + let mut res: Vec = vec![]; let mut prev = 0.0; for (i, s) in $vec.iter().enumerate() { let delta = *s - prev; @@ -127,28 +161,36 @@ macro_rules! assert_slope_feq { prev = *s; } - let res : Vec = res.iter().copied().collect(); + let res: Vec = res.iter().copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.0001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } #[macro_export] macro_rules! assert_decimated_slope_feq { ($vec:expr, $decimate:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let mut res : Vec = vec![]; + let mut res: Vec = vec![]; let mut prev = 0.0; for (i, s) in $vec.iter().enumerate() { let delta = *s - prev; @@ -158,29 +200,36 @@ macro_rules! assert_decimated_slope_feq { prev = *s; } - let res : Vec = res.iter().step_by($decimate).copied().collect(); + let res: Vec = res.iter().step_by($decimate).copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.0001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } - #[macro_export] macro_rules! assert_decimated_slope_feq_fine { ($vec:expr, $decimate:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let mut res : Vec = vec![]; + let mut res: Vec = vec![]; let mut prev = 0.0; for (i, s) in $vec.iter().enumerate() { let delta = *s - prev; @@ -190,28 +239,36 @@ macro_rules! assert_decimated_slope_feq_fine { prev = *s; } - let res : Vec = res.iter().step_by($decimate).copied().collect(); + let res: Vec = res.iter().step_by($decimate).copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.0000001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } #[macro_export] macro_rules! assert_decimated_slope_feq_sfine { ($vec:expr, $decimate:expr, $cmp_vec:expr) => { let cmp_vec = $cmp_vec; - let mut res : Vec = vec![]; + let mut res: Vec = vec![]; let mut prev = 0.0; for (i, s) in $vec.iter().enumerate() { let delta = *s - prev; @@ -221,28 +278,38 @@ macro_rules! assert_decimated_slope_feq_sfine { prev = *s; } - let res : Vec = res.iter().step_by($decimate).copied().collect(); + let res: Vec = res.iter().step_by($decimate).copied().collect(); for (i, (s, scmp)) in res.iter().zip(cmp_vec.iter()).enumerate() { if (s - scmp).abs() > 0.000000001 { - panic!(r#" + panic!( + r#" table_left: {:?} table_right: {:?} assertion failed: `(left[{}] == right[{}])` left: `{:?}`, - right: `{:?}`"#, &res[i..], &(cmp_vec[i..]), i, i, s, scmp) + right: `{:?}`"#, + &res[i..], + &(cmp_vec[i..]), + i, + i, + s, + scmp + ) } } - } + }; } #[macro_export] macro_rules! dump_table { ($vec:expr) => { - for (i, s) in $vec.iter().enumerate() { println!("{:2} {:?}", i, s); } - } + for (i, s) in $vec.iter().enumerate() { + println!("{:2} {:?}", i, s); + } + }; } #[allow(dead_code)] @@ -314,7 +381,7 @@ pub fn collect_gates(inp: &[f32]) -> Vec<(usize, usize)> { macro_rules! assert_rmsmima { ($rms:expr, $b:expr) => { assert_f3tupl_eq!($rms, $b); - } + }; } #[macro_export] @@ -322,7 +389,7 @@ macro_rules! assert_minmax_of_rms { ($rms:expr, $b:expr) => { let (_, min, max) = $rms; assert_fpair_eq!((min, max), $b); - } + }; } #[allow(unused)] @@ -344,14 +411,26 @@ pub fn pset_d(matrix: &mut Matrix, nid: NodeId, parm: &str, v_denorm: f32) { } #[allow(unused)] -pub fn pset_n_wait(matrix: &mut Matrix, ne: &mut NodeExecutor, nid: NodeId, parm: &str, v_norm: f32) { +pub fn pset_n_wait( + matrix: &mut Matrix, + ne: &mut NodeExecutor, + nid: NodeId, + parm: &str, + v_norm: f32, +) { let p = nid.inp_param(parm).unwrap(); matrix.set_param(p, SAtom::param(v_norm)); run_for_ms(ne, 15.0); } #[allow(unused)] -pub fn pset_d_wait(matrix: &mut Matrix, ne: &mut NodeExecutor, nid: NodeId, parm: &str, v_denorm: f32) { +pub fn pset_d_wait( + matrix: &mut Matrix, + ne: &mut NodeExecutor, + nid: NodeId, + parm: &str, + v_denorm: f32, +) { let p = nid.inp_param(parm).unwrap(); matrix.set_param(p, SAtom::param(p.norm(v_denorm))); run_for_ms(ne, 15.0); @@ -364,7 +443,13 @@ pub fn pset_mod(matrix: &mut Matrix, nid: NodeId, parm: &str, modamt: f32) { } #[allow(unused)] -pub fn pset_mod_wait(matrix: &mut Matrix, ne: &mut NodeExecutor, nid: NodeId, parm: &str, modamt: f32) { +pub fn pset_mod_wait( + matrix: &mut Matrix, + ne: &mut NodeExecutor, + nid: NodeId, + parm: &str, + modamt: f32, +) { let p = nid.inp_param(parm).unwrap(); matrix.set_param_modamt(p, Some(modamt)); run_for_ms(ne, 15.0); @@ -386,7 +471,10 @@ pub fn save_wav(name: &str, buf: &[f32]) { } } -pub fn run_no_input(node_exec: &mut hexodsp::nodes::NodeExecutor, seconds: f32) -> (Vec, Vec) { +pub fn run_no_input( + node_exec: &mut hexodsp::nodes::NodeExecutor, + seconds: f32, +) -> (Vec, Vec) { run_realtime_no_input(node_exec, seconds, false) } @@ -395,16 +483,20 @@ pub fn run_for_ms(node_exec: &mut hexodsp::nodes::NodeExecutor, ms: f32) -> (Vec run_realtime_no_input(node_exec, ms / 1000.0, false) } -pub fn run_realtime_no_input(node_exec: &mut hexodsp::nodes::NodeExecutor, seconds: f32, sleep_a_bit: bool) -> (Vec, Vec) { +pub fn run_realtime_no_input( + node_exec: &mut hexodsp::nodes::NodeExecutor, + seconds: f32, + sleep_a_bit: bool, +) -> (Vec, Vec) { node_exec.test_run(seconds, sleep_a_bit) } pub fn calc_rms_mimax_each_ms(buf: &[f32], ms: f32) -> Vec<(f32, f32, f32)> { let ms_samples = ms * SAMPLE_RATE / 1000.0; - let len_ms = ms_samples as usize; + let len_ms = ms_samples as usize; - let mut idx = 0; - let mut res = vec![]; + let mut idx = 0; + let mut res = vec![]; loop { if (idx + len_ms) > buf.len() { break; @@ -417,11 +509,8 @@ pub fn calc_rms_mimax_each_ms(buf: &[f32], ms: f32) -> Vec<(f32, f32, f32)> { min = s.min(min); } - let rms : f32 = - buf[idx..(idx + len_ms)] - .iter() - .map(|s: &f32| s * s).sum::() - / ms_samples; + let rms: f32 = + buf[idx..(idx + len_ms)].iter().map(|s: &f32| s * s).sum::() / ms_samples; res.push((rms, min, max)); @@ -434,8 +523,9 @@ pub fn calc_rms_mimax_each_ms(buf: &[f32], ms: f32) -> Vec<(f32, f32, f32)> { #[allow(dead_code)] pub fn run_and_undersample( node_exec: &mut hexodsp::nodes::NodeExecutor, - run_len_ms: f32, samples: usize) -> Vec -{ + run_len_ms: f32, + samples: usize, +) -> Vec { let (out_l, _out_r) = run_no_input(node_exec, run_len_ms / 1000.0); let sample_interval = out_l.len() / samples; @@ -452,8 +542,8 @@ pub fn run_and_undersample( #[allow(dead_code)] pub fn run_and_get_each_rms_mimax( node_exec: &mut hexodsp::nodes::NodeExecutor, - len_ms: f32) -> Vec<(f32, f32, f32)> -{ + len_ms: f32, +) -> Vec<(f32, f32, f32)> { let (out_l, _out_r) = run_no_input(node_exec, (len_ms * 3.0) / 1000.0); calc_rms_mimax_each_ms(&out_l[..], len_ms) } @@ -467,8 +557,8 @@ pub fn run_and_get_each_rms_mimax( pub fn run_and_get_rms_mimax( node_exec: &mut hexodsp::nodes::NodeExecutor, len_ms: f32, - sample_ms: f32) -> Vec<(f32, f32, f32)> -{ + sample_ms: f32, +) -> Vec<(f32, f32, f32)> { let (out_l, _out_r) = run_no_input(node_exec, len_ms / 1000.0); calc_rms_mimax_each_ms(&out_l[..], sample_ms) } @@ -476,8 +566,8 @@ pub fn run_and_get_rms_mimax( #[allow(dead_code)] pub fn run_and_get_first_rms_mimax( node_exec: &mut hexodsp::nodes::NodeExecutor, - len_ms: f32) -> (f32, f32, f32) -{ + len_ms: f32, +) -> (f32, f32, f32) { let (out_l, _out_r) = run_no_input(node_exec, (len_ms * 3.0) / 1000.0); let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], len_ms); rms_mimax[0] @@ -486,18 +576,15 @@ pub fn run_and_get_first_rms_mimax( #[allow(unused)] pub fn run_and_get_l_rms_mimax( node_exec: &mut hexodsp::nodes::NodeExecutor, - len_ms: f32) -> (f32, f32, f32) -{ + len_ms: f32, +) -> (f32, f32, f32) { let (out_l, _out_r) = run_no_input(node_exec, (len_ms * 3.0) / 1000.0); let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], len_ms); rms_mimax[1] } #[allow(unused)] -pub fn run_and_get_counted_freq( - node_exec: &mut hexodsp::nodes::NodeExecutor, ms: f32) - -> f64 -{ +pub fn run_and_get_counted_freq(node_exec: &mut hexodsp::nodes::NodeExecutor, ms: f32) -> f64 { let (out_l, _out_r) = // +0.1 here for some extra samples // this is just for tuning the frequency counter, so that it detects @@ -506,7 +593,7 @@ pub fn run_and_get_counted_freq( run_no_input(node_exec, (ms + 0.1) / 1000.0); let mut zero_trans = 0; - let mut last_val = 0.0; + let mut last_val = 0.0; for s in out_l.iter() { if last_val >= 0.0 && *s < 0.0 { @@ -531,12 +618,11 @@ pub fn run_and_get_counted_freq( pub fn run_and_get_fft4096( node_exec: &mut hexodsp::nodes::NodeExecutor, thres: u32, - offs_ms: f32) -> Vec<(u16, u32)> -{ + offs_ms: f32, +) -> Vec<(u16, u32)> { let min_samples_for_fft = 4096.0; - let offs_samples = (offs_ms * (SAMPLE_RATE / 1000.0)).ceil(); - let min_len_samples = - offs_samples + let offs_samples = (offs_ms * (SAMPLE_RATE / 1000.0)).ceil(); + let min_len_samples = offs_samples // 2.0 * for safety margin + 2.0 * min_samples_for_fft; let run_len_s = min_len_samples / SAMPLE_RATE; @@ -547,8 +633,8 @@ pub fn run_and_get_fft4096( #[allow(unused)] pub fn run_and_get_fft4096_2( node_exec: &mut hexodsp::nodes::NodeExecutor, - thres: u32) -> Vec<(u16, u32)> -{ + thres: u32, +) -> Vec<(u16, u32)> { let min_samples_for_fft = 4096.0; let min_len_samples = 2.0 * min_samples_for_fft; let run_len_s = min_len_samples / SAMPLE_RATE; @@ -560,9 +646,9 @@ pub fn run_and_get_fft4096_2( #[allow(unused)] pub fn run_fft_spectrum_each_47ms( node_exec: &mut hexodsp::nodes::NodeExecutor, - thres: u32, count: usize) - -> Vec> -{ + thres: u32, + count: usize, +) -> Vec> { let mut out = vec![]; for _ in 0..count { @@ -579,9 +665,9 @@ pub fn run_fft_spectrum_each_47ms( #[allow(unused)] pub fn calc_exp_avg_buckets4096(fft: &[(u16, u32)]) -> Vec<(u16, u32)> { - let mut avg = vec![]; - let mut last_n = [0; 256]; - let mut p = 0; + let mut avg = vec![]; + let mut last_n = [0; 256]; + let mut p = 0; let mut cur_len = 2; for (i, (fq, lvl)) in fft.iter().enumerate() { @@ -590,12 +676,8 @@ pub fn calc_exp_avg_buckets4096(fft: &[(u16, u32)]) -> Vec<(u16, u32)> { if p >= cur_len { avg.push(( *fq, - last_n - .iter() - .take(cur_len) - .map(|x| *x) - .sum::() - / (cur_len as u32))); + last_n.iter().take(cur_len).map(|x| *x).sum::() / (cur_len as u32), + )); p = 0; } @@ -616,12 +698,7 @@ pub fn avg_fft_freqs(round_by: f32, ranges: &[u16], fft: &[(u16, u32)]) -> Vec<( let mut from = 0; let mut out = vec![]; for rng in ranges.iter() { - out.push( - (from, - ((avg_fft_range(from, *rng, fft) - / round_by) - .floor() * round_by) - as u32)); + out.push((from, ((avg_fft_range(from, *rng, fft) / round_by).floor() * round_by) as u32)); from = *rng; } @@ -631,10 +708,10 @@ pub fn avg_fft_freqs(round_by: f32, ranges: &[u16], fft: &[(u16, u32)]) -> Vec<( #[allow(unused)] pub fn avg_fft_range(from_freq: u16, to_freq: u16, fft: &[(u16, u32)]) -> f32 { let mut count = 0; - let mut sum = 0; + let mut sum = 0; for (fq, lvl) in fft.iter() { if from_freq <= *fq && *fq < to_freq { - sum += *lvl; + sum += *lvl; count += 1; } } @@ -642,17 +719,15 @@ pub fn avg_fft_range(from_freq: u16, to_freq: u16, fft: &[(u16, u32)]) -> f32 { sum as f32 / count as f32 } - #[allow(unused)] pub fn run_and_get_fft512( node_exec: &mut hexodsp::nodes::NodeExecutor, thres: u32, - offs_ms: f32) -> Vec<(u16, u32)> -{ + offs_ms: f32, +) -> Vec<(u16, u32)> { let min_samples_for_fft = 512.0; - let offs_samples = (offs_ms * (SAMPLE_RATE / 1000.0)).ceil(); - let min_len_samples = - offs_samples + let offs_samples = (offs_ms * (SAMPLE_RATE / 1000.0)).ceil(); + let min_len_samples = offs_samples // 2.0 * for safety margin + 2.0 * min_samples_for_fft; let run_len_s = min_len_samples / SAMPLE_RATE; @@ -660,12 +735,11 @@ pub fn run_and_get_fft512( fft_thres_at_ms(&mut out_l[..], FFT::F512, thres, offs_ms) } - #[allow(unused)] pub fn run_and_get_fft4096_now( node_exec: &mut hexodsp::nodes::NodeExecutor, - thres: u32) -> Vec<(u16, u32)> -{ + thres: u32, +) -> Vec<(u16, u32)> { let min_samples_for_fft = 4096.0 * 1.5; // 1.5 for some extra margin let run_len_s = min_samples_for_fft / SAMPLE_RATE; let (mut out_l, _out_r) = run_no_input(node_exec, run_len_s); @@ -676,8 +750,8 @@ pub fn run_and_get_fft4096_now( #[allow(unused)] pub fn run_and_get_avg_fft4096_now( node_exec: &mut hexodsp::nodes::NodeExecutor, - thres: u32) -> Vec<(u16, u32)> -{ + thres: u32, +) -> Vec<(u16, u32)> { let min_samples_for_fft = 4096.0 * 1.5; // 1.5 for some extra margin let run_len_s = min_samples_for_fft / SAMPLE_RATE; @@ -717,17 +791,17 @@ pub enum FFT { impl FFT { pub fn size(&self) -> usize { match self { - FFT::F16 => 16, - FFT::F32 => 32, - FFT::F64 => 64, - FFT::F128 => 128, - FFT::F512 => 512, - FFT::F1024 => 1024, - FFT::F2048 => 2048, - FFT::F4096 => 4096, - FFT::F8192 => 8192, - FFT::F16384 => 16384, - FFT::F65535 => 65535, + FFT::F16 => 16, + FFT::F32 => 32, + FFT::F64 => 64, + FFT::F128 => 128, + FFT::F512 => 512, + FFT::F1024 => 1024, + FFT::F2048 => 2048, + FFT::F4096 => 4096, + FFT::F8192 => 8192, + FFT::F16384 => 16384, + FFT::F65535 => 65535, } } } @@ -755,30 +829,22 @@ pub fn fft(buf: &mut [f32], size: FFT, amp_thres: u32) -> Vec<(u16, u32)> { // Hann window: for (i, s) in buf[0..len].iter_mut().enumerate() { - let w = - 0.5 - * (1.0 - - ((2.0 * std::f32::consts::PI * i as f32) - / (len as f32 - 1.0)) - .cos()); + let w = 0.5 * (1.0 - ((2.0 * std::f32::consts::PI * i as f32) / (len as f32 - 1.0)).cos()); *s *= w; } - use rustfft::{FftPlanner, num_complex::Complex}; + use rustfft::{num_complex::Complex, FftPlanner}; let mut complex_buf = - buf.iter() - .map(|s| Complex { re: *s, im: 0.0 }) - .collect::>>(); + buf.iter().map(|s| Complex { re: *s, im: 0.0 }).collect::>>(); let mut p = FftPlanner::::new(); let fft = p.plan_fft_forward(len); fft.process(&mut complex_buf[0..len]); - let amplitudes: Vec<_> = - complex_buf[0..len].iter().map(|c| c.norm() as u32).collect(); -// println!("fft: {:?}", &complex_buf[0..len]); + let amplitudes: Vec<_> = complex_buf[0..len].iter().map(|c| c.norm() as u32).collect(); + // println!("fft: {:?}", &complex_buf[0..len]); for (i, amp) in amplitudes.iter().enumerate() { if *amp >= amp_thres { @@ -787,12 +853,10 @@ pub fn fft(buf: &mut [f32], size: FFT, amp_thres: u32) -> Vec<(u16, u32)> { // no freqency images above nyquist... continue; } -// println!("{:6.0} {}", freq, *amp); + // println!("{:6.0} {}", freq, *amp); res.push((freq.round() as u16, *amp)); } } res } - - diff --git a/tests/modamt.rs b/tests/modamt.rs index cca933c..943a2be 100644 --- a/tests/modamt.rs +++ b/tests/modamt.rs @@ -12,14 +12,11 @@ fn check_param_mod_amt_no_input() { let sin = NodeId::Sin(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); - matrix.set_param_modamt( - sin.inp_param("freq").unwrap(), Some(0.2)).unwrap(); + matrix.set_param_modamt(sin.inp_param("freq").unwrap(), Some(0.2)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.4999, -1.0, 1.0)); @@ -30,20 +27,19 @@ fn check_param_mod_amt_with_input() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let sin = NodeId::Sin(0); + let sin = NodeId::Sin(0); let sin2 = NodeId::Sin(1); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin2) - .out(None, None, sin2.out("sig"))); - matrix.place(0, 1, Cell::empty(sin) - .input(sin.inp("freq"), None, None) - .out(None, None, sin.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(sin2).out(None, None, sin2.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(sin).input(sin.inp("freq"), None, None).out(None, None, sin.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); - matrix.set_param_modamt( - sin.inp_param("freq").unwrap(), Some(0.2)).unwrap(); + matrix.set_param_modamt(sin.inp_param("freq").unwrap(), Some(0.2)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.48997, -1.0, 1.0)); @@ -57,13 +53,13 @@ fn check_param_mod_amt_set() { let tst = NodeId::Test(0); let amp = NodeId::Amp(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(tst) - .out(None, None, tst.out("sig"))); - matrix.place(0, 1, Cell::empty(amp) - .input(amp.inp("inp"), None, None) - .out(None, None, amp.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(tst).out(None, None, tst.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(amp).input(amp.inp("inp"), None, None).out(None, None, amp.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_n(&mut matrix, tst, "p", 1.0); matrix.sync().unwrap(); @@ -72,28 +68,24 @@ fn check_param_mod_amt_set() { assert_rmsmima!(rms, (1.0, 1.0, 1.0)); // Enable modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), Some(0.2)).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), Some(0.2)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.04, 0.2, 0.2)); // Change modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), Some(0.1)).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), Some(0.1)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.01, 0.1, 0.1)); // Remove modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), None).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), None).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (1.0, 1.0, 1.0)); } - #[test] fn check_param_mod_amt_set_bipol() { let (node_conf, mut node_exec) = new_node_engine(); @@ -102,13 +94,13 @@ fn check_param_mod_amt_set_bipol() { let tst = NodeId::Test(0); let amp = NodeId::Amp(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(tst) - .out(None, None, tst.out("sig"))); - matrix.place(0, 1, Cell::empty(amp) - .input(amp.inp("inp"), None, None) - .out(None, None, amp.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(tst).out(None, None, tst.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(amp).input(amp.inp("inp"), None, None).out(None, None, amp.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_n(&mut matrix, tst, "p", -1.0); matrix.sync().unwrap(); @@ -117,22 +109,19 @@ fn check_param_mod_amt_set_bipol() { assert_rmsmima!(rms, (1.0, -1.0, -1.0)); // Enable modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), Some(0.2)).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), Some(0.2)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.04, -0.2, -0.2)); // Change modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), Some(0.1)).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), Some(0.1)).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (0.01, -0.1, -0.1)); // Remove modulation - matrix.set_param_modamt( - amp.inp_param("inp").unwrap(), None).unwrap(); + matrix.set_param_modamt(amp.inp_param("inp").unwrap(), None).unwrap(); let rms = run_and_get_first_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rms, (1.0, -1.0, -1.0)); diff --git a/tests/node_ad.rs b/tests/node_ad.rs index 8b92d0d..53fc11d 100644 --- a/tests/node_ad.rs +++ b/tests/node_ad.rs @@ -10,27 +10,44 @@ fn check_node_ad_1() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(ad) - .out(None, None, ad.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let trig_p = ad.inp_param("trig").unwrap(); matrix.set_param(trig_p, SAtom::param(1.0)); let res = run_for_ms(&mut node_exec, 25.0); - assert_decimated_slope_feq!(res.0, 50, vec![ - 0.0, 0.0, 0.0, 0.0, 0.0, - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.007558584, 0.007558584, 0.007558584, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - -0.002267599, -0.0022675395, -0.002267599, -0.0022675395, - -0.0022675693, -0.0022675693, -0.0022675842, -0.0022675693, - 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_slope_feq!( + res.0, + 50, + vec![ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.007558584, + 0.007558584, + 0.007558584, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.0022675693, + -0.0022675693, + -0.0022675842, + -0.0022675693, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); matrix.set_param(trig_p, SAtom::param(0.0)); run_for_ms(&mut node_exec, 10.0); @@ -51,48 +68,92 @@ fn check_node_ad_retrig() { let mut matrix = Matrix::new(node_conf, 3, 3); let test = NodeId::Test(0); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("sig"))); - matrix.place(0, 1, Cell::empty(ad) - .input(ad.inp("trig"), None, None) - .out(None, None, ad.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(ad).input(ad.inp("trig"), None, None).out(None, None, ad.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let trig_p = test.inp_param("p").unwrap(); matrix.set_param(trig_p, SAtom::param(1.0)); let res = run_for_ms(&mut node_exec, 25.0); - assert_decimated_slope_feq!(res.0, 50, vec![ - // XXX: Direct trigger! - // Due to Test node outputting an unsmoothed value! - - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.007558584, 0.007558584, 0.007558584, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - -0.002267599, -0.0022675395, -0.002267599, -0.0022675395, - -0.0022675693, -0.0022675693, -0.0022675842, -0.0022675693, - -0.0022675726, - 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_slope_feq!( + res.0, + 50, + vec![ + // XXX: Direct trigger! + // Due to Test node outputting an unsmoothed value! + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.007558584, + 0.007558584, + 0.007558584, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.0022675693, + -0.0022675693, + -0.0022675842, + -0.0022675693, + -0.0022675726, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); matrix.set_param(trig_p, SAtom::param(0.0)); run_for_ms(&mut node_exec, 0.1); matrix.set_param(trig_p, SAtom::param(1.0)); let res = run_for_ms(&mut node_exec, 1.5); - assert_decimated_feq!(res.0, 2, vec![ - 0.0075585, 0.022675736, 0.03779289, 0.05291005, 0.068027206, 0.08314436, - 0.09826152, 0.113378674, 0.12849583, 0.143613, 0.15873015, - 0.1738473, 0.18896446, 0.20408161, 0.21919878, 0.23431593, - 0.24943309, 0.26455024, 0.2796674, 0.29478455, 0.3099017, - 0.32501888, 0.34013602, 0.3552532, 0.37037033, 0.3854875, - 0.40060467, 0.4157218, 0.43083897, 0.4459561, 0.46107328, - 0.47619045, 0.4913076 - ]); + assert_decimated_feq!( + res.0, + 2, + vec![ + 0.0075585, + 0.022675736, + 0.03779289, + 0.05291005, + 0.068027206, + 0.08314436, + 0.09826152, + 0.113378674, + 0.12849583, + 0.143613, + 0.15873015, + 0.1738473, + 0.18896446, + 0.20408161, + 0.21919878, + 0.23431593, + 0.24943309, + 0.26455024, + 0.2796674, + 0.29478455, + 0.3099017, + 0.32501888, + 0.34013602, + 0.3552532, + 0.37037033, + 0.3854875, + 0.40060467, + 0.4157218, + 0.43083897, + 0.4459561, + 0.46107328, + 0.47619045, + 0.4913076 + ] + ); // Reset trigger matrix.set_param(trig_p, SAtom::param(0.0)); @@ -118,21 +179,56 @@ fn check_node_ad_retrig() { // Retrigger right in the decay phase matrix.set_param(trig_p, SAtom::param(1.0)); let res = run_for_ms(&mut node_exec, 1.0); - assert_slope_feq!(res.0, vec![ - // Re-attack until we are at 1.0 again - 0.007558584, 0.007558584, 0.007558584, 0.0075585246, 0.007558584, - 0.007558584, 0.007558584, 0.007558584, 0.007558584, 0.007558584, - 0.0007558465, - // Restart decay after 1.0 was reached: - -0.002267599, -0.0022675395, -0.002267599, - -0.0022675395, -0.002267599, -0.0022675395, -0.002267599, - -0.002267599, -0.0022675395, -0.002267599, -0.0022675395, - -0.002267599, -0.0022675395, -0.002267599, -0.002267599, - -0.0022675395, -0.002267599, -0.0022675395, -0.002267599, - -0.0022675395, -0.002267599, -0.002267599, -0.0022675395, - -0.002267599, -0.0022675395, -0.002267599, -0.0022675395, - -0.002267599, -0.002267599, -0.0022675395, -0.002267599, -0.0022675395 - ]); + assert_slope_feq!( + res.0, + vec![ + // Re-attack until we are at 1.0 again + 0.007558584, + 0.007558584, + 0.007558584, + 0.0075585246, + 0.007558584, + 0.007558584, + 0.007558584, + 0.007558584, + 0.007558584, + 0.007558584, + 0.0007558465, + // Restart decay after 1.0 was reached: + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395 + ] + ); } #[test] @@ -141,29 +237,27 @@ fn check_node_ad_inp_sin() { let mut matrix = Matrix::new(node_conf, 3, 3); let sin = NodeId::Sin(0); - let ad = NodeId::Ad(0); + let ad = NodeId::Ad(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(ad) - .input(ad.inp("inp"), None, None) - .out(None, None, ad.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(ad).input(ad.inp("inp"), None, None).out(None, None, ad.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let trig_p = ad.inp_param("trig").unwrap(); - let atk_p = ad.inp_param("atk").unwrap(); - let dcy_p = ad.inp_param("dcy").unwrap(); + let atk_p = ad.inp_param("atk").unwrap(); + let dcy_p = ad.inp_param("dcy").unwrap(); // check if we have any frequencies resembling 440Hz matrix.set_param(trig_p, SAtom::param(1.0)); run_for_ms(&mut node_exec, 4.0); let fft = run_and_get_fft4096_now(&mut node_exec, 6); - assert_eq!(fft, vec![ - (409, 6), (420, 7), (431, 7), (441, 7), (452, 7), (463, 7), (474, 6) - ]); + assert_eq!(fft, vec![(409, 6), (420, 7), (431, 7), (441, 7), (452, 7), (463, 7), (474, 6)]); // Next we test if lengthening the attack has // effect on the captured frequencies. @@ -173,9 +267,7 @@ fn check_node_ad_inp_sin() { matrix.set_param(atk_p, SAtom::param(atk_p.norm(40.0))); matrix.set_param(trig_p, SAtom::param(1.0)); let fft = run_and_get_fft4096_now(&mut node_exec, 300); - assert_eq!(fft, vec![ - (431, 318), (441, 354) - ]); + assert_eq!(fft, vec![(431, 318), (441, 354)]); matrix.set_param(trig_p, SAtom::param(0.0)); run_for_ms(&mut node_exec, 8.0); @@ -203,12 +295,10 @@ fn check_node_ad_shp_log() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(ad) - .out(None, None, ad.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, ad, "trig", 1.0); @@ -216,15 +306,37 @@ fn check_node_ad_shp_log() { pset_n(&mut matrix, ad, "dshp", 1.0); let res = run_for_ms(&mut node_exec, 25.0); - assert_decimated_slope_feq!(res.0, 50, vec![ - 0.0, 0.0, 0.0, 0.0, 0.0, - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.008391023, 0.0045030117, 0.0026732683, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - -0.0005967021, -0.000685215, -0.0007713437, -0.0008877516, - -0.0010555983, -0.0013227463, -0.0018290281, -0.0032775402, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_slope_feq!( + res.0, + 50, + vec![ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.008391023, + 0.0045030117, + 0.0026732683, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + -0.0005967021, + -0.000685215, + -0.0007713437, + -0.0008877516, + -0.0010555983, + -0.0013227463, + -0.0018290281, + -0.0032775402, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); } #[test] @@ -232,12 +344,10 @@ fn check_node_ad_shp_exp() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(ad) - .out(None, None, ad.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, ad, "trig", 1.0); @@ -245,15 +355,37 @@ fn check_node_ad_shp_exp() { pset_n(&mut matrix, ad, "dshp", 0.0); let res = run_for_ms(&mut node_exec, 25.0); - assert_decimated_slope_feq!(res.0, 50, vec![ - 0.0, 0.0, 0.0, 0.0, 0.0, - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.0029080845, 0.007420212, 0.023684025, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - -0.006719053, -0.004248917, -0.0026466101, -0.0015081167, - -0.00075439364, -0.00030602422, -0.00008370355, -0.000008119583, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_slope_feq!( + res.0, + 50, + vec![ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.0029080845, + 0.007420212, + 0.023684025, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + -0.006719053, + -0.004248917, + -0.0026466101, + -0.0015081167, + -0.00075439364, + -0.00030602422, + -0.00008370355, + -0.000008119583, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); } #[test] @@ -261,61 +393,76 @@ fn check_node_ad_eoet() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(ad) - .out(None, None, ad.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - matrix.place(1, 0, Cell::empty(ad) - .out(None, None, ad.out("eoet"))); - matrix.place(1, 1, Cell::empty(out) - .input(out.inp("ch2"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); + matrix.place(1, 0, Cell::empty(ad).out(None, None, ad.out("eoet"))); + matrix.place(1, 1, Cell::empty(out).input(out.inp("ch2"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, ad, "trig", 1.0); let res = run_for_ms(&mut node_exec, 25.0); // just make sure we are running an env: - assert_decimated_slope_feq!(res.0, 50, vec![ - 0.0, 0.0, 0.0, 0.0, 0.0, - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.007558584, 0.007558584, 0.007558584, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - -0.002267599, -0.0022675395, -0.002267599, -0.0022675395, - -0.0022675693, -0.0022675693, -0.0022675842, -0.0022675693, - 0.0, // <- EOET expected here - 0.0, 0.0, 0.0 - ]); + assert_decimated_slope_feq!( + res.0, + 50, + vec![ + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.007558584, + 0.007558584, + 0.007558584, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + -0.002267599, + -0.0022675395, + -0.002267599, + -0.0022675395, + -0.0022675693, + -0.0022675693, + -0.0022675842, + -0.0022675693, + 0.0, // <- EOET expected here + 0.0, + 0.0, + 0.0 + ] + ); // check if trigger appears: - assert_decimated_feq!(res.1, 50, vec![ - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): - 0.0, 0.0, 0.0, - // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): - 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, - 1.0, 1.0, // <- End of envelope! - 0.0, 0.0, 0.0 - ]); + assert_decimated_feq!( + res.1, + 50, + vec![ + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + // 44.1 per ms, attack is default 3.0ms (roughly 3 * 50 samples): + 0.0, 0.0, 0.0, + // 44.1 per ms, decay is default 10.0ms (=> roughly 9 * 50 samples): + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, // <- End of envelope! + 0.0, 0.0, 0.0 + ] + ); } - #[test] fn check_node_ad_atk_dcy() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); let test = NodeId::Test(0); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("sig"))); - matrix.place(0, 1, Cell::empty(ad) - .input(ad.inp("trig"), None, None) - .out(None, None, ad.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(ad).input(ad.inp("trig"), None, None).out(None, None, ad.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_d(&mut matrix, ad, "atk", 20.0); @@ -328,18 +475,38 @@ fn check_node_ad_atk_dcy() { pset_d(&mut matrix, ad, "atk", 50.0); let res = run_for_ms(&mut node_exec, 20.0); - assert_decimated_slope_feq!(res.0, 40, vec![ - // Slope is getting less and less steep, as expected: - 0.0011277795, 0.0010179877, 0.00092345476, 0.00084143877, - 0.0007699132, 0.0007072091, 0.0006517768, 0.00060266256, - 0.00055885315, 0.0005196929, 0.00048446655, 0.00045353174, - // Slope does not change after the "atk" change has been smoothed - 0.00045353174, 0.00045353174, 0.00045353174, 0.00045347214, - 0.00045353174, 0.00045353174, 0.00045353174, 0.00045353174, - 0.00045347214, 0.00045353174, - // attack phase ended, and now we decay: - -0.002267599 - ]); + assert_decimated_slope_feq!( + res.0, + 40, + vec![ + // Slope is getting less and less steep, as expected: + 0.0011277795, + 0.0010179877, + 0.00092345476, + 0.00084143877, + 0.0007699132, + 0.0007072091, + 0.0006517768, + 0.00060266256, + 0.00055885315, + 0.0005196929, + 0.00048446655, + 0.00045353174, + // Slope does not change after the "atk" change has been smoothed + 0.00045353174, + 0.00045353174, + 0.00045353174, + 0.00045347214, + 0.00045353174, + 0.00045353174, + 0.00045353174, + 0.00045353174, + 0.00045347214, + 0.00045353174, + // attack phase ended, and now we decay: + -0.002267599 + ] + ); // check if decay stays stable: let res = run_for_ms(&mut node_exec, 2.0); @@ -347,16 +514,37 @@ fn check_node_ad_atk_dcy() { pset_d(&mut matrix, ad, "dcy", 200.0); let res = run_for_ms(&mut node_exec, 20.0); - assert_decimated_slope_feq!(res.0, 40, vec![ - // Slope is getting less and less steep, as expected: - -0.002197802, -0.0012806058, -0.00083732605, -0.0005899668, - -0.00043797493, -0.00033789873, -0.00026863813, -0.00021868944, - -0.00018143654, -0.00015294552, -0.00013071299, - // Slope does not change after the "dcy" change has been smoothed - -0.000113368034, -0.000113368034, -0.00011339784, -0.00011339784, - -0.000113368034, -0.000113368034, -0.00011339784, -0.000113368034, - -0.000113368034, -0.00011339784, -0.000113368034, -0.000113368034 - ]); + assert_decimated_slope_feq!( + res.0, + 40, + vec![ + // Slope is getting less and less steep, as expected: + -0.002197802, + -0.0012806058, + -0.00083732605, + -0.0005899668, + -0.00043797493, + -0.00033789873, + -0.00026863813, + -0.00021868944, + -0.00018143654, + -0.00015294552, + -0.00013071299, + // Slope does not change after the "dcy" change has been smoothed + -0.000113368034, + -0.000113368034, + -0.00011339784, + -0.00011339784, + -0.000113368034, + -0.000113368034, + -0.00011339784, + -0.000113368034, + -0.000113368034, + -0.00011339784, + -0.000113368034, + -0.000113368034 + ] + ); } #[test] @@ -364,31 +552,68 @@ fn check_node_ad_mult() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let ad = NodeId::Ad(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(ad) - .out(None, None, ad.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let ad = NodeId::Ad(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(ad).out(None, None, ad.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, ad, "trig", 1.0); pset_n(&mut matrix, ad, "mult", 2.0); let res = run_for_ms(&mut node_exec, 2000.0); - assert_decimated_slope_feq_fine!(res.0, 1800, vec![ - 0.0, - // looong attack: - 0.00007558, 0.00007558, 0.00007558, 0.00007558, - 0.00007558, 0.00007558, 0.00007558, - // looong decay: - -0.000022709, -0.000022709, -0.000022709, -0.000022709, -0.000022709, - -0.000022709, -0.000022709, -0.000022709, -0.000022709, -0.000022709, - -0.000022709, -0.000022709, -0.000022709, -0.000022709, -0.000022709, - -0.000022709, -0.000022709, -0.000022709, -0.000022709, -0.000022709, - -0.000022709, -0.000022709, -0.000022709, -0.000022709, - 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, - ]); + assert_decimated_slope_feq_fine!( + res.0, + 1800, + vec![ + 0.0, + // looong attack: + 0.00007558, + 0.00007558, + 0.00007558, + 0.00007558, + 0.00007558, + 0.00007558, + 0.00007558, + // looong decay: + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + -0.000022709, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ] + ); } - diff --git a/tests/node_allp.rs b/tests/node_allp.rs index 7db17b9..0680bce 100644 --- a/tests/node_allp.rs +++ b/tests/node_allp.rs @@ -11,21 +11,17 @@ fn check_node_allp() { let mut matrix = Matrix::new(node_conf, 4, 4); let test = NodeId::Test(0); - let ap = NodeId::AllP(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(0, 1, Cell::empty(ap) - .input(ap.inp("inp"), None, None) - .out(None, None, ap.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); - matrix.place(1, 0, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(1, 1, Cell::empty(out) - .input(out.inp("ch2"), None, None) - .out(None, None, None)); + let ap = NodeId::AllP(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place( + 0, + 1, + Cell::empty(ap).input(ap.inp("inp"), None, None).out(None, None, ap.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); + matrix.place(1, 0, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place(1, 1, Cell::empty(out).input(out.inp("ch2"), None, None).out(None, None, None)); pset_d(&mut matrix, ap, "time", 3.0); matrix.sync().unwrap(); @@ -55,9 +51,23 @@ fn check_node_allp() { // 2ms the previous 1.0 * 0.7 fed back into the filter, // including even more smearing due to cubic interpolation: - v.append(&mut vec![-0.0019286226, 0.04086761, -0.1813516, -0.35157663, -0.36315754, -0.35664573,]); + v.append(&mut vec![ + -0.0019286226, + 0.04086761, + -0.1813516, + -0.35157663, + -0.36315754, + -0.35664573, + ]); v.append(&mut vec![-0.357; (2.0 * 44.1_f32).floor() as usize - 5]); - v.append(&mut vec![-0.3550714, -0.39786762, -0.1756484, -0.005423375, 0.006157537, -0.00035427228]); + v.append(&mut vec![ + -0.3550714, + -0.39786762, + -0.1756484, + -0.005423375, + 0.006157537, + -0.00035427228, + ]); v.append(&mut vec![0.0; 10]); //d// println!("res={:?}", res.1); diff --git a/tests/node_bosc.rs b/tests/node_bosc.rs index be97623..7e8284d 100644 --- a/tests/node_bosc.rs +++ b/tests/node_bosc.rs @@ -10,13 +10,10 @@ fn check_node_bosc_1() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); - let bosc = NodeId::BOsc(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(bosc) - .out(None, None, bosc.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let bosc = NodeId::BOsc(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(bosc).out(None, None, bosc.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); pset_s(&mut matrix, bosc, "wtype", 0); // Sine pset_d(&mut matrix, bosc, "freq", 220.0); matrix.sync().unwrap(); @@ -57,7 +54,7 @@ fn check_node_bosc_1() { assert_eq!(fft[9].0, 1098); pset_s(&mut matrix, bosc, "wtype", 3); // Pulse - pset_n(&mut matrix, bosc, "pw", 0.0); // Pulse width no mod + pset_n(&mut matrix, bosc, "pw", 0.0); // Pulse width no mod run_for_ms(&mut node_exec, 10.0); let fft = run_and_get_fft4096_now(&mut node_exec, 120); assert_eq!(fft[0].0, 205); @@ -72,10 +69,10 @@ fn check_node_bosc_1() { assert_eq!(fft[9].0, 1540); assert_eq!(fft[10].0, 1981); - pset_n(&mut matrix, bosc, "pw", 1.0); // Pulse width mod + pset_n(&mut matrix, bosc, "pw", 1.0); // Pulse width mod run_for_ms(&mut node_exec, 10.0); let fft = run_and_get_fft4096_now(&mut node_exec, 120); - assert_eq!(fft[0].0, 0); // DC component from short pulse + assert_eq!(fft[0].0, 0); // DC component from short pulse assert_eq!(fft[1].0, 11); // but full amplitude! assert_eq!(fft[2].0, 215); assert_eq!(fft[3].0, 226); @@ -92,21 +89,21 @@ fn check_node_bosc_1() { assert_eq!(fft[14].0, 1324); assert_eq!(fft[15].0, 1540); -// Old test code that worked with the pulse width DC compensation: -// assert_eq!(fft[0].0, 215); -// assert_eq!(fft[1].0, 226); -// assert_eq!(fft[2].0, 431); -// assert_eq!(fft[3].0, 441); -// assert_eq!(fft[4].0, 452); -// assert_eq!(fft[5].0, 657); -// assert_eq!(fft[6].0, 668); -// assert_eq!(fft[7].0, 872); -// assert_eq!(fft[8].0, 883); -// assert_eq!(fft[9].0, 1098); -// assert_eq!(fft[10].0, 1109); -// assert_eq!(fft[11].0, 1314); -// assert_eq!(fft[12].0, 1324); -// assert_eq!(fft[13].0, 1540); + // Old test code that worked with the pulse width DC compensation: + // assert_eq!(fft[0].0, 215); + // assert_eq!(fft[1].0, 226); + // assert_eq!(fft[2].0, 431); + // assert_eq!(fft[3].0, 441); + // assert_eq!(fft[4].0, 452); + // assert_eq!(fft[5].0, 657); + // assert_eq!(fft[6].0, 668); + // assert_eq!(fft[7].0, 872); + // assert_eq!(fft[8].0, 883); + // assert_eq!(fft[9].0, 1098); + // assert_eq!(fft[10].0, 1109); + // assert_eq!(fft[11].0, 1314); + // assert_eq!(fft[12].0, 1324); + // assert_eq!(fft[13].0, 1540); } #[test] @@ -114,20 +111,17 @@ fn check_node_bosc_det() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); - let bosc = NodeId::BOsc(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(bosc) - .out(None, None, bosc.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let bosc = NodeId::BOsc(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(bosc).out(None, None, bosc.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); pset_s(&mut matrix, bosc, "wtype", 3); // Pulse - pset_n(&mut matrix, bosc, "pw", 0.0); // Pulse width no mod + pset_n(&mut matrix, bosc, "pw", 0.0); // Pulse width no mod pset_d(&mut matrix, bosc, "freq", 220.0); matrix.sync().unwrap(); let fft = run_and_get_fft4096_now(&mut node_exec, 120); -// println!("TO {:?}", fft); + // println!("TO {:?}", fft); assert_eq!(fft[0].0, 205); assert_eq!(fft[1].0, 215); assert_eq!(fft[2].0, 226); @@ -142,7 +136,7 @@ fn check_node_bosc_det() { pset_d_wait(&mut matrix, &mut node_exec, bosc, "freq", 1000.0); let fft = run_and_get_fft4096_now(&mut node_exec, 200); -// println!("TO {:?}", fft); + // println!("TO {:?}", fft); assert_eq!(fft[0].0, 991); assert_eq!(fft[1].0, 1001); assert_eq!(fft[2].0, 1012); @@ -152,7 +146,7 @@ fn check_node_bosc_det() { pset_n_wait(&mut matrix, &mut node_exec, bosc, "det", 0.1); let fft = run_and_get_fft4096_now(&mut node_exec, 200); -// println!("TO {:?}", fft); + // println!("TO {:?}", fft); assert_eq!(fft[0].0, 1992); assert_eq!(fft[1].0, 2003); assert_eq!(fft[2].0, 2013); diff --git a/tests/node_comb.rs b/tests/node_comb.rs index 2d394ca..b855609 100644 --- a/tests/node_comb.rs +++ b/tests/node_comb.rs @@ -7,46 +7,74 @@ fn check_node_comb_1() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise_1 = NodeId::Noise(0); - let comb_1 = NodeId::Comb(0); - let out_1 = NodeId::Out(0); - matrix.place(0, 1, - Cell::empty(noise_1) - .input(None, None, None) - .out(None, noise_1.out("sig"), None)); - matrix.place(1, 1, - Cell::empty(comb_1) - .input(None, comb_1.inp("inp"), None) - .out(None, comb_1.out("sig"), None)); - matrix.place(2, 2, - Cell::empty(out_1) - .input(None, out_1.inp("ch1"), out_1.inp("ch1")) - .out(None, None, None)); + let comb_1 = NodeId::Comb(0); + let out_1 = NodeId::Out(0); + matrix.place( + 0, + 1, + Cell::empty(noise_1).input(None, None, None).out(None, noise_1.out("sig"), None), + ); + matrix.place( + 1, + 1, + Cell::empty(comb_1).input(None, comb_1.inp("inp"), None).out(None, comb_1.out("sig"), None), + ); + matrix.place( + 2, + 2, + Cell::empty(out_1).input(None, out_1.inp("ch1"), out_1.inp("ch1")).out(None, None, None), + ); pset_n(&mut matrix, comb_1, "g", 0.950); pset_n(&mut matrix, comb_1, "time", 0.014); matrix.sync().unwrap(); let fft = run_and_get_avg_fft4096_now(&mut node_exec, 180); - assert_eq!(fft, vec![ - (0, 216), (11, 221), (22, 216), (3370, 206), (3381, 248), - (3391, 191), (6740, 185), (6751, 207), (6761, 195), (10131, 215), - (10142, 210), (10153, 213), (10164, 201), (20338, 187), (20349, 184) - ]); + assert_eq!( + fft, + vec![ + (0, 216), + (11, 221), + (22, 216), + (3370, 206), + (3381, 248), + (3391, 191), + (6740, 185), + (6751, 207), + (6761, 195), + (10131, 215), + (10142, 210), + (10153, 213), + (10164, 201), + (20338, 187), + (20349, 184) + ] + ); pset_n_wait(&mut matrix, &mut node_exec, comb_1, "time", 0.030); let fft = run_and_get_avg_fft4096_now(&mut node_exec, 180); - assert_eq!(fft, vec![ - (1001, 206), (2993, 196), (3004, 219), (3994, 197), - (6998, 211), (8000, 201) - ]); + assert_eq!( + fft, + vec![(1001, 206), (2993, 196), (3004, 219), (3994, 197), (6998, 211), (8000, 201)] + ); pset_n_wait(&mut matrix, &mut node_exec, comb_1, "g", 0.999); let fft = run_and_get_avg_fft4096_now(&mut node_exec, 1000); - assert_eq!(fft, vec![ - (0, 2003), (11, 1015), (991, 1078), (1001, 1837), (2003, 1059), - (2993, 1420), (3004, 1775), (3994, 1297), (4005, 1485) - ]); + assert_eq!( + fft, + vec![ + (0, 2003), + (11, 1015), + (991, 1078), + (1001, 1837), + (2003, 1059), + (2993, 1420), + (3004, 1775), + (3994, 1297), + (4005, 1485) + ] + ); } #[test] @@ -54,21 +82,20 @@ fn check_node_comb_time() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let test = NodeId::Test(0); - let comb_1 = NodeId::Comb(0); - let out_1 = NodeId::Out(0); - matrix.place(0, 1, - Cell::empty(test) - .input(None, None, None) - .out(None, test.out("tsig"), None)); - matrix.place(1, 1, - Cell::empty(comb_1) - .input(None, comb_1.inp("inp"), None) - .out(None, comb_1.out("sig"), None)); - matrix.place(2, 2, - Cell::empty(out_1) - .input(None, out_1.inp("ch1"), out_1.inp("ch1")) - .out(None, None, None)); + let test = NodeId::Test(0); + let comb_1 = NodeId::Comb(0); + let out_1 = NodeId::Out(0); + matrix.place(0, 1, Cell::empty(test).input(None, None, None).out(None, test.out("tsig"), None)); + matrix.place( + 1, + 1, + Cell::empty(comb_1).input(None, comb_1.inp("inp"), None).out(None, comb_1.out("sig"), None), + ); + matrix.place( + 2, + 2, + Cell::empty(out_1).input(None, out_1.inp("ch1"), out_1.inp("ch1")).out(None, None, None), + ); pset_n(&mut matrix, comb_1, "g", 0.75); pset_d(&mut matrix, comb_1, "time", 100.0); diff --git a/tests/node_cqnt.rs b/tests/node_cqnt.rs index 58ad85b..6cb6bef 100644 --- a/tests/node_cqnt.rs +++ b/tests/node_cqnt.rs @@ -7,17 +7,14 @@ use common::*; fn setup_cqnt(matrix: &mut Matrix, trig_out: bool) { let cqnt = NodeId::CQnt(0); - let out = NodeId::Out(0); + let out = NodeId::Out(0); if trig_out { - matrix.place(0, 0, Cell::empty(cqnt) - .out(None, None, cqnt.out("t"))); + matrix.place(0, 0, Cell::empty(cqnt).out(None, None, cqnt.out("t"))); } else { - matrix.place(0, 0, Cell::empty(cqnt) - .out(None, None, cqnt.out("sig"))); + matrix.place(0, 0, Cell::empty(cqnt).out(None, None, cqnt.out("sig"))); } - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(matrix, cqnt, "keys", 0); matrix.sync().unwrap(); @@ -39,20 +36,13 @@ fn check_node_cqnt_1() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - -0.075, -0.075, - -0.0666, -0.0666, - -0.0583, - -0.05, -0.05, - -0.04166, -0.04166, - -0.0333, - -0.0250, -0.0250, - -0.0166, -0.0166, - -0.0083, - 0.0, 0.0, - 0.0083, 0.0083, - 0.0166 - ]); + assert_vec_feq!( + v, + vec![ + -0.075, -0.075, -0.0666, -0.0666, -0.0583, -0.05, -0.05, -0.04166, -0.04166, -0.0333, + -0.0250, -0.0250, -0.0166, -0.0166, -0.0083, 0.0, 0.0, 0.0083, 0.0083, 0.0166 + ] + ); } #[test] @@ -73,16 +63,10 @@ fn check_node_cqnt_one_key() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - -0.05833, - -0.05833, - -0.05833, - -0.05833, - -0.05833, - -0.05833, - -0.05833, - -0.05833, - ]); + assert_vec_feq!( + v, + vec![-0.05833, -0.05833, -0.05833, -0.05833, -0.05833, -0.05833, -0.05833, -0.05833,] + ); } #[test] @@ -105,11 +89,10 @@ fn check_node_cqnt_one_key_oct() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - -0.1583, -0.1583, -0.1583, -0.1583, - -0.0583, -0.0583, -0.0583, - 0.0416, 0.0416, 0.0416 - ]); + assert_vec_feq!( + v, + vec![-0.1583, -0.1583, -0.1583, -0.1583, -0.0583, -0.0583, -0.0583, 0.0416, 0.0416, 0.0416] + ); } #[test] @@ -132,17 +115,13 @@ fn check_node_cqnt_min_max_oct() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - -0.1583, -0.1583, -0.1583, - -0.15, -0.15, - -0.1416, -0.1416, - -0.0583, -0.0583, - -0.05, -0.05, -0.05, - -0.0416, -0.0416, - 0.0416, 0.0416, - 0.0499, 0.0499, - 0.0583, 0.0583 - ]); + assert_vec_feq!( + v, + vec![ + -0.1583, -0.1583, -0.1583, -0.15, -0.15, -0.1416, -0.1416, -0.0583, -0.0583, -0.05, + -0.05, -0.05, -0.0416, -0.0416, 0.0416, 0.0416, 0.0499, 0.0499, 0.0583, 0.0583 + ] + ); } #[test] @@ -167,9 +146,18 @@ fn check_node_cqnt_min_max_oct_trig_out() { let idxs_big = collect_signal_changes(&v[..], 50); - assert_eq!(idxs_big, vec![ - (0, 100), (5341, 100), (10240, 100), - (15140, 100), (20041, 100), (24941, 100), - (29841, 100), (34740, 100), (39640, 100) - ]); + assert_eq!( + idxs_big, + vec![ + (0, 100), + (5341, 100), + (10240, 100), + (15140, 100), + (20041, 100), + (24941, 100), + (29841, 100), + (34740, 100), + (39640, 100) + ] + ); } diff --git a/tests/node_delay.rs b/tests/node_delay.rs index f051cbb..9bbe833 100644 --- a/tests/node_delay.rs +++ b/tests/node_delay.rs @@ -10,21 +10,22 @@ fn check_node_delay_1() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); - let ad = NodeId::Ad(0); - let sin = NodeId::Sin(0); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(ad) - .input(ad.inp("inp"), None, None) - .out(None, None, ad.out("sig"))); - matrix.place(0, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, None) - .out(None, None, dly.out("sig"))); - matrix.place(0, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let ad = NodeId::Ad(0); + let sin = NodeId::Sin(0); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(ad).input(ad.inp("inp"), None, None).out(None, None, ad.out("sig")), + ); + matrix.place( + 0, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, None).out(None, None, dly.out("sig")), + ); + matrix.place(0, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); matrix.sync().unwrap(); pset_d(&mut matrix, ad, "atk", 50.0); @@ -33,22 +34,67 @@ fn check_node_delay_1() { let res = run_for_ms(&mut node_exec, 500.0); // 441 decimation => 10ms resolution - assert_decimated_feq!(res.0, 441, vec![ - // smoothing time: - 0.0, - // burst of sine for 100ms: - 0.04741215, -0.17181772, 0.2669262, -0.22376089, 0.000030220208, - 0.24654882, -0.30384964, 0.20876096, -0.070250794, 0.0000024548233, - // 150ms silence: - 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, - // delayed burst of sine for 100ms: - 0.047408286, -0.17181452, 0.2669317, -0.22377986, 0.000059626997, - 0.24652793, -0.30384338, 0.2087649, -0.070256576, 0.000003647874, - // silence afterwards: - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_feq!( + res.0, + 441, + vec![ + // smoothing time: + 0.0, + // burst of sine for 100ms: + 0.04741215, + -0.17181772, + 0.2669262, + -0.22376089, + 0.000030220208, + 0.24654882, + -0.30384964, + 0.20876096, + -0.070250794, + 0.0000024548233, + // 150ms silence: + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + // delayed burst of sine for 100ms: + 0.047408286, + -0.17181452, + 0.2669317, + -0.22377986, + 0.000059626997, + 0.24652793, + -0.30384338, + 0.2087649, + -0.070256576, + 0.000003647874, + // silence afterwards: + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); } #[test] @@ -56,30 +102,28 @@ fn check_node_delay_2() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(0, 2, Cell::empty(dly) - .out(None, None, dly.out("sig"))); - matrix.place(0, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(0, 2, Cell::empty(dly).out(None, None, dly.out("sig"))); + matrix.place(0, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); matrix.sync().unwrap(); pset_d(&mut matrix, dly, "time", 31.0); - pset_d(&mut matrix, dly, "inp", 1.0); + pset_d(&mut matrix, dly, "inp", 1.0); let res = run_for_ms(&mut node_exec, 150.0); // 441 decimation => 10ms resolution - assert_decimated_feq!(res.0, 441, vec![ - // 10ms smoothing time for "inp" - 0.001133, - // 30ms delaytime just mixing the 0.5: - 0.5, 0.5, 0.5, - // the delayed smoothing ramp (10ms): - 0.951113, - // the delay + input signal: - 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 - ]); + assert_decimated_feq!( + res.0, + 441, + vec![ + // 10ms smoothing time for "inp" + 0.001133, // 30ms delaytime just mixing the 0.5: + 0.5, 0.5, 0.5, // the delayed smoothing ramp (10ms): + 0.951113, // the delay + input signal: + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ] + ); } #[test] @@ -87,32 +131,34 @@ fn check_node_delay_time_mod() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); - let sin = NodeId::Sin(1); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(1, 1, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(1, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, dly.inp("time")) - .out(None, None, dly.out("sig"))); - matrix.place(1, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let sin = NodeId::Sin(1); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(1, 1, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 1, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, dly.inp("time")).out( + None, + None, + dly.out("sig"), + ), + ); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); matrix.sync().unwrap(); - pset_n(&mut matrix, dly, "mix", 1.0); + pset_n(&mut matrix, dly, "mix", 1.0); pset_d(&mut matrix, dly, "time", 100.0); // skip delay time: run_for_ms(&mut node_exec, 100.0); let fft = run_and_get_fft4096_now(&mut node_exec, 600); - assert_eq!(fft[0], (431, 614)); + assert_eq!(fft[0], (431, 614)); assert_eq!(fft[1], (441, 1012)); let sin2 = NodeId::Sin(0); - matrix.place(0, 3, Cell::empty(sin2) - .out(sin2.out("sig"), None, None)); + matrix.place(0, 3, Cell::empty(sin2).out(sin2.out("sig"), None, None)); matrix.sync().unwrap(); pset_d(&mut matrix, sin2, "freq", 0.5); @@ -126,8 +172,8 @@ fn check_node_delay_time_mod() { let fft = run_and_get_fft4096_now(&mut node_exec, 110); // Expect a sine sweep over a // range of low frequencies: - assert_eq!(fft[0], (86, 111)); - assert_eq!(fft[5], (237, 114)); + assert_eq!(fft[0], (86, 111)); + assert_eq!(fft[5], (237, 114)); assert_eq!(fft[10], (517, 110)); // Sweep upwards: @@ -143,39 +189,40 @@ fn check_node_delay_time_mod() { assert_eq!(fft[4], (6471, 407)); } - #[test] fn check_node_delay_trig() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); let test = NodeId::Test(0); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(1, 1, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(0, 3, Cell::empty(test) - .out(test.out("sig"), None, None)); - matrix.place(1, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, dly.inp("trig")) - .out(None, None, dly.out("sig"))); - matrix.place(1, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(1, 1, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place(0, 3, Cell::empty(test).out(test.out("sig"), None, None)); + matrix.place( + 1, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, dly.inp("trig")).out( + None, + None, + dly.out("sig"), + ), + ); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); matrix.sync().unwrap(); - pset_n(&mut matrix, dly, "mix", 1.0); + pset_n(&mut matrix, dly, "mix", 1.0); pset_n(&mut matrix, dly, "mode", 1.0); pset_d(&mut matrix, dly, "time", 5.0); // Trigger the delay 2 times, with an interval of 20ms: - pset_n(&mut matrix, test, "p", 1.0); + pset_n(&mut matrix, test, "p", 1.0); run_for_ms(&mut node_exec, 10.0); - pset_n(&mut matrix, test, "p", 0.0); + pset_n(&mut matrix, test, "p", 0.0); run_for_ms(&mut node_exec, 10.0); - pset_n(&mut matrix, test, "p", 1.0); + pset_n(&mut matrix, test, "p", 1.0); run_for_ms(&mut node_exec, 10.0); - pset_n(&mut matrix, test, "p", 0.0); + pset_n(&mut matrix, test, "p", 0.0); run_for_ms(&mut node_exec, 10.0); // Now the delay should have a 20ms delay time. @@ -197,27 +244,25 @@ fn check_node_delay_trig() { assert_eq!(idx_first_non_zero, (44100 * 20) / 1000); } - #[test] fn check_node_delay_fb() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 4, 4); let test = NodeId::Test(0); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(1, 1, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(1, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, None) - .out(None, None, dly.out("sig"))); - matrix.place(1, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(1, 1, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place( + 1, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, None).out(None, None, dly.out("sig")), + ); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); - pset_n(&mut matrix, dly, "mix", 1.0); + pset_n(&mut matrix, dly, "mix", 1.0); pset_d(&mut matrix, dly, "time", 5.0); - pset_n(&mut matrix, dly, "fb", 0.5); + pset_n(&mut matrix, dly, "fb", 0.5); matrix.sync().unwrap(); @@ -238,20 +283,19 @@ fn check_node_delay_fb_neg() { let mut matrix = Matrix::new(node_conf, 4, 4); let test = NodeId::Test(0); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(1, 1, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(1, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, None) - .out(None, None, dly.out("sig"))); - matrix.place(1, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(1, 1, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place( + 1, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, None).out(None, None, dly.out("sig")), + ); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); - pset_n(&mut matrix, dly, "mix", 1.0); + pset_n(&mut matrix, dly, "mix", 1.0); pset_d(&mut matrix, dly, "time", 10.0); - pset_n(&mut matrix, dly, "fb", -1.0); + pset_n(&mut matrix, dly, "fb", -1.0); matrix.sync().unwrap(); @@ -271,20 +315,19 @@ fn check_node_delay_fb_pos() { let mut matrix = Matrix::new(node_conf, 4, 4); let test = NodeId::Test(0); - let dly = NodeId::Delay(0); - let out = NodeId::Out(0); - matrix.place(1, 1, Cell::empty(test) - .out(None, None, test.out("tsig"))); - matrix.place(1, 2, Cell::empty(dly) - .input(dly.inp("inp"), None, None) - .out(None, None, dly.out("sig"))); - matrix.place(1, 3, Cell::empty(out) - .input(out.inp("ch1"), None, None) - .out(None, None, None)); + let dly = NodeId::Delay(0); + let out = NodeId::Out(0); + matrix.place(1, 1, Cell::empty(test).out(None, None, test.out("tsig"))); + matrix.place( + 1, + 2, + Cell::empty(dly).input(dly.inp("inp"), None, None).out(None, None, dly.out("sig")), + ); + matrix.place(1, 3, Cell::empty(out).input(out.inp("ch1"), None, None).out(None, None, None)); - pset_n(&mut matrix, dly, "mix", 1.0); + pset_n(&mut matrix, dly, "mix", 1.0); pset_d(&mut matrix, dly, "time", 10.0); - pset_n(&mut matrix, dly, "fb", 1.0); + pset_n(&mut matrix, dly, "fb", 1.0); matrix.sync().unwrap(); @@ -295,15 +338,18 @@ fn check_node_delay_fb_pos() { let idxs_big = collect_signal_changes(&res.0[..], 70); - assert_eq!(idxs_big, vec![ - (441, 100), - (441 + 1 * 441, 100), - (441 + 2 * 441, 100), - (441 + 3 * 441, 100), - (441 + 4 * 441, 100), - (441 + 5 * 441, 100), - (441 + 6 * 441, 100), - (441 + 7 * 441, 100), - (441 + 8 * 441, 100), - ]); + assert_eq!( + idxs_big, + vec![ + (441, 100), + (441 + 1 * 441, 100), + (441 + 2 * 441, 100), + (441 + 3 * 441, 100), + (441 + 4 * 441, 100), + (441 + 5 * 441, 100), + (441 + 6 * 441, 100), + (441 + 7 * 441, 100), + (441 + 8 * 441, 100), + ] + ); } diff --git a/tests/node_map.rs b/tests/node_map.rs index 5471187..3326106 100644 --- a/tests/node_map.rs +++ b/tests/node_map.rs @@ -10,14 +10,12 @@ fn check_node_map() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let map = NodeId::Map(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(map) - .out(None, None, map.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - pset_n(&mut matrix, map, "inp", 0.5); - pset_n(&mut matrix, map, "atv", 0.5); // => 0.25 + let map = NodeId::Map(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(map).out(None, None, map.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); + pset_n(&mut matrix, map, "inp", 0.5); + pset_n(&mut matrix, map, "atv", 0.5); // => 0.25 pset_n(&mut matrix, map, "offs", 0.1); // => 0.35 pset_n(&mut matrix, map, "imin", 0.0); @@ -36,14 +34,12 @@ fn check_node_map_clip() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let map = NodeId::Map(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(map) - .out(None, None, map.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - pset_n(&mut matrix, map, "inp", 0.5); - pset_n(&mut matrix, map, "atv", 0.5); // => 0.25 + let map = NodeId::Map(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(map).out(None, None, map.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); + pset_n(&mut matrix, map, "inp", 0.5); + pset_n(&mut matrix, map, "atv", 0.5); // => 0.25 pset_n(&mut matrix, map, "offs", 0.80); // => 1.05 pset_n(&mut matrix, map, "imin", 0.0); diff --git a/tests/node_mix3.rs b/tests/node_mix3.rs index 43b7def..80f7c01 100644 --- a/tests/node_mix3.rs +++ b/tests/node_mix3.rs @@ -10,31 +10,40 @@ fn check_node_mix3_1() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 5, 5); - let amp_1 = NodeId::Amp(0); - let amp_3 = NodeId::Amp(2); - let amp_2 = NodeId::Amp(1); - let mix3_1 = NodeId::Mix3(0); - let out_1 = NodeId::Out(0); - matrix.place(1, 1, - Cell::empty(amp_1) - .input(None, None, None) - .out(None, amp_1.out("sig"), None)); - matrix.place(1, 2, - Cell::empty(amp_3) - .input(None, None, None) - .out(amp_3.out("sig"), None, None)); - matrix.place(2, 1, - Cell::empty(amp_2) - .input(None, None, None) - .out(None, None, amp_2.out("sig"))); - matrix.place(2, 2, - Cell::empty(mix3_1) - .input(mix3_1.inp("ch1"), mix3_1.inp("ch2"), mix3_1.inp("ch3")) - .out(None, mix3_1.out("sig"), None)); - matrix.place(3, 2, - Cell::empty(out_1) - .input(None, out_1.inp("ch1"), None) - .out(None, None, None)); + let amp_1 = NodeId::Amp(0); + let amp_3 = NodeId::Amp(2); + let amp_2 = NodeId::Amp(1); + let mix3_1 = NodeId::Mix3(0); + let out_1 = NodeId::Out(0); + matrix.place( + 1, + 1, + Cell::empty(amp_1).input(None, None, None).out(None, amp_1.out("sig"), None), + ); + matrix.place( + 1, + 2, + Cell::empty(amp_3).input(None, None, None).out(amp_3.out("sig"), None, None), + ); + matrix.place( + 2, + 1, + Cell::empty(amp_2).input(None, None, None).out(None, None, amp_2.out("sig")), + ); + matrix.place( + 2, + 2, + Cell::empty(mix3_1).input(mix3_1.inp("ch1"), mix3_1.inp("ch2"), mix3_1.inp("ch3")).out( + None, + mix3_1.out("sig"), + None, + ), + ); + matrix.place( + 3, + 2, + Cell::empty(out_1).input(None, out_1.inp("ch1"), None).out(None, None, None), + ); pset_d(&mut matrix, amp_1, "inp", 0.200); pset_d(&mut matrix, mix3_1, "gain2", 0.2); // 0.04 diff --git a/tests/node_mux9.rs b/tests/node_mux9.rs index 00486cf..c1d87a3 100644 --- a/tests/node_mux9.rs +++ b/tests/node_mux9.rs @@ -6,16 +6,16 @@ mod common; use common::*; fn setup_mux9_slct(matrix: &mut Matrix) { - let amp = NodeId::Amp(0); + let amp = NodeId::Amp(0); let mux9 = NodeId::Mux9(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(amp) - .out(None, None, amp.out("sig"))); - matrix.place(0, 1, Cell::empty(mux9) - .input(mux9.inp("slct"), None, None) - .out(None, None, mux9.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(amp).out(None, None, amp.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(mux9).input(mux9.inp("slct"), None, None).out(None, None, mux9.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); for i in 1..=9 { pset_n(matrix, mux9, &format!("in_{}", i), 0.01 * (i as f32)); } @@ -25,11 +25,9 @@ fn setup_mux9_slct(matrix: &mut Matrix) { fn setup_mux9(matrix: &mut Matrix) { let mux9 = NodeId::Mux9(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(mux9) - .out(None, None, mux9.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(mux9).out(None, None, mux9.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); for i in 1..=9 { pset_n(matrix, mux9, &format!("in_{}", i), 0.01 * (i as f32)); } @@ -120,7 +118,7 @@ fn check_node_mux9_slct() { setup_mux9_slct(matrix); let mux9 = NodeId::Mux9(0); - let amp = NodeId::Amp(0); + let amp = NodeId::Amp(0); pset_s(matrix, mux9, "in_cnt", 5.into()); pset_n_wait(matrix, node_exec, amp, "inp", 0.9); @@ -134,36 +132,16 @@ fn check_node_mux9_slct() { pset_n(matrix, amp, "inp", 1.0); let (out, _) = run_for_ms(node_exec, 20.0); - assert_decimated_feq!(out, 90, vec![ - 0.01, - 0.02, - 0.03, - 0.04, - 0.05, - 0.06, - 0.06, - 0.06, - 0.06, - ]); + assert_decimated_feq!(out, 90, vec![0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.06, 0.06, 0.06,]); pset_s(matrix, mux9, "in_cnt", 8.into()); pset_n_wait(matrix, node_exec, amp, "inp", 0.0); pset_n(matrix, amp, "inp", 1.0); let (out, _) = run_for_ms(node_exec, 20.0); - assert_decimated_feq!(out, 50, vec![ - 0.01, - 0.02, - 0.03, - 0.04, - 0.05, - 0.06, - 0.07, - 0.08, - 0.09, - 0.09, - 0.09, - 0.09, - 0.09, - ]); + assert_decimated_feq!( + out, + 50, + vec![0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.09, 0.09, 0.09, 0.09,] + ); } diff --git a/tests/node_noise.rs b/tests/node_noise.rs index 7b4bffe..3add3ee 100644 --- a/tests/node_noise.rs +++ b/tests/node_noise.rs @@ -11,18 +11,16 @@ fn check_node_noise_bipolar() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_n(&mut matrix, noise, "atv", 1.0); matrix.sync().unwrap(); let (out_l, _) = run_for_ms(&mut node_exec, 25.0); - assert_float_eq!(out_l[0], 0.1545); - assert_float_eq!(out_l[10], 0.5924); + assert_float_eq!(out_l[0], 0.1545); + assert_float_eq!(out_l[10], 0.5924); assert_float_eq!(out_l[11], -0.3643); let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 10.0); @@ -37,26 +35,22 @@ fn check_node_noise_seed() { let noise = NodeId::Noise(0); let nois2 = NodeId::Noise(1); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - matrix.place(1, 0, Cell::empty(nois2) - .out(None, None, nois2.out("sig"))); - matrix.place(1, 1, Cell::empty(out) - .input(out.inp("ch2"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); + matrix.place(1, 0, Cell::empty(nois2).out(None, None, nois2.out("sig"))); + matrix.place(1, 1, Cell::empty(out).input(out.inp("ch2"), None, None)); pset_n(&mut matrix, noise, "atv", 1.0); pset_n(&mut matrix, nois2, "atv", 1.0); matrix.sync().unwrap(); let (out_l, out_r) = run_for_ms(&mut node_exec, 25.0); - assert_float_eq!(out_l[0], 0.1545); - assert_float_eq!(out_l[10], 0.5924); + assert_float_eq!(out_l[0], 0.1545); + assert_float_eq!(out_l[10], 0.5924); - assert_float_eq!(out_r[0], -0.2156); - assert_float_eq!(out_r[10], 0.9441); + assert_float_eq!(out_r[0], -0.2156); + assert_float_eq!(out_r[10], 0.9441); } #[test] @@ -65,38 +59,33 @@ fn check_node_noise_unipolar() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, noise, "mode", 1); pset_n(&mut matrix, noise, "atv", 1.0); matrix.sync().unwrap(); let (out_l, _) = run_for_ms(&mut node_exec, 25.0); - assert_float_eq!(out_l[0], 0.5772); - assert_float_eq!(out_l[10], 0.7962); - assert_float_eq!(out_l[11], 0.3178); + assert_float_eq!(out_l[0], 0.5772); + assert_float_eq!(out_l[10], 0.7962); + assert_float_eq!(out_l[11], 0.3178); let rms_mimax = calc_rms_mimax_each_ms(&out_l[..], 10.0); assert_rmsmima!(rms_mimax[0], (0.3214, 0.002, 0.9985)); assert_rmsmima!(rms_mimax[1], (0.3373, 0.0001, 0.9996)); } - #[test] fn check_node_noise_atv_offs() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, noise, "mode", 1); pset_n(&mut matrix, noise, "atv", 0.5); pset_n(&mut matrix, noise, "offs", 0.3); @@ -114,11 +103,9 @@ fn check_node_noise_atv_offs_2() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, noise, "mode", 1); pset_n(&mut matrix, noise, "atv", -0.5); pset_n(&mut matrix, noise, "offs", -0.4); @@ -136,11 +123,9 @@ fn check_node_noise_atv_offs_bipolar() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, noise, "mode", 0); pset_n(&mut matrix, noise, "atv", 0.5); pset_n(&mut matrix, noise, "offs", 0.4); @@ -158,11 +143,9 @@ fn check_node_noise_fft() { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, noise, "mode", 0); pset_n(&mut matrix, noise, "atv", 1.0); pset_n(&mut matrix, noise, "offs", 0.0); @@ -171,8 +154,6 @@ fn check_node_noise_fft() { let fft = run_and_get_fft4096(&mut node_exec, 50, 1000.0); assert!(fft.len() > 15); for (_freq, lvl) in fft { - assert_float_eq!( - (((lvl as i64 - 57) as f32).abs() / 10.0).floor(), - 0.0); + assert_float_eq!((((lvl as i64 - 57) as f32).abs() / 10.0).floor(), 0.0); } } diff --git a/tests/node_pverb.rs b/tests/node_pverb.rs index dc3ec91..529582b 100644 --- a/tests/node_pverb.rs +++ b/tests/node_pverb.rs @@ -6,33 +6,41 @@ mod common; use common::*; fn trig_env(matrix: &mut Matrix, node_exec: &mut NodeExecutor) { - let ad_1 = NodeId::Ad(0); + let ad_1 = NodeId::Ad(0); pset_n(matrix, ad_1, "trig", 1.0); run_for_ms(node_exec, 7.0); // Wait for attack start. pset_n(matrix, ad_1, "trig", 0.0); } fn setup_pverb(matrix: &mut Matrix) { - let sin_1 = NodeId::Sin(0); - let ad_1 = NodeId::Ad(0); + let sin_1 = NodeId::Sin(0); + let ad_1 = NodeId::Ad(0); let pverb_1 = NodeId::PVerb(0); - let out_1 = NodeId::Out(0); - matrix.place(0, 0, - Cell::empty(sin_1) - .input(None, None, None) - .out(None, None, sin_1.out("sig"))); - matrix.place(0, 1, - Cell::empty(ad_1) - .input(ad_1.inp("inp"), None, None) - .out(ad_1.out("sig"), None, None)); - matrix.place(1, 0, - Cell::empty(pverb_1) - .input(None, None, pverb_1.inp("in_l")) - .out(None, None, pverb_1.out("sig_l"))); - matrix.place(1, 1, - Cell::empty(out_1) - .input(out_1.inp("ch1"), None, None) - .out(None, None, None)); + let out_1 = NodeId::Out(0); + matrix.place( + 0, + 0, + Cell::empty(sin_1).input(None, None, None).out(None, None, sin_1.out("sig")), + ); + matrix.place( + 0, + 1, + Cell::empty(ad_1).input(ad_1.inp("inp"), None, None).out(ad_1.out("sig"), None, None), + ); + matrix.place( + 1, + 0, + Cell::empty(pverb_1).input(None, None, pverb_1.inp("in_l")).out( + None, + None, + pverb_1.out("sig_l"), + ), + ); + matrix.place( + 1, + 1, + Cell::empty(out_1).input(out_1.inp("ch1"), None, None).out(None, None, None), + ); pset_n(matrix, ad_1, "ashp", 0.870); pset_n(matrix, ad_1, "dshp", 0.870); pset_d(matrix, ad_1, "atk", 6.0); @@ -51,19 +59,19 @@ fn check_node_pverb_dcy_1() { setup_pverb(matrix); matrix.sync().unwrap(); -// pset_n(&mut matrix, pverb_1, "dcy", 0.675); -// pset_n(&mut matrix, pverb_1, "dif", 1.000); -// pset_n(&mut matrix, pverb_1, "ihpf", -1.543); -// pset_n(&mut matrix, pverb_1, "ilpf", 0.565); -// pset_n(&mut matrix, pverb_1, "in_l", 0.000); -// pset_n(&mut matrix, pverb_1, "in_r", 0.000); -// pset_n(&mut matrix, pverb_1, "mdepth", 0.200); -// pset_n(&mut matrix, pverb_1, "mshp", 0.500); -// pset_n(&mut matrix, pverb_1, "mspeed", 0.075); -// pset_n(&mut matrix, pverb_1, "predly", 0.000); -// pset_n(&mut matrix, pverb_1, "rhpf", -1.543); -// pset_n(&mut matrix, pverb_1, "rlpf", 0.565); -// pset_n(&mut matrix, pverb_1, "size", 0.330); + // pset_n(&mut matrix, pverb_1, "dcy", 0.675); + // pset_n(&mut matrix, pverb_1, "dif", 1.000); + // pset_n(&mut matrix, pverb_1, "ihpf", -1.543); + // pset_n(&mut matrix, pverb_1, "ilpf", 0.565); + // pset_n(&mut matrix, pverb_1, "in_l", 0.000); + // pset_n(&mut matrix, pverb_1, "in_r", 0.000); + // pset_n(&mut matrix, pverb_1, "mdepth", 0.200); + // pset_n(&mut matrix, pverb_1, "mshp", 0.500); + // pset_n(&mut matrix, pverb_1, "mspeed", 0.075); + // pset_n(&mut matrix, pverb_1, "predly", 0.000); + // pset_n(&mut matrix, pverb_1, "rhpf", -1.543); + // pset_n(&mut matrix, pverb_1, "rlpf", 0.565); + // pset_n(&mut matrix, pverb_1, "size", 0.330); // Dry mix: pset_n_wait(matrix, node_exec, pverb_1, "mix", 0.000); @@ -75,7 +83,7 @@ fn check_node_pverb_dcy_1() { // We see the sine decaying with the AD envelope: assert_eq!(spec[0], vec![(388, 42), (431, 120), (474, 82), (517, 6)]); assert_eq!(spec[1], vec![(388, 32), (431, 92), (474, 63), (517, 5)]); - assert_eq!(spec[2], vec![(345, 5), (388, 12), (431, 16), (474, 14), (517, 8)]); + assert_eq!(spec[2], vec![(345, 5), (388, 12), (431, 16), (474, 14), (517, 8)]); assert_eq!(spec[3], vec![]); // Wet mix & clear out the reset in the tank: @@ -138,15 +146,11 @@ fn check_node_pverb_dcy_2() { let rms_spec = run_and_get_rms_mimax(node_exec, 500.0, 100.0); //d// dump_table!(rms_spec); - assert_vec_feq!(rms_spec.iter().map(|rms| rms.0).collect::>(), - // Decay over 500 ms: - vec![ - 0.2108, - 0.5744, - 0.0881, - 0.0021, - 0.0006 - ]); + assert_vec_feq!( + rms_spec.iter().map(|rms| rms.0).collect::>(), + // Decay over 500 ms: + vec![0.2108, 0.5744, 0.0881, 0.0021, 0.0006] + ); } #[test] @@ -167,14 +171,9 @@ fn check_node_pverb_dcy_3() { //d// dump_table!(rms_spec); assert_vec_feq!( rms_spec.iter().map(|rms| rms.0).collect::>(), - // Decay over 5000 ms: - vec![ - 0.6254, - 0.2868, - 0.0633, - 0.0385, - 0.0186, - ]); + // Decay over 5000 ms: + vec![0.6254, 0.2868, 0.0633, 0.0385, 0.0186,] + ); } #[test] @@ -192,22 +191,17 @@ fn check_node_pverb_dcy_4() { let rms_spec = run_and_get_rms_mimax(node_exec, 5000.0, 1000.0); //d// dump_table!(rms_spec); - assert_vec_feq!(rms_spec.iter().map(|rms| rms.0).collect::>(), - // Decay over 10000 ms: - vec![ - 0.1313, - 0.0995, - 0.0932, - 0.0507, - 0.0456, - ]); + assert_vec_feq!( + rms_spec.iter().map(|rms| rms.0).collect::>(), + // Decay over 10000 ms: + vec![0.1313, 0.0995, 0.0932, 0.0507, 0.0456,] + ); } - #[test] fn check_node_pverb_dif_on() { init_test!(matrix, node_exec, 3); - let ad_1 = NodeId::Ad(0); + let ad_1 = NodeId::Ad(0); let pverb_1 = NodeId::PVerb(0); setup_pverb(matrix); @@ -256,7 +250,7 @@ fn check_node_pverb_dif_on() { #[test] fn check_node_pverb_dif_off() { init_test!(matrix, node_exec, 3); - let ad_1 = NodeId::Ad(0); + let ad_1 = NodeId::Ad(0); let pverb_1 = NodeId::PVerb(0); setup_pverb(matrix); @@ -299,7 +293,10 @@ fn check_node_pverb_dif_off() { // We expect a diffuse but defined response: assert_eq!(spec[0], vec![]); - assert_eq!(spec[1], vec![(301, 4), (345, 6), (388, 84), (431, 206), (474, 152), (517, 23), (560, 7)]); + assert_eq!( + spec[1], + vec![(301, 4), (345, 6), (388, 84), (431, 206), (474, 152), (517, 23), (560, 7)] + ); assert_eq!(spec[2], vec![]); assert_eq!(spec[3], vec![(345, 7), (388, 79), (431, 198), (474, 134), (517, 15), (560, 4)]); assert_eq!(spec[7], vec![]); @@ -310,11 +307,10 @@ fn check_node_pverb_dif_off() { assert_eq!(spec[19], vec![]); } - #[test] fn check_node_pverb_dif_off_predly() { init_test!(matrix, node_exec, 3); - let ad_1 = NodeId::Ad(0); + let ad_1 = NodeId::Ad(0); let pverb_1 = NodeId::PVerb(0); setup_pverb(matrix); @@ -337,7 +333,6 @@ fn check_node_pverb_dif_off_predly() { let spec = run_fft_spectrum_each_47ms(node_exec, 4, 20); dump_table!(spec); - // 0 [] // 1 [] // 2 [] @@ -354,5 +349,18 @@ fn check_node_pverb_dif_off_predly() { assert_eq!(spec[1], vec![]); // ~50ms assert_eq!(spec[2], vec![]); // ~50ms assert_eq!(spec[3], vec![]); // ~50ms - assert_eq!(spec[4], vec![(215, 5), (301, 11), (345, 15), (388, 46), (431, 105), (474, 86), (517, 18), (560, 14), (603, 5)]); + assert_eq!( + spec[4], + vec![ + (215, 5), + (301, 11), + (345, 15), + (388, 46), + (431, 105), + (474, 86), + (517, 18), + (560, 14), + (603, 5) + ] + ); } diff --git a/tests/node_quant.rs b/tests/node_quant.rs index f68817b..6e65081 100644 --- a/tests/node_quant.rs +++ b/tests/node_quant.rs @@ -6,18 +6,15 @@ mod common; use common::*; fn setup_quant(matrix: &mut Matrix, trig_out: bool) { - let qnt = NodeId::Quant(0); - let out = NodeId::Out(0); + let qnt = NodeId::Quant(0); + let out = NodeId::Out(0); if trig_out { - matrix.place(0, 0, Cell::empty(qnt) - .out(None, None, qnt.out("t"))); + matrix.place(0, 0, Cell::empty(qnt).out(None, None, qnt.out("t"))); } else { - matrix.place(0, 0, Cell::empty(qnt) - .out(None, None, qnt.out("sig"))); + matrix.place(0, 0, Cell::empty(qnt).out(None, None, qnt.out("sig"))); } - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(matrix, qnt, "keys", 0); matrix.sync().unwrap(); @@ -39,21 +36,13 @@ fn check_node_quant_1() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - 0.0, - 0.0083, 0.0083, - 0.0166, - 0.0250, 0.0250, - 0.0333, 0.0333, - 0.0416, - 0.0500, 0.0500, - 0.0583, 0.0583, - 0.0666, - 0.075, 0.075, - 0.0833, 0.0833, - 0.0916, - 0.1 - ]); + assert_vec_feq!( + v, + vec![ + 0.0, 0.0083, 0.0083, 0.0166, 0.0250, 0.0250, 0.0333, 0.0333, 0.0416, 0.0500, 0.0500, + 0.0583, 0.0583, 0.0666, 0.075, 0.075, 0.0833, 0.0833, 0.0916, 0.1 + ] + ); } #[test] @@ -72,22 +61,32 @@ fn check_node_quant_2() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - 0.0, - 0.0, - -1.0 * 0.0083, - -1.0 * 0.0166, -1.0 * 0.0166, - -1.0 * 0.0250, -1.0 * 0.0250, - -1.0 * 0.0333, - -1.0 * 0.0416, -1.0 * 0.0416, - -1.0 * 0.0500, -1.0 * 0.0500, - -1.0 * 0.0583, - -1.0 * 0.0666, -1.0 * 0.0666, - -1.0 * 0.075, -1.0 * 0.075, - -1.0 * 0.0833, - -1.0 * 0.0916, -1.0 * 0.0916, - -1.0 * 0.1 - ]); + assert_vec_feq!( + v, + vec![ + 0.0, + 0.0, + -1.0 * 0.0083, + -1.0 * 0.0166, + -1.0 * 0.0166, + -1.0 * 0.0250, + -1.0 * 0.0250, + -1.0 * 0.0333, + -1.0 * 0.0416, + -1.0 * 0.0416, + -1.0 * 0.0500, + -1.0 * 0.0500, + -1.0 * 0.0583, + -1.0 * 0.0666, + -1.0 * 0.0666, + -1.0 * 0.075, + -1.0 * 0.075, + -1.0 * 0.0833, + -1.0 * 0.0916, + -1.0 * 0.0916, + -1.0 * 0.1 + ] + ); } #[test] @@ -108,21 +107,31 @@ fn check_node_quant_oct() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - 0.1 + 0.0, - 0.1 + 0.0083, 0.1 + 0.0083, - 0.1 + 0.0166, - 0.1 + 0.0250, 0.1 + 0.0250, - 0.1 + 0.0333, 0.1 + 0.0333, - 0.1 + 0.0416, - 0.1 + 0.0500, 0.1 + 0.0500, - 0.1 + 0.0583, 0.1 + 0.0583, - 0.1 + 0.0666, - 0.1 + 0.075, 0.1 + 0.075, - 0.1 + 0.0833, 0.1 + 0.0833, - 0.1 + 0.0916, - 0.1 + 0.1 - ]); + assert_vec_feq!( + v, + vec![ + 0.1 + 0.0, + 0.1 + 0.0083, + 0.1 + 0.0083, + 0.1 + 0.0166, + 0.1 + 0.0250, + 0.1 + 0.0250, + 0.1 + 0.0333, + 0.1 + 0.0333, + 0.1 + 0.0416, + 0.1 + 0.0500, + 0.1 + 0.0500, + 0.1 + 0.0583, + 0.1 + 0.0583, + 0.1 + 0.0666, + 0.1 + 0.075, + 0.1 + 0.075, + 0.1 + 0.0833, + 0.1 + 0.0833, + 0.1 + 0.0916, + 0.1 + 0.1 + ] + ); } #[test] @@ -143,14 +152,13 @@ fn check_node_quant_keys() { v.push(res.0[0]); } - assert_vec_feq!(v, vec![ - -0.0416, - 0.0416, 0.0416, 0.0416, 0.0416, - 0.0416, 0.0416, 0.0416, 0.0416, - 0.0500, 0.0500, - 0.0583, 0.0583, 0.0583, 0.0583, - 0.0583, 0.0583, 0.0583, 0.0583, 0.0583 - ]); + assert_vec_feq!( + v, + vec![ + -0.0416, 0.0416, 0.0416, 0.0416, 0.0416, 0.0416, 0.0416, 0.0416, 0.0416, 0.0500, + 0.0500, 0.0583, 0.0583, 0.0583, 0.0583, 0.0583, 0.0583, 0.0583, 0.0583, 0.0583 + ] + ); } #[test] @@ -173,7 +181,5 @@ fn check_node_quant_trig_out() { let idxs_big = collect_signal_changes(&v[..], 50); - assert_eq!(idxs_big, vec![ - (0, 100), (1359, 100), (19734, 100), (23409, 100) - ]); + assert_eq!(idxs_big, vec![(0, 100), (1359, 100), (19734, 100), (23409, 100)]); } diff --git a/tests/node_rndwk.rs b/tests/node_rndwk.rs index 49e3368..a1ccc06 100644 --- a/tests/node_rndwk.rs +++ b/tests/node_rndwk.rs @@ -12,24 +12,38 @@ fn check_node_rndwk_def_trig() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); pset_n(&mut matrix, rwk, "trig", 1.0); run_for_ms(&mut node_exec, 4.2); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 20.0); - assert_decimated_feq!(out_l, 40, vec![ - 0.0, // start value - // slew ramp: - 0.001814059, 0.0139077855, 0.026001511, 0.03809524, 0.050188966, - 0.062282693, 0.07437642, 0.08647014, 0.09856387, 0.110657595, - // end value: - 0.11378352, 0.11378352, 0.11378352, 0.11378352, 0.11378352, - ]); + assert_decimated_feq!( + out_l, + 40, + vec![ + 0.0, // start value + // slew ramp: + 0.001814059, + 0.0139077855, + 0.026001511, + 0.03809524, + 0.050188966, + 0.062282693, + 0.07437642, + 0.08647014, + 0.09856387, + 0.110657595, + // end value: + 0.11378352, + 0.11378352, + 0.11378352, + 0.11378352, + 0.11378352, + ] + ); pset_n(&mut matrix, rwk, "trig", 0.0); pset_d_wait(&mut matrix, &mut node_exec, rwk, "slew", 10.0); @@ -37,11 +51,15 @@ fn check_node_rndwk_def_trig() { run_for_ms(&mut node_exec, 4.0); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 20.0); - assert_decimated_feq!(out_l, 15, vec![ - 0.11378352, 0.11378352, 0.11378352, // last value - 0.11831867, 0.15233228, 0.18634588, 0.22035949, 0.2543731, - 0.26017055, 0.26017055, // end value - ]); + assert_decimated_feq!( + out_l, + 15, + vec![ + 0.11378352, 0.11378352, 0.11378352, // last value + 0.11831867, 0.15233228, 0.18634588, 0.22035949, 0.2543731, 0.26017055, + 0.26017055, // end value + ] + ); } #[test] @@ -51,10 +69,8 @@ fn check_node_rndwk_step() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, rwk, "step", 1.0); matrix.sync().unwrap(); @@ -62,16 +78,28 @@ fn check_node_rndwk_step() { run_for_ms(&mut node_exec, 4.51); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 50.0); - assert_decimated_feq!(out_l, 200, vec![ - 0.0, // start value - // slew ramp: - 0.054119427, 0.11458806, 0.1750567, 0.23552532, 0.29599395, - 0.3564626, 0.4169312, 0.47739986, 0.5378685, - // end value - // which is 5.0 * 0.11378352 - // (the first random sample, see previous test) - 0.56891763, 0.56891763, - ]); + assert_decimated_feq!( + out_l, + 200, + vec![ + 0.0, // start value + // slew ramp: + 0.054119427, + 0.11458806, + 0.1750567, + 0.23552532, + 0.29599395, + 0.3564626, + 0.4169312, + 0.47739986, + 0.5378685, + // end value + // which is 5.0 * 0.11378352 + // (the first random sample, see previous test) + 0.56891763, + 0.56891763, + ] + ); } #[test] @@ -81,10 +109,8 @@ fn check_node_rndwk_offs() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, rwk, "offs", 0.3); pset_d(&mut matrix, rwk, "slew", 10.0); matrix.sync().unwrap(); @@ -93,17 +119,23 @@ fn check_node_rndwk_offs() { run_for_ms(&mut node_exec, 4.51); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 20.0); - assert_decimated_feq!(out_l, 60, vec![ - 0.0, // start value - // slew ramp: - 0.088435374, 0.2244898, 0.3605442, - // end value - // which is 0.11378352 + 0.3 - // (the first random sample, see previous test) - 0.41378355, - 0.41378355, - 0.41378355, - ]); + assert_decimated_feq!( + out_l, + 60, + vec![ + 0.0, // start value + // slew ramp: + 0.088435374, + 0.2244898, + 0.3605442, + // end value + // which is 0.11378352 + 0.3 + // (the first random sample, see previous test) + 0.41378355, + 0.41378355, + 0.41378355, + ] + ); } #[test] @@ -113,10 +145,8 @@ fn check_node_rndwk_offs_neg() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, rwk, "offs", -0.2); matrix.sync().unwrap(); @@ -124,14 +154,23 @@ fn check_node_rndwk_offs_neg() { run_for_ms(&mut node_exec, 4.51); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 20.0); - assert_decimated_feq!(out_l, 60, vec![ - 0.0, // start value - // slew ramp: - 0.011791383, 0.029931974, 0.04807256, 0.06621315, 0.084353745, - // end value - // which is (0.11378352 - 0.2).abs() - 0.08621648, 0.08621648, - ]); + assert_decimated_feq!( + out_l, + 60, + vec![ + 0.0, // start value + // slew ramp: + 0.011791383, + 0.029931974, + 0.04807256, + 0.06621315, + 0.084353745, + // end value + // which is (0.11378352 - 0.2).abs() + 0.08621648, + 0.08621648, + ] + ); } #[test] @@ -141,10 +180,8 @@ fn check_node_rndwk_max() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, rwk, "step", 1.0); // => first sample is 0.56891763 pset_d(&mut matrix, rwk, "max", 0.5); matrix.sync().unwrap(); @@ -153,15 +190,27 @@ fn check_node_rndwk_max() { run_for_ms(&mut node_exec, 4.51); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 50.0); - assert_decimated_feq!(out_l, 200, vec![ - 0.0, // start value - // slew ramp: - 0.054119427, 0.11458806, 0.1750567, 0.23552532, 0.29599395, - 0.3564626, 0.4169312, - // end value - // which is (0.5 - 0.43108237) == 0.06891763 - 0.43108237, 0.43108237, 0.43108237, 0.43108237 - ]); + assert_decimated_feq!( + out_l, + 200, + vec![ + 0.0, // start value + // slew ramp: + 0.054119427, + 0.11458806, + 0.1750567, + 0.23552532, + 0.29599395, + 0.3564626, + 0.4169312, + // end value + // which is (0.5 - 0.43108237) == 0.06891763 + 0.43108237, + 0.43108237, + 0.43108237, + 0.43108237 + ] + ); } #[test] @@ -171,10 +220,8 @@ fn check_node_rndwk_min() { let rwk = NodeId::RndWk(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(rwk) - .out(None, None, rwk.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(rwk).out(None, None, rwk.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, rwk, "step", 1.0); // => first sample is 0.56891763 pset_d(&mut matrix, rwk, "max", 1.0); pset_d(&mut matrix, rwk, "min", 0.75); // wraps first sample to 0.93108237 @@ -184,12 +231,15 @@ fn check_node_rndwk_min() { run_for_ms(&mut node_exec, 4.51); // wait for trigger... let (out_l, _) = run_for_ms(&mut node_exec, 100.0); // 75ms slew time default - assert_decimated_feq!(out_l, 400, vec![ - 0.0, // start value - // slew ramp: - 0.11458806, 0.23552532, 0.3564626, 0.47739986, - 0.5983371, 0.7192744, 0.84021163, - // end value - 0.93108237, 0.93108237, 0.93108237, 0.93108237, 0.93108237, 0.93108237, - ]); + assert_decimated_feq!( + out_l, + 400, + vec![ + 0.0, // start value + // slew ramp: + 0.11458806, 0.23552532, 0.3564626, 0.47739986, 0.5983371, 0.7192744, 0.84021163, + // end value + 0.93108237, 0.93108237, 0.93108237, 0.93108237, 0.93108237, 0.93108237, + ] + ); } diff --git a/tests/node_sampl.rs b/tests/node_sampl.rs index b9e7413..02ae956 100644 --- a/tests/node_sampl.rs +++ b/tests/node_sampl.rs @@ -11,15 +11,13 @@ fn check_node_sampl_1() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let freq_p = smpl.inp_param("freq").unwrap(); + let freq_p = smpl.inp_param("freq").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav")); let (rms, min, max) = run_and_get_l_rms_mimax(&mut node_exec, 50.0); @@ -63,11 +61,9 @@ fn check_node_sampl_long_freq() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); @@ -89,15 +85,13 @@ fn check_node_sampl_detune() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let det_p = smpl.inp_param("det").unwrap(); + let det_p = smpl.inp_param("det").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav")); run_no_input(&mut node_exec, 0.05); @@ -147,16 +141,14 @@ fn check_node_sampl_reverse() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let freq_p = smpl.inp_param("freq").unwrap(); - let dir_p = smpl.inp_param("dir").unwrap(); + let freq_p = smpl.inp_param("freq").unwrap(); + let dir_p = smpl.inp_param("dir").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav")); matrix.set_param(dir_p, SAtom::setting(1)); @@ -202,26 +194,22 @@ fn check_node_sampl_reload() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav")); - hexodsp::save_patch_to_file(&mut matrix, "check_matrix_serialize.hxy") - .unwrap(); + hexodsp::save_patch_to_file(&mut matrix, "check_matrix_serialize.hxy").unwrap(); } { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - hexodsp::load_patch_from_file( - &mut matrix, "check_matrix_serialize.hxy").unwrap(); + hexodsp::load_patch_from_file(&mut matrix, "check_matrix_serialize.hxy").unwrap(); let rmsmima = run_and_get_l_rms_mimax(&mut node_exec, 50.0); assert_rmsmima!(rmsmima, (0.5004, -0.9997, 0.9997)); @@ -237,20 +225,16 @@ fn check_node_sampl_load_err() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_NOSIN.wav")); let (rms, min, max) = run_and_get_l_rms_mimax(&mut node_exec, 50.0); - assert_rmsmima!( - (rms, min, max), - (0.0, 0.0, 0.0)); + assert_rmsmima!((rms, min, max), (0.0, 0.0, 0.0)); let err = matrix.pop_error(); assert_eq!(err.unwrap(), "Sample Loading Error\nCouldn't load sample 'tests/sample_NOSIN.wav':\nLoadError(IoError(Os { code: 2, kind: NotFound, message: \"No such file or directory\" }))"); @@ -262,16 +246,14 @@ fn check_node_sampl_trigger() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav")); matrix.set_param(pmode_p, SAtom::setting(1)); @@ -290,22 +272,17 @@ fn create_1sec_const(s: f32) -> SAtom { let mut test_sample_ramp = vec![s; (SAMPLE_RATE_US) + 1]; test_sample_ramp[0] = SAMPLE_RATE; - SAtom::audio( - "1second_const.wav", - std::sync::Arc::new(test_sample_ramp)) + SAtom::audio("1second_const.wav", std::sync::Arc::new(test_sample_ramp)) } fn create_1sec_ramp() -> SAtom { let mut test_sample_ramp = vec![0.0; (SAMPLE_RATE_US) + 1]; test_sample_ramp[0] = SAMPLE_RATE; for i in 0..(test_sample_ramp.len() - 1) { - test_sample_ramp[i + 1] = - (i as f32) / ((test_sample_ramp.len() - 2) as f32) + test_sample_ramp[i + 1] = (i as f32) / ((test_sample_ramp.len() - 2) as f32) } - SAtom::audio( - "1second_ramp.wav", - std::sync::Arc::new(test_sample_ramp)) + SAtom::audio("1second_ramp.wav", std::sync::Arc::new(test_sample_ramp)) } #[test] @@ -314,16 +291,14 @@ fn check_node_sampl_trigger_reset_phase() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); // One Shot Mode @@ -336,8 +311,8 @@ fn check_node_sampl_trigger_reset_phase() { matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 100.0); - assert_minmax_of_rms!(rmsvec[0], (0.0, 0.09499)); - assert_minmax_of_rms!(rmsvec[2], (0.1950, 0.2949)); + assert_minmax_of_rms!(rmsvec[0], (0.0, 0.09499)); + assert_minmax_of_rms!(rmsvec[2], (0.1950, 0.2949)); // lower trigger level, for retrigger later matrix.set_param(trig_p, (0.0).into()); @@ -364,16 +339,14 @@ fn check_node_sampl_trigger_loop_reset_phase() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); // Loop mode: @@ -386,8 +359,8 @@ fn check_node_sampl_trigger_loop_reset_phase() { matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 100.0); - assert_minmax_of_rms!(rmsvec[0], (0.0, 0.3050)); - assert_minmax_of_rms!(rmsvec[2], (0.1950, 0.2949)); + assert_minmax_of_rms!(rmsvec[0], (0.0, 0.3050)); + assert_minmax_of_rms!(rmsvec[2], (0.1950, 0.2949)); } #[test] @@ -396,33 +369,31 @@ fn check_node_sampl_offs_len() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); - let offs_p = smpl.inp_param("offs").unwrap(); - let len_p = smpl.inp_param("len").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); + let offs_p = smpl.inp_param("offs").unwrap(); + let len_p = smpl.inp_param("len").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); matrix.set_param(pmode_p, SAtom::setting(0)); // Select part 0.5 to 0.75 of the sample: matrix.set_param(offs_p, SAtom::param(0.5)); - matrix.set_param(len_p, SAtom::param(0.25)); + matrix.set_param(len_p, SAtom::param(0.25)); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 50.0); assert_minmax_of_rms!(rmsvec[0], (0.001113, 0.54999)); - assert_minmax_of_rms!(rmsvec[2], (0.6, 0.65)); + assert_minmax_of_rms!(rmsvec[2], (0.6, 0.65)); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 50.0); assert_minmax_of_rms!(rmsvec[0], (0.65, 0.6999)); assert_minmax_of_rms!(rmsvec[1], (0.70, 0.75)); - assert_minmax_of_rms!(rmsvec[2], (0.5, 0.55)); + assert_minmax_of_rms!(rmsvec[2], (0.5, 0.55)); } #[test] @@ -431,25 +402,23 @@ fn check_node_sampl_offs_len_zero_crash() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); - let offs_p = smpl.inp_param("offs").unwrap(); - let len_p = smpl.inp_param("len").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); + let offs_p = smpl.inp_param("offs").unwrap(); + let len_p = smpl.inp_param("len").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); matrix.set_param(pmode_p, SAtom::setting(0)); // Select part 0.5 to 0.75 of the sample: matrix.set_param(offs_p, SAtom::param(1.0)); - matrix.set_param(len_p, SAtom::param(0.0)); + matrix.set_param(len_p, SAtom::param(0.0)); matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 50.0); @@ -457,7 +426,7 @@ fn check_node_sampl_offs_len_zero_crash() { // Select part 0.5 to 0.75 of the sample: matrix.set_param(offs_p, SAtom::param(0.9)); - matrix.set_param(len_p, SAtom::param(0.0)); + matrix.set_param(len_p, SAtom::param(0.0)); matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 50.0); @@ -465,7 +434,7 @@ fn check_node_sampl_offs_len_zero_crash() { // Select part 0.5 to 0.75 of the sample: matrix.set_param(offs_p, SAtom::param(1.0)); - matrix.set_param(len_p, SAtom::param(0.0)); + matrix.set_param(len_p, SAtom::param(0.0)); matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 50.0); @@ -477,20 +446,20 @@ fn check_node_sampl_offs_modulated_crash() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); - let sin = NodeId::Sin(0); + let sin = NodeId::Sin(0); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(sin) - .out(None, None, sin.out("sig"))); - matrix.place(0, 1, Cell::empty(smpl) - .input(smpl.inp("offs"), None, None) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(sin).out(None, None, sin.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(smpl).input(smpl.inp("offs"), None, None).out(None, None, smpl.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); matrix.set_param(pmode_p, SAtom::setting(0)); @@ -505,24 +474,22 @@ fn check_node_sampl_declick() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); let dclick_p = smpl.inp_param("dclick").unwrap(); - let dcms_p = smpl.inp_param("dcms").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); + let dcms_p = smpl.inp_param("dcms").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); matrix.set_param(sample_p, create_1sec_const(1.0)); // One Shot Mode - matrix.set_param(pmode_p, SAtom::setting(1)); + matrix.set_param(pmode_p, SAtom::setting(1)); matrix.set_param(dclick_p, SAtom::setting(0)); - matrix.set_param(dcms_p, SAtom::param(dcms_p.norm(3.14))); + matrix.set_param(dcms_p, SAtom::param(dcms_p.norm(3.14))); matrix.set_param(trig_p, (1.0).into()); let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 3.0); @@ -542,56 +509,86 @@ fn check_node_sampl_declick() { // now the de-click should run: let rmsvec = run_and_get_each_rms_mimax(&mut node_exec, 1.0); - assert_minmax_of_rms!(rmsvec[0], (0.0, 0.3105)); + assert_minmax_of_rms!(rmsvec[0], (0.0, 0.3105)); assert_minmax_of_rms!(rmsvec[1], (0.3177, 0.6282)); assert_minmax_of_rms!(rmsvec[2], (0.6354, 0.9460)); } - #[test] fn check_node_sampl_declick_offs_len() { let (node_conf, mut node_exec) = new_node_engine(); let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); let dclick_p = smpl.inp_param("dclick").unwrap(); - let dcms_p = smpl.inp_param("dcms").unwrap(); - let trig_p = smpl.inp_param("trig").unwrap(); - let offs_p = smpl.inp_param("offs").unwrap(); - let len_p = smpl.inp_param("len").unwrap(); + let dcms_p = smpl.inp_param("dcms").unwrap(); + let trig_p = smpl.inp_param("trig").unwrap(); + let offs_p = smpl.inp_param("offs").unwrap(); + let len_p = smpl.inp_param("len").unwrap(); matrix.set_param(sample_p, create_1sec_const(1.0)); // One Shot Mode - matrix.set_param(pmode_p, SAtom::setting(1)); + matrix.set_param(pmode_p, SAtom::setting(1)); matrix.set_param(dclick_p, SAtom::setting(1)); - matrix.set_param(dcms_p, SAtom::param(dcms_p.norm(3.14))); + matrix.set_param(dcms_p, SAtom::param(dcms_p.norm(3.14))); matrix.set_param(trig_p, (1.0).into()); matrix.set_param(offs_p, SAtom::param(0.9)); - matrix.set_param(len_p, SAtom::param(0.008)); + matrix.set_param(len_p, SAtom::param(0.008)); // trigger: run_for_ms(&mut node_exec, 5.0); let res = run_for_ms(&mut node_exec, 12.0); - assert_decimated_feq!(res.0, 15, vec![ - 0.0, - 0.11080169, 0.22160338, 0.33240506, 0.44320676, 0.5540084, 0.6648101, - 0.7756118, 0.8864135, 0.98414195, - 1.0, 1.0, 1.0, 1.0, 1.0, - 0.9331123, 0.82376325, 0.7144141, 0.59939045, 0.49106687, 0.3827433, - 0.27441972, 0.16609615, 0.057772573, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 - ]); + assert_decimated_feq!( + res.0, + 15, + vec![ + 0.0, + 0.11080169, + 0.22160338, + 0.33240506, + 0.44320676, + 0.5540084, + 0.6648101, + 0.7756118, + 0.8864135, + 0.98414195, + 1.0, + 1.0, + 1.0, + 1.0, + 1.0, + 0.9331123, + 0.82376325, + 0.7144141, + 0.59939045, + 0.49106687, + 0.3827433, + 0.27441972, + 0.16609615, + 0.057772573, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0 + ] + ); } #[test] @@ -600,37 +597,43 @@ fn check_node_sampl_rev_2() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); - let dir_p = smpl.inp_param("dir").unwrap(); - let pmode_p = smpl.inp_param("pmode").unwrap(); + let dir_p = smpl.inp_param("dir").unwrap(); + let pmode_p = smpl.inp_param("pmode").unwrap(); matrix.set_param(sample_p, create_1sec_ramp()); // Reverse: - matrix.set_param(dir_p, SAtom::setting(1)); + matrix.set_param(dir_p, SAtom::setting(1)); // Loop mode: matrix.set_param(pmode_p, SAtom::setting(0)); let res = run_for_ms(&mut node_exec, 1000.0); - assert_decimated_feq!(res.0, 5000, vec![ - 0.9999773, 0.886596, 0.77321476, 0.6598335, 0.5464522, - 0.43307102, 0.31968975, 0.20630851, 0.09292727 - ]); + assert_decimated_feq!( + res.0, + 5000, + vec![ + 0.9999773, 0.886596, 0.77321476, 0.6598335, 0.5464522, 0.43307102, 0.31968975, + 0.20630851, 0.09292727 + ] + ); // Forward: matrix.set_param(dir_p, SAtom::setting(0)); let res = run_for_ms(&mut node_exec, 1000.0); - assert_decimated_feq!(res.0, 5000, vec![ - 0.0, 0.11338125, 0.2267625, 0.34014374, 0.453525, 0.5669062, - 0.6802875, 0.79366875, 0.90705 - ]); + assert_decimated_feq!( + res.0, + 5000, + vec![ + 0.0, 0.11338125, 0.2267625, 0.34014374, 0.453525, 0.5669062, 0.6802875, 0.79366875, + 0.90705 + ] + ); } #[test] @@ -639,11 +642,9 @@ fn check_node_sampl_4() { let mut matrix = Matrix::new(node_conf, 3, 3); let smpl = NodeId::Sampl(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smpl) - .out(None, None, smpl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smpl).out(None, None, smpl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let sample_p = smpl.inp_param("sample").unwrap(); @@ -651,10 +652,24 @@ fn check_node_sampl_4() { let fft = run_and_get_fft4096(&mut node_exec, 0, 1000.0); assert_eq!( - avg_fft_freqs(4.0, + avg_fft_freqs( + 4.0, &[10, 100, 200, 300, 440, 800, 1000, 2000, 3000, 4000, 12000, 22050], - &fft[..]), vec![ - (0, 32), (10, 204), (100, 104), (200, 16), (300, 32), (440, 8), - (800, 4), (1000, 0), (2000, 0), (3000, 0), (4000, 0), (12000, 0) - ]); + &fft[..] + ), + vec![ + (0, 32), + (10, 204), + (100, 104), + (200, 16), + (300, 32), + (440, 8), + (800, 4), + (1000, 0), + (2000, 0), + (3000, 0), + (4000, 0), + (12000, 0) + ] + ); } diff --git a/tests/node_sfilter.rs b/tests/node_sfilter.rs index 72a7276..fa9fd63 100644 --- a/tests/node_sfilter.rs +++ b/tests/node_sfilter.rs @@ -10,19 +10,17 @@ fn setup_sfilter_matrix() -> (Matrix, NodeExecutor) { let mut matrix = Matrix::new(node_conf, 3, 3); let noise = NodeId::Noise(0); - let sf = NodeId::SFilter(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(0, 1, Cell::empty(sf) - .input(sf.inp("inp"), None, None) - .out(None, None, sf.out("sig"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - matrix.place(1, 1, Cell::empty(noise) - .out(None, None, noise.out("sig"))); - matrix.place(1, 2, Cell::empty(out) - .input(out.inp("ch2"), None, None)); + let sf = NodeId::SFilter(0); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(sf).input(sf.inp("inp"), None, None).out(None, None, sf.out("sig")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); + matrix.place(1, 1, Cell::empty(noise).out(None, None, noise.out("sig"))); + matrix.place(1, 2, Cell::empty(out).input(out.inp("ch2"), None, None)); pset_n(&mut matrix, noise, "atv", 1.0); matrix.sync().unwrap(); @@ -32,8 +30,10 @@ fn setup_sfilter_matrix() -> (Matrix, NodeExecutor) { fn fft_with_freq_res_type( matrix: &mut Matrix, node_exec: &mut NodeExecutor, - ftype: i64, freq: f32, res: f32) -> Vec<(u16, u32)> -{ + ftype: i64, + freq: f32, + res: f32, +) -> Vec<(u16, u32)> { let sf = NodeId::SFilter(0); pset_d(matrix, sf, "freq", freq); pset_d_wait(matrix, node_exec, sf, "res", res); @@ -48,46 +48,74 @@ fn check_node_sfilter_lowpass() { // Low Pass @ 1000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, - ], &fft[..]), vec![ - (0, 16), (100, 24), (250, 16), (500, 12), (750, 12), (1000, 12), - (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0), - ]); + avg_fft_freqs( + 4.0, + &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000,], + &fft[..] + ), + vec![ + (0, 16), + (100, 24), + (250, 16), + (500, 12), + (750, 12), + (1000, 12), + (1500, 8), + (2000, 4), + (3000, 4), + (4000, 0), + (8000, 0), + (12000, 0), + ] + ); -// let v = run_and_get_fft4096_2(&mut node_exec, 1); -// assert_eq!( -// avg_fft_freqs(4.0, &[ -// 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, -// ], &v[..]), vec![ -// (0, 16), (100, 24), (250, 16), (500, 12), (750, 12), (1000, 12), -// (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0), -// ]); -// assert!(false); + // let v = run_and_get_fft4096_2(&mut node_exec, 1); + // assert_eq!( + // avg_fft_freqs(4.0, &[ + // 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, + // ], &v[..]), vec![ + // (0, 16), (100, 24), (250, 16), (500, 12), (750, 12), (1000, 12), + // (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0), + // ]); + // assert!(false); // Low Pass @ 4000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, - ], &fft[..]), vec![ - (0, 16), (100, 20), (250, 16), (500, 12), (750, 20), (1000, 16), - (1500, 16), (2000, 16), (3000, 12), (4000, 8), (8000, 4), (12000, 4), - ]); + avg_fft_freqs( + 4.0, + &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000,], + &fft[..] + ), + vec![ + (0, 16), + (100, 20), + (250, 16), + (500, 12), + (750, 20), + (1000, 16), + (1500, 16), + (2000, 16), + (3000, 12), + (4000, 8), + (8000, 4), + (12000, 4), + ] + ); // Low Pass @ 22050Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16),] + ); // Low Pass @ 0Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 0, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0),] + ); } #[test] @@ -97,36 +125,64 @@ fn check_node_sfilter_lowpass_tpt() { // Low Pass TPT @ 1000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 1, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, - ], &fft[..]), vec![ - (0, 16), (100, 24), (250, 16), (500, 12), (750, 12), (1000, 12), - (1500, 8), (2000, 4), (3000, 4), (4000, 0), (8000, 0), (12000, 0), - ]); + avg_fft_freqs( + 4.0, + &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000,], + &fft[..] + ), + vec![ + (0, 16), + (100, 24), + (250, 16), + (500, 12), + (750, 12), + (1000, 12), + (1500, 8), + (2000, 4), + (3000, 4), + (4000, 0), + (8000, 0), + (12000, 0), + ] + ); // Low Pass TPT @ 4000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 1, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000, - ], &fft[..]), vec![ - (0, 16), (100, 20), (250, 16), (500, 12), (750, 20), (1000, 16), - (1500, 16), (2000, 16), (3000, 12), (4000, 8), (8000, 4), (12000, 0), - ]); + avg_fft_freqs( + 4.0, + &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 8000, 12000, 16000,], + &fft[..] + ), + vec![ + (0, 16), + (100, 20), + (250, 16), + (500, 12), + (750, 20), + (1000, 16), + (1500, 16), + (2000, 16), + (3000, 12), + (4000, 8), + (8000, 4), + (12000, 0), + ] + ); // Low Pass TPT @ 22050Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 1, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16),] + ); // Low Pass TPT @ 0Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 1, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0),] + ); } #[test] @@ -136,36 +192,52 @@ fn check_node_sfilter_highpass() { // High Pass @ 1000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 2, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 4), (250, 4), (500, 8), (750, 8), (1000, 16), - (1500, 16), (2000, 16), (3000, 16), (8000, 16), - ]); + avg_fft_freqs(4.0, &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 4), + (250, 4), + (500, 8), + (750, 8), + (1000, 16), + (1500, 16), + (2000, 16), + (3000, 16), + (8000, 16), + ] + ); // High Pass @ 4000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 2, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (250, 0), (500, 0), (750, 4), (1000, 4), - (1500, 4), (2000, 8), (3000, 12), (8000, 16), - ]); + avg_fft_freqs(4.0, &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (250, 0), + (500, 0), + (750, 4), + (1000, 4), + (1500, 4), + (2000, 8), + (3000, 12), + (8000, 16), + ] + ); // High Pass @ 22050Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 2, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 16), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 16),] + ); // High Pass @ 0Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 2, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 24), (100, 16), (1000, 16), (4000, 16), (12000, 16), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 24), (100, 16), (1000, 16), (4000, 16), (12000, 16),] + ); } #[test] @@ -175,39 +247,54 @@ fn check_node_sfilter_highpass_tpt() { // High Pass TPT @ 1000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 3, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (250, 4), (500, 8), (750, 8), (1000, 16), - (1500, 16), (2000, 16), (3000, 16), (8000, 16), - ]); + avg_fft_freqs(4.0, &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (250, 4), + (500, 8), + (750, 8), + (1000, 16), + (1500, 16), + (2000, 16), + (3000, 16), + (8000, 16), + ] + ); // High Pass TPT @ 4000Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 3, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (250, 0), (500, 0), (750, 4), (1000, 4), - (1500, 4), (2000, 8), (3000, 12), (8000, 16), - ]); + avg_fft_freqs(4.0, &[100, 250, 500, 750, 1000, 1500, 2000, 3000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (250, 0), + (500, 0), + (750, 4), + (1000, 4), + (1500, 4), + (2000, 8), + (3000, 12), + (8000, 16), + ] + ); // High Pass TPT @ 22050Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 3, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0),] + ); // High Pass TPT @ 0Hz let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 3, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 24), (100, 16), (1000, 16), (4000, 16), (12000, 16), - ]); + avg_fft_freqs(4.0, &[100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 24), (100, 16), (1000, 16), (4000, 16), (12000, 16),] + ); } - #[test] fn check_node_sfilter_halsvf_lowpass() { let (mut matrix, mut node_exec) = setup_sfilter_matrix(); @@ -215,83 +302,117 @@ fn check_node_sfilter_halsvf_lowpass() { // Low Pass Hal Chamberlin SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 20), (500, 20), (700, 50), (900, 240), (1000, 60), - (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 20), + (500, 20), + (700, 50), + (900, 240), + (1000, 60), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Hal Chamberlin SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 20), (500, 20), (700, 30), (900, 40), (1000, 20), - (1500, 0), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 20), + (500, 20), + (700, 30), + (900, 40), + (1000, 20), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Hal Chamberlin SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 20), (700, 20), (900, 10), (1000, 10), - (1500, 0), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 10), + (500, 20), + (700, 20), + (900, 10), + (1000, 10), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Hal Chamberlin SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 24), (100, 16), (500, 20), (1000, 20), (2000, 40), (3500, 340), - (4000, 180), (5000, 20), (6000, 8), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 24), + (100, 16), + (500, 20), + (1000, 20), + (2000, 40), + (3500, 340), + (4000, 180), + (5000, 20), + (6000, 8), + (8000, 0) + ] + ); // Low Pass Hal Chamberlin SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 12), (500, 16), (1000, 16), (2000, 20), (3500, 20), - (4000, 16), (5000, 8), (6000, 4), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 20), + (100, 12), + (500, 16), + (1000, 16), + (2000, 20), + (3500, 20), + (4000, 16), + (5000, 8), + (6000, 4), + (8000, 0) + ] + ); // Low Pass Hal Chamberlin SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 24), (20000, 16) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 24), (20000, 16)] + ); // Low Pass Hal Chamberlin SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 22050.0, 1.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), vec![ - (0, 8), (100, 16), (1000, 16), (4000, 24), (12000, 160), - (16000, 176), (20000, 24) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), + vec![(0, 8), (100, 16), (1000, 16), (4000, 24), (12000, 160), (16000, 176), (20000, 24)] + ); // Low Pass Hal Chamberlin SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 12), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 12), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0),] + ); // Low Pass Hal Chamberlin SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 4, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 56), (1, 0), (5, 0), (10, 0), (100, 0), (1000, 0), - (4000, 0), (12000, 0), - ]); + avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 56), (1, 0), (5, 0), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0),] + ); } #[test] @@ -301,84 +422,117 @@ fn check_node_sfilter_halsvf_highpass() { // High Pass Hal Chamberlin SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 30), (900, 220), (1000, 80), - (1500, 30), (2000, 20), (3000, 20), (4000, 10) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 30), + (900, 220), + (1000, 80), + (1500, 30), + (2000, 20), + (3000, 20), + (4000, 10) + ] + ); // High Pass Hal Chamberlin SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 20), (900, 30), (1000, 30), - (1500, 20), (2000, 20), (3000, 20), (4000, 20) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 20), + (900, 30), + (1000, 30), + (1500, 20), + (2000, 20), + (3000, 20), + (4000, 20) + ] + ); // High Pass Hal Chamberlin SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 10), (900, 10), (1000, 20), (1500, 20), - (2000, 20), (3000, 20), (4000, 10) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 10), + (900, 10), + (1000, 20), + (1500, 20), + (2000, 20), + (3000, 20), + (4000, 10) + ] + ); // High Pass Hal Chamberlin SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 20), - (3500, 320), (4000, 200), (5000, 40), (6000, 28), (8000, 20) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 20), + (3500, 320), + (4000, 200), + (5000, 40), + (6000, 28), + (8000, 20) + ] + ); // High Pass Hal Chamberlin SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 8), - (3500, 12), (4000, 16), (5000, 16), (6000, 20), (8000, 20) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 8), + (3500, 12), + (4000, 16), + (5000, 16), + (6000, 20), + (8000, 20) + ] + ); // High Pass Hal Chamberlin SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 8), (4000, 24), - (12000, 32), (16000, 40), (20000, 40) - ]); + vec![(0, 0), (100, 0), (1000, 8), (4000, 24), (12000, 32), (16000, 40), (20000, 40)] + ); // High Pass Hal Chamberlin SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 144), - (16000, 192), (20000, 48) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 144), (16000, 192), (20000, 48)] + ); // High Pass Hal Chamberlin SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 52), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 52), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16)] + ); // High Pass Hal Chamberlin SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 5, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 112), (10, 36), (100, 16), (1000, 20), (4000, 16), (12000, 20) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 112), (10, 36), (100, 16), (1000, 20), (4000, 16), (12000, 20)] + ); } #[test] @@ -388,84 +542,120 @@ fn check_node_sfilter_halsvf_bandpass() { // Band Pass Hal Chamberlin SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 10), (700, 40), (900, 230), - (1000, 70), (1500, 20), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 10), + (700, 40), + (900, 230), + (1000, 70), + (1500, 20), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Band Pass Hal Chamberlin SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 10), (700, 30), (900, 30), - (1000, 30), (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 10), + (700, 30), + (900, 30), + (1000, 30), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Band Pass Hal Chamberlin SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 10), (700, 10), (900, 10), - (1000, 10), (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 10), + (700, 10), + (900, 10), + (1000, 10), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Band Pass Hal Chamberlin SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 20), - (3500, 330), (4000, 190), (5000, 30), (6000, 10), (8000, 0) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 20), + (3500, 330), + (4000, 190), + (5000, 30), + (6000, 10), + (8000, 0) + ] + ); // Band Pass Hal Chamberlin SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 10), (3500, 20), - (4000, 10), (5000, 10), (6000, 10), (8000, 10) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 10), + (3500, 20), + (4000, 10), + (5000, 10), + (6000, 10), + (8000, 10) + ] + ); // Band Pass Hal Chamberlin SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), - (12000, 0), (16000, 0), (20000, 0) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (16000, 0), (20000, 0)] + ); // Band Pass Hal Chamberlin SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 136), - (16000, 200), (20000, 48) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 8), (12000, 136), (16000, 200), (20000, 48)] + ); // Band Pass Hal Chamberlin SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 48), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 48), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0)] + ); // Band Pass Hal Chamberlin SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 6, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 4), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 4), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0)] + ); } #[test] @@ -475,87 +665,146 @@ fn check_node_sfilter_halsvf_notch() { // Notch Hal Chamberlin SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 10), (850, 10), (900, 20), (950, 10), - (1000, 10), (1100, 20), (1200, 20), (1400, 20), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 10), + (850, 10), + (900, 20), + (950, 10), + (1000, 10), + (1100, 20), + (1200, 20), + (1400, 20), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Hal Chamberlin SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 10), (850, 10), (900, 0), (950, 0), - (1000, 0), (1100, 0), (1200, 10), (1400, 10), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 10), + (850, 10), + (900, 0), + (950, 0), + (1000, 0), + (1100, 0), + (1200, 10), + (1400, 10), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Hal Chamberlin SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 0), (850, 0), (900, 0), (950, 0), - (1000, 0), (1100, 0), (1200, 0), (1400, 10), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 0), + (850, 0), + (900, 0), + (950, 0), + (1000, 0), + (1100, 0), + (1200, 0), + (1400, 10), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Hal Chamberlin SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 10), (1000, 10), (2000, 10), (3500, 10), - (4000, 20), (4500, 10), (5000, 10), (6000, 20), (8000, 10) - ]); + avg_fft_freqs( + 10.0, + &[100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000], + &fft[..] + ), + vec![ + (0, 20), + (100, 10), + (500, 10), + (1000, 10), + (2000, 10), + (3500, 10), + (4000, 20), + (4500, 10), + (5000, 10), + (6000, 20), + (8000, 10) + ] + ); // Notch Hal Chamberlin SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 10), (1000, 10), (2000, 10), (3500, 0), - (4000, 0), (5000, 0), (6000, 10), (8000, 10) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 20), + (100, 10), + (500, 10), + (1000, 10), + (2000, 10), + (3500, 0), + (4000, 0), + (5000, 0), + (6000, 10), + (8000, 10) + ] + ); // Notch Hal Chamberlin SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16) - ]); + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 16)] + ); // Notch Hal Chamberlin SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16) - ]); + vec![(0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 16)] + ); // Notch Hal Chamberlin SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 68), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 68), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16)] + ); // Notch Hal Chamberlin SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 7, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 20), (10, 32), (100, 16), (1000, 20), (4000, 16), (12000, 20) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 20), (10, 32), (100, 16), (1000, 20), (4000, 16), (12000, 20)] + ); } #[test] @@ -565,84 +814,145 @@ fn check_node_sfilter_simpersvf_lowpass() { // Low Pass Simper SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 20), (500, 20), (700, 50), (900, 240), (1000, 60), - (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 20), + (500, 20), + (700, 50), + (900, 240), + (1000, 60), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Simper SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 20), (900, 20), (1000, 10), - (1500, 0), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 10), + (500, 10), + (700, 20), + (900, 20), + (1000, 10), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Simper SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 10), (900, 0), (1000, 0), - (1500, 0), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 10), + (500, 10), + (700, 10), + (900, 0), + (1000, 0), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Low Pass Simper SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 24), (100, 16), (500, 20), (1000, 20), (2000, 36), (3500, 332), - (4000, 164), (5000, 20), (6000, 8), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 24), + (100, 16), + (500, 20), + (1000, 20), + (2000, 36), + (3500, 332), + (4000, 164), + (5000, 20), + (6000, 8), + (8000, 0) + ] + ); // Low Pass Simper SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 12), (500, 16), (1000, 16), (2000, 12), (3500, 8), - (4000, 8), (5000, 4), (6000, 4), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 20), + (100, 12), + (500, 16), + (1000, 16), + (2000, 12), + (3500, 8), + (4000, 8), + (5000, 4), + (6000, 4), + (8000, 0) + ] + ); // Low Pass Simper SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16), (22050, 0) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), + vec![ + (0, 16), + (100, 16), + (1000, 16), + (4000, 16), + (12000, 16), + (16000, 16), + (20000, 16), + (22050, 0) + ] + ); // Low Pass Simper SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 22050.0, 1.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![ - (0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16), (22050, 0) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), + vec![ + (0, 8), + (100, 16), + (1000, 16), + (4000, 16), + (12000, 16), + (16000, 16), + (20000, 16), + (22050, 0) + ] + ); // Low Pass Simper SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), vec![ - (0, 0), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - (22050, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), + vec![(0, 0), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (22050, 0)] + ); // Low Pass Simper SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 8, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), vec![ - (0, 68), (1, 0), (5, 0), (10, 4), (100, 0), (1000, 0), - (4000, 0), (12000, 0), (22050, 0) - ]); + avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), + vec![ + (0, 68), + (1, 0), + (5, 0), + (10, 4), + (100, 0), + (1000, 0), + (4000, 0), + (12000, 0), + (22050, 0) + ] + ); } #[test] @@ -652,84 +962,117 @@ fn check_node_sfilter_simpersvf_highpass() { // High Pass Simper SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 30), (900, 220), (1000, 80), - (1500, 30), (2000, 20), (3000, 20), (4000, 10) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 30), + (900, 220), + (1000, 80), + (1500, 30), + (2000, 20), + (3000, 20), + (4000, 10) + ] + ); // High Pass Simper SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 10), (900, 10), (1000, 20), - (1500, 20), (2000, 20), (3000, 10), (4000, 10) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 10), + (900, 10), + (1000, 20), + (1500, 20), + (2000, 20), + (3000, 10), + (4000, 10) + ] + ); // High Pass Simper SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (500, 0), (700, 0), (900, 0), (1000, 10), (1500, 10), - (2000, 10), (3000, 10), (4000, 10) - ]); + avg_fft_freqs(10.0, &[500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (500, 0), + (700, 0), + (900, 0), + (1000, 10), + (1500, 10), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // High Pass Simper SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 20), - (3500, 312), (4000, 184), (5000, 40), (6000, 28), (8000, 20) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 20), + (3500, 312), + (4000, 184), + (5000, 40), + (6000, 28), + (8000, 20) + ] + ); // High Pass Simper SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 4), - (3500, 8), (4000, 8), (5000, 8), (6000, 12), (8000, 16) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 4), + (3500, 8), + (4000, 8), + (5000, 8), + (6000, 12), + (8000, 16) + ] + ); // High Pass Simper SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), - (12000, 0), (16000, 0), (20000, 0) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (16000, 0), (20000, 0)] + ); // High Pass Simper SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - (16000, 0), (20000, 0) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (16000, 0), (20000, 0)] + ); // High Pass Simper SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 32), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 32), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16)] + ); // High Pass Simper SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 9, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 92), (10, 36), (100, 16), (1000, 20), (4000, 16), (12000, 20) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 92), (10, 36), (100, 16), (1000, 20), (4000, 16), (12000, 20)] + ); } #[test] @@ -739,84 +1082,120 @@ fn check_node_sfilter_simpersvf_bandpass() { // Band Pass Simper SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 10), (700, 40), (900, 230), - (1000, 70), (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 10), + (700, 40), + (900, 230), + (1000, 70), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Band Pass Simper SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 10), (700, 10), (900, 10), - (1000, 10), (1500, 10), (2000, 0), (3000, 0), (4000, 0) - ]); + avg_fft_freqs(10.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 10), + (700, 10), + (900, 10), + (1000, 10), + (1500, 10), + (2000, 0), + (3000, 0), + (4000, 0) + ] + ); // Band Pass Simper SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 0), (250, 0), (500, 8), (700, 8), (900, 8), - (1000, 8), (1500, 4), (2000, 4), (3000, 4), (4000, 0) - ]); + avg_fft_freqs(4.0, &[250, 500, 700, 900, 1000, 1500, 2000, 3000, 4000, 12000], &fft[..]), + vec![ + (0, 0), + (250, 0), + (500, 8), + (700, 8), + (900, 8), + (1000, 8), + (1500, 4), + (2000, 4), + (3000, 4), + (4000, 0) + ] + ); // Band Pass Simper SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 20), - (3500, 320), (4000, 170), (5000, 20), (6000, 10), (8000, 0) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 20), + (3500, 320), + (4000, 170), + (5000, 20), + (6000, 10), + (8000, 0) + ] + ); // Band Pass Simper SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 0), (500, 0), (1000, 0), (2000, 0), (3500, 10), - (4000, 0), (5000, 0), (6000, 0), (8000, 0) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 0), + (100, 0), + (500, 0), + (1000, 0), + (2000, 0), + (3500, 10), + (4000, 0), + (5000, 0), + (6000, 0), + (8000, 0) + ] + ); // Band Pass Simper SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), - (12000, 0), (16000, 0), (20000, 0) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (16000, 0), (20000, 0)] + ); // Band Pass Simper SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - (16000, 0), (20000, 0) - ]); + vec![(0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (16000, 0), (20000, 0)] + ); // Band Pass Simper SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 4), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 4), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0)] + ); // Band Pass Simper SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 10, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 12), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 12), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0)] + ); } #[test] @@ -826,87 +1205,146 @@ fn check_node_sfilter_simpersvf_notch() { // Notch Simper SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 10), (850, 10), (900, 20), (950, 10), - (1000, 10), (1100, 20), (1200, 20), (1400, 20), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 10), + (850, 10), + (900, 20), + (950, 10), + (1000, 10), + (1100, 20), + (1200, 20), + (1400, 20), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Simper SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 0), (850, 0), (900, 0), (950, 0), - (1000, 0), (1100, 0), (1200, 0), (1400, 10), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 0), + (850, 0), + (900, 0), + (950, 0), + (1000, 0), + (1100, 0), + (1200, 0), + (1400, 10), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Simper SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 0), (700, 0), (850, 0), (900, 0), (950, 0), - (1000, 0), (1100, 0), (1200, 0), (1400, 0), (2000, 10), - (3000, 10), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 0), + (700, 0), + (850, 0), + (900, 0), + (950, 0), + (1000, 0), + (1100, 0), + (1200, 0), + (1400, 0), + (2000, 10), + (3000, 10), + (4000, 10) + ] + ); // Notch Simper SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 10), (1000, 10), (2000, 10), (3500, 10), - (4000, 20), (4500, 10), (5000, 10), (6000, 20), (8000, 10) - ]); + avg_fft_freqs( + 10.0, + &[100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000], + &fft[..] + ), + vec![ + (0, 20), + (100, 10), + (500, 10), + (1000, 10), + (2000, 10), + (3500, 10), + (4000, 20), + (4500, 10), + (5000, 10), + (6000, 20), + (8000, 10) + ] + ); // Notch Simper SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 10), (1000, 10), (2000, 0), (3500, 0), - (4000, 0), (5000, 0), (6000, 10), (8000, 10) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 20), + (100, 10), + (500, 10), + (1000, 10), + (2000, 0), + (3500, 0), + (4000, 0), + (5000, 0), + (6000, 10), + (8000, 10) + ] + ); // Notch Simper SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16) - ]); + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 16)] + ); // Notch Simper SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16) - ]); + vec![(0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 16)] + ); // Notch Simper SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 32), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 32), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16)] + ); // Notch Simper SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 11, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 20), (10, 32), (100, 16), (1000, 20), (4000, 16), (12000, 20) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 20), (10, 32), (100, 16), (1000, 20), (4000, 16), (12000, 20)] + ); } #[test] @@ -916,88 +1354,146 @@ fn check_node_sfilter_simpersvf_peak() { // Peak Simper SVF @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 20), (500, 30), (700, 70), (850, 120), (900, 340), (950, 620), - (1000, 320), (1100, 170), (1200, 80), (1400, 40), (2000, 20), - (3000, 20), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 20), + (500, 30), + (700, 70), + (850, 120), + (900, 340), + (950, 620), + (1000, 320), + (1100, 170), + (1200, 80), + (1400, 40), + (2000, 20), + (3000, 20), + (4000, 10) + ] + ); // Peak Simper SVF @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 20), (500, 20), (700, 30), (850, 40), (900, 30), (950, 40), - (1000, 40), (1100, 40), (1200, 20), (1400, 20), (2000, 20), - (3000, 20), (4000, 20) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 20), + (500, 20), + (700, 30), + (850, 40), + (900, 30), + (950, 40), + (1000, 40), + (1100, 40), + (1200, 20), + (1400, 20), + (2000, 20), + (3000, 20), + (4000, 20) + ] + ); // Peak Simper SVF @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000 - ], &fft[..]), vec![ - (0, 10), (500, 10), (700, 10), (850, 10), (900, 10), (950, 10), - (1000, 20), (1100, 10), (1200, 10), (1400, 10), (2000, 10), - (3000, 20), (4000, 10) - ]); + avg_fft_freqs( + 10.0, + &[500, 700, 850, 900, 950, 1000, 1100, 1200, 1400, 2000, 3000, 4000, 12000], + &fft[..] + ), + vec![ + (0, 10), + (500, 10), + (700, 10), + (850, 10), + (900, 10), + (950, 10), + (1000, 20), + (1100, 10), + (1200, 10), + (1400, 10), + (2000, 10), + (3000, 20), + (4000, 10) + ] + ); // Peak Simper SVF @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 20), (1000, 20), (2000, 50), - (3500, 640), (4000, 630), (4500, 80), (5000, 60), - (6000, 30), (8000, 20) - ]); + avg_fft_freqs( + 10.0, + &[100, 500, 1000, 2000, 3500, 4000, 4500, 5000, 6000, 8000, 12000], + &fft[..] + ), + vec![ + (0, 20), + (100, 10), + (500, 20), + (1000, 20), + (2000, 50), + (3500, 640), + (4000, 630), + (4500, 80), + (5000, 60), + (6000, 30), + (8000, 20) + ] + ); // Peak Simper SVF @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(10.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 20), (100, 10), (500, 10), (1000, 10), (2000, 10), (3500, 20), - (4000, 20), (5000, 10), (6000, 10), (8000, 20) - ]); + avg_fft_freqs(10.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 20), + (100, 10), + (500, 10), + (1000, 10), + (2000, 10), + (3500, 20), + (4000, 20), + (5000, 10), + (6000, 10), + (8000, 20) + ] + ); // Peak Simper SVF @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 22050.0, 0.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 16) - ]); + vec![(0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 16)] + ); // Peak Simper SVF @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 22050.0, 1.0); assert_eq!( avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050], &fft[..]), - vec![ - (0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), - (16000, 16), (20000, 24) - ]); + vec![(0, 8), (100, 16), (1000, 16), (4000, 16), (12000, 16), (16000, 16), (20000, 24)] + ); // Peak Simper SVF @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 28), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 28), (10, 12), (100, 20), (1000, 16), (4000, 16), (12000, 16)] + ); // Peak Simper SVF @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 12, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), vec![ - (0, 164), (10, 40), (100, 16), (1000, 20), (4000, 16), (12000, 20) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050], &fft[..]), + vec![(0, 164), (10, 40), (100, 16), (1000, 20), (4000, 16), (12000, 20)] + ); } #[test] @@ -1007,88 +1503,173 @@ fn check_node_sfilter_moog_lowpass() { // Low Pass Stilson/Moog @ 1000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 1000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 200, 400, 500, 700, 900, 1000, 1100, 1200, - 1500, 2000, 3000, 4000, 6000, 12000 - ], &fft[..]), vec![ - (0, 0), (100, 4), (200, 4), (400, 0), (500, 4), (700, 4), - (900, 12), (1000, 148), (1100, 64), (1200, 4), - (1500, 0), (2000, 0), (3000, 0), (4000, 0), (6000, 0) - ]); + avg_fft_freqs( + 4.0, + &[100, 200, 400, 500, 700, 900, 1000, 1100, 1200, 1500, 2000, 3000, 4000, 6000, 12000], + &fft[..] + ), + vec![ + (0, 0), + (100, 4), + (200, 4), + (400, 0), + (500, 4), + (700, 4), + (900, 12), + (1000, 148), + (1100, 64), + (1200, 4), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0), + (6000, 0) + ] + ); // Low Pass Stilson/Moog @ 1000Hz RES=0.5 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 1000.0, 0.5); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 200, 400, 500, 700, 900, 1000, 1100, 1200, - 1500, 2000, 3000, 4000, 6000, 12000 - ], &fft[..]), vec![ - (0, 4), (100, 4), (200, 8), (400, 8), (500, 8), - (700, 24), (900, 48), (1000, 28), (1100, 16), (1200, 4), - (1500, 0), (2000, 0), (3000, 0), (4000, 0), (6000, 0) - ]); + avg_fft_freqs( + 4.0, + &[100, 200, 400, 500, 700, 900, 1000, 1100, 1200, 1500, 2000, 3000, 4000, 6000, 12000], + &fft[..] + ), + vec![ + (0, 4), + (100, 4), + (200, 8), + (400, 8), + (500, 8), + (700, 24), + (900, 48), + (1000, 28), + (1100, 16), + (1200, 4), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0), + (6000, 0) + ] + ); // Low Pass Stilson/Moog @ 1000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 1000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 200, 400, 500, 700, 900, 1000, 1100, 1200, - 1500, 2000, 3000, 4000, 6000, 12000 - ], &fft[..]), vec![ - (0, 28), (100, 24), (200, 24), (400, 8), (500, 16), (700, 8), - (900, 8), (1000, 4), (1100, 4), (1200, 4), (1500, 0), (2000, 0), - (3000, 0), (4000, 0), (6000, 0) - ]); + avg_fft_freqs( + 4.0, + &[100, 200, 400, 500, 700, 900, 1000, 1100, 1200, 1500, 2000, 3000, 4000, 6000, 12000], + &fft[..] + ), + vec![ + (0, 28), + (100, 24), + (200, 24), + (400, 8), + (500, 16), + (700, 8), + (900, 8), + (1000, 4), + (1100, 4), + (1200, 4), + (1500, 0), + (2000, 0), + (3000, 0), + (4000, 0), + (6000, 0) + ] + ); // Low Pass Stilson/Moog @ 4000Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 4000.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 4), (100, 0), (500, 4), (1000, 4), (2000, 4), - (3500, 28), (4000, 60), (5000, 4), (6000, 0), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 4), + (100, 0), + (500, 4), + (1000, 4), + (2000, 4), + (3500, 28), + (4000, 60), + (5000, 4), + (6000, 0), + (8000, 0) + ] + ); // Low Pass Stilson/Moog @ 4000Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 4000.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[ - 100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000 - ], &fft[..]), vec![ - (0, 28), (100, 16), (500, 20), (1000, 20), (2000, 12), (3500, 8), - (4000, 8), (5000, 4), (6000, 0), (8000, 0) - ]); + avg_fft_freqs(4.0, &[100, 500, 1000, 2000, 3500, 4000, 5000, 6000, 8000, 12000], &fft[..]), + vec![ + (0, 28), + (100, 16), + (500, 20), + (1000, 20), + (2000, 12), + (3500, 8), + (4000, 8), + (5000, 4), + (6000, 0), + (8000, 0) + ] + ); // Low Pass Stilson/Moog @ 22050Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 22050.0, 0.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![ - (0, 16), (100, 16), (1000, 16), (4000, 16), (12000, 8), - (16000, 16), (20000, 8), (22050, 0) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), + vec![ + (0, 16), + (100, 16), + (1000, 16), + (4000, 16), + (12000, 8), + (16000, 16), + (20000, 8), + (22050, 0) + ] + ); // Low Pass Stilson/Moog @ 22050Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 22050.0, 1.0); assert_eq!( - avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), vec![ - (0, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - (16000, 0), (20000, 0), (22050, 0) - ]); + avg_fft_freqs(8.0, &[100, 1000, 4000, 12000, 16000, 20000, 22050, 22051], &fft[..]), + vec![ + (0, 0), + (100, 0), + (1000, 0), + (4000, 0), + (12000, 0), + (16000, 0), + (20000, 0), + (22050, 0) + ] + ); // Low Pass Stilson/Moog @ 0Hz RES=0.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 0.0, 0.0); assert_eq!( - avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), vec![ - (0, 0), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), - (22050, 0) - ]); + avg_fft_freqs(4.0, &[10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), + vec![(0, 0), (10, 0), (100, 0), (1000, 0), (4000, 0), (12000, 0), (22050, 0)] + ); // Low Pass Stilson/Moog @ 0Hz RES=1.0 let fft = fft_with_freq_res_type(&mut matrix, &mut node_exec, 13, 0.0, 1.0); assert_eq!( - avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), vec![ - (0, 0), (1, 0), (5, 0), (10, 0), (100, 0), (1000, 0), - (4000, 0), (12000, 0), (22050, 0) - ]); + avg_fft_freqs(4.0, &[1, 5, 10, 100, 1000, 4000, 12000, 22050, 22051], &fft[..]), + vec![ + (0, 0), + (1, 0), + (5, 0), + (10, 0), + (100, 0), + (1000, 0), + (4000, 0), + (12000, 0), + (22050, 0) + ] + ); } diff --git a/tests/node_smap.rs b/tests/node_smap.rs index a49fcae..bfac676 100644 --- a/tests/node_smap.rs +++ b/tests/node_smap.rs @@ -11,12 +11,10 @@ fn check_node_smap() { let mut matrix = Matrix::new(node_conf, 3, 3); let smap = NodeId::SMap(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smap) - .out(None, None, smap.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); - pset_n(&mut matrix, smap, "inp", 0.5); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smap).out(None, None, smap.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); + pset_n(&mut matrix, smap, "inp", 0.5); pset_n(&mut matrix, smap, "min", -1.0); pset_n(&mut matrix, smap, "max", -0.9); // we expect -0.95 @@ -35,7 +33,7 @@ fn check_node_smap() { let res = run_for_ms(&mut node_exec, 10.0); assert_decimated_feq!(res.0, 10, vec![-0.975; 50]); - pset_n(&mut matrix, smap, "inp", 1.0); + pset_n(&mut matrix, smap, "inp", 1.0); run_for_ms(&mut node_exec, 10.0); pset_s(&mut matrix, smap, "mode", 2); // unipolar inverted @@ -49,15 +47,13 @@ fn check_node_smap_clip() { let mut matrix = Matrix::new(node_conf, 3, 3); let smap = NodeId::SMap(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(smap) - .out(None, None, smap.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(smap).out(None, None, smap.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_s(&mut matrix, smap, "mode", 0); // unipolar - pset_n(&mut matrix, smap, "inp", -0.5); - pset_n(&mut matrix, smap, "min", 0.1); + pset_n(&mut matrix, smap, "inp", -0.5); + pset_n(&mut matrix, smap, "min", 0.1); pset_n(&mut matrix, smap, "max", -0.1); matrix.sync().unwrap(); @@ -74,7 +70,7 @@ fn check_node_smap_clip() { // go to -1.5 input here, which is very much below unipolar // and a bit below bipolar. - pset_n(&mut matrix, smap, "inp", -1.5); // out of range input + pset_n(&mut matrix, smap, "inp", -1.5); // out of range input run_for_ms(&mut node_exec, 10.0); diff --git a/tests/node_test.rs b/tests/node_test.rs index 524625d..f32371c 100644 --- a/tests/node_test.rs +++ b/tests/node_test.rs @@ -11,26 +11,24 @@ fn check_node_test_1() { let mut matrix = Matrix::new(node_conf, 3, 3); let test = NodeId::Test(0); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let p = test.inp_param("p").unwrap(); matrix.set_param(p, SAtom::param(1.0)); let res = run_for_ms(&mut node_exec, 2.0); - assert_decimated_feq!(res.0, 1, vec![ 1.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![1.0; 10]); matrix.set_param(p, SAtom::param(0.5)); let res = run_for_ms(&mut node_exec, 2.0); - assert_decimated_feq!(res.0, 1, vec![ 0.5; 10 ]); + assert_decimated_feq!(res.0, 1, vec![0.5; 10]); matrix.set_param(p, SAtom::param(0.0)); let res = run_for_ms(&mut node_exec, 1.0); - assert_decimated_feq!(res.0, 1, vec![ 0.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![0.0; 10]); } #[test] @@ -39,40 +37,30 @@ fn check_node_test_out_connected() { let mut matrix = Matrix::new(node_conf, 6, 3); let test = NodeId::Test(0); - let out = NodeId::Out(0); - let sin = NodeId::Sin(0); + let out = NodeId::Out(0); + let sin = NodeId::Sin(0); let sin2 = NodeId::Sin(1); let sin3 = NodeId::Sin(2); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("outc"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("outc"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); - matrix.place(1, 0, Cell::empty(test) - .out(None, None, test.out("out2"))); - matrix.place(1, 1, Cell::empty(out) - .input(out.inp("ch2"), None, None)); + matrix.place(1, 0, Cell::empty(test).out(None, None, test.out("out2"))); + matrix.place(1, 1, Cell::empty(out).input(out.inp("ch2"), None, None)); - matrix.place(2, 0, Cell::empty(test) - .out(None, None, test.out("out3"))); - matrix.place(2, 1, Cell::empty(sin) - .input(sin.inp("freq"), None, None)); + matrix.place(2, 0, Cell::empty(test).out(None, None, test.out("out3"))); + matrix.place(2, 1, Cell::empty(sin).input(sin.inp("freq"), None, None)); - matrix.place(3, 0, Cell::empty(test) - .out(None, None, test.out("out4"))); - matrix.place(3, 1, Cell::empty(sin2) - .input(sin2.inp("freq"), None, None)); + matrix.place(3, 0, Cell::empty(test).out(None, None, test.out("out4"))); + matrix.place(3, 1, Cell::empty(sin2).input(sin2.inp("freq"), None, None)); - matrix.place(4, 0, Cell::empty(test) - .out(None, None, test.out("sig"))); - matrix.place(4, 1, Cell::empty(sin3) - .input(sin3.inp("freq"), None, None)); + matrix.place(4, 0, Cell::empty(test).out(None, None, test.out("sig"))); + matrix.place(4, 1, Cell::empty(sin3).input(sin3.inp("freq"), None, None)); matrix.sync().unwrap(); let res = run_for_ms(&mut node_exec, 2.0); let mask = 0x01 | 0x04 | 0x08 | 0x10 | 0x20; - assert_decimated_feq!(res.0, 1, vec![ mask as f32; 10 ]); - assert_decimated_feq!(res.1, 1, vec![ 1.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![mask as f32; 10]); + assert_decimated_feq!(res.1, 1, vec![1.0; 10]); // Remove a connection for testing: matrix.place(1, 1, Cell::empty(NodeId::Nop)); @@ -80,8 +68,8 @@ fn check_node_test_out_connected() { let res = run_for_ms(&mut node_exec, 2.0); let mask = 0x01 | 0x08 | 0x10 | 0x20; - assert_decimated_feq!(res.0, 1, vec![ mask as f32; 10 ]); - assert_decimated_feq!(res.1, 1, vec![ 0.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![mask as f32; 10]); + assert_decimated_feq!(res.1, 1, vec![0.0; 10]); } #[test] @@ -91,22 +79,22 @@ fn check_node_test_in_connected() { let test = NodeId::Test(0); let tst2 = NodeId::Test(1); - let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(test) - .out(None, None, test.out("sig"))); - matrix.place(0, 1, Cell::empty(tst2) - .input(tst2.inp("f"), None, None) - .out(None, None, test.out("out3"))); - matrix.place(0, 2, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + let out = NodeId::Out(0); + matrix.place(0, 0, Cell::empty(test).out(None, None, test.out("sig"))); + matrix.place( + 0, + 1, + Cell::empty(tst2).input(tst2.inp("f"), None, None).out(None, None, test.out("out3")), + ); + matrix.place(0, 2, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); let res = run_for_ms(&mut node_exec, 2.0); - assert_decimated_feq!(res.0, 1, vec![ 1.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![1.0; 10]); matrix.place(0, 0, Cell::empty(NodeId::Nop)); matrix.sync().unwrap(); let res = run_for_ms(&mut node_exec, 2.0); - assert_decimated_feq!(res.0, 1, vec![ 0.0; 10 ]); + assert_decimated_feq!(res.0, 1, vec![0.0; 10]); } diff --git a/tests/node_tslfo.rs b/tests/node_tslfo.rs index 4605421..5fd3212 100644 --- a/tests/node_tslfo.rs +++ b/tests/node_tslfo.rs @@ -12,49 +12,43 @@ fn check_node_tslfo_1() { let tsl = NodeId::TsLFO(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(tsl) - .out(None, None, tsl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(tsl).out(None, None, tsl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); pset_d(&mut matrix, tsl, "time", 0.1); matrix.sync().unwrap(); // Test shortest time 0.1ms: let (out_l, _) = run_for_ms(&mut node_exec, 1.0); - assert_decimated_feq!(out_l, 1, vec![ - 0.0, 0.4535, 0.9070, 0.6394, 0.1859, - 0.2675, 0.7210, 0.8253, 0.37188, 0.0816 - ]); + assert_decimated_feq!( + out_l, + 1, + vec![0.0, 0.4535, 0.9070, 0.6394, 0.1859, 0.2675, 0.7210, 0.8253, 0.37188, 0.0816] + ); // Test 1ms: pset_d_wait(&mut matrix, &mut node_exec, tsl, "time", 1.0); let (out_l, _) = run_for_ms(&mut node_exec, 5.0); - assert_decimated_feq!(out_l, 10, vec![ - 0.7103, 0.8361, - 0.3826, 0.0708, 0.5244, 0.9779, 0.5685, 0.1150, - 0.3384 - ]); + assert_decimated_feq!( + out_l, + 10, + vec![0.7103, 0.8361, 0.3826, 0.0708, 0.5244, 0.9779, 0.5685, 0.1150, 0.3384] + ); // Test 300000.0 ms pset_d_wait(&mut matrix, &mut node_exec, tsl, "time", 300000.0); let (out_l, _) = run_for_ms(&mut node_exec, 3000.0); let ramp_slope = 1.0_f64 / (300.0 * 44100.0); let tri_slope = ramp_slope * 2.0; - assert_float_eq!( - (out_l[0] - out_l[10000]).abs(), - (tri_slope * 10000.0) as f32); - assert_float_eq!( - (out_l[10000] - out_l[11000]).abs(), - (tri_slope * 1000.0) as f32); - assert_decimated_feq!(out_l, 10000, vec![ - 0.7566, // => Slope is ~0.0015 per 10000 samples - 0.7551, - 0.7536, - 0.7521, - 0.7506, - 0.7490, - 0.7475, - ]); + assert_float_eq!((out_l[0] - out_l[10000]).abs(), (tri_slope * 10000.0) as f32); + assert_float_eq!((out_l[10000] - out_l[11000]).abs(), (tri_slope * 1000.0) as f32); + assert_decimated_feq!( + out_l, + 10000, + vec![ + 0.7566, // => Slope is ~0.0015 per 10000 samples + 0.7551, 0.7536, 0.7521, 0.7506, 0.7490, 0.7475, + ] + ); } #[test] @@ -64,10 +58,8 @@ fn check_node_tslfo_trig_slopes() { let tsl = NodeId::TsLFO(0); let out = NodeId::Out(0); - matrix.place(0, 0, Cell::empty(tsl) - .out(None, None, tsl.out("sig"))); - matrix.place(0, 1, Cell::empty(out) - .input(out.inp("ch1"), None, None)); + matrix.place(0, 0, Cell::empty(tsl).out(None, None, tsl.out("sig"))); + matrix.place(0, 1, Cell::empty(out).input(out.inp("ch1"), None, None)); matrix.sync().unwrap(); // Test 1ms but at full ramp up and resync/trigger: @@ -76,14 +68,27 @@ fn check_node_tslfo_trig_slopes() { pset_d_wait(&mut matrix, &mut node_exec, tsl, "trig", 1.0); let (out_l, _) = run_for_ms(&mut node_exec, 15.0); let ramp_slope = 1.0_f64 / ((10.0 / 1000.0) * 44100.0); - assert_float_eq!( - (out_l[0] - out_l[1]).abs(), - ramp_slope as f32); - assert_decimated_feq!(out_l, 50, vec![ - 0.00000022911095, 0.11349243, 0.22698463, 0.34047684, 0.45396903, - 0.56746125, 0.68095344, 0.79444563, 0.9079378, 0.020429054, - 0.13392125, 0.24741346, 0.36090568, 0.47439787 - ]); + assert_float_eq!((out_l[0] - out_l[1]).abs(), ramp_slope as f32); + assert_decimated_feq!( + out_l, + 50, + vec![ + 0.00000022911095, + 0.11349243, + 0.22698463, + 0.34047684, + 0.45396903, + 0.56746125, + 0.68095344, + 0.79444563, + 0.9079378, + 0.020429054, + 0.13392125, + 0.24741346, + 0.36090568, + 0.47439787 + ] + ); pset_d_wait(&mut matrix, &mut node_exec, tsl, "trig", 0.0); @@ -93,12 +98,25 @@ fn check_node_tslfo_trig_slopes() { pset_d_wait(&mut matrix, &mut node_exec, tsl, "trig", 1.0); let (out_l, _) = run_for_ms(&mut node_exec, 15.0); let ramp_slope = 1.0_f64 / ((10.0 / 1000.0) * 44100.0); - assert_float_eq!( - (out_l[1] - out_l[2]).abs(), - ramp_slope as f32); - assert_decimated_feq!(out_l, 50, vec![ - 0.0022888184, 0.88670975, 0.77331966, 0.65992963, 0.5465396, - 0.43314955, 0.3197595, 0.20636943, 0.09297939, 0.97968936, - 0.8662993, 0.75290924, 0.6395192, 0.5261291 - ]); + assert_float_eq!((out_l[1] - out_l[2]).abs(), ramp_slope as f32); + assert_decimated_feq!( + out_l, + 50, + vec![ + 0.0022888184, + 0.88670975, + 0.77331966, + 0.65992963, + 0.5465396, + 0.43314955, + 0.3197595, + 0.20636943, + 0.09297939, + 0.97968936, + 0.8662993, + 0.75290924, + 0.6395192, + 0.5261291 + ] + ); } diff --git a/tests/node_vosc.rs b/tests/node_vosc.rs index ea1ee47..02046cd 100644 --- a/tests/node_vosc.rs +++ b/tests/node_vosc.rs @@ -6,21 +6,28 @@ mod common; use common::*; fn setup_vosc(matrix: &mut Matrix) { - let vosc_1 = NodeId::VOsc(0); - let amp_1 = NodeId::Amp(0); - let out_1 = NodeId::Out(0); - matrix.place(0, 1, - Cell::empty(vosc_1) - .input(vosc_1.inp("damt"), None, None) - .out(vosc_1.out("sig"), None, None)); - matrix.place(1, 0, - Cell::empty(amp_1) - .input(None, None, amp_1.inp("inp")) - .out(amp_1.out("sig"), None, None)); - matrix.place(2, 0, - Cell::empty(out_1) - .input(None, None, out_1.inp("ch1")) - .out(None, None, None)); + let vosc_1 = NodeId::VOsc(0); + let amp_1 = NodeId::Amp(0); + let out_1 = NodeId::Out(0); + matrix.place( + 0, + 1, + Cell::empty(vosc_1).input(vosc_1.inp("damt"), None, None).out( + vosc_1.out("sig"), + None, + None, + ), + ); + matrix.place( + 1, + 0, + Cell::empty(amp_1).input(None, None, amp_1.inp("inp")).out(amp_1.out("sig"), None, None), + ); + matrix.place( + 2, + 0, + Cell::empty(out_1).input(None, None, out_1.inp("ch1")).out(None, None, None), + ); pset_n(matrix, vosc_1, "d", 0.500); pset_n(matrix, vosc_1, "v", 0.500); @@ -39,7 +46,7 @@ fn check_node_vosc_sine() { let fft = run_and_get_fft4096_2(node_exec, 500); dump_table!(fft); - assert_eq!(fft, vec![ (431, 614), (441, 1012) ]); + assert_eq!(fft, vec![(431, 614), (441, 1012)]); } #[test] @@ -54,95 +61,100 @@ fn check_node_vosc_d_v() { pset_n_wait(matrix, node_exec, vosc_1, "d", 0.25); let fft = run_and_get_fft4096_2(node_exec, 50); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (431, 589), - (441, 972), - (452, 395), - (872, 178), - (883, 244), - (894, 79), - (1314, 90), - (1324, 103) - ]); + assert_eq!( + fft, + vec![ + (431, 589), + (441, 972), + (452, 395), + (872, 178), + (883, 244), + (894, 79), + (1314, 90), + (1324, 103) + ] + ); // d=0.0, v=0.5 pset_n_wait(matrix, node_exec, vosc_1, "d", 0.0); let fft = run_and_get_fft4096_2(node_exec, 100); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (431, 521), - (441, 859), - (452, 349), - (872, 242), - (883, 332), - (894, 107), - (1314, 176), - (1324, 201), - (1755, 143), - (1766, 137), - (2196, 122), - (2638, 106) - ]); + assert_eq!( + fft, + vec![ + (431, 521), + (441, 859), + (452, 349), + (872, 242), + (883, 332), + (894, 107), + (1314, 176), + (1324, 201), + (1755, 143), + (1766, 137), + (2196, 122), + (2638, 106) + ] + ); // d=1.0, v=0.5 (symmetric to above) pset_n_wait(matrix, node_exec, vosc_1, "d", 0.0); let fft = run_and_get_fft4096_2(node_exec, 100); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (431, 521), - (441, 859), - (452, 349), - (872, 242), - (883, 332), - (894, 107), - (1314, 175), - (1324, 201), - (1755, 143), - (1766, 137), - (2196, 122), - (2638, 106) - ]); + assert_eq!( + fft, + vec![ + (431, 521), + (441, 859), + (452, 349), + (872, 242), + (883, 332), + (894, 107), + (1314, 175), + (1324, 201), + (1755, 143), + (1766, 137), + (2196, 122), + (2638, 106) + ] + ); // d=0.5, v=0.25 pset_n_wait(matrix, node_exec, vosc_1, "d", 0.5); pset_n_wait(matrix, node_exec, vosc_1, "v", 0.25); let fft = run_and_get_fft4096_2(node_exec, 100); dump_table!(fft); - assert_eq!(fft, vec![ - ( 0, 434), - ( 11, 217), - (431, 554), - (441, 913), - (452, 371), - (872, 215), - (883, 294) - ]); + assert_eq!( + fft, + vec![(0, 434), (11, 217), (431, 554), (441, 913), (452, 371), (872, 215), (883, 294)] + ); // d=0.25, v=0.25 pset_n_wait(matrix, node_exec, vosc_1, "d", 0.25); pset_n_wait(matrix, node_exec, vosc_1, "v", 0.25); let fft = run_and_get_fft4096_2(node_exec, 50); dump_table!(fft); - assert_eq!(fft, vec![ - (431, 614), (441, 1012), (452, 411) - ]); + assert_eq!(fft, vec![(431, 614), (441, 1012), (452, 411)]); // d=0.1, v=0.25 pset_n_wait(matrix, node_exec, vosc_1, "d", 0.1); pset_n_wait(matrix, node_exec, vosc_1, "v", 0.25); let fft = run_and_get_fft4096_2(node_exec, 50); dump_table!(fft); - assert_eq!(fft, vec![ - ( 0, 260), - ( 11, 130), - (431, 593), - (441, 977), - (452, 397), - (872, 105), - (883, 144), - (1314, 64), - (1324, 74) - ]); + assert_eq!( + fft, + vec![ + (0, 260), + (11, 130), + (431, 593), + (441, 977), + (452, 397), + (872, 105), + (883, 144), + (1314, 64), + (1324, 74) + ] + ); } #[test] @@ -159,60 +171,63 @@ fn check_node_vosc_ovrsmpl() { pset_n_wait(matrix, node_exec, vosc_1, "v", 0.5); let fft = run_and_get_fft4096_2(node_exec, 25); dump_table!(fft); - assert_eq!(fft, vec![ - (431, 521) , - (441, 859) , - (452, 349) , - (872, 242) , - (883, 332) , - (894, 107) , - (1303, 27) , - (1314, 175), - (1324, 201), - (1335, 50) , - (1744, 30) , - (1755, 143), - (1766, 137), - (1776, 25) , - (2186, 34) , - (2196, 122), - (2207, 98) , - (2627, 38) , - (2638, 106), - (2649, 71) , - (3068, 41) , - (3079, 93) , - (3090, 51) , - (3510, 44) , - (3521, 81) , - (3531, 37) , - (3951, 46) , - (3962, 70) , - (3973, 25) , - (4393, 48) , - (4404, 60) , - (4834, 49) , - (4845, 51) , - (5276, 48) , - (5286, 43) , - (5717, 47) , - (5728, 35) , - (6158, 46) , - (6169, 28) , - (6600, 43) , - (7041, 40) , - (7472, 26) , - (7483, 36) , - (7913, 28) , - (7924, 32) , - (8355, 29) , - (8366, 28) , - (8796, 30) , - (9238, 30) , - (9679, 29) , - (10121, 28), - (10562, 26), - ]); + assert_eq!( + fft, + vec![ + (431, 521), + (441, 859), + (452, 349), + (872, 242), + (883, 332), + (894, 107), + (1303, 27), + (1314, 175), + (1324, 201), + (1335, 50), + (1744, 30), + (1755, 143), + (1766, 137), + (1776, 25), + (2186, 34), + (2196, 122), + (2207, 98), + (2627, 38), + (2638, 106), + (2649, 71), + (3068, 41), + (3079, 93), + (3090, 51), + (3510, 44), + (3521, 81), + (3531, 37), + (3951, 46), + (3962, 70), + (3973, 25), + (4393, 48), + (4404, 60), + (4834, 49), + (4845, 51), + (5276, 48), + (5286, 43), + (5717, 47), + (5728, 35), + (6158, 46), + (6169, 28), + (6600, 43), + (7041, 40), + (7472, 26), + (7483, 36), + (7913, 28), + (7924, 32), + (8355, 29), + (8366, 28), + (8796, 30), + (9238, 30), + (9679, 29), + (10121, 28), + (10562, 26), + ] + ); // d=0.0, v=0.5, without oversampling pset_s(matrix, vosc_1, "ovrsmpl", 0); @@ -220,60 +235,63 @@ fn check_node_vosc_ovrsmpl() { pset_n_wait(matrix, node_exec, vosc_1, "v", 0.5); let fft = run_and_get_fft4096_2(node_exec, 25); dump_table!(fft); - assert_eq!(fft, vec![ - (431, 521), - (441, 859), - (452, 349), - (872, 242), - (883, 332), - (894, 108), - (1303, 26), - (1314, 175), - (1324, 201), - (1335, 51), - (1744, 30), - (1755, 143), - (1766, 137), - (1776, 26), - (2186, 34), - (2196, 122), - (2207, 98), - (2627, 38), - (2638, 106), - (2649, 71), - (3068, 41), - (3079, 93), - (3090, 52), - (3510, 44), - (3521, 81), - (3531, 37), - (3951, 46), - (3962, 70), - (3973, 26), - (4393, 48), - (4404, 61), - (4834, 48), - (4845, 51), - (5276, 48), - (5286, 43), - (5717, 47), - (5728, 35), - (6158, 45), - (6169, 28), - (6600, 43), - (7041, 40), - (7472, 26), - (7483, 36), - (7913, 28), - (7924, 32), - (8355, 29), - (8366, 28), - (8796, 30), - (9238, 30), - (9679, 29), - (10121, 28), - (10562, 26) - ]); + assert_eq!( + fft, + vec![ + (431, 521), + (441, 859), + (452, 349), + (872, 242), + (883, 332), + (894, 108), + (1303, 26), + (1314, 175), + (1324, 201), + (1335, 51), + (1744, 30), + (1755, 143), + (1766, 137), + (1776, 26), + (2186, 34), + (2196, 122), + (2207, 98), + (2627, 38), + (2638, 106), + (2649, 71), + (3068, 41), + (3079, 93), + (3090, 52), + (3510, 44), + (3521, 81), + (3531, 37), + (3951, 46), + (3962, 70), + (3973, 26), + (4393, 48), + (4404, 61), + (4834, 48), + (4845, 51), + (5276, 48), + (5286, 43), + (5717, 47), + (5728, 35), + (6158, 45), + (6169, 28), + (6600, 43), + (7041, 40), + (7472, 26), + (7483, 36), + (7913, 28), + (7924, 32), + (8355, 29), + (8366, 28), + (8796, 30), + (9238, 30), + (9679, 29), + (10121, 28), + (10562, 26) + ] + ); } #[test] @@ -291,17 +309,20 @@ fn check_node_vosc_dist() { pset_n_wait(matrix, node_exec, vosc_1, "v", 0.5); let fft = run_and_get_fft4096_2(node_exec, 100); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (431, 781), - (441, 1287), - (452, 523), - (1314, 340), - (1324, 389), - (2196, 238), - (2207, 191), - (3079, 179), - (3962, 134) - ]); + assert_eq!( + fft, + vec![ + (431, 781), + (441, 1287), + (452, 523), + (1314, 340), + (1324, 389), + (2196, 238), + (2207, 191), + (3079, 179), + (3962, 134) + ] + ); // dist=B.D.Jong (very similar to the TanH) pset_s(matrix, vosc_1, "dist", 2); @@ -310,16 +331,19 @@ fn check_node_vosc_dist() { pset_n_wait(matrix, node_exec, vosc_1, "v", 0.5); let fft = run_and_get_fft4096_2(node_exec, 100); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (431, 759), - (441, 1251), - (452, 509), - (1314, 282), - (1324, 323), - (2196, 172), - (2207, 138), - (3079, 115) - ]); + assert_eq!( + fft, + vec![ + (431, 759), + (441, 1251), + (452, 509), + (1314, 282), + (1324, 323), + (2196, 172), + (2207, 138), + (3079, 115) + ] + ); // dist=Fold pset_s(matrix, vosc_1, "dist", 3); @@ -328,24 +352,27 @@ fn check_node_vosc_dist() { pset_n_wait(matrix, node_exec, vosc_1, "v", 0.5); let fft = run_and_get_fft4096_2(node_exec, 100); //d// dump_table!(fft); - assert_eq!(fft, vec![ - ( 0, 381), - ( 11, 190), - ( 431, 370), - ( 441, 611), - ( 452, 248), - ( 872, 242), - ( 883, 331), - ( 894, 107), - (1314, 313), - (1324, 359), - (1755, 221), - (1766, 212), - (2196, 250), - (2207, 201), - (2638, 129), - (3079, 123) - ]); + assert_eq!( + fft, + vec![ + (0, 381), + (11, 190), + (431, 370), + (441, 611), + (452, 248), + (872, 242), + (883, 331), + (894, 107), + (1314, 313), + (1324, 359), + (1755, 221), + (1766, 212), + (2196, 250), + (2207, 201), + (2638, 129), + (3079, 123) + ] + ); } #[test] @@ -361,41 +388,47 @@ fn check_node_vosc_vs() { pset_d_wait(matrix, node_exec, vosc_1, "vs", 2.0); let fft = run_and_get_fft4096_2(node_exec, 150); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (872, 470), - (883, 644), - (894, 208), - (1314, 356), - (1324, 408), - (1755, 194), - (1766, 186), - (2638, 190), - (3079, 308), - (3090, 171), - (3510, 176), - (3521, 322), - (3951, 163), - (3962, 247) - ]); + assert_eq!( + fft, + vec![ + (872, 470), + (883, 644), + (894, 208), + (1314, 356), + (1324, 408), + (1755, 194), + (1766, 186), + (2638, 190), + (3079, 308), + (3090, 171), + (3510, 176), + (3521, 322), + (3951, 163), + (3962, 247) + ] + ); // d=0.3, vs=3.0 pset_n_wait(matrix, node_exec, vosc_1, "d", 0.3); pset_d_wait(matrix, node_exec, vosc_1, "vs", 3.0); let fft = run_and_get_fft4096_2(node_exec, 150); //d// dump_table!(fft); - assert_eq!(fft, vec![ - (1314, 378), - (1324, 433), - (1755, 578), - (1766, 554), - (2638, 163), - (3079, 168), - (4393, 189), - (4404, 237), - (4834, 262), - (4845, 276), - (5276, 258), - (5286, 228), - (5717, 184) - ]); + assert_eq!( + fft, + vec![ + (1314, 378), + (1324, 433), + (1755, 578), + (1766, 554), + (2638, 163), + (3079, 168), + (4393, 189), + (4404, 237), + (4834, 262), + (4845, 276), + (5276, 258), + (5286, 228), + (5717, 184) + ] + ); } diff --git a/tests/quant.rs b/tests/quant.rs index 6249f03..0f6c510 100644 --- a/tests/quant.rs +++ b/tests/quant.rs @@ -5,57 +5,33 @@ mod common; use common::*; -use hexodsp::dsp::helpers::Quantizer; use hexodsp::d_pit; +use hexodsp::dsp::helpers::Quantizer; #[test] fn check_quant_pos_neg_exact() { let mut q = Quantizer::new(); q.set_keys(0x0); - let v = - (0..=12).map(|i| - d_pit!( - q.process( - i as f32 * (0.1 / 12.0))) - ).collect::>(); + let v = (0..=12).map(|i| d_pit!(q.process(i as f32 * (0.1 / 12.0)))).collect::>(); - assert_vec_feq!(v, vec![ - 440.0, - 466.1638, - 493.8833, - 523.2511, - 554.3653, - 587.3295, - 622.25397, - 659.2551, - 698.4565, - 739.98883, - 783.9909, - 830.6094, - 880.0 - ]); + assert_vec_feq!( + v, + vec![ + 440.0, 466.1638, 493.8833, 523.2511, 554.3653, 587.3295, 622.25397, 659.2551, 698.4565, + 739.98883, 783.9909, 830.6094, 880.0 + ] + ); - let v = - (0..=12).map(|i| - d_pit!(q.process(i as f32 * (-0.1 / 12.0))) - ).collect::>(); + let v = (0..=12).map(|i| d_pit!(q.process(i as f32 * (-0.1 / 12.0)))).collect::>(); - assert_vec_feq!(v, vec![ - 440.0, - 415.3047, - 391.99542, - 369.99442, - 349.22824, - 329.62756, - 311.12698, - 293.66476, - 277.18265, - 261.62555, - 246.94165, - 233.08186, - 220.0 - ]); + assert_vec_feq!( + v, + vec![ + 440.0, 415.3047, 391.99542, 369.99442, 349.22824, 329.62756, 311.12698, 293.66476, + 277.18265, 261.62555, 246.94165, 233.08186, 220.0 + ] + ); } #[test] @@ -64,27 +40,19 @@ fn check_quant_precise_01_range() { q.set_keys(0x0); let v = - (0..=48).map(|i| - d_pit!( - q.process( - i as f32 * ((0.1 * 0.25) / 12.0))) - ).collect::>(); + (0..=48).map(|i| d_pit!(q.process(i as f32 * ((0.1 * 0.25) / 12.0)))).collect::>(); - assert_vec_feq!(v, vec![ - 440.0, - 466.1638, 466.1638, 466.1638, 466.1638, - 493.8833, 493.8833, 493.8833, 493.8833, - 523.2511, 523.2511, 523.2511, 523.2511, - 554.3653, 554.3653, 554.3653, 554.3653, - 587.3295, 587.3295, 587.3295, 587.3295, - 622.25397, 622.25397, 622.25397, 622.25397, - 659.2551, 659.2551, 659.2551, 659.2551, - 698.4565, 698.4565, 698.4565, 698.4565, - 739.98883, 739.98883, 739.98883, 739.98883, - 783.9909, 783.9909, 783.9909, 783.9909, - 830.6094, 830.6094, 830.6094, 830.6094, - 880.0, 880.0, 880.0, 880.0 - ]); + assert_vec_feq!( + v, + vec![ + 440.0, 466.1638, 466.1638, 466.1638, 466.1638, 493.8833, 493.8833, 493.8833, 493.8833, + 523.2511, 523.2511, 523.2511, 523.2511, 554.3653, 554.3653, 554.3653, 554.3653, + 587.3295, 587.3295, 587.3295, 587.3295, 622.25397, 622.25397, 622.25397, 622.25397, + 659.2551, 659.2551, 659.2551, 659.2551, 698.4565, 698.4565, 698.4565, 698.4565, + 739.98883, 739.98883, 739.98883, 739.98883, 783.9909, 783.9909, 783.9909, 783.9909, + 830.6094, 830.6094, 830.6094, 830.6094, 880.0, 880.0, 880.0, 880.0 + ] + ); } #[test] @@ -92,29 +60,24 @@ fn check_quant_neg_pos_range() { let mut q = Quantizer::new(); q.set_keys(0x0); - let v = - (0..=48).map(|i| { + let v = (0..=48) + .map(|i| { let i = i - 24; - d_pit!( - q.process( - i as f32 * ((0.1 * 0.25) / 12.0))) - }).collect::>(); + d_pit!(q.process(i as f32 * ((0.1 * 0.25) / 12.0))) + }) + .collect::>(); - assert_vec_feq!(v, vec![ - 311.12698, 311.12698, - 329.62756, 329.62756, 329.62756, 329.62756, - 349.22824, 349.22824, 349.22824, 349.22824, - 369.99442, 369.99442, 369.99442, 369.99442, - 391.99542, 391.99542, 391.99542, 391.99542, - 415.3047, 415.3047, 415.3047, 415.3047, - 440.0, 440.0, 440.0, - 466.1638, 466.1638, 466.1638, 466.1638, - 493.8833, 493.8833, 493.8833, 493.8833, - 523.2511, 523.2511, 523.2511, 523.2511, - 554.3653, 554.3653, 554.3653, 554.3653, - 587.3295, 587.3295, 587.3295, 587.3295, - 622.25397, 622.25397, 622.25397, 622.25397 - ]); + assert_vec_feq!( + v, + vec![ + 311.12698, 311.12698, 329.62756, 329.62756, 329.62756, 329.62756, 349.22824, 349.22824, + 349.22824, 349.22824, 369.99442, 369.99442, 369.99442, 369.99442, 391.99542, 391.99542, + 391.99542, 391.99542, 415.3047, 415.3047, 415.3047, 415.3047, 440.0, 440.0, 440.0, + 466.1638, 466.1638, 466.1638, 466.1638, 493.8833, 493.8833, 493.8833, 493.8833, + 523.2511, 523.2511, 523.2511, 523.2511, 554.3653, 554.3653, 554.3653, 554.3653, + 587.3295, 587.3295, 587.3295, 587.3295, 622.25397, 622.25397, 622.25397, 622.25397 + ] + ); } #[test] @@ -123,46 +86,39 @@ fn check_quant_edge_oct_offs() { q.set_keys(0b1001_0000_0000); let v = - (0..=24).map(|i| { - d_pit!( - q.process( - i as f32 * ((0.1 * 0.5) / 12.0))) - }).collect::>(); + (0..=24).map(|i| d_pit!(q.process(i as f32 * ((0.1 * 0.5) / 12.0)))).collect::>(); - assert_vec_feq!(v, vec![ - 415.3047, - 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, - 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, - 493.8833, 493.8833, - 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, - 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, - 830.6094, 830.6094 - ]); + assert_vec_feq!( + v, + vec![ + 415.3047, 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, + 493.8833, 493.8833, 493.8833, 493.8833, 493.8833, 830.6094, 830.6094, 830.6094, + 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, 830.6094, + 830.6094 + ] + ); } - #[test] fn check_quant_one_key() { let mut q = Quantizer::new(); q.set_keys(0b0010_0000_0000); - let v = - (0..=48).map(|i| { + let v = (0..=48) + .map(|i| { let i = i - 24; - d_pit!( - q.process( - i as f32 * ((0.1 * 0.5) / 12.0))) - }).collect::>(); + d_pit!(q.process(i as f32 * ((0.1 * 0.5) / 12.0))) + }) + .collect::>(); - assert_vec_feq!(v, vec![ - 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, - 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, - 220.0, - 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, - 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, - 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, - 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, - 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, - 880.0, 880.0, 880.0, 880.0, 880.0, 880.0 - ]); + assert_vec_feq!( + v, + vec![ + 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, 220.0, + 220.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, + 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, 440.0, + 440.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, 880.0, + 880.0 + ] + ); }