私はCSoundをLispに埋め込む作業を進めています。 CSound is a music synthesis (and more) open source software.CSoundをCommon Lispに埋め込む
これはかなり単純な(スクリプト言語)です。上記のリンクでは、クイックスタート(10分読み取り)を利用できます。現在私は割り当て部分(csound言語の大部分です)に取り組んでいます。
ここに私のコードです:
(defparameter *assign-statements* nil)
(defmacro assign (_name value &optional (rate 'i))
(let* ((name (if (typep _name 'symbol) _name (eval _name)))
(var (symb (format nil "~(~a~)" rate) name)))
`(progn
(defparameter ,name ',var)
(defparameter ,var ,value)
(setf *assign-statements*
(cons (format nil "~A = ~A" ,name ,value) *assign-statements*)))))
(defmacro assign* (&rest args)
`(progn ,@(mapcar (lambda (arg) (cons 'assign arg)) args)))
(defun opcode-call (opcode &rest args)
(format nil "~a ~{~a~^, ~}" opcode (mapcar (lambda (arg)
(if (stringp arg)
(let ((var (gensym)))
(eval (list 'assign (symb (symbol-name var)) arg 'a))
(symbol-value (symb (symbol-name var))))
arg))
args)))
(defmacro op (opcode &rest args)
`(opcode-call ',opcode ,@args))
コードが何をするかを実証するために:
(progn
(defparameter *assign-statements* nil)
(assign*
(freq 'p4)
(amp 'p5)
(att (+ 0.1 0.1))
(dec 0.4)
(sus 0.6)
(rel 0.7)
(cutoff 5000)
(res 0.4 k)
(env (op madsr (op moogladder freq amp) att dec sus rel) k))
(format t "~{~A~^~%~}~%"
(nreverse *assign-statements*)))
出力:
iFREQ = P4
iAMP = P5
iATT = 0.2
iDEC = 0.4
iSUS = 0.6
iREL = 0.7
iCUTOFF = 5000
kRES = 0.4
aG8707 = MOOGLADDER iFREQ, iAMP
aG8708 = MOOGLADDER iFREQ, iAMP
kENV = MADSR aG8708, iATT, iDEC, iSUS, iREL
NIL
これは、MOOGLADDERいるifreq」を除くすべての点で正確ですiAMP "が2回表示されます。
これはなぜですか?私はそれがどこで2回評価されているのか分かりません。 この繰り返しを削除するにはどうすればよいですか?コードに関する
注:
Csoundファイルは、kの概念を持っていると私は変数を評価。これは、可変記号の接頭辞として奇妙に実装された です。 lispの最も近い は、グローバル変数のものになります。だから私は そのように実装しました。しかし、レートに対応するために、私はシンボルとその値の間に間接参照のレベルを1つ持っています。例えば シンボル 'resには値' kResがあります。今度はシンボル 'kRes'の値は で、元の0.4です。
マクロ 'opと' assign *はそれぞれ 'opcode-call'と 'assign'を囲む単純なラッパーです。
「はオペコードコール機能であるため、自動的にこのよう Csoundファイルがネイティブ(完全)をサポートしていないネストされた関数呼び出しを可能にする、通常 順序評価が可能になります。これを回避するために、 'opcode-callは、それがタイプ (文字列)をチェックすることによって、paramリスト内の評価されたopcode呼び出しを探します。文字列が見つかった場合は、それをgensym 変数に置き換えます。
各割り当て呼び出しは、 割り当てのリストに割り当てを追加し、最後にcsound言語に出力するために使用されます。
オペコード・コールは、実行時に割り当て、フォームを作成し、それを評価しますか?それは良いアイデアですか? –