Skip to content

How to control SC Android remotely

danstowell edited this page Sep 13, 2010 · 11 revisions

You can control SuperCollider-Android remotely by sending OSC messages over the network. Actually you can use any OSC-capable software/hardware — on this page we’re going to use SuperCollider to control the phone from a desktop/laptop computer. We’ll assume you have:

  • An Android phone/device with the SuperCollider activity installed, with wifi/network access
  • Some other computer on which you can run the full SuperCollider language, with wifi/network access

And here’s what to do:

  1. Make sure the phone and the computer are connected to the network (e.g. using wifi).
  2. Find the IP address assigned to your Android phone.
    • On mine I go to Settings → Wireless controls → Wi-fi settings, then click on the name of the wi-fi network I’m connected to, and a box appears showing me the IP address, e.g. 192.168.1.10
  3. Start the SuperCollider activity on the phone.
    • By default it will try to start listening on port 57110. Make sure it’s not going to get blocked by firewalls.
  4. Start the SuperCollider client (language) on your computer.
  5. Create a Server object in SuperCollider language to represent the phone. In the following line of code we create a Server object and also set it as default, which is the easiest way to get going quickly:
    Server.default = s = Server(\phone, NetAddr("192.168.1.10", 57110));
    Note that the IP address and port of the phone are specified in that line – you will need to alter that to match your own phone’s address.

OK, now we have a reference to the remote server we can treat it like any server in SuperCollider. Let’s make a GUI window to represent it:

s.makeWindow

A GUI window should appear, with “phone” (the name of the server) on it. If the network communication is working, then the window should change from INACTIVE to RUNNING – if so then be happy, it means the language has sent a message to the server (the phone) asking for its status, and it has replied!

If not then check the IP address is correct, check for firewall issues, check that the SuperCollider activity is still running and foregrounded on the phone. If you have android dev tools set up you can use adb logcat to look for messages that might suggest problems. (For example if you grep through for the port number (usually 57110) you may find messages about binding or failing to bind the port.)

Note: at time of writing SuperCollider-Android has problems with freeing up the network port once it exits, which means that on the second run (and beyond) it may fail to connect to the port.

Now let’s do stuff with it:

  • Firstly, you probably noticed that there’s a default synth running when the activity launches. It has the node ID of 999. We can control it:
    s.sendMsg(\n_set, 999, \freq, exprand(300, 1000), \amp, 0.3);
    This line sends a randomly-chosen frequency to the node numbered 999.
  • You can see what synths/groups are currently running on the phone by executing this:
    s.queryAllNodes;
    You should be able to see a representation of the server’s node tree, posted to the SuperCollider post window.
  • Now you might like to stop the synth:
    s.sendMsg(\n_free, 999);

Now you’re free to use the phone just like you’d use a normal SuperCollider server. Here are some examples, you can step through them line-by-line/block-by-block:


////////////////////////////
// Simple synthesis
q = {MoogFF.ar(Pulse.ar((77,77.2..78).midicps).mean, XLine.kr(10,10000,0.1))}.play
q.free

////////////////////////////
// Patterns
(
SynthDef(\myowser, { |out=0, freq=440, amp=0.1, gate=1|
	var ampenv = EnvGen.ar(Env.adsr(), gate, doneAction: 2);
	var frqenv = EnvGen.ar(Env.adsr(0.1, 2, 0.7).exprange(50, 3000), gate);
	var son = Pulse.ar(freq);
	son = MoogFF.ar(son, frqenv);
	Out.ar(out, son * amp * ampenv)
}).add
)

x = Synth(\myowser, [\amp, 0.75]);
x.set(\gate, 0);
(
Pbind(
	\instrument, \myowser,
	\midinote, Pseq([
		Pseq([77, 79, Prand([82, 85, 89, 94])], 4),
		[70]
		]) - 10,
	\dur, 0.5,
	\amp, 0.75
).play
)

////////////////////////////
// Do some machine listening
~bus = Bus.control(s)
x = {LeakDC.ar(MoogFF.ar(WhiteNoise.ar(0.2), SinOsc.ar(0.05,pi/2).exprange(200, 5000)))}.play
(
y = {
	var son = In.ar(0);
	var ana = SpecCentroid.kr(FFT(LocalBuf(1024), son));
	Out.kr(~bus, ana.round);
}.play(target: x, addAction: \addAfter)
)

Task{ 100.do{ 0.3.wait; ~bus.get(_.postln) } }.play

x.free
y.free