From d45176c24a2110a8a177ed3dcae35b15cfd78ab3 Mon Sep 17 00:00:00 2001 From: Erich Eckner Date: Tue, 3 May 2016 15:59:01 +0200 Subject: manpage neu, Makefile neu, version update --- sound-cutter.in | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100755 sound-cutter.in (limited to 'sound-cutter.in') 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 -- cgit v1.2.3-54-g00ecf