Arbitrary frequency slide at arbitrary time

97 views
Skip to first unread message

Joel J.

unread,
Jul 19, 2012, 12:02:18 PM7/19/12
to over...@googlegroups.com
Say I have a an instrument like

(definst sinewave [freq 220] (sin-osc freq))

And I start it up using

(def sound (sinewave))

So it starts making a 220 Hz sound.

Now, some arbitrary amount of time later I want to change it to be at some other arbitrary frequency; let's say 440 Hz.  Normally I could just do

(ctl sound :freq 440)

and it would switch to 440 Hz.

However, I want to be fancy about it and make it slide up to that frequency over the course of a second or so.

The intuitive thing for me to do at this point, given my current limited knowledge of how this all works, is to pass a line ugen to the control function.  My reasoning goes like this: I can pass a line ugen to sin-osc in a definst, and freq is just what gets passed to sin-osc, so I should be able to use ctl to pass a line ugen to sin-osc by using the :freq parameter, like so:

(ctl :freq (line:ar 220 440 1))

But when I try to do that, I get an exception:
Failed attempting to send an OSC message to SuperCollider server. Reason: incorrect arglist type in OSC message /n_set. Expected a float representing a control value found class overtone.sc.machinery.ugen.sc_ugen.SCUGen. Message name: /n_set Type sig: [:node-id :ALTERNATING-ctl-handle-THEN-ctl-val*] Arg list: (52 "freq" #<sc-ugen: line:ar [0]>)

So that's no good, apparently because of something to do with how SuperCollider works (control messages can only be to non-changing float values?)

So what _is_ the idiomatic way to slide from one frequency to another in an instrument that is already playing?  Is there an "easy" way to do that, or do you have to kind of kludge it with something like:

(definst sliding-sine [start-freq 0 end-freq 220 slide-duration 1]
  (sin-osc (line:ar start-freq end-freq slide-duration)))

(def slider (atom (sliding-sine)))
(at (+ (now) 1000) (do (kill @slider) (reset! slider (sliding-sine 440 330 1))))

[apologies if g-mail destroys the formatting...]
This does mostly do what I want it to, except there's a faint 'pop' when it kills the first sound and starts the second, which is fine for just fooling around but I wouldn't want it in anything final.

Cheers,
Joel

Chris Ford

unread,
Jul 19, 2012, 12:36:28 PM7/19/12
to over...@googlegroups.com
Is there a way to do it via feedback? So if you send a new ctrl signal, you could use some kind of feedback loop to gradually move towards the new frequency.

I'm a bit sketchy about the details, sorry.

Chris

Aaron S

unread,
Jul 19, 2012, 12:44:02 PM7/19/12
to over...@googlegroups.com
Hi Joel,

I use the slew ugen for this effect in the mini-beast. Translating it your example: (definst sinewave [freq 220] (sin-osc (slew freq 10.0 10.0)))
Adjust the up/down values from 10.0 to your taste. Or make them a function of the frequency if you need the slide from 220 to 440 to take the same time as a slide from 440 to 880.

Best,
Aaron

Jeff Rose

unread,
Jul 19, 2012, 1:10:46 PM7/19/12
to over...@googlegroups.com
Aaron's recommendation is the best way currently, but what you want to
do is actually a great idea. I'm going to work on it and get back to
you...

Joel J.

unread,
Jul 19, 2012, 3:09:06 PM7/19/12
to over...@googlegroups.com
Thanks Aaron, that's exactly the sort of thing I had in mind!  Also thanks for the link to the minibeast synth; I've been meaning to check it out but hadn't gotten around to it.  Pretty daunting, but I'm looking forward to learning from it.

--Joel

Joel J.

unread,
Jul 19, 2012, 3:09:56 PM7/19/12
to over...@googlegroups.com
Sweet! ^_^

Jeff Rose

unread,
Jul 19, 2012, 7:24:02 PM7/19/12
to over...@googlegroups.com
OK, here is a proof of concept. It doesn't quite do what you want yet, but it demonstrates the strategy we can use to pull it off. Using node-map-controls we can connect a bus to a synth parameter. So here I did it all by hand. The idea version, like your example, should be in a macro that allocates the bus, maps the parameter to it, creates and fires off the control synth, and then once the synth completes free the bus. Currently there is an /n_end event sent when a synth node completes, but I think we should have a higher level and easier to use event to catch when a synth finishes. Sam, you've been doing a lot of work with the event system lately. Any thoughts on how this should work? Anyway, you should be able to give this example a go. Just evaluate form by form.

-Jeff

(ns examples.synth-control
(:use overtone.live))

(definst simple
[freq 440 depth 30 warble 0.3]
(let [freq (slew freq 7 12)
snd (apply + (saw (+ [freq (* freq 1.013) (* freq 0.992)]
(* warble (sin-osc:kr warble [0 2.0945 4.7])))))
filt (rlpf snd
(+ (* freq 2) (* freq (sin-osc 0.2)))
(+ 0.31 (* 0.3 (sin-osc 0.03))))]
filt))

(defn synth-ctl
[node param ctl-synth]
(let [cur-val (node-get-control node [param])]
(ctl-synth test-bus)
(node-map-controls node [param test-bus])))

(defsynth bus-line
[start 0 end 1 dur 1 bus 0]
(out bus (line:kr start end dur :action FREE)))

(def test-bus (control-bus 1))
(def s (simple))
(synth-ctl s :freq (partial bus-line 880 220 4))
(stop)

Aaron S

unread,
Jul 19, 2012, 8:19:58 PM7/19/12
to over...@googlegroups.com
Wow! I had no idea that was possible. Thank you for posting this Jeff. There's an arpeggiator build into the mini-beast that may really benefit from being pulled out into it's own defsynth like this.

Joel J.

unread,
Jul 20, 2012, 11:23:20 AM7/20/12
to over...@googlegroups.com
Sweet, this is much more in line with what I had in mind!  Thanks!  XD

--Joel
Reply all
Reply to author
Forward
0 new messages