How to send raw OSC to create a simple sound

Hey there! I am trying to get again into Supercollider and I’d really like to know what actually happens in the background when for example evaluating:

x = { SinOsc.ar(200, 0, 0.5) }.play;

In the end sclang is converting this to raw OSC commands and sends those to scsynth, right?

I have followed the Server Tutorial in the Help Browser and I get how it is working to generate SynthDefs and how to instantiate these as Synth on the server. Also the concept of using sclang as a command line tool to not use the IDE at all for this is clear to me.

It would be great if you could point me to other resources if you feel like they could fill the gaps which might be missing in my understanding. In the end, it would be great if I knew which raw OSC commands the line above fires when evaluating and how I could use another program to do the same.

Any hints very much appreciated :slight_smile:

I would suggest to just read the code of the Class Library. It is actually quite approachable.

For example, here’s the code for Function.play:

play { arg target, outbus = 0, fadeTime = 0.02, addAction=\addToHead, args;
		var def, synth, server, bytes, synthMsg;
		target = target.asTarget;
		server = target.server;
		if(server.serverRunning.not) {
			("server '" ++ server.name ++ "' not running.").warn; ^nil
		};
		def = this.asSynthDef(
			fadeTime:fadeTime,
			name: SystemSynthDefs.generateTempName
		);
		synth = Synth.basicNew(def.name, server);
			// if notifications are enabled on the server,
			// use the n_end signal to remove the temp synthdef
		if(server.notified) {
			OSCFunc({
				server.sendMsg(\d_free, def.name);
			}, '/n_end', server.addr, argTemplate: [synth.nodeID]).oneShot;
		};
		synthMsg = synth.newMsg(target, [\i_out, outbus, \out, outbus] ++ args, addAction);
		def.doSend(server, synthMsg);
		^synth
	}

It does the following things:

  1. create a new SynthDef from the function, automatically adding an Out.ar Ugen if omitted
  2. create a Synth object – without sending it to the Server yet
  3. register an OSC responder function that will free the SynthDef once the Synth has stopped playing
  4. create an OSC message for a new Synth
  5. send the SynthDef to the Server – this is an asynchronous command! – with the OSC message in 4. as the completion message. This will effectively create the Synth once the SynthDef has been successfully registered on the Server.
2 Likes

It would be great if you could point me to other resources if you feel like they could fill the gaps which might be missing in my understanding. In the end, it would be great if I knew which raw OSC commands the line above fires when evaluating and how I could use another program to do the same.

Any hints very much appreciated :slight_smile:

You may be looking for the Help docs “Server Command Reference” and “Synth Definition File Format”. Together these are enough to communicate directly with the server, even optionally without sclang at all.

Tom

2 Likes

Thank you very much for your answers, will check it out! But from a first glance, so I get it right that in the end everything that is evaluating is creating a SynthDef beforehand? And if yes, are they all saved to a file before the Synth is created?

everything that is evaluating is creating a SynthDef beforehand

I am not sure what you mean exactly with “everything that is evaluating”. Calling play on a function will interpret the function as a Ugen graph function, create a temporary SynthDef and start a Synth on the Server. In this case many things happen behind the scenes.

On the other hand, if you manually create a SynthDef and then start a Synth, things become more explicit.

And if yes, are they all saved to a file before the Synth is created?

For one-shot SynthDefs, like in your example, it depends. If the SynthDef size is small, it is directly sent to the Server (/d_recv). Otherwise the SynthDef is first stored on disk as a temporary file, then we ask the Server to read the file (/d_load) and finally we remove the file (as we do not need it anymore). Check the implementation of SynthDef.doLoad.

NB: the above only applies to “implicit” SynthDef creation, such as when you call play on a Function. For “proper” SynthDefs, you can explicitly choose the behavior with .add, .store, .load, .send, etc.

1 Like

Well… I guess I am also not so sure what I mean with it. But I think you two have pointed me into a good direction to go further. Thank you very much for taking your time!