You should explore this code from beatDetect in Frequency mode. At the end of the song, I present a report of number of snares, kicks and hats as well as the time lapsed. I am noticing the time reported and ctr values depend on the BUFFERSIZE value when you load the file.
I am suspecting these functions are tuned for certain instruments at their proper frequencies.
For sounds, I downloaded wav files from http://www.orangefreesounds.com/category/loops/drum-loops/ and this is the one I have examined: http://www.orangefreesounds.com/drum-beat-loop-130-bpm/ hoping I could get the 120bpm or about 2 beats per sec. My results:
Time 8.397 secs
BUFFERSIZE 512
onCounter 0 0.0
kickCtr counter 13 1.548172
snareCtr counter 10 1.1909015
hatCtr counter 24 2.8581636
Time 7.73 secs
BUFFERSIZE 1024
onCounter 0 0.0
kickCtr counter 26 3.3635187
snareCtr counter 19 2.457956
hatCtr counter 27 3.4928849
Time 3.367 secs
BUFFERSIZE 2048
onCounter 0 0.0
kickCtr counter 25 7.4250073
snareCtr counter 24 7.128007
hatCtr counter 38 11.286012
For the last one, I noticed the code took a few seconds longer to load which could explain why the time reported is lower. There must be a proper way to do it. Read the instructions that ocmes with the code and explore his recommendations.
Code below with my attempt to get the beat-per-second.
Kf
/**
* This sketch demonstrates how to use the BeatDetect object in FREQ_ENERGY mode.<br />
* You can use <code>isKick</code>, <code>isSnare</code>, </code>isHat</code>, <code>isRange</code>,
* and <code>isOnset(int)</code> to track whatever kind of beats you are looking to track, they will report
* true or false based on the state of the analysis. To "tick" the analysis you must call <code>detect</code>
* with successive buffers of audio. You can do this inside of <code>draw</code>, but you are likely to miss some
* audio buffers if you do this. The sketch implements an <code>AudioListener</code> called <code>BeatListener</code>
* so that it can call <code>detect</code> on every buffer of audio processed by the system without repeating a buffer
* or missing one.
* <p>
* This sketch plays an entire song so it may be a little slow to load.
* <p>
* For more information about Minim and additional features,
* visit http://code.compartmental.net/minim/
*/
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioPlayer song;
BeatDetect beat;
BeatListener bl;
float kickSize, snareSize, hatSize;
//==========
final int BUFFERSIZE=2048;
int onctr=0;
int kickCtr=0;
int snareCtr=0;
int hatCtr=0;
int mytime=-1;
void setup()
{
size(512, 200, P3D);
minim = new Minim(this);
song = minim.loadFile("Shuffle-beat-133-bpm.wav",BUFFERSIZE);
song.play();
// a beat detection object that is FREQ_ENERGY mode that
// expects buffers the length of song's buffer size
// and samples captured at songs's sample rate
beat = new BeatDetect(song.bufferSize(), song.sampleRate());
// set the sensitivity to 300 milliseconds
// After a beat has been detected, the algorithm will wait for 300 milliseconds
// before allowing another beat to be reported. You can use this to dampen the
// algorithm if it is giving too many false-positives. The default value is 10,
// which is essentially no damping. If you try to set the sensitivity to a negative value,
// an error will be reported and it will be set to 10 instead.
// note that what sensitivity you choose will depend a lot on what kind of audio
// you are analyzing. in this example, we use the same BeatDetect object for
// detecting kick, snare, and hat, but that this sensitivity is not especially great
// for detecting snare reliably (though it's also possible that the range of frequencies
// used by the isSnare method are not appropriate for the song).
beat.setSensitivity(300);
kickSize = snareSize = hatSize = 16;
// make a new beat listener, so that we won't miss any buffers for the analysis
bl = new BeatListener(beat, song);
textFont(createFont("Helvetica", 16));
textAlign(CENTER);
}
void draw()
{
background(0);
// draw a green rectangle for every detect band
// that had an onset this frame
float rectW = width / beat.detectSize();
for (int i = 0; i < beat.detectSize(); ++i)
{
// test one frequency band for an onset
if ( beat.isOnset(i) )
{
fill(0, 200, 0);
rect( i*rectW, 0, rectW, height);
}
}
// draw an orange rectangle over the bands in
// the range we are querying
int lowBand = 5;
int highBand = 15;
// at least this many bands must have an onset
// for isRange to return true
int numberOfOnsetsThreshold = 4;
if ( beat.isRange(lowBand, highBand, numberOfOnsetsThreshold) )
{
fill(232, 179, 2, 200);
rect(rectW*lowBand, 0, (highBand-lowBand)*rectW, height);
}
if ( beat.isKick() ) kickSize = 32;
if ( beat.isSnare() ) snareSize = 32;
if ( beat.isHat() ) hatSize = 32;
fill(255);
textSize(kickSize);
text("KICK", width/4, height/2);
textSize(snareSize);
text("SNARE", width/2, height/2);
textSize(hatSize);
text("HAT", 3*width/4, height/2);
kickSize = constrain(kickSize * 0.95, 16, 32);
snareSize = constrain(snareSize * 0.95, 16, 32);
hatSize = constrain(hatSize * 0.95, 16, 32);
//==========
if (beat.isOnset()) onctr++;
if ( beat.isKick() ) kickCtr++;
if ( beat.isSnare() ) snareCtr++;
if ( beat.isHat() ) hatCtr++;
if (song.isPlaying()) {
if (mytime>=0) {
mytime=millis()-mytime;
} else {
mytime=millis();
}
} else {
println("Time", mytime/1000.0, "secs");
println("BUFFERSIZE",BUFFERSIZE);
println("onCounter", onctr, onctr*1000.0/mytime);
println("kickCtr counter", kickCtr, kickCtr*1000.0/mytime);
println("snareCtr counter", snareCtr, snareCtr*1000.0/mytime);
println("hatCtr counter", hatCtr, hatCtr*1000.0/mytime);
exit();
}
}
class BeatListener implements AudioListener
{
private BeatDetect beat;
private AudioPlayer source;
BeatListener(BeatDetect beat, AudioPlayer source)
{
this.source = source;
this.source.addListener(this);
this.beat = beat;
}
void samples(float[] samps)
{
beat.detect(source.mix);
}
void samples(float[] sampsL, float[] sampsR)
{
beat.detect(source.mix);
}
}