This is a variation of the standard Nyquist ENV function, where the ‘decay’ and ‘release’ phases are exponential rather than linear.
(see: http://www.cs.cmu.edu/~rbd/doc/nyquist/part8.html#index350
and http://www.cs.cmu.edu/~rbd/doc/nyquist/part2.html#index34)
;; Same as the ENV fuction except :
;; 1) The release and decay stages are exponential rather than linear.
;; 2) The additional optional parameter 'epsilon' [dB] determines the closeness to
;; zero of the decay tail [offset by -ve epsilon so as to decay to zero].
;; 3) If (t1 + t2 + t4 - duration) ['sustain' (t3) = 0], the envelope retains 2 decay phases.
(defun envelope (t1 t2 t4 l1 l2 l3 &optional (duration 1.0) (epsilon -60))
(let ((eps (db-to-linear epsilon))
(actual-dur (get-duration duration))
min-dur ratio t3)
(setf min-dur (+ t1 t2 t4))
(cond
((< actual-dur min-dur)
(setf ratio (/ t1 (float (+ t1 t4))))
(setf t1 (* ratio actual-dur))
(setf t2 (- actual-dur t1))
(setf t3 0.0)
(setf t4 0.0)
(setf l2 0.0)
(setf l3 0.0))
(t
(setf t3 (- actual-dur t1 t2 t4))))
(let ((t2 (+ t1 t2)) ;cumulative time
(t3 (- actual-dur t4))
(l1eps (+ l1 eps)) ;offset exponential curve
(l2eps (+ l2 eps))
(l3eps (+ l3 eps)))
(set-logical-stop
(abs-env (at *rslt*
(sim
(- eps) ;compensate for offset
(pwl t1 l1 t1 0 t2 0 t2 l2 t3 l3 t3 0 actual-dur)
(pwev eps t1 eps t1 l1eps t2 l2eps t2 eps t3 eps t3 l3eps actual-dur eps))))
duration))))
Example usage:
;version 4
;type generate
(defun envelope (t1 t2 t4 l1 l2 l3 &optional (duration 1.0) (epsilon -60))
(let ((eps (db-to-linear epsilon))
(actual-dur (get-duration duration))
min-dur ratio t3)
(setf min-dur (+ t1 t2 t4))
(cond
((< actual-dur min-dur)
(setf ratio (/ t1 (float (+ t1 t4))))
(setf t1 (* ratio actual-dur))
(setf t2 (- actual-dur t1))
(setf t3 0.0)
(setf t4 0.0)
(setf l2 0.0)
(setf l3 0.0))
(t
(setf t3 (- actual-dur t1 t2 t4))))
(let ((t2 (+ t1 t2)) ;cumulative time
(t3 (- actual-dur t4))
(l1eps (+ l1 eps)) ;offset exponential curve
(l2eps (+ l2 eps))
(l3eps (+ l3 eps)))
(set-logical-stop
(abs-env (at *rslt*
(sim
(- eps) ;compensate for offset
(pwl t1 l1 t1 0 t2 0 t2 l2 t3 l3 t3 0 actual-dur)
(pwev eps t1 eps t1 l1eps t2 l2eps t2 eps t3 eps t3 l3eps actual-dur eps))))
duration))))
(setf duration 2.5)
(stretch-abs duration
(mult
(envelope 0.03 0.1 0.5 1.0 0.5 0.4)
(fmosc 70 (mult 12 (hzosc 6 *tri-table*)) *tri-table*)))