Easy BPM Calculation in Java

After last weeks mixed success, I started implementing the more advanced techniques Yov408 describes in his article. However, nothing seemed to improve the calculated beats per minute. I was about to go and implement the Fourier Transform, something which I wanted to avoid in order to keep the algorithm zippy. But I went back to the spreadsheet and discovered a much simpler solution.

downloadDownload the NetBeans example project

The second sample I tried has about 3 or 4 beats too much. Upon closer inspection of those misses, those are all instances where the energy went above the threshold during for only one sample.

Once I understood the nature of the problem, it was easy to implement a solution that only detects a beat when the energy is high enough for a few more samples. I put this into code and was amazed by the results. Pretty much any song I used resulted in a BPM count withing 5 BPM of the actual count.

The adapted algorithm is:

Every 1024 samples:

  • Compute the instant sound energy ‘e’ on the 1024 new sample values taken in (an) and (bn) using the formula (R1)
  • Compute the average local energy with (E) sound energy history buffer: <p align="center">

  • Shift the sound energy history buffer (E) of 1 index to the right. We make room for the new energy value and flush the oldest.
  • Pile in the new energy value ‘e’ at E[0].
  • If ‘e’ > ‘C*’ we detect a possible beat. If a possible beat was not detected in the previous calculation, we start counting, N = 0.  Otherwise, N is increased by one.</em> </li>
  • If N equals a threshold (3 is a pretty good value),  a true beat is detected.
  • </ul>

    Given the simplicity of the algorithm I think this is an incredible result and good enough to move into the next step of the project: Porting this to small devices.

    To be continued …

    downloadDownload the NetBeans example project

    BTW for those following along via e-mail or the RSS feed, come visit the site and let me know what you think of the new logo.

    Image credit