New Minim for 2.0

This commit is contained in:
Casey Reas
2012-09-17 18:07:38 +00:00
parent 9f38058e52
commit 057447c68b
30 changed files with 1625 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
/**
* This sketch demonstrates how to use an FFT to analyze
* the audio being generated by an AudioPlayer.
* <p>
* FFT stands for Fast Fourier Transform, which is a
* method of analyzing audio that allows you to visualize
* the frequency content of a signal. You've seen
* visualizations like this before in music players
* and car stereos.
*/
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
AudioPlayer jingle;
FFT fft;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// specify that we want the audio buffers of the AudioPlayer
// to be 1024 samples long because our FFT needs to have
// a power-of-two buffer size and this is a good size.
jingle = minim.loadFile("jingle.mp3", 1024);
// loop the file indefinitely
jingle.loop();
// create an FFT object that has a time-domain buffer
// the same size as jingle's sample buffer
// note that this needs to be a power of two
// and that it means the size of the spectrum will be half as large.
fft = new FFT( jingle.bufferSize(), jingle.sampleRate() );
}
void draw()
{
background(0);
stroke(255);
// perform a forward FFT on the samples in jingle's mix buffer,
// which contains the mix of both the left and right channels of the file
fft.forward( jingle.mix );
for(int i = 0; i < fft.specSize(); i++)
{
// draw the line for frequency band i, scaling it up a bit so we can see it
line( i, height, i, height - fft.getBand(i)*8 );
}
}

View File

@@ -0,0 +1,65 @@
/**
* Get Meta Data
* by Damien Di Fede.
*
* This sketch demonstrates how to use the <code>getMetaData</code>
* method of <code>AudioPlayer</code>. This method is also available
* for <code>AudioSnippet</code> and <code>AudioSample</code>.
* You should use this method when you want to retrieve metadata
* about a file that you have loaded, like ID3 tags from an mp3 file.
* If you load WAV file or other non-tagged file, most of the metadata
* will be empty, but you will still have information like the filename
* and the length.
*/
import ddf.minim.*;
Minim minim;
AudioPlayer groove;
AudioMetaData meta;
void setup()
{
size(512, 256, P2D);
minim = new Minim(this);
groove = minim.loadFile("groove.mp3");
meta = groove.getMetaData();
textFont(createFont("Serif", 12));
}
int ys = 25;
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();
}

View File

@@ -0,0 +1,41 @@
/**
* This sketch demonstrates how to monitor the currently active audio input
* of the computer using an <code>AudioInput</code>. What you will actually
* be monitoring depends on the current settings of the machine the sketch is running on.
* Typically, you will be monitoring the built-in microphone, but if running on a desktop
* its feasible that the user may have the actual audio output of the computer
* as the active audio input, or something else entirely.
* <p>
* When you run your sketch as an applet you will need to sign it in order to get an input.
*/
import ddf.minim.*;
Minim minim;
AudioInput in;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// use the getLineIn method of the Minim object to get an AudioInput
in = minim.getLineIn();
// uncomment this line to *hear* what is being monitored, in addition to seeing it
in.enableMonitoring();
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms so we can see what we are monitoring
for(int i = 0; i < in.bufferSize() - 1; i++)
{
line( i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50 );
line( i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50 );
}
}

View File

@@ -0,0 +1,53 @@
/**
* This sketch demonstrates how to create a simple synthesis chain that
* involves controlling the value of a UGenInput with the output of
* a UGen. In this case, we patch an Oscil generating a sine wave into
* the amplitude input of an Oscil generating a square wave. The result
* is known as amplitude modulation.
*/
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
Oscil wave;
Oscil mod;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// use the getLineOut method of the Minim object to get an AudioOutput object
out = minim.getLineOut();
// create a triangle wave Oscil, set to 440 Hz, at 1.0 amplitude
// in this case, the amplitude we construct the Oscil with
// doesn't matter because we will be patching something to
// its amplitude input.
wave = new Oscil( 440, 1.0f, Waves.TRIANGLE );
// create a sine wave Oscil for modulating the amplitude of wave
mod = new Oscil( 2, 0.4f, Waves.SINE );
// connect up the modulator
mod.patch( wave.amplitude );
// patch wave to the output
wave.patch( out );
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
for(int i = 0; i < out.bufferSize() - 1; i++)
{
line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 );
line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 );
}
}

View File

@@ -0,0 +1,43 @@
/**
* This sketch demonstrates how to play a file with Minim using an AudioPlayer. <br />
* It's also a good example of how to draw the waveform of the audio.
*/
import ddf.minim.*;
Minim minim;
AudioPlayer player;
void setup()
{
size(512, 200, P3D);
// we pass this to Minim so that it can load files from the data directory
minim = new Minim(this);
// loadFile will look in all the same places as loadImage does.
// this means you can find files that are in the data folder and the
// sketch folder. you can also pass an absolute path, or a URL.
player = minim.loadFile("marcus_kellis_theme.mp3");
// play the file
player.play();
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
// the values returned by left.get() and right.get() will be between -1 and 1,
// so we need to scale them up to see the waveform
// note that if the file is MONO, left.get() and right.get() will return the same value
for(int i = 0; i < player.bufferSize() - 1; i++)
{
float x1 = map( i, 0, player.bufferSize(), 0, width );
float x2 = map( i+1, 0, player.bufferSize(), 0, width );
line( x1, 50 + player.left.get(i)*50, x2, 50 + player.left.get(i+1)*50 );
line( x1, 150 + player.right.get(i)*50, x2, 150 + player.right.get(i+1)*50 );
}
}

View File

@@ -0,0 +1,84 @@
/**
* This sketch demonstrates how to an <code>AudioRecorder</code> to record audio to disk.
* To use this sketch you need to have something plugged into the line-in on your computer, or else be working on a
* laptop with an active built-in microphone. Press 'r' to toggle recording on and off and the press 's' to save to disk.
* The recorded file will be placed in the sketch folder of the sketch.
*/
import ddf.minim.*;
Minim minim;
AudioInput in;
AudioRecorder recorder;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
in = minim.getLineIn();
// create a recorder that will record from the input to the filename specified, using buffered recording
// buffered recording means that all captured audio will be written into a sample buffer
// then when save() is called, the contents of the buffer will actually be written to a file
// the file will be located in the sketch's root folder.
recorder = minim.createRecorder(in, "myrecording.wav", true);
textFont(createFont("Arial", 12));
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
// the values returned by left.get() and right.get() will be between -1 and 1,
// so we need to scale them up to see the waveform
for(int i = 0; i < in.bufferSize() - 1; i++)
{
line(i, 50 + in.left.get(i)*50, i+1, 50 + in.left.get(i+1)*50);
line(i, 150 + in.right.get(i)*50, i+1, 150 + in.right.get(i+1)*50);
}
if ( recorder.isRecording() )
{
text("Currently recording...", 5, 15);
}
else
{
text("Not recording.", 5, 15);
}
}
void keyReleased()
{
if ( key == 'r' )
{
// to indicate that you want to start or stop capturing audio data, you must call
// beginRecord() and endRecord() on the AudioRecorder object. You can start and stop
// as many times as you like, the audio data will be appended to the end of the buffer
// (in the case of buffered recording) or to the end of the file (in the case of streamed recording).
if ( recorder.isRecording() )
{
recorder.endRecord();
}
else
{
recorder.beginRecord();
}
}
if ( key == 's' )
{
// we've filled the file out buffer,
// now write it to the file we specified in createRecorder
// in the case of buffered recording, if the buffer is large,
// this will appear to freeze the sketch for sometime
// in the case of streamed recording,
// it will not freeze as the data is already in the file and all that is being done
// is closing the file.
// the method returns the recorded audio as an AudioRecording,
// see the example AudioRecorder >> RecordAndPlayback for more about that
recorder.save();
println("Done saving.");
}
}

View File

@@ -0,0 +1,92 @@
/**
* This sketch demonstrates how to use an <code>AudioRecorder</code> to record audio to disk.
* Press 'r' to toggle recording on and off and the press 's' to save to disk.
* The recorded file will be placed in the sketch folder of the sketch.
*/
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
AudioRecorder recorder;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
out = minim.getLineOut();
// create a recorder that will record from the input to the filename specified, using buffered recording
// buffered recording means that all captured audio will be written into a sample buffer
// then when save() is called, the contents of the buffer will actually be written to a file
// the file will be located in the sketch's root folder.
recorder = minim.createRecorder(out, "myrecording.wav", true);
// patch some sound into the output so we have something to record
Oscil wave = new Oscil( 440.f, 1.0f );
Oscil mod = new Oscil( 4.0f, 0.25f, Waves.SAW );
mod.offset.setLastValue( 0.5f );
mod.patch( wave.amplitude );
wave.patch( out );
textFont(createFont("Arial", 12));
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
// the values returned by left.get() and right.get() will be between -1 and 1,
// so we need to scale them up to see the waveform
for(int i = 0; i < out.bufferSize() - 1; i++)
{
line(i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50);
line(i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50);
}
if ( recorder.isRecording() )
{
text("Currently recording...", 5, 15);
}
else
{
text("Not recording.", 5, 15);
}
}
void keyReleased()
{
if ( key == 'r' )
{
// to indicate that you want to start or stop capturing audio data, you must call
// beginRecord() and endRecord() on the AudioRecorder object. You can start and stop
// as many times as you like, the audio data will be appended to the end of the buffer
// (in the case of buffered recording) or to the end of the file (in the case of streamed recording).
if ( recorder.isRecording() )
{
recorder.endRecord();
}
else
{
recorder.beginRecord();
}
}
if ( key == 's' )
{
// we've filled the file out buffer,
// now write it to the file we specified in createRecorder
// in the case of buffered recording, if the buffer is large,
// this will appear to freeze the sketch for sometime
// in the case of streamed recording,
// it will not freeze as the data is already in the file and all that is being done
// is closing the file.
// the method returns the recorded audio as an AudioRecording,
// see the example AudioRecorder >> RecordAndPlayback for more about that
recorder.save();
println("Done saving.");
}
}

View File

@@ -0,0 +1,68 @@
/**
* This is a relatively simple file player that lets you scrub forward and backward in an audio file.<br />
* It should be noted that it's not *exactly* scrubbing because the playback speed is not changed,
* it's simply that the position in the song is changed by very small increments when fast-forwarding or rewinding.
* But the end result is convincing enough.
* <p>
* The positioning code is inside of the Play, Rewind, and Forward classes, which are in button.pde.
*/
import ddf.minim.*;
Minim minim;
AudioPlayer song;
Play play;
Rewind rewind;
Forward ffwd;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// load a file from the data folder, use a sample buffer of 1024 samples
song = minim.loadFile("fair1939.wav", 512);
// buttons for control
play = new Play(width/2 - 50, 130, 20, 10);
rewind = new Rewind(width/2, 130, 20, 10);
ffwd = new Forward(width/2 + 50, 130, 20, 10);
}
void draw()
{
background(0);
// draw the wave form
// this wav is MONO, so we only need the left channel,
// though we could have used the right channel and gotten the same values
stroke(255);
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)*10);
}
// draw the position in the song
// the position is in milliseconds,
// to get a meaningful graphic, we need to map the value to the range [0, width]
float x = map(song.position(), 0, song.length(), 0, width);
stroke(255, 0, 0);
line(x, 50 - 20, x, 50 + 20);
// do the controls
play.update();
play.draw();
rewind.update();
rewind.draw();
ffwd.update();
ffwd.draw();
}
void mousePressed()
{
play.mousePressed();
rewind.mousePressed();
ffwd.mousePressed();
}
void mouseReleased()
{
play.mouseReleased();
rewind.mouseReleased();
ffwd.mouseReleased();
}

View File

@@ -0,0 +1,255 @@
abstract class Button
{
int x, y, hw, hh;
Button(int x, int y, int hw, int hh)
{
this.x = x;
this.y = y;
this.hw = hw;
this.hh = hh;
}
boolean pressed()
{
return mouseX > x - hw && mouseX < x + hw && mouseY > y - hh && mouseY < y + hh;
}
abstract void mousePressed();
abstract void mouseReleased();
abstract void update();
abstract void draw();
}
class Play extends Button
{
boolean play;
boolean invert;
Play(int x, int y, int hw, int hh)
{
super(x, y, hw, hh);
play = true;
}
// code to handle playing and pausing the file
void mousePressed()
{
if ( pressed() )
{
invert = true;
if ( song.isPlaying() )
{
song.pause();
play = true;
}
else
{
song.loop();
play = false;
}
}
}
void mouseReleased()
{
invert = false;
}
// play is a boolean value used to determine what to draw on the button
void update()
{
if ( song.isPlaying() ) play = false;
else play = true;
}
void draw()
{
if ( invert )
{
fill(255);
stroke(0);
}
else
{
noFill();
stroke(255);
}
rect(x - hw, y - hh, hw*2, hh*2);
if ( invert )
{
fill(0);
stroke(255);
}
else
{
fill(255);
noStroke();
}
if ( play )
{
triangle(x - hw/3, y - hh/2, x - hw/3, y + hh/2, x + hw/2, y);
}
else
{
rect(x - hw/3, y - hh/2, hw/4, hh);
rect(x + hw/8, y - hh/2, hw/4, hh);
}
}
}
class Rewind extends Button
{
boolean invert;
boolean pressed;
Rewind(int x, int y, int hw, int hh)
{
super(x, y, hw, hh);
invert = false;
}
// code used to scrub backward in the file
void update()
{
// if the rewind button is currently being pressed
if (pressed)
{
// get the current song position
int pos = song.position();
// if it greater than 200 milliseconds
if ( pos > 200 )
{
// rewind the song by 200 milliseconds
song.skip(-200);
}
else
{
// if the song hasn't played more than 100 milliseconds
// just rewind to the beginning
song.rewind();
}
}
}
void mousePressed()
{
pressed = pressed();
if ( pressed )
{
invert = true;
// if the song isn't currently playing, rewind it to the beginning
if ( !song.isPlaying() ) song.rewind();
}
}
void mouseReleased()
{
pressed = false;
invert = false;
}
void draw()
{
if ( invert )
{
fill(255);
stroke(0);
}
else
{
noFill();
stroke(255);
}
rect(x - hw, y - hh, hw*2, hh*2);
if ( invert )
{
fill(0);
stroke(255);
}
else
{
fill(255);
noStroke();
}
triangle(x - hw/2, y, x, y - hh/2, x, y + hh/2);
triangle(x, y, x + hw/2, y - hh/2, x + hw/2, y + hh/2);
}
}
class Forward extends Button
{
boolean invert;
boolean pressed;
Forward(int x, int y, int hw, int hh)
{
super(x, y, hw, hh);
invert = false;
}
void update()
{
// if the forward button is currently being pressed
if (pressed)
{
// get the current position of the song
int pos = song.position();
// if the song's position is more than 40 milliseconds from the end of the song
if ( pos < song.length() - 40 )
{
// forward the song by 40 milliseconds
song.skip(40);
}
else
{
// otherwise, cue the song at the end of the song
song.cue( song.length() );
}
// start the song playing
song.play();
}
}
void mousePressed()
{
pressed = pressed();
if ( pressed )
{
invert = true;
}
}
void mouseReleased()
{
pressed = false;
invert = false;
}
void draw()
{
if ( invert )
{
fill(255);
stroke(0);
}
else
{
noFill();
stroke(255);
}
rect(x - hw, y - hh, hw*2, hh*2);
if ( invert )
{
fill(0);
stroke(255);
}
else
{
fill(255);
noStroke();
}
triangle(x, y, x - hw/2, y - hh/2, x - hw/2, y + hh/2);
triangle(x, y - hh/2, x, y + hh/2, x + hw/2, y);
}
}

Binary file not shown.

View File

@@ -0,0 +1,66 @@
/**
* This sketch demonstrates how to create synthesized sound with Minim using an <code>AudioOutput</code> and the
* default instrument built into an <code>AudioOutput</code>. By using the <code>playNote</code> method you can
* schedule notes to played at some point in the future, essentially allowing to you create musical scores with
* code. Because they are constructed with code, they can be either deterministic or different every time. This
* sketch creates a deterministic score, meaning it is the same every time you run the sketch. It also demonstrates
* a couple different versions of the <code>playNote</code> method.
* <p>
* For more complex examples of using <code>playNote</code> check out algorithmicCompExample and compositionExample
* in the Synthesis folder.
*/
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// use the getLineOut method of the Minim object to get an AudioOutput object
out = minim.getLineOut();
// given start time, duration, and frequency
out.playNote( 0.0, 0.9, 97.99 );
out.playNote( 1.0, 0.9, 123.47 );
// given start time, duration, and note name
out.playNote( 2.0, 2.9, "C3" );
out.playNote( 3.0, 1.9, "E3" );
out.playNote( 4.0, 0.9, "G3" );
// given start time and note name or frequency
// (duration defaults to 1.0)
out.playNote( 5.0, "" );
out.playNote( 6.0, 329.63);
out.playNote( 7.0, "G4" );
// the note offset is simply added into the start time of
// every subsequenct call to playNote. It's expressed in beats,
// but since the default tempo of an AudioOuput is 60 beats per minute,
// this particular call translates to 8.1 seconds, as you might expect.
out.setNoteOffset( 8.1 );
// because only given a note name or frequency
// starttime defaults to 0.0 and duration defaults to 1.0
out.playNote( "G5" );
out.playNote( 987.77 );
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
for(int i = 0; i < out.bufferSize() - 1; i++)
{
line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 );
line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 );
}
}

View File

@@ -0,0 +1,178 @@
/**
* An FFT object is used to convert an audio signal into its frequency domain representation. This representation
* lets you see how much of each frequency is contained in an audio signal. Sometimes you might not want to
* work with the entire spectrum, so it's possible to have the FFT object calculate average frequency bands by
* simply averaging the values of adjacent frequency bands in the full spectrum. There are two different ways
* these can be calculated: <b>Linearly</b>, by grouping equal numbers of adjacent frequency bands, or
* <b>Logarithmically</b>, by grouping frequency bands by <i>octave</i>, which is more akin to how humans hear sound.
* <br/>
* This sketch illustrates the difference between viewing the full spectrum, linearly spaced averaged bands,
* and logarithmically spaced averaged bands.
* <p>
* From top to bottom:
* <ul>
* <li>The full spectrum.</li>
* <li>The spectrum grouped into 30 linearly spaced averages.</li>
* <li>The spectrum grouped logarithmically into 10 octaves, each split into 3 bands.</li>
* </ul>
*
* Moving the mouse across the sketch will highlight a band in each spectrum and display what the center
* frequency of that band is. The averaged bands are drawn so that they line up with full spectrum bands they
* are averages of. In this way, you can clearly see how logarithmic averages differ from linear averages.
*/
import ddf.minim.analysis.*;
import ddf.minim.*;
Minim minim;
AudioPlayer jingle;
FFT fftLin;
FFT fftLog;
float height3;
float height23;
float spectrumScale = 4;
PFont font;
void setup()
{
size(512, 480);
height3 = height/3;
height23 = 2*height/3;
minim = new Minim(this);
jingle = minim.loadFile("jingle.mp3", 1024);
// loop the file
jingle.loop();
// create an FFT object that has a time-domain buffer the same size as jingle's sample buffer
// note that this needs to be a power of two
// and that it means the size of the spectrum will be 1024.
// see the online tutorial for more info.
fftLin = new FFT( jingle.bufferSize(), jingle.sampleRate() );
// calculate the averages by grouping frequency bands linearly. use 30 averages.
fftLin.linAverages( 30 );
// create an FFT object for calculating logarithmically spaced averages
fftLog = new FFT( jingle.bufferSize(), jingle.sampleRate() );
// calculate averages based on a miminum octave width of 22 Hz
// split each octave into three bands
// this should result in 30 averages
fftLog.logAverages( 22, 3 );
rectMode(CORNERS);
font = loadFont("ArialMT-12.vlw");
}
void draw()
{
background(0);
textFont(font);
textSize( 18 );
float centerFrequency = 0;
// perform a forward FFT on the samples in jingle's mix buffer
// note that if jingle were a MONO file, this would be the same as using jingle.left or jingle.right
fftLin.forward( jingle.mix );
fftLog.forward( jingle.mix );
// draw the full spectrum
{
noFill();
for(int i = 0; i < fftLin.specSize(); i++)
{
// if the mouse is over the spectrum value we're about to draw
// set the stroke color to red
if ( i == mouseX )
{
centerFrequency = fftLin.indexToFreq(i);
stroke(255, 0, 0);
}
else
{
stroke(255);
}
line(i, height3, i, height3 - fftLin.getBand(i)*spectrumScale);
}
fill(255, 128);
text("Spectrum Center Frequency: " + centerFrequency, 5, height3 - 25);
}
// no more outline, we'll be doing filled rectangles from now
noStroke();
// draw the linear averages
{
// since linear averages group equal numbers of adjacent frequency bands
// we can simply precalculate how many pixel wide each average's
// rectangle should be.
int w = int( width/fftLin.avgSize() );
for(int i = 0; i < fftLin.avgSize(); i++)
{
// if the mouse is inside the bounds of this average,
// print the center frequency and fill in the rectangle with red
if ( mouseX >= i*w && mouseX < i*w + w )
{
centerFrequency = fftLin.getAverageCenterFrequency(i);
fill(255, 128);
text("Linear Average Center Frequency: " + centerFrequency, 5, height23 - 25);
fill(255, 0, 0);
}
else
{
fill(255);
}
// draw a rectangle for each average, multiply the value by spectrumScale so we can see it better
rect(i*w, height23, i*w + w, height23 - fftLin.getAvg(i)*spectrumScale);
}
}
// draw the logarithmic averages
{
// since logarithmically spaced averages are not equally spaced
// we can't precompute the width for all averages
for(int i = 0; i < fftLog.avgSize(); i++)
{
centerFrequency = fftLog.getAverageCenterFrequency(i);
// how wide is this average in Hz?
float averageWidth = fftLog.getAverageBandWidth(i);
// we calculate the lowest and highest frequencies
// contained in this average using the center frequency
// and bandwidth of this average.
float lowFreq = centerFrequency - averageWidth/2;
float highFreq = centerFrequency + averageWidth/2;
// freqToIndex converts a frequency in Hz to a spectrum band index
// that can be passed to getBand. in this case, we simply use the
// index as coordinates for the rectangle we draw to represent
// the average.
int xl = (int)fftLog.freqToIndex(lowFreq);
int xr = (int)fftLog.freqToIndex(highFreq);
// if the mouse is inside of this average's rectangle
// print the center frequency and set the fill color to red
if ( mouseX >= xl && mouseX < xr )
{
fill(255, 128);
text("Logarithmic Average Center Frequency: " + centerFrequency, 5, height - 25);
fill(255, 0, 0);
}
else
{
fill(255);
}
// draw a rectangle for each average, multiply the value by spectrumScale so we can see it better
rect( xl, height, xr, height - fftLog.getAvg(i)*spectrumScale );
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* This sketch demonstrates how to create synthesized sound with Minim
* using an AudioOutput and an Oscil. An Oscil is a UGen object,
* one of many different types included with Minim. For many more examples
* of UGens included with Minim, have a look in the Synthesis
* folder of the Minim examples.
*/
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
Oscil wave;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// use the getLineOut method of the Minim object to get an AudioOutput object
out = minim.getLineOut();
// create a sine wave Oscil, set to 440 Hz, at 0.5 amplitude
wave = new Oscil( 440, 0.5f, Waves.SINE );
// patch the Oscil to the output
wave.patch( out );
}
void draw()
{
background(0);
stroke(255);
// draw the waveforms
for(int i = 0; i < out.bufferSize() - 1; i++)
{
line( i, 50 + out.left.get(i)*50, i+1, 50 + out.left.get(i+1)*50 );
line( i, 150 + out.right.get(i)*50, i+1, 150 + out.right.get(i+1)*50 );
}
}

View File

@@ -0,0 +1,81 @@
/**
* This sketch demonstrates how to use the <code>loadSample</code> method of <code>Minim</code>.
* The <code>loadSample</code> method allows you to specify the sample you want to load
* with a <code>String</code> and optionally specify what you want the buffer size of the
* returned <code>AudioSample</code> to be. Minim is able to load wav files, au files, aif
* files, snd files, and mp3 files. When you call <code>loadSample</code>, if you just
* specify the filename it will try to load the sample from the data folder of your sketch.
* However, you can also specify an absolute path (such as "C:\foo\bar\thing.wav") and the
* file will be loaded from that location (keep in mind that won't work from an applet).
* You can also specify a URL (such as "http://www.mysite.com/mp3/song.mp3") but keep in mind
* that if you run the sketch as an applet you may run in to security restrictions
* if the applet is not on the same domain as the file you want to load. You can get around
* the restriction by signing all of the jars in the applet.
* <p>
* An <code>AudioSample</code> is a special kind of file playback that allows
* you to repeatedly <i>trigger</i> an audio file. It does this by keeping the
* entire file in an internal buffer and then keeping a list of trigger points.
* <code>AudioSample</code> supports up to 20 overlapping triggers, which
* should be plenty for short sounds. It is not advised that you use this class
* for long sounds (like entire songs, for example) because the entire file is
* kept in memory.
* <p>
* Use 'k' and 's' to trigger a kick drum sample and a snare sample, respectively.
* You will see their waveforms drawn when they are played back.
*/
import ddf.minim.*;
Minim minim;
AudioSample kick;
AudioSample snare;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
// load BD.wav from the data folder
kick = minim.loadSample( "BD.mp3", // filename
512 // buffer size
);
// An AudioSample will spawn its own audio processing Thread,
// and since audio processing works by generating one buffer
// of samples at a time, we can specify how big we want that
// buffer to be in the call to loadSample.
// above, we requested a buffer size of 512 because
// this will make the triggering of the samples sound more responsive.
// on some systems, this might be too small and the audio
// will sound corrupted, in that case, you can just increase
// the buffer size.
// if a file doesn't exist, loadSample will return null
if ( kick == null ) println("Didn't get kick!");
// load SD.wav from the data folder
snare = minim.loadSample("SD.wav", 512);
if ( snare == null ) println("Didn't get snare!");
}
void draw()
{
background(0);
stroke(255);
// use the mix buffer to draw the waveforms.
for (int i = 0; i < kick.bufferSize() - 1; i++)
{
float x1 = map(i, 0, kick.bufferSize(), 0, width);
float x2 = map(i+1, 0, kick.bufferSize(), 0, width);
line(x1, 50 - kick.mix.get(i)*50, x2, 50 - kick.mix.get(i+1)*50);
line(x1, 150 - snare.mix.get(i)*50, x2, 150 - snare.mix.get(i+1)*50);
}
}
void keyPressed()
{
if ( key == 's' ) snare.trigger();
if ( key == 'k' ) kick.trigger();
}

View File

@@ -0,0 +1,88 @@
/* delayExample
is an example of using the Delay UGen in a continuous sound example.
Use the mouse to control the delay time and the amount of feedback
in the delay unit.
author: Anderson Mills
Anderson Mills's work was supported by numediart (www.numediart.org)
*/
// import everything necessary to make sound.
import ddf.minim.*;
import ddf.minim.ugens.*;
// create all of the variables that will need to be accessed in
// more than one methods (setup(), draw(), stop()).
Minim minim;
AudioOutput out;
Delay myDelay1;
// setup is run once at the beginning
void setup()
{
// initialize the drawing window
size( 512, 200, P2D );
// initialize the minim and out objects
minim = new Minim(this);
out = minim.getLineOut( Minim.MONO, 2048 );
// initialize myDelay1 with continual feedback and no audio passthrough
myDelay1 = new Delay( 0.6, 0.9, true, false );
// create the Blip that will be used
Oscil myBlip = new Oscil( 245.0, 0.3, Waves.saw( 15 ) );
// create an LFO to be used for an amplitude envelope
Oscil myLFO = new Oscil( 0.5, 0.3, Waves.square( 0.005 ) );
// our LFO will operate on a base amplitude
Constant baseAmp = new Constant(0.3);
// we get the final amplitude by summing the two
Summer ampSum = new Summer();
Summer sum = new Summer();
// patch everything together
// the LFO is patched into a summer along with a constant value
// and that sum is used to drive the amplitude of myBlip
baseAmp.patch( ampSum );
myLFO.patch( ampSum );
ampSum.patch( myBlip.amplitude );
// the Blip is patched directly into the sum
myBlip.patch( sum );
// and the Blip is patched through the delay into the sum.
myBlip.patch( myDelay1 ).patch( sum );
// patch the sum into the output
sum.patch( out );
}
// draw is run many times
void draw()
{
// erase the window to dark grey
background( 64 );
// draw using a light gray stroke
stroke( 192 );
// draw the waveforms
for( int i = 0; i < out.bufferSize() - 1; i++ )
{
// find the x position of each buffer value
float x1 = map( i, 0, out.bufferSize(), 0, width );
float x2 = map( i+1, 0, out.bufferSize(), 0, width );
// draw a line from one buffer position to the next for both channels
line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50);
line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50);
}
}
// when the mouse is moved, change the delay parameters
void mouseMoved()
{
// set the delay time by the horizontal location
float delayTime = map( mouseX, 0, width, 0.0001, 0.5 );
myDelay1.setDelTime( delayTime );
// set the feedback factor by the vertical location
float feedbackFactor = map( mouseY, 0, height, 0.0, 0.99 );
myDelay1.setDelAmp( feedbackFactor );
}

View File

@@ -0,0 +1,81 @@
/* filterExample
is an example of using the different filters
in continuous sound.
author: Damien Di Fede, Anderson Mills
Anderson Mills's work was supported by numediart (www.numediart.org)
*/
// import everything necessary to make sound.
import ddf.minim.*;
import ddf.minim.ugens.*;
// the effects package is needed because the filters are there for now.
import ddf.minim.effects.*;
// create all of the variables that will need to be accessed in
// more than one methods (setup(), draw(), stop()).
Minim minim;
AudioOutput out;
// setup is run once at the beginning
void setup()
{
// initialize the drawing window
size(300, 200, P2D);
// initialize the minim and out objects
minim = new Minim(this);
out = minim.getLineOut();
// create all of the variables
IIRFilter filt;
Oscil osc;
Oscil cutOsc;
Constant cutoff;
// initialize the oscillator
// (a sawtooth wave has energy across the spectrum)
osc = new Oscil(500, 0.2, Waves.SAW);
// uncoment one of the filters to hear it's effect
//filt = new LowPassSP(400, out.sampleRate());
//filt = new LowPassFS(400, out.sampleRate());
filt = new BandPass(400, 100, out.sampleRate());
//filt = new HighPassSP(400, out.sampleRate());
//filt = new NotchFilter(400, 100, out.sampleRate());
// create an Oscil we will use to modulate
// the cutoff frequency of the filter.
// by using an amplitude of 800 and an
// offset of 1000, the cutoff frequency
// will sweep between 200 and 1800 Hertz.
cutOsc = new Oscil(1, 800, Waves.SINE);
// offset the center value of the Oscil by 1000
cutOsc.offset.setLastValue( 1000 );
// patch the oscil to the cutoff frequency of the filter
cutOsc.patch(filt.cutoff);
// patch the sawtooth oscil through the filter and then to the output
osc.patch(filt).patch(out);
}
// draw is run many times
void draw()
{
// erase the window to black
background( 0 );
// draw using a white stroke
stroke( 255 );
// draw the waveforms
for( int i = 0; i < out.bufferSize() - 1; i++ )
{
// find the x position of each buffer value
float x1 = map( i, 0, out.bufferSize(), 0, width );
float x2 = map( i+1, 0, out.bufferSize(), 0, width );
// draw a line from one buffer position to the next for both channels
line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50);
line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50);
}
}

View File

@@ -0,0 +1,76 @@
/* frequencyModulation
<p>
A simple example for doing FM (frequency modulation) using two Oscils.
Use the mouse to control the speed and range of the frequency modulation.
<p>
Author: Damien Di Fede
*/
// import everything necessary to make sound.
import ddf.minim.*;
import ddf.minim.ugens.*;
// create all of the variables that will need to be accessed in
// more than one methods (setup(), draw(), stop()).
Minim minim;
AudioOutput out;
// the Oscil we use for modulating frequency.
Oscil fm;
// setup is run once at the beginning
void setup()
{
// initialize the drawing window
size( 512, 200, P3D );
// initialize the minim and out objects
minim = new Minim( this );
out = minim.getLineOut();
// make the Oscil we will hear.
// arguments are frequency, amplitude, and waveform
Oscil wave = new Oscil( 200, 0.8, Waves.TRIANGLE );
// make the Oscil we will use to modulate the frequency of wave.
// the frequency of this Oscil will determine how quickly the
// frequency of wave changes and the amplitude determines how much.
// since we are using the output of fm directly to set the frequency
// of wave, you can think of the amplitude as being expressed in Hz.
fm = new Oscil( 10, 2, Waves.SINE );
// set the offset of fm so that it generates values centered around 200 Hz
fm.offset.setLastValue( 200 );
// patch it to the frequency of wave so it controls it
fm.patch( wave.frequency );
// and patch wave to the output
wave.patch( out );
}
// draw is run many times
void draw()
{
// erase the window to black
background( 0 );
// draw using a white stroke
stroke( 255 );
// draw the waveforms
for( int i = 0; i < out.bufferSize() - 1; i++ )
{
// find the x position of each buffer value
float x1 = map( i, 0, out.bufferSize(), 0, width );
float x2 = map( i+1, 0, out.bufferSize(), 0, width );
// draw a line from one buffer position to the next for both channels
line( x1, 50 + out.left.get(i)*50, x2, 50 + out.left.get(i+1)*50);
line( x1, 150 + out.right.get(i)*50, x2, 150 + out.right.get(i+1)*50);
}
}
// we can change the parameters of the frequency modulation Oscil
// in real-time using the mouse.
void mouseMoved()
{
float modulateAmount = map( mouseY, 0, height, 220, 1 );
float modulateFrequency = map( mouseX, 0, width, 0.1, 100 );
fm.frequency.setLastValue( modulateFrequency );
fm.amplitude.setLastValue( modulateAmount );
}

View File

@@ -0,0 +1,90 @@
/**
* This sketch demonstrates how to use the loadFileIntoBuffer method of the Minim class and is also a good
* reference for some of the methods of the MultiChannelBuffer class. When the sketch begins it loads
* a file from the data folder into a MultiChannelBuffer and then modifies that sample data before
* using it to create a Sampler UGen. You can hear the result of this modification by hitting
* the space bar.
*/
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
MultiChannelBuffer sampleBuffer;
AudioOutput output;
Sampler sampler;
void setup()
{
size(512, 200, P3D);
// create Minim and an AudioOutput
minim = new Minim(this);
output = minim.getLineOut();
// construct a new MultiChannelBuffer with 2 channels and 1024 sample frames.
// in our particular case, it doesn't really matter what we choose for these
// two values because loadFileIntoBuffer will reconfigure the buffer
// to match the channel count and length of the file.
sampleBuffer = new MultiChannelBuffer( 1, 1024 );
// we pass the buffer to the method and Minim will reconfigure it to match
// the file. if the file doesn't exist, or there is some other problen with
// loading it, the function will return 0 as the sample rate.
float sampleRate = minim.loadFileIntoBuffer( "SD.wav", sampleBuffer );
// make sure the file load worked
if ( sampleRate > 0 )
{
// double the size of the buffer to give ourselves some silence to play with
int originalBufferSize = sampleBuffer.getBufferSize();
sampleBuffer.setBufferSize( originalBufferSize * 2 );
// go through first half of the buffer, which contains the original sample,
// and add a delayed version of each sample at some random position.
// we happen to know that the source file is only one channel
// but in general you'd want to iterate over all channels when doing something like this
for( int s = 0; s < originalBufferSize; ++s )
{
int delayIndex = s + int( random( 0, originalBufferSize ) );
float sampleValue = sampleBuffer.getSample( 0, s );
float destValue = sampleBuffer.getSample( 0, delayIndex );
sampleBuffer.setSample( 0, // channel
delayIndex, // sample frame to set
sampleValue + destValue // the value to set
);
}
// create a sampler that will use our buffer to generate audio.
// we must provide the sample rate of the audio and the number of voices.
sampler = new Sampler( sampleBuffer, sampleRate, 1 );
// and finally, connect to the output so we can hear it
sampler.patch( output );
}
}
void draw()
{
background(0);
stroke(255);
// use the mix buffer to draw the waveforms.
for (int i = 0; i < output.bufferSize() - 1; i++)
{
float x1 = map(i, 0, output.bufferSize(), 0, width);
float x2 = map(i+1, 0, output.bufferSize(), 0, width);
line(x1, 50 - output.left.get(i)*50, x2, 50 - output.left.get(i+1)*50);
line(x1, 150 - output.right.get(i)*50, x2, 150 - output.right.get(i+1)*50);
}
}
void keyPressed()
{
if ( key == ' ' && sampler != null )
{
sampler.trigger();
}
}

View File

@@ -0,0 +1 @@
name = Minim Audio

View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -0,0 +1 @@
3.0 BETA