• jon@schemawound.com
Supercollider
The Tunnel

The Tunnel

Today Waxen Wings has released my track ‘The Tunnel’ on the album ’Far Far Away’. The track was produced entirely using Supercollider.  I know one of the issues many people have with systems like Supercollider is figuring out a workflow.  I figured I would take the time to break down how I created this song in hopes it helps someone else.

Since the theme of the compilation was how difficult it is to hear people from far away I knew I needed to start with some reverberation.  I then played with various combinations of oscillators and distortion until I came up with the following loop that produced quite a lot of variation on it’s own.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
({FreeVerb.ar(((((SinOsc.ar(7) * SinOsc.ar(LFSaw.ar(0.1, 0, 0.5, 0.5) * 100) * SinOsc.ar(LFSaw.ar(0.25, 0, 0.5, 0.5) * 600)) * 6).distort * SinOsc.ar(500)) * 6).distort * 0.5 + SinOsc.ar(30, 0, 0.5), SinOsc.ar(0.014) * 0.5 + 0.5, 1, 0.5, 1)!2;}).play;
({FreeVerb.ar(((((SinOsc.ar(7) * SinOsc.ar(LFSaw.ar(0.1, 0, 0.5, 0.5) * 100) * SinOsc.ar(LFSaw.ar(0.25, 0, 0.5, 0.5) * 600)) * 6).distort * SinOsc.ar(500)) * 6).distort * 0.5 + SinOsc.ar(30, 0, 0.5), SinOsc.ar(0.014) * 0.5 + 0.5, 1, 0.5, 1)!2;}).play;
({FreeVerb.ar(((((SinOsc.ar(7) * SinOsc.ar(LFSaw.ar(0.1, 0, 0.5, 0.5) * 100) * SinOsc.ar(LFSaw.ar(0.25, 0, 0.5, 0.5) * 600)) * 6).distort * SinOsc.ar(500)) * 6).distort * 0.5 + SinOsc.ar(30, 0, 0.5), SinOsc.ar(0.014) * 0.5 + 0.5, 1, 0.5, 1)!2;}).play;

I then decided to work in reverse and start pulling pieces out into well named variables to see what I actually had.  I put the results into a synthdef.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
(//----------Tunnel SynthDef----------
SynthDef(TheTunnel, {
arg
out = 0, amp = 1,
lfo1Speed = 0.1, lfo1Depth = 100,
lfo2Speed = 0.25, lfo2Depth = 600,
osc1Freq = 7,
loSineFreq = 30, loSineAmp = 0.5,
clip1Amp = 6, clipModFreq = 500, clip2Amp = 6,
verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1, verbDamp = 0.5
;
var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
//Osc1
var osc1 = SinOsc.ar(osc1Freq);
//Osc2
var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
//Osc3
var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
//Sum and Clip
var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
//Output
var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
Out.ar(out, verb1!2);
}).store;
)
(//----------Tunnel SynthDef---------- SynthDef(TheTunnel, { arg out = 0, amp = 1, lfo1Speed = 0.1, lfo1Depth = 100, lfo2Speed = 0.25, lfo2Depth = 600, osc1Freq = 7, loSineFreq = 30, loSineAmp = 0.5, clip1Amp = 6, clipModFreq = 500, clip2Amp = 6, verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1, verbDamp = 0.5 ; var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp); //Osc1 var osc1 = SinOsc.ar(osc1Freq); //Osc2 var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only var osc2 = SinOsc.ar(lfo1 * lfo1Depth); //Osc3 var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only var osc3 = SinOsc.ar(lfo2 * lfo2Depth); //Sum and Clip var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq); //Output var output = (clip1 * clip2Amp).distort * 0.5 + loSine; var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth; var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp); Out.ar(out, verb1!2); }).store; )
(//----------Tunnel SynthDef----------
	SynthDef(TheTunnel, {
		arg
			out = 0,			amp = 1,
			lfo1Speed = 0.1,	lfo1Depth = 100,
			lfo2Speed = 0.25,	lfo2Depth = 600,
			osc1Freq = 7,
			loSineFreq = 30,	loSineAmp = 0.5,
			clip1Amp = 6,		clipModFreq = 500,		clip2Amp = 6,
			verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1, verbDamp = 0.5
		;
		var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
		//Osc1
		var osc1 = SinOsc.ar(osc1Freq);
		//Osc2
		var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
		var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
		//Osc3
		var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
		var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
		//Sum and Clip
		var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
		//Output
		var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
		var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
		var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
		Out.ar(out, verb1!2);
	}).store; 
)

This can be played as follows:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
~tunnel = Synth(TheTunnel);
~tunnel = Synth(TheTunnel);
~tunnel = Synth(TheTunnel);

Next I revised the synthdef to include lag time for smooth transition between input values. I built knobs to control each parameter of the synth. I created a preset system to store good sets of values. In order to make finding interesting sounding patches easier I eventually added a random button and a button to print all current knob values to the post window. I also added midi responders to allow myself to ‘play’ the presets using a midi keyboard.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
(//----------Tunnel SynthDef----------
SynthDef(TheTunnel, {
|
out = 0, amp = 1, lfo1Speed = 0.1, lfo1Depth = 100, lfo2Speed = 0.25,
lfo2Depth = 600, osc1Freq = 7, loSineFreq = 30, loSineAmp = 0.5, clip1Amp = 6,
clipModFreq = 500, clip2Amp = 6, verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1,
verbDamp = 0.5
|
var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
//Osc1
var osc1 = SinOsc.ar(osc1Freq);
//Osc2
var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
//Osc3
var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
//Sum and Clip
var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
//Output
var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
Out.ar(out, verb1!2);
}, [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]).store;
)
(//----------Synth Setup----------
//----Start Synth----
~tunnel = Synth(TheTunnel);
~presets =
[
// amp, lfo1Speed, lfo1Depth, lfo2Speed, lfo2Depth, osc1Freq, loSineFreq, loSineAmp, clip1Amp, clipModFreq, clip2Amp, verbLfoSpeed, verbLfoDepth, verbRoom, verbDamp
[ 1, 0.1, 100, 0.25, 600, 7, 30, 0.5, 6, 500, 6, 0.014, 1, 1, 0.5 ],
[ 1, 030.756, 628.79, 0.25, 600, 35.412, 11.8, 0.5, 6, 500, 6, 0.151, 0.204, 1, 1 ],
[ 2, 048.345, 446.41, 45.021, 694.56, 14.97, 42.53, 0.14, 1.833, 168.49, 1, 0.014, 0.314, 1, 0 ],
[ 1.5, 0.507, 1000, 6.285, 317.08, 34.579, 31.77, 0.5, 3.672, 44.59, 3.492, 0.316, 0.49, 0.461, 1 ],
[ 1.5, 0.507, 288.03, 0.67, 317.08, 10.449, 88.06, 0.37, 2.557, 44.59, 3.492, 0.155, 1, 1, 1 ],
[ 0.575, 100, 1000, 96.903, 1000, 50, 88.06, 1.22, 6, 127.37, 6, 0.167, 0.493, 1, 1 ],
[ 1.2, 1, 101.3, 1.5, 74.79, 11.691, 5.2, 0, 3.225, 49.8, 2.754, 0.51, 0.494, 0.784, 0.497 ],
[ 2.852, 0.001, 80.79, 100, 306.59, 11.691, 5.2, 0, 3.225, 49.8, 3.734, 0.273, 0.656, 0.784, 0.889 ],
[ 1.116, 71.939, 631.92, 72.476, 427.99, 17.475, 96.68, 0.56, 4.298, 496.15, 5.649, 0.804, 0.694, 0.303, 0.461 ],
[ 0.979, 34.043, 650.05, 29.176, 480.98, 30.836, 66.66, 1.13, 2.401, 205.91, 2.664, 0.173, 0.778, 0.517, 0.88 ],
[ 2.206, 22.558, 217.5, 91.033, 520.13, 3.484, 84.09, 1.59, 2.731, 259.07, 5.919, 0.571, 0.988, 0.133, 0.0 ]
];
)
(//----------Tunnel GUI----------
//Global Variables
var layout;
var knobSize = 60@80;
var buttonSize = 20@20;
var titleFont = Font( "Times-Bold", 25 );
//Knob Variables
var ampControlSpec, ampKnob;
var lfoSpeedControlSpec, lfoDepthControlSpec, lfo1SpeedKnob, lfo1DepthKnob, lfo2SpeedKnob, lfo2DepthKnob;
var osc1FreqControlSpec, loSineFreqControlSpec, loSineAmpControlSpec, osc1FreqKnob, loSineFreqKnob, loSineAmpKnob;
var clipAmpControlSpec, clipModControlSpec, clip1AmpKnob, clipModFreqKnob, clip2AmpKnob;
var verbControlSpec, verbLfoSpeedKnob, verbLfoDepthKnob, verbRoomKnob, verbDampKnob;
//Button Variables
var callPreset, presetButton1, presetButton2, presetButton3, presetButton4, presetButton5, presetButton6, presetButton7, presetButton8, presetButton9, presetButton10,
presetButton11, presetButtonRandom, presetButtonShow;
//Window Setup
w = Window( "The Tunnel", Rect( 128, 230, 280, 620));
w.view.decorator = layout = FlowLayout( w.view.bounds );
w.front;
//Master Knobs
StaticText(w, 150@20).string_("Master").font = titleFont; layout.nextLine;
ampControlSpec = ControlSpec(0, 10, lin, 0.001);
ampKnob = EZKnob(w, knobSize, "Amp", ampControlSpec, action: {|inValue| ~tunnel.set(amp, inValue.value);}, layout:vert2);
layout.nextLine;
//LFO Knobs
lfoDepthControlSpec = ControlSpec(1, 1000, lin, 0.01);
lfoSpeedControlSpec = ControlSpec(0.001, 100, lin, 0.001);
StaticText(w, 150@20).string_("LFO").font = titleFont; layout.nextLine;
lfo1SpeedKnob = EZKnob(w, knobSize, "Lfo1Speed", lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo1Speed, inValue.value);}, layout:vert2);
lfo1DepthKnob = EZKnob(w, knobSize, "Lfo1Depth", lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo1Depth, inValue.value);}, layout:vert2);
lfo2SpeedKnob = EZKnob(w, knobSize, "Lfo2Speed", lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo2Speed, inValue.value);}, layout:vert2);
lfo2DepthKnob = EZKnob(w, knobSize, "Lfo2Depth", lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo2Depth, inValue.value);}, layout:vert2);
layout.nextLine;
//OSC Knobs
osc1FreqControlSpec = ControlSpec(0.5, 50, lin, 0.001);
loSineFreqControlSpec = ControlSpec(1, 100, lin, 0.01);
loSineAmpControlSpec = ControlSpec(0.0, 2, lin, 0.01);
StaticText(w, 150@20).string_("Osc").font = titleFont; layout.nextLine;
osc1FreqKnob = EZKnob(w, knobSize, "osc1Freq", osc1FreqControlSpec, action: {|inValue| ~tunnel.set(osc1Freq, inValue.value);}, layout:vert2);
loSineFreqKnob = EZKnob(w, knobSize, "loSineFreq", loSineFreqControlSpec, action: {|inValue| ~tunnel.set(loSineFreq, inValue.value);}, layout:vert2);
loSineAmpKnob = EZKnob(w, knobSize, "loSineAmp", loSineAmpControlSpec, action: {|inValue| ~tunnel.set(loSineAmp, inValue.value);}, layout:vert2);
layout.nextLine;
//Clip Knobs
clipAmpControlSpec = ControlSpec(1, 6, lin, 0.001);
clipModControlSpec = ControlSpec(10, 500, lin, 0.01);
StaticText(w, 150@20).string_("Clip").font = titleFont; layout.nextLine;
clip1AmpKnob = EZKnob(w, knobSize, "clip1Amp", clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip1Amp, inValue.value);}, layout:vert2);
clipModFreqKnob = EZKnob(w, knobSize, "clipModFreq", clipModControlSpec, action: {|inValue| ~tunnel.set(clipModFreq, inValue.value);}, layout:vert2);
clip2AmpKnob = EZKnob(w, knobSize, "clip2Amp", clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip2Amp, inValue.value);}, layout:vert2);
//Verb Knobs
verbControlSpec = ControlSpec(0, 1, lin, 0.0001);
StaticText(w, 150@20).string_("Reverb").font = titleFont; layout.nextLine;
verbLfoSpeedKnob = EZKnob(w, knobSize, "lfoSpeed", verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoSpeed, inValue.value);}, layout:vert2);
verbLfoDepthKnob = EZKnob(w, knobSize, "lfoDepth", verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoDepth, inValue.value);}, layout:vert2);
verbRoomKnob = EZKnob(w, knobSize, "verbRoom", verbControlSpec, action: {|inValue| ~tunnel.set(verbRoom, inValue.value);}, layout:vert2);
verbDampKnob = EZKnob(w, knobSize, "verbDamp", verbControlSpec, action: {|inValue| ~tunnel.set(verbDamp, inValue.value);}, layout:vert2);
layout.nextLine;
//Preset Buttons
callPreset = { | presetNum |
ampKnob.valueAction = ~presets[presetNum][0];
lfo1SpeedKnob.valueAction = ~presets[presetNum][1];
lfo1DepthKnob.valueAction = ~presets[presetNum][2];
lfo2SpeedKnob.valueAction = ~presets[presetNum][3];
lfo2DepthKnob.valueAction = ~presets[presetNum][4];
osc1FreqKnob.valueAction = ~presets[presetNum][5];
loSineFreqKnob.valueAction = ~presets[presetNum][6];
loSineAmpKnob.valueAction = ~presets[presetNum][7];
clip1AmpKnob.valueAction = ~presets[presetNum][8];
clipModFreqKnob.valueAction = ~presets[presetNum][9];
clip2AmpKnob.valueAction = ~presets[presetNum][10];
verbLfoSpeedKnob.valueAction = ~presets[presetNum][11];
verbLfoDepthKnob.valueAction = ~presets[presetNum][12];
verbRoomKnob.valueAction = ~presets[presetNum][13];
verbDampKnob.valueAction = ~presets[presetNum][14];
};
StaticText(w, 150@20).string_("Presets").font = titleFont; layout.nextLine;
presetButton1 = (Button(w, buttonSize).states = [["1", Color.black]]).action = {callPreset.value(0);};
presetButton2 = (Button(w, buttonSize).states = [["2", Color.black]]).action = {callPreset.value(1);};
presetButton3 = (Button(w, buttonSize).states = [["3", Color.black]]).action = {callPreset.value(2);};
presetButton4 = (Button(w, buttonSize).states = [["4", Color.black]]).action = {callPreset.value(3);};
presetButton5 = (Button(w, buttonSize).states = [["5", Color.black]]).action = {callPreset.value(4);};
presetButton6 = (Button(w, buttonSize).states = [["6", Color.black]]).action = {callPreset.value(5);};
presetButton7 = (Button(w, buttonSize).states = [["7", Color.black]]).action = {callPreset.value(6);};
presetButton8 = (Button(w, buttonSize).states = [["8", Color.black]]).action = {callPreset.value(7);};
presetButton9 = (Button(w, buttonSize).states = [["9", Color.black]]).action = {callPreset.value(8);};
presetButton10 = (Button(w, buttonSize).states = [["10", Color.black]]).action = {callPreset.value(9);};
presetButton11 = (Button(w, buttonSize).states = [["11", Color.black]]).action = {callPreset.value(10);};
presetButtonRandom = (Button(w, buttonSize).states = [["R", Color.black]]).action = {
ampKnob.valueAction = ampControlSpec.map(1.0.rand); lfo1SpeedKnob.valueAction = lfoSpeedControlSpec.map(1.0.rand);
lfo1DepthKnob.valueAction = lfoDepthControlSpec.map(1.0.rand); lfo2SpeedKnob.valueAction = lfoSpeedControlSpec.map(1.0.rand);
lfo2DepthKnob.valueAction = lfoDepthControlSpec.map(1.0.rand); osc1FreqKnob.valueAction = osc1FreqControlSpec.map(1.0.rand);
loSineFreqKnob.valueAction = loSineFreqControlSpec.map(1.0.rand); loSineAmpKnob.valueAction = loSineAmpControlSpec.map(1.0.rand);
clip1AmpKnob.valueAction = clipAmpControlSpec.map(1.0.rand); clipModFreqKnob.valueAction = clipModControlSpec.map(1.0.rand);
clip2AmpKnob.valueAction = clipAmpControlSpec.map(1.0.rand); verbLfoSpeedKnob.valueAction = verbControlSpec.map(1.0.rand);
verbLfoDepthKnob.valueAction = verbControlSpec.map(1.0.rand); verbRoomKnob.valueAction = verbControlSpec.map(1.0.rand);
verbDampKnob.valueAction = verbControlSpec.map(1.0.rand); };
presetButtonShow = (Button(w, buttonSize).states = [["S", Color.black]]).action = {
~tunnel.get(amp, {|val| ("amp:" ++ val.value).postln;});
~tunnel.get(lfo1Speed, {|val| ("lfo1Speed:" ++ val.value).postln;});
~tunnel.get(lfo1Depth, {|val| ("lfo1Depth:" ++ val.value).postln;});
~tunnel.get(lfo2Speed, {|val| ("lfo2Speed:" ++ val.value).postln;});
~tunnel.get(lfo2Depth, {|val| ("lfo2Depth:" ++ val.value).postln;});
~tunnel.get(osc1Freq, {|val| ("osc1Freq:" ++ val.value).postln;});
~tunnel.get(loSineFreq, {|val| ("loSineFreq:" ++ val.value).postln;});
~tunnel.get(loSineAmp, {|val| ("loSineAmp:" ++ val.value).postln;});
~tunnel.get(clip1Amp, {|val| ("clip1Amp:" ++ val.value).postln;});
~tunnel.get(clipModFreq, {|val| ("clipModFreq:" ++ val.value).postln;});
~tunnel.get(clip2Amp, {|val| ("clip2Amp:" ++ val.value).postln;});
~tunnel.get(verbLfoSpeed, {|val| ("verbLfoSpeed:" ++ val.value).postln;});
~tunnel.get(verbLfoDepth, {|val| ("verbLfoDepth:" ++ val.value).postln;});
~tunnel.get(verbRoom, {|val| ("verbRoom:" ++ val.value).postln;});
~tunnel.get(verbDamp, {|val| ("verbDamp:" ++ val.value).postln;});
};
//Set all knobs equal to current bus values so that if the gui is recreated it matches the playing synth
~tunnel.get(amp, {|val| AppClock.sched(0.0,{ ampKnob.value = val.value;});});
~tunnel.get(lfo1Speed, {|val| AppClock.sched(0.0,{ lfo1SpeedKnob.value = val.value;});});
~tunnel.get(lfo1Depth, {|val| AppClock.sched(0.0,{ lfo1DepthKnob.value = val.value;});});
~tunnel.get(lfo2Speed, {|val| AppClock.sched(0.0,{ lfo2SpeedKnob.value = val.value;});});
~tunnel.get(lfo2Depth, {|val| AppClock.sched(0.0,{ lfo2DepthKnob.value = val.value;});});
~tunnel.get(osc1Freq, {|val| AppClock.sched(0.0,{ osc1FreqKnob.value = val.value;});});
~tunnel.get(loSineFreq, {|val| AppClock.sched(0.0,{ loSineFreqKnob.value = val.value;});});
~tunnel.get(loSineAmp, {|val| AppClock.sched(0.0,{ loSineAmpKnob.value = val.value;});});
~tunnel.get(clip1Amp, {|val| AppClock.sched(0.0,{ clip1AmpKnob.value = val.value;});});
~tunnel.get(clipModFreq, {|val| AppClock.sched(0.0,{ clipModFreqKnob.value = val.value;});});
~tunnel.get(clip2Amp, {|val| AppClock.sched(0.0,{ clip2AmpKnob.value = val.value;});});
~tunnel.get(verbLfoSpeed, {|val| AppClock.sched(0.0,{ verbLfoSpeedKnob.value = val.value;});});
~tunnel.get(verbLfoDepth, {|val| AppClock.sched(0.0,{ verbLfoDepthKnob.value = val.value;});});
~tunnel.get(verbRoom, {|val| AppClock.sched(0.0,{ verbRoomKnob.value = val.value;});});
~tunnel.get(verbDamp, {|val| AppClock.sched(0.0,{ verbDampKnob.value = val.value;});});
//----------Tunnel MIDI----------
//Init MIDI
MIDIIn.connect;
MIDIIn.noteOn = nil;
NoteOnResponder.removeAll;
NoteOnResponder({~presetButton1.doAction;}, nil, nil, 64, nil);
NoteOnResponder({~presetButton2.doAction;}, nil, nil, 65, nil);
NoteOnResponder({~presetButton3.doAction;}, nil, nil, 66, nil);
NoteOnResponder({~presetButton4.doAction;}, nil, nil, 67, nil);
NoteOnResponder({~presetButton5.doAction;}, nil, nil, 68, nil);
NoteOnResponder({~presetButton6.doAction;}, nil, nil, 69, nil);
NoteOnResponder({~presetButton7.doAction;}, nil, nil, 70, nil);
NoteOnResponder({~presetButton8.doAction;}, nil, nil, 71, nil);
NoteOnResponder({~presetButton9.doAction;}, nil, nil, 72, nil);
NoteOnResponder({~presetButton10.doAction;}, nil, nil, 73, nil);
NoteOnResponder({~presetButton11.doAction;}, nil, nil, 74, nil);
)
(//----------Tunnel SynthDef---------- SynthDef(TheTunnel, { | out = 0, amp = 1, lfo1Speed = 0.1, lfo1Depth = 100, lfo2Speed = 0.25, lfo2Depth = 600, osc1Freq = 7, loSineFreq = 30, loSineAmp = 0.5, clip1Amp = 6, clipModFreq = 500, clip2Amp = 6, verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1, verbDamp = 0.5 | var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp); //Osc1 var osc1 = SinOsc.ar(osc1Freq); //Osc2 var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only var osc2 = SinOsc.ar(lfo1 * lfo1Depth); //Osc3 var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only var osc3 = SinOsc.ar(lfo2 * lfo2Depth); //Sum and Clip var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq); //Output var output = (clip1 * clip2Amp).distort * 0.5 + loSine; var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth; var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp); Out.ar(out, verb1!2); }, [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]).store; ) (//----------Synth Setup---------- //----Start Synth---- ~tunnel = Synth(TheTunnel); ~presets = [ // amp, lfo1Speed, lfo1Depth, lfo2Speed, lfo2Depth, osc1Freq, loSineFreq, loSineAmp, clip1Amp, clipModFreq, clip2Amp, verbLfoSpeed, verbLfoDepth, verbRoom, verbDamp [ 1, 0.1, 100, 0.25, 600, 7, 30, 0.5, 6, 500, 6, 0.014, 1, 1, 0.5 ], [ 1, 030.756, 628.79, 0.25, 600, 35.412, 11.8, 0.5, 6, 500, 6, 0.151, 0.204, 1, 1 ], [ 2, 048.345, 446.41, 45.021, 694.56, 14.97, 42.53, 0.14, 1.833, 168.49, 1, 0.014, 0.314, 1, 0 ], [ 1.5, 0.507, 1000, 6.285, 317.08, 34.579, 31.77, 0.5, 3.672, 44.59, 3.492, 0.316, 0.49, 0.461, 1 ], [ 1.5, 0.507, 288.03, 0.67, 317.08, 10.449, 88.06, 0.37, 2.557, 44.59, 3.492, 0.155, 1, 1, 1 ], [ 0.575, 100, 1000, 96.903, 1000, 50, 88.06, 1.22, 6, 127.37, 6, 0.167, 0.493, 1, 1 ], [ 1.2, 1, 101.3, 1.5, 74.79, 11.691, 5.2, 0, 3.225, 49.8, 2.754, 0.51, 0.494, 0.784, 0.497 ], [ 2.852, 0.001, 80.79, 100, 306.59, 11.691, 5.2, 0, 3.225, 49.8, 3.734, 0.273, 0.656, 0.784, 0.889 ], [ 1.116, 71.939, 631.92, 72.476, 427.99, 17.475, 96.68, 0.56, 4.298, 496.15, 5.649, 0.804, 0.694, 0.303, 0.461 ], [ 0.979, 34.043, 650.05, 29.176, 480.98, 30.836, 66.66, 1.13, 2.401, 205.91, 2.664, 0.173, 0.778, 0.517, 0.88 ], [ 2.206, 22.558, 217.5, 91.033, 520.13, 3.484, 84.09, 1.59, 2.731, 259.07, 5.919, 0.571, 0.988, 0.133, 0.0 ] ]; ) (//----------Tunnel GUI---------- //Global Variables var layout; var knobSize = 60@80; var buttonSize = 20@20; var titleFont = Font( "Times-Bold", 25 ); //Knob Variables var ampControlSpec, ampKnob; var lfoSpeedControlSpec, lfoDepthControlSpec, lfo1SpeedKnob, lfo1DepthKnob, lfo2SpeedKnob, lfo2DepthKnob; var osc1FreqControlSpec, loSineFreqControlSpec, loSineAmpControlSpec, osc1FreqKnob, loSineFreqKnob, loSineAmpKnob; var clipAmpControlSpec, clipModControlSpec, clip1AmpKnob, clipModFreqKnob, clip2AmpKnob; var verbControlSpec, verbLfoSpeedKnob, verbLfoDepthKnob, verbRoomKnob, verbDampKnob; //Button Variables var callPreset, presetButton1, presetButton2, presetButton3, presetButton4, presetButton5, presetButton6, presetButton7, presetButton8, presetButton9, presetButton10, presetButton11, presetButtonRandom, presetButtonShow; //Window Setup w = Window( "The Tunnel", Rect( 128, 230, 280, 620)); w.view.decorator = layout = FlowLayout( w.view.bounds ); w.front; //Master Knobs StaticText(w, 150@20).string_("Master").font = titleFont; layout.nextLine; ampControlSpec = ControlSpec(0, 10, lin, 0.001); ampKnob = EZKnob(w, knobSize, "Amp", ampControlSpec, action: {|inValue| ~tunnel.set(amp, inValue.value);}, layout:vert2); layout.nextLine; //LFO Knobs lfoDepthControlSpec = ControlSpec(1, 1000, lin, 0.01); lfoSpeedControlSpec = ControlSpec(0.001, 100, lin, 0.001); StaticText(w, 150@20).string_("LFO").font = titleFont; layout.nextLine; lfo1SpeedKnob = EZKnob(w, knobSize, "Lfo1Speed", lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo1Speed, inValue.value);}, layout:vert2); lfo1DepthKnob = EZKnob(w, knobSize, "Lfo1Depth", lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo1Depth, inValue.value);}, layout:vert2); lfo2SpeedKnob = EZKnob(w, knobSize, "Lfo2Speed", lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo2Speed, inValue.value);}, layout:vert2); lfo2DepthKnob = EZKnob(w, knobSize, "Lfo2Depth", lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo2Depth, inValue.value);}, layout:vert2); layout.nextLine; //OSC Knobs osc1FreqControlSpec = ControlSpec(0.5, 50, lin, 0.001); loSineFreqControlSpec = ControlSpec(1, 100, lin, 0.01); loSineAmpControlSpec = ControlSpec(0.0, 2, lin, 0.01); StaticText(w, 150@20).string_("Osc").font = titleFont; layout.nextLine; osc1FreqKnob = EZKnob(w, knobSize, "osc1Freq", osc1FreqControlSpec, action: {|inValue| ~tunnel.set(osc1Freq, inValue.value);}, layout:vert2); loSineFreqKnob = EZKnob(w, knobSize, "loSineFreq", loSineFreqControlSpec, action: {|inValue| ~tunnel.set(loSineFreq, inValue.value);}, layout:vert2); loSineAmpKnob = EZKnob(w, knobSize, "loSineAmp", loSineAmpControlSpec, action: {|inValue| ~tunnel.set(loSineAmp, inValue.value);}, layout:vert2); layout.nextLine; //Clip Knobs clipAmpControlSpec = ControlSpec(1, 6, lin, 0.001); clipModControlSpec = ControlSpec(10, 500, lin, 0.01); StaticText(w, 150@20).string_("Clip").font = titleFont; layout.nextLine; clip1AmpKnob = EZKnob(w, knobSize, "clip1Amp", clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip1Amp, inValue.value);}, layout:vert2); clipModFreqKnob = EZKnob(w, knobSize, "clipModFreq", clipModControlSpec, action: {|inValue| ~tunnel.set(clipModFreq, inValue.value);}, layout:vert2); clip2AmpKnob = EZKnob(w, knobSize, "clip2Amp", clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip2Amp, inValue.value);}, layout:vert2); //Verb Knobs verbControlSpec = ControlSpec(0, 1, lin, 0.0001); StaticText(w, 150@20).string_("Reverb").font = titleFont; layout.nextLine; verbLfoSpeedKnob = EZKnob(w, knobSize, "lfoSpeed", verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoSpeed, inValue.value);}, layout:vert2); verbLfoDepthKnob = EZKnob(w, knobSize, "lfoDepth", verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoDepth, inValue.value);}, layout:vert2); verbRoomKnob = EZKnob(w, knobSize, "verbRoom", verbControlSpec, action: {|inValue| ~tunnel.set(verbRoom, inValue.value);}, layout:vert2); verbDampKnob = EZKnob(w, knobSize, "verbDamp", verbControlSpec, action: {|inValue| ~tunnel.set(verbDamp, inValue.value);}, layout:vert2); layout.nextLine; //Preset Buttons callPreset = { | presetNum | ampKnob.valueAction = ~presets[presetNum][0]; lfo1SpeedKnob.valueAction = ~presets[presetNum][1]; lfo1DepthKnob.valueAction = ~presets[presetNum][2]; lfo2SpeedKnob.valueAction = ~presets[presetNum][3]; lfo2DepthKnob.valueAction = ~presets[presetNum][4]; osc1FreqKnob.valueAction = ~presets[presetNum][5]; loSineFreqKnob.valueAction = ~presets[presetNum][6]; loSineAmpKnob.valueAction = ~presets[presetNum][7]; clip1AmpKnob.valueAction = ~presets[presetNum][8]; clipModFreqKnob.valueAction = ~presets[presetNum][9]; clip2AmpKnob.valueAction = ~presets[presetNum][10]; verbLfoSpeedKnob.valueAction = ~presets[presetNum][11]; verbLfoDepthKnob.valueAction = ~presets[presetNum][12]; verbRoomKnob.valueAction = ~presets[presetNum][13]; verbDampKnob.valueAction = ~presets[presetNum][14]; }; StaticText(w, 150@20).string_("Presets").font = titleFont; layout.nextLine; presetButton1 = (Button(w, buttonSize).states = [["1", Color.black]]).action = {callPreset.value(0);}; presetButton2 = (Button(w, buttonSize).states = [["2", Color.black]]).action = {callPreset.value(1);}; presetButton3 = (Button(w, buttonSize).states = [["3", Color.black]]).action = {callPreset.value(2);}; presetButton4 = (Button(w, buttonSize).states = [["4", Color.black]]).action = {callPreset.value(3);}; presetButton5 = (Button(w, buttonSize).states = [["5", Color.black]]).action = {callPreset.value(4);}; presetButton6 = (Button(w, buttonSize).states = [["6", Color.black]]).action = {callPreset.value(5);}; presetButton7 = (Button(w, buttonSize).states = [["7", Color.black]]).action = {callPreset.value(6);}; presetButton8 = (Button(w, buttonSize).states = [["8", Color.black]]).action = {callPreset.value(7);}; presetButton9 = (Button(w, buttonSize).states = [["9", Color.black]]).action = {callPreset.value(8);}; presetButton10 = (Button(w, buttonSize).states = [["10", Color.black]]).action = {callPreset.value(9);}; presetButton11 = (Button(w, buttonSize).states = [["11", Color.black]]).action = {callPreset.value(10);}; presetButtonRandom = (Button(w, buttonSize).states = [["R", Color.black]]).action = { ampKnob.valueAction = ampControlSpec.map(1.0.rand); lfo1SpeedKnob.valueAction = lfoSpeedControlSpec.map(1.0.rand); lfo1DepthKnob.valueAction = lfoDepthControlSpec.map(1.0.rand); lfo2SpeedKnob.valueAction = lfoSpeedControlSpec.map(1.0.rand); lfo2DepthKnob.valueAction = lfoDepthControlSpec.map(1.0.rand); osc1FreqKnob.valueAction = osc1FreqControlSpec.map(1.0.rand); loSineFreqKnob.valueAction = loSineFreqControlSpec.map(1.0.rand); loSineAmpKnob.valueAction = loSineAmpControlSpec.map(1.0.rand); clip1AmpKnob.valueAction = clipAmpControlSpec.map(1.0.rand); clipModFreqKnob.valueAction = clipModControlSpec.map(1.0.rand); clip2AmpKnob.valueAction = clipAmpControlSpec.map(1.0.rand); verbLfoSpeedKnob.valueAction = verbControlSpec.map(1.0.rand); verbLfoDepthKnob.valueAction = verbControlSpec.map(1.0.rand); verbRoomKnob.valueAction = verbControlSpec.map(1.0.rand); verbDampKnob.valueAction = verbControlSpec.map(1.0.rand); }; presetButtonShow = (Button(w, buttonSize).states = [["S", Color.black]]).action = { ~tunnel.get(amp, {|val| ("amp:" ++ val.value).postln;}); ~tunnel.get(lfo1Speed, {|val| ("lfo1Speed:" ++ val.value).postln;}); ~tunnel.get(lfo1Depth, {|val| ("lfo1Depth:" ++ val.value).postln;}); ~tunnel.get(lfo2Speed, {|val| ("lfo2Speed:" ++ val.value).postln;}); ~tunnel.get(lfo2Depth, {|val| ("lfo2Depth:" ++ val.value).postln;}); ~tunnel.get(osc1Freq, {|val| ("osc1Freq:" ++ val.value).postln;}); ~tunnel.get(loSineFreq, {|val| ("loSineFreq:" ++ val.value).postln;}); ~tunnel.get(loSineAmp, {|val| ("loSineAmp:" ++ val.value).postln;}); ~tunnel.get(clip1Amp, {|val| ("clip1Amp:" ++ val.value).postln;}); ~tunnel.get(clipModFreq, {|val| ("clipModFreq:" ++ val.value).postln;}); ~tunnel.get(clip2Amp, {|val| ("clip2Amp:" ++ val.value).postln;}); ~tunnel.get(verbLfoSpeed, {|val| ("verbLfoSpeed:" ++ val.value).postln;}); ~tunnel.get(verbLfoDepth, {|val| ("verbLfoDepth:" ++ val.value).postln;}); ~tunnel.get(verbRoom, {|val| ("verbRoom:" ++ val.value).postln;}); ~tunnel.get(verbDamp, {|val| ("verbDamp:" ++ val.value).postln;}); }; //Set all knobs equal to current bus values so that if the gui is recreated it matches the playing synth ~tunnel.get(amp, {|val| AppClock.sched(0.0,{ ampKnob.value = val.value;});}); ~tunnel.get(lfo1Speed, {|val| AppClock.sched(0.0,{ lfo1SpeedKnob.value = val.value;});}); ~tunnel.get(lfo1Depth, {|val| AppClock.sched(0.0,{ lfo1DepthKnob.value = val.value;});}); ~tunnel.get(lfo2Speed, {|val| AppClock.sched(0.0,{ lfo2SpeedKnob.value = val.value;});}); ~tunnel.get(lfo2Depth, {|val| AppClock.sched(0.0,{ lfo2DepthKnob.value = val.value;});}); ~tunnel.get(osc1Freq, {|val| AppClock.sched(0.0,{ osc1FreqKnob.value = val.value;});}); ~tunnel.get(loSineFreq, {|val| AppClock.sched(0.0,{ loSineFreqKnob.value = val.value;});}); ~tunnel.get(loSineAmp, {|val| AppClock.sched(0.0,{ loSineAmpKnob.value = val.value;});}); ~tunnel.get(clip1Amp, {|val| AppClock.sched(0.0,{ clip1AmpKnob.value = val.value;});}); ~tunnel.get(clipModFreq, {|val| AppClock.sched(0.0,{ clipModFreqKnob.value = val.value;});}); ~tunnel.get(clip2Amp, {|val| AppClock.sched(0.0,{ clip2AmpKnob.value = val.value;});}); ~tunnel.get(verbLfoSpeed, {|val| AppClock.sched(0.0,{ verbLfoSpeedKnob.value = val.value;});}); ~tunnel.get(verbLfoDepth, {|val| AppClock.sched(0.0,{ verbLfoDepthKnob.value = val.value;});}); ~tunnel.get(verbRoom, {|val| AppClock.sched(0.0,{ verbRoomKnob.value = val.value;});}); ~tunnel.get(verbDamp, {|val| AppClock.sched(0.0,{ verbDampKnob.value = val.value;});}); //----------Tunnel MIDI---------- //Init MIDI MIDIIn.connect; MIDIIn.noteOn = nil; NoteOnResponder.removeAll; NoteOnResponder({~presetButton1.doAction;}, nil, nil, 64, nil); NoteOnResponder({~presetButton2.doAction;}, nil, nil, 65, nil); NoteOnResponder({~presetButton3.doAction;}, nil, nil, 66, nil); NoteOnResponder({~presetButton4.doAction;}, nil, nil, 67, nil); NoteOnResponder({~presetButton5.doAction;}, nil, nil, 68, nil); NoteOnResponder({~presetButton6.doAction;}, nil, nil, 69, nil); NoteOnResponder({~presetButton7.doAction;}, nil, nil, 70, nil); NoteOnResponder({~presetButton8.doAction;}, nil, nil, 71, nil); NoteOnResponder({~presetButton9.doAction;}, nil, nil, 72, nil); NoteOnResponder({~presetButton10.doAction;}, nil, nil, 73, nil); NoteOnResponder({~presetButton11.doAction;}, nil, nil, 74, nil); )
(//----------Tunnel SynthDef----------
	SynthDef(TheTunnel, {
		|
			out = 0,								amp = 1,							lfo1Speed = 0.1,				lfo1Depth = 100,			lfo2Speed = 0.25,		
			lfo2Depth = 600,			osc1Freq = 7,				loSineFreq = 30,				loSineAmp = 0.5,			clip1Amp = 6,		
			clipModFreq = 500,		clip2Amp = 6,				verbLfoSpeed = 0.014, 	verbLfoDepth = 1, 		verbRoom = 1, 
			verbDamp = 0.5
		|
		var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
		//Osc1
		var osc1 = SinOsc.ar(osc1Freq);
		//Osc2
		var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
		var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
		//Osc3
		var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
		var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
		//Sum and Clip
		var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
		//Output
		var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
		var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
		var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
		Out.ar(out, verb1!2);
	}, [0, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]).store; 
)

(//----------Synth Setup----------
	
	//----Start Synth----
	~tunnel = Synth(TheTunnel);
	~presets = 
		[
			//	amp,			lfo1Speed,	lfo1Depth,	lfo2Speed,	lfo2Depth,	osc1Freq,	loSineFreq,	loSineAmp,	clip1Amp,	clipModFreq,	clip2Amp,	verbLfoSpeed,	verbLfoDepth,	verbRoom,	verbDamp
			[		1, 				0.1,				100, 			0.25, 			600, 			7, 					30, 					0.5,				6, 					500, 					6, 					0.014,					1, 							1, 					0.5				],
			[		1, 				030.756,		628.79, 		0.25, 			600, 			35.412, 		11.8, 				0.5,				6, 					500, 					6, 					0.151, 				0.204, 				1, 					1					],
			[		2, 				048.345,		446.41, 		45.021,		694.56, 		14.97, 		42.53, 			0.14,			1.833, 		168.49,				1, 					0.014, 				0.314, 				1, 					0					],
			[		1.5, 		0.507, 		1000, 			6.285, 		317.08, 		34.579, 		31.77, 			0.5, 			3.672, 		44.59, 				3.492, 		0.316, 				0.49, 					0.461, 		1					],
			[		1.5, 		0.507, 		288.03,		0.67, 			317.08, 		10.449, 		88.06, 			0.37, 			2.557, 		44.59, 				3.492, 		0.155, 				1, 							1, 					1					],
			[		0.575,		100, 			1000, 			96.903, 		1000, 			50, 				88.06, 			1.22, 			6, 					127.37, 				6, 					0.167, 				0.493, 				1, 					1					],
			[		1.2, 		1, 					101.3, 		1.5, 			74.79, 		11.691, 		5.2, 				0, 					3.225, 		49.8, 					2.754, 		0.51, 					0.494, 				0.784, 		0.497		],
			[		2.852,		0.001, 		80.79, 		100, 			306.59, 		11.691, 		5.2, 				0, 					3.225, 		49.8, 					3.734, 		0.273, 				0.656, 				0.784, 		0.889		],
			[		1.116,		71.939, 		631.92, 		72.476,		427.99, 		17.475, 		96.68, 			0.56, 			4.298, 		496.15, 				5.649, 		0.804, 				0.694, 				0.303, 		0.461		],
			[		0.979,		34.043, 		650.05, 		29.176,		480.98, 		30.836, 		66.66, 			1.13, 			2.401, 		205.91, 				2.664, 		0.173, 				0.778, 				0.517, 		0.88			],
			[		2.206,		22.558, 		217.5,			91.033,		520.13,		3.484,			84.09,				1.59, 			2.731,			259.07, 				5.919,			0.571, 				0.988, 				0.133, 		0.0				]
		];
)

(//----------Tunnel GUI----------
	
	//Global Variables
	var layout;
	var knobSize = 60@80;
	var buttonSize = 20@20;
	var titleFont = Font( "Times-Bold", 25 );

	//Knob Variables
	var ampControlSpec, ampKnob;
	var lfoSpeedControlSpec, lfoDepthControlSpec, lfo1SpeedKnob, lfo1DepthKnob, lfo2SpeedKnob, lfo2DepthKnob;
	var osc1FreqControlSpec, loSineFreqControlSpec, loSineAmpControlSpec, osc1FreqKnob, loSineFreqKnob, loSineAmpKnob;
	var clipAmpControlSpec, clipModControlSpec, clip1AmpKnob, clipModFreqKnob, clip2AmpKnob;
	var verbControlSpec, verbLfoSpeedKnob, verbLfoDepthKnob, verbRoomKnob, verbDampKnob;

	//Button Variables
	var callPreset, presetButton1, presetButton2, presetButton3, presetButton4, presetButton5, presetButton6, presetButton7, presetButton8, presetButton9, presetButton10, 
			presetButton11, presetButtonRandom, presetButtonShow;

	//Window Setup
	w = Window( "The Tunnel", Rect( 128, 230, 280, 620)); 
	w.view.decorator = layout = FlowLayout( w.view.bounds ); 
	w.front;

	//Master Knobs
	StaticText(w, 150@20).string_("Master").font = titleFont;	layout.nextLine;
	ampControlSpec = ControlSpec(0, 10, lin, 0.001);
	ampKnob = EZKnob(w, knobSize, "Amp",	ampControlSpec, action: {|inValue| ~tunnel.set(amp, inValue.value);}, layout:vert2);
	layout.nextLine;

	//LFO Knobs
	lfoDepthControlSpec = ControlSpec(1, 1000, lin, 0.01);
	lfoSpeedControlSpec = ControlSpec(0.001, 100, lin, 0.001);
	StaticText(w, 150@20).string_("LFO").font = titleFont;	layout.nextLine;
	lfo1SpeedKnob = EZKnob(w, knobSize, "Lfo1Speed",	lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo1Speed, inValue.value);}, layout:vert2);
	lfo1DepthKnob = EZKnob(w, knobSize, "Lfo1Depth",	lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo1Depth, inValue.value);}, layout:vert2);
	lfo2SpeedKnob = EZKnob(w, knobSize, "Lfo2Speed",	lfoSpeedControlSpec, action: {|inValue| ~tunnel.set(lfo2Speed, inValue.value);}, layout:vert2);
	lfo2DepthKnob = EZKnob(w, knobSize, "Lfo2Depth",	lfoDepthControlSpec, action: {|inValue| ~tunnel.set(lfo2Depth, inValue.value);}, layout:vert2);
	layout.nextLine;

	//OSC Knobs
	osc1FreqControlSpec = ControlSpec(0.5, 50, lin, 0.001);
	loSineFreqControlSpec = ControlSpec(1, 100, lin, 0.01);
	loSineAmpControlSpec = ControlSpec(0.0, 2, lin, 0.01);
	StaticText(w, 150@20).string_("Osc").font = titleFont;	layout.nextLine;
	osc1FreqKnob = EZKnob(w, knobSize, "osc1Freq",	osc1FreqControlSpec, action: {|inValue| ~tunnel.set(osc1Freq, inValue.value);}, layout:vert2);
	loSineFreqKnob = EZKnob(w, knobSize, "loSineFreq",	loSineFreqControlSpec, action: {|inValue| ~tunnel.set(loSineFreq, inValue.value);}, layout:vert2);
	loSineAmpKnob = EZKnob(w, knobSize, "loSineAmp",	loSineAmpControlSpec, action: {|inValue| ~tunnel.set(loSineAmp, inValue.value);}, layout:vert2);
	layout.nextLine;

	//Clip Knobs
	clipAmpControlSpec = ControlSpec(1, 6, lin, 0.001);
	clipModControlSpec = ControlSpec(10, 500, lin, 0.01);
	StaticText(w, 150@20).string_("Clip").font = titleFont;	layout.nextLine;
	clip1AmpKnob = EZKnob(w, knobSize, "clip1Amp",	clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip1Amp, inValue.value);}, layout:vert2);
	clipModFreqKnob = EZKnob(w, knobSize, "clipModFreq",	clipModControlSpec, action: {|inValue| ~tunnel.set(clipModFreq, inValue.value);}, layout:vert2);
	clip2AmpKnob = EZKnob(w, knobSize, "clip2Amp", clipAmpControlSpec, action: {|inValue| ~tunnel.set(clip2Amp, inValue.value);}, layout:vert2);
		
	//Verb Knobs
	verbControlSpec = ControlSpec(0, 1, lin, 0.0001);
	StaticText(w, 150@20).string_("Reverb").font = titleFont;	layout.nextLine;
	verbLfoSpeedKnob = EZKnob(w, knobSize, "lfoSpeed",	verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoSpeed, inValue.value);}, layout:vert2);
	verbLfoDepthKnob = EZKnob(w, knobSize, "lfoDepth",	verbControlSpec, action: {|inValue| ~tunnel.set(verbLfoDepth, inValue.value);}, layout:vert2);
	verbRoomKnob = EZKnob(w, knobSize, "verbRoom",	verbControlSpec, action: {|inValue| ~tunnel.set(verbRoom, inValue.value);}, layout:vert2);
	verbDampKnob = EZKnob(w, knobSize, "verbDamp",	verbControlSpec, action: {|inValue| ~tunnel.set(verbDamp, inValue.value);}, layout:vert2);
	layout.nextLine;

	//Preset Buttons
	callPreset = { | presetNum |
			ampKnob.valueAction 						= ~presets[presetNum][0];
			lfo1SpeedKnob.valueAction 		= ~presets[presetNum][1];
			lfo1DepthKnob.valueAction			= ~presets[presetNum][2];
			lfo2SpeedKnob.valueAction 		= ~presets[presetNum][3];
			lfo2DepthKnob.valueAction			= ~presets[presetNum][4];
			osc1FreqKnob.valueAction 			= ~presets[presetNum][5];
			loSineFreqKnob.valueAction 		= ~presets[presetNum][6];
			loSineAmpKnob.valueAction 		= ~presets[presetNum][7];
			clip1AmpKnob.valueAction 			= ~presets[presetNum][8];
			clipModFreqKnob.valueAction		= ~presets[presetNum][9];
			clip2AmpKnob.valueAction 			= ~presets[presetNum][10];
			verbLfoSpeedKnob.valueAction	= ~presets[presetNum][11];
			verbLfoDepthKnob.valueAction	= ~presets[presetNum][12];
			verbRoomKnob.valueAction 			= ~presets[presetNum][13];
			verbDampKnob.valueAction 			= ~presets[presetNum][14];
	};

	StaticText(w, 150@20).string_("Presets").font = titleFont;	layout.nextLine;
	presetButton1 			= (Button(w, buttonSize).states = [["1", Color.black]]).action = {callPreset.value(0);};
	presetButton2 			= (Button(w, buttonSize).states = [["2", Color.black]]).action = {callPreset.value(1);};
	presetButton3 			= (Button(w, buttonSize).states = [["3", Color.black]]).action = {callPreset.value(2);};
	presetButton4 			= (Button(w, buttonSize).states = [["4", Color.black]]).action = {callPreset.value(3);};
	presetButton5 			= (Button(w, buttonSize).states = [["5", Color.black]]).action = {callPreset.value(4);};
	presetButton6 			= (Button(w, buttonSize).states = [["6", Color.black]]).action = {callPreset.value(5);};
	presetButton7 			= (Button(w, buttonSize).states = [["7", Color.black]]).action = {callPreset.value(6);};
	presetButton8 			= (Button(w, buttonSize).states = [["8", Color.black]]).action = {callPreset.value(7);};
	presetButton9 			= (Button(w, buttonSize).states = [["9", Color.black]]).action = {callPreset.value(8);};
	presetButton10 			= (Button(w, buttonSize).states = [["10", Color.black]]).action = {callPreset.value(9);};
	presetButton11 			= (Button(w, buttonSize).states = [["11", Color.black]]).action = {callPreset.value(10);};
	presetButtonRandom	= (Button(w, buttonSize).states = [["R", Color.black]]).action = {
			ampKnob.valueAction 						= ampControlSpec.map(1.0.rand);												lfo1SpeedKnob.valueAction 		= lfoSpeedControlSpec.map(1.0.rand);
			lfo1DepthKnob.valueAction 		= lfoDepthControlSpec.map(1.0.rand);									lfo2SpeedKnob.valueAction 		= lfoSpeedControlSpec.map(1.0.rand);
			lfo2DepthKnob.valueAction 		= lfoDepthControlSpec.map(1.0.rand);									osc1FreqKnob.valueAction 			= osc1FreqControlSpec.map(1.0.rand);
			loSineFreqKnob.valueAction 		= loSineFreqControlSpec.map(1.0.rand);								loSineAmpKnob.valueAction 		= loSineAmpControlSpec.map(1.0.rand);
			clip1AmpKnob.valueAction 			= clipAmpControlSpec.map(1.0.rand);									clipModFreqKnob.valueAction		= clipModControlSpec.map(1.0.rand);
			clip2AmpKnob.valueAction 			= clipAmpControlSpec.map(1.0.rand);									verbLfoSpeedKnob.valueAction	= verbControlSpec.map(1.0.rand);
			verbLfoDepthKnob.valueAction 	= verbControlSpec.map(1.0.rand);											verbRoomKnob.valueAction 			= verbControlSpec.map(1.0.rand);
			verbDampKnob.valueAction 			= verbControlSpec.map(1.0.rand);											};
	presetButtonShow 		= (Button(w, buttonSize).states = [["S", Color.black]]).action = {
			~tunnel.get(amp, 						{|val| ("amp:" ++ val.value).postln;});
			~tunnel.get(lfo1Speed,			{|val| ("lfo1Speed:" ++ val.value).postln;});
			~tunnel.get(lfo1Depth,			{|val| ("lfo1Depth:" ++ val.value).postln;});
			~tunnel.get(lfo2Speed,			{|val| ("lfo2Speed:" ++ val.value).postln;});
			~tunnel.get(lfo2Depth,			{|val| ("lfo2Depth:" ++ val.value).postln;});
			~tunnel.get(osc1Freq,				{|val| ("osc1Freq:" ++ val.value).postln;});
			~tunnel.get(loSineFreq,			{|val| ("loSineFreq:" ++ val.value).postln;});
			~tunnel.get(loSineAmp,			{|val| ("loSineAmp:" ++ val.value).postln;});
			~tunnel.get(clip1Amp,				{|val| ("clip1Amp:" ++ val.value).postln;});
			~tunnel.get(clipModFreq,		{|val| ("clipModFreq:" ++ val.value).postln;});
			~tunnel.get(clip2Amp,				{|val| ("clip2Amp:" ++ val.value).postln;});
			~tunnel.get(verbLfoSpeed,	{|val| ("verbLfoSpeed:" ++ val.value).postln;});
			~tunnel.get(verbLfoDepth,	{|val| ("verbLfoDepth:" ++ val.value).postln;});
			~tunnel.get(verbRoom,				{|val| ("verbRoom:" ++ val.value).postln;});
			~tunnel.get(verbDamp,				{|val| ("verbDamp:" ++ val.value).postln;});
	};

	//Set all knobs equal to current bus values so that if the gui is recreated it matches the playing synth
	~tunnel.get(amp, 						{|val| AppClock.sched(0.0,{ ampKnob.value = val.value;});});
	~tunnel.get(lfo1Speed,			{|val| AppClock.sched(0.0,{ lfo1SpeedKnob.value = val.value;});});
	~tunnel.get(lfo1Depth,			{|val| AppClock.sched(0.0,{ lfo1DepthKnob.value = val.value;});});
	~tunnel.get(lfo2Speed,			{|val| AppClock.sched(0.0,{ lfo2SpeedKnob.value = val.value;});});
	~tunnel.get(lfo2Depth,			{|val| AppClock.sched(0.0,{ lfo2DepthKnob.value = val.value;});});
	~tunnel.get(osc1Freq,				{|val| AppClock.sched(0.0,{ osc1FreqKnob.value = val.value;});});
	~tunnel.get(loSineFreq,			{|val| AppClock.sched(0.0,{ loSineFreqKnob.value = val.value;});});
	~tunnel.get(loSineAmp,			{|val| AppClock.sched(0.0,{ loSineAmpKnob.value = val.value;});});
	~tunnel.get(clip1Amp,				{|val| AppClock.sched(0.0,{ clip1AmpKnob.value = val.value;});});
	~tunnel.get(clipModFreq,		{|val| AppClock.sched(0.0,{ clipModFreqKnob.value = val.value;});});
	~tunnel.get(clip2Amp,				{|val| AppClock.sched(0.0,{ clip2AmpKnob.value = val.value;});});
	~tunnel.get(verbLfoSpeed,	{|val| AppClock.sched(0.0,{ verbLfoSpeedKnob.value = val.value;});});
	~tunnel.get(verbLfoDepth,	{|val| AppClock.sched(0.0,{ verbLfoDepthKnob.value = val.value;});});
	~tunnel.get(verbRoom,				{|val| AppClock.sched(0.0,{ verbRoomKnob.value = val.value;});});
	~tunnel.get(verbDamp,				{|val| AppClock.sched(0.0,{ verbDampKnob.value = val.value;});});

//----------Tunnel MIDI----------
	//Init MIDI
	MIDIIn.connect;
	MIDIIn.noteOn = nil;
	NoteOnResponder.removeAll;
	NoteOnResponder({~presetButton1.doAction;}, nil, nil, 64, nil); 
	NoteOnResponder({~presetButton2.doAction;}, nil, nil, 65, nil); 
	NoteOnResponder({~presetButton3.doAction;}, nil, nil, 66, nil); 
	NoteOnResponder({~presetButton4.doAction;}, nil, nil, 67, nil); 
	NoteOnResponder({~presetButton5.doAction;}, nil, nil, 68, nil); 
	NoteOnResponder({~presetButton6.doAction;}, nil, nil, 69, nil); 
	NoteOnResponder({~presetButton7.doAction;}, nil, nil, 70, nil); 
	NoteOnResponder({~presetButton8.doAction;}, nil, nil, 71, nil); 
	NoteOnResponder({~presetButton9.doAction;}, nil, nil, 72, nil);
	NoteOnResponder({~presetButton10.doAction;}, nil, nil, 73, nil);
	NoteOnResponder({~presetButton11.doAction;}, nil, nil, 74, nil);
)                                 


While the knobs were fun to experiment with I eventually realized that individual knob moves were not going to get me to where I needed to go with this track. I scrapped the midi input and scrapped all the GUI code except for the preset system. I increased the lag times on the synthdef to 30 seconds so that each time I chose a preset it would morph from one preset to the other. Then I made a task that posted the elapsed time since the synth started running to the post window. I used this as my guide and made notes of which presets sounded good merging into each other and how long I wanted to let each hold. In the end I only ended up using a handfull of the presets. My final ‘performance’ code starts the recording, executes the patch changes and then stops the recording. If you attempt to run this code you will need to change the directory referance to a valid one on your system.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
(//----------Tunnel SynthDef----------
SynthDef(TheTunnel, {
|
out = 0, amp = 1, lfo1Speed = 0.1, lfo1Depth = 100, lfo2Speed = 0.25,
lfo2Depth = 600, osc1Freq = 7, loSineFreq = 30, loSineAmp = 0.5, clip1Amp = 6,
clipModFreq = 500, clip2Amp = 6, verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1,
verbDamp = 0.5
|
var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
//Osc1
var osc1 = SinOsc.ar(osc1Freq);
//Osc2
var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
//Osc3
var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
//Sum and Clip
var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
//Output
var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
Out.ar(out, verb1!2 * 0.5);
}, [0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]).add;
)
(
//----Start Synth----
~tunnelSynth = Synth(TheTunnel);
//----Preset----
~tunnelPreset = ();
~tunnelPreset.current = 0;
~tunnelPreset.list = [
// amp, lfo1Speed, lfo1Depth, lfo2Speed, lfo2Depth, osc1Freq, loSineFreq, loSineAmp, clip1Amp, clipModFreq, clip2Amp, verbLfoSpeed, verbLfoDepth, verbRoom, verbDamp
/*00*/ [ 1, 0.1, 100, 0.25, 600, 7, 30, 0.5, 6, 500, 6, 0.014, 1, 1, 0.5 ],
/*01*/ [ 1, 30.756, 628.79, 0.25, 600, 35.412, 11.8, 0.5, 6, 500, 6, 0.151, 0.204, 1, 1 ],
/*02*/ [ 1, 48.345, 446.41, 45.021, 694.56, 14.97, 42.53, 0.14, 1.833, 168.49, 1, 0.014, 0.314, 1, 0 ],
/*03*/ [ 1.163, 0.507, 1000, 6.285, 317.08, 34.579, 31.77, 0.5, 3.672, 44.59, 3.492, 0.316, 0.49, 0.461, 1 ],
/*04*/ [ 1.392, 0.507, 288.03, 0.67, 317.08, 10.449, 88.06, 0.37, 2.557, 44.59, 3.492, 0.155, 1, 1, 1 ],
/*05*/ [ 0.575, 100, 1000, 96.903, 1000, 50, 88.06, 1.22, 6, 127.37, 6, 0.167, 0.493, 1, 1 ],
/*06*/ [ 3.2, 1, 101.3, 1.5, 74.79, 11.691, 5.2, 0, 3.225, 49.8, 2.754, 0.51, 0.494, 0.784, 0.497 ],
/*07*/ [ 2.505, 0.001, 80.79, 100, 306.59, 11.691, 5.2, 0, 3.225, 49.8, 3.734, 0.273, 0.656, 0.784, 0.889 ],
/*08*/ [ 0.9, 71.939, 631.92, 72.476, 427.99, 17.475, 96.68, 0.56, 4.298, 496.15, 5.649, 0.804, 0.694, 0.303, 0.461 ],
/*09*/ [ 0.6, 34.043, 650.05, 29.176, 480.98, 30.836, 66.66, 1.13, 2.401, 205.91, 2.664, 0.173, 0.778, 0.517, 0.88 ],
/*10*/ [ 0.54, 22.558, 217.5, 91.033, 520.13, 3.484, 84.09, 1.59, 2.731, 259.07, 5.919, 0.571, 0.988, 0.133, 0.0 ]
];
~tunnelPreset.load = { |ev|
var current = ev.current;
~tunnelSynth.set(amp, ev.list[current][0]);
~tunnelSynth.set(lfo1Speed, ev.list[current][1]);
~tunnelSynth.set(lfo1Depth, ev.list[current][2]);
~tunnelSynth.set(lfo2Speed, ev.list[current][3]);
~tunnelSynth.set(lfo2Depth, ev.list[current][4]);
~tunnelSynth.set(osc1Freq, ev.list[current][5]);
~tunnelSynth.set(loSineFreq, ev.list[current][6]);
~tunnelSynth.set(loSineAmp, ev.list[current][7]);
~tunnelSynth.set(clip1Amp, ev.list[current][8]);
~tunnelSynth.set(clipModFreq, ev.list[current][9]);
~tunnelSynth.set(clip2Amp, ev.list[current][10]);
~tunnelSynth.set(verbLfoSpeed, ev.list[current][11]);
~tunnelSynth.set(verbLfoDepth, ev.list[current][12]);
~tunnelSynth.set(verbRoom, ev.list[current][13]);
~tunnelSynth.set(verbDamp, ev.list[current][14]);
};
//----------Tunnel GUI----------
~tunnelWindow = Window( "The Tunnel", Rect( 128, 230, 110, 140));
~tunnelWindow.view.decorator = FlowLayout( ~tunnelWindow.view.bounds );
~tunnelPreset.list.do({|each, count| (Button(~tunnelWindow, 30@30).states = [[count]]).action = {(~tunnelPreset.current = count).load;};});
~tunnelWindow.front;
~tunnelWindow.onClose = {~tunnelSynth.free;};
//Kill the gui if the user kills the sound
CmdPeriod.doOnce({
~tunnelWindow.close;
});
)
(//---------Perform Song----------
~tunnelTask = Task({
~tunnelSynth.free;
s.recChannels = 2;
s.recHeaderFormat = "AIFF";
s.recSampleFormat = "int24";
s.prepareForRecord("C:\Users\Jennifer\Jon\Code\thetunnel.aiff");
s.record;
~tunnelSynth = Synth(TheTunnel, [amp, 0]); 1.wait;
~tunnelSynth.set(amp, 1); 128.wait;
~tunnelSynth.set(amp, 0.7);
~tunnelSynth.set(clip1Amp, 100);
~tunnelSynth.set(clip2Amp, 100); 30.wait;
(~tunnelPreset.current = 2).load; 15.wait;
(~tunnelPreset.current = 6).load; 30.wait;
~tunnelSynth.set(amp, 0); 35.wait;
~tunnelSynth.free;
s.stopRecording;
});
~tunnelTask.play;
)
(//----------Tunnel SynthDef---------- SynthDef(TheTunnel, { | out = 0, amp = 1, lfo1Speed = 0.1, lfo1Depth = 100, lfo2Speed = 0.25, lfo2Depth = 600, osc1Freq = 7, loSineFreq = 30, loSineAmp = 0.5, clip1Amp = 6, clipModFreq = 500, clip2Amp = 6, verbLfoSpeed = 0.014, verbLfoDepth = 1, verbRoom = 1, verbDamp = 0.5 | var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp); //Osc1 var osc1 = SinOsc.ar(osc1Freq); //Osc2 var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only var osc2 = SinOsc.ar(lfo1 * lfo1Depth); //Osc3 var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only var osc3 = SinOsc.ar(lfo2 * lfo2Depth); //Sum and Clip var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq); //Output var output = (clip1 * clip2Amp).distort * 0.5 + loSine; var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth; var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp); Out.ar(out, verb1!2 * 0.5); }, [0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]).add; ) ( //----Start Synth---- ~tunnelSynth = Synth(TheTunnel); //----Preset---- ~tunnelPreset = (); ~tunnelPreset.current = 0; ~tunnelPreset.list = [ // amp, lfo1Speed, lfo1Depth, lfo2Speed, lfo2Depth, osc1Freq, loSineFreq, loSineAmp, clip1Amp, clipModFreq, clip2Amp, verbLfoSpeed, verbLfoDepth, verbRoom, verbDamp /*00*/ [ 1, 0.1, 100, 0.25, 600, 7, 30, 0.5, 6, 500, 6, 0.014, 1, 1, 0.5 ], /*01*/ [ 1, 30.756, 628.79, 0.25, 600, 35.412, 11.8, 0.5, 6, 500, 6, 0.151, 0.204, 1, 1 ], /*02*/ [ 1, 48.345, 446.41, 45.021, 694.56, 14.97, 42.53, 0.14, 1.833, 168.49, 1, 0.014, 0.314, 1, 0 ], /*03*/ [ 1.163, 0.507, 1000, 6.285, 317.08, 34.579, 31.77, 0.5, 3.672, 44.59, 3.492, 0.316, 0.49, 0.461, 1 ], /*04*/ [ 1.392, 0.507, 288.03, 0.67, 317.08, 10.449, 88.06, 0.37, 2.557, 44.59, 3.492, 0.155, 1, 1, 1 ], /*05*/ [ 0.575, 100, 1000, 96.903, 1000, 50, 88.06, 1.22, 6, 127.37, 6, 0.167, 0.493, 1, 1 ], /*06*/ [ 3.2, 1, 101.3, 1.5, 74.79, 11.691, 5.2, 0, 3.225, 49.8, 2.754, 0.51, 0.494, 0.784, 0.497 ], /*07*/ [ 2.505, 0.001, 80.79, 100, 306.59, 11.691, 5.2, 0, 3.225, 49.8, 3.734, 0.273, 0.656, 0.784, 0.889 ], /*08*/ [ 0.9, 71.939, 631.92, 72.476, 427.99, 17.475, 96.68, 0.56, 4.298, 496.15, 5.649, 0.804, 0.694, 0.303, 0.461 ], /*09*/ [ 0.6, 34.043, 650.05, 29.176, 480.98, 30.836, 66.66, 1.13, 2.401, 205.91, 2.664, 0.173, 0.778, 0.517, 0.88 ], /*10*/ [ 0.54, 22.558, 217.5, 91.033, 520.13, 3.484, 84.09, 1.59, 2.731, 259.07, 5.919, 0.571, 0.988, 0.133, 0.0 ] ]; ~tunnelPreset.load = { |ev| var current = ev.current; ~tunnelSynth.set(amp, ev.list[current][0]); ~tunnelSynth.set(lfo1Speed, ev.list[current][1]); ~tunnelSynth.set(lfo1Depth, ev.list[current][2]); ~tunnelSynth.set(lfo2Speed, ev.list[current][3]); ~tunnelSynth.set(lfo2Depth, ev.list[current][4]); ~tunnelSynth.set(osc1Freq, ev.list[current][5]); ~tunnelSynth.set(loSineFreq, ev.list[current][6]); ~tunnelSynth.set(loSineAmp, ev.list[current][7]); ~tunnelSynth.set(clip1Amp, ev.list[current][8]); ~tunnelSynth.set(clipModFreq, ev.list[current][9]); ~tunnelSynth.set(clip2Amp, ev.list[current][10]); ~tunnelSynth.set(verbLfoSpeed, ev.list[current][11]); ~tunnelSynth.set(verbLfoDepth, ev.list[current][12]); ~tunnelSynth.set(verbRoom, ev.list[current][13]); ~tunnelSynth.set(verbDamp, ev.list[current][14]); }; //----------Tunnel GUI---------- ~tunnelWindow = Window( "The Tunnel", Rect( 128, 230, 110, 140)); ~tunnelWindow.view.decorator = FlowLayout( ~tunnelWindow.view.bounds ); ~tunnelPreset.list.do({|each, count| (Button(~tunnelWindow, 30@30).states = [[count]]).action = {(~tunnelPreset.current = count).load;};}); ~tunnelWindow.front; ~tunnelWindow.onClose = {~tunnelSynth.free;}; //Kill the gui if the user kills the sound CmdPeriod.doOnce({ ~tunnelWindow.close; }); ) (//---------Perform Song---------- ~tunnelTask = Task({ ~tunnelSynth.free; s.recChannels = 2; s.recHeaderFormat = "AIFF"; s.recSampleFormat = "int24"; s.prepareForRecord("C:\Users\Jennifer\Jon\Code\thetunnel.aiff"); s.record; ~tunnelSynth = Synth(TheTunnel, [amp, 0]); 1.wait; ~tunnelSynth.set(amp, 1); 128.wait; ~tunnelSynth.set(amp, 0.7); ~tunnelSynth.set(clip1Amp, 100); ~tunnelSynth.set(clip2Amp, 100); 30.wait; (~tunnelPreset.current = 2).load; 15.wait; (~tunnelPreset.current = 6).load; 30.wait; ~tunnelSynth.set(amp, 0); 35.wait; ~tunnelSynth.free; s.stopRecording; }); ~tunnelTask.play; )
(//----------Tunnel SynthDef----------
	SynthDef(TheTunnel, {
		|
			out = 0,					amp = 1,					lfo1Speed = 0.1,				lfo1Depth = 100,			lfo2Speed = 0.25,		
			lfo2Depth = 600,			osc1Freq = 7,				loSineFreq = 30,				loSineAmp = 0.5,			clip1Amp = 6,		
			clipModFreq = 500,		clip2Amp = 6,				verbLfoSpeed = 0.014, 		verbLfoDepth = 1, 		verbRoom = 1, 
			verbDamp = 0.5
		|
		var loSine = SinOsc.ar(loSineFreq, 0, loSineAmp);
		//Osc1
		var osc1 = SinOsc.ar(osc1Freq);
		//Osc2
		var lfo1 = LFSaw.ar(lfo1Speed, 0, 0.5, 0.5); //Make positve only
		var osc2 = SinOsc.ar(lfo1 * lfo1Depth);
		//Osc3
		var lfo2 = LFSaw.ar(lfo2Speed, 0, 0.5, 0.5); //Make positve only
		var osc3 = SinOsc.ar(lfo2 * lfo2Depth);
		//Sum and Clip
		var clip1 = ((osc1 * osc2 * osc3) * clip1Amp).distort * SinOsc.ar(clipModFreq);
		//Output
		var output = (clip1 * clip2Amp).distort * 0.5 + loSine;
		var verbLfo = (SinOsc.ar(verbLfoSpeed) * 0.5 + 0.5) * verbLfoDepth;
		var verb1 = FreeVerb.ar(output, verbLfo, verbRoom, verbDamp, amp);
		Out.ar(out, verb1!2 * 0.5);
	}, [0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]).add; 
)

(
	//----Start Synth----
	~tunnelSynth = Synth(TheTunnel);
	
	//----Preset----
	~tunnelPreset = ();
	~tunnelPreset.current = 0;
	~tunnelPreset.list = [
		//			amp,	lfo1Speed,	lfo1Depth,	lfo2Speed,	lfo2Depth,	osc1Freq,	loSineFreq,	loSineAmp,	clip1Amp,	clipModFreq,	clip2Amp,	verbLfoSpeed,	verbLfoDepth,	verbRoom,	verbDamp
		/*00*/	[	1, 		0.1,		100, 		0.25, 		600, 		7, 			30, 			0.5,		6, 			500, 			6, 			0.014,			1, 				1, 			0.5			],
		/*01*/	[	1, 		30.756,	628.79, 	0.25, 		600, 		35.412, 	11.8, 			0.5,		6, 			500, 			6, 			0.151, 		0.204, 		1, 			1			],
		/*02*/	[	1,		48.345,	446.41, 	45.021,	694.56, 	14.97, 	42.53, 		0.14,		1.833, 	168.49,		1, 			0.014, 		0.314, 		1, 			0			],
		/*03*/	[	1.163,	0.507, 	1000, 		6.285, 	317.08, 	34.579, 	31.77, 		0.5, 		3.672, 	44.59, 		3.492, 	0.316, 		0.49, 			0.461, 	1			],
		/*04*/	[	1.392,	0.507, 	288.03,	0.67, 		317.08, 	10.449, 	88.06, 		0.37, 		2.557, 	44.59, 		3.492, 	0.155, 		1, 				1, 			1			],
		/*05*/	[	0.575,	100, 		1000, 		96.903, 	1000, 		50, 		88.06, 		1.22, 		6, 			127.37, 		6, 			0.167, 		0.493, 		1, 			1			],
		/*06*/	[	3.2, 	1, 			101.3, 	1.5, 		74.79, 	11.691, 	5.2, 			0, 			3.225, 	49.8, 			2.754, 	0.51, 			0.494, 		0.784, 	0.497		],
		/*07*/	[	2.505,	0.001, 	80.79, 	100, 		306.59, 	11.691, 	5.2, 			0, 			3.225, 	49.8, 			3.734, 	0.273, 		0.656, 		0.784, 	0.889		],
		/*08*/	[	0.9,	71.939, 	631.92, 	72.476,	427.99, 	17.475, 	96.68, 		0.56, 		4.298, 	496.15, 		5.649, 	0.804, 		0.694, 		0.303, 	0.461		],
		/*09*/	[	0.6,	34.043, 	650.05, 	29.176,	480.98, 	30.836, 	66.66, 		1.13, 		2.401, 	205.91, 		2.664, 	0.173, 		0.778, 		0.517, 	0.88		],
		/*10*/	[	0.54,	22.558, 	217.5,		91.033,	520.13,	3.484,		84.09,			1.59, 		2.731,		259.07, 		5.919,		0.571, 		0.988, 		0.133, 	0.0			]
	];
	~tunnelPreset.load = { |ev| 
		var current = ev.current;
		~tunnelSynth.set(amp, ev.list[current][0]);
		~tunnelSynth.set(lfo1Speed, ev.list[current][1]);
		~tunnelSynth.set(lfo1Depth, ev.list[current][2]);
		~tunnelSynth.set(lfo2Speed, ev.list[current][3]);
		~tunnelSynth.set(lfo2Depth, ev.list[current][4]);
		~tunnelSynth.set(osc1Freq, ev.list[current][5]);
		~tunnelSynth.set(loSineFreq, ev.list[current][6]);
		~tunnelSynth.set(loSineAmp, ev.list[current][7]);
		~tunnelSynth.set(clip1Amp, ev.list[current][8]);
		~tunnelSynth.set(clipModFreq, ev.list[current][9]);
		~tunnelSynth.set(clip2Amp, ev.list[current][10]);
		~tunnelSynth.set(verbLfoSpeed, ev.list[current][11]);
		~tunnelSynth.set(verbLfoDepth, ev.list[current][12]);
		~tunnelSynth.set(verbRoom, ev.list[current][13]);
		~tunnelSynth.set(verbDamp, ev.list[current][14]);
	};

	//----------Tunnel GUI----------
	~tunnelWindow = Window( "The Tunnel", Rect( 128, 230, 110, 140)); 
	~tunnelWindow.view.decorator = FlowLayout( ~tunnelWindow.view.bounds );
	~tunnelPreset.list.do({|each, count| (Button(~tunnelWindow, 30@30).states = [[count]]).action = {(~tunnelPreset.current = count).load;};});
	~tunnelWindow.front;
	~tunnelWindow.onClose = {~tunnelSynth.free;};

	//Kill the gui if the user kills the sound
	CmdPeriod.doOnce({
		~tunnelWindow.close;
	});
)

(//---------Perform Song----------
	~tunnelTask = Task({
		~tunnelSynth.free;
		s.recChannels = 2;
		s.recHeaderFormat = "AIFF";
		s.recSampleFormat = "int24";
		s.prepareForRecord("C:\Users\Jennifer\Jon\Code\thetunnel.aiff");
		s.record;
		~tunnelSynth = Synth(TheTunnel, [amp, 0]); 	1.wait;
		~tunnelSynth.set(amp, 1);						128.wait;
		~tunnelSynth.set(amp, 0.7);
		~tunnelSynth.set(clip1Amp, 100); 
		~tunnelSynth.set(clip2Amp, 100);				30.wait;
		(~tunnelPreset.current = 2).load;				15.wait;
		(~tunnelPreset.current = 6).load;				30.wait;
		~tunnelSynth.set(amp, 0);						35.wait;
		~tunnelSynth.free;
		s.stopRecording;
	});
	~tunnelTask.play;
)