Envelope function

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*)))