#!/bin/bash # Copyright © 2012-2026 ScriptFanix # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # A copy of the GNU General Public License v3 is includded in the LICENSE file # at the root of the project. # soxtaskid persists across destinations so encode tasks share a single sox task declare soxtaskid decodeFile() { # copy destinations bypass decoding entirely if [[ ${destinationformat["$destination"]} == copy ]] then copied=1 else # Dispatch to the appropriate decoder based on the source # MIME type. # sox_needed is set when normalization, resampling, or channel # up/downmixing is required. Used to determine whether to # insert an intermediate sox processing task. case "$mimetype" in 'video/'*) # Extract audio if ffmpeg is available (( disablevideo )) && continue extractAudio if (( ${destinationnormalize["$destination"]}))\ || ( [ -n "${destinationfrequency["$destination"]}" ]\ && (( ${rate:-0} != ${destinationfrequency["$destination"]}))\ ) || ( [ -n "${destinationchannels["$destination"]}" ]\ && (( ${channels:-0} != ${destinationchannels["$destination"]} )) ) then sox_needed=1 fi ;; 'audio/mpeg') # Copy MP3 as-is if format and quality match # otherwise decode with sox if [[ ${destinationformat[$destination]} = mp3 ]] \ && checkCopy then copied=1 else decodeSox fi ;; 'application/ogg opus'|'audio/ogg opus') # Copy Opus as-is if format and quality match # otherwise decode with opusdec if [[ ${destinationformat[$destination]} = opus ]] \ && checkCopy then copied=1 else (( disableopusdec )) && continue decodeOpusdec if (( ${destinationnormalize["$destination"]}))\ || ( [ -n "${destinationfrequency["$destination"]}" ]\ && (( ${rate:-0} != ${destinationfrequency["$destination"]}))\ ) || ( [ -n "${destinationchannels["$destination"]}" ]\ && (( ${channels:-0} != ${destinationchannels["$destination"]} )) ) then sox_needed=1 fi fi ;; 'application/ogg'*|'audio/ogg'*) # Ogg Vorbis: copy if format/quality match # otherwise decode with sox if [[ ${destinationformat[$destination]} = vorbis ]] \ && checkCopy then copied=1 else decodeSox fi ;; 'audio/x-flac'|'audio/flac') # FLAC: always decode via sox # copy for FLAC makes little sense decodeSox ;; *) # Unknown MIME type: probe with file to detect # Musepack extendedtype=$(file -b "$sourcepath/$filename") case "$extendedtype" in *'Musepack '*) (( disablempcdec )) && continue decodeMpcdec if (( ${destinationnormalize["$destination"]}))\ || ( [ -n "${destinationfrequency["$destination"]}" ]\ && (( ${rate:-0} != ${destinationfrequency["$destination"]}))\ ) || ( [ -n "${destinationchannels["$destination"]}" ]\ && (( ${channels:-0} != ${destinationchannels["$destination"]} )) ) then sox_needed=1 fi ;; *) # Truly unknown format: try # ffmpeg if available, # otherwise fall back to sox if (( disablevideo )) then decodeSox else extractAudio if (( ${destinationnormalize["$destination"]}))\ || ( [ -n "${destinationfrequency["$destination"]}" ]\ && (( ${rate:-0} != ${destinationfrequency["$destination"]}))\ ) || ( [ -n "${destinationchannels["$destination"]}" ]\ && (( ${channels:-0} != ${destinationchannels["$destination"]} )) ) then sox_needed=1 fi fi ;; esac ;; esac if ! (( copied )) then # Insert a decode task if one doesn't already exist for # this source file # keyed by $tmpfile so multiple destinations share a # single decode task if ! decodetaskid=$( Select tasks id <<<"key = $tmpfile" ) then decodetaskid=$( Insert tasks <<-EOInsert key $tmpfile source_file $fileid $( for key in ${!commandline[@]} do echo "cmd_arg$key ${commandline[key]}" done ) status 0 cleanup $tmpfile.wav EOInsert ) progressSpin fi if (( sox_needed )) then # Insert a sox post-processing task chained # after the decode task decodeSox "$tempdir/$tmpfile.wav" if ! soxtaskid=$( Select tasks id <<<"key = $tmpfile" ) then # Increment the decode task's # required_by counter so cleaner() # waits for all dependent tasks to # finish before cleaning up the # intermediate file parent_required=$( Select tasks required_by \ <<<"id = $decodetaskid" ) Update tasks required_by $((++parent_required)) \ <<<"id = $decodetaskid" soxtaskid=$( Insert tasks <<-EOInsert key $tmpfile source_file $fileid $( for key in ${!commandline[@]} do echo "cmd_arg$key ${commandline[key]}" done ) requires $decodetaskid status 0 cleanup $tmpfile.wav EOInsert ) progressSpin fi fi fi fi }