#lang typed/racket
(require racket/flonum)
(require/typed "rsound.rkt"
[default-sample-rate (-> Real)])
(provide response/raw
response/mag
roots->poly
coefficients->poly
poles&zeros->poly
coefficient-sets->poly
roots->coefficients
chebyshev-s-poles
s-space->z-space
real-part/ck
lpf-coefficients
lpf-tap-vectors
up-to-power-of-two
all-but-n
product-of
sum-of
num-poles
zeros-at-negative-one)
(: i Complex)
(define i (exact->inexact (sqrt -1)))
(define twopi (* 2 pi))
(define-type Poly (Complex -> Complex))
(define-type Z-Plane-Points (Listof Complex))
(define-type Zeros Z-Plane-Points)
(define-type Poles Z-Plane-Points)
(define-type Coefficients (Listof Real))
(define-type Frequency Nonnegative-Real)
(define-type Signal (-> Real))
(define-type Network1 (Flonum -> Flonum))
(: response/raw (Poly -> Frequency -> Complex))
(define (response/raw poly)
(define sr-inv (exact->inexact
(/ 1 (default-sample-rate))))
(lambda (omega)
(define z (exp (* i sr-inv twopi omega)))
(poly z)))
(: response/mag (Poly Boolean -> Frequency -> Real))
(define ((response/mag poly db?) frequency)
(define mag (exact->inexact
(magnitude ((response/raw poly) frequency))))
(cond [db? (mag->db mag)]
[else mag]))
(: mag->db (Inexact-Real -> Real))
(define (mag->db mag)
(* 10 (/ (ann (log (ann (filter-out-nan (max 1.0e-6 mag))
Positive-Real))
Real)
(/ (log 10) 2))))
(: roots->poly (Zeros -> Poly))
(define (roots->poly roots)
(coefficients->poly (roots->coefficients roots)))
(: coefficients->poly (Coefficients -> Poly))
(define ((coefficients->poly coefficients) x)
(for/fold: ([so-far : Complex 0.0+0.0i])
([coefficient (in-list coefficients)])
(+ coefficient (* so-far x))))
(: poles&zeros->poly (Poles Zeros -> Poly))
(define (poles&zeros->poly poles zeros)
(coefficient-sets->poly (roots->coefficients zeros)
(roots->coefficients poles)))
(: coefficient-sets->poly (Coefficients Coefficients -> Poly))
(define (coefficient-sets->poly ff-coefficients fb-coefficients)
(let ([feedback-poly (coefficients->poly fb-coefficients)]
[feedforward-poly (coefficients->poly ff-coefficients)])
(lambda (x)
(/ (feedforward-poly x)
(feedback-poly x)))))
(: roots->coefficients (Z-Plane-Points -> (Listof Flonum)))
(define (roots->coefficients z-plane-points)
(let ([neg-points (map - z-plane-points)])
(reverse
(for/list: ([exponent : Exact-Nonnegative-Integer
(ann
(in-range 0
(add1 (length neg-points)))
(Sequenceof Nonnegative-Fixnum))])
(real-part/ck
(sum-of (map product-of (all-but-n exponent neg-points))))))))
(: lpf-coefficients (Real -> (Listof Flonum)))
(define (lpf-coefficients scale)
(define pre-warped (* 2.0 (tan (/ scale 0.5))))
(define s-poles (map (lambda: ([x : Complex])
(* pre-warped x))
chebyshev-s-poles))
(define z-poles (map s-space->z-space s-poles))
(roots->coefficients z-poles))
(: lpf-tap-vectors (Real -> (Vector FlVector FlVector Real)))
(define (lpf-tap-vectors scale)
(define coefficients (lpf-coefficients scale))
(define gain (/ (apply + coefficients)
zeros-at-negative-one/sum))
(define tap-multipliers
(apply flvector
(map (lambda: ([x : Flonum]) (* x -1.0))
(cdr coefficients))))
(vector zeros-at-negative-one/flvec tap-multipliers gain))
(define num-poles 4)
(define no-zeros (list 1.0 0.0 0.0 0.0 0.0))
(define no-zeros/sum 1.0)
(define no-zeros/flvec (apply flvector (cdr no-zeros)))
(define zeros-at-negative-one (list 1.0 4.0 6.0 4.0 1.0))
(define zeros-at-negative-one/sum (apply + zeros-at-negative-one))
(define zeros-at-negative-one/flvec (apply flvector (cdr zeros-at-negative-one)))
(: chebyshev-s-poles Poles)
(define chebyshev-s-poles
(let ()
(define epsilon 0.5)
(define left-half
(for/list: : (Listof Complex)
([m (in-range num-poles)])
(* i (cos (+ (* (/ 1 num-poles)
(acos (/ i epsilon)))
(/ (* pi m) num-poles))))))
left-half))
(define-predicate float? Float)
(: fir-filter ((Listof (List Nonnegative-Fixnum Real)) -> Network1))
(define (fir-filter params)
(match params
[`((,delays ,amplitudes) ...)
(: max-delay Index)
(define max-delay
(up-to-power-of-two (+ 1 (apply max delays))))
(define wraparound-limit (- max-delay 1))
(: wraparound (Index -> Index))
(define (wraparound idx)
(cond [(<= wraparound-limit idx) 0]
[else (ensure-index (add1 idx))]))
(: delay-buf (Vectorof Float))
(define delay-buf (make-vector max-delay 0.0))
(: next-idx Index)
(define next-idx 0)
(: delays/t (Listof Nonnegative-Integer))
(define delays/t
(cond [(andmap exact-nonnegative-integer? delays)
delays]
[(error 'impossible "Make TR happy")]))
(define amplitudes/real
(cond [(andmap real? amplitudes)
amplitudes]
[(error 'impossible "Make TR happy")]))
(: amplitudes/t (Listof Float))
(define amplitudes/t
(map (ann real->double-flonum (Real -> Flonum)) amplitudes/real))
(lambda: ([this-val : Float])
(vector-set! delay-buf next-idx this-val)
(define result
(for/fold:
([sum : Float 0.0])
([d (in-list delays/t)]
[a (in-list amplitudes/t)])
(define offset-idx (- next-idx d))
(define wrapped
(cond [(< offset-idx 0)
(ensure-index (+ offset-idx max-delay))]
[(<= max-delay offset-idx)
(ensure-index (- offset-idx max-delay))]
[else offset-idx]))
(+ sum
(* a (vector-ref delay-buf wrapped)))))
(set! next-idx (wraparound next-idx))
result)]
[other (raise-type-error 'fir-filter "(listof (list number number))" 0 params)]))
(: ensure-index (Integer -> Index))
(define (ensure-index n)
(cond [(index? n) n]
[else (raise-type-error 'ensure-index "Index" 0 n)]))
(: s-space->z-space (Complex -> Complex))
(define (s-space->z-space pole)
(exp pole)
(/ (+ 1.0 (/ pole 2.0))
(- 1.0 (/ pole 2.0))))
(: sum-of ((Listof Complex) -> Complex))
(define (sum-of l) (foldl + 0.0+0.0i l))
(: product-of ((Listof Complex) -> Complex))
(define (product-of l) (foldl * 1.0+0.0i l))
(: all-but-n (All (T) (Natural (Listof T) -> (Listof (Listof T)))))
(define (all-but-n n-in l)
(define n (ann n-in Integer))
(cond [(<= n 0) (list l)]
[(= n (length l)) (list '())]
[else
(define drop-this-one
(all-but-n (- n 1 ) (cdr l)))
(define keep-this-one
(map (lambda: ([x : (Listof T)])
(cons (car l) x))
(all-but-n n (cdr l))))
(append drop-this-one keep-this-one)]))
(: foo (Integer -> Natural))
(define (foo n)
(cond [(<= n 0) 13]
[else
(ann (- n 1) Natural)]))
(: real-part/ck (Complex -> Flonum))
(define (real-part/ck i)
(define angl (angle i))
(define wrapped-angle (cond [(< angl (- (/ pi 2))) (+ angl (* 2 pi))]
[else angl]))
(cond [(< (abs wrapped-angle) angle-epsilon)
(real->double-flonum (magnitude i))]
[(< (abs (- pi wrapped-angle)) angle-epsilon)
(- (real->double-flonum (magnitude i)))]
[else (error 'real-part/ck "angle ~s of complex number ~s is not close to zero or pi." wrapped-angle i)]))
(define angle-epsilon 1e-5)
(: up-to-power-of-two (Index -> Index))
(define (up-to-power-of-two n)
(define log-2 (log 2))
(define log-2-n (log (max n 1)))
(cond [(<= log-2-n 0) (error 'up-to-power-of-two
"impossible, make TR happy.")]
[(<= log-2 0) (error 'up-to-power-of-two
"impossible, make TR happy.")]
[else
(ensure-index
(expt 2 (ceiling
(inexact->exact
(/ log-2-n log-2)))))]))
(define-predicate is-irnan? Inexact-Real-Nan)
(: filter-out-nan ((U Positive-Inexact-Real Inexact-Real-Nan)
->
Positive-Inexact-Real))
(define (filter-out-nan n)
(cond [(is-irnan? n) (error 'boo)]
[else n]))