【发布时间】:2013-09-27 12:34:19
【问题描述】:
我正在尝试使用 clojure 的泛音库制作音乐。为了产生有趣的声音,加法合成很有用,这意味着我需要几个频率的正弦振荡器并简单地添加它们。在泛音中,要创建一个合成器,实现这一点,我可以写:
(definst myinst [freq 100]
(* 0.2 (reduce + (map sin-osc [101.0 100 99.0]))))
为了更可重用,我写了一个函数,它接受一个频率并返回一个包含所有这些频率的列表,你可以在代码 sn-p 中看到:
(defn split-freq [freq]
(apply vector (map #(* freq %) [1.01 1 0.99])))
当执行(split-freq 100) 时,REPL 给了我以下信息:
[101.0 100 99.0]
和输入一模一样,我提供了上面的map函数。事实上,我复制了结果。现在,我试试这个:
(definst myinst [freq 100]
(* 0.2 (reduce + (map sin-osc (split-freq freq)))))
不幸的是,REPL 告诉我,我做错了:
CompilerException java.lang.ClassCastException:
overtone.sc.machinery.ugen.sc_ugen.ControlProxy cannot be cast to java.lang.Number,
compiling:(form-init1807789563491679853.clj:1)
但是这段代码可以正常工作:
(definst myinst [freq 100]
(* 0.2 (reduce + (map sin-osc (apply vector (map #(* freq %) [1.01 1 0.99]))))))
虽然,我只是简单地把函数定义放进去。
我认为我主要缺乏理解。我想,如果其中一个版本有效,那么其他版本也必须有效。
我的问题是: 为什么我的“改进”版本不起作用? 为什么第一个 sn-p 工作? 如何规避这种行为?
Clojure 1.3.0
Overtone 0.8
(use 'overtone.core)
【问题讨论】:
-
尝试宏扩展对 definst 的调用。可能 definst 是一个复杂的宏,它将通常是函数(如
+)解释为对一组信号求和的合成器定义,而您的新定义形式会破坏宏。 Clojure 代码无法在 sc 合成器进程中运行,因此您的表单需要翻译成 sc 合成器定义,并且实际上不能是真正的 clojure 代码。
标签: clojure type-conversion sound-synthesis