diff --git a/src/dsp/node_sampl.rs b/src/dsp/node_sampl.rs index 543ead4..7e0e2c9 100644 --- a/src/dsp/node_sampl.rs +++ b/src/dsp/node_sampl.rs @@ -8,11 +8,13 @@ use crate::dsp::{SAtom, ProcBuf, DspNode, LedPhaseVals}; /// A simple amplifier #[derive(Debug, Clone)] pub struct Sampl { + sample_idx: usize, } impl Sampl { pub fn new() -> Self { Self { + sample_idx: 0, } } pub const freq : &'static str = @@ -35,15 +37,26 @@ impl DspNode for Sampl { &mut self, ctx: &mut T, atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) { - use crate::dsp::{out}; //, inp, denorm, denorm_v, inp_dir, at}; + use crate::dsp::{out, at, inp, denorm}; //, inp, denorm, denorm_v, inp_dir, at}; -// let gain = inp::Amp::gain(inputs); -// let att = inp::Amp::att(inputs); -// let inp = inp::Amp::inp(inputs); - let out = out::Sampl::sig(outputs); + let sample = at::Sampl::sample(atoms); + let freq = inp::Sampl::freq(inputs); + let out = out::Sampl::sig(outputs); - for frame in 0..ctx.nframes() { - out.write(frame, 0.0); + if let SAtom::AudioSample((_, Some(sample_data))) = sample { + let sd_len = sample_data.len() - 1; + + for frame in 0..ctx.nframes() { + let speed = denorm::Sampl::freq(freq, frame) / 440.0; + + let sd = sample_data[self.sample_idx % sd_len + 1]; + out.write(frame, sd); + self.sample_idx += (1.0 * speed).ceil() as usize; + } + } else { + for frame in 0..ctx.nframes() { + out.write(frame, 0.0); + } } ctx_vals[0].set(1.0); diff --git a/src/nodes/node_conf.rs b/src/nodes/node_conf.rs index f18d399..fa66d6f 100644 --- a/src/nodes/node_conf.rs +++ b/src/nodes/node_conf.rs @@ -12,6 +12,7 @@ use super::{ }; 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 @@ -142,6 +143,10 @@ pub struct NodeConfigurator { feedback_filter: FeedbackFilter, + /// Loads and Caches audio samples that are set as parameters + /// for nodes. + sample_lib: SampleLibrary, + /// Contains (automateable) parameters params: std::collections::HashMap, /// Stores the most recently set parameter values @@ -226,6 +231,7 @@ impl NodeConfigurator { (NodeConfigurator { nodes, shared, + sample_lib: SampleLibrary::new(), feedback_filter: FeedbackFilter::new(), output_fb_values: vec![], output_fb_cons: None, @@ -292,6 +298,13 @@ 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 { + self.sample_lib.load(&path).unwrap().clone() + } else { + at + }; + self.atom_values.insert(param, at.clone()); if let Some(nparam) = self.atoms.get_mut(¶m) { diff --git a/src/sample_lib.rs b/src/sample_lib.rs index 0c0a79f..c5d603b 100644 --- a/src/sample_lib.rs +++ b/src/sample_lib.rs @@ -64,7 +64,9 @@ impl SampleLibrary { }, hound::SampleFormat::Int => { for s in rd.samples::().step_by(channels) { - v.push(s? as f32 / (i16::MAX as f32)); + let s = s?; + let s = s as f32 / (i16::MAX as f32); + v.push(s); } }, }; diff --git a/tests/basics.rs b/tests/basics.rs index 9cbfc32..2e51a9e 100644 --- a/tests/basics.rs +++ b/tests/basics.rs @@ -1105,3 +1105,37 @@ fn check_matrix_output_feedback() { assert_float_eq!(fo_amp.1, 0.11627); } + +#[test] +fn check_node_sampl_1() { + 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)); + matrix.sync().unwrap(); + + let sample_p = smpl.inp_param("sample").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); + assert_float_eq!(rms, 0.505); + assert_float_eq!(min, -0.9998); + assert_float_eq!(max, 1.0); + + let fft = run_and_get_fft4096(&mut node_exec, 800, 0.0); + assert_eq!(fft[0], (441, 940)); + + matrix.set_param(freq_p, SAtom::param(0.1)); + let fft = run_and_get_fft4096(&mut node_exec, 800, 0.0); + assert_eq!(fft[0], (894, 988)); + + matrix.set_param(freq_p, SAtom::param(-0.1)); + let fft = run_and_get_fft4096(&mut node_exec, 800, 0.0); + assert_eq!(fft[0], (220, 988)); +}