I spent the better part of a year (in my spare time) organizing my music collection. With my music carefully organized and accurately tagged, I found myself wanting the Beats Per Minute (BPM) for some of my music and realized that BPM can be included in the ID3 tags of MP3 files or the Vorbis tags of FLAC files. My default music player, Clementine, which hasn’t seen updates for quite some time and may be due to be replaced by an updated player, allows me to display BPM but doesn’t have a feature to calculate BPM for a song. Clementine also won’t allow me to edit the BPM that is part of the tags for any given song.
I spent some time trying to figure out how to go about adding the BPM for songs and eventually, after several days of searching, I came across some solutions, but they were kind of scattered across a number of websites and confusing. So, I figured I should put together a post on how to: (a) calculate BPM for a song (MP3 or FLAC), (b) show how to add the BPM to the tags, (c) show how to batch calculate BPM and add it to tags, and (d) show how to recurse through several folders calculating the BPM and adding it to tags.
(NOTE: I’m doing all of this on Kubuntu 22.04.)
Calculating BPM
It turns out, there is a super simple Beats Per Minute (BPM) calculator for linux: bpm-tools. Install it with:
sudo apt-get install bpm-tools
Using bpm-tools is super easy and it’s surprisingly effective. Let’s say that I want to calculate the BPM for the song Dancing Queen by ABBA. Open a Konsole and enter the directory where the song is. Then use the following line of code:
bpm-tag -n DancingQueen.mp3
Let’s break down what this command does. “bpm-tag” calls the bpm-tools software. The “-n” tells it to just display the BPM but not add it to the tag. Finally, the name of the music file comes last. Here’s the result of that command when I ran it:
ryan@ryan-desktop:~/Desktop/ABBA$ bpm-tag -n DancingQueen.mp3
DancingQueen.mp3: 100.605 BPM
There’s the BPM listed: 100.605.
There are five options you can use with bpm-tag:
-f Ignore existing BPM value
-n Display BPM only, don’t tag
-m Minimum detected BPM
-x Maximum detected BPM
-h Display this help message and exit
If you want to go ahead and tag the song with the BPM, you can use the same code as above but swap out the “-n” with “-f” or, if there is no existing BPM tag, you can leave out the option altogether.
To illustrate that it adds the tag, I’m going to install another package that allows me to see tag information for MP3 files, eyeD3:
sudo apt-get install eyed3
Now, I’m going to use eyeD3 to view the tag information of Dancing Queen before I add the BPM tag:
eyeD3 DancingQueen.mp3
I used Picard to access MusicBrainz to tag my music as part of my music organization effort. As a result, I actually have lots of tags for this particular song. Here’s the output:
ryan@ryan-desktop:~/Desktop/ABBA$ eyeD3 DancingQueen.mp3
/home/ryan/Desktop/ABBA/DancingQueen.mp3 [ 8.85 MB ]
-------------------------------------------------------------------------------------------------------------------------------------------------------
Time: 03:52 MPEG1, Layer III [ 320 kb/s @ 44100 Hz - Dual channel stereo ]
-------------------------------------------------------------------------------------------------------------------------------------------------------
ID3 v2.3:
title: Dancing Queen
artist: ABBA
album: The Ultimate Collection
album artist: ABBA
release date: 1992
original release date: 1992
recording date: 2003
eyed3.id3:WARNING: Non standard genre name: Adult Contemporary
track: 1/20 genre: Adult Contemporary (id None)
disc: 3/4
Popularity: [email: b''] [rating: 0] [play count: 1]
Publisher/label: Reader's Digest
Unique File ID: [b'http://musicbrainz.org'] : a502f559-f70c-4e0d-a5e5-e0cc319d0bd7
UserTextFrame: [Description: SCRIPT]
Latn
UserTextFrame: [Description: ARTISTS]
ABBA
UserTextFrame: [Description: FMPS_PlayCount]
1
UserTextFrame: [Description: originalyear]
1992
UserTextFrame: [Description: BARCODE]
0347120000009
UserTextFrame: [Description: CATALOGNUMBER]
B91001BK
UserTextFrame: [Description: FMPS_Rating_Amarok_Score]
0.5
UserTextFrame: [Description: MusicBrainz Album Status]
official
UserTextFrame: [Description: MusicBrainz Album Release Country]
GB
UserTextFrame: [Description: MusicBrainz Album Type]
album/compilation
UserTextFrame: [Description: MusicBrainz Album Id]
03e645f2-1d71-423f-bc6c-6dcb37793a9b
UserTextFrame: [Description: MusicBrainz Artist Id]
d87e52c5-bb8d-4da8-b941-9f4928627dc8
UserTextFrame: [Description: MusicBrainz Album Artist Id]
d87e52c5-bb8d-4da8-b941-9f4928627dc8
UserTextFrame: [Description: MusicBrainz Release Group Id]
dbf09c2a-5a16-36c0-b3f8-2025f0dd47aa
UserTextFrame: [Description: MusicBrainz Release Track Id]
b1034c39-63ee-3bbe-814b-bf4f51b9367d
-------------------------------------------------------------------------------------------------------------------------------------------------------
I’m not going to go through all of the tags but want to make it clear that BPM is not included. Now, I’ll use bpm-tag to calculate the BPM and add it to the file.
bpm-tag DancingQueen.mp3
Note that I didn’t include an option to, for instance, overwrite the BPM since there is not a current BPM in the ID3 tag. I just told bpm-tag to calculate the BPM and add it to the tags. Here’s the updated tag information using eyeD3:
ryan@ryan-desktop:~/Desktop/ABBA$ eyeD3 DancingQueen.mp3
/home/ryan/Desktop/ABBA/DancingQueen.mp3 [ 8.85 MB ]
---------------------------------------------------------------------------------------------------------------------------
Time: 03:52 MPEG1, Layer III [ 320 kb/s @ 44100 Hz - Dual channel stereo ]
---------------------------------------------------------------------------------------------------------------------------
ID3 v2.3:
title: Dancing Queen
artist: ABBA
album: The Ultimate Collection
album artist: ABBA
release date: 1992
original release date: 1992
recording date: 2003
eyed3.id3:WARNING: Non standard genre name: Adult Contemporary
track: 1/20 genre: Adult Contemporary (id None)
disc: 3/4
Popularity: [email: b''] [rating: 0] [play count: 1]
BPM: 101
Publisher/label: Reader's Digest
Unique File ID: [b'http://musicbrainz.org'] : a502f559-f70c-4e0d-a5e5-e0cc319d0bd7
UserTextFrame: [Description: SCRIPT]
Latn
UserTextFrame: [Description: ARTISTS]
ABBA
UserTextFrame: [Description: FMPS_PlayCount]
1
UserTextFrame: [Description: originalyear]
1992
UserTextFrame: [Description: BARCODE]
0347120000009
UserTextFrame: [Description: CATALOGNUMBER]
B91001BK
UserTextFrame: [Description: FMPS_Rating_Amarok_Score]
0.5
UserTextFrame: [Description: MusicBrainz Album Status]
official
UserTextFrame: [Description: MusicBrainz Album Release Country]
GB
UserTextFrame: [Description: MusicBrainz Album Type]
album/compilation
UserTextFrame: [Description: MusicBrainz Album Id]
03e645f2-1d71-423f-bc6c-6dcb37793a9b
UserTextFrame: [Description: MusicBrainz Artist Id]
d87e52c5-bb8d-4da8-b941-9f4928627dc8
UserTextFrame: [Description: MusicBrainz Album Artist Id]
d87e52c5-bb8d-4da8-b941-9f4928627dc8
UserTextFrame: [Description: MusicBrainz Release Group Id]
dbf09c2a-5a16-36c0-b3f8-2025f0dd47aa
UserTextFrame: [Description: MusicBrainz Release Track Id]
b1034c39-63ee-3bbe-814b-bf4f51b9367d
---------------------------------------------------------------------------------------------------------------------------
As you can see, the BPM has now been added to the song. And, importantly, none of the other tags were deleted or removed. Groovy!
Batch Add BPM
Adding the BPM to a song one at a time is great and all, but what if I want to add the BPM to an entire folder of files? It’s time for a bash script. Here’s the script I came up with to go through an entire folder, calculate the BPM, and add it to the tags. First, for MP3 files:
#!/bin/bash
# Directory containing music files
MUSIC_DIR="/home/ryan/Desktop/ABBA"
# Loop through each file in the directory
for file in "$MUSIC_DIR"/*.mp3; do
echo "Processing $file..."
# Calculate BPM
BPM=$(bpm-tag -f "$file")
echo "Calculated BPM: $BPM"
done
What does this script do? First, it tells the computer this is a bash script. Second, you have to set the directory where the music files are located. I was using ABBA for my test, so that is where it was pointed. I HIGHLY recommend that you test this with a copy of a folder of music before unleasing this script on a directory of music you don’t want to lose. Also, note that the directory doesn’t end with a “/”. I got tripped up there for a bit. Next is a loop that tells the computer to go through every MP3 file in the directory/folder where the music is stored. It will print out “Processing” followed by the name of the file for each file. Finally, it calculates the BPM for the file and, with the “-f” option in place, it will both write to the tags and, if a BPM tag is already calculated for that song and in the tags, it will overwrite it. The last line before ending the loop just prints out the calculated BPM for each song. I’d suggest testing this to make sure it works for you.
How do you run the script? Save the above script or code into a text file (on KDE, use Kate) and save it with the extension “.sh”. I called mine “bpm_mp3.sh”. Then, open a konsole and run the script with the following code:
sh bmp_mp3.sh
Since the location for the music is hard-coded into the script, it doesn’t actually matter where the script is stored or where you run it from. But that does mean you have to change the directory for your music every time you run the script (more on this below).
FLAC?
Now, for a twist. While slightly more than half of my music is in MP3 format, I also have a bunch of music in FLAC. Can we do the same things in FLAC? Yes, of course.
First, a quick note about reading the tags for FLAC. eyeD3 cannot read FLAC tags. Apparently, FLAC uses the Vorbis tag format, not ID3, which is for MP3 files. No worries. We just need a different package. Enter: “flac.” Included in the “flac” package is a function that allows you read and modify FLAC tags: metaflac. So, install “flac”:
sudo apt-get install flac
Now, to get all the tag information from a FLAC file requires you to export it to a file and then open that file. I’m using a different file with FLAC since my ABBA album is in MP3 – Hiraeth, by 100 Mile House. Here’s the code:
metaflac --export-tags-to=tags.tmp 02\ -\ Hiraeth.flac
nano tags.tmp
The first line calls the function, “metaflac,” and tells it to export all the tags to a file called “tags.tmp.” After the option for what you want metaflac to do is the name of the FLAC file, “02\ -\ Hiraeth.flac” (I have spaces in the file name, which is a pain for this, but so it goes.) The second line loads the “tags.tmp” file into the konsole so I can see the tags. Here is what I saw:
ALBUM=Hiraeth
ALBUMARTIST=100 Mile House
ALBUMARTISTSORT=100 Mile House
ARTIST=100 Mile House
ARTISTS=100 Mile House
ARTISTSORT=100 Mile House
DATE=2016-11-18
DISCNUMBER=1
DISCTOTAL=1
FMPS_PLAYCOUNT=2
FMPS_RATING_AMAROK_SCORE=0.75
GENRE=Folk
ISRC=CA4VC1600002
LABEL=Fallen Tree Records
LYRICS=Hiraeth
Long may our hope find a way to escape
The box in the hall where we hid it that day
Long may I see all she tries to hide
Long may she be right by my side
Long may the room where we sleep at night
Hold us in its arms when we lose sight
Long may we speak only honest words
Long may we beat the odds against us
Long may we go to the streets of this town
Our concrete home where we can be found
Long may we love with a fire in our hearts
Unafraid of the ones who put out the spark
Long may we know
Long may we know
Long may we know
Long may we know
Long live the night by the fire in the woods
Our hearts opened wide for all to look
MEDIA=Digital Media
MUSICBRAINZ_ALBUMARTISTID=e5b32dda-098b-442f-8c71-9264baafbecc
MUSICBRAINZ_ALBUMID=a7f05529-fc90-4ea3-9652-85853a5258e9
MUSICBRAINZ_ARTISTID=e5b32dda-098b-442f-8c71-9264baafbecc
MUSICBRAINZ_RELEASEGROUPID=118f5d0c-aa85-4c2c-a947-96286786fa86
MUSICBRAINZ_RELEASETRACKID=b7597318-aed2-4566-8030-b173a2bfa4f8
MUSICBRAINZ_TRACKID=4ec96812-69fe-4421-bfcd-8654419d927a
ORIGINALDATE=2016-11-18
ORIGINALYEAR=2016
RELEASECOUNTRY=CA
RELEASESTATUS=official
RELEASETYPE=album
TITLE=Hiraeth
TOTALDISCS=1
TOTALTRACKS=13
TRACKNUMBER=2
TRACKTOTAL=13
You can see I have a lot of information in the tags, including lyrics, but not BPM. I can add BPM for each song individually using bpm-tag just like I did above. To add the bpm-tag for the entire folder of music, I just have to change my script file from above like this:
#!/bin/bash
# Directory containing music files
MUSIC_DIR="/home/ryan/Desktop/Hiraeth"
# Loop through each file in the directory
for file in "$MUSIC_DIR"/*.flac; do
echo "Processing $file..."
# Calculate BPM
BPM=$(bpm-tag -f "$file")
echo "Calculated BPM: $BPM"
done
The only change to the script file is that it is going to look through the folder for every file that ends in “.flac” and then run the bpm-tag function on those files. If you check the FLAC tags after running this, you should see BPM listed for each song. I called this file “bpm_flac.sh” and ran it the same way I ran the script file above.
Command for Adding BPM to Files in Folders and Subfolders
While I’m not sure I necessarily recommend what I’m about to do and will warn you to do this only if you are fully aware that it could cause major problems if something goes wrong, you may also want a script file that runs through a series of folders looking for every MP3 or FLAC file, calculates the BPM, and tags it. Of course, that is possible as well. Here’s how you can do that assuming you have already installed bpm-tools as suggested above. Open a konsole, navigate to the parent folder (with all the subfolders underneath it) and run the following line of code for MP3s:
find . -name '*.mp3' -exec bpm-tag -f {} {}.mp3 \;
Here’s what this will do. “find” tells the computer to look for every file that matches some criteria. The “.” is part of the find function. The “-name ‘*.mp3’ is what you are looking for. It tells the computer to look in the name of the file for any file (the asterisk fills in the name of the individual files) that ends with “.mp3”. Next, once it finds a file, it will then execute (“-exec”) the following command. That command is the “bpm-tag” command with the “-f” option (so it will force a calculation of the BPM and writing that to the ID3 tag. The last part of the command is the brackets. The first set of brackets “{}” reflect the original name of the file and the second brackets followed by “{}.mp3” tell the computer what the output file should be called. Since we want to just add the BPM to existing files, we don’t want to change anything there. The last line and semi-colon end the function.
Some simple modifications will run the same operation on FLAC files:
find . -name '*.flac' -exec bpm-tag -f {} {}.flac \;
Once every file has been found, processed, and tagged, you can check to see if it worked by using the commands above to check the tags. As noted above, if you have all of your music stored in one folder and you have lots and lots of music, running this command could take a long, long time!
One final thought. Let’s say you were feeling adventurous and ran the above two commands on your massive collection of music, tagging all the songs in the process. But, then, you added some new music and didn’t add BPM to those new songs when you added them. You could also re-run the scripts above without the bpm-tag “-f” option. If you do, it won’t reprocess every file. It will just go through all the files, skipping the ones that are already tagged, and process and tag the ones that don’t have a BPM tag.
NOTE: When I was experimenting with my bash script, I did end up at one point installing two additional packages. Since I installed them before I got the script to work, I’m not sure if they are actually necessary for the bash script, but I want to make sure I note them here: “sox” and “libsox-fmt-all.”
Leave a Reply