Amarok 2は、ID3v2タグの「bpm」フィールドを使用して音楽コレクションを検索できます。それはvery音楽コレクション全体のタグを付け直して、気に入ったトラックの「気分」を見つけられるようにするのがいいでしょう。
しかし、私を助けることができたビート検出ソフトウェアは見つかりませんでした。使用したことがありますか? CLI、できれば。また、同じ「bpm」フィールドを使用してFLACにタグを付ける方法に似たものがあるかどうかにも興味があります。
ありがとう! :)
追伸Niceムードバー機能があることは知っていますが、検索には役に立ちません。
サイトでDaveParilloが BpmDj プロジェクトを見つけたと提案しました。これには、bpmを非常に計算するbpmcount
実行可能ファイルがあります。mp3とflacを処理します。
161.135 Metallica/2008 - Death Magnetic/01-That Was Just Your Life.flac
63.5645 Doom3.mp3
残っているのは、コレクションのタグを付け直すことだけです。成功したらいつでもこの答えを更新します。ありがとう! :)
ステップ1
コレクション全体に対してbpmcount
を実行し、結果をテキストファイルに保存します。問題は、bpmcount
が時々クラッシュし、複数のファイルを処理するときに最大2GBのメモリを消費しようとするため、ファイル名を1つずつフィードする必要があることです。このような:
musicdir='/home/ootync/music'
find "$musicdir" -iregex ".*\.\(mp3\|ogg\|flac\|ape\)" -exec bpmcount {} \; \
| fgrep "$musicdir" > "$musicdir/BPMs.txt"
ステップ2
追加のパッケージが必要です:apt-get install vorbis-tools flac python-mutagen
。 「bpm」タグを追加する方法を見てみましょう。
mid3v2 --TBPM 100 Doom3.mp3
vorbiscomment -a -t "BPM=100" mother.ogg
metaflac --set-tag="BPM=100" metallica.flac
残念ながら、*。apeトラックはありません
これでBPMが作成され、コレクション全体にタグを付け直す必要があります。スクリプトは次のとおりです。
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
Step 2.1 Revisitedこれは、BPMタグをコレクションに追加するスクリプトです。
CPUコアごとに1つのプロセスを実行して、プロセスを高速化します。さらに、一時ファイルを使用せず、ファイルが既にタグ付けされているかどうかを検出できます。
さらに、FLACにはID3とVorbisCommentの両方が含まれていることがあります。このスクリプトは両方を更新します。
#!/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
楽しい! :)
これは、BPMを検出してFLACファイルタグに入れるコマンドラインツールです。
私はbpmcount
を使用してkolyptoの元のスクリプトを使用し、bpm-tag
(bpm-tools
のユーティリティ)に書き換えて、インストールに成功した。私はまた、私自身のいくつかの改善を行いました。
GitHubで見つけることができます https://github.com/meridius/bpmwrap
私はあなたが探しているものを正確に実行するツールを知りませんが、私は MusicIP をいじってみました。
Linuxを使用した/ Javaバージョン-音楽ライブラリを完全に分析するには長い時間がかかりますが、実際には機能します。他の曲に類似した曲を見つけることができます。右クリックしてください。生成されたプレイリストと選択したオプションのように選択した曲の数を増やしたり減らしたりするオプションもあります。特定のジャンルを削除するように選択することもできます。それは一種のクールですが、すごい要素が消えた後、私はその使用をやめました。
無料版は、最大75曲のプレイリストを(少なくとも)m3u形式でエクスポートします。
現在はサポートされていませんが、 Predexis として商用化しようとしていると思います。
あなたが探していると言っているようなツールではありませんが、 Bansheeメディアプレーヤー はbpmを検出できます。
私はすべての音楽の再生、整理、およびポータブルプレーヤーとの同期にBansheeを使用しています。私は提携していませんが、私が試したすべてのプログラムの中で一番気に入っています。また、bpmを含む、トラックのあらゆる種類のプロパティに基づいて「スマートプレイリスト」を生成することもできます。
曲に関するあらゆる種類のことを分析し、演奏している曲に似た曲を見つける拡張機能があります。それは Mirage と呼ばれ、私はしばらく使用しましたが、さまざまな気分に合うものの再生リストをいくつか作成したので、もう使用しません(Mirageによると必ずしも同じではありません)。 。
Bansheeが検出したbpmをファイルのID3v2の「bpm」タグに保存するかどうかはわかりません。プログラムの外部からbpmタグを簡単に確認する方法を誰かが知っている場合は、確認します。
Linuxではありませんが、Wineでうまく機能する可能性があります-私は MixMeister BPM Analyzer を使用します
Macで@meridius 'ソリューションを機能させるには、少し手間をかけ、スクリプトを少し変更する必要がありました。
# Let's install bpm-tools
git clone http://www.pogo.org.uk/~mark/bpm-tools.git
cd bpm-tools
make && make install
# There will be errors, but they did not affect the result
# The following three lines could be replaced by including this directory in your $PATH
ln -s <absolute path to bpm-tools>/bpm /usr/local/bin/bpm
ln -s <absolute path to bpm-tools>/bpm-tag /usr/local/bin/bpm-tag
ln -s <absolute path to bpm-tools>/bpm-graph /usr/local/bin/bpm-graph
cd ..
# Time to install a bunch of GNU tools
# Not all of these packages are strictly necessary for this script, but I decided I wanted the whole GNU toolchain in order to avoid this song-and-dance in the future
brew install coreutils findutils gnu-tar gnu-sed gawk gnutls gnu-indent gnu-getopt bash flac vorbis-tools
brew tap homebrew/dupes; brew install grep
# Now for Mutagen (contains mid3v2)
git clone https://github.com/nex3/mutagen.git
cd mutagen
./setup.py build
Sudo ./setup.py install
# There will be errors, but they did not affect the result
cd ..
次に、GNU=すべてのバージョン、およびその他のいくつかの微調整を指すようにスクリプトを変更する必要がありました。
#!/usr/local/bin/bash
# ================================= FUNCTIONS =================================
function help() {
less <<< 'BPMWRAP
Description:
This BASH script is a wrapper for bpm-tag utility of bpm-tools and several
audio tagging utilities. The purpose is to make BPM (beats per minute)
tagging as easy as possible.
Default behaviour is to look through working directory for *.mp3 files
and compute and print their BPM in the following manner:
[current (if any)] [computed] [filename]
Usage:
bpmwrap [options] [directory or filenames]
Options:
You can specify files to process by one of these ways:
1) state files and/or directories containing them after options
2) specify --import file
3) specify --input file
With either way you still can filter the resulting list using --type option(s).
Remember that the script will process only mp3 files by default, unless
specified otherwise!
-i, --import file
Use this option to set BPM tag for all files in given file instead of
computing it. Expected format of every row is BPM number and absolute path
to filename separated by semicolon like so:
145;/home/trinity/music/Apocalyptica/07 beyond time.mp3
Remember to use --write option too.
-n, --input file
Use this option to give the script list of FILES to process INSTEAD of paths
where to look for them. Each row whould have one absolute path.
This will bypass the searching part and is that way useful when you want
to process large number of files several times. Like when you are not yet
sure what BPM limits to set. Extension filtering will still work.
-o, --output file
Save output also to a file.
-l, --list-save file
Save list of files about to get processed. You can use this list later
as a file for --input option.
-t, --type filetype
Extension of file type to work with. Defaults to mp3. Can be specified
multiple times for more filetypes. Currently supported are mp3 ogg flac.
-e, --existing-only
Only show BPM for files that have it. Do NOT compute new one.
-w, --write
Write computed BPM to audio file but do NOT overwrite existing value.
-f, --force
Write computed BPM to audio file even if it already has one. Aplicable only
with --write option.
-m, --min minbpm
Set minimal BPM to look for when computing. Defaults to bpm-tag minimum 84.
-x, --max maxbpm
Set maximal BPM to look for when computing. Defaults to bpm-tag maximum 146.
-v, --verbose
Show "progress" messages.
-c, --csv-friendly
Use semicolon (;) instead of space to separate output columns.
-h, --help
Show this help.
Note:
Program bpm-tag (on whis is this script based) is looking only for lowercase
file extensions. If you get 0 (zero) BPM, this should be the case. So just
rename the file.
License:
GPL V2
Links:
bpm-tools (http://www.pogo.org.uk/~mark/bpm-tools/)
Dependencies:
bpm-tag mid3v2 vorbiscomment metaflac
Author:
Martin Lukeš ([email protected])
Based on work of kolypto (http://superuser.com/a/129157/137326)
'
}
# Usage: result=$(inArray $needle haystack[@])
# @param string needle
# @param array haystack
# @returns int (1 = NOT / 0 = IS) in array
function inArray() {
needle="$1"
haystack=("${!2}")
out=1
for e in "${haystack[@]}" ; do
if [[ "$e" = "$needle" ]] ; then
out=0
break
fi
done
echo $out
}
# Usage: result=$(implode $separator array[@])
# @param char separator
# @param array array to implode
# @returns string separated array elements
function implode() {
separator="$1"
array=("${!2}")
IFSORIG=$IFS
IFS="$separator"
echo "${array[*]}"
IFS=$IFSORIG
}
# @param string file
# @returns int BPM value
function getBpm() {
local file="$1"
local ext="${file##*.}"
declare -l ext # convert to lowercase
{ case "$ext" in
'mp3') mid3v2 -l "$file" ;;
'ogg') vorbiscomment -l "$file" ;;
'flac') metaflac --export-tags-to=- "$file" ;;
esac ; } | fgrep 'BPM=' -a | cut -d'=' -f2
}
# @param string file
# @param int BPM value
function setBpm() {
local file="$1"
local bpm="${2%%.*}"
local ext="${file##*.}"
declare -l ext # convert to lowercase
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
}
# # @param string file
# # @returns int BPM value
function computeBpm() {
local file="$1"
local m_opt=""
[ ! -z "$m" ] && m_opt="-m $m"
local x_opt=""
[ ! -z "$x" ] && x_opt="-x $x"
local row=$(bpm-tag -fn $m_opt $x_opt "$file" 2>&1 | fgrep "$file")
echo $(echo "$row" \
| gsed -r 's/.+ ([0-9]+\.[0-9]{3}) BPM/\1/' \
| gawk '{printf("%.0f\n", $1)}')
}
# @param string file
# @param int file number
# @param int BPM from file list given by --import option
function oneThread() {
local file="$1"
local filenumber="$2"
local bpm_hard="$3"
local bpm_old=$(getBpm "$file")
[ -z "$bpm_old" ] && bpm_old="NONE"
if [ "$e" ] ; then # only show existing
myEcho "$filenumber/$NUMFILES${SEP}$bpm_old${SEP}$file"
else # compute new one
if [ "$bpm_hard" ] ; then
local bpm_new="$bpm_hard"
else
local bpm_new=$(computeBpm "$file")
fi
[ "$w" ] && { # write new one
if [[ ! ( ("$bpm_old" != "NONE") && ( -z "$f" ) ) ]] ; then
setBpm "$file" "$bpm_new"
else
[ "$v" ] && myEcho "Non-empty old BPM value, skipping ..."
fi
}
myEcho "$filenumber/$NUMFILES${SEP}$bpm_old${SEP}$bpm_new${SEP}$file"
fi
}
function myEcho() {
[ "$o" ] && echo -e "$1" >> "$o"
echo -e "$1"
}
# ================================== OPTIONS ==================================
eval set -- $(/usr/local/Cellar/gnu-getopt/1.1.6/bin/getopt -n $0 -o "-i:n:o:l:t:ewfm:x:vch" \
-l "import:,input:,output:,list-save:,type:,existing-only,write,force,min:,max:,verbose,csv-friendly,help" -- "$@")
declare i n o l t e w f m x v c h
declare -a INPUTFILES
declare -a INPUTTYPES
while [ $# -gt 0 ] ; do
case "$1" in
-i|--import) shift ; i="$1" ; shift ;;
-n|--input) shift ; n="$1" ; shift ;;
-o|--output) shift ; o="$1" ; shift ;;
-l|--list-save) shift ; l="$1" ; shift ;;
-t|--type) shift ; INPUTTYPES=("${INPUTTYPES[@]}" "$1") ; shift ;;
-e|--existing-only) e=1 ; shift ;;
-w|--write) w=1 ; shift ;;
-f|--force) f=1 ; shift ;;
-m|--min) shift ; m="$1" ; shift ;;
-x|--max) shift ; x="$1" ; shift ;;
-v|--verbose) v=1 ; shift ;;
-c|--csv-friendly) c=1 ; shift ;;
-h|--help) h=1 ; shift ;;
--) shift ;;
-*) echo "bad option '$1'" ; exit 1 ;; #FIXME why this exit isn't fired?
*) INPUTFILES=("${INPUTFILES[@]}" "$1") ; shift ;;
esac
done
# ================================= DEFAULTS ==================================
#NOTE Remove what requisities you don't need but don't try to use them after!
# always mp3/flac ogg flac
REQUIRES="bpm-tag mid3v2 vorbiscomment metaflac"
which $REQUIRES > /dev/null || { myEcho "These binaries are required: $REQUIRES" >&2 ; exit 1; }
[ "$h" ] && {
help
exit 0
}
[[ $m && $x && ( $m -ge $x ) ]] && {
myEcho "Minimal BPM can't be bigger than NOR same as maximal BPM!"
exit 1
}
[[ "$i" && "$n" ]] && {
echo "You cannot specify both -i and -n options!"
exit 1
}
[[ "$i" && ( "$m" || "$x" ) ]] && {
echo "You cannot use -m nor -x option with -i option!"
exit 1
}
[ "$e" ] && {
[[ "$w" || "$f" ]] && {
echo "With -e option you don't have any value to write!"
exit 1
}
[[ "$m" || "$x" ]] && {
echo "With -e option you don't have any value to count!"
exit 1
}
}
for file in "$o" "$l" ; do
if [ -f "$file" ] ; then
while true ; do
read -n1 -p "Do you want to overwrite existing file ${file}? (Y/n): " key
case "$key" in
y|Y|"") echo "" > "$file" ; break ;;
n|N) exit 0 ;;
esac
echo ""
done
echo ""
fi
done
[ ${#INPUTTYPES} -eq 0 ] && INPUTTYPES=("mp3")
# NUMCPU="$(ggrep ^processor /proc/cpuinfo | wc -l)"
NUMCPU="$(sysctl -a | ggrep machdep.cpu.core_count | gsed -r 's/(.*)([0-9]+)(.*)/\2/')"
LASTPID=0
TYPESALLOWED=("mp3" "ogg" "flac")
# declare -A BPMIMPORT # array of BPMs from --import file, keys are file names
declare -A BPMIMPORT # array of BPMs from --import file, keys are file names
for type in "${INPUTTYPES[@]}" ; do
[[ $(inArray $type TYPESALLOWED[@]) -eq 1 ]] && {
myEcho "Filetype $type is not one of allowed types (${TYPESALLOWED[@]})!"
exit 1
}
done
### here are three ways how to pass files to the script...
if [ "$i" ] ; then # just parse given file list and set BPM to listed files
if [ -f "$i" ] ; then
# myEcho "Setting BPM tags from given file ..."
while read row ; do
bpm="${row%%;*}"
file="${row#*;}"
ext="${file##*.}"
ext="${ext,,}" # convert to lowercase
if [ -f "$file" ] ; then
if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then
FILES=("${FILES[@]}" "$file")
BPMIMPORT["$file"]="$bpm"
else
myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file"
fi
else
myEcho "Skipping non-existing file $file"
fi
done < "$i"
else
myEcho "Given import file does not exists!"
exit 1
fi
Elif [ "$n" ] ; then # get files from file list
if [ -f "$n" ] ; then
rownumber=1
while read file ; do
if [ -f "$file" ] ; then
ext="${file##*.}"
ext="${ext,,}" # convert to lowercase
if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then
FILES=("${FILES[@]}" "$file")
else
myEcho "Skipping file on row $rownumber (unwanted filetype $ext) ... $file"
fi
else
myEcho "Skipping file on row $rownumber (non-existing) ... $file"
fi
let rownumber++
done < "$n"
unset rownumber
else
myEcho "Given input file $n does not exists!"
exit 1
fi
else # get files from given parameters
[ ${#INPUTFILES[@]} -eq 0 ] && INPUTFILES=`pwd`
for file in "${INPUTFILES[@]}" ; do
[ ! -e "$file" ] && {
myEcho "File or directory $file does not exist!"
exit 1
}
done
impl_types=`implode "|" INPUTTYPES[@]`
while read file ; do
echo -ne "Creating list of files ... (${#FILES[@]}) ${file}\033[0K"\\r
FILES=("${FILES[@]}" "$file")
done < <(gfind "${INPUTFILES[@]}" -type f -regextype posix-awk -iregex ".*\.($impl_types)")
echo -e "Counted ${#FILES[@]} files\033[0K"\\r
fi
[ "$l" ] && printf '%s\n' "${FILES[@]}" > "$l"
NUMFILES=${#FILES[@]}
FILENUMBER=1
[ $NUMFILES -eq 0 ] && {
myEcho "There are no ${INPUTTYPES[@]} files in given files/paths."
exit 1
}
declare SEP=" "
[ "$c" ] && SEP=";"
# =============================== MAIN SECTION ================================
if [ "$e" ] ; then # what heading to show
myEcho "num${SEP}old${SEP}filename"
else
myEcho "num${SEP}old${SEP}new${SEP}filename"
fi
for file in "${FILES[@]}" ; do
[ `jobs -p | wc -l` -ge $NUMCPU ] && wait
[ "$v" ] && myEcho "Parsing (${FILENUMBER}/${NUMFILES})\t$file ..."
oneThread "$file" "$FILENUMBER" "${BPMIMPORT[$file]}" &
LASTPID="$!"
let FILENUMBER++
done
[ "$v" ] && myEcho "Waiting for last process ..."
wait $LASTPID
[ "$v" ] && myEcho \\n"DONE"
@kolyptoと@meridiusにご尽力いただきありがとうございます。
... CLIワークフローを維持し、音楽ツールにお金を払わなくても済むまでの苦痛...
正しいBPM値でMP3ファイルにタグを付けるための別のツールを見つけました。
BPMDetect と呼ばれます。オープンソース。 QT libsはGnomeでうまく動作します。 GUIが付属していますが、コンソールのみのバージョンとしてコンパイルできます(readme.txtに記載されている「scons console = 1」を実行します)。
それ以外の場合は、64ビットのUbuntuホストでBPMDetectをコンパイルするのが(fmodexに依存するため)困難だったため、結局、BpmDJの「bpmcount」も使用しました。上記の(非常にクールでよく書かれた)シェルスクリプト(下記を参照)を使用しました。BpmDJWebサイトから入手可能な[x64 .rpm] [3]から抽出された「bpmcount」バイナリ(私は.rpmを抽出しただけです)と
pm2cpio bpmdj-4.2.pl2-0.x86_64.rpm|cpio -idv
そしてそれは魅力のように働きました。私は上記のスクリプトを変更しなければならなかったので、そのままでは私の側では機能していませんでした(bpmcountバイナリのstdout/stderrの問題)。私の変更はファイルのリダイレクトに関するものです:
local bpm=$(bpmcount "$file" 3>&1 1>/dev/null 2>&3 | grep '^[0-9]' | cut -f1)
Stackoverflowの この質問 で推奨される別のツールがあります: aubio 、これはpythonモジュールに付属しています。
コンパイルBpmDjの処理に忙しいので、まだ試していません。他の誰かが同様のトラブルに苦労していることに気づいた場合に備えて、私は絶対に確認することを強くお勧めします:
最新のg ++コンパイラのアップグレードでは、特に最近のdebianおよびubuntuリリースに関していくつかの問題が発生しているようです。彼がこれらの問題に気づくやいなや、著者は、現れた非互換性を修正し、今や魅力のようにコンパイルされる新しいリリースをまとめる親切になりました。したがって、最近の容赦のないコンパイルエラーで絶望に陥っている人は誰でもいます。あなたは今、救われています。
@mmx、ツールも見た目は良いですが、SoX
に依存しています。デフォルトでは、mp3機能はありません。したがって、最初にLaX/MADサポートを使用してSoXをコンパイルする必要があります。これは、残念なことに、私と同じぐらい怠惰な人々にとってはあまりにも多くの労力です。