Saturday, July 25, 2009

Auto chiptunes with Moog

Wow, it's been a while since I've posted, but It's been a busy month.
Here's an update to Dan's auto chiptune thing that I modified in my last post. This time I decided to mate it with my Moog synthdef in an attempt to create a pitch tracking interface for my synth. Surprisingly it works pretty well.

(
SynthDef("chiptune", { |oscType =0, oscType2 = 1, pan = 0, level = 0.5, cutoff = 500, gain = 3.3, attack = 0.1, decay = 0.1, sust = 0.7, rel = 0.2, attackf = 0.1, decayf = 0.1, sustf = 0.9, relf = 0.2, gate = 1, freq =440, lagLev = 0.2|
var son, pitch, amp, wibble, oscArray, oscArray2, ampEnv, filterEnv, osc1, osc2, fade, filter;
son = SoundIn.ar;
pitch = Tartini.kr(son)[0];
amp = Amplitude.ar(son);
pitch = Median.kr(5, pitch); // smooth
pitch = pitch.min(10000).max(10); // limit
pitch = pitch.cpsmidi.round.midicps; // coerce

oscArray = [Saw.ar(Lag.kr(pitch, lagLev)), SinOsc.ar(Lag.kr(pitch, lagLev)), Pulse.ar(Lag.kr(pitch, lagLev))];
oscArray2 = [Saw.ar(Lag.kr(pitch, lagLev)), SinOsc.ar(Lag.kr(pitch, lagLev)), Pulse.ar(Lag.kr(pitch, lagLev))];
ampEnv = EnvGen.ar(Env.adsr(attack, decay, sust, rel), gate, doneAction:2);
filterEnv = EnvGen.ar(Env.adsr(attackf, decayf, sustf, relf), gate, doneAction:2);
osc1 = Select.ar(oscType, oscArray);
osc2 = Select.ar(oscType2, oscArray2);
fade = Pan2.ar(XFade2.ar(osc1, osc2, pan , level * ampEnv, 0));
filter = MoogFF.ar(fade, cutoff * filterEnv, gain);
wibble = FreeVerb.ar(filter, 0.3, 0.1, 0.9); // bit of reverb just to taste
Out.ar(0, wibble.dup);
}).memStore;
)

Sunday, July 5, 2009

Auto Chiptune

A while ago now Dan posted some auto chip tune generating code on his blog, I've been meaning to write about this for ages, but I've only just got round to it. It takes any MP3 file and converts it to chiptune like sounds by using Tartini to follow the pitch and then re synthesising with a pulse wave. Here's the original code as taken from his blog.
s.boot;
(
SynthDef("help_mp3_01", { |bufnum = 0|
var son, pitch, amp, wibble;
son = DiskIn.ar(2, bufnum).mean;
pitch = Tartini.kr(son)[0];
amp = Amplitude.ar(son);
pitch = Median.kr(5, pitch); // smooth
pitch = pitch.min(10000).max(10); // limit
pitch = pitch.cpsmidi.round.midicps; // coerce
wibble = Pulse.ar(pitch, 0.2, amp * 2); // resynthesise
wibble = FreeVerb.ar(wibble, 0.3, 0.1, 0.9); // bit of reverb just to taste
Out.ar(0, wibble.dup);
}).memStore;
)

// Now let's create the MP3 object and cue it into a Buffer.
m = MP3("../mp3s/Gimme A Pig Foot And A Bottle Of Beer.mp3");
m.start;
b = Buffer.cueSoundFile(s, m.fifo, 0, 2);
// Off we go:
x = Synth("help_mp3_01", [\bufnum, b.bufnum], addAction:\addToTail);

// Please remember to tidy up after yourself:
x.free;
b.close; b.free;
m.finish;




Just for the hell of it I decided to adapt it to use live audio input and give it three different oscillators to choose from. Here's my version, you can change the oscillator with the \oscType parameter.

(
SynthDef("chiptune", { |oscType = 0|
var son, pitch, amp, wibble, oscArray;
son = SoundIn.ar;
pitch = Tartini.kr(son)[0];
amp = Amplitude.ar(son);
pitch = Median.kr(5, pitch); // smooth
pitch = pitch.min(10000).max(10); // limit
pitch = pitch.cpsmidi.round.midicps; // coerce
oscArray = [Pulse.ar(pitch, 0.2, amp * 2), SinOsc.ar(pitch, 0, amp * 2), Saw.ar(pitch, amp * 2)];
wibble = Select.ar(oscType, oscArray); // resynthesise
wibble = FreeVerb.ar(wibble, 0.3, 0.1, 0.9); // bit of reverb just to taste
Out.ar(0, wibble.dup);
}).memStore;
)


// Off we go:
x = Synth("chiptune", [\oscType, 1], addAction:\addToTail);

// Please remember to tidy up after yourself:
x.free;


sounds pretty good with guitar.

Thursday, June 25, 2009

SuperCollider 3.3.1 is out - Safari 4 fix.

SuperCollider 3.3.1 is out now and it works with Safari 4! I don't know about you but that's a weight off my mind.

Thursday, June 18, 2009

A Generative Looper.

What's a generative looper? It's a type of cartilaginous fish, but it's also a interesting new project from Arthur Carabot, via the SC Users list. Here's the source and here's an intructional video.
I can't get it to work at the moment but maybe it's just me.

Tuesday, June 16, 2009

More Dominator Deconstruction.

Another attempt at the rave hoover sound, this time from Wouter Snoei on the SC-Users list, probably the best so far and based on further research into the Alpha Juno 2. Here's the code,

(
SynthDef( "hoover", { |freq = 220, amp = 0.1, lgu = 0.1, lgd = 1, gate = 1|
var pwm, mix, env;

freq = freq.cpsmidi.lag(lgu,lgd).midicps;
freq = SinOsc.kr( { 2.9 rrand: 3.1 }!3, {2pi.rand}!3 ).exprange( 0.995, 1.005 ) * freq;
pwm = SinOsc.kr( {2.0 rrand: 4.0}!3 ).range(0.125,0.875);

// the saw/pulses
mix = (LFSaw.ar( freq * [0.25,0.5,1], 1 ).range(0,1)
* (1 - LFPulse.ar(freq * [0.5,1,2], 0, pwm))).sum * 0.1;

// the bass
mix = mix + LFPar.ar( freq * 0.25, 0, 0.1 );

// eq for extra sharpness
mix = BPeakEQ.ar( mix, 6000, 1, 3 );
mix = BPeakEQ.ar( mix, 3500, 1, 6 );

// kind of chorus
mix = mix + CombC.ar( mix.dup, 1/200,
SinOsc.kr( 3, [0.5pi, 1.5pi] ).range(1/300,1/200),
0.0 ) * 0.5;

env = EnvGen.kr( Env.asr, gate );

Out.ar( 0, mix * env * amp );
}).store;
)

(
p = Pmono(\hoover,
\dur, Pseq([0.25,0.5,7, 0.25]* 0.24, inf),
\lgu, 0.15,
\lgd, Pseq([ 0.1, 0.1, 1.5, 0.25], inf ),
\midinote, Pseq([20, 67, 62, 20] , inf)).play;
)
p.stop;

(
p = Pmono(\hoover, \dur, 0.24,
\lgu, 0.2,
\lgd, Pseq([1,1,2,0.5,2,2,2,2], inf ),
\midinote, Pseq([55, 40, 67, 55, 40, 55, 53, 52], inf)).play;
)
p.stop;


Wouter's come up with a more accurate version of the pulse width modulation, certainly more accurate than my complete guess work and it sounds great.

Here's a little line of code taken from Wouter's post that may offer a bit of an explaination of what's going on with the modulation.

{ LFSaw.ar( 200, 1 ).range(0,1) * (1-LFPulse.ar( 400, 0, 2/3 )) }.plot;

If you run it you should get this plot,



You can see the waveform is a sort of flattened saw wave, this might explain why Dan had trouble identifying what it was.

Sunday, June 14, 2009

Deconstructing the Dominator

Dan's got a post over on his blog about reverse engineering the "hoover sound' found in the old school rave classic Dominator by Human Resource. He took a pretty technical approach and did various forms of analysis to come up with something that sound pretty good.
I thought I'd have a go myself, but I decided to take a more direct approach and look it up. I found this wikipedia article about it, it turns out that Human Resource were using a Roland Alpha Juno 2 to create that sound, a mid 80's digital/analogue hybrid synth. There's a good explanation of it's features here, importantly though, it does have a chorus unit built in, which Dan did identify as being the key feature of the sound.

Here's my re-construction attempt, I did start out to try and recreate the functions of an Alpha Juno 2, but in the end I mostly just improvised.

(
SynthDef(\aj2, {
arg freq = 440, gate = 1, lagLev = 0.01, predelay=0.01, speed=0.05, depth=0.01, ph_diff=0.5;
var width1, width2, width3, osc1, osc2, osc3, filterOut, mix, sig, modulators, numDelays = 8, lfo;
width1 = SinOsc.ar(4, 0, 0.8, 0.2).abs;
width2 = SinOsc.ar(6, 0, 0.8, 0.2).abs;
width3 = SinOsc.ar(2, 0, 0.8, 0.2).abs;
lfo = SinOsc.kr(5, 0, 5);
osc1 = Pulse.ar(Lag.kr(freq + lfo), width1);
osc2 = Pulse.ar(Lag.kr((freq/2) + lfo), 0.5);
osc3 = Pulse.ar(Lag.kr((freq*2) + lfo), width3);
mix = Mix.new([osc1, osc2, osc3]);
modulators = Array.fill(numDelays, {arg i;
       SinOsc.kr(speed * rrand(0.94, 1.06), ph_diff * i, depth, predelay);}); 
sig = DelayC.ar(mix, 0.5, modulators);  
sig = sig.sum;
Out.ar(0, sig.dup)
}).store
)

p = Pmono(\aj2, \dur, 0.24, \midinote, Pseq([40, 67, 64, 62, 62, 62, 62, 62], inf)).play;



I've got three pulse width modulated square wave oscillators here, modulated with low frequency SinOscs and some vibrato added with another low frequency SinOsc. These are put through a chorus efect taken from the ixi-audio.com tutorial, featured here before.

My patch is mostly based on random guesswork and a little bit of research, but it sounds okay, though probably not as good as Dan's scientific attempt.

Monday, June 8, 2009

2 channel bitcrusher

A small update to my bitcrusher plugin, duplicating the bitchrushed output for 'stereo'. The old version had only 1 channel output, which was to be expected as the input was only 1 channel, but this meant that in Garageband at least the signal was just one channel of a 2 channel track. In effect that the signal was panned all the way to the left with no way of centering it, duplicating the output works round this.




( 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).dup;


Out.ar([0,1], 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;

)