Question

I'm trying to make music with the overtone library of clojure. To produce interesting sounds, additive synthesis is useful, that means that I take sinus oscillators of several frequencies and simply add them. In overtone, to create a synthesizer, which realizes that, I can write:

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

To be a bit more reusable, I write a function, which takes a frequency and returns a list with all these frequencies, you can see in the code snippet:

(defn split-freq [freq]
  (apply vector (map #(* freq %) [1.01 1 0.99])))

When executing (split-freq 100), the REPL gives me the following:

[101.0 100 99.0]

which is exactly the same as the input, I provided the map function above. In fact, I copied the result. Now, I try this:

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

Unfortunately, the REPL tells me, that I'm doing wrong:

CompilerException java.lang.ClassCastException: 
overtone.sc.machinery.ugen.sc_ugen.ControlProxy cannot be cast to java.lang.Number, 
compiling:(form-init1807789563491679853.clj:1)

But this code works fine:

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc (apply vector (map #(* freq %) [1.01 1 0.99]))))))

although, I simply put in the function definition.

I think I have a principal lack of understanding. I thought, that if one of those version work, the others must work, too.

My questions are: Why does my 'improved' version does not work? Why does the first snippet work? How can I circumvent this behavior?

Clojure 1.3.0
Overtone 0.8
(use 'overtone.core)
Was it helpful?

Solution

ups, you are right, i haven't understand the noisesmith comment. It's true that you can't use this value "freq" in your function directly because this value is not bound at the time that your function need it (before the macro execution)

So here is a workaround to this problem, also using the let form, it is not so elegant as to make your own macro but works

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

and you can execute as a normal function

((myinst "my-instrument"))

I hope that helps you

Juan


Previous comment, now not valid response

maybe you are making a mistake with your argument value declaration in your improved version

That's your code

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

And, as in clojure you can't assign default value to argument function, your improved version would work if, by example, you use a let form to assign the default value

(definst myinst []
  (let [freq 100]
    (* 0.2 (reduce + (map sin-osc (split-freq freq))))))  
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top