;; Q is usually around 0.5
;; gain is either a boost up to +5.0db or a reduction down to -24.0db
(bind-func static lshelf_c
"low shelf filter: returns filtering closure which implements a state variable filter"
(lambda ()
(let ((ic1eq 0.0) (ic2eq 0.0)
(A 0.0)
(g 0.0)
(k 0.0)
(a1 0.0) (a2 0.0) (a3 0.0)
(m0 1.0) (m1 1.0) (m2 1.0)
(ogain -1000000.0) (ocutoff -1.0) (oQ -1.0)
(v1 0.0) (v2 0.0) (v3:SAMPLE 0.0))
(lambda (in cutoff gain Q)
(if (or (<> gain ogain)
(<> cutoff ocutoff)
(<> Q oQ))
(begin
;; negative frq & res
(if (< cutoff 0.0) (set! cutoff (fabs cutoff)))
(if (< Q 0.0) (set! Q (fabs Q)))
(set! ogain gain)
(set! ocutoff cutoff)
(set! oQ Q)
;; one option: do the check (= res oldres) trick here
(set! A (pow 10.0 (/ gain 40.0)))
(set! g (/ (tan (* SPI (/ cutoff SRs)))
(sqrt A)))
(set! k (/ 1.0 (+ Q 0.0000001)))
(set! a1 (/ 1.0 (+ 1.0 (* g (+ g k)))))
(set! a2 (* g a1))
(set! a3 (* g a2))
(set! m0 1.0)
(set! m1 (* k (- A 1.0)))
(set! m2 (- (* A A) 1.0))))
(set! v3 (- in ic2eq))
(set! v1 (+ (* a1 ic1eq) (* a2 v3)))
(set! v2 (+ ic2eq (* a2 ic1eq) (* a3 v3)))
(set! ic1eq (- (* 2.0:f v1) ic1eq))
(set! ic2eq (- (* 2.0 v2) ic2eq))
(+ in (* m1 v1) (* m2 v2))))))