Endlessly repeating...
25 February 2012
A jam I recorded last night using the Machinedrum, Monomachine, modular and Mono Evolver. Percussion's all from the Machinedrum, the drone running throughout is from the Mono Evolver (which did this so well that I've pretty much fully reconsidered selling it), the lead (such as it is) is from the modular and the Monoevolver's on bass.
24th Feb jam
29 September 2011
More playing helper monkey from me. This time it was constructing a system of detectors to conjure up a space just from sound. Laura Tarjuman - whose project this is - made a video of the results. Technically this was pretty simple (most of the coding was done in about four hours) but it's an excellent demonstration of just how easy Processing and Arduino have made integrating software and hardware (a webcam and IR rangers in this case). It's a good time to be a hacker.
19 July 2011
It's been hell of quite around here recently so I figure I'd put in a quick post covering what I've been up to for the past couple of months (not blogging obviously). The main thing was a Reactable and Processing with Vanessa McKeown, a student at Chelsea College of Art & Design. There's a whole heap of information about that Vanessa's project blog. The main thing I learnt on this is that debugging problems relating to the detection properties of the Reactable (i.e. detected markers jittering and so on) is really time consuming and coping tactics need to be built into the software early on. We didn't do this and it caused a lot of bother as the deadline approached. If you're building a Reactable yourself, get it working a long way before your deadline.
More recently I've been helping out with Dimitris Mylonas' online colour naming system. I've learnt a lot about AJAX in the course of that, which is bound to come in handy for anything else I end up doing that's online and interactive in anything more than a superficial way. It was also good to apply Numpy to something new - so much better than Matlab. That project got a brief mention in The Economist.
17 February 2011
A lot of my ideas involve generating musical information (notes, triggers, continuous control data) in one language (I'll refer to this as the controller for convenience) and then passing that to SuperCollider to make some noise with. That approach raises the question of where to put the intelligence in that system. Either the controller processes everything into musical information and SuperCollider acts as a 'dumb' synth or the controller can send a load of numbers without semantic meaning to SuperCollider which can then figure out what to do with them. To my mind, a logical way to choose which system to use is to look at whether you want to change the controller setup or the SuperCollider setup more often. If you're changing the SuperCollider setup frequently then doing more processing at that end makes sense as it reduces the need for the controller to know about the synth architecture. In my case, I'm writing a lot more controllers at the moment so I've put the more of the note generation logic at that end. This means I can swap controllers easily without having to fiddle with the SuperCollider code.
To assist with all that, the following OSC responder code offers a useful amount of flexibility. It takes an OSC message, interprets the first string as the name of a synth to be instantiated and then adds the subsequent pairs of strings and numbers as parameters to that synth. What you can't do easily with this method is subsequently control the created synths so make sure that they free themselves (doneAction:2 in an EnvGen for example) unless you want a huge pileup.
o = OSCresponder(nil, "/controller", {
arg t, r, msg;
var synthName, synthArgs;
// first argument is the synth name
synthName = msg[1].asSymbol;
// remove the first two elements of OSC message, these contain
// the path and synth name
1.do({|i| msg.removeAt(i)});
// create a new array to hold the synth arguments
synthArgs = Array.new(msg.size);
// for the remaining elements of the OSC message go through and convert the first
// of every pair to be a control name and add the second as the control data
msg.do({
arg item, i;
if(i.even, {synthArgs.add(item.asSymbol)}, {synthArgs.add(item)});
});
// create the new synth
Synth.new(synthName, synthArgs);
}).add;
16 February 2011
I made the switch from TextMate to MacVim about a month ago now and unlike my previous attempts to switch to Vim the change seems to have stuck this time. Of course once you find an editor you like there's a desire to use it for everything you can and that meant getting scvim working. Here's how it's done...
- Download a copy of the SuperCollider source from the SourceForge page
- Open up Terminal and
cd to supercollider_source/editors/scvim
- The manual install instructions in the scvim readme are good so have a quick read of that
- Copy the executables from the bin directory to /usr/local/bin
- Copy the ftplugin, syntax and indent directories to ~/.vim. If you're using Pathogen (and I'd recommend that you do) then create an scvim directory in ~/.vim/bundle and move the aforementioned directories there instead
- Copy the scclasses directory to ~/Library/Application Support/SuperCollider/Extensions. At this point I renamed the scclasses directory to something less generic but you don't have to
cd to /usr/local/bin and run ln -s /Applications/SuperCollider/sclang sclang
- To generate the help files you'll need to install links and unrtf, the easiest way to do this is through MacPorts
- After you've got links and unrtf, run
scvim_make_help -l -c -s /Applications/SuperCollider/Help
- scvim makes a lot of use of the function keys so quickly have a look at the keyboard options in system preferences and make sure that the option about using F1, F2, etc as standard function keys is set
- Next step is to edit .scvimrc so open that up in (presumably if you're reading this) vim
- Uncomment lines 33 and 34 (
let g:sclangTerm = "open -a /Applications/Utilities/Terminal.app" and the subsequent line)
- Save your changes to .scvimrc
- Enter
:source ~/.scvimrc in vim
- Open a new file in vim called test.sc. The important bit is the .sc extension, this will prompt vim to load the SuperCollider commands
- Enter
:SClangStart in vim, hopefully a terminal window will come up showing the usual SuperCollider post window stuff
- At this point you should be able to run SuperCollider commands as normal. Try entering
s = Server.local.boot and hitting F6, hopefully the server will boot.
- You can review the rest of the shortcuts that scvim adds by having a look at ~/.scvim
26 January 2011
I've just finished uploading a new ugen for SuperCollider called DFM1. It's a port of Tony Hardie-Bick's DFM1 filter, which is a great sounding, overdrivable, self-oscillatable, incredibly detailed model of an analog filter. Full source code is available, so if you've got an interest in DSP coding it'd be an excellent example. If you just want to make some strange noise it's pretty damn good for that as well. You can download DFM1 from here.
20 January 2011
Via @mclduk I've finally found a tutorial for TempoClocks in SuperCollider that I can get my head around. To celebrate and to help me remember it, here's a very quick example of some livecoding...
First we need a synth:
SynthDef(\beep, {
arg freq = 440;
var sig;
sig = SinOsc.ar(freq, mul:0.2);
sig = sig * EnvGen.kr(Env.perc(0.1, 0.5), doneAction:2);
Out.ar(0, sig);
}).send(s);
I'm not going to bother explaining all of that because it's out of the scope of the tutorial, suffice to say it makes a short beeping sound and then frees itself.
The idea of this method of livecoding is to use a TempoClock to call a function every beat. The function can be modified while the clock is running and so we have livecoding. The first thing we need is an empty function:
a = {}
Exciting eh? Next we need a TempoClock:
c = TempoClock(2)
The argument is the clock's rate, in this case 120bpm (the argument is beats per second, 2 * 60 = 120). Next thing is to tell the clock to call our empty function every beat:
c.schedAbs(
0, //evaluate this immediately
{
arg ...args;
arg[0].postln; // arg[0] is the beat number
a.value(args[0]); // pass the beat number to our function
1.0 // do it all again on the next beat
}
);
If you evaluate that you should see a number counting up in the post window.
The next step is to make our function do something:
a = {Synth(\beep)};
Evaluate that and you should hear a beep every half a second. Congratulations, you just livecoded!
a = {Synth(\beep, [freq, 480])};
Yeah, ok that's not all that exciting but it was a breakthrough for me. It'd be nice if we could do something at a different interval than every beat. Fortunately, we're passing the beat number to our function.
a = {
arg beat;
// if beat number is even play a high note
if(beat % 2 == 0, {Synth(\beep, [\freq, 440])});
// play a low note every beat
Synth(\beep, [\freq, 219]);
}
I'm not going to get into the modulo operation but suffice to say it's hugely useful for subdividing counters like this. You can also access external data in our function:
~notes = [50, 52, 56];
a = {Synth(\beep, [\freq, ~notes.choose.midicps])};
The contents of ~notes can be changed on the go as well. None of this is particularly groundbreaking but if you've never played around with this stuff it'll hopefully get you from sitting to crawling.
7 December 2010
Solving this problem has been bugging me on and off for ages now so I thought I'd share the solution I eventually came up with. First, the problem: how to do on-the-fly looping of audio in SuperCollider in sync with a sequencer? In this case the sequencer is going to be a very simple example in Processing but the method will work with a hardware drum machine as well.
The trick I settled on is to think like an old hardware loop pedal. In other words, set up the looper with more capacity that you think you're going to need and then do the recording into some part of that space. The record 'head' (to borrow some old tape terminology) is positioned using a phasor that, left alone, runs from the start of the recording area to the end. An OSC responder (or MIDI responder or whatever your sequencer speaks) is set up that causes the phasor to jump back to zero when it's triggered. If you send the trigger at the end of your sequenced loop you get synchronised looping. Overdubbing on to the loop is a simple matter of making sure that the contents of the buffer is read before the new material is added on each pass.
This is, in a way, a bit of a dumb approach and I'm kind of embarrassed about how long it took me. The obvious problem is that you need to make a buffer longer than you're ever going to need and "ever" is always a bit hard to define. Also, having huge under-utilised chunks of memory isn't exactly efficient but in, in practice, a 60 second loop only takes up ~2.5MB so it's not going to bring a modern laptop to it's knees even with a few instances going. Anyway, I hope this helps someone.
First the SuperCollider code:
// definition of the looper
SynthDef(\looper, {
// need a buffer to listen to and an input for the loop trigger
arg bufnum, t_reset;
// variables for the existing signal in the loop, the new input,
// the output signal and the recording head position
var inputSig, outputSig, existingSig, recHead;
// get the input signal
inputSig = In.ar(0);
// generate the recording (also playback) position
recHead = Phasor.ar(t_reset, BufRateScale.kr(bufnum), 0, BufFrames.kr(0));
// read the existing signal from the loop
existingSig = BufRd.ar(1, bufnum, recHead);
// put the existing signal plus the new signal into the loop
BufWr.ar(inputSig + existingSig, bufnum, recHead);
// play back signal we got from the loop before the writing operation
Out.ar(0, existingSig);
}).add;
// a crappy instrument to test with
SynthDef(\ping, {
arg freq;
var sig;
sig = SinOsc.ar(freq) * 0.5;
sig = EnvGen.kr(Env.perc(0.05, 2), doneAction:2) * sig;
Out.ar(0, sig);
}).add;
// create a big empty buffer (20 secs is enough for me)
b = Buffer.alloc(s, 20 * s.sampleRate, 1)
// listen for a an OSC message indicating that we've reached the loop point
p = OSCresponderNode(nil, '/newbar', {|t, r, msg| ~looper.set(\t_reset, 1)}).add;
// listen for OSC triggering the test instrument
o = OSCresponderNode(nil, '/newnote', {
|t, r, msg| msg[1].postln; Synth.new(\ping, [\freq, msg[1].midicps])
}).add;
// create an instance of the looper
~looper = Synth.new(\looper, [\bufnum, b.bufnum])
Now the Processing:
// import the OSC libraries (see http://www.sojamo.de/libraries/oscP5/)
import oscP5.*;
import netP5.*;
// the OSC handler and target address
OscP5 oscP5;
NetAddress remote;
// where in the bar are we
int beatCount;
// lock to a scale so the test instrument sounds a bit nicer
int[] cMinor = {48, 50, 52, 53, 55, 57, 59, 60, 62, 64, 65, 67, 69};
void setup() {
size(260, 200);
frameRate(30);
// draw a keyboard to test with
for(int i = 1; i <= 12; i++) {
line(20 * i, 0, 20 * i, 100);
}
// instantiate the OSC handler
oscP5 = new OscP5(this, 10000);
// Supercollider is assumed to be listening on
// localhost at the default sclang port
remote = new NetAddress("127.0.0.1", 57120);
}
void draw() {
// pulse in time with beat
fill(255 / ((frameCount % 15) + 1));
rect(10, 110, 40, 40);
// one beat every 15 frames
if(frameCount % 15 == 0) {
beatCount++;
}
// at the end of the 16 beat bar, trigger the loop back to the beginning
if(beatCount == 16) {
OscMessage msg = new OscMessage("/newbar");
oscP5.send(msg, remote);
beatCount = 0;
}
// pulse in time with the bar
fill(255 / (beatCount + 1));
rect(60, 110, 40, 40);
}
// use the mouse to play the test instrument
void mousePressed() {
int noteNum = int(mouseX / 20);
OscMessage msg = new OscMessage("/newnote");
msg.add(cMinor[noteNum]);
oscP5.send(msg, remote);
}
7 December 2010
After the backward lookinginess of the last three posts I thought a bit of new music might be nice. I picked up an Elektron Monomachine at the weekend and this is the result of the first proper play I've had with it:
First Monomachine jam
It's a very easy fit with the Machinedrum (unsurprisingly). I haven't quite figured out how to fit it in with the rest of my existing live setup. I'm very keen to keep using open-source software in there somewhere so I may have to get into using Supercollider more for effects processing and textures.
7 December 2010
The great link dump concludes (probably, I might put up some of stuff from collaborations at a later date) with the EP I put together in 2006:
- Resignation
- Backward Rough
- Smoky
- Sinewaves
- We Make My Doubts
For convenience, the whole thing's also available in a .zip file.