3

Clojureの倍音ライブラリで音楽を作ろうとしています。興味深いサウンドを生成するには、加算合成が役立ちます。つまり、いくつかの周波数の正弦波オシレーターを使用して、それらを単純に加算します。倍音で、それを実現するシンセサイザーを作成するには、次のように記述できます。

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

1 に答える 1

1

アップ、あなたは正しいです、私はノイズスミスのコメントを理解していません。この値「freq」を関数で直接使用できないのは事実です。この値は、関数が必要とする時点 (マクロ実行前) にはバインドされていないためです。

したがって、ここにこの問題の回避策があります。これも let フォームを使用します。独自のマクロを作成するほどエレガントではありませんが、機能します

(defn myinst [inst-name]
  (let [the-freq 100]
   (definst inst-name [freq the-freq] (* 0.2 (reduce + (map sin-osc (split-freq the-freq)))))))

通常の関数として実行できます

((myinst "my-instrument"))

お役に立てば幸いです

ファン


以前のコメント、現在は有効な応答ではありません

改良版では引数の値の宣言を間違えているのかもしれません

それはあなたのコードです

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc (split-freq freq)))))

また、clojure では引数関数にデフォルト値を割り当てることができないため、たとえば let フォームを使用してデフォルト値を割り当てると、改善されたバージョンが機能します。

(definst myinst []
  (let [freq 100]
    (* 0.2 (reduce + (map sin-osc (split-freq freq))))))  
于 2013-09-24T09:00:46.370 に答える