Saturday, May 2, 2009

Crushing the Bits for Fun and Profit

Bitcrushing, reducing the sample and bit rate of audio for effect was invented by audio pioneer Bit Crusher in the early 80's and is pretty easy to implement in SuperCollider.
There are a few ways of doing it, but probably the easiest is to use the ladspa plugins that are part of the Standard SC plugin pack.
There don't seem to be any help docs with these plugins, but they aren't too hard to work out.
For now I'm using Decimator, which looks a bit like this,

Decimator.ar(in, rate, bits, mul, add )

It takes audio in, and the new sample rate and bit depths you want to use, as well as the standard mul and add args.

Here's my faithful drum machine yet again, this time with some bitcrushing.

(
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

)



(
SynthDef("bitcrush", { arg out;
var audio, efx, f;

audio = In.ar(20,2);
efx= Decimator.ar(audio, SinOsc.ar(0.05, 0, 9000, 1000).abs, 1);
Out.ar(out, efx);
}).memStore;
)

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


(




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;


)



This uses the same method that I used previously to add an effect to a pattern, sending the output of the pattern to the bitcrusher through a bus, and making sure the order of execution is correct the with Synth.after method.
I'm using a sin oscillator to modulate the sample rate, varying it between 1000 and 10000 and using a .abs method to make sure it doesn't go negative, because negative sample rates don't work.
At lower bit rates and depths it's got a very 8-bit sound not unlike the ZX Spectrum beeper.
Buzzy.

2 comments: