[CM] CLM power-env
Michael Klingbeil
michael@klingbeil.com
Tue, 25 Feb 2003 13:52:21 -0500
I think I have managed to get the power-env stuff in "env.lisp" to
work (at least with C compilation). The idea of power-env is to allow
each envelope segment to have a base parameter to control the
concavity.
Anyway the version in env.lisp didn't seem to work. There were two
problems: envelope class type is now "seg" rather than "envelope",
and "seg-end" is not supported by the run macro.
So I tried something like this to support seg-end in run:
(def-clm-fun 'seg-end #'(lambda (var x) (pushnew 'seg-end
methods) (package-op '<seg-end> var x :clm-integer)))
(add-clm-method
'seg-end +env+
#'(lambda () "clm_int[gen_addr+5]")
nil)
But this didn't seem to quite work. I concluded that I would have
needed to to change this in cmus.lisp
(defun method-type (method)
(if (member method '(mus-length mus-channel mus-location
mus-channels mus-order mus-cosines))
'int
(if (member method '(mus-data mus-xcoeffs mus-ycoeffs seg-end))
'int
'double)))
I didn't really want to mess around with cmus.lisp (Also shouldn't
the return type be stored in the clm-methods table?? package-op seems
to take a return type parameter as well, so the method-type defun
looks like a hack to me... but maybe I am wrong about that!)
Anyway, I decided to just use mus-length instead of seg-end since
there was no mus-length method for envelopes. There is probably a
better way to do this and I'm open to suggestions!
So here is my result:
(in-package :clm)
;;; extension of env to provide individual base on each segment
(include 1 and 0 => linear and step)
;;; (make-power-env (envelope (scaler 1.0) (offset 0.0) duration)
;;; returns a penv struct containing an array of envelopes
;;; where the envelope is a sequence of triples [x y base]
(def-clm-struct penv envs total-envs current-env current-pass)
(add-clm-method
'mus-length +env+
#'(lambda () "clm_int[gen_addr+5]")
nil)
(defmacro power-env (pe1)
`(let* ((pe ,pe1)
(val (env (aref (penv-envs pe) (penv-current-env pe)))))
(decf (penv-current-pass pe))
(when (zerop (penv-current-pass pe))
(when (< (penv-current-env pe) (penv-total-envs pe))
(incf (penv-current-env pe))
(setf (penv-current-pass pe) (mus-length (aref (penv-envs pe)
(penv-current-env pe))))))
val))
(defun make-power-env (&key envelope (scaler 1.0) (offset 0.0) duration)
(let* ((len (1- (floor (length envelope) 3)))
(pe (make-penv :envs (make-array len :element-type 'seg)
:total-envs len
:current-env 0
:current-pass 0))
(xext (- (nth (- (length envelope) 3) envelope) (first envelope))))
(loop for i from 0 below len and
x0 in envelope by #'cdddr and y0 in (cdr envelope) by
#'cdddr and base in (cddr envelope) by #'cdddr and
x1 in (cdddr envelope) by #'cdddr and y1 in (cddddr
envelope) by #'cdddr do
(setf (aref (penv-envs pe) i)
(make-env :envelope (list 0.0 y0 1.0 y1)
:base base
:scaler scaler
:offset offset
:duration (* duration (/ (- x1 x0) xext)))))
(setf (penv-current-pass pe) (seg-end (aref (penv-envs pe) 0)))
pe))