96 lines
2.3 KiB
Nim
96 lines
2.3 KiB
Nim
|
## State Variable Filter after Hal Chamberlin, Musical Applications of Microprocessors
|
||
|
## Only stable up to fc ~= fs / 6.5 !
|
||
|
|
||
|
import std/math
|
||
|
|
||
|
type
|
||
|
FilterMode* = enum
|
||
|
fmLowPass, fmHighPass, fmBandPass, fmBandReject
|
||
|
|
||
|
FilterSV* = object
|
||
|
mode: FilterMode
|
||
|
cutoff: float
|
||
|
q: float
|
||
|
lowPass: float
|
||
|
hiPass: float
|
||
|
bandPass: float
|
||
|
bandReject: float
|
||
|
a: float
|
||
|
b: float
|
||
|
maxCutoff: float
|
||
|
sampleRate: float
|
||
|
needs_update: bool
|
||
|
|
||
|
|
||
|
proc reset*(self: var FilterSV) =
|
||
|
self.lowPass = 0
|
||
|
self.hiPass = 0
|
||
|
self.bandPass = 0
|
||
|
self.bandReject = 0
|
||
|
|
||
|
|
||
|
proc initFilterSV*(mode: FilterMode = fmLowPass, sampleRate: float = 48_000): FilterSV =
|
||
|
result.mode = mode
|
||
|
result.sampleRate = sampleRate
|
||
|
result.reset()
|
||
|
result.a = 0
|
||
|
result.b = 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 = if cutoff > self.maxCutoff: self.maxCutoff else: 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
|
||
|
|