Irgendwelche Beat Detection Software für Linux?

15745
kolypto

Amarok 2 kann die Musiksammlung mithilfe des 'bpm' -Felds des ID3v2-Tags durchsuchen. Das wäre sehr schön, wenn ich die gesamte Musiksammlung neu erstellen würde, damit ich die 'Stimmung' des Tracks finde, der mir gefällt.

Ich habe jedoch keine Beat-Detection-Software gefunden, die mir geholfen hätte. Hast du schon mal eins benutzt? Vorzugsweise CLI. Ich bin auch interessiert, ob es etwas Ähnliches gibt, um FLACs mit demselben 'bpm'-Feld zu kennzeichnen.

Vielen Dank! :)

PS: Ich bin mir bewusst, dass es eine nette Moodbar-Funktion gibt, die jedoch zum Suchen unbrauchbar ist.

28
Hast du diese Seite gesehen? http://www.mmartins.com/mmartins/bpmdetection/bpmdetection.asp Das scheint genau das zu sein, was Sie suchen. DaveParillo vor 14 Jahren 3
@DaveParillo, dass "Stimmung eines Tracks" ein Link zu Ihrer Festplatte ist und somit für jeden außer Ihnen nutzlos ist Justin Smith vor 14 Jahren 0
@ Justin Smith, er meinte eine Datei in BpmDj-Dokumenten :) Hier ist die Online-Version: http://bpmdj.yellowcouch.org/clustering.html kolypto vor 14 Jahren 0
@Justin - Entschuldigung - verrückter Abzugsfinger, denke ich. DaveParillo vor 14 Jahren 0

9 Antworten auf die Frage

15
kolypto

At the site DaveParillo suggested I've found BpmDj project. It has a bpmcount executable that calculates the bpm very nice: it handles mp3 as well as flac:

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

The only thing that's left is to retag the collection. I'll update this answer whenever I succeed. Thanks! :)


Step 1

Run bpmcount against the entire collection and store the results into a textfile. The problem is that bpmcount crashes from time to time and tries to eat up to 2GB of memory when it processes several files so we should feed it with filenames one by one. Like this:

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

Step 2

We'll need some additional packages: apt-get install vorbis-tools flac python-mutagen. Now have a look at how the 'bpm' tag can be added:

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

Alas, I have no *.ape tracks

Now we have the BPMs and the entire collection should be retagged. Here's the script:

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 Here's a script that will add BPM tags to your collection.

It runs one process per CPU Core to make the process faster. Additionally, it uses no temporary files and it capable of detecting whether a file is already tagged.

Additionally, I've discovered that FLAC sometimes has both ID3 and VorbisComment inside. This script updates both.

#!/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="$" 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="$" local ext="$" 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" "$" >/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 

Enjoy! :)

Ausgezeichnet! Ich hatte es letzte Nacht nicht versucht, es zu versuchen. Versuchen Sie Mid3v2: http://linux.die.net/man/1/mid3v2 so lange, bis Ex Falso die Befehlszeilenbearbeitung unterstützt. Die id3v2-ID ist "TBPM" DaveParillo vor 14 Jahren 0
Danke, ich werde es in ein paar Tagen versuchen und die Ergebnisse posten :) Ich frage mich, ob FLAC so etwas unterstützt: Ich muss das mal ausprobieren. kolypto vor 14 Jahren 1
Gute Arbeit an Schritt 2. Ich wünschte, ich könnte zweimal stimmen! DaveParillo vor 14 Jahren 1
Vielen Dank :) Leider hat mein Amarok das neue Tag in FLACs nicht bemerkt, das mir am besten gefällt :)). kolypto vor 14 Jahren 1
Wie hast du es installiert? Die Drehzahl, die sie bieten, scheint in meinem Computer nicht zu funktionieren, und ich habe Schwierigkeiten mit der Zusammenstellung. pedrosaurio vor 12 Jahren 0
@pedrosaurio, ich habe es kompiliert :) Sehen Sie sich einfach die Fehler an, die Sie beim Erstellen von "make" erhalten, und installieren Sie die genannten Pakete kolypto vor 12 Jahren 0
Anscheinend ist bpmdj eine Android-App. Wie haben Sie die bpmcount-Funktion daraus extrahiert? Ist es separat erhältlich oder müssen wir die App kaufen? Benubird vor 9 Jahren 0
@kolypto der Link funktioniert nicht mehr zum Quellcode. Ist es dasselbe wie [this] (http://bpmdj.yellowcouch.org/try-desktop.html)? max pleaner vor 8 Jahren 0
8
mmx

This is a command-line tool to detect the BPM and put it in the FLAC file tags:

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

Die neueste Version ist auch für MP3 und Ogg Vorbis geeignet. encoded vor 11 Jahren 0
Ubuntu hat [bpm-tools-Pakete] (http://packages.ubuntu.com/saucy/bpm-tools) in frech verfügbar. naught101 vor 10 Jahren 0
5
meridius

Ich habe das Original-Skript von kolypto verwendet bpmcountund es für bpm-tag(Utility of bpm-tools) neu geschrieben, wofür ich mit der Installation mehr Glück hatte. Ich habe auch einige Verbesserungen vorgenommen.

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

Um an einem Mac arbeiten zu können, waren einige Änderungen erforderlich, die ich unten in meine eigene Antwort aufgenommen habe (weil es für einen Kommentar zu lang ist). Adrian vor 8 Jahren 0
2
DaveParillo

I don't know of a tool that does exactly what you are looking for, but I have played around with MusicIP.

Used the linux / java version - it takes a long time to completely analyze a music library, but it really does work. You can find songs that are similar to other songs. You can right click on the playlist generated and select option to select more or fewer songs like the one selected. You can also choose to eliminate certain genre's. It's kind of cool, but after the wow factor wore off, I stopped using it.

The free version exports playlists up to 75 songs in (at least) m3u format.

It's currently unsupported, but I think they have tried to take it commercial as Predexis.

1
Dom

While it is not just a tool like you say you are looking for, Banshee media player can detect bpm.

I use Banshee for all my music playing, organisation and synchronizing to portable players. I'm not affiliated, but I like the program the best of all that I've tried. It can also generate "smart playlists" based on all sorts of properties of the tracks, including bpm.

There is an extension which analyses all sorts of things about the song, and will find similar songs to the one you're playing. It's called Mirage, and I used it for a while, but I don't any more, as I've created a number of playlists of ones that suit various moods (not necessarily similar according to Mirage).

I don't know if Banshee will save the bpm it detected back into the ID3v2 "bpm" tag of the file. If anyone knows how to easily check the bpm tag from outside the program I'll check.

1
Shevek

It's not Linux but may well work in Wine - I use MixMeister BPM Analyzer

0
Sergio

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

Es heißt BPMDetect . Open Source. QT-Bibliotheken funktionieren also gut unter Gnome. Kommt mit einer GUI, kann aber nur als Konsole-Version 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 (siehe unten) genommen, die Binärdatei "bpmcount", die aus [x64 .rpm] [3] extrahiert wurde und auf der BpmDJ-Website verfügbar ist (ich extrahiere nur die .rpm-Datei) mit

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

und es funktionierte wie ein Zauber. Ich musste nur das obige Skript modifizieren, da es außerhalb meiner Einstellung nicht auf meiner Seite funktionierte (Problem mit stdout / stderr der Binärdatei bpmcount). Bei meiner Änderung geht es um die Umleitung von Dateien:

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

In dieser Frage wird ein weiteres Werkzeug für stackoverflow empfohlen: aubio, das mit Python-Modulen geliefert wird.

Ich habe es nicht ausprobiert, weil ich irgendwie damit beschäftigt war, BpmDj zu kompilieren . Für den Fall, dass sich andere Personen beim Versuch ähnlichen Problemen stellen müssen, würde ich dringend empfehlen, absolut sicher zu gehen:

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

Mit den neuesten g ++ - Compiler-Upgrades scheinen sich einige Probleme insbesondere in den letzten Debian- und Ubuntu-Releases ergeben zu haben. Sobald er sich dieser Probleme bewusst wurde, hatte der Autor die Freundlichkeit, die entstandenen Inkompatibilitäten zu beheben und eine neue Version zusammenzustellen, die sich nun wie ein Zauber zusammensetzt. Jeder, der in letzter Zeit vor verzweifelten Kompilationsfehlern in Verzweiflung geraten war, ist jetzt gerettet.

@ mmx, Ihre Tools sehen auch gut aus, aber sie sind darauf angewiesen SoX, was standardmäßig keine MP3-Funktionen bietet. Sie müssen also zuerst SoX mit Lame / MAD-Unterstützung kompilieren, was für Leute, die so faul wie ich sind, zu viel Aufwand bedeutet.

0
Adrian

Um die @meridius-Lösung auf meinem Mac zum Laufen zu bringen, musste ich etwas mehr Arbeit leisten 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 so anpassen, dass es auf die GNU-Versionen von allem und ein paar weiteren Verbesserungen zeigte:

#!/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š (martin.meridius@gmail.com) 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 "$" ; 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 "$" IFS=$IFSORIG }  # @param string file # @returns int BPM value function getBpm() { local file="$1" local ext="$" 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="$" local ext="$" 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]) BPM/\1/' \ | gawk '') }  # @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$$bpm_old$$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$$bpm_old$$bpm_new$$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=("$" "$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=("$" "$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 $? (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 "$" ; do [[ $(inArray $type TYPESALLOWED[@]) -eq 1 ]] && { myEcho "Filetype $type is not one of allowed types ($)!" 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="$" file="$" ext="$" ext="$" # convert to lowercase if [ -f "$file" ] ; then if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then 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="$" ext="$" # convert to lowercase if [ $(inArray $ext INPUTTYPES[@]) -eq 0 ] ; then 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 "$" ; 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[@]}) $\033[0K"\\r FILES=("$" "$file") done < <(gfind "$" -type f -regextype posix-awk -iregex ".*\.($impl_types)") echo -e "Counted ${#FILES[@]} files\033[0K"\\r fi  [ "$l" ] && printf '%s\n' "$" > "$l"  NUMFILES=${#FILES[@]} FILENUMBER=1  [ $NUMFILES -eq 0 ] && { myEcho "There are no $ files in given files/paths." exit 1 }  declare SEP=" " [ "$c" ] && SEP=";"   # =============================== MAIN SECTION ================================  if [ "$e" ] ; then # what heading to show myEcho "num$old$filename" else myEcho "num$old$new$filename" fi  for file in "$" ; do [ `jobs -p | wc -l` -ge $NUMCPU ] && wait [ "$v" ] && myEcho "Parsing ($/$)\t$file ..." oneThread "$file" "$FILENUMBER" "$" & 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.

... den Schmerz, den ich durchmache, um einen CLI-Workflow aufrechtzuerhalten und kein Geld für Musikwerkzeuge zu zahlen ...