Showing posts with label patterns. Show all posts
Showing posts with label patterns. Show all posts

Thursday, March 19, 2009

Some Birthday Code

It's was my birthday recently and I was lucky enough to  get this birthday code from my old friend and Finchley's premier SuperCollidist, Dan. 

I was going to post the code on here, but it's pretty long and I can't get it to format nicely at the moment, so you'll have to make do with the .scd file in the link above. 

Happy Birthday to me.  

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.

 

Tuesday, February 10, 2009

Simple Drum Machine

After shamelessly flashing my Moog synth, I think it's time to reveal another SuperCollider creation. A very simple drum machine, made up of two parts. A SynthDef, defining my drums and a pattern template to play them. 

Here's the SynthDef 

(
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
 
 )

I have four sound sources, four envelopes and four panners.

I have to admit that the drum sounds are a bit crappy and need some more work, they've got a certain Casio feel to them, and not in a good way, but they do the job.

After some experimentation I've discovered that pretty much anything sounds something like a drum if you put it through a percussive envelope, but so far the best results seem to come from some sort of noise source and/or a SinOsc. 

The bass drum is a fairly low frequency sine with a bit of crackle added to it at a low level.

The snare is a sine with some white noise subtracted from it, I don't fully understand this yet, but subtracting a white noise source from the sine sounded better than adding it. 

A wild guess lead me to the klank UGen in creating the hat( I think it might be a felt one)  and the tom is just a simple SinOsc. 

All these sound sources are controlled with percussive envelopes, each with slightly varying attack and release times. 

These are then passed to a two channel panner, which apart from allowing me to control the level of the sound also allows me to change the position of the sound between two channels. 

   Here's the pattern I use to control it. 
 

(
   
   
  

 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]); 
 
 
 p = Pbind(
  \instrument, \drums,
  \dur, 0.12,
  \bassLevel, Pseq ([a], inf), 
  \snareLevel, Pseq ([b], inf),
  \hatLevel, Pseq ([c], inf),  
  \tomLevel, Pseq ([d], inf)
   
  ).play;
   
   
  )  

The args passed to my SynthDef include levels for each of the drums. Sequencing these using a pattern seemed like the easiest way of triggering them. Each value of the pattern can be set at either 0 for no drum or >0 to trigger a drum sound. This might not be the most efficient way of doing things but it does work.

I still don't understand exactly how it works, but the /dur argument sets the tempo, I think each event is timed as a fraction of the default clock setting of 1, but I could be wrong. 

You can do all kinds of great things with patterns, above I'm nesting them rather than defining them directly which will allow me to more easily create complex drum sequences. If I want to compose a song I can define more patterns and sequence them with the main pattern. 

(
   
   
  

 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 = Pseq ([0, 0,  1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1]);
 
 p = Pbind(
  \instrument, \drums,
  \dur, 0.12,
  \bassLevel, Pseq ([a], inf), 
  \snareLevel, Pseq ([b, e], inf),
  \hatLevel, Pseq ([c], inf),  
  \tomLevel, Pseq ([d], inf)
   
  ).play;
   
   
  )  

Like that.