Showing posts with label drum machine. Show all posts
Showing posts with label drum machine. Show all posts

Thursday, April 16, 2009

Pattern FX with Pfx

It's time to bring out my drum machine again. I've done effects with it before, but this is a new method, slightly more intuitive as you don't need to mess about with busses, it's all handled by the patterns.

(
SynthDef(\drums, {|out = 0, bassLevel = 0 , snareLevel = 0, hatLevel = 0, tomLevel = 0, pan1 = -1, pan2 = -1, pan3 = 1, pan4 = 1|

var env1, env2, env3, env4, bass, snare, hat, tom, bassOut, snareOut, hatOut, tomOut, mixer;
env1 = EnvGen.kr(Env.perc(0.001, 0.2, 1, -4), 1, doneAction:2);
env2 = EnvGen.kr(Env.perc(0.001, 0.5, 1, -1), 1, doneAction:2);
env3 = EnvGen.kr(Env.perc(0.002, 0.3, 1, -2), 1, doneAction:2);
env4 = EnvGen.kr(Env.perc(0.001, 0.1, 1, -5), 1, doneAction:2);
bass = SinOsc.ar(80) + Crackle.ar(1, 0.5);
bassOut = Pan2.ar(bass*env1, pan1, bassLevel);

snare = SinOsc.ar(120) - WhiteNoise.ar(0.5, 0.5);
snareOut = Pan2.ar(snare*env4, pan2, snareLevel);

hat = Klank.ar(`[ [ 6563, 9875 ],
[ 0.6, 0.5 ],
[ 0.002, 0.003] ], PinkNoise.ar(1));
hatOut = Pan2.ar(hat*env3, pan2, hatLevel);

tom = SinOsc.ar(440);
tomOut = Pan2.ar(tom*env4, pan4, tomLevel);

mixer = Mix.new([bassOut, snareOut, hatOut, tomOut]);


Out.ar(out, mixer);

}).store

)




Pfx, or at least it's near relation Pfxb, is currently being debated on the SC Users list so some people might be having problems with it. It seems to work fine for me with OS X, but I think it's a pretty new feature so you might need the latest SuperCollider release candidate if you want to give it a try.

This code is very closely adapted from the Pfx help file, all I've really done is bodge my drum machine sythdef onto it, but it works very well.

(
SynthDef(\echo, { arg out=0, maxdtime=0.2, dtime=0.2, decay=2, gate=1;
var env, in;
env = Linen.kr(gate, 0.05, 1, 0.1, 2);
in = In.ar(out, 2);
XOut.ar(out, env, CombL.ar(in * env, maxdtime, dtime, decay, 1, in));
}, [\ir, \ir, 0.1, 0.1, 0]).store;

SynthDef(\distort, { arg out=0, pregain=40, amp=0.2, gate=1;
var env;
env = Linen.kr(gate, 0.05, 1, 0.1, 2);
XOut.ar(out, env, (In.ar(out, 2) * pregain).distort * amp);
}, [\ir, 0.1, 0.1, 0]).store;

SynthDef(\wah, { arg out=0, gate=1;
var env, in;
env = Linen.kr(gate, 0.05, 1, 0.4, 2);
in = In.ar(out, 2);
XOut.ar(out, env, RLPF.ar(in, LinExp.kr(LFNoise1.kr(0.3), -1, 1, 200,
8000), 0.1).softclip * 0.8);
}, [\ir, 0]).store;
)


(




a = Pseq ([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]);
b = Pseq ([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]);
c = Pseq ([0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0]);
d = Pseq ([0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1]);
e = Pwhite (0.14, 0.16, inf);

p = Pbind(
\instrument, \drums,
\dur, e,
\bassLevel, Pseq ([a], inf),
\snareLevel, Pseq ([b], inf),
\hatLevel, Pseq ([c], inf),
\tomLevel, Pseq ([d], inf)

);


q = Pfx(p, \echo, \dtime, 0.02, \decay, 0.1);

r = Pfx(q, \distort, \pregain, 20, \amp, 0.25);

o = Pfx(r, \wah).play;
)






Pfx takes a pattern and the name of the effect synthdef as arguemnts, then the names and the arguments you'd usually pass to the synthdef to control it. Pfx then takes the patern you've specified and plays it through the effect you've given it.

As shown in the above code, you can easily nest Pfx patterns to layer on more effects. I've got my original drum machine pattern defined as normal then I've passed it to a Pfx named q, then passed that new pattern on to r and then o, so I end up with my initially defined pattern passed through three effects.

Sounds dubesque.

Tuesday, February 17, 2009

A Filter and Even More Drum Machine

Pulled from the ever informative SuperCollider Users Mailing List is this fine little example of an interesting low pass filter courtesy of nonprivate,  aka DJ Cylob.

"

this is kind of nice,

here's the normal sort of lpf:

(

var f;
f = FSinOsc.kr(1, 0, 24, 84).midicps;
RLPF.ar(Saw.ar(70,0.2), f, 0.3)
}.play
)

but with this combo of lpf and mid eq, the bass disappears as the resonance increases, which is a bit more like a real filter.

(

var f;
f = FSinOsc.kr(1, 0, 24, 84).midicps;

MidEQ.ar(
 LPF.ar(Saw.ar(70,0.2), f), 
 f, 

 0.5, 18, 0.6


}.play
)
"

Inspired by this I decided to see if I could use it on my drum machine and at the same learn how to send the output of a pattern through an effect. 

Here's the code I came up with, adapted from the Pbind help file which covers this very topic. 

(
SynthDef(\drums, {|out = 0, bassLevel = 0 , snareLevel = 0, hatLevel = 0, tomLevel = 0, pan1 = 0, pan2 = 0, pan3 = 0, pan4 = 0|

 var env1, env2, env3, env4, bass, snare, hat, tom, bassOut, snareOut, hatOut, tomOut, mixer; 
 env1 = EnvGen.kr(Env.perc(0.001, 0.2, 1, -4), 1, doneAction:2);
 env2 = EnvGen.kr(Env.perc(0.001, 0.5, 1, -1), 1, doneAction:2);
 env3 = EnvGen.kr(Env.perc(0.002, 0.3, 1, -2), 1, doneAction:2);
 env4 = EnvGen.kr(Env.perc(0.001, 0.1, 1, -5), 1, doneAction:2); 
 bass = SinOsc.ar(80) + Crackle.ar(1, 0.5);
 bassOut = Pan2.ar(bass*env1, pan1, bassLevel);
 
 snare = SinOsc.ar(120) - WhiteNoise.ar(0.5, 0.5);
 snareOut = Pan2.ar(snare*env4, pan2, snareLevel); 
 
 hat = Klank.ar(`[ [ 6563, 9875 ],
  [ 0.6, 0.5 ],
  [ 0.002, 0.003] ], PinkNoise.ar(1)); 
 hatOut = Pan2.ar(hat*env3, pan2, hatLevel); 
 
 tom = SinOsc.ar(440); 
 tomOut = Pan2.ar(tom*env4, pan4, tomLevel); 
 
 mixer = Mix.new([bassOut, snareOut, hatOut, tomOut]); 
 
 
 Out.ar(out, mixer);
 
 }).store
 
 )
   
 

 (
  SynthDef("lpfandmideq", { arg out;  
 var audio, efx, f;
 f = SinOsc.kr(3, 0, 24, 84).midicps; 
 audio = In.ar(20,2);
 efx= MidEQ.ar(
 LPF.ar(audio, f), 
 f, 

 0.5, 18, 0.6
); 
 
 Out.ar(out, efx);
}).memStore;  
  )
   
  (  
  a = Synth.after(1, "lpfandmideq");  
  )  
   
   
  (
   
   
  

 a = Pseq ([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]);
 b = Pseq ([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]);
 c = Pseq ([0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0]);
 d = Pseq ([0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1]); 
 e = Pwhite (0.14, 0.16, inf);
 
 p = Pbind(
  \instrument, \drums,
  \out, 20,
  \dur, e,
  \bassLevel, Pseq ([a], inf), 
  \snareLevel, Pseq ([b], inf),
  \hatLevel, Pseq ([c], inf),  
  \tomLevel, Pseq ([d], inf)
   
  ).play;
   
   
  )  

 To make this work you will need to make sure that you evaluate each section in brackets separately, apart from that it's pretty striaghtforward really.

In setting up the effect synth I needed to make sure that I set the input bus and the number of channels,  this needs two beacuse the drum machine is a two channel synth

audio = In.ar(20,2);

then create an instance of this synth

(  
  a = Synth.after(1, "lpfandmideq");  
  )  

and finally set the output of my pattern to the same bus that I set as the input of my effect. 

\out, 20,

and that's Jazz. 

Surprisingly easy really and it doesn't sound too bad.

 

Wednesday, February 11, 2009

More drum machine

I've been fiddling with my maliciously inept drum machine a bit more and using a couple of the enormous selection of pattern classes I've added some new features. 

A lot of real drum machines both hardware and software have a 'swing' or 'shuffle' which add a bit of syncopation though I suspect most of them do it in a more sophisticated way than what I've done here.   

e = Pwhite (0.14, 0.16);

 \dur, e,

I've used a Pwhite pattern to randomly select the \dur interval. 

The Pwhite pattern randomly generates values from a range provided by the first two parameters and repeats this a number of times set by the third value entered, with inf being the default. Sticking this into my drum sequence means that the interval between each drum sound will be random, givning it a possibly more 'organic' feel. Or maybe just making it sound wonky.

I've seen some software synths that let the user generate random patterns, I've done something similar using a Pwrand.

 f = Pwrand ([0, 1], [75, 25].normalizeSum, inf);

 \bassLevel, Pseq ([f], inf), 

 A Pwrand pattern generates random numbers from a list with a weighted probability. The above line generates a pattern with a 25% chance of each step having a drum sound  and a 75% chance of being silent.

Pwrand takes two arrays as arguments, the first one being the list of numbers to select randomly from, the second one being a list of probabilities, which should add up to one. Passing the second array a .normaliseSum message neatly side steps my poor mental arithmetic and automatically normalises the array elements to sum to one. Being able to weight the results makes the resulting pattern sound more rhythmic, without long silences or rolls that an unweighted probability would lead to.   

Here's the full pattern with these two bits added. 

 (

 a = Pseq ([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]);
 b = Pseq ([0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]);
 c = Pseq ([0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0]);
 d = Pseq ([0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1]); 
 e = Pwhite (0.14, 0.16);
 f = Pwrand ([0, 1], [75, 25].normalizeSum, inf);
 
 
 p = Pbind(
  \instrument, \drums,
  \dur, e,
  \bassLevel, Pseq ([f], inf), 
  \snareLevel, Pseq ([b], inf),
  \hatLevel, Pseq ([f], inf),  
  \tomLevel, Pseq ([d], inf)
   
  ).play;
   
   
  )