From 2ec533edca424e3571b496e1fb4b6b7e0a162ddf Mon Sep 17 00:00:00 2001 From: Christopher Arndt Date: Mon, 29 Apr 2024 15:31:28 +0200 Subject: [PATCH] Add cutoff param smoothing in multimode_filter example Signed-off-by: Christopher Arndt --- examples/multimode_filter.nim | 8 ++++++-- examples/paramsmooth.nim | 35 +++++++++++++++++++++++++++++++++++ examples/svf.nim | 10 +--------- 3 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 examples/paramsmooth.nim diff --git a/examples/multimode_filter.nim b/examples/multimode_filter.nim index 5bfe683..8604d66 100644 --- a/examples/multimode_filter.nim +++ b/examples/multimode_filter.nim @@ -2,6 +2,7 @@ import nymph +import paramsmooth import svf const PluginUri = "urn:nymph:examples:multimode-filter" @@ -19,6 +20,7 @@ type q: ptr cfloat mode: ptr cfloat svf: FilterSV + smoothCutoff: ParamSmooth proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble; @@ -26,6 +28,7 @@ proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble; Lv2Handle {.cdecl.} = let plug = createShared(SVFPlugin) plug.svf = initFilterSV(fmLowPass, sampleRate) + plug.smoothCutoff = initParamSmooth(20.0, sampleRate) return plug @@ -56,12 +59,13 @@ proc activate(instance: Lv2Handle) {.cdecl.} = proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = let plug = cast[ptr SVFPlugin](instance) + let cutoff = plug.cutoff[].clamp(16.0, 7_000.0) plug.svf.setMode(plug.mode[].int.clamp(0, 3).FilterMode) - plug.svf.setCutoff(plug.cutoff[].clamp(16.0, 7_000.0)) plug.svf.setQ(plug.q[].clamp(0.8, 10.0)) - plug.svf.calcCoef() for pos in 0 ..< nSamples: + plug.svf.setCutoff(plug.smoothCutoff.process(cutoff)) + plug.svf.calcCoef() plug.output[pos] = plug.svf.process(plug.input[pos]) diff --git a/examples/paramsmooth.nim b/examples/paramsmooth.nim new file mode 100644 index 0000000..5cd08d6 --- /dev/null +++ b/examples/paramsmooth.nim @@ -0,0 +1,35 @@ +## One-pole LPF for smooth parameter changes +## +## https://www.musicdsp.org/en/latest/Filters/257-1-pole-lpf-for-smooth-parameter-changes.html + +import math + +const TwoPi = PI * 2 + +type + ParamSmooth* = object + a, b, t, z: float + fs: float64 + + +proc reset*(self: var ParamSmooth) = + self.z = 0.0 + + +proc setSampleRate*(self: var ParamSmooth, sampleRate: float64) = + if sampleRate != self.fs: + self.fs = sampleRate + self.a = exp(-TwoPi / (self.t * 0.001 * sampleRate)) + self.b = 1.0 - self.a + self.z = 0.0 + + +proc process*(self: var ParamSmooth, sample: float): float = + self.z = (sample * self.b) + (self.z * self.a) + return self.z + + +proc initParamSmooth*(smoothingTimeMs: float = 20.0, sampleRate: float64 = 48_000.0): ParamSmooth = + result.t = smoothingTimeMs + result.setSampleRate(sampleRate) + diff --git a/examples/svf.nim b/examples/svf.nim index fe0e9db..095c7bf 100644 --- a/examples/svf.nim +++ b/examples/svf.nim @@ -11,15 +11,7 @@ type FilterSV* = object mode: FilterMode - cutoff: float - q: float - lowPass: float - hiPass: float - bandPass: float - bandReject: float - a: float - b: float - maxCutoff: float + cutoff, q, lowPass, hiPass, bandPass, bandReject, a, b, maxCutoff: float sampleRate: float64 needs_update: bool