Mandelbrot Player

The mandelbrot before audio playback commencesI’ve built on my previous Frequency Mandelbrot to add basic audio playback controls to it. It no longer starts automatically upon loading, you now have to press ‘P‘ on your keyboard to begin playback and there are a number of other hot keys for different playback options.

An audio file can be played, paused, rewound, and fast-forwarded. The left and right audio channels as well as beats and the overall volume are taken and used to colour a mandelbrot fractal. The left and right audio channels generate a series of lines that change speed and direction based on the audio peaks. The centre of the fractal has a constraint on it based on the beats, so as the amount of beats increase, it will freeze and stay still while the outer area of the fractal, which appears as a background continues to animate around it. And yes, it is meant to have the lines through it.

The keyboard controls for playback are:

Play: P
Pause: S
Fast-Forward: F
Rewind: R
Restart: H
Stop: Q

Mandelbrot during audio playbackA note on these playback options, at the moment, ‘Q‘ will actually close the link to the song file, so this should not be used unless it is needed. Attempting to start the song again with ‘P‘ after ‘Q‘ has been used will cause Processing to error. I haven’t gotten around this as of yet unfortunately.

To replay a song from the start, press ‘H‘ and this will return the play head to the start of the file.

Rewind ‘R‘ and fast forward ‘F‘ skip the track back and forward by 500 milliseconds, so ‘R‘ should be used in place of ‘H‘ if you don’t want to return to the start of the song.

The source code is a little bit different to previous versions as I have added a class for keyPressed to determine what to do if the control keys are pressed:


// Create the controls.
void keyPressed()
{
if ( key == 'p' ) song.play(); // Press P to play the song.
if ( key == 's' ) song.pause(); // Press S to pause playing.
if ( key == 'h' ) song.rewind(); // Press H to reset to the start.
if ( key == 'f' ) song.skip(500); // Press F to fast forward.
if ( key == 'r' ) song.skip(-500); // Press R to rewind.
if ( key == 'q' ) song.close(); // Press Q to quit playing.
}

It’s all fairly straight forward, the Minim library is very simple to use and there are some great tools in it that you can play with. I highly recommend it if you are working with audio in Processing.

You can have a look at it in action here. The song used in this piece is “Freedom (Waking Mix)” by vo1k1 2008 – Licensed under Creative Commons Attribution Noncommercial (3.0).

This is fairly CPU intensive, so many computers will have trouble running this, it is also about 9mb to load so you probably don’t want to try it on a low speed connection.

The full source code is available from the same page as the applet, or you can see it after the jump:


import ddf.minim.*;
import ddf.minim.analysis.*;

FFT fft;

AudioPlayer song;
BeatDetect beat;

float fSize;

void setup()
{
size(300, 300);

// Start Minim
Minim.start(this);

// Set the length of the sample buffers.
song = Minim.loadFile("freedom.mp3", 512);
// Uncomment song.play() to play the song as soon as the environment loads
//  song.play();
beat = new BeatDetect();

float fSize = 20;
// Tell the FFT the buffer size and sample rate.
fft = new FFT(song.bufferSize(), song.sampleRate());
}

// Create the controls.
void keyPressed()
{
if ( key == 'p' ) song.play(); // Press P to play the song.
if ( key == 's' ) song.pause(); // Press S to pause playing.
if ( key == 'h' ) song.rewind(); // Press H to reset to the start.
if ( key == 'f' ) song.skip(500); // Press F to fast forward.
if ( key == 'r' ) song.skip(-500); // Press R to rewind.
if ( key == 'q' ) song.close(); // Press Q to quit playing.
}

void draw()
{
background(0);
// Run a mix FFT
fft.forward(song.mix);
fill(255);

loadPixels();

// Maximum number of iterations for each point.
float maxiterations = 200; // Lower renders quicker
float xmin = -2.5;
float ymin = -2;
float wh = 2;

// Detect the beats in the song mix
beat.detect(song.mix);
// Iterate fSize based on beats.
if ( beat.isOnset() ) fSize += 0.1;

// Restrict fSize to create variation when the beat count gets too high.
fSize = constrain(fSize, -10, 10);

ymin = -1;
xmin = -1.5;

maxiterations = maxiterations + fSize;

// x goes from xmin to xmax
float xmax = xmin + wh;
// y goes from ymin to ymax
float ymax = ymin + wh;

// Calculate amount we increment x,y for each pixel
float dx = (xmax - xmin) / (width);
float dy = (ymax - ymin) / (height);

// Start y
float y = ymin;
for(int j = 0; j < height; j++) {
// Start x
float x = xmin;
for(int i = 0;  i < width; i++) {

float a = x;
float b = y;
int n = 0;

while (n < maxiterations) {
float aa = a * a;
float bb = b * b;
float twoab = 2.0 * a * b;
a = aa - bb + x;
b = twoab + y;
if(aa + bb > 16.0f) {
break;
}
n++;
}

// Colouring pixels using the left and right audio channels - song.right.get(i) etc.
if (n == maxiterations) pixels[i+j*width] = 0;
else pixels[i+j*width] = color(n*(song.right.get(i)*50) % 255, n*(song.left.get(i)*50) % 200, n*(song.right.get(i)*30));
x += dx;
}
y += dy;
}
updatePixels();
}

// End Minim after the song finishes playing.
void stop()
{
song.close();
super.stop();
}

Tags: , , , , , ,

Leave a Reply