Simple BPM counter

An Analyze plug-in to count the BPM of the selected audio.
Beats are detected based on amplitude, so it should work well with a simple drum track (though it may give a multiple of the musical tempo, depending on the drum rhythm).
I would not expect this to work well with complex music as beats are detected only by whether there is a pulse of higher amplitude than the “threshold” level.

Installation instructions for Nyquist plug-ins: http://audacityteam.org/download/plugins

This plug-in requires Audacity 1.3.8 or later.
bpm-count.ny (1.27 KB)

Found I had to lower the threshold to detect compound time more accurately but I guess that’s expected.

Would I assume this could not be combined with a labelling function e.g. after labelling (if requested) it throws its message box?

I understand the BPM detection is only done done on the first minute, though in fact setting:

(setq tlen (min (get-duration 1) 360.0));

seemed to give better results on 3 to 6 minute pop tracks than the (setq tlen (min (get-duration 1) 60.0)); as shipped. It took about a couple of seconds longer with the higher value but that was a price well worth paying.



Gale

This plug-in was written in response to a request for counting heartbeats. I’m waiting to hear back from that user, but I think it should work quite well for that purpose.

For use with music this plug-in is extremely limited as it currently is. To be really useful it would need to have much more sophisticated beat detection. Currently it detects a beat when the amplitude exceeds the threshold value. A long sustained high amplitude sound would be counted as one beat. It takes no account of rhythm so a rhythm of “beat-rest-rest-beat” would be counted as 2 beats rather than 4. If the selection includes silence before or after the actual recording, then this will throw the BPM calculation way out.

When testing on a click track, a 60 second sample was sufficient to provide accuracy of +/- 1 BPM. I think it is necessary to have some limit on the maximum duration that is analysed, and this will be particularly true if a more sophisticated (much slower and heavier on RAM) beat detection algorithm is used, but for now I’ve increased the max up to 10 minutes which still completes in a reasonable time.

Nyquist plug-ins can only return 1 result, so a label track OR text in a dialogue box may be returned.
However, a Nyquist plug-in can return a label track (or sound) AND output text into the debug window (requires that the Debug button is pressed).

As I’m sure you figured, I’d be happy to replace the beat.ny shipped in Audacity with something “better”. More accurate detection would be just part of the aim. Could you make user-intelligible debug output that just said “BPM was detected as x”, then labelled the detected beats?


Gale

Accurate beat detection is very tricky.

I could quite easily add a “beat count” to the Debug window of beat.ny, or adapt this BPM counter so that it outputs labels and shows the BPM in the Debug window.
The main problem with both of these ideas is that beat detection for music is very poor with both of these plug-ins. The number of missed beats and additional false beats will make the BPM count hopelessly inaccurate.

I think that what is required is:
a) Much more accurate beat detection (very tricky).
b) Analysis of the detected beats that will reject false beats and calculate probable missing beats (very tricky).

This code pulls out beats pretty well in some music (mono track only):

(defun filter (s-in)
  (highpass8 (lp s-in 2000) 40))

(defun track (s-in)
  (mult 100.0
  (snd-avg (filter s-in) 100 100 op-average)))

(force-srate *sound-srate* 
  (hp (snd-chase (track s) 0.001 0.5) 20))

Using a tweaked version of the code in my last post:
tracks000.png
Track1. Detected beats with the new code.
Track 2. A click track at the same tempo as the music.
Track 3. The music being analysed.
Track 4. Output from beat.ny.

The new code has picked out the beats pretty well, but has included a half-beat and a couple of “phantom” beats.
beat.ny has missed the first couple of beats entirely, but then added lots of phantom beats toward the end of the selection.

Thanks, Steve. It looks quite promising. Any plug-in that output BPM count (in a debug window) and labels, and was even slightly more accurate than beat.ny would be an improvement.

How much of the detection problem is with setting the threshold correctly? Would a “pre-analysis” of the peaks and RMS help in suggesting a threshold value?

Most users I guess would select the whole track, but on the assumption tempo in pop songs rarely changes, should they be encouraged in the “help” to select a small part of the track with a cleanly defined and loud solo pulse?



Gale

How about putting the BPM in the labels? (Disclaimer: I haven’t looked at how this plugin works, so I don’t know if the following is possible or reasonable) Thus, the current BPM could be shown - for example, it might be an increasing number if the selected audio is speeding up.

Edit: Punctuation.

I think it would make the labels rather cluttered. Even with just the number (eg, “140”) that would put 1680 characters into the label text for a 4 minute track if every beat was detected. It might be better to output a rolling average every 15 seconds or so. However the main problem at the moment is that for most music the bpm count is hopelessly inaccurate.

Hi.

How easy would it be for a combination of this nyquist plugin, and the equal labels one to be made?
I’d like a plugin where it prompts you for a BPM figure, you type it in, and then it makes a label at the beginning of every bar (or beat if Audacity can handle that many labels) for that BPM speed.

Could someone who’s really good at nyquist programming help me out? Thank you :slight_smile:

You can do that with Equal Label plug-in . All you need to do is work out 60/BPM (use a calculator if necessary).
For example, to mark every beat at 120 BPM:
60/120 = 0.5
Enter 0.5 as the “Label Interval” in the Equal Label plug-in.

That’s what I thought :slight_smile: Already tried doing that, but I can’t seem to get the Equal Label plugin to accept values under 1 second :frowning:

Any other ideas?

Are you using the Regular Interval Labels distributed with Audacity 1.3.13 Beta? That will do what you want. If there is a specific label interval that is not producing correct labels, please specify the interval.


Gale

Ah. I was using an older version of the equal labels plugin. Extracted the latest version from the Audacity 1.3.13 deb and now it works and accepts decimal values. Cheers :slight_smile:

Keep in mind that if “Final audio segment equal with others?” is set to “yes” (it is by default) then the intervals won’t have the specified length but something pretty close to it (so a final label could be placed precisely at the end of the selected track). I had a hard time figuring out why 1.85 produced exactly the same labels as 1.86 (on my track) which of course should make quite a difference after just a few bars.

So if you want the interval length to be exactly the specified number you need to disable this option.

You’ve not got the current version of Equal labels.
Which version of Audacity do you have? (look in “Help menu > About Audacity” for the full version number)

1.3.13-beta (Unicode)

I’m just getting started with Audacity, having downloaded it two days ago. Should I have downloaded version 1.2.6 instead?

Good, that’s the correct version of Audacity.

My mistake, it appears that the latest version of equal labels has not been released yet.
If you’d like to try the latest, (not yet released) version, here’s the download link: http://forum.audacityteam.org/download/file.php?id=3270
This version of Regular Interval Labels will be included in Audacity 1.3.14 and is described in the on-line manual here: http://manual.audacityteam.org/man/Analyze_Menu#interval_labels

Ah, the description seems much better in this version. I suppose if I had started with this one I wouldn’t have spent an hour digging into the code (and mainly trying to learn lisp in the first place). I’ve learned a lot though. :slight_smile:

Thanks for your replies.