AudioSource defines three AudioBuffer members as well implementing the Recordable and Effectable interfaces. You will never create an AudioSource directly, it exists merely to provide common functionality for the classes AudioPlayer, AudioSample, AudioOuput, and AudioInput.
Sample Buffers
The three sample buffers are named left, right, and mix. They are continually updated with the left channel, right channel. and mix of left and right channels of the audio source. All three buffers are available and contain values even if the associated audio is mono. In the case of a mono audio source all three buffers will contain exactly the same samples. Each sample buffer is an AudioBuffer object.
AudioBuffer: Get and Size
Two methods of AudioBuffer that you will use alot are get(int i) and size(). The size method returns the length of the buffer. The get method returns the float value of the ith sample in the buffer. This value will be in the range [-1, 1]. For this reason, it is often referred to as a normalized float sample. A sample is a measurement of the amplitude of the audio source at a particular moment in time. To be able to hear a sound, the amplitude must vary over time. The simplest kind of variance is a square wave, which alternates between equal numbers of samples having the value -1 and 1. So, ten samples equal to -1 and then ten samples equal to 1 and then ten samples equal to -1 and so on. However, recorded audio is always much more complex than this. The get method doesn’t do any bounds checking. So if you ask for a sample at a position less than 0 or ask for a sample at a position greater than or equal to the value returned by size you will get an ArrayOutOfBounds exception. The following example shows how to use get and size to draw the waveform of an audio signal.
Code Sample (view online)
/** * This sketch is an example of how to use the <code>get</code> method of an <code>AudioBuffer</code> to get the * value of a sample in one of an <code>AudioSource</code>'s sample buffers. The classes in Minim that extend <code>AudioSource</code> * and therefore inherit the <code>left</code>, <code>right</code>, and <code>mix</code> buffers of that class, are * <code>AudioInput</code>, <code>AudioOutput</code>, <code>AudioSample</code>, and <code>AudioPlayer</code>. * Not coincidentally, these are also all of the classes in Minim that are <code>Recordable</code>. * <p> * The value returned by <code>get</code> will always be between -1 and 1, unless you are using an <code>AudioOutput</code> * whose signals mix together to produce sample values outside of this range. If that is the case you will notice * it right away because the audio will sound distorted. You can use <code>get</code> to draw the waveform of the * audio in an <code>AudioBuffer</code>, but it is not the best choice for doing so. See the toArray example for more * about this. */ import ddf.minim.*; Minim minim; AudioPlayer groove; void setup() { size(512, 200, P3D); minim = new Minim(this); groove = minim.loadFile("groove.mp3"); groove.loop(); } void draw() { background(0); stroke(255); // we multiply the values returned by get by 50 so we can see the waveform for ( int i = 0; i < groove.bufferSize() - 1; i++ ) { float x1 = map(i, 0, groove.bufferSize(), 0, width); float x2 = map(i+1, 0, groove.bufferSize(), 0, width); line(x1, height/4 - groove.left.get(i)*50, x2, height/4 - groove.left.get(i+1)*50); line(x1, 3*height/4 - groove.right.get(i)*50, x2, 3*height/4 - groove.right.get(i+1)*50); } } void stop() { // always close Minim audio classes when you finish with them groove.close(); // always stop Minim before exiting minim.stop(); super.stop(); }
AudioBuffer: Level
The level method of an AudioBuffer returns the current “volume” level of the buffer. This value will always be between zero and one, but you may find that the value returned is often smaller than you expect. The level is found by calculating the root-mean-squared amplitude of the samples in the buffer. First the samples are all squared, then the average (mean) of all the samples is taken (sum and then divide by the number of samples), then the square root of the average is returned. This is why the range can be determined as [0, 1] because the largest value a squared sample can have is 1. However, in order for the RMS amplitude to equal 1, every sample must have either -1 or 1 as its value (amplitude). This is only going to be the case if your sound is a square wave at full amplitude. If your sound is a song or other complex sound source, the level is generally going to be much lower.
Code Sample (view online)
/** * This sketch is an example of how to use the <code>level</code> method of an <code>AudioBuffer</code> to get the * level of one of an <code>AudioSource</code>'s sample buffers. The classes in Minim that extend <code>AudioSource</code> * and therefore inherit the <code>left</code>, <code>right</code>, and <code>mix</code> buffers of that class, are * <code>AudioInput</code>, <code>AudioOutput</code>, <code>AudioSample</code>, and <code>AudioPlayer</code>. * Not coincidentally, these are also all of the classes in Minim that are <code>Recordable</code>. * <p> * The value returned by <code>level</code> will always be between zero and one, but you may find that the value * returned is often smaller than you expect. The level is found by calculating the root-mean-squared amplitude of the * samples in the buffer. First the samples are all squared, then the average (mean) of all the samples is taken (sum * and then divide by the number of samples), then the square root of the average is returned. This is why the range can be * determined as [0, 1] because the largest value a squared sample can have is 1. However, in order for the RMS amplitude * to equal 1, every sample must have either -1 or 1 as its value (amplitude). This is only going to be the case * if your sound is a square wave at full amplitude. If your sound is a song or other complex sound source, * the level is generally going to be much lower. */ import ddf.minim.*; import ddf.minim.signals.*; Minim minim; AudioPlayer groove; void setup() { size(200, 200, P3D); minim = new Minim(this); groove = minim.loadFile("groove.mp3"); groove.loop(); rectMode(CORNERS); } void draw() { background(0); fill(255); // draw the current level of the left and right sample buffers // level() returns a value between 0 and 1, so we scale it up rect(0, height, width/2, height - groove.left.level()*1000); rect(width/2, height, width, height - groove.right.level()*1000); } void stop() { // always close Minim audio classes when you finish with them groove.close(); // always stop Minim before exiting minim.stop(); super.stop(); }
AudioBuffer: toArray
The fourth and final method available on an AudioBuffer is toArray(). This method returns a copy of the values in the buffer in a float array. The float array returned by toArray will always be the same length as the buffer’s size. The values in the array will always be between -1 and 1, unless you are using an AudioOutput whose signals mix together to produce sample values outside of this range. If that is the case you will notice it right away because the audio will sound distorted. You can use toArray to draw the waveform of the audio in an AudioBuffer and it is the preferred method for doing so. The reason for this is due to threading. The actual audio I/O happens in its own thread and calls back into the main thread (your sketch) when it has a new buffer of samples. Because of this, when using get to draw the waveform, it is possible (in fact highly likely) that the samples in the buffer will be changed while you are in the middle of drawing the waveform, which will result in a waveform that seems to have discontinuities. When you use toArray you are given a copy of the current contents of the buffer and it is guaranteed, thanks to synchronization, that the entire array is created without the samples changing in the process.
Code Sample (view online)
/** * This sketch is an example of how to use the <code>toArray</code> method of an <code>AudioBuffer</code> to get a * copy of all the samples in one of an <code>AudioSource</code>'s sample buffers. The classes in Minim that extend <code>AudioSource</code> * and therefore inherit the <code>left</code>, <code>right</code>, and <code>mix</code> buffers of that class, are * <code>AudioInput</code>, <code>AudioOutput</code>, <code>AudioSample</code>, and <code>AudioPlayer</code>. * Not coincidentally, these are also all of the classes in Minim that are <code>Recordable</code>. * <p> * The float array returned by <code>toArray</code> will always be the same length as the buffer's size. The values in * the array will always be between -1 and 1, unless you are using an <code>AudioOutput</code> * whose signals mix together to produce sample values outside of this range. If that is the case you will notice * it right away because the audio will sound distorted. You can use <code>toArray</code> to draw the waveform of the * audio in an <code>AudioBuffer</code> and it is the preferred method for doing so. The reason for this is due to * threading. The actual audio I/O happens in its own thread and calls back into the main thread (your sketch) when it * has a new buffer of samples. Because of this, when using <code>get</code> to draw the waveform, it is possible * (in fact highly likely) that the samples in the buffer will be changed while you are in the middle of drawing the * waveform, which will result in a waveform that seems to have discontinuities. When you use <code>toArray</code> you * are given a copy of the current contents of the buffer and it is guaranteed, thanks to synchronization, that * the entire array is created without the samples changing in the process. */ import ddf.minim.*; Minim minim; AudioPlayer groove; void setup() { size(512, 200, P3D); minim = new Minim(this); groove = minim.loadFile("groove.mp3"); groove.loop(); } void draw() { background(0); stroke(255); float[] left = groove.left.toArray(); float[] right = groove.right.toArray(); // we only loop to left.length - 1 because we are accessing index i+1 in the loop for ( int i = 0; i < left.length - 1; i++ ) { float x1 = map(i, 0, groove.bufferSize(), 0, width); float x2 = map(i+1, 0, groove.bufferSize(), 0, width); // we multiply the values returned by get by 50 so we can see the waveform line(x1, height/4 - left[i]*50, x2, height/4 - left[i+1]*50); line(x1, 3*height/4 - right[i]*50, x2, 3*height/4 - right[i+1]*50); } } void stop() { // always close Minim audio classes when you finish with them groove.close(); // always stop Minim before exiting minim.stop(); super.stop(); }
Closing An AudioSource
As with all audio I/O classes in Minim, you should call the close method when you are finished using the object. This allows the thread managing playback/monitoring to finish properly and frees resources used by that thread. You can choose to close an audio source somewhere other than in the stop method, like if you wanted to assign a new player to groove you’d need to call close before assigning a new player. If you didn’t do this, the thread for the original player would continue executing and you’d have no way to stop it.
Other Methods
AudioSource derives from Controller and as such has all of its methods available, which are described in the section about Controller. As mentioned above, it also implements Recordable and Effectable, meaning that it and the four classes that derive from it have those methods available. Please see the Recordable section and Effectable section for details about those methods.
-
Pingback from There is light!! | A Dreamer of the Day on January 24, 2010 at 11:55 am

1 comment
Comments feed for this article
Trackback link: http://code.compartmental.net/tools/minim/manual-audiosource/trackback/