
SIGNALVOID 3: The Piano
SIGNALVOID is a noise compilation. Participants were asked to create up to three tracks, each of exactly one minute in length, with no gaps of silence at the beginning or end. Download the compilation here: http://archive.org/details/SignalvoidMp3
This piece was my third submission for SIGNALVOID. After “Burn It To Disc And Then Burn The Disc” and “The Same Color As Your Skin” I was not sure where to go with my final submission to the compilation. While digging through old code for inspiration I found this piece. I was designing it to be used with a GUI and gave up before it was completed. It was untouched for several months before I decided to revive it for the compilation. I made some minor changes to the code to clean up the sound and remove the GUI and used it pretty much as is. This is the piece that inspired my Subsonic Issues post so you will want to add a high pass filter if you decide to run this code yourself.
(
SynthDef(ThePiano, {
|
sampleHoldFreq = 1, saw0Freq = 0.1, saw0DepthMin = 1, saw0DepthMax = 1000,
saw1FreqLeft = 10, saw1FreqRight = 10.92,
saw2FreqLeft = 9, saw2FreqRight = 11.59,
saw5FreqLeft = 0.1, saw5FreqRight = 0.125, saw5DepthMin = 1, saw5DepthMax = 60
i_comb0MaxDelay = 1, comb0Delay = 0.001, comb0Decay = 0.1,
i_comb1MaxDelay = 1, comb1Delay = 0.0125, comb1Decay = 0.1,
verb0Mix = 1.0, verb0Room = 0.7,
verb1Mix = 1.0, verb1Room = 1.0,
amp = 1
|
//Local Vars
var sampleAndHold;
var saw = Array.new;
var comb = Array.new;
var verb = Array.new;
var comp;
//Saws
/* -----------
Saw Index:
0: Mod for Saw 3 (Sample and Hold mod)
1: Dual Channel Saw
2: Dual Channel Saw
3: Saw with freq modified by a S&H
4: 1 * 2 * 3
5: Mod for saw 6
6: 5 * 4, used for reverb
-------------*/
sampleAndHold = Latch.ar(WhiteNoise.ar, Impulse.ar(sampleHoldFreq));
saw = saw.add(SinOsc.ar(saw0Freq).range(saw0DepthMin, saw0DepthMax));
saw = saw.add(LFSaw.ar([saw1FreqLeft, saw1FreqRight]));
saw = saw.add(LFSaw.ar([saw2FreqLeft, saw2FreqRight]));
saw = saw.add(LFSaw.ar(sampleAndHold * saw[0]));
saw = saw.add(saw[1] * saw[2] * saw[3]);
saw = saw.add(LFSaw.kr([saw5FreqLeft, saw5FreqRight]).range(saw5DepthMin, saw5DepthMax));
saw = saw.add(LFSaw.ar(saw [5] * saw[4]));
//Combs
comb = comb.add(CombC.ar(saw[4], i_comb0MaxDelay, comb0Delay, comb0Decay));
comb = comb.add(CombC.ar(comb[0], i_comb1MaxDelay, comb1Delay, comb1Decay));
//Verbs
verb = verb.add(FreeVerb.ar(comb[1], verb0Mix, verb0Room));
verb = verb.add(FreeVerb.ar(verb[0] * saw[6], verb1Mix, verb1Room));
//Out
Out.ar(0, verb[1] * (amp * 0.2));
}).add;
)
(
x = Synth(ThePiano, [
saw0ModFreq, 0.1, saw0ModDepthMin, 1, saw0ModDepthMax, 1000,
saw1FreqLeft, 10, saw1FreqRight, 10.92,
saw2FreqLeft, 9, saw2FreqRight, 11.59,
saw5FreqLeft, 0.1, saw5FreqRight, 0.125, saw5DepthMin, 1, saw5DepthMax, 60,
i_comb0MaxDelay, 0.001, comb0Delay, 0.001, comb0Decay, 0.1,
i_comb1MaxDelay, 0.0125, comb1Delay, 0.0125, comb1Decay, 0.1,
verb0Mix, 1.0, verb0Room, 0.7,
verb1Mix, 1.0, verb1Room, 1.0,
amp, 1
]);
)
For those curious of how the GUI version worked the code is below. If I remember properly a lot of the knobs are far too subtle to make a difference in the sound.
(
SynthDef(ThePiano, {
|
sampleHoldFreq = 1, saw0Freq = 0.1, saw0DepthMin = 1, saw0DepthMax = 1000,
saw1FreqLeft = 10, saw1FreqRight = 10.92,
saw2FreqLeft = 9, saw2FreqRight = 11.59,
saw5FreqLeft = 0.1, saw5FreqRight = 0.125, saw5DepthMin = 1, saw5DepthMax = 60
i_comb0MaxDelay = 1, comb0Delay = 0.001, comb0Decay = 0.1,
i_comb1MaxDelay = 1, comb1Delay = 0.0125, comb1Decay = 0.1,
verb0Mix = 1.0, verb0Room = 0.7,
verb1Mix = 1.0, verb1Room = 1.0,
amp = 1
|
//Local Vars
var sampleAndHold;
var saw = Array.new;
var comb = Array.new;
var verb = Array.new;
var comp;
//Saws
/* -----------
Saw Index:
0: Mod for Saw 3 (Sample and Hold mod)
1: Dual Channel Saw
2: Dual Channel Saw
3: Saw with freq modified by a S&H
4: 1 * 2 * 3
5: Mod for saw 6
6: 5 * 4, used for reverb
-------------*/
sampleAndHold = Latch.ar(WhiteNoise.ar, Impulse.ar(sampleHoldFreq));
saw = saw.add(SinOsc.ar(saw0Freq).range(saw0DepthMin, saw0DepthMax));
saw = saw.add(LFSaw.ar([saw1FreqLeft, saw1FreqRight]));
saw = saw.add(LFSaw.ar([saw2FreqLeft, saw2FreqRight]));
saw = saw.add(LFSaw.ar(sampleAndHold * saw[0]));
saw = saw.add(saw[1] * saw[2] * saw[3]);
saw = saw.add(LFSaw.kr([saw5FreqLeft, saw5FreqRight]).range(saw5DepthMin, saw5DepthMax));
saw = saw.add(LFSaw.ar(saw [5] * saw[4]));
//Combs
comb = comb.add(CombC.ar(saw[4], i_comb0MaxDelay, comb0Delay, comb0Decay));
comb = comb.add(CombC.ar(comb[0], i_comb1MaxDelay, comb1Delay, comb1Decay));
//Verbs
verb = verb.add(FreeVerb.ar(comb[1], verb0Mix, verb0Room));
verb = verb.add(FreeVerb.ar(verb[0] * saw[6], verb1Mix, verb1Room));
//Out
Out.ar(0, verb[1] * (amp * 0.2));
}).add;
)
/*
(
x = Synth(ThePiano, [
saw0ModFreq, 0.1, saw0ModDepthMin, 1, saw0ModDepthMax, 1000,
saw1FreqLeft, 10, saw1FreqRight, 10.92,
saw2FreqLeft, 9, saw2FreqRight, 11.59,
saw5FreqLeft, 0.1, saw5FreqRight, 0.125, saw5DepthMin, 1, saw5DepthMax, 60,
i_comb0MaxDelay, 0.001, comb0Delay, 0.001, comb0Decay, 0.1,
i_comb1MaxDelay, 0.0125, comb1Delay, 0.0125, comb1Decay, 0.1,
verb0Mix, 1.0, verb0Room, 0.7,
verb1Mix, 1.0, verb1Room, 1.0,
amp, 1
]);
)
*/
(
//----------ThePiano GUI----------
//Global Variables
var layout;
var knobSize = 60@80;
var knobResolution = 0.0001;
var buttonSize = 20@20;
var titleFont = Font( "Times-Bold", 25 );
var titleSize = 120@25;
//Knob Variables
var sampleHoldView, sampleHoldFreqKnob, saw0FreqKnob, saw0DepthMinKnob, saw0DepthMaxKnob;
var saw1View, saw1FreqLKnob, saw1FreqRKnob;
var saw2View, saw2FreqLKnob, saw2FreqRKnob;
var saw5View, saw5FreqLKnob, saw5FreqRKnob, saw5DepthMinKnob, saw5DepthMaxKnob;
var comb0View, comb0DelayKnob, comb0DecayKnob;
var comb1View, comb1DelayKnob, comb1DecayKnob;
var verbView, verbMixKnob, verb0RoomKnob, verb1RoomKnob;
var masterView, ampKnob;
//Start Synth
~thePiano = Synth(ThePiano);
//Window Setup
~thePianoWindow = Window( "The Piano", Rect( 128, 230, 820, 260));
~thePianoWindow.view.decorator = layout = FlowLayout( ~thePianoWindow.view.bounds );
//Sample and Hold Knobs
sampleHoldView = CompositeView(~thePianoWindow, 260@120);
sampleHoldView.decorator = FlowLayout( sampleHoldView.bounds );
StaticText(sampleHoldView, titleSize).string_("Sample and Hold").font = titleFont; sampleHoldView.decorator.nextLine;
sampleHoldFreqKnob = EZKnob(sampleHoldView, knobSize, "ImpulseFreq", ControlSpec(0.01, 1000, lin, knobResolution);,
action: {|inValue| ~thePiano.set(sampleHoldFreq, inValue.value);}, layout:vert2);
saw0FreqKnob = EZKnob(sampleHoldView, knobSize, "LfoFreq", ControlSpec(0.0001, 5000, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw0ModFreq, inValue.value);}, layout:vert2);
saw0DepthMinKnob = EZKnob(sampleHoldView, knobSize, "DepthMin", ControlSpec(1, 5000, lin, knobResolution);,
action: {|inValue|
~thePiano.set(saw0DepthMin, inValue.value);
if((inValue.value > saw0DepthMaxKnob.value), //Make sure min and max are tied together
{saw0DepthMaxKnob.value = inValue.value; saw0DepthMaxKnob.doAction;}
)
}, layout:vert2);
saw0DepthMaxKnob = EZKnob(sampleHoldView, knobSize, "DepthMax", ControlSpec(1, 5000, lin, knobResolution);,
action: {|inValue|
~thePiano.set(saw0DepthMax, inValue.value);
if((inValue.value < saw0DepthMinKnob.value), //Make sure min and max are tied together
{saw0DepthMinKnob.value = inValue.value; saw0DepthMinKnob.doAction;}
)
}, layout:vert2);
//Saw1 Knobs
saw1View = CompositeView(~thePianoWindow, 140@120);
saw1View.decorator = FlowLayout( saw1View.bounds );
StaticText(saw1View, titleSize).string_("Saw 1").font = titleFont; saw1View.decorator.nextLine;
saw1FreqLKnob = EZKnob(saw1View, knobSize, "Freq_L", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw1FreqLeft, inValue.value);}, layout:vert2);
saw1FreqRKnob = EZKnob(saw1View, knobSize, "Freq_R", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw1FreqRight, inValue.value);}, layout:vert2);
//Saw2 Knobs
saw2View = CompositeView(~thePianoWindow, 140@120);
saw2View.decorator = FlowLayout( saw2View.bounds );
StaticText(saw2View, titleSize).string_("Saw 2").font = titleFont; saw2View.decorator.nextLine;
saw2FreqLKnob = EZKnob(saw2View, knobSize, "Freq_L", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw2FreqLeft, inValue.value);}, layout:vert2);
saw2FreqRKnob = EZKnob(saw2View, knobSize, "Freq_R", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw2FreqRight, inValue.value);}, layout:vert2);
//Saw5 Knobs
saw5View = CompositeView(~thePianoWindow, 260@120);
saw5View.decorator = FlowLayout( saw5View.bounds );
StaticText(saw5View, titleSize).string_("Saw 5").font = titleFont; saw5View.decorator.nextLine;
saw5FreqLKnob = EZKnob(saw5View, knobSize, "Freq_L", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw5FreqLeft, inValue.value);}, layout:vert2);
saw5FreqRKnob = EZKnob(saw5View, knobSize, "Freq_R", ControlSpec(0.0001, 100, lin, knobResolution);,
action: {|inValue| ~thePiano.set(saw5FreqRight, inValue.value);}, layout:vert2);
saw5DepthMinKnob = EZKnob(saw5View, knobSize, "DepthMin", ControlSpec(1, 1000, lin, knobResolution);,
action: {|inValue|
~thePiano.set(saw5DepthMin, inValue.value);
if((inValue.value > saw5DepthMaxKnob.value), //Make sure min and max are tied together
{saw5DepthMaxKnob.value = inValue.value; saw5DepthMaxKnob.doAction;}
)
}, layout:vert2);
saw5DepthMaxKnob = EZKnob(saw5View, knobSize, "DepthMax", ControlSpec(1, 1000, lin, knobResolution);,
action: {|inValue|
~thePiano.set(saw5DepthMax, inValue.value);
if((inValue.value < saw5DepthMinKnob.value), //Make sure min and max are tied together
{saw5DepthMinKnob.value = inValue.value; saw5DepthMinKnob.doAction;}
)
}, layout:vert2);
//Comb0 Knobs
comb0View = CompositeView(~thePianoWindow, 140@120);
comb0View.decorator = FlowLayout( comb0View.bounds );
StaticText(comb0View, titleSize).string_("Comb 0").font = titleFont; comb0View.decorator.nextLine;
comb0DelayKnob = EZKnob(comb0View, knobSize, "Delay", ControlSpec(0.0001, 1, lin, knobResolution);,
action: {|inValue| ~thePiano.set(comb0Delay, inValue.value);}, layout:vert2);
comb0DecayKnob = EZKnob(comb0View, knobSize, "Decay", ControlSpec(0.0001, 10, lin, knobResolution);,
action: {|inValue| ~thePiano.set(comb0Decay, inValue.value);}, layout:vert2);
//Comb1 Knobs
comb1View = CompositeView(~thePianoWindow, 140@120);
comb1View.decorator = FlowLayout( comb1View.bounds );
StaticText(comb1View, titleSize).string_("Comb 1").font = titleFont; comb1View.decorator.nextLine;
comb1DelayKnob = EZKnob(comb1View, knobSize, "Delay", ControlSpec(0.0001, 1, lin, knobResolution);,
action: {|inValue| ~thePiano.set(comb1Delay, inValue.value);}, layout:vert2);
comb1DecayKnob = EZKnob(comb1View, knobSize, "Decay", ControlSpec(0.0001, 10, lin, knobResolution);,
action: {|inValue| ~thePiano.set(comb1Decay, inValue.value);}, layout:vert2);
//Verb Knobs
verbView = CompositeView(~thePianoWindow, 200@120);
verbView.decorator = FlowLayout( verbView.bounds );
StaticText(verbView, titleSize).string_("Verb").font = titleFont; verbView.decorator.nextLine;
verbMixKnob = EZKnob(verbView, knobSize, "Mix", ControlSpec(0, 1, lin, knobResolution);,
action: {|inValue|
~thePiano.set(verb0Mix, inValue.value);
~thePiano.set(verb1Mix, inValue.value);
}, layout:vert2);
verb0RoomKnob = EZKnob(verbView, knobSize, "Room 0", ControlSpec(0, 1, lin, knobResolution);,
action: {|inValue| ~thePiano.set(verb0Room, inValue.value);}, layout:vert2);
verb1RoomKnob = EZKnob(verbView, knobSize, "Room 1", ControlSpec(0, 1, lin, knobResolution);,
action: {|inValue| ~thePiano.set(verb1Room, inValue.value);}, layout:vert2);
//Master Knobs
masterView = CompositeView(~thePianoWindow, 140@120);
masterView.decorator = FlowLayout( masterView.bounds );
StaticText(masterView, titleSize).string_("Master").font = titleFont; masterView.decorator.nextLine;
ampKnob = EZKnob(masterView, knobSize, "Amp", ControlSpec(0, 1, lin, knobResolution);,
action: {|inValue| ~thePiano.set(amp, inValue.value);}, layout:vert2);
//Show the window
~thePianoWindow.front;
//Add Functions
~thePianoWindow.onClose = {~thePiano.free;};
//Set all knobs equal to current synth values, defaults sound be set by synthdef, not GUI
~thePiano.get(sampleHoldFreq, {|val| AppClock.sched(0.0, {sampleHoldFreqKnob.value = val.value})});
~thePiano.get(saw0Freq, {|val| AppClock.sched(0.0, {saw0FreqKnob.value = val.value})});
~thePiano.get(saw0DepthMin, {|val| AppClock.sched(0.0, {saw0DepthMinKnob.value = val.value})});
~thePiano.get(saw0DepthMax, {|val| AppClock.sched(0.0, {saw0DepthMaxKnob.value = val.value})});
~thePiano.get(saw1FreqLeft, {|val| AppClock.sched(0.0, {saw1FreqLKnob.value = val.value})});
~thePiano.get(saw1FreqRight, {|val| AppClock.sched(0.0, {saw1FreqRKnob.value = val.value})});
~thePiano.get(saw2FreqLeft, {|val| AppClock.sched(0.0, {saw2FreqLKnob.value = val.value})});
~thePiano.get(saw2FreqRight, {|val| AppClock.sched(0.0, {saw2FreqRKnob.value = val.value})});
~thePiano.get(saw5FreqLeft, {|val| AppClock.sched(0.0, {saw5FreqLKnob.value = val.value})});
~thePiano.get(saw5FreqRight, {|val| AppClock.sched(0.0, {saw5FreqRKnob.value = val.value})});
~thePiano.get(saw5DepthMin, {|val| AppClock.sched(0.0, {saw5DepthMinKnob.value = val.value})});
~thePiano.get(saw5DepthMax, {|val| AppClock.sched(0.0, {saw5DepthMaxKnob.value = val.value})});
~thePiano.get(comb0Delay, {|val| AppClock.sched(0.0, {comb0DelayKnob.value = val.value})});
~thePiano.get(comb0Decay, {|val| AppClock.sched(0.0, {comb0DecayKnob.value = val.value})});
~thePiano.get(comb1Delay, {|val| AppClock.sched(0.0, {comb1DelayKnob.value = val.value})});
~thePiano.get(comb1Decay, {|val| AppClock.sched(0.0, {comb1DecayKnob.value = val.value})});
~thePiano.get(verb0Mix, {|val| AppClock.sched(0.0, {verbMixKnob.value = val.value})});
~thePiano.get(verb0Room, {|val| AppClock.sched(0.0, {verb0RoomKnob.value = val.value})});
~thePiano.get(verb1Room, {|val| AppClock.sched(0.0, {verb1RoomKnob.value = val.value})});
~thePiano.get(amp, {|val| AppClock.sched(0.0, {ampKnob.value = val.value})});
//Kill the gui if someone kills the sound
CmdPeriod.doOnce({
~thePianoWindow.close;
});
)