Skip to content

Instantly share code, notes, and snippets.

@rriemann
Created April 20, 2016 16:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save rriemann/286dc826b0457fc071fa84faf6a8f6ef to your computer and use it in GitHub Desktop.
Save rriemann/286dc826b0457fc071fa84faf6a8f6ef to your computer and use it in GitHub Desktop.
BPM Tags
#!/bin/sh
#
# Copyright (C) 2013 Mark Hills <mark@xwax.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2, as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License version 2 for more details.
#
# You should have received a copy of the GNU General Public License
# version 2 along with this program; if not, write to the Free
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
# Analyse an audio file and add BPM metadata
#
set -e
usage()
{
cat <<END
bpm-tag (C) Copyright 2013 Mark Hills <mark@xwax.org>
Usage: bpm-tag [options] <file>
Tag an audio file with tempo (in beats-per-minute, BPM)
-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
See the bpm-tag(1) man page for more information and examples.
END
}
# Parse command line arguments
FORCE=false
WRITE=true
ARGS=""
while getopts "fhnm:x:" OPT; do
case "$OPT" in
f)
FORCE=true
;;
n)
WRITE=false
;;
m)
ARGS="$ARGS -m $OPTARG"
;;
x)
ARGS="$ARGS -x $OPTARG"
;;
h)
usage
exit 0
;;
?)
exit 1
esac
done
shift $((OPTIND - 1))
if [ -z "$1" ]; then
usage >&2
exit 1
fi
set -u
FILE="$1"
shift
# Don't overwrite an existing BPM tag
case "$FILE" in
*.flac)
BPM=`metaflac --show-tag=BPM "$FILE" | sed -e 's/BPM=//'`
;;
*.mp3)
BPM=`mid3v2 --list "$FILE" | sed -n 's/^TBPM.*: \([0-9\.]\+\)/\1/p'`
;;
*.ogg)
BPM=`vorbiscomment "$FILE" | sed -n 's/^BPM=//p'`
;;
*)
echo "$FILE: file extension not known" >&2
exit 1
;;
esac
if [ -n "$BPM" ] && ! $FORCE; then
echo "$FILE: already tagged, $BPM BPM" >&2
exit 1
fi
# Analyse the BPM
BPM=`sox -V1 "$FILE" -r 44100 -e float -c 1 -t raw - | bpm $ARGS`
if [ -z "$BPM" ]; then
exit 1
fi
echo "$FILE: $BPM BPM" >&2
if ! $WRITE; then
exit 0
fi
# Write a BPM tag
case "$FILE" in
*.flac)
metaflac --remove-tag=BPM --set-tag="BPM=$BPM" "$FILE"
;;
*.mp3)
mid3v2 --TBPM "$BPM" "$FILE"
;;
*.ogg)
vorbiscomment -at "BPM=$BPM" "$FILE"
;;
*)
echo "$FILE: don't know how to tag this type of file" >&2
exit 1
esac
@kennyboy1978
Copy link

kennyboy1978 commented Apr 2, 2020

I use the below script (based on bpm-tag itself) to check whether the BPM tag is either 0 or empty and then run bpm-tag to generate the tag. If there is a tag found greater than 0 it prints the value of the tag. I know I've gone the long way around (I could have just edited/branched the bpm-tag script) but I'm attempting to learn basic bash and wanted to create my own using bpm-tag as the main program, if that makes sense.

I presume you could use the variables "$FOUNDBPM" (The BPM in a numercial value) and "${FILE%/*}" (The filename of the file being scanned) in your script ?

#!/bin/bash

find "$1" -type f ( -name ".mp3" -o -name ".flac" ) | while read -r FILE; do

case "$FILE" in
*.flac)
FOUNDBPM=$(metaflac --show-tag=BPM "$FILE" | sed -e 's/BPM=//')
;;
.mp3)
FOUNDBPM=$(mid3v2 -l "$FILE" | sed -En 's/^TBPM=([[:digit:].]+).
/\1/p')
;;
esac

if [ 0 == "$FOUNDBPM" ] || [ -z "$FOUNDBPM" ]
then
echo "${FILE%/}" contains a track that is has no BPM set, now running bpm-tag.
bpm-tag -f -m 120 -x 250 "$FILE"
else
echo "${FILE%/
}" has already been given the value of "$FOUNDBPM" BPM
fi
done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment