SuperCollider Project


Interfacing Synths with a Basic GUI

The Projects

The projects are designed to help you learn SuperCollider and also to provide an active and practical element to what could otherwise become a rather dry and technical exercise. Each semester, depending on how things are going, we will undertake either three or four main projects, probably using either SuperCollider or MaxMSP. The final project is invariably an individual choice project, and will be worth significantly more than the others in terms of percentages in your portfolio. For three projects, the percentages will be 25, 25 and 50% respectively. For four projects, they will be 20, 20, 20 and 40%. Every three or four weeks, we will spend a session 'performing' these projects. You are encouraged to involve as many of the group as you can in doing so...

Interfacing Synths with a Basic GUI

Code for a basic version of this project

(
SynthDef("variablesine", { arg freq;
	var f, g, osc;
	
	osc = RLPF.ar(LFPulse.ar(SinOsc.kr(freq, 0, 10, 21), 0.1), 100, 0.1).clip2(0.4);
	Out.ar(0, osc);
}).writeDefFile; 
s.sendSynthDef("variablesine");
)

(
SynthDef("def", { arg freq;
	var f, g, osc;

	osc = CombL.ar(
		RLPF.ar(LFPulse.ar(FSinOsc.kr(freq,0,80,160),0,0.4,0.05), 
		   FSinOsc.kr([0.6,0.7],0,3600,4000), 0.2),
		0.3, [0.2,0.25], 2);
	Out.ar(0, osc);
}).writeDefFile;
s.sendSynthDef("def");
)

(
SynthDef("scratchy", { arg freq;
	var f, g, osc;
	osc = RHPF.ar(BrownNoise.ar([0.5,0.5], -0.49).max(0) * 20, 5000, 1);
	Out.ar(0, osc);
}).writeDefFile;
s.sendSynthDef("scratchy");
)

(
SynthDef("scratchy", { arg freq1, freq2, freq3;
	var f, g, osc;
	osc = RHPF.ar(BrownNoise.ar([freq1,freq2], -0.49).max(0) * freq3, 5000, 1);
	Out.ar(0, osc);
}).writeDefFile;
s.sendSynthDef("scratchy");
)

(
SynthDef("sprinkler", { arg freq;
	var f, g, osc;
	osc = BPZ2.ar(WhiteNoise.ar(LFPulse.kr(MouseX.kr(0.2,50), 0, 0.25, 0.1)));
	Out.ar(0, osc);
}).writeDefFile;
s.sendSynthDef("sprinkler");
)

(
SynthDef("liquid", {
	var clockRate, clockTime, clock, centerFreq, freq, panPos, patch;

	clockRate = MouseX.kr(1, 200, 1);
	clockTime = clockRate.reciprocal;
	clock = Impulse.kr(clockRate, 0.4);

	centerFreq = MouseY.kr(100, 8000, 1);
	freq = Latch.kr(WhiteNoise.kr(centerFreq * 0.5, centerFreq), clock);
	panPos = Latch.kr(WhiteNoise.kr, clock);
	patch = CombN.ar(
			Pan2.ar( 
				SinOsc.ar(
					freq, 
					0, 
					Decay2.kr(clock, 0.1 * clockTime, 0.9 * clockTime)
				), 
				panPos
			),
			0.3, 0.3, 2
		);
	Out.ar(0, patch);
}).writeDefFile;
s.sendSynthDef("liquid");
)



Synth("variablesine", [\freq, 0.4]);

(
s.sendMsg("/s_new", "sprinkler", 1003, 1, 0, "freq", 0.6);
s.sendMsg("/s_new", "liquid", 1001, 1, 0, "freq", 0.4);
s.sendMsg("/s_new", "def", 1002, 1, 0, "freq", 10.7);
s.sendMsg("/s_new", "variablesine", 1003, 1, 0, "freq", 0.4);
)

// Free the nodes
(
s.sendMsg("/n_free", 1000);
s.sendMsg("/n_free", 1001);
s.sendMsg("/n_free", 1002);
s.sendMsg("/n_free", 1003);
)

// Here's the GUI!

(
var w, b1, b2, b3, sl1, sl2, sl3, sl4, sl5, sl20, num1, num2, num3, num4;    //lots of variables!
var str1, str2, str3, str4, str5, str6, str7, str8, str9, s;

s = Server.local;			// instance of a local server

// Create window - 350 x 500 pixels
w = SCWindow("Simple FM Controller", Rect(100, 800, 650, 500));
w.view.background = Color.blue;	// the window background will be blue
w.front;						// Bring the window to the front

// Create our 3 buttons
b1 = SCButton(w, Rect(5, 5, 110, 25));	// The first button starts and stops the server
b1.states = [
		["Start Server", Color.black, Color.green],
		["Stop Server", Color.white, Color.red],
			];
b1.action = { arg view;
		if (b1.value == 1, {
				s.boot;
		},{
				s.quit;
		});
};

b2 = SCButton(w, Rect(120, 5, 110, 25));	// This button sends both our SynthDefs
b2.states = [
		["Load SynthDefs", Color.black, Color.green]
			];
b2.action = { arg view;
	s.sendSynthDef("scratchy");
	s.sendSynthDef("liquid");
};

b3 = SCButton(w, Rect(235, 5, 110, 25));	// This one starts and stops the synths
b3.states = [
		["Play", Color.black, Color.green],
		["Stop", Color.white, Color.red],
			];
b3.action = { arg view;
		if (b3.value == 1, {
				s.sendMsg("/s_new", "scratchy", 1000, 1, 0, "freq", 80, "freq2", 1);
				s.sendMsg("/s_new", "liquid", 1001, 0, 0, "freq", 80);
				s.sendMsg("n_map", 1000, \freq2, 10);
				sl2.value = 1;	// These two commands set sliders 2 and 4 to values of
				sl4.value = 1/20;	// 1 and 1/20 whenever you start the synth
		},{
				s.sendMsg("/n_free", 1000);
				s.sendMsg("/n_free", 1001);
		});
};

// Create our sliders
sl1 = SCSlider(w, Rect(25, 100, 50, 300));
sl1.action = {
		var val;
//		val = ((800*sl1.value)+80);
		val = ((0.2*sl1.value));
		s.sendMsg("/n_set", 1000, "freq", val);
		num1.value = val;		// This will set the value of number box 1 = value of slider 1
};

sl2 = SCSlider(w, Rect(107, 100, 50, 300));
sl2.action = {
		var val;
		val = sl2.value;
		s.sendMsg("/n_set", 1000, "freq2", val);
		num2.value = val;		// This will set the value of number box 2 = value of slider 2
};

sl20 = SCSlider(w, Rect(157, 100, 50, 300));
sl20.action = {
		var val;
		val = sl20.value;
		s.sendMsg("/n_set", 1000, "freq3", val);
		num2.value = val;		// This will set the value of number box 2 = value of slider 2
};

sl3 = SCSlider(w, Rect(291, 100, 50, 300));
sl3.action = {
		var val;
		val = ((1000*sl3.value)+1);
		s.sendMsg("/n_set", 1001, "freq", val);
		num3.value = val;		// This will set the value of number box 3 = value of slider 3
};

sl4 = SCSlider(w, Rect(374, 100, 50, 300));
sl4.action = {
		var val;
		val = (20*sl4.value);
		s.sendMsg("/n_set", 1001, "amp", val);
		num4.value = val;		// I'm sure you can guess by now what this does!
};

sl5 = SCSlider(w, Rect(75, 40, 200, 30));			// This slider will control the pan
sl5.value = 0.5;								// The default position is set to 0.5 (halfway)
sl5.action = {
		var val;
		val = sl5.value;
		s.sendMsg("/n_set", 1000, "pan", val);	// The value of the slider position is sent to the
};											// pan argument of node 1000 (our variablesine synth)

// Create our text strings
str1 = SCStaticText(w, Rect(23, 70, 133, 30));		// All of our text strings are assigned a position,
str1.string = "|-------Variablesine-------|";		// content and Font type. You can send colour
str1.font = Font("Futura-Medium", 14);			// (or color!) information as well.

str2 = SCStaticText(w, Rect(189, 70, 133, 30));
str2.string = "|---------Modulator---------|";
str2.font = Font("Futura-Medium", 14);

str3 = SCStaticText(w, Rect(23, 400, 55, 25));
str3.string = "Freq(Hz)";
str3.font = Font("Futura-Medium", 14);

str4 = SCStaticText(w, Rect(112, 400, 55, 25));
str4.string = "Amp.";
str4.font = Font("Futura-Medium", 14);

str5 = SCStaticText(w, Rect(189, 400, 55, 25));
str5.string = "Freq(Hz)";
str5.font = Font("Futura-Medium", 14);

str6 = SCStaticText(w, Rect(280, 400, 55, 25));
str6.string = "Amp.";
str6.font = Font("Futura-Medium", 14);

str7 = SCStaticText(w, Rect(165, 42, 50, 25));
str7.string = "Pan";
str7.font = Font("Futura-Medium", 14);

str8 = SCStaticText(w, Rect(62, 42, 10, 25));
str8.string = "L";
str8.font = Font("Futura-Medium", 14);

str9 = SCStaticText(w, Rect(279, 42, 10, 25));
str9.string = "R";
str9.font = Font("Futura-Medium", 14);

//create our number boxes
num1 = SCNumberBox(w, Rect(25, 430, 50, 25));		// Finally, we create our number boxes.
num2 = SCNumberBox(w, Rect(107, 430, 50, 25));		// Each one is assigned a size and position.
num3 = SCNumberBox(w, Rect(191, 430, 50, 25));		// You can assign a default value by using
num4 = SCNumberBox(w, Rect(274, 430, 50, 25)); 	// variablename.value = number eg num1.value = 80; 

)