我正在尝试使用clojure的overtone库制作音乐。为了产生有趣的声音,加法合成是很有用的,这意味着我需要取多个不同频率的正弦振荡器并将它们简单地相加。在overtone中,我可以编写以下代码来创建实现该功能的合成器:
(definst myinst [freq 100]
(* 0.2 (reduce + (map sin-osc [101.0 100 99.0]))))
为了更加可重用,我编写了一个函数,它接受一个频率并返回包含所有这些频率的列表,您可以在代码片段中看到:
(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]))))))
虽然我只是简单地放置了函数定义。
我认为我存在一个主要的理解缺失。我以为,如果其中一个版本有效,其他版本也必须有效。
我的问题是: 为什么我的“改进”版本不起作用? 为什么第一个片段有效? 如何规避这种行为?
Clojure 1.3.0
Overtone 0.8
(use 'overtone.core)
+
)的操作解释为合并一组信号的合成定义,而您的新 definst 表单打破了这个宏。Clojure 代码无法在 sc 合成器进程中运行,因此您的表单需要转换为 sc 合成器定义,并且实际上不是真正的 Clojure 代码。 - noisesmith