SuperCollider DrumMachine1
Some experiments in drum machine creation. I noticed I had to do a bit of editing for timing when I recorded these and imported to Logic Pro. Not too bad though....use the jump to onset tool in Logic. Ableton Link for SuperCollider will be the way to go for accurate timing. That will appear in the main SC release soon. There is a 3rd party quark that is useable now.
The drum machine below is cobbled together from various sources. Use it with that in mind. The main framework is taken from a KraftWerk example in the SuperCollider release. That framework has been re-structured a bit to make sense as a drum machine, but is basically the same. Some of the Synth Defs are from forums and gleaned from the web.
First block of code is the Synths....
(
SynthDef(\bd, { | out=0, rt = 0.05 |
var osc, env;
osc = FSinOsc.ar(40);
env = EnvGen.kr(Env.perc(0, rt), doneAction: 2);
Out.ar(out, Pan2.ar(osc, 0, env));
}).add;
SynthDef(\sd, { | out=0 |
var osc1, osc2, env;
osc1 = WhiteNoise.ar;
osc2 = FSinOsc.ar(200);
env = EnvGen.kr(Env.perc(0, 0.05), doneAction: 2);
Out.ar(out, Pan2.ar(LPF.ar(Mix([osc1, osc2]), 12000), 0, env));
}).add;
SynthDef(\hat, { | out=0 |
var osc1, env;
osc1 = WhiteNoise.ar;
env = EnvGen.kr(Env.perc(0, 0.01), doneAction: 2);
Out.ar(out, Pan2.ar(osc1, 0, env));
}).add;
SynthDef(\hat2, { | out=0 |
var osc1, env, osc2;
osc1 = WhiteNoise.ar;
osc1.tanh;
osc2 = Crackle.ar();
env = EnvGen.kr(Env.perc(0, 0.01), doneAction: 2);
Out.ar(out, Pan2.ar(osc1*(osc2*0.5), 0, env));
}).add;
SynthDef(\res, { | out=0 gate=1 freq fltBus |
var aEnv, osc, flt;
aEnv = EnvGen.kr(Env.perc(0, 0.7), gate, doneAction: 2);
osc = Mix([Saw.ar(freq), Pulse.ar(freq / 2, 0.5)]);
flt = RLPF.ar(osc, In.kr(fltBus, 1), 0.1, aEnv);
Out.ar(out, Pan2.ar(flt, 0));
}).add;
SynthDef(\resControl, { | fltBus |
ReplaceOut.kr(fltBus, LFNoise1.kr(0.3, 1000, 1500));
}).add;
SynthDef(\bass2, { | out=0 gate=1 freq=200 |
var aEnv, fEnv, osc, flt;
aEnv = EnvGen.kr(Env.asr(0, 1, 1), gate, doneAction: 2);
fEnv = EnvGen.kr(Env.perc(0, 3), levelScale: 6000);
osc = Mix([Saw.ar(freq * [1, 1.005]), Pulse.ar(freq / 2, 0.5)]);
flt = LPF.ar(osc, fEnv + 100, aEnv);
Out.ar(out, flt);
}).add;
SynthDef(\delayz, { | bus in mix |
var sig, delay;
sig = In.ar(bus, 2);
delay = CombL.ar(sig, 0.25, [0.25, 0.24], 2);
ReplaceOut.ar(bus, XFade2.ar(sig, delay,mix));
}).add;
SynthDef(\faderz, { | out=0 in mute=1 amp=1 |
Out.ar(out, In.ar(in, 2) * mute * amp)
}).add;
SynthDef(\hihats2,
{
|amp=0.1,out=0,pan=0,carfreq=200,mod1freq=200,mod1amt=0.1,mod2freq=200,mod2amt=0.1,mod3freq=200,mod3amt=0.1,att=0.005,attCurve=0,dec=0.1,decCurve=0,hpfFreq=2000|
var car, mod1, mod2, mod3, env, audio;
env = EnvGen.kr(Env([0,1,0],[att,dec],[attCurve,decCurve]),1,amp,doneAction:2);
mod3 = SinOsc.ar(mod3freq,0,mod3amt);
mod2 = Pulse.ar(mod2freq + (mod2freq * mod3), mod2amt, 1);
mod1 = SinOsc.ar(mod1freq + (mod1freq * mod2), 0, mod1amt);
car = SinOsc.ar(carfreq + (carfreq * mod1), 0, env);
car = HPF.ar(car,hpfFreq);
audio = Pan2.ar(car,pan);
Out.ar(out,audio);
}
).add;
SynthDef(\hh_z,
{
|amp=0.1,out=0,pan=0,carfreq=200,mod1freq=200,mod1amt=0.1,mod2freq=200,mod2amt=0.1,mod3freq=200,mod3amt=0.1,att=0.005,attCurve=0,dec=0.1,decCurve=0,hpfFreq=2000|
var car, mod1, mod2, mod3, env, audio;
env = EnvGen.kr(Env([0,1,0],[att,dec],[attCurve,decCurve]),1,amp,doneAction:2);
mod3 = SinOsc.ar(mod3freq,0,mod3amt);
mod2 = SinOsc.ar(mod2freq + (mod2freq * mod3), 0, mod2amt);
mod1 = SinOsc.ar(mod1freq + (mod1freq * mod2), 0, mod1amt);
car = SinOsc.ar(carfreq + (carfreq * mod1), 0, env);
car = HPF.ar(car,hpfFreq);
audio = Pan2.ar(car,pan);
Out.ar(out,audio);
}
).add;
)
//groups and busses....1st this block
(
//this clock will get used later..
~tc = TempoClock.default;
~master = Bus.audio(s, 2);
~masterAmp = Bus.control(s, 1);
~mixGroup = Group.new;
~fxGroup = Group.new;
~synthGroupz = Group.before(~fxGroup);
~ch7 = (Bus.audio(s, 2));
~masterFader = Synth(\faderz, [\out, 0, \in, ~master], ~mixGroup);
~masterFader.map(\amp, ~masterAmp);
~masterAmp.value = 1;
)
//then this block...
(
~numChannels = 9;
~master = Bus.audio(s, 2);
~masterAmp = Bus.control(s, 1);
~numChannels.do { | i |
("ch" ++ i).asSymbol.envirPut(Bus.audio(s, 2));
("chAmp" ++ i).asSymbol.envirPut(Bus.control(s, 1));
};
~resFlt = Bus.control(s, 1);
~soloGate = Bus.control(s, 1);
~soloFreq = Bus.control(s, 1);
)
//and then this last block...
(
~masterFader = Synth(\faderz, [\out, 0, \in, ~master], ~mixGroup);
~numChannels.do { | i |
("fader" ++ i).asSymbol.envirPut(Synth(\faderz, [\out, ~master, \in, ("ch" ++ i).asSymbol.envirGet], ~mixGroup));
};
~ch3ins01 = Synth(\delayz, [\bus, ~ch3, \mix, -0.8], ~fxGroup);
~ch4ins01 = Synth(\delayz, [\bus, ~ch4, \mix, -0.9], ~fxGroup);
~ch5ins01 = Synth(\delayz, [\bus, ~ch5, \mix, -0.6], ~fxGroup);
~ch6ins01 = Synth(\delayz, [\bus, ~ch6, \mix, 0.0], ~fxGroup);
~ch7ins01 = Synth(\delayz, [\bus, ~ch7, \mix, -0.8], ~fxGroup);
~ch8ins01 = Synth(\delayz, [\bus, ~ch8, \mix, -0.5], ~fxGroup);
~masterFader.map(\amp, ~masterAmp);
~numChannels.do { | i | ("fader" ++ i).asSymbol.envirGet.map(\amp, ("chAmp" ++ i).asSymbol.envirGet) };
~masterAmp.value = 1;
~chAmp0.value = 0.7;
~chAmp1.value = 0.3;
~chAmp2.value = 0.6;
~chAmp3.value = 0.3;
~chAmp4.value = 0.8;
~chAmp5.value = 0.1;
~chAmp6.value = 0.07;
~chAmp7.value = 0.03;
~chAmp8.value = 0.075;
)
Check the node tree for an idea about how the groups are being arranged. At this point it should look like this. The empty group is "mixGroup" and it will contain all of the synths as they are created and destroyed. The order of execution is one group after another. Therefore the effects will need to come after the synths. In the node tree to the left this is the case.
Now we have the Pbinds that will sequence the pattern. This block needs to be selected and run. Note that if we want a sound to be without the effect we need to change the output (\out) to 0 - see the bass_versez2 Pbind below. That Pbind sets the output to 0 which bypasses the effect chain.
(
~bass_versez = Pbind(
\instrument, \sd,
\out, ~ch7,
//\out, 0,
\scale, [0, 2, 3, 5, 7, 8, 10],
\degree, Pseq([0, 0, 3, 6, 7], inf),
\octave, 3,
\dur, Pseq([1,1,2,1], inf),
//\dur, Pseq([7.5, 0.5, 3.5, 0.5, 4], inf),
\group, ~synthGroupz.nodeID
);
~bass_versez2 = Pbind(
\instrument, \bd,
//\out, ~ch4,
\out, 0,
\scale, [0, 2, 3, 5, 7, 8, 10],
\degree, Pseq([0, 0, 3, 6, 7], inf),
\octave, 3,
\dur, Pseq([1,1,0.5,1], inf),
//\dur, Pseq([7.5, 0.5, 3.5, 0.5, 4], inf),
\group, ~synthGroupz.nodeID
);
~hat = Pbind(
\instrument, \hat,
\out, ~ch2,
\dur, Pseq([0.25], 128),
\group, ~synthGroupz.nodeID
);
~hat2 = Pbind(
\instrument, \hat2,
\out, ~ch2,
\dur, Pseq([0.25,0.5,1,0.25], 128),
\group, ~synthGroupz.nodeID
);
~hat3 = Pbind(
\instrument, \hh_z,
\amp,Pbrown(0.7,1,0.001,inf),
\out, ~ch4,
\carfreq, 5000 * Pgauss(1,0.5,inf),
\mod1freq, 883 * Pgauss(1,0.02,inf),
\mod1amt, 0.6,
\mod2freq, 283,
\mod2amt, 0.7,
\mod3freq, 487,
\mod3amt, 0.8,
\att, 0.003,
\attCurve, 2,
\dec,Pbrown(0.05,0.6,0.001,inf),
\decCurve, -7,
//\freq, \,
\amp, Pseq([0.1,0.02,Pwrand([0,0.02],[9,11].normalizeSum)],inf) * Pgauss(1,0.08,inf),
\dur, Pseq([0.25,0.5,1,2,0.25,0.25,0.25,0.25,0.25],128),
\timingOffset, Pbrown(-0.02,0.02,0.001,inf),
\hpfFreq, 3000
);
~hat4 = Pbind(
\instrument, \hihats2,
\amp,Pbrown(0.7,1,0.001,inf),
\out, ~ch4,
\carfreq, 5000 * Pgauss(1,0.5,inf),
\mod1freq, 883 * Pgauss(1,0.02,inf),
\mod1amt, 0.6,
\mod2freq, 283,
\mod2amt, 0.7,
\mod3freq, 487,
\mod3amt, 0.8,
\att, 0.003,
\attCurve, 2,
\dec,Pbrown(0.05,0.6,0.001,inf),
\decCurve, -7,
//\freq, \,
\amp, Pseq([0.1,0.02,Pwrand([0,0.02],[9,11].normalizeSum)],inf) * Pgauss(1,0.08,inf),
\dur, Pseq([0.25,0.25],128),
\timingOffset, Pbrown(-0.02,0.02,0.001,inf),
\hpfFreq, 3000
);
)
Then we play the Pbinds in some sort of sequential or parallel order. Or in the last block of code a system clock which plays a sequence.
//run this first
(
~intro1 = Ppar([~bass_versez, ~bass_versez2, ~hat2, ~hat3, ~hat4, ~hat]);
~intro2 = Ppar([~bass_versez, ~hat3,~bass_versez2]);
~intro3 = Ppar([ ~hat4, ~bass_versez2]);
)
//then use these...
~intro1 = Ppar([~bass_versez, ~bass_versez2, ~hat2, ~hat3, ~hat4, ~hat]).play;
~intro1.stop;
SystemClock.sched(1, {
~tc.tempo = 136/ 60;
//~beat = 0; ~tc.schedAbs(~tc.beats.ceil, { ~beat = ~beat + 1; ~beat.postln; 1 });
~tc.sched(16, { ~tc.tempo = 136 / 60 });
Pseq([
~intro1,
~intro2,
~intro3,
]).play;
});
//we can mute everything with the master fader environment variable.
~masterFader.set(\mute, 0);
~masterFader.set(\mute, 1);