At the moment i'm using a mish mash of messy audio conversion scripts (found on github) to convert audio into different formats. I have a master FLAC collection and convert into different formats for different devices, ie. mp3, opus, ogg, aac etc. My requirements are to keep the exact same directory structure, id tags, etc as the master collection and output them into required format. Does anybody know of a single script / tool what can do this what is terminal based and works on linux?
wozbit: If you have a good idea how would you construct it (Especially the part that looks and reacts to dir/subdir changes) and it's bash I may give it a try.
The closest i've found is https://sourceforge.net/projects/audenc/ but i cannot get it to work..
Would be nice if the script could detect changed files and only convert what is new etc I'm suprised there is hardly anything out there what is up to the job. A good idea for a new github project!
This is the uncool non-nerdy answer, but foobar2000 works pretty well in wine and can do this. A while ago I wanted to do something similar (especially with preservering the directory structure) and fb2k was just easiest. Though it should be doable as a python/bash script with ffmpeg too. Just needs more effort.
A try at a simple unidirectional model for two dirs (With some help from freenode #bash). It basically loops over every found flac and checks if ogg is there in the 2nd folder, if not makes one. Also if ogg mtime is older, makes a new ogg. Just a model, didn't bother with actual encoding code so far.
http://paste.debian.net/plain/993464
To test:
mkdir -p ~/tmp/test/one
cd ~/tmp/test/one
touch a.flac b.flac c.flac
# run 'test' script
./test
basext = a.flac, base = a, dir = .
/home/b/tmp/test/two/./a.ogg ... making one
encoding ...
basext = b.flac, base = b, dir = .
/home/b/tmp/test/two/./b.ogg ... making one
encoding ...
basext = c.flac, base = c, dir = .
/home/b/tmp/test/two/./c.ogg ... making one
encoding .
touch one/a.flac
./test
basext = a.flac, base = a, dir = .
/home/b/tmp/test/two/./a.ogg ... is older, making new one
encoding ...
basext = b.flac, base = b, dir = .
/home/b/tmp/test/two/./b.ogg ... already there
basext = c.flac, base = c, dir = .
/home/b/tmp/test/two/./c.ogg ... already there
tree
.
├── one
│ ├── a.flac
│ ├── b.flac
│ └── c.flac
├── test
└── two
├── a.ogg
├── b.ogg
└── c.ogg
Probably needs some additional sanity checking, but after that should be easily expandable to multiple destinations/encoders. p.s. Actually I'd probably do multiple scripts, each for one encoder.
edit: and bash parallel version of the same
http://paste.debian.net/plain/993697
To my knowledge, the closest tool to the OP's request is this:
https://sourceforge.net/projects/pacpl/
Not using it myself but worthy of investigation?
To my knowledge, the closest tool to the OP's request is this:
https://sourceforge.net/projects/pacpl/
Not using it myself but worthy of investigation?
It does exactly what is needed. I used it to convert my audio files to MP3 for portable listening. Input from one tree, output to another of same structure.
pacpl manual page (http://manpages.ubuntu.com/manpages/zesty/man1/pacpl.1.html)
I've just re-encoded a large FLAC library to 128kbps Opus with this one-liner:
find * -type f -name \*.flac -exec dirname {} \; | sort -u | while read d; do echo "$d" && mkdir -p "$HOME/Music_portable/${d}" && ls "$d"/*.flac | parallel 'opusenc --quiet --bitrate 128 {} "$HOME"/Music_portable/"${d}"/{.}.opus'; done
It uses the 'find' command to recursively locate directories containing FLAC files and creates a mirror of the directory tree. It echoes the directory name to give the user an idea of progress. It then uses GNU parallel (https://www.gnu.org/software/parallel/) to utilise multiple processor cores when transcoding.
Edit the output directory and the encoder preference then simply navigate your terminal to the parent directory of your FLAC library. Paste the command and hit enter. You could edit the command to output to four different formats in four different destinations, if your processor is up to it.
And it needn't take much to throw this into a script where 'find' checks for modification times and/or newly-created FLAC files. Since the default behaviour for some encoders is to overwrite without prompting, the script could be added as a cron or anacron job so that it would periodically update your lossy library with zero user intervention.
lothario15: thats pretty cool, thanks for sharing. (I can see two points that could make trouble, sort and ls).
I've just re-encoded a large FLAC library to 128kbps Opus with this one-liner:
find * -type f -name \*.flac -exec dirname {} \; | sort -u | while read d; do echo "$d" && mkdir -p "$HOME/Music_portable/${d}" && ls "$d"/*.flac | parallel 'opusenc --quiet --bitrate 128 {} "$HOME"/Music_portable/"${d}"/{.}.opus'; done
That's a helluva line of code.
Gonna keep it on Google Keep for whenever it comes in handy.
Thank you!
wow, nice one-liner. Have to figure out a way for it to detect changed files.
I found this script on github, modified it slightly, also created version for fdk-aac.
Tested with fdkaac 0.6.3 and opusenc opus-tools 0.1.9 (using libopus 1.1.5)
* Keeps directory structure
* Copies metadata
* Detects changed files
* Uses parallel
flac2opus.sh
#!/bin/bash
export BITRATE=64
function usage
{
echo
echo "Usage:"
echo " $0 FLAC_DIR LOSSY_DIR"
}
function encode
{
if [ ! -f "$LOSSY_DIR"/"$(echo "$1" | sed 's/.flac/.opus/')" ]; then
ARTIST=`metaflac "$FLAC_DIR"/"$1" --show-tag=ARTIST | sed s/.*=//`
TITLE=`metaflac "$FLAC_DIR"/"$1" --show-tag=TITLE | sed s/.*=//g`
ALBUM=`metaflac "$FLAC_DIR"/"$1" --show-tag=ALBUM | sed s/.*=//g`
TRACKNUMBER=`metaflac "$FLAC_DIR"/"$1" --show-tag=TRACKNUMBER | sed s/.*=//g`
DISCNUMBER=`metaflac "$FLAC_DIR"/"$1" --show-tag=DISCNUMBER | sed s/.*=//g`
echo "encoding $1"
flac -s -c -d "$FLAC_DIR"/"$1" | opusenc --quiet --bitrate "$BITRATE" --artist "$ARTIST" --album "$ALBUM" \
--title "$TITLE" --comment "TRACKNUMBER=$TRACKNUMBER" --comment "DISCNUMBER=$DISCNUMBER" \
- "$LOSSY_DIR"/"$(echo "$1" | sed 's/\.flac$/\.opus/')"
fi
}
export -f encode
#If user didn't provide 2 arguments, quit.
if [ "$#" -ne 2 ]; then
usage
exit
fi
export FLAC_DIR="$1"
export LOSSY_DIR="$2"
#If first argument isn't a directory, quit.
if [ ! -d "$FLAC_DIR" ]; then
usage
exit
fi
#if LOSSY_DIR doesn't exist, create it
if [ ! -d "$LOSSY_DIR" ]; then
mkdir "$LOSSY_DIR"
fi
#recreate the folder structure in lossy
echo "Creating the folder structure."
diff --new-line-format="" --unchanged-line-format="" \
<(find "$FLAC_DIR" -mindepth 1 -maxdepth 3 -type d -printf '%P\n' | sort) \
<(find "$LOSSY_DIR" -mindepth 1 -maxdepth 3 -type d -printf '%P\n' | sort) |while read fname; do
mkdir -v -p "$LOSSY_DIR/$fname"
done
echo "Encoding missing songs."
diff --new-line-format="" --unchanged-line-format="" \
<(find "$FLAC_DIR" -mindepth 1 -name \*.flac -printf '%P\n' | sort) \
<(find "$LOSSY_DIR" -mindepth 1 -name \*.opus -printf '%P\n' | sed 's/\.opus$/\.flac/g' | sort) \
| parallel --no-notice encode
flac2aac.sh
#!/bin/bash
export FDKAAC_PROFILE=5
export FDKAAC_BITRATE_MODE=2
function usage
{
echo
echo "Usage:"
echo " $0 FLAC_DIR LOSSY_DIR"
}
function encode
{
if [ ! -f "$LOSSY_DIR"/"$(echo "$1" | sed 's/.flac/.m4a/')" ]; then
ARTIST=`metaflac "$FLAC_DIR"/"$1" --show-tag=ARTIST | sed s/.*=//`
TITLE=`metaflac "$FLAC_DIR"/"$1" --show-tag=TITLE | sed s/.*=//g`
ALBUM=`metaflac "$FLAC_DIR"/"$1" --show-tag=ALBUM | sed s/.*=//g`
TRACKNUMBER=`metaflac "$FLAC_DIR"/"$1" --show-tag=TRACKNUMBER | sed s/.*=//g`
DISCNUMBER=`metaflac "$FLAC_DIR"/"$1" --show-tag=DISCNUMBER | sed s/.*=//g`
echo "encoding $1"
flac -s -c -d "$FLAC_DIR"/"$1" | fdkaac -S -p "$FDKAAC_PROFILE" -m "$FDKAAC_BITRATE_MODE" --artist "$ARTIST" --album "$ALBUM" \
--title "$TITLE" --comment "TRACKNUMBER=$TRACKNUMBER" --comment "DISCNUMBER=$DISCNUMBER" \
- -o "$LOSSY_DIR"/"$(echo "$1" | sed 's/\.flac$/\.m4a/')"
fi
}
export -f encode
#If user didn't provide 2 arguments, quit.
if [ "$#" -ne 2 ]; then
usage
exit
fi
export FLAC_DIR="$1"
export LOSSY_DIR="$2"
#If first argument isn't a directory, quit.
if [ ! -d "$FLAC_DIR" ]; then
usage
exit
fi
#if LOSSY_DIR doesn't exist, create it
if [ ! -d "$LOSSY_DIR" ]; then
mkdir "$LOSSY_DIR"
fi
#recreate the folder structure in lossy
echo "Creating the folder structure."
diff --new-line-format="" --unchanged-line-format="" \
<(find "$FLAC_DIR" -mindepth 1 -maxdepth 3 -type d -printf '%P\n' | sort) \
<(find "$LOSSY_DIR" -mindepth 1 -maxdepth 3 -type d -printf '%P\n' | sort) |while read fname; do
mkdir -v -p "$LOSSY_DIR/$fname"
done
echo "Encoding missing songs."
diff --new-line-format="" --unchanged-line-format="" \
<(find "$FLAC_DIR" -mindepth 1 -name \*.flac -printf '%P\n' | sort) \
<(find "$LOSSY_DIR" -mindepth 1 -name \*.m4a -printf '%P\n' | sed 's/\.m4a$/\.flac/g' | sort) \
| parallel --no-notice encode
No problem. Hope it's useful. You need to install parallel from the repositories beforehand since it has a citation notice that needs to be agreed first by typing:
parallel --bibtex
After doing that once, you're good to go.
The command worked flawlessly with my FLAC library. I added the sort and echo commands to give me an indication of progress. Since find doesn't necessarily sort alphanumerically, the sort -u orders every unique directory. I started encoding in the evening with 2pac; by the morning I saw that it had reached Radiohead so didn't have too long to go until it finished.
Smok3, I know it's generally bad practice to use the output of ls but parallel doesn't seem to mind how it's fed. That said, I'm no expert and I'm always looking to improve my terminal-fu so let me know what problems you foresee using sort and ls in this command. Thanks.
Wozbit, here's a start on using find to detect file modification timestamps:
https://stackoverflow.com/questions/5566310/how-to-recursively-find-and-list-the-latest-modified-files-in-a-directory-with-s
@lothario15, Nothing specific, but I wonder if there is an equally nice onliner without ls.
@wozbit, you sure it will detect changed flacs or just new flacs?
i will see if i can use a diff option so it detects modified files
Tought one with the script you posted.
Wozbit, was the script you found on github this one?
https://github.com/SimonPersson/flac2opus
I've been using this successfully for a while. I just checked - it does detect and encode new files. Also it re-encodes where the filename or tags are different from the existing opus file.
Or look into Caudec which was developed by one of our members.
Wozbit, was the script you found on github this one?
https://github.com/SimonPersson/flac2opus
I've been using this successfully for a while. I just checked - it does detect and encode new files. Also it re-encodes where the filename or tags are different from the existing opus file.
Yes thats the script!
At the moment i'm using a mish mash of messy audio conversion scripts (found on github) to convert audio into different formats. I have a master FLAC collection and convert into different formats for different devices, ie. mp3, opus, ogg, aac etc. My requirements are to keep the exact same directory structure, id tags, etc as the master collection and output them into required format. Does anybody know of a single script / tool what can do this what is terminal based and works on linux?
I wrote this for use on my linux mint box. Works great. Converts my entire flac tree to mp3. I have a similar one for wav, though anyone should be able to modify this one to do wav.
_______________
#!/bin/bash
#####################################
if [ -z $1 ];then echo Give target directory such as . ; exit 0;fi
find "$1" -depth -name '*' | while read file ; do
directory=$(dirname "$file")
oldfilename=$(basename "$file")
newfilename=$(basename "${file%.[Ff][Ll][Aa][Cc]}")
if [ "$oldfilename" != "$newfilename" ]; then
ffmpeg -i "$directory/$oldfilename" -ab 320k "$directory/$newfilename.mp3" </dev/null
rm "$directory/$oldfilename"
fi
done
#replace all flac occurences with mp3 within filenames
find . -depth -name '*flac*' -execdir bash -c 'for f; do mv -i "$f" "${f//flac/mp3}"; done' bash {} +
# replace flac with mp3 WITHIN all .m3u files
find . -name "*.m3u" -exec sed -i 's/flac/mp3/g' {} +
____________________________________________
:)