2017-05-18 3 views
1

Ich arbeite an der Einbettung von CSound in Lisp. CSound is a music synthesis (and more) open source software.Einbetten von CSound in Common Lisp

Es hat eine ziemlich einfache (Scripting) Sprache. Schnellstart (10 Minuten gelesen) ist unter dem obigen Link verfügbar. Momentan arbeite ich nur an dem Zuweisungsteil (was ein großer Teil der csound-Sprache ist).

Hier ist mein Code:

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

Um zu zeigen, was der Code tut:

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

Ausgänge:

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 

Diese in jeder Hinsicht korrekt ist, außer, „MOOGLADDER ifreq, iAMP "erscheint zweimal.

Warum ist das? Ich kann nicht herausfinden, wo es zweimal ausgewertet wird. Wie beseitige ich diese Wiederholung?


Hinweise über den Code:

  • Csound hat das Konzept von a, k und i Variablen bewerten. Dies ist seltsam als Präfix für das variable Symbol implementiert. Das am nächsten liegende Gegenstück in Lisp würde das einer globalen Variable sein. Also habe ich als solches implementiert. Um jedoch die Rate anzupassen, habe ich eine Indirektions-Ebene zwischen dem Symbol und seinem Wert. z.B. das Symbol 'res hat für seinen Wert' kRes. Nun hat das Symbol 'kRes für seinen Wert das Original 0.4.

  • Die Makros 'op' und 'assign *' sind einfache Wrapper um 'opcode-call' bzw. 'assign'. nativ

  • ‚opcode-call ist eine Funktion, und ermöglicht somit automatisch für normale um Auswertung und damit für verschachtelte Funktionsaufrufe ermöglichen, die csound nicht unterstützt (vollständig). Um dies zu umgehen, sucht opcode-call in seiner Parameterliste nach allen ausgewerteten Opcode-Aufrufen, indem es den Typ (string) überprüft. Wenn es eine Zeichenkette findet, wird diese durch eine gensym Variable ersetzt.

  • Jeder Assign-Aufruf fügt die Zuweisung zur Liste der Assign-Anweisungen hinzu, die dann schließlich zur Ausgabe in die csound-Sprache verwendet wird.

+0

Opcode-Aufruf erzeugt zur Laufzeit ein Assign-Form und wertet sie aus? Ist das eine gute Idee? –

Antwort

4

Ihr Makro ASSIGN lässt den Wert zweimal berechnen. Siehe den Kommentar unten.

(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) 
     (push (format nil "~A = ~A" ,name ,var) ; <- use the var 
      *assign-statements*)))) 

Versuchen Sie es:

CL-USER 52 > (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 
aG2719 = MOOGLADDER iFREQ, iAMP 
kENV = MADSR aG2719, iATT, iDEC, iSUS, iREL 
NIL 
+0

Danke! Über das Auswerten des Zuweisungsformulars zur Laufzeit: Ich weiß nicht, ob es eine gute Idee ist.Wollen Sie damit sagen, dass dies zu nicht standardmäßigen Interaktionen zwischen Laufzeit und Kompilierzeit führt und unnötige Komplexität erzeugt, die vielleicht vermieden werden sollte? –