2017-05-18 1 views
1

나는 CSound를 Lisp에 포함시키고있다. CSound is a music synthesis (and more) open source software.CSound를 Common Lisp에 포함하기

매우 간단한 (스크립팅) 언어입니다. 위의 링크에서 빠른 시작 (10 분 읽기)을 사용할 수 있습니다. 현재 저는 과제 부분 (csound 언어의 상당 부분)을 다루고 있습니다. ,

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 :

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

출력 :

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

코드가 무엇을 보여주기 위해 :

여기 내 코드입니다 iAMP "가 두 번 나타납니다.

왜인가요? 나는 그것이 두 번 평가되는 것을 파악할 수 없다. 이 반복을 어떻게 제거합니까? 코드 약


주 :

  • CSound에은 (A)의 개념 (k)를 가지고 있는데이 변수를 평가. 이것은 이며 이상하게 변수 심볼의 접두사로 구현됩니다. lisp에서 가장 가까운 은 글로벌 변수의 것입니다. 그래서 나는 을 이와 같이 구현했습니다. 그러나 비율을 수용하기 위해 나는 심볼과 그 값 사이에 간접적 인 수준을 가지고있다. 예 : 'res의 값은'kRes입니다. 이제 'kRes'기호의 값은 이고 원래 0.4입니다.

  • 매크로 'op 및'assign *은 'opcode-call'및 'assign'주변의 간단한 래퍼입니다.

  • '오피 통화는 기능이며, 따라서 자동으로 따라서 CSound에 기본적하지 (완전)을 지원합니까 중첩 된 함수 호출을 허용, 일반 차 평가를 할 수 있습니다. 이 문제를 해결하기 위해 'opcode-call은 유형이 (문자열)인지 확인하여 매개 변수 목록에서 평가 된 opcode 호출을 찾습니다. 문자열을 찾으면 gensym 변수로 바꿉니다.

  • 각 할당 호출은 할당 문 목록에 할당을 추가하고 마지막으로 csound 언어로 출력하는 데 사용됩니다.

+0

오피 호출은 실행시 할당 형식을 생성하고 평가? 그거 좋은 생각이야? –

답변

4

매크로 ASSIGN 값을 두 번 계산할 수 있습니다. 아래의 설명을 참조하십시오.

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

을보십시오 :

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

고마워요! 런타임에 assign-form을 평가하는 것에 대해 : 좋은 생각인지 나는 모른다.이것이 비표준 방식으로 런타임과 컴파일 타임 간의 상호 작용을 유도하기 때문에 불필요한 복잡성을 야기 할 수 있으며, 이는 아마도 피해야한다는 말입니까? –

관련 문제