Friday, August 21, 2009

More 140 character SuperCollider Tweets

Even SuperCollidists aren't immune to the memetic allure of Twitter, there's been a whole load of 140 character SuperCollider programmes appearing both on Twitter and on the SC Users list. Thankfully someone has been kind enough to collect them all up and put them on this page here, at the SC Wiki. Smashing.

Here's a couple of my favorites,

from Fredrik Olofsson

{RHPF.ar(GbmanN.ar([2300,1150]),LFSaw.ar(Pulse.ar(4,[1,2]/8,1,LFPulse.ar(1/8)/5+1))+2)}.play

And from the Venerable Dan

{LocalOut.ar(a=DynKlank.ar(`[LocalIn.ar.clip2(LFPulse.kr([1,2,1/8]).sum/2)**100*100],Impulse.ar(10)));HPF.ar(a).clip2!2}.play//#supercollider

Sunday, August 9, 2009

Recreating the THX sound

In a similar vein to the recreation of the rave hoover here's another reverse engineer and recreation of a famous sound, the tooth shattering TXH Deep Note. You can read the full story on EarSlap, but here's the final code.

//inverting init sort, louder bass, final volume envelope, some little tweaks

(

{

var numVoices = 30;

var fundamentals = ({rrand(200.0, 400.0)}!numVoices).sort.reverse;

var finalPitches = (numVoices.collect({|nv| (nv/(numVoices/6)).round * 12; }) + 14.5).midicps;

var outerEnv = EnvGen.kr(Env([0, 0.1, 1], [8, 4], [2, 4]));

var ampEnvelope = EnvGen.kr(Env([0, 1, 1, 0], [3, 21, 3], [2, 0, -4]), doneAction: 2);



var snd = Mix

({|numTone|



var initRandomFreq = fundamentals[numTone] + LFNoise2.kr(0.5, 6 * (numVoices - (numTone + 1)));

var destinationFreq = finalPitches[numTone] + LFNoise2.kr(0.1, (numTone / 3));

var sweepEnv =

EnvGen.kr(

Env([0, rrand(0.1, 0.2), 1], [rrand(5.5, 6), rrand(8.5, 9)],

[rrand(2.0, 3.0), rrand(4.0, 5.0)]));

var freq = ((1 - sweepEnv) * initRandomFreq) + (sweepEnv * destinationFreq);



Pan2.ar

(

BLowPass.ar(Saw.ar(freq), freq * 6, 0.6),

rrand(-0.5, 0.5),

(1 - (1/(numTone + 1))) * 1.5

) / numVoices

}!numVoices);



Limiter.ar(BLowPass.ar(snd, 2000 + (outerEnv * 18000), 0.5, (2 + outerEnv) * ampEnvelope));

}.play;

)


Apparently the original took 20,000 lines of C code! This is a tad more efficient and sounds very close to the original.

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.