summaryrefslogtreecommitdiff
path: root/sound-cutter.in
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2016-05-03 15:59:01 +0200
committerErich Eckner <git@eckner.net>2016-05-03 15:59:01 +0200
commitd45176c24a2110a8a177ed3dcae35b15cfd78ab3 (patch)
treed81af4ac9f62c828c8fa74fbbe1d78a951c43d24 /sound-cutter.in
parent1ec1f71c318c223d10f6f0f8d24a2ca5a39ec9e5 (diff)
downloadsound-cutter-d45176c24a2110a8a177ed3dcae35b15cfd78ab3.tar.xz
manpage neu, Makefile neu, version updatev1.0.1
Diffstat (limited to 'sound-cutter.in')
-rwxr-xr-xsound-cutter.in333
1 files changed, 333 insertions, 0 deletions
diff --git a/sound-cutter.in b/sound-cutter.in
new file mode 100755
index 0000000..2878350
--- /dev/null
+++ b/sound-cutter.in
@@ -0,0 +1,333 @@
+#!/bin/bash
+
+set -e
+
+verwendung() {
+ >&2 echo 'Dies ist sound-cutter Version #VERSION#'
+ >&2 echo ''
+ >&2 echo 'Verwendung:'
+ >&2 echo ''
+ >&2 echo "${me}"' [ -f | --force ] [ -a | --ausfuehrlich ] [ -1 | --noGain ] [ -n | --dummy ] { ( -i | --input ) input$i.flac } ( -o | --output ) output.flac ( -p | --points ) points'
+ >&2 echo ''
+ >&2 echo ' Mischen und Schneiden:'
+ >&2 echo ' -f | --force: output.flac ggf. überschreiben'
+ >&2 echo ' -1 | --noGain: Lautstärke nicht normalisieren'
+ >&2 echo ' -n | --dummy: nur auszuführenden Befehl anzeigen und nichts tun'
+ >&2 echo ' -s | --sampleRate: alternative Samplerate zum Abspeichern'
+ >&2 echo ' -i | --input: Quelle'
+ >&2 echo ' -o | --output: Ziel'
+ >&2 echo ' -p | --points: Punktedatei'
+ >&2 echo ' -a | --ausfuehrlich: ausführliche Zwischenausgaben machen'
+ >&2 echo ''
+ >&2 echo "$0"' [ -h | --help ]'
+ >&2 echo ' Hilfe anzeigen'
+ >&2 echo ''
+ [ -z "$1" ] && exit 1 || exit $1
+}
+
+timetosample() {
+ local zeit
+ case "$2" in
+ *:*:*)
+ zeit="$2"
+ ;;
+ *:*)
+ zeit="0:$2"
+ ;;
+ *)
+ zeit="0:0:0$2"
+ ;;
+ esac
+ bc <<< "( 0.5 + $1 * $(date "+%s.%N" -ud "1970-01-01 ${zeit}") ) / 1"
+}
+
+me="$(readlink -f "$0")"
+
+eval set -- "$(
+ getopt -o 1ahfi:no:p:s: \
+ --long noGain \
+ --long ausfuehrlich \
+ --long help \
+ --long force \
+ --long input: \
+ --long dummy \
+ --long output: \
+ --long points: \
+ --long sampleRate: \
+ -n "$(basename "$0")" -- "$@" || \
+ echo verwendung
+)"
+
+noGain=false
+ausfuehrlich=false
+force=false
+dummy=false
+
+while true; do
+ case "$1" in
+ -1|--noGain)
+ noGain=true
+ ;;
+ -a|--ausfuehrlich)
+ ausfuehrlich=true
+ ;;
+ -f|--force)
+ force=true
+ ;;
+ -h|--help)
+ verwendung 0
+ ;;
+ -i|--input)
+ shift
+ inputs[${#inputs[@]}]="$1"
+ ;;
+ -n|--dummy)
+ dummy=true
+ ;;
+ -o|--output)
+ shift
+ [ -n "${output}" ] && echo 'Ich kann nur eine Output-Datei-Option verstehen.' && verwendung
+ output="$1"
+ ;;
+ -p|--points)
+ shift
+ [ -n "${points}" ] && echo 'Ich kann nur eine Point-Datei-Option verstehen.' && verwendung
+ points="$1"
+ ;;
+ -s|--sampleRate)
+ shift
+ [ -n "${outRate}" ] && echo 'Ich kann nur eine Samplerate-Option verstehen.' && verwendung
+ outRate="$1"
+ ;;
+ --)
+ shift
+ [ $# -gt 0 ] && echo 'Unbekannte Parameter: '"$#" && verwendung
+ break
+ ;;
+ *)
+ >&2 echo 'Hups, das sollte nicht passieren könne, '"$1"' kenne ich doch nicht ...'
+ exit -1
+ ;;
+ esac
+ shift
+done
+
+[ -z "${output}" ] && >&2 echo 'Output-Datei fehlt!' && verwendung
+[ -z "${points}" ] && >&2 echo 'Points-Datei fehlt!' && verwendung
+[ "${#inputs[@]}" -eq 0 ] && >&2 echo 'Input-Datei fehlt!' && verwendung
+
+[ ! -e "${points}" ] && >&2 echo "Die Schnittpunktedatei '${points}' existiert nicht!" && exit 1
+for inp in "${inputs[@]}"
+do
+ [ ! -e "${inp}" ] && >&2 echo "Die Inputdatei '${inp}' existiert nicht!" && verwendung
+ [ $(echo "${inp}" | grep -c "\s") -gt 0 ] && >&2 echo "Bitte keine Leerzeichen im input-Dateinamen!" && exit 1
+done
+
+[ $(echo "${output}" | grep -c "\s") -gt 0 ] && >&2 echo "Bitte keine Leerzeichen im output-Dateinamen!" && exit 1
+[ $(echo "${points}" | grep -c "\s") -gt 0 ] && >&2 echo "Bitte keine Leerzeichen im points-Dateinamen!" && exit 1
+
+if [ -e "${output}" ]
+then
+ if ${force}
+ then
+ ${dummy} || rm "${output}"
+ else
+ >&2 echo "Die Ausgabedatei '${output}' existiert bereits!" && exit 1
+ fi
+fi
+odn="$(dirname "$(readlink -f "${output}")")"
+obn="$(basename "${output}")"
+if [ $(ls -1 "${odn}" | grep "$(echo "${obn}" | sed "s/%[0-9]\?n/.*/g")" | wc -l) -gt 0 ]
+then
+ if ${force}
+ then
+ ${dummy} || rm ${odn}/$(echo "${obn}" | sed "s/%[0-9]\?n/*/g")
+ else
+ >&2 echo "Die Ausgabedatei '${output}' existiert bereits!" && exit 1
+ fi
+fi
+
+inRate="$(soxi -r "${inputs[0]}")"
+[ -z "${outRate}" ] && outRate="${inRate}"
+
+i=-1
+absInTime=0
+absOutTime=0
+while read -r in
+do
+ line="$(
+ echo "${in}" | \
+ sed 's|\s\+| |g' | \
+ sed 's/^ *//' | \
+ sed 's/ *\(\#\( .*\)\?\)\?$//'
+ )"
+ [ -z "${line}" ] && continue
+ teilEins="$(echo "${line}" | sed 's| *\(#.*\)\?$||')"
+ teilZwei="$(echo "${line}" | sed 's|^[^#]*\(# *\)\?||')"
+
+ if [ ${i} -eq -1 ]
+ then
+ firstline="${teilEins}"
+ remixcmd="${teilZwei}"
+ if echo "${remixcmd}" | \
+ grep -q "rate "
+ then
+ >&2 echo 'FEHLER: "rate" explizit gesetzt, das bringt die Zeitmessung durcheinander - verwende statt dessen die Option "-s" bzw. "--sampleRate".'
+ verwendung
+ fi
+ i=0
+ continue
+ fi
+ if [ -z "${teilEins}" ]
+ then
+ if [ -n "${trackmods[${i}]}" ]
+ then
+ echo "Syntaxfehler in Track $[${i}+1]: habe bereits Modifikatoren gelesen ('${trackmods[${i}]}' -> '${teilZwei}')"
+ exit 1
+ fi
+ trackmods[${i}]=" ${teilZwei}"
+ inTimecorrections[${i}]=0
+ outTimecorrections[${i}]=0
+ while echo "${trackmods[${i}]}" | grep -q " trimsplice"
+ do
+ rest="${trackmods[${i}]#* trimsplice}"
+
+ end=$(timetosample ${inRate} $(echo "${rest}" | awk '{print $1}'))
+ if [ ! "${doverlaps[${i}]}" == "" ]
+ then
+ end=$[${end}+${doverlaps[${i}]}]
+ fi
+ inDiscard=$(timetosample ${inRate} $(echo "${rest}" | awk '{print $2}'))
+ outDiscard=$(timetosample ${outRate} $(echo "${rest}" | awk '{print $2}'))
+ inExcess=$(timetosample ${inRate} $(echo "${rest}" | awk '{print $3}'))
+ outExcess=$(timetosample ${outRate} $(echo "${rest}" | awk '{print $3}'))
+ leeway=$(timetosample ${inRate} $(echo "${rest}" | awk '{print $4}'))
+
+ trackmods[${i}]="$(
+ echo "${trackmods[${i}]}" | \
+ sed "s/ \+trimsplice\( \+[^ ]\+\)\{4\}/ trim 0s ${end}s ${inDiscard}s splice -t ${end}s,${inExcess}s,${leeway}s/"
+ )"
+ inTimecorrections[${i}]=$[${inTimecorrections[${i}]}+${inDiscard}+2*${inExcess}]
+ outTimecorrections[${i}]=$[${outTimecorrections[${i}]}+${outDiscard}+2*${outExcess}]
+ done
+ continue
+ fi
+
+ i=$[${i}+1]
+
+ tmp=$(timetosample ${inRate} "${teilEins}")
+ inTimes[${i}]=$[${tmp}-${absInTime}]
+ absInTime=${tmp}
+ tmp=$(timetosample ${outRate} "${teilEins}")
+ outTimes[${i}]=$[${tmp}-${absOutTime}]
+ absOutTime=${tmp}
+
+ newFile[${i}]=true
+ teilZwei="${teilZwei} "
+ while [ -n "${teilZwei}" ]
+ do
+ case "${teilZwei}" in
+ "overlap "*)
+ teilZwei="${teilZwei#* }"
+ overlaps[${i}]=$[$(timetosample ${inRate} ${teilZwei%% *})/2]
+ doverlaps[${i}]=$[2*${overlaps[${i}]}]
+ teilZwei="${teilZwei#* }"
+ ;;
+ "noNewFile"*)
+ teilZwei="${teilZwei#* }"
+ newFile[${i}]=false
+ ;;
+ " ")
+ break
+ ;;
+ *)
+ >&2 echo "'${teilZwei}' ist unverständlich zwischen zwei Stücken ('${line}')"
+ exit 1
+ ;;
+ esac
+ done
+done < "${points}"
+
+if ${ausfuehrlich}
+then
+ echo "trackmods:"
+ for (( i=0; i<=${#inTimes[@]}; i++ ))
+ do
+ echo "${i}: ${trackmods[${i}]} ; ${inTimes[${i}]} ; ${overlaps[${i}]} ; ${doverlaps[${i}]} ; ${inTimecorrections[${i}]}"
+ done
+fi
+
+repcmd=""
+abstime=0
+for (( i=1; i<=${#inTimes[@]}; i++ ))
+do
+ abstime=$[${abstime}+${inTimes[${i}]}]
+ [ -z "${doverlaps[${i}]}" ] && continue
+ repcmd="${repcmd} trim 0s $[${abstime}-${doverlaps[${i}]}]s : trim 0s ${doverlaps[${i}]}s repeat :"
+ abstime=0
+done
+
+trackmodcmd=""
+abstime=0
+for (( i=0; i<=${#inTimes[@]}; i++ ))
+do
+ if [ ${i} -gt 0 ]
+ then
+ [ -n "${inTimecorrections[$[${i}-1]]}" ] && \
+ inTimes[${i}]=$[${inTimes[${i}]}-${inTimecorrections[$[${i}-1]]}]
+ [ -n "${outTimecorrections[$[${i}-1]]}" ] && \
+ outTimes[${i}]=$[${outTimes[${i}]}-${outTimecorrections[$[${i}-1]]}]
+ fi
+
+ [ -n "${inTimes[$[${i}+1]]}" ] && abstime=$[${abstime}+${inTimes[$[${i}+1]]}]
+ [ -n "${doverlaps[${i}]}" ] && abstime=$[${abstime}+${doverlaps[${i}]}]
+ [ "${trackmods[${i}]}" == "${trackmods[$[${i}+1]]}" ] && continue
+ if [ ${i} -eq ${#inTimes[@]} ]
+ then
+ trackmodcmd="${trackmodcmd}${trackmods[${i}]} "
+ else
+ trackmodcmd="${trackmodcmd}trim 0s ${abstime}s${trackmods[${i}]} : "
+ fi
+ abstime=0
+done
+
+splicecmd=""
+abstime=0
+for (( i=0; i<=${#inTimes[@]}; i++ ))
+do
+ [ -n "${inTimes[${i}]}" ] && abstime=$[${abstime}+${inTimes[${i}]}]
+ [ -z "${overlaps[${i}]}" ] && continue
+ splicecmd="${splicecmd} ${abstime}s,${overlaps[${i}]}s,0s"
+ abstime=$[${abstime}+${doverlaps[${i}]}]
+done
+[ -n "${splicecmd}" ] && splicecmd="splice -t${splicecmd}"
+
+trimcmd=""
+for (( i=1; i<=${#outTimes[@]}; i++ ))
+do
+ trimcmd="${trimcmd}trim 0s =${outTimes[${i}]}s : "
+ ${newFile[${i}]} && trimcmd="${trimcmd}newfile : "
+done
+
+[ ${outRate} -ne ${inRate} ] && remixcmd="${remixcmd} rate -v ${outRate}"
+
+if ! ${noGain}
+then
+ firstline="${firstline} gain -b"
+ remixcmd="${remixcmd} gain -n"
+fi
+
+echo sox -M "${inputs[@]}" -p trim ${firstline}
+echo sox -t sox - -p ${repcmd}
+echo sox -t sox - -p ${trackmodcmd}
+echo sox -t sox - -p ${splicecmd} ${remixcmd}
+echo sox -t sox - ${output} ${trimcmd}
+
+if ! ${dummy}
+then
+ sox -M "${inputs[@]}" -p trim ${firstline}| \
+ sox -t sox - -p ${repcmd} | \
+ sox -t sox - -p ${trackmodcmd} | \
+ sox -t sox - -p ${splicecmd} ${remixcmd} | \
+ sox -t sox - ${output} ${trimcmd}
+fi