Sunday, May 31, 2009

Hadron

Anonther intersting new quark,Hadron is a graphical patching environment for use in SC. Looks a bit like it may cover some of the same ground as TeaTracks, featured here previously, but I haven't used it yet. There is a very handy instructional video, which is allways nice.

Tuesday, May 19, 2009

Simple Phaser effect.

Another guitar effect, but also suitable for other things, a simple phaser. This example was adapted from the truly fantastic ixi-audio SuperCollider tutorial.

(
SynthDef(\phaser, { arg out=0, in=0;

var input,dsig, mixed;
input = SoundIn.ar(in, 1);

dsig = AllpassL.ar(input, 4, SinOsc.ar(2, 0, 0.005, 0.005), 0);
mixed = input + dsig;
Out.ar([out, out+1], mixed);
}).load(s);
)

a = Synth(\phaser, addAction:\addToTail)


Very similar to flange, but with a shorter delay time and no feedback, it's got a more otherworldly sound.

Tuesday, May 12, 2009

Creating plugins with SuperCollider AU

SuperColliderAU is an AudioUnit wrapper that allows you to embed a SuperCollider server in a AU host and either control it through SClang or package it up as a stand alone plugin.
It is of course OS X only being based around Apples AU API and there are some limitations to what you can do with it. According to the SourceForge page activity on this project seems to have stalled a bit, but it's pretty usuable in it's current state. It is possible to create effects units, but instruments with midi support don't seem to work very well. I've strugled to get anything to happen with Garage Band as a host at least, but that could just be me.
To install it you'll need to follow the instructions provided on the readme, it's very simple, just adding the main class and the server to the relevant directories, then recompile the lang and you're ready to go.
I decided to use it to create a bitcrushing plugin, making use of the Decimator Ugen, featured here before. The code is really simple, here it is.




( var name, func, specs, componentType, componentSubtype, builder;

name = "Decimator"; // name of your plugin
func = {
| sampleRate, bitRate|

var decOut, in;

in = AudioIn.ar([1]); //Input from AU host

decOut = Decimator.ar(in, sampleRate , bitRate);


Out.ar(0, decOut);//Output to AU host
};

specs = #[
[0, 20000 , \Linear, 10000,\Hertz ] ,
[0, 16 , \Linear, 8,\Indexed ]
];




componentType = \aufx;



componentSubtype = \DECI;


builder = AudioUnitBuilder.new(name, componentSubtype,func, specs, componentType);




builder.makeInstall;

)





There's a function, this is the code that the server will execute when it's embeded in the AU host, there's an array of specs that described the units, range and presets for the GUI control and a builder command that takes the relevant arguments and packages up the plugin.
The function is a very simple effect patch that takes the audio in from the AU host, decimates it and sends it to the output. The help file is a bit vague about this, but I assume that the relevant audio bus used for input from the AU host is 1, and that it needs to be sent out through 0, this is what seems to work anyway.
After that there's the control spec array, this is slightly different from the standard SC spec, but it is explained in the help file fairly well. It contains the range of values, the type and the default setting. In this case I've st up two suitable sliders to control the bit rate and sample rate, I selected index as the type for the bit rate as this gives an integer.
The builder command takes the name of the plugin, a component subtype, basically a unique identifier for the plugin, the function to be used, the spec and the component type, in this case an audio effect unit.
All being well, when this could runs it should create a plugin in the SuperCollider_f/scaudk folder, which can then be loaded into your AU host.

Here's the final product ready rolled.
It you want to gove it a try it should be fairly self explanatory, but I can't guarantee compatabilty with all AU hosts.

Saturday, May 9, 2009

Guitar effects

I've concentrated mostly on synthesis so far with my SuperCollider experiments, but today for a change I've been trying out some audio prosessing with a live input, my guitar.

To get a Mic or line input in SC you have several options, but using a SoundIn Ugen seems to be the easiest. SoundIn is a wrapper for the standard In Ugen, but it makes thigs easier by offsetting the bus index so that the first audio input is always 0. Setting up audio in in SuperCollider can be a bit of a chore, so check the help file if you can't fathom how input works.

Let's start with distortion, there's loads of ways of doing this,


{SoundIn.ar(0).fold2(0.3)}.play

using fold2 works well, as does clip

{SoundIn.ar(0).clip2(0.3)}.play

and there's also the obviously titled distort

{SoundIn.ar(0).distort}.play

The effect of this sems to be fairly subtle though. Making better use of it is this SynthDef, which comes from the Pfx help file, last used with my drum machine.

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, (SoundIn.ar(out, 2) * pregain).distort * amp);

}, [\ir, 0.1, 0.1, 0]).store;



You'll need to use a line like this to set the synth up.

a = Synth(\distort, addAction:\addToTail)

and if you're feeling like Alec Empire you can't beat a bit of bitcrushing for uttlerly insane fuzz.

{Decimator.ar(SoundIn.ar(0), 10000, 1)}.play



FreeVerb is an excellent choice for reverb,

{FreeVerb.ar(SoundIn.ar(0).distort)}.play


but something like flange is more difficult. This example is taken from the ixi-audio tutorial from ixi-audio.com, very slightly adapted to fit my audio input busses.

A flange effect adds a continually varying delayed signal to the original creating a phasing effect. The AllpassL in this case is the delay, with the LFpar UGen controlling the delay time, which is then mixed with the original input.



*/



(
SynthDef(\flanger, { arg out=0, in=0, delay=0.1, depth=0.08, rate=0.06, fdbk=0.0, decay=0.0;

var input, maxdelay, maxrate, dsig, mixed, local;
maxdelay = 0.013;
maxrate = 10.0;
input = SoundIn.ar(in, 1);
local = LocalIn.ar(1);
dsig = AllpassL.ar( // the delay (you could use AllpassC (put 0 in decay))
input + (local * fdbk),
maxdelay * 2,
LFPar.kr( // very similar to SinOsc (try to replace it) - Even use LFTri
rate * maxrate,
0,
depth * maxdelay,
delay * maxdelay),
decay);
mixed = input + dsig;
LocalOut.ar(mixed);
Out.ar([out, out+1], mixed);
}).load(s);
)




After evaluating that SynthDef you'll need to set up an instance of the synth and set the audio in like this,

a = Synth(\flanger, [\in, 0], addAction:\addToTail)

you can then set the various parameters of the effect like this.


a.set(\delay, 0.04)
a.set(\depth, 0.04)
a.set(\rate, 0.01)
a.set(\fdbk, 0.08)
a.set(\decay, 0.01)

.

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.