diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 3d0ed2b..365926b 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -799,7 +799,8 @@ impl Comb { #[inline] pub fn next_feedback(&mut self, time: f32, g: f32, v: f32) -> f32 { let s = self.delay.cubic_interpolate_at(time); - self.delay.feed(v + s * g); + let v = v + s * g; + self.delay.feed(v); v } diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index 1b48d70..9908ec1 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -38,6 +38,8 @@ mod node_bosc; mod node_vosc; #[allow(non_upper_case_globals)] mod node_biqfilt; +#[allow(non_upper_case_globals)] +mod node_comb; pub mod biquad; pub mod tracker; @@ -73,6 +75,7 @@ use crate::fa_biqfilt_type; use crate::fa_biqfilt_ord; use crate::fa_vosc_ovrsmpl; use crate::fa_distort; +use crate::fa_comb_mode; use node_amp::Amp; use node_sin::Sin; @@ -93,6 +96,7 @@ use node_mix3::Mix3; use node_bosc::BOsc; use node_vosc::VOsc; use node_biqfilt::BiqFilt; +use node_comb::Comb; pub const MIDI_MAX_FREQ : f32 = 13289.75; @@ -489,7 +493,7 @@ define_exp!{n_declick d_declick 0.0, 50.0} define_exp!{n_env d_env 0.0, 1000.0} define_exp!{n_time d_time 0.5, 5000.0} -define_exp!{n_ftme d_ftme 0.25, 1000.0} +define_exp!{n_ftme d_ftme 0.1, 1000.0} // Special linear gain factor for the Out node, to be able // to reach more exact "1.0". @@ -641,6 +645,12 @@ macro_rules! node_list { (1 time n_ftme d_ftme r_fms f_ms stp_m 0.0, 1.0, 25.0) (2 g n_id d_id r_id f_def stp_d -1.0, 1.0, 0.7) [0 sig], + comb => Comb UIType::Generic UICategory::Signal + (0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + (1 time n_ftme d_ftme r_fms f_ms stp_m 0.0, 1.0, 25.0) + (2 g n_id d_id r_id f_def stp_d -1.0, 1.0, 0.7) + {3 0 mode setting(0) fa_comb_mode 0 1} + [0 sig], noise => Noise UIType::Generic UICategory::Osc (0 atv n_id d_id r_id f_def stp_d -1.0, 1.0, 0.5) (1 offs n_id d_id r_s f_def stp_d -1.0, 1.0, 0.0) diff --git a/src/dsp/node_comb.rs b/src/dsp/node_comb.rs new file mode 100644 index 0000000..daf1044 --- /dev/null +++ b/src/dsp/node_comb.rs @@ -0,0 +1,116 @@ +// Copyright (c) 2021 Weird Constructor +// 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; + +#[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", + _ => "?", + }; + write!($formatter, "{}", s) +} } } + + +/// A simple amplifier +#[derive(Debug, Clone)] +pub struct Comb { + comb: Box, +} + +impl Comb { + pub fn new(_nid: &NodeId) -> Self { + 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 = + "Comb g\nThe internal factor for the comb filter.\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 \ + feedback or feedforward 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 + +This is a comb filter that can be used for filtering +as well as for building reverbs or anything you might +find it useful for. + +For typical arrangements in combination with allpass filters, +see the documentation of the 'Comb' node! +"#; +} + +impl DspNode for Comb { + fn outputs() -> usize { 1 } + + fn set_sample_rate(&mut self, srate: f32) { + self.comb.set_sample_rate(srate); + } + + fn reset(&mut self) { + self.comb.reset(); + } + + #[inline] + fn process( + &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}; + + 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 mode = at::Comb::mode(atoms); + + let c = &mut *self.comb; + + if mode.i() == 0 { + 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)); + } + } else { + for frame in 0..ctx.nframes() { + let v = inp.read(frame); + + out.write(frame, + c.next_feedforward( + denorm::Comb::time(time, frame), + denorm::Comb::g(g, frame), + v)); + } + } + + let last_frame = ctx.nframes() - 1; + ctx_vals[0].set(out.read(last_frame)); + } +} diff --git a/src/dsp/node_sfilter.rs b/src/dsp/node_sfilter.rs index c169c94..4bdcf92 100644 --- a/src/dsp/node_sfilter.rs +++ b/src/dsp/node_sfilter.rs @@ -122,7 +122,8 @@ Next page: more filters (eg. Moog) SFilter - Simple Audio Filter Collection For a more colored filter reach for the Stilson/Moog filter with a 24dB -fall off per octave. +fall off per octave. Beware high cutoff frequencies for this filter, +as it can become quite unstable. LP 24m - Low-pass Stilson/Moog filter (24dB) HP 24m - High-pass Stilson/Moog filter (24dB)