nymph/examples/svf.nim

90 lines
2.2 KiB
Nim

## State Variable Filter after Hal Chamberlin, Musical Applications of Microprocessors
##
## Only stable up to fc ~= fs / 6.5 !
## Sensible range for q ~= 0.8 .. 10.0
import std/math
type
FilterMode* = enum
fmLowPass, fmHighPass, fmBandPass, fmBandReject
FilterSV* = object
mode: FilterMode
cutoff, q, lowPass, hiPass, bandPass, bandReject, a, b, maxCutoff: float
sampleRate: float64
needs_update: bool
proc reset*(self: var FilterSV) =
self.lowPass = 0.0
self.hiPass = 0.0
self.bandPass = 0.0
self.bandReject = 0.0
proc initFilterSV*(mode: FilterMode = fmLowPass, sampleRate: float64 = 48_000.0): FilterSV =
result.mode = mode
result.sampleRate = sampleRate
result.reset()
result.a = 0.0
result.b = 0.0
result.maxCutoff = sampleRate / 6.0
result.needs_update = true
proc calcCoef*(self: var FilterSV) =
if self.needs_update:
self.a = 2.0 * sin(PI * self.cutoff / self.sampleRate)
if self.q > 0.0:
self.b = 1.0 / self.q
else:
self.b = 0.0
self.needs_update = false
proc setCutoff*(self: var FilterSV, cutoff: float) =
let fc = min(self.maxCutoff, cutoff)
if fc != self.cutoff:
self.cutoff = fc
self.needs_update = true
proc setQ*(self: var FilterSV, q: float) =
if q != self.q:
self.q = q
self.needs_update = true
proc setMode*(self: var FilterSV, mode: FilterMode) =
self.mode = mode
proc setSampleRate*(self: var FilterSV, sampleRate: float) =
if sampleRate != self.sampleRate:
self.sampleRate = sampleRate
self.needs_update = true
self.reset()
self.calcCoef()
proc process*(self: var FilterSV, sample: float): float =
self.lowPass += self.a * self.bandPass
self.hiPass = sample - (self.lowPass + (self.b * self.bandPass))
self.bandPass += self.a * self.hiPass
self.bandReject = self.hiPass + self.lowPass
case self.mode:
of fmLowPass:
return self.lowPass
of fmHighPass:
return self.hiPass
of fmBandPass:
return self.bandPass
of fmBandReject:
return self.bandReject