diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 6b0d7c0..ffe1700 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -1304,6 +1304,26 @@ impl PolyBlepOscillator { s } + + #[inline] + pub fn next_pulse_no_dc(&mut self, freq: f32, israte: f32, pw: f32) -> f32 { + let phase_inc = freq * israte; + + let pw = (0.1 * pw) + ((1.0 - pw) * 0.5); // some scaling + + 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); + + self.phase += phase_inc; + self.phase = self.phase.fract(); + + s + } } //pub struct UnisonBlep { diff --git a/src/dsp/node_bosc.rs b/src/dsp/node_bosc.rs index 3796c18..ecad029 100644 --- a/src/dsp/node_bosc.rs +++ b/src/dsp/node_bosc.rs @@ -3,8 +3,11 @@ // 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::PolyBlepOscillator; +use crate::dsp::{ + NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext, + GraphAtomData, GraphFun, +}; +use crate::dsp::helpers::{PolyBlepOscillator, lerp}; #[macro_export] macro_rules! fa_bosc_wtype { ($formatter: expr, $v: expr, $denorm_v: expr) => { { @@ -144,4 +147,45 @@ impl DspNode for BOsc { ctx_vals[0].set(out.read(ctx.nframes() - 1)); } + + fn graph_fun() -> Option { + let mut osc = Box::new(PolyBlepOscillator::new(0.0)); + let israte = 1.0 / 128.0; + + 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 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 det = gd.get_norm(det as u32); + + // the detune scaling with lerp is wrong... + // let pow = lerp((det + 0.2) * (1.0 / 0.4), 0.25, 4.0); + // let freq = (2.0_f32).powf(pow); + let freq = 2.0; + + if init { + osc.reset(); + if wtype == 1 { + // 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); } + } + } + + 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 + })) + } }