/*Thank you for finding my code for 'doubleshot'. Please note: the following code is unedited and published purely as I left it when I decided the piece was finished. This was my first attempt at coding for performance, so please excuse its clutter and disorganization.
-BT Feb. 6, 2019
*/
/*
//////Thank you to Eli Fieldsteel and his tireless work to educate artists and creators on the power of Super Collider.////
//////See his pieces and instruction at http://www.elifieldsteel.com/////////
*/
//Composition 1 ORGANIZED
//NOTES: Events that need to be made:
//---Event 1:looping of cafe atmosphere////////
//---Event 1.5: individual random talking points and shouts////////
//---Event 2: individual tapping of espresso cup/////
//---Event 3: rhythmic low beat -randomness////
//---Event 4: rhythmic perc with espresso cup-looping. Choosing random taps and kicks.////
//---Event 5: Bass comes in on tempo with perc, pbind of two note progressions
//---EVENT 5.5: Create a common tempo clock
//////TO DO: fix mid beat so that both dur and amp are in sync
//////TO DO: Allow cafe ambi buffer to be faded out upon STOP.*****08/4/2018 DONE!!! Used adsr envelope and gate to activate release in synth//////
//---Event 6: swirl hit in tempo and pitch with bass; random swirly twinkles
//////TO DO: ---need to be tweaked and made more efficient. right now use WAY too much cpu. USE ITERATION TO GENERATE RANDOM SECTIONS OF IT TO SHIMMER --DONE(08/23/2018). Made more efficient by using EFs technique to readbuf according to a noise envelope for it's frequency, thereby giving some randomness. I also created mono version and used randomized panning to lessen cpu load.
//---Event 7: Bass third pbind that can be transitioned to on command and loop as many times as I'd like.
//---Event 8: Crust getting pulled away, fade out cafe atmosphere over 8 seconds time. drums stop.
//---Event 9 and event 10: twinkle and swirls complimenting each other in harmony. wide stereo. twinkle sent to delay and reverb bus. scale progression iterative. individual talking points heavily reverbed and delayed to be hit on command
//---Bass and beat left with descending scale of twinkle and bpf on swirl.
//---fades out and ends
//0. organize synth folder
//In Composition1 folder, include code for synthdefs, pbinds, code to allocate audio bus for reverb, code to read multiple sound files into dictionary buffers
//11-10-18; second reverb bus (long tail) not being able to be sent to. figure this out to be controlled when events are called. Works if I replace \reverb with \reverb2 in the reverb bus, but I cannot use it as a second reverb. Figure this out
s.quit;
s.plotTree;
s.meter;
(
//1. config the server
s = Server.local;
ServerOptions.devices;
s.options.outDevice_(
"Built-in Output"
//"Soundflower (2ch)"
//"Zen Studio"
);
//give local host server numb of channels my output device has and that I will be using
s.options.numOutputBusChannels_(2);
//for mic or instrument in, want to use:
s.options.inDevice_(
//"Zen Studio"
"Built-in Microph"
);
//s.options.numInputBusChannels_(12);
s.options.sampleRate_(44100);
//set higher memsize before booting (2^20)
s.options.memSize_(2.pow(20));
s.newBusAllocators;
ServerBoot.removeAll;
ServerTree.removeAll;
ServerQuit.removeAll;
//2. initialize global variables
//like default min output bus, for instance if new pc sends hardware outputs to NOT output zero, which would suck and I would have to go through and change all synthdef output refs. Meanwhile, setting a global output bus index variable helps with this.
~out = 0;
//3. define piece-specific functions
~makeBuffers = {
(
b = Dictionary.new;
PathName("/Users/shorthouse/Documents/SuperCollider 2018/Pieces/1/buffers/voices/").entries.do{
arg subfolder;
b.add(subfolder.folderName.asSymbol ->
Array.fill(
subfolder.entries.size,
{
arg i;
Buffer.read(s, subfolder.entries[i].fullPath);
}
)
)
};
)};
~makeBusses = {
~bus = Dictionary.new;
~bus.add(\reverb2 -> Bus.audio(s,2));
~bus.add(\reverb -> Bus.audio(s,2));
~bus.add(\delay -> Bus.audio(s,2));
};
~cleanup = {
s.newBusAllocators;
ServerBoot.removeAll;
ServerTree.removeAll;
ServerQuit.removeAll;
};
~makeNodes = {
s.bind({
~mainGrp = Group.new;
~delayGrp = Group.after(~mainGrp);
~delaySynth = Synth.new(
\delaystereo,
[
\amp, 1,
\in, ~bus[\delay],
\out, ~out,
],
~delayGrp
);
~reverbGrp = Group.after(~delayGrp);
~reverbSynth = Synth.new(
\reverb,
[
\in, ~bus[\reverb],
\out, ~out,
],
~reverbGrp
);
~reverbSynth = Synth.new(
\reverb2,
[
\in, ~bus[\reverb2],
\out, ~out,
],
~reverbGrp
);
});
};
~makeEvents = {
//MIDIIn.connectAll;
//Events need to be in order of occurance of gradualness from cafe into the space of ones mind with repeated iterations and melodies
e = Dictionary.new;
///08/4/2018: NEED TO FIGURE OUT HOW TO BE ABLE TO FADE THIS BUFFER OUT ON COMMAND. SET IT AS A SYNTH AND THEN BE ABLE TO TRIGGER A FADE OUT. Changing the 'rel' midplay does not help because the synth has already been instantiated. The updated rel would only take effect if synth is re-ran. I want to be able to trigger a fade out as it's playing at any point in time.
e.add(\eventcafeatmos -> {
~cafeatmos =
Synth(\cafeatmos)
});
e.add(\twinkle1 -> {
~twinkle1 =
rrand(4,7).do{
Pbind(
\instrument, \twinklemel2,
\buf, b[\hits][19],
\dur, Pseq([1], 1),
\amp, 50,
\atk, Prand([0.3,0.7,1.2,2],1),
\rel, Prand([3,4,5],1),
\bpfmix, 0,
\rq, Prand([0.01, 0.08, 0.1, 0.2, 0.4],1),
\rate, Prand([1,0.8,0.6,0.4],1),
\pan, Prand([-1,-0.7,-0.3, 0.3, 0.7, 1],1),
\group, ~mainGrp,
\out, ~bus[\reverb],
).play;
}
});
e.add(\randomshouts -> {
(
Synth(\randshout,
[
\buf, b[\ct][rrand(0,4)],
\rstart, rrand(0.8,1.3),
\rend, rrand(0.6,1.1),
\rdur, rrand(0.7,2),
\amp, 0.5,
\pan, rrand(-0.3,0.3),
\out, ~out,
]
);
)
});
e.add(\randomshouts2 -> {
(
Synth(\randshout2,
[
\buf, b[\ct][rrand(0,4)],
\rstart, rrand(0.8,1.3),
\rend, rrand(0.6,1.1),
\rdur, rrand(0.7,2),
\amp, 1,
\pan, rrand(-1,1),
\out, ~bus[\reverb2],
\out, ~bus[\delay],
]
);
)
});
e.add(\randomshouts3 -> {
(
Synth(\randshout,
[
\buf, b[\ct][rrand(0,4)],
\rstart, rrand(0.8,1.3),
\rend, rrand(0.6,1.1),
\rdur, rrand(0.7,2),
\amp, 0.8,
\pan, rrand(-1,1),
\out, ~out,
\out, ~bus[\delay],
]
);
)
});
//NEED TO MAKE THIS BASS LOOP TO A RHYTHM. HOW DO I DO THIS?
e.add(\basstap -> {
var db, task;
db = -30;
task = Task({
1.wait;
70.do({
db = db + 0.5;
0.25.wait;
});
});
~basstap2.stop;
~basstap = Pbind(
\instrument, \simpbass,
\rel, 0.3,
\dur, Pseq([0.4,0.4,0.4,0.4],inf),
//Pseq([0.5,0.5,0.5,0.5,0.8], inf),
\note, Pseq([40, 40, 40, 40, 40, 40],inf),
//\amp, Pseq([0.8, 0.65, 0.65], inf),
\db, Pfunc({
if(db < -5) {db} {-5};
}),
\out, ~out,
).play;
task.play;
});
e.add(\basstap2 -> {
~basstap.stop;
~basstap2 =
Pbind(
\instrument, \simpbass,
\dur, Pseq([0.25, 0.25, 0.25], inf),
\note, Pseq([40, 40, 40], inf),
\amp, Pseq([0.9, 0.7, 0.7], inf),
\out, ~out,
).play;
});
e.add(\basstap3 -> {
~basstap3 =
Pbind(
\instrument, \simpbass,
\dur, Pseq([1], inf),
\note, Pseq([60], inf),
\amp, 0.8,
\out, ~out,
).play;
});
e.add(\bpfswirls -> {
~bpfswirls =
Pbind(
\instrument, \bpfswirl,
\dur, Prand([1, 1.5, 2, 2.5],inf),
\cf, Pseq([500,1000,2000,3000,5000],inf),
\start, 0,
\end, b[\hits][16].numFrames-1,
\freq, 0.4,
\amp, 8,
\pan, Prand([-1,-0.8,-0.5, 0.5, 0.8, 1], inf),
\rq, Pseq([0.9,0.8,0.7,0.55,0.3],inf),
\group, ~mainGrp,
\out, ~bus[\reverb2],
).play;
});
e.add(\lowbeat -> {
~lowbeat =
Pbind(
\instrument, \espkik,
\amp, Pseq([3, 2, 2, 2],inf),
\dur,Pseq([(1/4),(1/4),(1/4),(1/4)],inf),
//Prand([(1/8), (1/4), (1/2)], inf),
\rate, Prand([1, 0.8, 0.6, 1.2, 1.3],inf),
\cfmin, Prand([90,95,100,110,120],inf),
\cfmax, Prand([180, 190, 200, 210, 220],inf),
\group, ~reverbGrp,
).play;
~cafeatmos.set(\gate,0);
});
e.add(\midbeat -> {
var amp1, task1;
amp1 = 0.1;
task1 = Task({
1.wait;
30.do({
amp1 = amp1 + 0.02;
0.2.wait;
});
});
~midbeat =
Pbind(
\instrument, \espmidhit,
\dur, Pseq([(1/8),(1/16),(1/8),(1/8),(1/8),(1/8),(1/8),(1/8),(1/8)], inf),
\buf, Prand(b[\taps], inf),
\rate, 1,
\amp, Pfunc({
if(amp1 < 0.5) {amp1} {rrand(0.40,0.75)};
}),
//Prand([1, 0.8, 0.6, 0.45, 0.4, 0.3], inf),
).play;
task1.play;
});
/*MIDIdef.noteOn(\controller, {
arg val, num;
[val, num].postln;
});*/
/*MIDIdef.cc(\controller, {
arg val, num;
[val, num].postln;
});*/
};
//4. register functions with serverboot/quit/tree
ServerBoot.add(~makeBuffers);
ServerBoot.add(~makeBusses);
ServerQuit.add(~cleanup);
//5. boot server
s.waitForBoot({
s.sync; //says to server hey whatever you're doing finish it up and let me know when you're done
SynthDef(\cafeatmos,
{
arg amp=0.6, out=0, gate=1;
var sig, env, gen;
env = Env.adsr(15,1,1,15,peakLevel: 0.5, curve:1);
gen = EnvGen.kr(env, gate, doneAction:2);
sig = PlayBuf.ar(2, b[\hits][6]);
sig = LPF.ar(sig, 4000);
sig = sig*amp*gen;
Out.ar(out, sig);
}).add;
SynthDef(\randshout,
{
arg amp=0.7, out=0, buf=b[\ct][0], rstart=1, rend=1, rdur=1, pan=0;
var sig, env;
env = EnvGen.kr(Env([0,1,0],[0.2,3]),doneAction:2);
sig = PlayBuf.ar(2, buf);
sig = LPF.ar(sig, 4000);
sig = Balance2.ar(sig[0],sig[1], pan, amp);
sig = sig*env*amp;
Out.ar(out, sig);
}).add;
SynthDef(\randshout2,
{
arg amp=1, out=0, buf=b[\ct][0], rstart=1, rend=1, rdur=1, pan=0;
var sig, env;
env = EnvGen.kr(Env([0,1,0],[0.4,2]),doneAction:2);
sig = PlayBuf.ar(2, buf, XLine.kr(rstart, rend, rdur));
sig = LPF.ar(sig, 4000);
sig = DelayN.ar(sig, 0.6, rrand(0.1,0.6),0.6, sig);
sig = DelayC.ar(sig, 1.0, rrand(0.8,1.0), 0.4, sig);
sig = Balance2.ar(sig[0],sig[1], pan, amp);
sig = sig*env*amp;
Out.ar(out, sig);
}).add;
SynthDef(\espkik,
{
arg out=0, amp=1, atk=0.02, rel=0.8, buf=0,cfmin = 90, cfmax = 150, rqmin=0.5, rqmax=0.85;
var sig, env;
env = EnvGen.kr(Env([0,1,0],[atk,rel]), doneAction:2);
sig = {PlayBuf.ar(1, b[\hits][14], 0.08, startPos:504000)}!2;
sig = BPF.ar(sig,
{LFNoise1.kr(0.1).exprange(cfmin, cfmax)}!2,
{LFNoise1.kr(0.1).exprange(rqmin, rqmax)}!2);
sig = Balance2.ar(sig[0],sig[1],0);
sig = sig*env*amp;
Out.ar(out, sig);
}).add;
//SYNTHDEF FOR 'HATS'
SynthDef(\esphat,
{
arg pan=0,out=0, amp=20, atk = 0.1, buf=0, sus=0,rel=0.5, cfmin=5000, cfmax = 10000, rqmin = 0.6, rqmax = 1;
var sig, env;
env = EnvGen.kr(Env([0,5,5,0], [atk, sus, rel]), doneAction:2);
sig = {PlayBuf.ar(2, b[\hits][0], 1, startPos:768000)}!2;
sig = BPF.ar(sig,
{LFNoise1.kr(0.5).exprange(cfmin, cfmax)}!2,
{LFNoise1.kr(0.2).exprange(rqmin, rqmax)}!2);
sig = Balance2.ar(sig[0], sig[1], pan);
sig = sig*env*amp;
sig = Pan2.ar(sig, pan);
Out.ar(out, sig);
}).add;
//SYNTHDEF FOR MIDDY HITS
SynthDef(\espmidhit,
{
arg pan=0, out=0, amp=3, atk=0.02, buf=0, rel=0.5, cfmin = 100, cfmax = 250, rqmin=0.7, rqmax=0.9;
var sig, env;
env = EnvGen.kr(Env([0,4,0],[atk,rel]), doneAction:2);
sig = PlayBuf.ar(2,buf,0.4, doneAction:2);
sig = BPF.ar(sig,
{LFNoise1.kr(0.1).exprange(cfmin, cfmax)}!2,
{LFNoise1.kr(0.1).exprange(rqmin, rqmax)}!2);
sig = sig*env*amp;
Out.ar(out, sig);
}).add;
SynthDef(\simpbass,
{
arg out = 0, cutoff = 250, note = 35, atk = 0, rel = 0.6, c1 = 1, c2 = -1, amp = 0.7, cf = 120, rq = 1.0;
//HEY PS! the c1 and c2 refer to "curvature values" of the amplitude envelope. Still need to look up what positive and negative values mean here, as well as the shape of curvature when these values are close to +_1.
var sig, env;
env = EnvGen.kr(Env(
[0,1,0], [atk, rel], [c1, 0, c2]), doneAction:2);
sig = RLPF.ar(SinOsc.ar(note.midicps,0, amp),cutoff);
sig = BPF.ar(sig, cf, rq);
sig = Pan2.ar(sig, 0);
sig = sig*amp*env;
Out.ar(out, sig);
}).store;
SynthDef(\bpfbuf, {
arg atk=0, sus=0, rel=3, c1=1, c2=(-1), buf=0, rate=1, spos=0, freq=440, rq=1, bpfmix=0, pan=0, amp=1, out=0;
var sig, env;
env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1, 0 ,c2]), doneAction:2); //doenaction 2 ends file trigger when envelope is done playing
sig = PlayBuf.ar(2, buf, rate*BufRateScale.ir(buf), startPos:spos); //playbuf = 2 bc my signals are stereo
sig = XFade2.ar(sig, BPF.ar(sig, freq, rq, 1/rq.sqrt), bpfmix*2-1);
sig = sig * env;
sig = Balance2.ar(sig[0],sig[1],pan);
Out.ar(out, sig);
}).add;
SynthDef(\bpfswirl, {
arg atk=0.5, sus=0, rel=1, c1=1, c2=(-1), start, end, rate=0.8, spos=0, freq=1, cf=3000, rq=0.7, bpfmix=0.7, pan=0, amp=6, out=0;
var sig, env, ptr;
ptr = LFDNoise1.ar(freq).range(start,end);
sig = BufRd.ar(1, b[\hits][18], ptr);
env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1, 0 ,c2]), doneAction:2); //doenaction 2 ends file trigger when envelope is done playing
//sig = PlayBuf.ar(2, b[\hits][16], rate, startPos:spos); //playbuf = 2 bc my signals are stereo
sig = BPF.ar(sig, cf, rq, 1/rq.sqrt);
sig = sig*env;
//sig = Balance2.ar(sig[0],sig[1],pan,amp);
sig = Pan2.ar(sig, pan, amp);
sig = sig * amp;
Out.ar(out, sig);
}).add;
SynthDef(\sawcrust,
{
arg out=0, atk=1, sus=1, rel=1, c1=1, c2=(-1), pan=0, amp=1, cfmin=800, cfmax=1000, rqmin=0.5, rqmax=0.9, sfreq=10, lindur=2, linend=40, cffmin=9000, cffmax=11000, rqqmin=0.2, rqqmax=0.5;
var sig, env;
env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1, 0, c2]),doneAction:2);
sig = {Saw.ar(XLine.kr(sfreq,linend,lindur))*env}!2;
sig = {BPF.ar(sig, exprand(cfmin, cfmax), rrand(rqmin,rqmax), amp)}!2;
sig = Pan2.ar(sig, pan, amp);
Out.ar(out, sig);
}).add;
SynthDef(\sawcrust2,
{
arg out=0, atk=1, sus=1, rel=1, c1=1, c2=(-1), pan=0, amp=1, cfmin=800, cfmax=1000, rqmin=0.5, rqmax=0.9, sfreq=10, lindur=2, linend=40, cffmin=9000, cffmax=11000, rqqmin=0.2, rqqmax=0.5;
var sig, env;
env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1, 0, c2]),doneAction:2);
sig = {Saw.ar(XLine.kr(sfreq,linend,lindur))*env}!2;
sig = {BPF.ar(sig, exprand(cfmin, cfmax), rrand(rqmin,rqmax), amp)}!2;
sig = {BPF.ar(sig, rrand(cffmin,cffmax), rrand(rqqmin, rqqmax))}!2;
sig = Pan2.ar(sig, pan, amp);
Out.ar(out, sig);
}).add;
SynthDef(\twinklemel2, {
arg atk=0, sus=2, rel=3, c1=1, c2=(-1), buf=0, rate=1, spos=0, freq=840, rq=1, bpfmix=0, pan=0, amp=1, out=0;
var sig, env;
env = EnvGen.kr(Env([0,1,1,0], [atk, sus, rel], [c1, 0 ,c2]), doneAction:2); //doenaction 2 ends file trigger when envelope is done playing
sig = PlayBuf.ar(2, buf, rate*BufRateScale.ir(buf), startPos:spos, doneAction:2);
sig = BLowPass.ar(sig, 2500);//playbuf = 2 bc my signals are stereo
sig = XFade2.ar(sig, BPF.ar(sig, freq, rq, 1/rq.sqrt), bpfmix*2-1);
sig = sig * env;
sig = Balance2.ar(sig[0],sig[1],pan,amp);
Out.ar(out, sig);
}).add;
SynthDef(\reverb, {
arg in, predelay=0.1, revtime=1.8, lpf=4500, mix=0.15, amp=1, out=0;
var dry, wet, temp, sig;
dry = In.ar(in, 2);
temp = In.ar(in, 2);
wet = 0;
temp = DelayN.ar(temp, 0,2, predelay);
16.do{
temp = AllpassN.ar(temp, 0.05, {Rand(0.001, 0.05)}!2, revtime);
temp = LPF.ar(temp, lpf);
wet = wet + temp;
};
sig = XFade2.ar(dry, wet, mix*2-1, amp);
Out.ar(out, sig);
}).add;
SynthDef(\reverb2, {
arg in, out=0, pan=0.5;
var input, rev, sig;
input = In.ar(in, 2);
rev = JPverb.ar(input,
\t60.kr(1, 0.05),
\damp.kr(0, 0.05),
\size.kr(1, 0.05),
\earlyDiff.kr(0.707, 0.05),
\modDepth.kr(5, 0.05),
\modFreq.kr(2, 0.05),
\low.kr(1, 0.05),
\mid.kr(1, 0.05),
\high.kr(1, 0.05),
\lowcut.kr(200, 0.05),
\highcut.kr(2000, 0.05)
);
sig = Mix([input, rev]) *0.1;
Out.ar(out, sig);
}).add;
SynthDef(\delaystereo, {
|
in = 0, out = 0, amp = 1, delayTime = 0.5, maxDelayTime = 5, feedback = 0.4,
filterType = 0, cutoff = 20000, rq = 1, mix = 0.7, lagTime = 0.1
|
var input, lowPass, highPass, bandPass, filter, localIn, delay, sig;
input = In.ar(in, 2);
localIn = LocalIn.ar(2);
lowPass = RLPF.ar(localIn, cutoff, rq);
highPass = RHPF.ar(localIn, cutoff, rq);
bandPass = BPF.ar(localIn, cutoff, rq);
filter = Select.ar(filterType, [localIn, lowPass, highPass, bandPass]);
delay = DelayC.ar(input + (filter * feedback), maxDelayTime, delayTime.lag2(lagTime));
LocalOut.ar(delay);
sig = (filter * mix) + (input * (1-mix));
sig = sig * amp;
Out.ar(out, sig);
}).add;
s.sync;
ServerTree.add(~makeNodes);
ServerTree.add(~makeEvents);
s.freeAll;
s.sync;
"donebitch".postln;
});
)
s.quit;
//7/23/2018 - added event for twinkle, fixed timing for the mid hit buffer sampling. Added folder of buffers of random blurts from recordings. Re-mapped synths for kick, mid, and hat to refer to new bufnum of main sample. Made memo to include baby sound into melody. NEED TO: assign events for percussive fade in and out. Event for random shouts and hollers, at varying rates. Event for periodic tapping of espresso cup. Figure out how to loop events. NEED TO LOOP BASS. CREATING A PBIND ALONE DOES NOT DO IT.
//7/24/2018 - Looped bass indefinitely with a pbind. NEED TO: Create another event that stops prior bass loop and induces new bass loop with note sequence change. That way I can switch between one looping sequence and the other at will.
s.meter;
//a test:
e[\eventcafeatmos].play;
e[\randomshouts].play;//centered and clean and low amp
Synth(\twinklemel2, [\buf, 19, \pan, rrand(-0.9,0.9), \out, ~bus[\delay]]);
Synth(\esphat, [\amp, 45, \out,~bus[\reverb2]], ~mainGrp);
e[\bpfswirls].play;
e[\randomshouts3].play; //clean and delayed
e[\twinkle1].play;
e[\twinkle1].play;
~twinkle1.stop; //does not work
e[\randomshouts2].play; //delayed and verbed and warped
Synth(\simpbass, [\amp, 1.5, \note, 34, \out, ~bus[\delay], ~bus[\reverb]], ~mainGrp);
e[\basstap].play;
~basstap.stop;
e[\basstap2].play;
~basstap2.stop;
e[\basstap3].play;
~basstap3.stop;
e[\lowbeat].play;
~lowbeat.stop;
e[\midbeat].play;
~midbeat.stop;
~mainGrp.stop;
(~crust = {
Pbind(
\instrument, \sawcrust2,
\dur, Pseq([1,0.5], 3),
\amp, 1.5,
\group, ~mainGrp,
\out, ~bus[\reverb2],
).play;
};)
~crust.play;
Synth(\espmidhit, [\amp, 2]);
Synth(\espkik, [\amp, 10, \out, ~bus[\reverb2]], ~mainGrp);
s.meter;
s.quit;
b[\hits][19].play;
b[\ct][4].play;
b[\hits][16].play;
b[\hits][18].play;
//6. anything else requiring a booted server activate
//2/6/2019: added Pfunc aspects to bass and midbeat for fading in Pbind upon activating the event.
s.record;
s.record;
Comments