• jon@schemawound.com

Helping Until It Hurts

While learning Supercollider I have found several cases where convenience methods and syntactic sugar can actually impede the learning process. Below I mention two cases that have caused me trouble in the past. Both these methods are often used in introductory tutorials. My belief is they are used as a way to hook the new user in by providing immediate results without the messy details. I question whether teaching these methods early causes more harm as they muddy the separation of language and server.

Function.play

No matter which tutorial you started following to learn Supercollider it likely introduced you to sound by something similar to the following:

{SinOsc.ar(440)}.play

Simple and concice, certainly better then this:

SynthDef(test, {Out.ar(0, SinOsc.ar(440))}).play

Often new users seem confused about the separation between language and server. Function.play blurs the line by not making it apparent that a SynthDef is being built and used behind the scenes. I remember feeling very confused when I was later told that the only way to generate sound with Supercollider was by using SynthDefs. This seemed to contradict all the code I had written.

According to the help file for Function.play it “…wraps the Function in a SynthDef (adding an Out ugen if needed), creates and starts a new Synth with it, and returns the Synth object. A Linen is also added to avoid clicks, which is configured to allow the resulting Synth to have its gate argument set, or to respond to a release message. Args in the function become args in the resulting def.” While that is useful to limit the number of concepts being thrown at new users I think obscuring the fact that a SynthDef is being created is confusing.

While Function.play is very useful for testing out code I would suggest new users are taught Function.asSynthDef.play in order to make the SynthDef creation more explicit. The code below receives all the benefits of Function.play while still making it obvious that a SynthDef is being created:

{SinOsc.ar(440)}.asSynthDef.play

MouseX/MouseY

The other pair of Ugens I wanted to talk about are MouseX and MouseY, while browsing the tutorials you likely encountered code like this:

{ SinOsc.ar(MouseX.kr(40, 10000, 1), 0, 0.1) }.play

This is a very quick way to get interactivity into the tutorials and I can understand its allure. My concern is that it sets a bad example about how interactivity is handled in the language. After learning about MouseX/MouseY I began searching for the Ugens that handle keyboard input and MIDI CC messages. Based on the mouse examples this seems like a logical next step. In actually these messages are handled by the language and passed to the Synth through arguments. Because of the mouse examples I had a poor mental model about the way in which interactivity is handled.

Conclusion

Function.play, MouseX and Mouse.Y are all very useful techniques for testing and developing sounds but in my case they obscured some essential concepts and caused confusion when I tried to understand the architecture of Supercollider.

Tags :