Monday, October 28, 2013

Installing SuperCollider on Windows 7 and 8 and dealing with 'Device unavailable' could not initialize audio'

After another break from SuperColliding and switching from OSX to a Windows machine I thought I'd share my experiences installing and setting up SC on windows.

A few years ago when I first started with SuperCollider the Windows port was something of a poor relation to the lead OSX platform and the up and coming Linux port, but things have changed since then and the latest Windows version seems pretty good so far. The only downside I've found so far is driver and hardware support issues, although this may not be much of a problem depending on what hardware you have.

Installing the latest Windows port is theoretically pretty easy, just head over to the Sourceforge repository and download the latest version of the installer. All being well it should install itself without any bother from the super easy to use config GUI and you'll be ready to go.

I had no trouble at all setting it up on my Windows 7 laptop, everything worked right first time, no issues at all. My Windows 8 desktop on the other hand was a bit tougher.

I'm not sure, but I don't think it was an OS issue, it seems more likely that it was a hardware driver issue with my motherboard's crappy on board sound .

After using the installer and trying to boot the server for the first time I got this error:

'SC_PortAudioDriver: PortAudio failed at Pa_OpenDefaultStream with error: 'Device unavailable'
could not initialize audio'

Very helpful. After some Googling it seemed like a driver problem and the solution was something I already happened to have installed, ASIO4ALL. This is a universal ASIO driver which gives ASIO support to a whole range of crappy Windows sound cards that don't usually support it. Windows SuperCollider apparently plays nicely with ASIO sound cards, so using this should help.

The next thing I needed to do was to get SuperCollider to talk to my sound hardware in ASIO mode, which was pretty easily achieved by running this line of code:

Server.local.options.device ="ASIO4ALL"

Which I added to my startup file so it runs every time I open up the SC IDE.

And, success! Well nearly, because for reasons I really don't understand sometimes it works and sometimes it doesn't. Often when I boot the server ASIO4ALL says that the output device is unavailable and I have to disable it and enable it again to make it work. I think I might be better of getting a discrete sound card.

In short,

SuperCollider on Windows is pretty easy to get going if you are lucky with your sound hardware. If not Try ASIO4ALL, it's free and is very easy to install. It might be helpful.







Wednesday, July 20, 2011

Detuning oscillators.

I'm still not entirely sure how PmonoArtic works, perhaps it will forever remain a mystery, but I do know how the important part of this synth def I came up with works. Well more or less anyway.



(
SynthDef("aSynth",{

arg lagLev = 0.2, freq= 440, cutoff = 500, gate = 0.5;
var osc1 = Mix.fill(8, { SinOsc.ar(freq + 10.0.rand, 0, 0.05) }); var filterEnv = EnvGen.ar(Env.adsr(0.02, 0.1, 0.05, 1), gate, doneAction:2);
var filterOutput = MoogFF.ar(osc1, cutoff * filterEnv, 3.3); Out.ar(0, filterOutput);


}).store
)

(
PmonoArtic("aSynth",
\freq, Pseq([440,330,440,330,550,770,880], inf),
\legato, Pwrand(#[0.5, 1.0], #[0.1, 0.9], inf),
\dur, 0.3,
\cutoff, Pwhite(5000, 10000, inf)



).play
)

This is inspired by something I read on the SC Users list and it's an attempt at a synth that's more analoguesque. It didn't work quite as well as I had anticipated, so I think I'll have to try some more advanced techniques, but I suppose it's a start.

The significant bit is this line:

var osc1 = Mix.fill(8, { SinOsc.ar(freq + 10.0.rand, 0, 0.05) });

Here I'm using the Mix command along with fill to create an array of eight different oscillators all tuned slightly differently, randomly assigned plus or minus 10hz from the frequency passed to the sythdef. It's supposed to give it a vaguely chorus like effect by layering detuned oscillators, which it does a bit, but the effect isn't quite as noticeable as I thought. Increasing the number of oscillators doesn't help much and increasing the frequency that they can change by sounds pretty horrible.

The mix and fill commands are pretty simple to use, by the way.

On it's own you can use Mix.new(array) to mix an array of channels together, or you can use Mix.fill(n, function) to create a whole new array of channels with the function you specify.

I could be wrong, but I think that when you use Mix.fill in a synth def it will only evaluate the function when the synth is loaded, so if you're using random varaibles like I am above, they'll only be random once when it's run.


Tuesday, July 5, 2011

I've forgotten everything I ever learned about SuperCollider.

It's been so long I'm not even sure how to spell SuperCollider anymore, I think it's two lls, but that looks wrong.

Several versions of SC have come out since I last used it and of course lots of the quarks and plugins I had from previous versions now no longer work, so I've had to start from scratch with a fresh install. This is probably no bad thing as it means I need to work from the ground up and remind myself how it all works.

I've done this before I think, but now it's time to do again, a SuperCollider Theramin, this time with a phase effect.


{SinOsc.ar(MouseY.kr(1,880),SinOsc.kr(MouseX.kr(0,100)))}.play

Wednesday, April 20, 2011

I'm still alive.

I know it's been a very long time since I've updated this blog, but I'm still here and I think it's about time I started looking at Supercollider again. Watch this space.

Monday, November 30, 2009

'Harmoniser' with Tartini

A little patch I made today following on from the auto chip tune stuff from before. This time a 'harmoniser' type effect made with the same Tartini type resynthesising, using a live input. I've got 'harmoniser' in inverted commas because frankly it isn't very harmonic, but it's a start I suppose. Here's the code.

(
SynthDef("Harm", {|offSet1, offSet2, output, osc1, osc2, mix, pitch1, pitch2, fader|

var sound = SoundIn.ar;
var pitch = Tartini.kr(sound)[0];
var amp = Amplitude.ar(sound);
pitch = Median.kr(5, pitch); // smooth
pitch = pitch.min(10000).max(10); // limit
pitch1 = pitch.cpsmidi.round + 40;
pitch2 = pitch.cpsmidi.round + 60;

pitch1 = pitch1.midicps;
pitch2 = pitch2.midicps;

osc1 = Saw.ar(pitch1, amp * 2); // resynthesise
osc2 = Pulse.ar(pitch2, 0.2, amp * 2);
mix = Mix.ar([osc1, osc2]);
fader = XFade2.ar(sound, mix, -0.5);
output = FreeVerb.ar(fader, 0.3, 0.1, 0.9); // bit of reverb just to taste
Out.ar(0, output);

}).memStore;


)

x = Synth("Harm");



Here Im using Tartini to determine the pitch of the input, then using fairly roundabout method converting it to two lots of midi notes, adding to it to increase the pitch then sending it to some oscillators and finally mixing it back with the original input. If you change the numbers that I've added to the pitches here,

pitch1 = pitch.cpsmidi.round + 40;
pitch2 = pitch.cpsmidi.round + 60;



you should be able to change the 'harmony'.

There may be a better method to shift the synthesised pitches, I'm not sure but this does seem to work.
It sort of sound okay with some guitar or vocal input, but really bad with anything more complex.

Friday, October 30, 2009

Installing bbcut2 in OS X

I've just upgraded to OS X Snow Leopard and apart from it giving me the ability to take up serpents, drink any deadly thing and not be hurt etc, I also found myself reinstalling SuperCollider from scratch, including all the extensions, quarks and what have you that I had in my previous install.
Everything went smoothly with the exception of bbcut, which took a bit of work. I had the same problem when I installed it the first time round, but I ended up taking such as circuitous route to getting it working that I couldn't remember what I'd done by the time I'd finished. This time I took a more systematic approach and I've isolated the problem.
The latest version of the extension pack provided with the standard SC install includes some, but not all of the Ugens and classes that come with bbcut. If you follow the install instructions that come with bbcut you'll end up with conflicts and the class library won't compile.
To get it to work you'll need to leave out the three ugens in the bbcut2 ugens folder and the machinelistening classes from the bbcut2 classes folder when moving the bbcut folders to your SC directory. These seem to be the source of the conflicts and if you copy over the rest of the files as described in the bbcut2 help file it should all be okay.
If you've already copied these into your SC folder you'll need to make sure you delete the version of the files that come with bbcut and replace the them with the versions that come with the standard SC download, they are different and only the ones from the standard SC download will work. And that's jazz.

I've no idea how this goes on other platforms but I imagine there might be similar problems.

à bientôt.

Sunday, October 18, 2009

Wicki - not wiki

Another soupçon of useful code from the SC-Users list, a Wicki keybord, as used by the Wicki system.
What's the Wicki system? I'm not entirely sure, but it seems to be a way of learning to play music with a type writer style keyboard. There's some background info available here and here.
This bit of code is a class that creates a Wicki keyboard, it is a bit long so I won't reproduce it on this blog, but you can download it here, along with a bit of test code. You can use the keyboard to record and playback sequences of notes, which are stored in an array, probably easier than typing frequencies or midi values directly into patterns and do things like transpose the entire sequence.
As with all SC classes you'll need to put it in the extensions folder and recompile the language before it'll work. The wickiTest file in the zip shows of some of the class methods, but it doesn't mention the startRecording and stopRecording methods. If you want to record an a array of notes you'll need to set it up by doing something like
m.startRecording
and then
m.stopRecording
when you're done.

Saturday, October 3, 2009

From Den Haag

Some great code from tn8, via the SC-Users list, the source code from a piece that she performed at the SC symposium. You can download it here.
It's a fantastic track and it's pretty rare to see the complete source for a song written entirely in SC, so it's worth a look.

Thursday, September 17, 2009

Comb Filter Effect

Another handy snippet of code pulled from the SC-Users list once again. Credit for this goes to Kernal, kernel@audiospillage.com.
The gui should be mostly self explanatory I think, but if you want to use this with other inputs besides the test sound you'll need to set the input bus and send your sound through that.


// parrallel comb filters implemented as effect return

// send the synth defs(
(
SynthDef("ImpulseTest", {|bus = 3|

Out.ar(bus, [Impulse.ar(SinOsc.kr(0.23).range(0.5,23), 0.5)]);

}).send(s);
);

(
SynthDef("CombUnit",{| d1 = 0.001, d2 = 0.001, d3 = 0.001, d4 = 0.001, d5 = 0.001,
t1 = 1, t2 = 1, t3 = 1, t4 = 1, t5 = 1,
f1 = 20000, f2 = 20000, f3 = 20000, f4 = 20000, f5 = 20000,
vol = 1, inBus = 3, outBus = 0|

var in, out, c1, c2, c3, c4, c5;

in = In.ar(inBus, 1);

c1 = LPF.ar(CombC.ar(in, 1, d1, t1), f1);
c2 = LPF.ar(CombC.ar(in, 1, d2, t2), f2);
c3 = LPF.ar(CombC.ar(in, 1, d3, t3), f3);
c4 = LPF.ar(CombC.ar(in, 1, d4, t4), f4);
c5 = LPF.ar(CombC.ar(in, 1, d5, t5), f5);

out = (c1 + c2 + c3 + c4 + c5) * 0.2;

Out.ar([outBus, outBus + 1], out * vol);

}).send(s);
);
)



// create the synth
(
var grp, node, testNode, wComb, testRunning = 0, inputBus = 3;

s.sendMsg("s_new", "CombUnit", node = s.nextNodeID, 1, 1);
// s.sendMsg("g_new",grp = s.nextNodeID,1,1); // create group @ tail of default node

wComb = SCWindow("C O M A", Rect(100, 300, 720, 220))
.onClose_({
if(testRunning == 1, s.sendMsg("n_free", testNode));
s.sendMsg("n_free", node);
})
.front;

// input bus
SCNumberBox(wComb, Rect(10, 10, 30, 20))
.value_(3)
.action_({|v|
inputBus = v.value;
s.sendMsg("n_set", node, "inBus", inputBus);
if(testRunning == 0, s.sendMsg("n_set", testNode, "bus", inputBus));
});

SCStaticText(wComb, Rect(45, 10, 100, 20))
.string_("Input Bus");

// output bus
SCNumberBox(wComb, Rect(150, 10, 30, 20))
.value_(0)
.action_({|v| s.sendMsg("n_set", node, "outBus", v.value)});

SCStaticText(wComb, Rect(185, 10, 100, 20))
.string_("Output Bus");

// audio test
SCButton(wComb, Rect(300, 10, 100, 20))
.states_([
["Start Test", Color.green, Color.black],
["Stop Test", Color.red, Color.black]
])
.action_({
if(testRunning == 0, {
s.sendMsg("s_new", "ImpulseTest", testNode = s.nextNodeID, 0, 1, "bus", inputBus);
testRunning = 1;
},{
s.sendMsg("n_free", testNode);
testRunning = 0;
});
});

// comb frequencies
SCStaticText(wComb, Rect(10, 40, 100, 20)).string_("Comb Frequencies");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(10, 60 + (i * 25), 40, 20))
.value_(950);

SCStaticText(wComb, Rect(55, 60 + (i * 25), 15, 20)).string_("Hz");

SCSlider(wComb, Rect(80, 60 + (i * 25), 130, 20))
.value_(0.5)
.action_({|v| var time, freq;
freq = [1, 20000, 6].asSpec.map(v.value);
time = 1.0 / freq;
s.sendMsg("n_set", node, i, time);
box.value_(freq.asInteger);
})
};

// resonances
SCStaticText(wComb, Rect(250, 40, 100, 20)).string_("Resonances");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(250, 60 + (i * 25), 30, 20))
.value_(50);

SCStaticText(wComb, Rect(285, 60 + (i * 25), 15, 20)).string_("%");

SCSlider(wComb, Rect(300, 60 + (i * 25), 150, 20))
.value_(0.5)
.action_({|v|
s.sendMsg("n_set", node, i+5, [0, 9, 4].asSpec.map(v.value));
box.value_(v.value * 100);
});
};

// low pass frequencies
SCStaticText(wComb, Rect(555, 40, 100, 20)).string_("Low Pass Frequencies");
5.do{|i|
var box;

box = SCNumberBox(wComb, Rect(490, 60 + (i * 25), 40, 20)).value_(20000);
SCStaticText(wComb, Rect(535, 60 + (i * 25), 15, 20)).string_("Hz");

SCSlider(wComb, Rect(555, 60 + (i * 25), 150, 20))
.value_(1)
.action_({ |v| var freq;
freq = [20, 20000, \exp].asSpec.map(v.value);
s.sendMsg("n_set", node, i+10, freq);
box.value_(freq);
});
};

// volume control
SCStaticText(wComb, Rect(10, 190, 70, 20)).string_("Volume");
SCSlider(wComb, Rect(80, 190, 625, 20))
.value_(1)
.action_({|v| s.sendMsg("n_set", node, "vol", [0, 1, 4].asSpec.map(v.value))});
)

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.

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;

)







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.