djcev.com

//

Git Repos / dotfiles / commit 6a60919

Commit: 6a60919816171e613a5a45942e2f78d7e6295416
Parent: d224ae2e188fbc122b300d92c319759cf52700a6
Author: Cameron Vanderzanden, 2022-01-29 20:43
Committer: Cameron Vanderzanden, 2022-01-29 20:43

Commit Message

Adding first batch of audio file handling scripts.

Some of these are in regular use, some aren't and may need to be
checked. I updated calls to mpv for its latest set of options
(2022-01) and replaced calls to a named image viewer with xdg-open.

There are still two more larger scripts to add.

It would be a good idea to add checks for necessary software to these
scripts. (Necessary software being things like eyeD3, flac, mid3v2,
sox, etc).

Change List

Diff bin/audio_to_cbr320.sh

diff --git a/bin/audio_to_cbr320.sh b/bin/audio_to_cbr320.sh
new file mode 100755
index 0000000..b8ef78b
--- /dev/null
+++ b/bin/audio_to_cbr320.sh
@@ -0,0 +1,197 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- audio_to_cbr320.sh 2015/02/18 cev
+#- audio_to_cbr320.sh 2021/07/23 cev
+#- audio_to_cbr320.sh 2022/01/29 cev
+## Usage: audio_to_cbr320.sh [-3fhV] <inputfile> <outputfile>
+##
+## Convert <inputfile> flac/mp3 into a 320kbps constant-bitrate mp3
+## file at <outputfile>.
+##
+## -3 Operate on mp3 files
+## -f Operate on flac files
+## -h Show help
+## -V Print version info
+#
+# TODO: This needs better error checking.
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+mode=""
+ext=""
+
+if [ $self = "flac_to_cbr320.sh" -o $self = "flac_to_cbr320" ]; then
+ mode="flac"
+ ext="flac"
+elif [ $self = "mp3_to_cbr320.sh" -o $self = "mp3_to_cbr320" ]; then
+ mode="mp3"
+ ext="mp3"
+fi
+
+die_inputoutputsame() {
+ print_self error
+ printf "%binput file %b%s %band output file %b%s %bare the same!%b\n" \
+ "$_norm" "$_error" "$1" "$_norm" "$_error" "$2" "$_norm" "$_clear" >&2
+ exit 1
+}
+
+die_invalidargumentcount() {
+ print_self error
+ printf "%b need an input file and output file! " "$_norm" >&2
+ printf "(Argument count != %b2%b).%b\n" "$_error" "$_norm" "$_clear" >&2
+ exit 1
+}
+
+die_noinput() {
+ print_self error
+ printf "%binput file %b%s %bdoes not exist!%b\n" \
+ "$_norm" "$_error" "$1" "$_norm" "$_clear" >&2
+ exit 1
+}
+
+die_nooutput() {
+ print_self error
+ printf "%boutput file not specified!%b\n" "$_norm" "$_clear" >&2
+ exit 1
+}
+
+die_unknownfiletype() {
+ print_unknownfiletype "$*"
+ exit 1
+}
+
+is_flac() { test_mimetype.sh -t "audio/x-flac" "$@" ; }
+
+is_mp3() {
+ if test_mimetype.sh -t "audio/mpeg" "$@"; then
+ return 0
+ else
+ # test file extension
+ tmpname="$(basename "$@" ".mp3")"
+ tmpname2="${@##$tmpname}"
+ if [ "$tmpname2" = ".mp3" ]; then
+ return 0
+ fi
+ fi
+ return 1
+}
+
+mp3_copytags() {
+ # copy tags using py-mutagen
+ # TODO: replicate the flac_copytags system below to re-generate the mp3
+ # tags, instead of copying (possibly corrupt) tags with mid3cp.
+ mid3cp --write-v1 "$1" "$2"
+}
+
+mp3_transcode() {
+ inpfile="${1}"
+ outfile="${2}"
+ wavfile="${outfile}.wav"
+
+ # decode; had to update this 2022/01/29 because mpv options changed.
+ mpv --msg-level=all=warn \
+ --no-audio-display \
+ --no-video \
+ --audio-samplerate=44100 \
+ --ao=pcm \
+ --ao-pcm-file="${wavfile}" \
+ "$inpfile"
+ # encode
+ lame --preset insane -S "$wavfile" "$outfile"
+ rm -v "$wavfile"
+}
+
+# There's a better way to do this.
+flac_gettag() {
+ metaflac --no-utf8-convert --list "$1" | grep "$2" | cut -d'=' -f 2-
+}
+
+flac_copytags() {
+ title="$(flac_gettag "$1" "TITLE=")"
+ artist="$(flac_gettag "$1" "ARTIST=")"
+ album="$(flac_gettag "$1" "ALBUM=")"
+ year="$(flac_gettag "$1" "DATE=")"
+ comment="$(flac_gettag "$1" "COMMENT=")"
+ trackno="$(flac_gettag "$1" "TRACKNUMBER=")"
+ tracktotal="$(flac_gettag "$1" "TRACKTOTAL=")"
+ genre="$(flac_gettag "$1" "GENRE=")"
+ albumartist="$(flac_gettag "$1" "ALBUMARTIST=")"
+ if [ -n "$tracktotal" ];
+ then tracks="$trackno/$tracktotal"
+ else
+ tracks="$trackno"
+ fi
+ [ -n "$title" ] && mid3v2 -t "$title" "$2"
+ [ -n "$artist" ] && mid3v2 -a "$artist" "$2"
+ [ -n "$album" ] && mid3v2 -A "$album" "$2"
+ [ -n "$year" ] && mid3v2 -y "$year" "$2"
+ [ -n "$comment" ] && mid3v2 -c "$comment" "$2"
+ [ -n "$tracks" ] && mid3v2 -T "$tracks" "$2"
+ [ -n "$genre" ] && mid3v2 -g "$genre" "$2"
+ [ -n "$albumartist" ] && mid3v2 --TPE2 "$albumartist" "$2"
+ if [ -f "00 cover.jpg" ]; then
+ eyeD3 --quiet --add-image="00 cover.jpg:FRONT_COVER:" "$2"
+ elif [ -f "cover.jpg" ]; then
+ eyeD3 --quiet --add-image="cover.jpg:FRONT_COVER:" "$2"
+ fi
+}
+
+flac_transcode() {
+ inpfile="${1}"
+ outfile="${2}"
+ wavfile="${outfile}.wav"
+
+ # decode
+ flac -s -o "$wavfile" -d "$inpfile"
+ # encode
+ lame --preset insane -S "$wavfile" "$outfile"
+ rm -v "$wavfile"
+}
+
+while getopts "3fhV?" option; do
+ case $option in
+ 3) mode="mp3" && ext="mp3" ;;
+ f) mode="flac" && ext="flac" ;;
+ h) print_help && exit ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+# need exactly two arguments at this point
+[ $# -ne 2 ] && die_invalidargumentcount
+# no input file specified
+[ -z "$1" -o ! -e "$1" ] && die_noinput "$1"
+# no output file specified
+if [ -z "$2" ] && die_nooutput
+# input file and output file are the same
+if [ "$1" = "$2" ] && die_inputoutputsame "$1" "$2"
+
+if [ "$mode" ]; then
+ eval transcode=\${mode}_transcode
+ eval copytags=\${mode}_copytags
+ $transcode "$1" "$2"
+ $copytags "$1" "$2"
+ exit 0
+fi
+
+if is_flac "$1"; then
+ mode="flac" && ext="flac"
+ flac_transcode "$1" "$2"
+ flac_copytags "$1" "$2"
+ exit 0
+elif is_mp3 "$1"; then
+ mode="mp3" && ext="mp3"
+ mp3_transcode "$1" "$2"
+ mp3_copytags "$1" "$2"
+ exit 0
+else
+ shortname="$(basename "$1")"
+ die_unknownfiletype "$shortname"
+fi

Return to the top of this page or return to the overview of this repo.

Diff bin/cd_audio.sh

diff --git a/bin/cd_audio.sh b/bin/cd_audio.sh
new file mode 100755
index 0000000..32687d2
--- /dev/null
+++ b/bin/cd_audio.sh
@@ -0,0 +1,87 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- cd_audio.sh 2015/02/17 cev
+#- cd_audio.sh 2021/07/23 cev
+#- cd_audio.sh 2022/01/29 cev
+## Usage: cd_audio.sh [-3fhV] [-o outdir] <directory>
+##
+## Convert mp3 or flac files in <directory> to wav files in an
+## autogenerated dir (or outdir). Then print a suitable command
+## for writing the wav files to a redbook audio CD.
+##
+## -3 Convert mp3 files
+## -f Convert flac files
+## -h Show help
+## -o Write wav files to outdir instead of creating a dir in /tmp
+## -V Print version info
+# Todo: switch from specifying filetype to detecting filetype? Would allow
+# generation of audio CDs from mixed format sources.
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+mode="mp3"
+cd_command=${cd_command:-"cdrecord"}
+cd_opts=${cd_opts:-"-v -dao -pad -audio speed=1 dev=5,0,0"}
+
+die_directorynotfound() {
+ print_directorynotfound "$@"
+ exit 1
+}
+
+while getopts "3fho:V?" option; do
+ case $option in
+ 3) mode="mp3" ;;
+ f) mode="flac" ;;
+ h) print_help && exit ;;
+ o) tdir="$OPTARG" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+if [ -n "$tdir" ]; then
+ if [ ! -d "$tdir" ]; then
+ print_self error
+ printf "%boutput dir %b%s %bdoes not exist or is not a directory!%b\n" \
+ "$_norm" "$_error" "$tdir" "$_norm" "$_clear" >&2
+ fi
+else
+ tdir=$(mktemp -d ${TMPDIR:-/tmp}/${self}.XXXXXXXX)
+fi
+
+[ ! -d "$@" ] && die_directorynotfound "$@"
+
+if [ $mode = "flac" ]; then
+ extension="flac"
+ command="flac -d -o"
+ command_expr="\${outfile}"
+elif [ $mode = "mp3" ]; then
+ extension="mp3"
+ command="mpv --msg-level=all=warn --no-audio-display --no-video"
+ command="$command --audio-samplerate=44100 --ao=pcm"
+ command_expr="--ao-pcm-file=\${outfile}"
+fi
+
+for f in "$@"/*."$extension"; do
+ file="$(basename "$f")"
+ outfile="$tdir/${file}.wav"
+ print_self
+ printf "%bprocessing '%b%s%b'...%b\n" \
+ "$_norm" "$_high" "$file" "$_norm" "$_clear"
+ eval e="\$$command_expr"
+ $command "$e" "$f"
+ unset e
+done
+
+# echo the command; don't run it. let the user copy/paste it when ready.
+print_self
+printf "%bwaves written. copy & paste the next line to burn.%b\n" \
+ "$_norm" "$_clear"
+printf "%s %s %s && rm %s && rmdir %s\n" \
+ "$cd_command" "$cd_opts" "$tdir/*.wav" "$tdir/*.wav" "$tdir"

Return to the top of this page or return to the overview of this repo.

Diff bin/flac_reencode.sh

diff --git a/bin/flac_reencode.sh b/bin/flac_reencode.sh
new file mode 100755
index 0000000..7b7d959
--- /dev/null
+++ b/bin/flac_reencode.sh
@@ -0,0 +1,109 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- flac_reencode.sh 2015/03/26 cev
+#- flac_reencode.sh 2021/07/23 cev
+## Usage: flac_reencode.sh [-hV] <file or directory>
+##
+## -h Show help
+## -V Print version info
+# Useful for sniffing out broken flac files.
+# References:
+# http://unix.aspcode.net/view/63539508700411522976682/copy-all-tags-from-one-flac-file-to-another
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+tdir=""
+cwd=""
+
+cleanup() {
+ if [ -n "$tdir" -a -d "$tdir" ]; then
+ rm -f $tdir/*.backup $tdir/*.wav $tdir/*.tags $tdir/picture
+ rmdir $tdir
+ fi
+ if [ -n "$cwd" ]; then cd "$cwd"; fi
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+flac_recover() {
+ printf " %berror.%b\n" "$_error" "$_clear"
+ mv "$1" "$2"
+ exit 1
+}
+
+flac_reencode() {
+ print_self
+ printf "%b%s%b" "$_high" "$@" "$_norm"
+ base="$(basename "$@" ".flac")"
+ printf "."
+ flac --totally-silent -o "$tdir/$base.wav" -d "$@" || \
+ flac_recover "$tdir/$base.backup" "$@"
+ mv "$@" "$tdir/$base.backup"
+ printf "."
+ flac --totally-silent -o "$@" "$tdir/$base.wav" || \
+ flac_recover "$tdir/$base.backup" "$@"
+ printf "."
+
+ printf " copying tags"
+ metaflac --no-utf8-convert \
+ --export-tags-to="$tdir/$base.tags" "$tdir/$base.backup" && \
+ metaflac \
+ --remove-all-tags --import-tags-from="$tdir/$base.tags" "$@" || \
+ flac_recover "$tdir/$base.backup" "$@"
+ printf "."
+ pic="$(metaflac --list --block-type=PICTURE "$tdir/$base.backup")"
+ if [ -n "$pic" ]; then
+ metaflac --export-picture-to="$tdir/picture" "$tdir/$base.backup" || \
+ flac_recover "$tdir/$base.backup" "$@"
+ printf "."
+ metaflac --import-picture-from="3||||$tdir/picture" "$@" || \
+ flac_recover "$tdir/$base.backup" "$@"
+ printf "."
+ rm "$tdir/picture"
+ else
+ printf ".."
+ fi
+ rm "$tdir/$base.backup" "$tdir/$base.wav"
+
+ printf "%b\n" "$_clear"
+}
+
+while getopts "hV?" option; do
+ case $option in
+ h) print_help && exit ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+
+trap cleanup EXIT
+tdir=$(mktemp -d ${TMPDIR:-/tmp}/${self}.XXXXXXXX)
+
+if [ -d "$@" ]; then
+ cwd="$PWD"
+ cd "$@"
+ for i in *.flac; do
+ flac_reencode "$i"
+ done
+ cd "$cwd"
+elif [ -e "$@" ]; then
+ flac_reencode "$@"
+else
+ die_filenotfound "$*"
+fi

Return to the top of this page or return to the overview of this repo.

Diff bin/flac_to_mp3.sh

diff --git a/bin/flac_to_mp3.sh b/bin/flac_to_mp3.sh
new file mode 100755
index 0000000..ecd270f
--- /dev/null
+++ b/bin/flac_to_mp3.sh
@@ -0,0 +1,189 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- flac_to_mp3.sh 2015/09/01 cev
+#- flac_to_mp3.sh 2021/07/23 cev
+## Usage: flac_to_mp3.sh [-hV] [-c file] [-d directory] [-o file] <input file>
+##
+## Convert a flac file to an mp3 file, preserving tags.
+##
+## -c Cover image
+## -d Output base directory
+## -h Show help
+## -o Output file name
+## -r Apply replaygain to output file
+## -V Print version info
+# This hasn't been touched in a while and may or may not work. Haven't
+# needed it since I stopped transcoding to mp3 in scs4tool.sh.
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+cwd=""
+
+coverfile=""
+outdir=""
+flacfile=""
+mp3file=""
+rgain=""
+wavfile=""
+ttags=""
+tpic=""
+
+cleanup() {
+ if [ "$ttags" -a -r "$ttags" ]; then rm "$ttags"; fi
+ if [ "$tpic" -a -r "$tpic" ]; then rm "$tpic"; fi
+ if [ "${tpic}.jpg" -a -r "${tpic}.jpg" ]; then rm "${tpic}.jpg"; fi
+ if [ "$wavfile" -a -r "$wavfile" ]; then rm "$wavfile"; fi
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+cleartags() {
+ A=""; TPE2=""; a=""; TBPM=""; c=""; y=""; g=""; TKEY=""; t=""; tt=""; T=""
+ rgag=""; rgap=""; rgtg=""; rgtp=""
+ export A TPE2 a TBPM c y g TKEY t tt T rgag rgap rgtg rgtp
+}
+
+readcover() {
+ pic="$(metaflac --list --block-type=PICTURE "$flacfile")"
+ if [ -n "$pic" ]; then
+ tpic=$(mktemp ${TMPDIR:-/tmp}/${self}.pic.XXXXXXXX)
+ metaflac --export-picture-to="$tpic.jpg" "$flacfile"
+ coverfile="$tpic.jpg"
+ fi
+}
+
+readtags() {
+ metaflac --no-utf8-convert --export-tags-to="$ttags" "$flacfile"
+ while read i; do
+ k=$(printf "%s" "$i" | cut -d '=' -f 1)
+ # convert ':' into '_' because ':' will mess up mp3 comments.
+ # shows up most often in URLs; example: 'visit http://'... comments
+ v=$(printf "%s" "$i" | cut -d '=' -f 2- | tr ':' '_')
+ case $k in
+ album|ALBUM) A="$v" ;;
+ albumartist|ALBUMARTIST) TPE2="$v" ;;
+ artist|ARTIST) a="$v" ;;
+ comment|COMMENT) c="$v" ;;
+ bpm|BPM) TBPM="$v" ;;
+ date|DATE) y="$v" ;;
+ genre|GENRE) g="$v" ;;
+ initialkey|INITIALKEY) TKEY="$v" ;;
+ title|TITLE) t="$v" ;;
+ tracktotal|TRACKTOTAL) tt="$v" ;;
+ tracknumber|TRACKNUMBER) T="$v" ;;
+ replaygain_album_gain|REPLAYGAIN_ALBUM_GAIN) rgag="$v" ;;
+ replaygain_album_peak|REPLAYGAIN_ALBUM_PEAK) rgap="$v" ;;
+ replaygain_track_gain|REPLAYGAIN_TRACK_GAIN) rgtg="$v" ;;
+ replaygain_track_peak|REPLAYGAIN_TRACK_PEAK) rgtp="$v" ;;
+ esac
+ done < $ttags
+}
+
+writecover() {
+ if [ -f "$coverfile" ]; then
+ eyeD3 --add-image="$coverfile:FRONT_COVER:" "$mp3file" 1>/dev/null 2>&1
+ fi
+}
+
+writetags() {
+ file="$mp3file"
+ [ "$A" ] && mid3v2 -A "$A" "$file"
+ [ "$TPE2" ] && mid3v2 --TPE2 "$TPE2" "$file"
+ [ "$a" ] && mid3v2 -a "$a" "$file"
+ [ "$TBPM" ] && mid3v2 --TBPM "$TBPM" "$file"
+ [ "$c" ] && mid3v2 -c "$c" "$file"
+ [ "$y" ] && mid3v2 -y "$y" "$file"
+ [ "$g" ] && mid3v2 -g "$g" "$file"
+ [ "$TKEY" ] && mid3v2 --TKEY "$TKEY" "$file"
+ [ "$t" ] && mid3v2 -t "$t" "$file"
+ if [ "$T" ]; then
+ if [ "$tt" ]; then mid3v2 -T "$T/$tt" "$file"
+ else mid3v2 -T "$T" "$file"
+ fi
+ fi
+ [ "$rgag" ] && mid3v2 --TXXX "replaygain_album_gain:$rgag" "$file"
+ [ "$rgap" ] && mid3v2 --TXXX "replaygain_album_peak:$rgap" "$file"
+ [ "$rgtg" ] && mid3v2 --TXXX "replaygain_track_gain:$rgtg" "$file"
+ [ "$rgtp" ] && mid3v2 --TXXX "replaygain_track_peak:$rgtp" "$file"
+}
+
+flac_decode() {
+ if [ "$rgain" = "Y" ]; then
+ flac --totally-silent \
+ --apply-replaygain-which-is-not-lossless=0t \
+ -o "$wavfile" -d "$flacfile"
+ else
+ flac --totally-silent -o "$wavfile" -d "$flacfile"
+ fi
+}
+
+mp3_encode() {
+ lame --preset insane --add-id3v2 -S "$wavfile" "$mp3file" 1>/dev/null 2>&1
+}
+
+while getopts "c:d:ho:rV?" option; do
+ case $option in
+ c) coverfile="$OPTARG" ;;
+ d) outdir="$OPTARG" ;;
+ h) print_help && exit ;;
+ o) mp3file="$OPTARG" ;;
+ r) rgain="Y" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -f "$@" ] && die_filenotfound "$*"
+
+trap cleanup EXIT
+ttags=$(mktemp ${TMPDIR:-/tmp}/${self}.tags.XXXXXXXX)
+
+[ ! "$outdir" ] && outdir="./"
+base=$(basename "$@" flac)
+flacfile="$@"
+[ ! "$mp3file" ] && mp3file="${base}mp3"
+wavfile="${TMPDIR:-/tmp}/${base}wav"
+
+print_self
+printf "%breading cover from %b%.45s%b\n" \
+ "$_norm" "$_high" "$flacfile" "$_clear"
+[ ! "$coverfile" ] && readcover
+
+print_self
+printf "%breading tags from %b%.46s%b\n" "$_norm" "$_high" "$flacfile" "$_clear"
+readtags
+
+print_self
+printf "%bdecoding %b%.55s%b\n" "$_norm" "$_high" "$flacfile" "$_clear"
+flac_decode
+
+print_self
+printf "%bencoding %b%.55s%b\n" "$_norm" "$_high" "$mp3file" "$_clear"
+mp3_encode
+
+print_self
+printf "%bwriting cover to %b%.47s%b\n" "$_norm" "$_high" "$mp3file" "$_clear"
+writecover
+
+print_self
+printf "%bwriting tags to %b%.48s%b\n" "$_norm" "$_high" "$mp3file" "$_clear"
+writetags
+
+print_self
+printf "%bfinished converting %b%.44s%b\n" \
+ "$_norm" "$_high" "$flacfile" "$_clear"

Return to the top of this page or return to the overview of this repo.

Diff bin/mpt_single.sh

diff --git a/bin/mpt_single.sh b/bin/mpt_single.sh
new file mode 100755
index 0000000..c1ea775
--- /dev/null
+++ b/bin/mpt_single.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Copyright (c) 2019-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- mpt_single.sh 2019/11/17 cev, last updated 2021/12/07.
+## Usage: mpt_single.sh [-hV] [-g gain] [-s rate] <file>
+##
+## Use openmpt123 to render <file> to flac.
+##
+## -g Set output gain to <gain> dB (passed to openmpt123)
+## -h Show help
+## -s Set samplerate to <rate> (passed to openmpt123)
+## -V Print version info
+#
+# TODO: This could be fleshed out quite a bit.
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+
+gain="-1.0"
+samplerate="44100"
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+do_file() {
+ openmpt123 --dither 1 --gain "$gain" \
+ --no-float --samplerate "$samplerate" \
+ --no-details --no-progress --no-meters \
+ --render "$*"
+ modtype="$(printf "%s" "$*" | awk -F. '{ print $NF }')"
+ bname="$(basename "$*" ".$modtype")"
+ flac --totally-silent -o "$bname.flac" "$*.wav"
+ rm "$*.wav"
+}
+
+while getopts "g:hs:V?" option; do
+ case $option in
+ g) gain="$OPTARG" ;;
+ h) print_help && exit ;;
+ s) samplerate="$OPTARG" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -e "$*" ] && die_filenotfound "$*"
+
+do_file "$*"
+
+exit 0

Return to the top of this page or return to the overview of this repo.

Diff bin/sox_spectrogram.sh

diff --git a/bin/sox_spectrogram.sh b/bin/sox_spectrogram.sh
new file mode 100755
index 0000000..d914af2
--- /dev/null
+++ b/bin/sox_spectrogram.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# Copyright (c) 2016-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- sox_spectrogram.sh 2016/07/14 cev, last updated 2022/01/29
+## Usage: sox_spectrogram.sh [-hV] [-o outputfile] <audiofile>
+##
+## Frontend for sox -n spectrogram. By default, generate a temporary
+## spectrogram of <audiofile> using sox and display it to the screen
+## with an image viewer. If -o outputfile is specified, then instead
+## generate a spectrogram image file of name outputfile and exit.
+##
+## -h Show help
+## -o Output file name
+## -V Print version info
+# TODO: implement option to choose image viewer; currently xdg-open
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+comment=""
+outfile=""
+shortname=""
+tmpfile=""
+
+cleanup() {
+ if [ "$tmpfile" -a -r "$tmpfile" ]; then rm "$tmpfile"; fi
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+x_spectrogram() {
+ sox "$1" -n spectrogram -h -m -t "$shortname" -c "$comment" -o "$2"
+}
+
+while getopts "ho:V?" option; do
+ case $option in
+ h) print_help && exit ;;
+ o) outfile="$OPTARG" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -f "$*" ] && die_filenotfound "$*"
+
+# TODO: third option: auto-generate output file name based on input file name.
+# something like:
+# for i in *mp3; do
+# sox "$i" -n spectrogram -c "$i" -o "$(basename "$i" ".mp3") [spec].png"
+# done
+
+shortname="$(basename "$*")"
+comment="$(file -b "$*")"
+
+if [ "$outfile" ]; then
+ x_spectrogram "$*" "$outfile"
+else
+ trap cleanup EXIT
+ tmpfile=$(mktemp ${TMPDIR:-/tmp}/${self}.1.XXXXXXXX)
+ x_spectrogram "$*" "$tmpfile"
+ xdg-open "$tmpfile"
+fi

Return to the top of this page or return to the overview of this repo.

Diff bin/tag_cover.sh

diff --git a/bin/tag_cover.sh b/bin/tag_cover.sh
new file mode 100755
index 0000000..c4dc644
--- /dev/null
+++ b/bin/tag_cover.sh
@@ -0,0 +1,144 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- tag_cover.sh 2016/07/05 cev, updated 2021/07/23 & 2022/01/29.
+## Usage: tag_cover.sh [-3fdhvV] [-c coverfile] <file>
+##
+## Add a cover image to an audio file (mp3 or flac) or display the
+## cover image embedded in an existing file.
+##
+## -3 Operate on mp3 files
+## -f Operate on flac files
+## -c Use [coverfile] instead of "00 cover.jpg"
+## -d Display cover embedded in file <file> to the screen
+## -h Show help
+## -v Verbose
+## -V Print version info
+#
+# TODO: better error checking.
+# TODO: implement option to choose image viewer instead of xdg-open
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+filetype=""
+fileext=""
+cover="00 cover.jpg"
+display=""
+verbose=""
+tdir=""
+
+if [ "$self" = "flac_cover.sh" -o "$self" = "flac_cover" ]; then
+ filetype="flac"
+ fileext="flac"
+elif [ "$self" = "mp3_cover.sh" -o "$self" = "mp3_cover" ]; then
+ filetype="mp3"
+ fileext="mp3"
+fi
+
+cleanup() {
+ if [ -n "$tdir" -a -d "$tdir" ]; then
+ rm -f $tdir/*.*
+ rmdir $tdir
+ fi
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+die_unknownfiletype() {
+ shortname="$(basename "$*")"
+ print_unknownfiletype "$shortname"
+ exit 1
+}
+
+is_flac() { test_mimetype.sh -t "audio/x-flac" "$@" ; }
+
+is_mp3() {
+ if test_mimetype.sh -t "audio/mpeg" "$@"; then
+ return 0
+ else
+ # test file extension
+ tmpname="$(basename "$@" ".mp3")"
+ tmpname2="${@##$tmpname}"
+ if [ "$tmpname2" = ".mp3" ]; then
+ return 0
+ fi
+ fi
+ return 1
+}
+
+flac_getcover() {
+ metaflac --export-picture-to="$tdir/$cover" "$*" 2>/dev/null
+}
+
+flac_setcover() {
+ metaflac --import-picture-from="3||||$cover" "$1"
+}
+
+mp3_getcover() {
+ eyeD3 --write-images "$tdir" "$*" 1>/dev/null 2>&1
+}
+
+mp3_setcover() {
+ eyeD3 --add-image="${cover}:FRONT_COVER:" "$1"
+}
+
+while getopts "3fc:dhvV?" option; do
+ case $option in
+ 3) filetype="mp3" && fileext="mp3" ;;
+ f) filetype="flac" && fileext="flac" ;;
+ c) cover="$OPTARG" ;;
+ d) display="y" ;;
+ h) print_help && exit 0 ;;
+ v) verbose="y" ;;
+ V) print_version && exit 0 ;;
+ "?") print_help && exit 0 ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -f "$*" ] && die_filenotfound "$*"
+
+if [ "$filetype" ]; then
+ eval get_cover=\${filetype}_getcover
+ eval set_cover=\${filetype}_setcover
+elif is_flac "$@"; then
+ filetype="flac" && fileext="flac"
+ get_cover="flac_getcover"
+ set_cover="flac_setcover"
+elif is_mp3 "$@"; then
+ filetype="mp3" && fileext="mp3"
+ get_cover="mp3_getcover"
+ set_cover="mp3_setcover"
+else
+ die_unknownfiletype "$*"
+fi
+
+if [ "$display" ]; then
+ trap cleanup EXIT
+ tdir=$(mktemp -d ${TMPDIR:-/tmp}/${self}.XXXXXXXX)
+ $get_cover "$*"
+ xdg-open "$tdir"/* &
+ sleep 1
+ exit 0
+else
+ if [ "$verbose" ]; then
+ print_self
+ printf "%badding cover '%b%s%b' to file '%b%s%b'%b\n" "$_norm" \
+ "$coverfile" "$_high" "$_norm" "$_high" "$*" "$_norm" "$_clear"
+ fi
+ $set_cover "$*"
+ exit 0
+fi

Return to the top of this page or return to the overview of this repo.

Diff bin/tag_key.sh

diff --git a/bin/tag_key.sh b/bin/tag_key.sh
new file mode 100755
index 0000000..c4f897a
--- /dev/null
+++ b/bin/tag_key.sh
@@ -0,0 +1,177 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- tag_key.sh 2016/01/05 cev, updated 2021/07/23 and 2022/01/29.
+## Usage: tag_key.sh [-3fhwV] <file>
+##
+## Shell script frontend for Mark Hills' *nix port of Ibrahim Sha'ath's
+## excellent "keyfinder" program.
+##
+## -3 Operate on mp3 files
+## -f Operate on flac files
+## -h Show help
+## -w Write detected key to KEY tag and COMMENT tag.
+## -V Print version info
+#
+# See http://www.ibrahimshaath.co.uk/keyfinder/ ,
+# https://github.com/ibsh/is_KeyFinder , and www.pogo.org.uk/~mark/key-tools/
+# for more information.
+#
+# TODO: Split writing to KEY and COMMENT to different options.
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+keybin="$HOME/bin/key"
+filetype=""
+fileext=""
+write=""
+
+if [ $self = "flac_key.sh" -o $self = "flac_key" ]; then
+ filetype="flac"
+ fileext="flac"
+elif [ $self = "mp3_key.sh" -o $self = "mp3_key" ]; then
+ filetype="mp3"
+ fileext="mp3"
+fi
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+die_istagged() {
+ print_self error
+ printf "%b%s%b already tagged, key: %b%s%b\n" \
+ "$_high" "$*" "$_norm" "$_high" "$key" "$_clear" >&2
+ exit 1
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+die_nokeyfound() {
+ print_self error
+ printf "%bcould not detect a key for file " "$_norm" >&2
+ printf "%b%s%b.%b\n" "$_high" "$*" "$_norm" "$_clear" >&2
+ exit 1
+}
+
+die_unknownfiletype() {
+ shortname="$(basename "$*")"
+ print_unknownfiletype "$shortname"
+ exit 1
+}
+
+is_flac() { test_mimetype.sh -t "audio/x-flac" "$@" ; }
+
+is_mp3() {
+ if test_mimetype.sh -t "audio/mpeg" "$@"; then
+ return 0
+ else
+ # test file extension
+ tmpname="$(basename "$@" ".mp3")"
+ tmpname2="${@##$tmpname}"
+ if [ "$tmpname2" = ".mp3" ]; then
+ return 0
+ fi
+ fi
+ return 1
+}
+
+mp3_comment() {
+ comm="$(mid3v2 --list "$@" | grep COMM | sed -e 's/COMM=//' | sed -e 's/^=eng=//')"
+}
+
+flac_comment() {
+ comm="$(metaflac --show-tag=COMMENT "$@" | sed -e 's/COMMENT=//')"
+}
+
+append_comment() {
+ if [ -z "$comm" ]; then
+ comm="$@"
+ else
+ comm="$@ - $comm"
+ fi
+}
+
+is_tagged() {
+ if [ -n "$key" ] && ! $force; then
+ die_istagged "$*"
+ fi
+}
+
+wrap_key() {
+ # TODO error checking
+ key="$(sox -V1 "$@" -r 44100 -e float -c 1 -t raw - | "$keybin")"
+ [ -z "$key" ] && die_nokeyfound "$*"
+}
+
+flac_key() {
+ key="$(metaflac --show-tag=INITIALKEY "$@" | sed -e 's/INITIALKEY=//')"
+ is_tagged "$@"
+ wrap_key "$@"
+ flac_comment "$@"
+ append_comment "$key"
+ key="$(printf "%s" "$key" | cut -d' ' -f 1)"
+ print_key "$key" "$comm"
+ if [ "$write" ]; then
+ metaflac --remove-tag=INITIALKEY --set-tag="INITIALKEY=$key" "$@"
+ metaflac --remove-tag=COMMENT --set-tag="COMMENT=$comm" "$@"
+ fi
+}
+
+mp3_key() {
+ key="$(mid3v2 --list "$@" | grep TKEY | sed -e 's/TKEY=//')"
+ is_tagged "$@"
+ wrap_key "$@"
+ mp3_comment "$@"
+ append_comment "$key"
+ key="$(printf "%s" "$key" | cut -d' ' -f 1)"
+ print_key "$key" "$comm"
+ if [ "$write" ]; then
+ mid3v2 --TKEY "$key" "$@"
+ mid3v2 -c "$comm" "$@"
+ fi
+}
+
+print_key() {
+ print_self
+ printf "%bkey '%b%s%b', " "$_norm" "$_high" "$1" "$_norm"
+ printf "comment: %b%.49s%b\n" "$_high" "$2" "$_clear"
+}
+
+while getopts "3fhwV?" option; do
+ case $option in
+ 3) filetype="mp3" && fileext="mp3" ;;
+ f) filetype="flac" && fileext="flac" ;;
+ h) print_help && exit ;;
+ w) write="yes" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -f "$*" ] && die_filenotfound "$*"
+
+if [ "$filetype" ]; then
+ eval func=\${filetype}_key
+elif is_flac "$*"; then
+ filetype="flac" && fileext="flac"
+ func="flac_key"
+elif is_mp3 "$*"; then
+ filetype="mp3" && fileext="mp3"
+ func="mp3_key"
+else
+ die_unknownfiletype "$*"
+fi
+
+$func "$*"
+exit 0

Return to the top of this page or return to the overview of this repo.

Diff bin/tag_rg.sh

diff --git a/bin/tag_rg.sh b/bin/tag_rg.sh
new file mode 100755
index 0000000..27bdf68
--- /dev/null
+++ b/bin/tag_rg.sh
@@ -0,0 +1,140 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- tag_key.sh 2016/01/16 cev, updated 2021/07/23 and 2022/01/29
+## Usage: tag_rg.sh [-3fhV] <file>
+##
+## Simple shim/frontend script to mp3gain and, somewhat unnecessarily,
+## metaflac --add-replay-gain. Adds replaygain_track_gain and replaygain
+## _album_gain id3 tags to an mp3, or the full replaygain complement
+## to a flac.
+##
+## -3 Operate on mp3 files
+## -f Operate on flac files
+## -h Show help
+## -V Print version info
+#
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+filetype=""
+fileext=""
+rgfile=""
+
+if [ $self = "flac_rg.sh" -o $self = "flac_rg" ]; then
+ filetype="flac"
+ fileext="flac"
+elif [ $self = "mp3_rg.sh" -o $self = "mp3_rg" ]; then
+ filetype="mp3"
+ fileext="mp3"
+fi
+
+cleanup() {
+ if [ -n "$rgfile" -a -e "$rgfile" ]; then rm $rgfile; fi
+}
+
+die_filenotfound() {
+ print_filenotfound "$*"
+ exit 1
+}
+
+die_nofile() {
+ print_nofile
+ exit 1
+}
+
+die_unknownfiletype() {
+ shortname="$(basename "$*")"
+ print_unknownfiletype "$shortname"
+ exit 1
+}
+
+is_flac() { test_mimetype.sh -t "audio/x-flac" "$@" ; }
+
+is_mp3() {
+ if test_mimetype.sh -t "audio/mpeg" "$@"; then
+ return 0
+ else
+ # test file extension
+ tmpname="$(basename "$@" ".mp3")"
+ tmpname2="${@##$tmpname}"
+ if [ "$tmpname2" = ".mp3" ]; then
+ return 0
+ fi
+ fi
+ return 1
+}
+
+mp3_rg_format_db() {
+ printf "%.2f dB" "$mp3rgaindb"
+}
+
+# Not going to do any error checking and/or stderr redirection in here,
+# because this is simple enough that I'd rather just see the error.
+mp3_rg() {
+ trap cleanup EXIT
+ rgfile=$(mktemp ${TMPDIR:-/tmp}/${self}.1.XXXXXXXX)
+ mp3gain -q -s s -k -o "$@" 1>$rgfile
+ zIFS="$IFS"
+ IFS=" "
+ # TODO: which one of these fields is album_peak / track_peak ? and/or
+ # how do we calculate those values?
+ # File \t MP3 gain \t dB gain \t Max Amplitude \t Max global_gain \t Min g_g
+ while read mp3file mp3rgain mp3rgaindb mp3maxamp mp3maxgg mp3mingg; do
+ [ "$mp3file" = "File" ] && continue
+ [ "$mp3file" = "\"Album\"" ] && break
+ mid3v2 --delete-frames="TXXX" "$mp3file"
+ mp3rgaindb=$(mp3_rg_format_db "$mp3rgaindb")
+ mid3v2 --TXXX "replaygain_track_gain:$mp3rgaindb" "$mp3file"
+ done < $rgfile
+ IFS="$zIFS"
+ if [ "$mp3file" = "\"Album\"" ]; then
+ mp3rgaindb=$(mp3_rg_format_db "$mp3rgaindb")
+ for i in "$@"; do
+ mid3v2 --TXXX "replaygain_album_gain:$mp3rgaindb" "$i"
+ done
+ fi
+ [ -f "$rgfile" ] && rm $rgfile
+}
+
+flac_rg() {
+ # a thousand thanks to the flac team for making this sane / easy.
+ # This script could have just been called "mp3_rg.sh", and I could have
+ # certainly left this flac "capability" out; I've included it just so I
+ # don't have to remember the option to metaflac. Not that it's hard to
+ # remember...
+ metaflac --add-replay-gain "$@"
+}
+
+while getopts "3fhV?" option; do
+ case $option in
+ 3) filetype="mp3" && fileext="mp3" ;;
+ f) filetype="flac" && fileext="flac" ;;
+ h) print_help && exit ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+[ $# -lt 1 ] && die_nofile
+[ ! -e "$*" ] && die_filenotfound "$*"
+
+if [ "$filetype" ]; then
+ eval func=\${filetype}_rg
+elif is_flac "$@"; then
+ filetype="flac" && fileext="flac"
+ func="flac_rg"
+elif is_mp3 "$@"; then
+ filetype="mp3" && fileext="mp3"
+ func="mp3_rg"
+else
+ die_unknownfiletype "$*"
+fi
+
+$func "$@"
+exit 0

Return to the top of this page or return to the overview of this repo.

Diff bin/test_mimetype.sh

diff --git a/bin/test_mimetype.sh b/bin/test_mimetype.sh
new file mode 100755
index 0000000..fefda7e
--- /dev/null
+++ b/bin/test_mimetype.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+#
+# Copyright (c) 2015-2022, Cameron Vanderzanden. Available under the
+# terms of the 2-clause BSD license. Please see the file "LICENSE" in
+# the root dir of this repository for more information.
+#
+#- test_mimetype.sh 2016/01/05 cev, updated 2021/07/23 and 2022/01/29 cev
+## Usage: test_mimetype.sh [-hvV] [-t type] <file>
+##
+## Call file(1) on <file> to determine if <file> is a file of mime type
+## [-t type]. Type defaults to text/plain.
+##
+## -h Show help
+## -t Test against mimetype [type].
+## -v Verbose
+## -V Print version info
+
+[ -x $HOME/bin/cev_print.sh ] && . $HOME/bin/cev_print.sh
+
+self="${0##*'/'}"
+testtype="text/plain"
+verbose=""
+
+while getopts "ht:vV?" option; do
+ case $option in
+ h) print_help && exit ;;
+ t) testtype="$OPTARG" ;;
+ v) verbose="Y" ;;
+ V) print_version && exit ;;
+ "?") print_help && exit ;;
+ esac
+ shift $((OPTIND - 1))
+done
+
+if [ $# -lt 1 ]; then
+ print_nofile
+ exit 2
+else
+ filename="$@"
+ shortname="$(basename "$@")"
+
+ if [ ! -f "$filename" ]; then
+ print_filenotfound "$filename"
+ exit 3
+ fi
+
+ filetype="$(file -b --mime-type "$filename")"
+ if [ "$filetype" = "$testtype" ]; then
+ if [ "$verbose" ]; then
+ print_self
+ printf "%b%s%b is %b%s%b\n" \
+ "$_high" "$shortname" "$_norm" "$_high" "$testtype" "$_clear"
+ fi
+ exit 0
+ else
+ if [ "$verbose" ]; then
+ print_self
+ printf "%b%s%b is not %b%s%b\n" \
+ "$_high" "$shortname" "$_norm" "$_high" "$testtype" "$_clear"
+ fi
+ exit 1
+ fi
+fi

Return to the top of this page or return to the overview of this repo.