Setup and Shutdown
To start using Minim you must first instatiate a Minim object, which you can then use to load audio files or acquire inputs and outputs. Then, before your program exits, you must close any audio I/O classes you get from Minim and then stop your Minim instance. Audio I/O classes include AudioPlayer, AudioSample, AudioSnippet, AudioInput, and AudioOutput. A good way to ensure this happens is to define a stop method in your sketch where you close all audio classes. Here’s a partial program that demonstrates these things:
Minim minim; AudioPlayer player; AudioInput input; void setup() { size(100, 100); minim = new Minim(this); player = minim.loadFile("song.mp3"); input = minim.getLineIn(); } void draw() { // do what you do } void stop() { // the AudioPlayer you got from Minim.loadFile() player.close(); // the AudioInput you got from Minim.getLineIn() input.close(); minim.stop(); // this calls the stop method that // you are overriding by defining your own // it must be called so that your application // can do all the cleanup it would normally do super.stop(); }
Users of Ess and Sonia should be familiar with these conventions. The reason for doing all of this is because all of the audio I/O is handled in separate threads and they must be allowed to finish in a normal fashion. You might also close an audio class during execution of your program in order to free the resources it has.
Playing A File
One of the main motivaters behind writing Minim was that neither of the available libraries for Processing allowed stereo playback of audio files. Minim to the rescue! It is incredibly easy to play a file using Minim. Just put the file into the data folder of your sketch and then use this code:
import ddf.minim.*; Minim minim; AudioPlayer song; void setup() { size(100, 100); minim = new Minim(this); // this loads mysong.wav from the data folder song = minim.loadFile("mysong.wav"); song.play(); } void draw() { background(0); } void stop() { song.close(); minim.stop(); super.stop(); }
Minim can play all of the typical uncompressed file formats such a WAV, AIFF, and AU. It can also play MP3 files thanks to the inclusion of Javazoom’s MP3SPI package with the distribution.
Retrieving MetaData
Metadata is information about a file, as opposed to the actual contents of the file. You can get the metadata of a file after you have loaded it into an AudioPlayer. The most likely reason you will want to do this is to display ID3 tag information. Here’s a short sketch that does exactly that:
import ddf.minim.*; Minim minim; AudioPlayer groove; AudioMetaData meta; void setup() { size(512, 256, P3D); minim = new Minim(this); // groove.mp3 would be in the sketches data folder groove = minim.loadFile("groove.mp3"); meta = groove.getMetaData(); // serif.vlw would be in the data folder, most likely created using the PDE textFont( loadFont("serif.vlw") ); textMode(SCREEN); } int ys = 15; int yi = 15; void draw() { background(0); int y = ys; text("File Name: " + meta.fileName(), 5, y); text("Length (in milliseconds): " + meta.length(), 5, y+=yi); text("Title: " + meta.title(), 5, y+=yi); text("Author: " + meta.author(), 5, y+=yi); text("Album: " + meta.album(), 5, y+=yi); text("Date: " + meta.date(), 5, y+=yi); text("Comment: " + meta.comment(), 5, y+=yi); text("Track: " + meta.track(), 5, y+=yi); text("Genre: " + meta.genre(), 5, y+=yi); text("Copyright: " + meta.copyright(), 5, y+=yi); text("Disc: " + meta.disc(), 5, y+=yi); text("Composer: " + meta.composer(), 5, y+=yi); text("Orchestra: " + meta.orchestra(), 5, y+=yi); text("Publisher: " + meta.publisher(), 5, y+=yi); text("Encoded: " + meta.encoded(), 5, y+=yi); } void stop() { // always close Minim audio classes when you are done with them groove.close(); // always stop Minim before exiting minim.stop(); super.stop(); }
Drawing A Waveform
Something else you might want to do is to draw the waveform of the sound you are playing. All of the classes in Minim that handle input and output of audio data (with the exception of AudioSnippet) derive from a class called AudioSource. This class defines three AudioBuffer members that are then inherited by classes that extend AudioSource. AudioPlayer is just such a class, so you can access these buffers with an AudioPlayer object. The buffers are named left, right, and mix. They contain the left channel, the right channel, and the mix of the left and right channels, respectively. Even if the audio you are playing is mono, all three buffers will be available and return values. When you are playing a mono file you will simply find that all three buffers contain the same information. So, let’s draw a waveform. We can redefine the draw function from up above like this:
void draw() { background(0); stroke(255); // we draw the waveform by connecting neighbor values with a line // we multiply each of the values by 50 // because the values in the buffers are normalized // this means that they have values between -1 and 1. // If we don't scale them up our waveform // will look more or less like a straight line. for(int i = 0; i < song.bufferSize() - 1; i++) { line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50); line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50); } }
This drawing code will work regardless of what kind of input or output class song is because they all extend AudioSource, which provides the buffers. There are two problems with the code we have so far, the window size is set to 100×100 up in setup and we have no idea how long the buffers are (i.e. what number song.bufferSize() returns). The first problem is easy enough to fix, we can set the window dimensions to 512×200. The second problem we can fix by including the buffer length we want in the call to loadFile. Now setup should look like this:
void setup() { size(512, 200); minim = new Minim(this); // specify 512 for the length of the sample buffers // the default buffer size is 1024 song = minim.loadFile("mysong.wav", 512); song.play(); }
This ensures that we have the same number of values in the buffer as we have screen real-estate to display them. If you don’t provide a value for the buffer size, the buffers will be 1024 samples long.
Drawing a Frequency Spectrum
Something else you might be interested in doing is analyzing your song while it plays and drawing the frequency spectrum. You can do this by using an FFT object. If we include an FFT object in our program and draw the spectrum a little faded out behind the waveform, our program will look like this:
import ddf.minim.*; import ddf.minim.analysis.*; Minim minim; AudioPlayer song; FFT fft; void setup() { size(512, 200); // always start Minim first! minim = new Minim(this); // specify 512 for the length of the sample buffers // the default buffer size is 1024 song = minim.loadFile("mysong.wav", 512); song.play(); // an FFT needs to know how // long the audio buffers it will be analyzing are // and also needs to know // the sample rate of the audio it is analyzing fft = new FFT(song.bufferSize(), song.sampleRate()); } void draw() { background(0); // first perform a forward fft on one of song's buffers // I'm using the mix buffer // but you can use any one you like fft.forward(song.mix); stroke(255, 0, 0, 128); // draw the spectrum as a series of vertical lines // I multiple the value of getBand by 4 // so that we can see the lines better for(int i = 0; i < fft.specSize(); i++) { line(i, height, i, height - fft.getBand(i)*4); } stroke(255); // I draw the waveform by connecting // neighbor values with a line. I multiply // each of the values by 50 // because the values in the buffers are normalized // this means that they have values between -1 and 1. // If we don't scale them up our waveform // will look more or less like a straight line. for(int i = 0; i < song.left.size() - 1; i++) { line(i, 50 + song.left.get(i)*50, i+1, 50 + song.left.get(i+1)*50); line(i, 150 + song.right.get(i)*50, i+1, 150 + song.right.get(i+1)*50); } } void stop() { song.close(); minim.stop(); super.stop(); }
Synthesizing Sound
Finally, just a quick introduction to the oscillator and filter classes available in Minim. The first thing you need to do to play synthesized sound is get an AudioOutput. You do this by asking Minim for one:
AudioOutput out = minim.getLineOut();
Calling getLineOut with no arguments will return a stereo line out with a buffer size of 1024 samples that plays 16 bit audio at a 44100 Hz sample rate. It’s mostly those first two things you want to worry about. If you want a mono line out or a different buffer size, you can call getLineOut like this:
AudioOutput out = minim.getLineOut(Minim.MONO);
OR
AudioOutput out = minim.getLineOut(Minim.STEREO, 512);
where 512 is the length you want the buffers to be. Once you have an AudioOutput, you can attach AudioSignals and AudioEffects to it. Minim comes with quite a few of both. So let’s attach a SquareWave to our AudioOutput and also a LowPassSP filter:
import ddf.minim.*; import ddf.minim.signals.*; import ddf.minim.effects.*; Minim minim; AudioOutput out; SquareWave square; LowPassSP lowpass; void setup() { size(512, 200); minim = new Minim(this); // get a stereo line out with a sample buffer of 512 samples out = minim.getLineOut(Minim.STEREO, 512); // create a SquareWave with a frequency of 440 Hz, // an amplitude of 1 and the same sample rate as out square = new SquareWave(440, 1, 44100); // create a LowPassSP filter with a cutoff frequency of 200 Hz // that expects audio with the same sample rate as out lowpass = new LowPassSP(200, 44100); // now we can attach the square wave and the filter to our output out.addSignal(square); out.addEffect(lowpass); } void draw() { // you might decide to draw the waveform here or do something else } // here we provide a way to mute out // because, let's face it, it's not a very pleasant sound void keyPressed() { if ( key == 'm' ) { if ( out.isMuted() ) { out.unmute(); } else { out.mute(); } } } void stop() { out.close(); minim.stop(); super.stop(); }
That’s it for the Quickstart Guide! I haven’t covered absolutely everything you can do with Minim, but I have touched on some of the main features. You can read the Javadoc to find out about the full API, or continue on to the manual, which provides a more thorough description of Minim than this guide. Additionally, you can browse the online examples, which demonstrate all of the features on Minim in one way or another. All of the online examples are included in the full distrubution of Minim and can be found in File > Examples > minim of the PDE. If you have any questions, or find any bugs, you can contact me through my website, or through the Processing forum.
Pingback: Code Log » Blog Archive » Minim: An Audio Library for Processing
Pingback: Playing Audio in Processing | matthewbrown.net.au
Pingback: Using The Output of Minim in Processing | matthewbrown.net.au
hello,
this minim library is kinda useful .is there any chance i can get it to run on windows operated Pc?
Yes, it is a Java library designed to work with Processing, so you should make sure you have Java installed on your Windows machine and then download Processing. Minim is included in the Processing download.
is there a way for me to tie the object that takes the line in and output it to the object that takes the line out so i can take with the mic and display it
If all you want to do is display the waveform from the mic, you can use the buffers provided by the AudioInput object itself, which you get to with left(), right(), and mix(). They work exactly the same way as the ones on AudioOutput.
this library is Amazing !
Thanks!
love it! thanks
Hi
Great lib…will it work with iProcessing on the iphone?
you rock!!! many, many thanks for your work.
@David There is no such thing as iProcessing for the iPhone. Also, iPhones don’t run Java. So, no, can’t use this on the iPhone.
Pingback: Obsessing over Processing | BlueAnt Digital Intelligence
Pingback: Obsessing over Processing |
Pingback: Sonido con Lenguaje de Programación Processing. Primer ejemplo. « Mosaic
Pingback: Sonido con Lenguaje de Programación Processing. Segundo ejemplo. « Mosaic
Pingback: Fourier Analyse | Informatik für Musik, Medien & Film