Common lisp 在公共Lisp中嵌入CSound

Common lisp 在公共Lisp中嵌入CSound,common-lisp,csound,Common Lisp,Csound,我正在致力于在Lisp中嵌入CSound 它有一种相当简单的(脚本)语言。快速启动(10分钟读取)在上面的链接中可用。目前我只做作业部分(这是csound语言的一大部分) 这是我的密码: (defparameter *assign-statements* nil) (defmacro assign (_name value &optional (rate 'i)) (let* ((name (if (typep _name 'symbol) _name (eval _name)))

我正在致力于在Lisp中嵌入CSound

它有一种相当简单的(脚本)语言。快速启动(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”出现两次

这是为什么?我想不出它在哪里被评估了两次。 如何消除这种重复?


关于代码的注释:

  • Csound具有a、k和i比率变量的概念。这是 奇怪地实现为变量符号的前缀。最近的 lisp中的对应项是全局变量。所以我 就这样实施。但是为了适应这个价格,我有一个 符号与其值之间的间接级别。e、 g.会议 符号'res'有其价值'kRes。现在,符号“kRes”已经成为了它的标志 值,原始值为0.4

  • 宏“op”和“assign*分别是围绕“操作码调用”和“assign”的简单包装

  • '操作码调用是一个函数,因此自动允许正常 顺序求值,从而允许嵌套函数调用 csound不(完全)本地支持。为了避免这种情况,“操作码调用”通过检查其类型,在参数列表中查找任何已计算的操作码调用 (字符串)。如果它找到一个字符串,它将用gensym替换该字符串 变数

  • 每次分配调用都会将分配添加到分配列表中 语句,然后最终用于输出到csound语言


您的宏
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*))))

您的宏
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*))))

操作码调用在运行时创建分配表单并对其求值?这是个好主意吗?操作码调用在运行时创建一个赋值表单并对其求值?这是个好主意吗?谢谢!关于在运行时评估分配表单:我不知道这是否是个好主意。你是说,因为这导致运行时和编译时之间以非标准方式进行交互,所以会产生不必要的复杂性,这也许应该避免?谢谢!关于在运行时评估分配表单:我不知道这是否是个好主意。您是说,因为这导致运行时和编译时之间以非标准方式进行交互,所以会产生不必要的复杂性,这也许应该避免?