September 3, 2004

Live Music Hacking

In Perl, no less!

This may be the coolest example of hacking that I've seen all week. He uses a very simple framework that lets him edit, in realtime, a program that algorithmically drives a sound synthesis server (SuperCollider here).

Before I read the article, I had some trouble visualizing how this would likely work. After all, I don't generally write programs that, after a few lines of coding, work at a basic level, and then do something more complex. Instead, after a few lines of coding, my programs don't do anything yet, and later there comes a kind of keystone-insertion point where the thing stands on its own, and does something resembling its final function.

This fellow's trick is to set up a framework that keeps him constantly at that tipping point between no-function and function, and what's more, able to continually reprogram, on stage no less, the shape of that last core piece.

So there's a framework; it's somewhat elaborate. There's a time server that can even keep multiple instances in synch, like a network metronome. There are some helper functions that mediate his connection to the audio equipment. And finally, there's -- sort of like an old-style LISP environment for Perl, he edits the inner event handler (which is, wonderfully, a continually re-evaluated data structure that is often, as a result, self-modifying) that dispatches events. An example is apropos:

Once everything is ready, run and type this little script in:

  # 231
  sub bang {
      my $self = shift;
      $self->code->[0] = '# ' . $self->{bangs};

Press ctrl-x and it will start to run. $self->{bangs} contains the number of bangs since the script was started, and this is written to the first line of the code (make sure that line doesn't have anything important in it). Calling $self->modified tells the editor that the code has changed, causing it to refresh the screen with the changes.

OK, lets make some sounds.

  sub bang {
      my $self = shift;
      my $note = 100;
      $note += 50 if $self->{bangs} % 4 == 0;  
      $note -= 30 if $self->{bangs} % 3 == 0;  
      $note += 60 if $self->{bangs} % 7 == 0;
      beep($note, 40);
      $self->code->[0] = '# note: ' . $note;

Hopefully this should play a bassline through your speaker. beep() is a routine imported from Audio::Beep; you just pass it a frequency in Hz and a duration in milliseconds.

Posted by mill1974 at September 3, 2004 4:10 PM