(load "blit.lisp") (defun envelope-or-number (in) (if (numberp in) (list 0 in 1 in) in )) (definstrument good-tri (start-time duration frequency &optional (amp 1.0) &key (amp-env '(0 1.0 1.0 1.0)) (freq-env '(0 1 1.0 1)) (leak .995) (leak2 .9995) (limit .1) ;attenuation at Nyquist, affects sharpness of waveform, eliminates Gibb's phenomena (!! Must be less than 1.0) (width 0.5) ;morphs the slope to a lag/lead ramp (can be an envelope) (glide 4) ;exponent of portamento (quartic functions approximate logarithmic behavior) (morph 1.0) ;Morphs even harmonics. 0 = parabola, 1 = triangle. (can be an envelope) (phase 0) ;initial phase, between 0 and 1 ) (multiple-value-bind (beg end) (times->samples start-time duration) (let* ( (blit1 (make-blit-init :frequency frequency :phase phase :nyquist limit)) ;bipolar BLIT is made by subtracting a phase-offset blit (blit2 (make-blit-init :frequency frequency :phase (+ phase 0.5) :nyquist limit)) ;(in this case duty-cycle is 0.5, but will (integrator (make-one-pole :a0 1 :b1 (- leak))) (integrator2 (make-one-pole :a0 1 :b1 (- leak2))) ; (R (-(- 1 (/ 126 *srate*)))) ; -3 dB at 20 Hz ; (dc-block (make-filter :order 2 :xcoeffs '(1 -1) :ycoeffs `(0 ,R) )) (amp (make-env :envelope amp-env :scaler amp :duration duration)) (width (make-env :envelope (envelope-or-number width) :duration duration)) (morph (make-env :envelope (envelope-or-number morph) :duration duration)) (freq (make-env :envelope (envelope-exp freq-env glide) :scaler frequency :duration duration)) ; initialize variables used in run loop f tri duty scale ) (run (loop for i from beg below end do (setf f (env freq) tri (env morph) duty (- 1 (env width)) (blit-phase blit2) (+ (blit-phase blit1) duty) ;set the duty-cycle / ramp slope scale (/ (* 2 (/ f *srate*)) (- duty (* duty duty))) ;scaling factor from Stilson and Smith scale (+ (* tri scale) (* (- 1 tri) 0.01)) ;?? ) (if (blit-wrapped blit1) (set-blit-frequency blit1 f) ) (if (blit-wrapped blit2) (set-blit-frequency blit2 f) ) (outa i (* (env amp) 1.1 ;;scale correction (one-pole integrator2 (* scale (one-pole integrator (- (blit blit1) (* tri (blit blit2))) ))) )) )) )) ) ;;(with-sound () (good-tri 0 5 100 0.3 :width '(0 0.2 1 0.8))) ;(with-sound () (good-tri 0 5 50 0.3 :width .995)) ;makes a decent sawtooth