Actions to modify BPM: Double, Half, Round to Integer

There seems to be some need for reliably changing the BPM tag (TBPM, Beats Per Minute) and I've seen some unreliable code out there, so I came up with some Action Groups to do the following:

  1. Double the BPM value. In case your BPM Analyzer has detected only half the rate. Knowingly creates the much-used (but technically illegal) xxx.xx format.
  2. Reduce the BPM value by one half. In case your BPM Analyzer has detected double the rate. Knowingly creates the much-used (but technically illegal) xxx.xx format.
  3. Round fractioned BPM to Integer value. To put BPM back to an integer value, if your mixer application doesn’t support fractioned BPM values. Fractional values will be rounded to the next integer. (Makes an ID3v2 standards conformant xxx format.)
All 3 action groups are tested and found robust to handle real-life data. They will graciously handle input formats like xxx, xxx.xx, .xx, xxx., xxx.x, xxx.xxx…. All are based on the same code fragments (actions) but separated into 2 or 3 single actions per group so that you can easily make your own changes (i.e., store BPM as integer BPM*100, a format that some rare software uses). If you use any of these on a file that doesn’t (yet) contain a BPM tag, one will be created with BPM set to zero (0 or 0.00).

Now here’s the code. I assume that you are comfortable modifying the column view and setting up actions and action groups. If not, please study the help/manual.

I strongly recommend setting up an extra column containing the BPM field so that you can actually see and follow the changes!

Action Group »BPM Double«

Format value:
Field: BPM
Format string: $if($grtr($strchr(%BPM%,'.'),0),$add($mul($left(%BPM%,$sub($strchr(%BPM%,'.'),1)),100),$left($mid(%BPM%,$add($strchr(%BPM%,'.'),1),2)00,2)),$mul(%BPM%,100))

Format value:
Field: BPM
Format string: $mul(%BPM%,2)

Format value:
Field: BPM
Format string: $ifgreater(%BPM%,0,$left(%BPM%,$sub($len(%BPM%),2)).$right(%BPM%,2),0.00)

Action Group »BPM Half«

Format value:
Field: BPM
Format string: $if($grtr($strchr(%BPM%,'.'),0),$add($mul($left(%BPM%,$sub($strchr(%BPM%,'.'),1)),100),$left($mid(%BPM%,$add($strchr(%BPM%,'.'),1),2)00,2)),$mul(%BPM%,100))

Format value:
Field: BPM
Format string: $div(%BPM%,2)

Format value:
Field: BPM
Format string: $ifgreater(%BPM%,0,$left(%BPM%,$sub($len(%BPM%),2)).$right(%BPM%,2),0.00)

Action Group »BPM Round to Integer«

Format value:
Field: BPM
Format string: $if($grtr($strchr(%BPM%,'.'),0),$add($mul($left(%BPM%,$sub($strchr(%BPM%,'.'),1)),100),$left($mid(%BPM%,$add($strchr(%BPM%,'.'),1),2)00,2)),$mul(%BPM%,100))

Format value:
Field: BPM
Format string: $div($add(%BPM%,50),100)

As you can see, the first action is always the same: It reads an existing BPM value and stores it back as an integer BPM100 value (i.e., 123.45 becomes 12345). The second action does something to the BPM value, i.e. multiplying it by 2, dividing it by 2, or rounding it to the nearest full integer. The third action (if used) converts the integer BPM100 result back into the xxx.xx format, which is (strictly spoken) »illegal« in ID3v2 but nevertheless used in this form by many applications. (And besides, as any good DJ will tell you, they need about 0.05 BPM precision anyway.) So we knowingly violate the specs here (and hope they come up with a redefinition at some point in time.

If you want to strictly adhere to the spec, you can always use the »BPM Round to Integer« action group after doing your other changes.

Voilà! BPMs made easy!

Hope you can use and enjoy these.

A word of caution for Mixmeister BPM Analyzer users:
Mixmeister BPM Analyzer always stores the BPM as an ID3v2.3 UTF-16 TBPM tag and MP3Tag will probably not show you that! Also, there is a known issue with Mixmeister corrupting cover images if ID3v2.4 is used. So if you are using ID3v2.3 and ISO-8859-1 encoding or ID3v2.4 and UTF-8 encoding, you will have some problems! Seen technically, it is perfectly legal to mix a zillion encodings in one file, but from a practical standpoint, it’s pure nonsense—you’ll end up with a lot of hard to diagnose problems.

If you don’t already have the TBPM tag in your file, Mixmeister will add one PLUS write back all your tags as ID3v2.3 with UTF-16 encoding. All without asking or any configuration options.

So my advice is: You can use Mixmeister BPM Analyzer (it’s one of the most accurate BPM detectors around) but you should have set up your MP3Tag to save the kind of tags you need and in any case re-save your tags with MP3Tag after using Mixmeister! (Simply select one, several or all files and press Ctrl-S for Save, or use the diskette symbol in the toolbar.)

Oh, well. I remember that someone wanted to round their BPM values to 10's values, i.e. only »groups« like 80, 90, 100, 110, …

Just to make things complete (and as an example how you can modify these), here’s the code:

Action Group »BPM Round to Tens«

Format value:
Field: BPM
Format string: $if($grtr($strchr(%BPM%,'.'),0),$add($mul($left(%BPM%,$sub($strchr(%BPM%,'.'),1)),100),$left($mid(%BPM%,$add($strchr(%BPM%,'.'),1),2)00,2)),$mul(%BPM%,100))

Format value:
Field: BPM
Format string: $div($sub($add(%BPM%,500),$mod($add(%BPM%,500),1000)),100)

Have fun!

Someone has been asking for »How to make fractional (xxx.xx) BPM values from whole numbers?«. Easy: Take above »BPM Double« or »BPM Half« example and just leave out the middle action, i.e. leave out the calculation part:

Action Group »BPM convert to fractional (xxx.xx)«

Format value:
Field: BPM
Format string: $if($grtr($strchr(%BPM%,'.'),0),$add($mul($left(%BPM%,$sub($strchr(%BPM%,'.'),1)),100),$left($mid(%BPM%,$add($strchr(%BPM%,'.'),1),2)00,2)),$mul(%BPM%,100))

Format value:
Field: BPM
Format string: $ifgreater(%BPM%,0,$left(%BPM%,$sub($len(%BPM%),2)).$right(%BPM%,2),0.00)

This will convert your BPM from almost any format (xxx, xxx.x, xxx.xxx) into xxx.xx (fractional, 2 decimal digits of precision).

Thanks for the actions,

I'm experimenting with them now but I have one question.

Is there a way to include if logic (not sure about the syntax) to do something like this in the second action?

IF BPM > 100
Then Half it.

Otherwise do nothing.

Since I know most (if not all) my songs are say less than 100, I can select all of them and have mp3 tag do all the work for me, instead of me having to manually select the obvious erroneous (double) bpm'd songs.

Thanks!

Sure thing, with MP3Tag you can do almost anything you want :slight_smile:

Make a copy of the Action Group »BPM Half« above, maybe name it »BPM Half if over 100«, then change the second action in the group as follows:

$ifgreater(%BPM%,10000,$div(%BPM%,2),%BPM%)

(We need to test for > 10000 here since we have converted BPM to BPM*100 as an integer value in the action before.)

A word of caution: I recommend being very careful with »generalized« changes like that—you might change a lot of songs whose BPM really are above 100.

how about if the decimal is <.05 then truncate or if >.95, then round up?

Hi Moonbase - Thanks for these actions - really useful!

I have one issue, most tracks have correct BPM, but I have now a selection of tracks where the BPM appears to have been multiplied by a factor of 10, eg 92.25 is now 922.50

Have I done something wrong (I've copied your code without changes) or is there another action I can apply to the divide BPM by a factor of 10?

Thanks for your help!

It is ery hard to tell from the distance what has gone wrong.
I think that iTunes ignores bpms with decimals (at least that was it like some versions ago and I never checked again). So it would be just as good to remove these fragments altogether.

To move the decimal point left use the following action:
Replace with regular expression for bpm
Search string: (\d).(\d)
Repace string: .$1$2