ArduinoToSCSC01.rtf
v1.0b001 081218

Sample Code for SuperCollider to control SC from an Arduino board.

In order to use it you must install the Arduino quark.  Evaluate the following to see if it's already there:

Quarks.gui;

If not, you should be able to install it with an internet connection and the following:

Quarks.update("arduino");
Quarks.install("arduino");

See the Quarks helpfile for more information.

// First you'll need to insert the address of your serial driver (see Arduino/Tools/Serial Port/).

// find out how you refer to your device, which is connected via a serial port:
SerialPort.listDevices

// Here are three examples:
p = ArduinoSMS("/dev/tty.usbserial-A4000PfP", 115200); // My NG 
p = ArduinoSMS("/dev/tty.usbserial-A40015oJ", 115200);  // My Diecimilla
p = ArduinoSMS("/dev/tty.usbserial-A40015oJ", 76800);  // My Diecimilla
p = ArduinoSMS("/dev/tty.usbmodemfa131", 9600);  // My Uno

// show what's coming in...
p.action = { | ... msg | msg.postln; };

// close the port!
SerialPort.closeAll;

// if necessary be more specific
p.action = { | ... msg | msg[1].postln; };

// close the port!
SerialPort.closeAll;

// Now I'll define a synthdef with an Envelope.
(
SynthDef(\EnvSine, 
	{ arg freq = 440, myDur = 0.1; 
	// For info:
	// EnvGen.kr(envelope, gate, levelScale, levelBias, timeScale, doneAction)
	// Env.perc(attackTime, releaseTime, peakLevel, curve)
	Out.ar(0, EnvGen.kr(Env.perc((myDur/1000), 0.1, 0.6, -4), 1.0, doneAction: 2) * SinOsc.ar(freq,0,0.1)) }
	).send(s);
)

//  This is the action that actually occurs when you run the read loop or the task...
//  Send it to a synthdef's frequency argument
// Use these examples with an analog device such as a potentiometer

(
p.action = { 
| ... msg | 
// The message is coming in on Arduino analogue input 0, so plug your control (I'd recommend a potentiometer) into the Arduino's analogue input 0.

msg[0].postln; // Just for information, also post the value - you can get rid of this if you want.
Synth(\EnvSine, [\freq, msg[0], \myDur, 100]);

};
)

// for use with a digital device such as a button
(
p.action = { 
| ... msg | 
// The message is coming in on Arduino analogue input 0, so plug your control (I'd recommend a potentiometer) into the Arduino's analogue input 0.

msg[1].postln; // Just for information, also post the value - you can get rid of this if you want.

if (msg[1] == 1, {
	Synth(\EnvSine, [\freq, (400.rand)+400, \myDur, 10]);
} );

};
)

// always remember
SerialPort.closeAll;

//////
// The below is Simple Message System functionality, and unfortunately this doesn't appear to be yet working with Arduino 1+.
//////

p = ArduinoSMS("/dev/tty.usbmodemfa131", 9600);  // My Uno

// Turn the pot and then evaluate the below - you should get a single 'note':
p.send($r, $a); // $r = receive; $a = analogue input; 2 = analogue input 2;

// and here's a loop sending a trigger every 0.3 second.
(
fork {
	var a;
	1000.do {
		p.send($r, $a); // $r = receive; $a = analogue input; 2 = analogue input 2;
		0.3.wait; // careful with this - it can crash SC if it's too low!
	}
}
)

// If you've finished, you should close the port.  If you don't you won't be able to contact the port via the Arduino software.

p.close;

// Then we put it into a task, which we can start, pause and resume if we want...
(
t = Task({ 
		500.do({
			p.send($r, $a);
			0.1.wait 
		}); 
	});
)

t.start;
t.pause;
t.resume;
t.reset;
t.stop;

// You must close the port:
p.close;

SerialPort.closeAll;

// Try this, too!

p = ArduinoSMS("/dev/tty.usbserial-A40015oJ", 115200);  // My Diecimilla
p = ArduinoSMS("/dev/tty.usbmodemfa131", 9600);  // My Uno

p.action = { |... msg| msg.postln; };

(
Tdef(\arduinoReader,{
	inf.do {
		p.send($r, $a);
		0.15.wait;
	}
})
)

Tdef(\arduinoReader).play;

// You may want to map the values onto another set, in the way that you can use the scale object in MaxMSP:

A ControlSpec is a helpful class which can be used to turn this into any desired range

(
var w, slid, cs;

w=SCWindow("My Window", Rect(100,500,200,200)); 
//A 200 by 200 window appears at screen co-ordinates (100, 500)

slid=SCSlider(w,Rect(10,10,150,40));

//arguments minimum value, maximum value, warp (mapping function), stepsize, starting value 
cs= ControlSpec(20, 20000, 'exp', 10, 1000); 

slid.action_({cs.map(slid.value).postln;}); //map to the desired range

w.front;
)

A note on baud rates and boards
The arduino board comes with a 16mhz crystal and therefore 115200 isn't a very good choice.  there are optimal baudrates for different crystals.  9600 is a standard albeit slow one that matches most common crystals.  using 115200 at 16mhz will give you an error of -3.5%.  this can result in dropouts and lost messages.  maybe your linux serial driver is more sensitive to this or something.  for 16mhz crystals: 9600, 19200, 38400, 76800, 250000 are all good <0.2% error rates.  see the atmega8 datasheet for more info/tables.
i never understood why the sms helpfiles insists on 115200 - which suits better for 3.686mhz.