How to use 'BeatDetect' correctly with Minim library?

On this page http://code.compartmental.net/minim/beatdetect_class_beatdetect.html

I am trying to figure out how to detect beats. There is some confusions that I have.


void draw()
{
  background(0);
  beat.detect(song.mix); // What does this mean "song.mix"?
  float a = map(eRadius, 20, 80, 60, 255);
  fill(60, 255, 0, a);
  if ( beat.isOnset() ) eRadius = 80;
  ellipse(width/2, height/2, eRadius, eRadius);
  eRadius *= 0.95;
  if ( eRadius < 20 ) eRadius = 20;
}

For example in this line beat.detect(song.mix); what does song.mix even mean?

isOnset();

I am a little confused with what does this description even mean:

In sound energy mode this returns true when a beat has been detected. In frequency energy mode this always returns false. So what is the difference between sound energy mode and frequency energy mode?

http://code.compartmental.net/minim/audioplayer_field_mix.html

Quote:

BeatDetect has two modes: sound energy tracking and frequency energy tracking. In sound energy mode, the level of the buffer, as returned by level() , is used as the instant energy in each frame. Beats, then, are spikes in this value, relative to the previous one second of sound. In frequency energy mode, the same process is used but instead of tracking the level of the buffer, an FFT is used to obtain a spectrum, which is then divided into average bands using logAverages() , and each of these bands is tracked individually. The result is that it is possible to track sounds that occur in different parts of the frequency spectrum independently (like the kick drum and snare drum).

In sound energy mode you use isOnset() to query the algorithm and in frequency energy mode you use isOnset(int i) , isKick() , isSnare() , and isRange() to query particular frequnecy bands or ranges of frequency bands. It should be noted that isKick() , isSnare() , and isHat() merely call isRange() with values determined by testing the algorithm against music with a heavy beat and they may not be appropriate for all kinds of music. If you find they are performing poorly with your music, you should use isRange() directly to locate the bands that provide the most meaningful information for you.

http://code.compartmental.net/minim/beatdetect_class_beatdetect.html

to set the mode Minim : : BeatDetect : : detectMode

please don’t open a new thread when the topic stays the same. Just use reply.

What to do

do some research

something like

 if ( beat.isOnset() ) {
     timer=millis(); 
     int diff=lastTimer-timer; 
     print(diff+" ");
     allDiff+=diff; 
     avg =   allDiff /  detectCounter; 
     print("*"+avg+"*"); 
     lastTimer=timer; 
     detectCounter++; 
}

avg (average) should give you the speed. The higher it is, the slower the song.

Chrisir

1 Like

Sorry i will keep this in mind for next time.

Did you get this code from the Internet or did you make it yourself? If you got it from the Interent, can I have the link to the full source code please?

1 Like

Yeah, well, get the full code is not really research…

But I just wrote it to give you the the idea. I haven’t tested it though.

But you can just copy it into the the previous Sketch I showed you. And play with it, test it, change it… that’s research

1 Like

Hey man, everytime I start my program and there is nothing being printed to the console I get this minor error message:

==== JavaSound Minim Error ====
==== Don't know the ID3 code TXXX

==== JavaSound Minim Error ====
==== Don't know the ID3 code TXXX

==== JavaSound Minim Error ====
==== Don't know the ID3 code TXXX

==== JavaSound Minim Error ====
==== Don't know the ID3 code TSSE

Do you know what this is? Am I supposed to be concerned by this error message?

No, that’s not an error, just a message

Post your entire code to get help

1 Like

Hey man.

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


Minim minim;
AudioPlayer audio;
BeatDetect beat;



int timer = 0, lastTimer = 0, detectCounter = 0, allDiff = 0;
float avg = 0.0;



void setup()
{
  minim = new Minim(this);
  audio = minim.loadFile("audio.mp3");
  beat = new BeatDetect();
  
  
  size(800, 800);
  audio.play(); 
}



void draw()
{
  beat.detect(audio.mix);
  if (beat.isOnset())
  {
     timer = millis();
     int diff = lastTimer - timer;
     println(diff+" ");
     allDiff += diff;
     avg = (float) allDiff / (float) detectCounter; 
     println("*"+avg+"*");
     lastTimer = timer;
     detectCounter++;
  }
  background(255);
  ellipse(200, 400, audio.left.get(1)*800, audio.left.get(1)*800);
  ellipse(600, 400, audio.right.get(1)*800, audio.right.get(1)*800);
}

This is my entire code.

So I am playing don’t stop me now and like you know how in the beginning it is going slowly but it is on beat (like the beat doesn’t change)? So like why do I get different results:

Here is an output sample of the beginning slow part I got:

-6570 
*-Infinity*
-17 
*-6587.0*
-16 
*-3301.5*
-16 
*-2206.3333*
-17 
*-1659.0*
-18 
*-1330.8*
-16 
*-1111.6666*
-16 
*-955.1429*
-16 
*-837.75*
-17 
*-746.55554*
-18 
*-673.7*
-32 
*-615.36365*
-17 
*-565.5*
-34 
*-524.61536*
-16 
*-488.2857*
-16 
*-456.8*
-17 
*-429.3125*
-17 
*-405.05884*
-17 
*-383.5*
-17 
*-364.21054*
-17 
*-346.85*

Why is it giving different results when the beat is the same if you happen to know?

Several mistakes I made

At end of setup say

lastTimer=millis();

Then

Is obviously wrong. Must be timer - lastTimer

Anyway the results or 16 or 17 which seems very short

Maybe it’s always true which would be wrong…

You could check it with an else block with println

You have to do some research

For example there is also isSnare in the library and several others

2 Likes

Sorry mate I don’t quite get you.

Originally, inside that if statement I only had this line println(true); and randomly it would print true to the console (it didn’t seem to be on beat at all).

I could but I want to just know the beat regardless of there is a snare, drum kick etc.

What didn’t you get? Place the line at end of setup and change the other line

With the other questions I can’t help you. Just play with it and do some research

if (beat.isOnset())
  {
     timer = millis();
     int diff = timer - lastTimer;
     println(diff+" ");
     allDiff += diff;
     avg = (float) allDiff / (float) detectCounter; 
     println("*"+avg+"*");
     lastTimer = timer;
     detectCounter++;
  }

So I replace this line lastTimer = timer; with lastTimer = millis(); that is what you mean?

I did originally and like I am not too sure why does it print true randomly when I was playing around with isOnset() I thought it is used to detect the beat?

Here place lastTimer= millis ();

And then the other line must be

1 Like

Hey man in regards to detectMode() http://code.compartmental.net/minim/beatdetect_method_detectmode.html

I read it and I know I have to pass in an integer argument, however when I did that in the void setup() function by passing in 1 (i.e. I put detectMode(1); inside void setup()) and it still used SOUND_ENERGY instead of FREQ_ENERGY. On the page it doesn’t quite tell me what specific integer I need to pass in in order for it to work. Would you know by any chance?

As it says: You can pass as parameters to detectMode

  • BeatDetect.SOUND_ENERGY or
  • BeatDetect.FREQ_ENERGY

Both are inbuilt integer constants

1 Like

Oh sorry I did not understand that bit before, now I get it.


I am using isKick() and isSnare() and it thinks its true at the beginning of the song, the beginning of the song only has a piano playing and somebody singing, which doesn’t make anysense.

beat.detect(audio.mix);
  
  if (beat.isKick())
  {
    print(true + " ");
  }

The above code is inside void draw().

(I am very sorry for asking a lot of questions. Everything is just going wrong).

it’s probably not an easy task for a computer

Did you read http://code.compartmental.net/minim/beatdetect_class_beatdetect.html ?

What about isRange?

1 Like

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);
  }
}
2 Likes

Hi mate thanks for your code I really appreciate it :slight_smile: I just have one question, how are you using frequency mode when you have not used beat.detectMode(BeatDetect.FREQ_ENERGY) within your code though?

While my code is now working the way I want it to, I just have a question with isRange(). With the last argument that you pass, what does this numberOfOnsetsThreshold mean? This variable numberOfOnsetsThreshold has been assigned 4 to it so what does it even do though, I am just a bit confused. I read the man page for isRange but I don’t get what does the last argument do exactly?