Na stronie DaveParillo zasugerował, że znalazłem projekt BpmDj . Ma bpmcount
plik wykonywalny, który bardzo ładnie oblicza bpm: obsługuje mp3, a także flac:
161.135 Metallica/2008 - Death Magnetic/01-That Was Just Your Life.flac
63.5645 Doom3.mp3
Jedyne, co pozostało, to przebudować kolekcję. Zaktualizuję tę odpowiedź, ilekroć mi się uda. Dzięki! :)
Krok 1
Uruchom bpmcount
całą kolekcję i zapisz wyniki w pliku tekstowym. Problem polega na tym, że bpmcount
od czasu do czasu ulega awarii i próbuje zużyć do 2 GB pamięci, gdy przetwarza kilka plików, dlatego powinniśmy podawać je nazwami plików jeden po drugim. Lubię to:
musicdir='/home/ootync/music'
find "$musicdir" -iregex ".*\.\(mp3\|ogg\|flac\|ape\)" -exec bpmcount {} \; \
| fgrep "$musicdir" > "$musicdir/BPMs.txt"
Krok 2
Będziemy potrzebowali kilka dodatkowych pakietów: apt-get install vorbis-tools flac python-mutagen
. Zobacz, jak można dodać tag „bpm”:
mid3v2 --TBPM 100 doom3.mp3
vorbiscomment -a -t "BPM=100" mother.ogg
metaflac --set-tag="BPM=100" metallica.flac
Niestety, nie mam utworów * .ape
Teraz mamy BPM i cała kolekcja powinna zostać zmieniona. Oto skrypt:
cat "$musicdir/BPMs.txt" | while read bpm file ; do
bpm=`printf "%.0f" "$bpm"` ;
case "$file" in
*.mp3) mid3v2 --TBPM "$bpm" "$file" > /dev/null ;;
*.ogg) vorbiscomment -a -t "BPM=$bpm" "$file" ;;
*.flac) metaflac --set-tag="BPM=$bpm" "$file" ;;
esac
done
Krok 2.1 Powrót do strony
Oto skrypt, który doda tagi BPM do Twojej kolekcji.
Uruchamia jeden proces na rdzeń procesora, aby proces był szybszy. Ponadto nie używa plików tymczasowych i jest w stanie wykryć, czy plik jest już oznaczony.
Dodatkowo odkryłem, że FLAC czasami zawiera zarówno ID3, jak i VorbisComment. Ten skrypt aktualizuje oba.
#!/bin/bash
function display_help() {
cat <<-HELP
Recursive BPM-writer for multicore CPUs.
It analyzes BPMs of every media file and writes a correct tag there.
Usage: $(basename "$0") path [...]
HELP
exit 0
}
[ $# -lt 1 ] && display_help
#=== Requirements
requires="bpmcount mid3v2 vorbiscomment metaflac"
which $requires > /dev/null || { echo "E: These binaries are required: $requires" >&2 ; exit 1; }
#=== Functions
function bpm_read(){
local file="$1"
local ext="${file##*.}"
declare -l ext
# Detect
{ case "$ext" in
'mp3') mid3v2 -l "$file" ;;
'ogg') vorbiscomment -l "$file" ;;
'flac') metaflac --export-tags-to=- "$file" ;;
esac ; } | fgrep 'BPM=' | cut -d'=' -f2
}
function bpm_write(){
local file="$1"
local bpm="${2%%.*}"
local ext="${file##*.}"
declare -l ext
echo "BPM=$bpm @$file"
# Write
case "$ext" in
'mp3') mid3v2 --TBPM "$bpm" "$file" ;;
'ogg') vorbiscomment -a -t "BPM=$bpm" "$file" ;;
'flac') metaflac --set-tag="BPM=$bpm" "$file"
mid3v2 --TBPM "$bpm" "$file" # Need to store to ID3 as well :(
;;
esac
}
#=== Process
function oneThread(){
local file="$1"
#=== Check whether there's an existing BPM
local bpm=$(bpm_read "$file")
[ "$bpm" != '' ] && return 0 # there's a nonempty BPM tag
#=== Detect a new BPM
# Detect a new bpm
local bpm=$(bpmcount "$file" | grep '^[0-9]' | cut -f1)
[ "$bpm" == '' ] && { echo "W: Invalid BPM '$bpm' detected @ $file" >&2 ; return 0 ; } # problems
# Write it
bpm_write "$file" "${bpm%%.*}" >/dev/null
}
NUMCPU="$(grep ^processor /proc/cpuinfo | wc -l)"
find $@ -type f -regextype posix-awk -iregex '.*\.(mp3|ogg|flac)' \
| while read file ; do
[ `jobs -p | wc -l` -ge $NUMCPU ] && wait
echo "$file"
oneThread "$file" &
done
Cieszyć się! :)