Irgendeine Beat Detection Software für Linux? [geschlossen]

29

Amarok 2 kann die Musiksammlung mithilfe des Felds "bpm" des ID3v2-Tags durchsuchen. Das wäre sehr schön, wenn ich die gesamte Musiksammlung nachzeichnen könnte, damit ich die "Stimmung" des Titels finde, den ich mag.

Ich habe jedoch keine Beat-Detection-Software gefunden, die mir hätte helfen können. Hast du jemals einen benutzt? CLI, vorzugsweise. Ich bin auch daran interessiert, ob es etwas Ähnliches gibt, um FLACs mit demselben 'bpm'-Feld zu kennzeichnen.

Vielen Dank! :)

PS Mir ist bewusst, dass es eine nette Moodbar-Funktion gibt, die jedoch für die Suche unbrauchbar ist.

kolypto
quelle
3
hast du diese seite gesehen mmartins.com/mmartins/bpmdetection/bpmdetection.asp Scheint genau das zu sein, wonach Sie suchen.
DaveParillo
@ DaveParillo, dass "Stimmung eines Tracks" Link ist ein Link zu Ihrer Festplatte, und als solche für niemanden nutzlos, außer Sie
Justin Smith
@ Justin Smith, er meinte eine Datei in BpmDj docs :) Hier ist die Online-Version: bpmdj.yellowcouch.org/clustering.html
kolypto
@ Justin - sorry - nervöser Abzugsfinger, denke ich.
DaveParillo

Antworten:

17

Auf der Site schlug DaveParillo vor, ich hätte ein BpmDj- Projekt gefunden. Es hat eine bpmcountausführbare Datei, die die BPM sehr gut berechnet: Sie verarbeitet sowohl MP3 als auch FLAC:

161.135 Metallica/2008 - Death Magnetic/01-That Was Just Your Life.flac
63.5645 Doom3.mp3

Das Einzige, was übrig bleibt, ist, die Sammlung neu zu kennzeichnen. Ich werde diese Antwort aktualisieren, wenn ich Erfolg habe. Vielen Dank! :)


Schritt 1

Führen Sie bpmcountdie gesamte Sammlung aus und speichern Sie die Ergebnisse in einer Textdatei. Das Problem ist, dass es bpmcountvon Zeit zu Zeit zu Abstürzen kommt und versucht, bis zu 2 GB Arbeitsspeicher zu belegen, wenn mehrere Dateien verarbeitet werden. Daher sollten wir die Dateinamen einzeln eingeben. So was:

musicdir='/home/ootync/music'
find "$musicdir" -iregex ".*\.\(mp3\|ogg\|flac\|ape\)" -exec bpmcount {} \; \
    | fgrep "$musicdir" > "$musicdir/BPMs.txt"

Schritt 2

Wir werden einige zusätzliche Pakete benötigen apt-get install vorbis-tools flac python-mutagen. Schauen Sie sich nun an, wie das Tag 'bpm' hinzugefügt werden kann:

mid3v2 --TBPM 100 doom3.mp3
vorbiscomment -a -t "BPM=100" mother.ogg
metaflac --set-tag="BPM=100" metallica.flac

Leider habe ich keine * .ape Spuren

Jetzt haben wir die BPMs und die gesamte Sammlung sollte neu markiert werden. Hier ist das Skript:

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

Schritt 2.1 Überarbeitet Hier ist ein Skript, das Ihrer Sammlung BPM-Tags hinzufügt.

Es wird ein Prozess pro CPU-Kern ausgeführt, um den Prozess zu beschleunigen. Darüber hinaus werden keine temporären Dateien verwendet und es kann festgestellt werden, ob eine Datei bereits markiert ist.

Außerdem habe ich festgestellt, dass FLAC manchmal sowohl ID3 als auch VorbisComment enthält. Dieses Skript aktualisiert beide.

#!/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

Genießen! :)

kolypto
quelle
Ausgezeichnet! Ich war letzte Nacht nicht dazu gekommen, es zu versuchen. Versuchen Sie es mit mid3v2: linux.die.net/man/1/mid3v2 , zumindest solange , bis Ex Falso die Befehlszeilenbearbeitung unterstützt. Die ID3v2 tad ID istTBPM
DaveParillo
1
Danke, ich werde es in ein paar Tagen versuchen und die Ergebnisse veröffentlichen :) Ich frage mich, ob FLAC so etwas unterstützt: Ich muss das überprüfen.
Kolypto
1
Gute Arbeit an Schritt 2. Ich wünschte, ich könnte zweimal stimmen!
DaveParillo
1
Danke :) Leider hat mein Amarok das neue Tag in FLACs, das mir am besten gefällt, nicht bemerkt :)) Fehler gemeldet.
kolypto
Wie hast du es installiert? Die von ihnen bereitgestellte Drehzahl scheint auf meinem Computer nicht zu funktionieren, und ich habe Probleme mit der Kompilierung.
Pedrosaurio
8

Dies ist ein Befehlszeilentool zum Erkennen des BPM und zum Einfügen in die FLAC-Datei-Tags:

http://www.pogo.org.uk/~mark/bpm-tools/

mmx
quelle
Die neueste Version unterstützt auch MP3s und Ogg Vorbis.
codiert
Ubuntu hat bpm-tools-Pakete in saucy verfügbar.
Naught101
6

Ich habe das ursprüngliche Skript von kolypto verwendet bpmcountund es für bpm-tag(Dienstprogramm von bpm-tools) umgeschrieben, für das ich beim Installieren mehr Glück hatte. Ich habe auch einige Verbesserungen vorgenommen.

Sie können es finden auf GitHub https://github.com/meridius/bpmwrap

Meridius
quelle
Dies erforderte ein paar Modifikationen, um auf einem Mac zu arbeiten, die ich in meiner eigenen Antwort unten angegeben habe (weil es für einen Kommentar zu lang ist)
Adrian
2

Ich kenne kein Tool, das genau das tut, wonach Sie suchen, aber ich habe mit MusicIP herumgespielt .

Verwendete die Linux / Java-Version - es dauert lange, eine Musikbibliothek vollständig zu analysieren, aber es funktioniert wirklich. Sie können Songs finden, die anderen Songs ähnlich sind. Sie können mit der rechten Maustaste auf die generierte Wiedergabeliste klicken und eine Option auswählen, um mehr oder weniger Titel wie den ausgewählten auszuwählen. Sie können auch bestimmte Genres entfernen. Es ist irgendwie cool, aber nachdem der Wow-Faktor nachgelassen hat, habe ich aufgehört, es zu benutzen.

Die kostenlose Version exportiert Wiedergabelisten mit bis zu 75 Titeln im (mindestens) m3u-Format.

Es wird derzeit nicht unterstützt, aber ich denke, sie haben versucht, es als Predexis zu vermarkten .

DaveParillo
quelle
1

Banshee Media Player ist nicht nur ein Tool, nach dem Sie suchen, sondern kann auch BPM erkennen.

Ich verwende Banshee zum Abspielen, Organisieren und Synchronisieren meiner Musik mit tragbaren Playern. Ich bin nicht angeschlossen, aber ich mag das Programm am besten von allem, was ich ausprobiert habe. Es kann auch "intelligente Wiedergabelisten" basierend auf allen Arten von Eigenschaften der Tracks, einschließlich BPM, erstellen.

Es gibt eine Erweiterung, die alle möglichen Dinge über den Song analysiert und ähnliche Songs findet, wie Sie sie spielen. Es heißt Mirage und ich habe es eine Weile benutzt, aber jetzt nicht mehr, da ich eine Reihe von Wiedergabelisten erstellt habe, die verschiedenen Stimmungen entsprechen (laut Mirage nicht unbedingt ähnlich).

Ich weiß nicht, ob Banshee die erkannte BPM wieder im ID3v2-Tag "BPM" der Datei speichern wird. Wenn jemand weiß, wie man das bpm-Tag einfach von außerhalb des Programms überprüft, werde ich es überprüfen.

Dom
quelle
1

Es ist kein Linux, kann aber in Wine funktionieren - ich benutze MixMeister BPM Analyzer

Shevek
quelle
0

Ich habe ein anderes Tool zum Kennzeichnen von MP3-Dateien mit dem richtigen BPM-Wert gefunden.

Es heißt BPMDetect . Open Source. QT-Bibliotheken funktionieren unter Gnome also einwandfrei. Kommt mit einer GUI, kann aber nur als Konsolenversion kompiliert werden (führen Sie "scons console = 1" wie in der readme.txt angegeben aus).

Ansonsten habe ich am Ende auch den "bpmcount" von BpmDJ verwendet, da ich Schwierigkeiten hatte, BPMDetect auf einem 64-Bit-Ubuntu-Host zu kompilieren (aufgrund der Abhängigkeit von fmodex). Also habe ich das (sehr coole und gut geschriebene) Shell-Skript oben genommen (siehe unten), die "bpmcount" -Binärdatei, die aus der [x64 .rpm] [3] auf der BpmDJ-Website extrahiert wurde (ich habe gerade die .rpm extrahiert) mit

pm2cpio bpmdj-4.2.pl2-0.x86_64.rpm|cpio -idv

und es wirkte wie ein Zauber. Ich musste nur das obige Skript modifizieren, da es auf meiner Seite nicht funktionierte (Problem mit stdout / stderr der bpmcount-Binärdatei). Meine Änderung betrifft die Dateiumleitung:

local bpm=$(bpmcount "$file" 3>&1 1>/dev/null 2>&3 | grep '^[0-9]' | cut -f1)
Sergio
quelle
0

In dieser Frage zum Stackoverflow wird ein anderes Tool empfohlen : aubio , das zusammen mit Python-Modulen geliefert wird.

Ich habe es nicht ausprobiert, weil ich ein bisschen damit beschäftigt war, BpmDj zu kompilieren . Nur für den Fall, dass jemand anderes mit ähnlichen Problemen zu kämpfen hat, würde ich dringend empfehlen, absolut sicherzugehen:

  1. nachdem ich die neueste Version der BpmDj-Quellen heruntergeladen habe
  2. die entsprechenden Boost-Bibliotheken installiert haben

Mit den neuesten g ++ - Compiler-Upgrades sind offenbar einige Probleme aufgetreten, insbesondere im Zusammenhang mit den jüngsten Debian- und Ubuntu-Releases. Sobald er Kenntnis von diesen Problemen erlangte, hatte der Autor die Freundlichkeit, die auftretenden Inkompatibilitäten zu beheben und eine neue Veröffentlichung zusammenzustellen, die nun wie ein Zauber kompiliert. Alle, die in letzter Zeit wegen unerbittlicher Kompilierungsfehler beinahe verzweifelt waren: Sie sind jetzt gerettet.

@ mmx , deine tools sehen auch gut aus, aber sie verlassen sich darauf SoX, dass sie standardmäßig keine mp3-funktionen haben. Sie müssen also zuerst SoX mit Lame / MAD-Unterstützung kompilieren, was für Leute, die so faul sind wie ich, leider zu mühsam ist.

J. Katzwinkel
quelle
0

Um die Lösung von @meridius auf meinem Mac zum Laufen zu bringen, musste ich einige zusätzliche Schritte ausführen und das Skript ein wenig ändern:

# 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 ..

Dann musste ich das Skript modifizieren, um auf die GNU-Versionen von allem und ein paar andere Verbesserungen zu verweisen:

#!/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"

Vielen Dank für Ihre harte Arbeit @kolypto und @meridius.

... die Qual, die ich habe, um einen CLI-Workflow aufrechtzuerhalten und kein Geld für Musik-Tools zu bezahlen ...

Adrian
quelle