#!/usr/bin/env 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. encodeFile::mp3() { # Build lame ABR encode command with all available metadata lameopts=(${ionice}lame --quiet --noreplaygain) lameopts+=(-v --abr ${destinationquality[$destination]}) # Embed ID3 tags for each available metadata field [ -n "$album" ] && lameopts+=(--tl "$album" ) [ -n "$artist" ] && lameopts+=(--ta "$artist") [ -n "$genre" ] && lameopts+=(--tg "$genre") [ -n "$title" ] && lameopts+=(--tt "$title") [ -n "$track" ] && lameopts+=(--tn "$track") [ -n "$year" ] && lameopts+=(--ty "$year") # Extended tags using ID3v2 frames (TXXX for custom/non-standard fields) [ -n "$albumartist" ] && lameopts+=(--tv TPE2="$albumartist") [ -n "$composer" ] && lameopts+=(--tv TCOM="$composer") [ -n "$performer" ] && lameopts+=(--tv TOPE="$performer") [ -n "$releasecountry" ] \ && lameopts+=(--tv TXXX="MusicBrainz Album Release Country=$releasecountry") [ -n "$replaygain_alb" ] \ && lameopts+=(--tv "TXXX=REPLAYGAIN_ALBUM_GAIN=$replaygain_alb") [ -n "$replaygain_trk" ] \ && lameopts+=(--tv "TXXX=REPLAYGAIN_TRACK_GAIN=$replaygain_trk") [ -n "$disc" ] && lameopts+=(--tv TPOS="$disc") # Handle noresample: force lame to use a specific sample rate to prevent # lame's own automatic downsampling at low bitrates if (( ${destinationnoresample[$destination]:-0} == 1 )) then # If 'rate' is not one of these value, it cannot be encoded to # MP3, in which case we'd be better of letting lame decide which # rate to use. if [ -n "${destinationfrequency["$destination"]}" ] then # Target frequency was explicitly set; use that case ${destinationfrequency["$destination"]} in 48000) lameopts+=(--resample 48) ;; 44100) lameopts+=(--resample 44.1) ;; 32000) lameopts+=(--resample 32) ;; 24000) lameopts+=(--resample 24) ;; 22050) lameopts+=(--resample 22.05) ;; 16000) lameopts+=(--resample 16) ;; 12000) lameopts+=(--resample 12) ;; 11025) lameopts+=(--resample 11.025) ;; 8000) lameopts+=(--resample 8) ;; esac elif (( rate > 48000 )) then # Source rate exceeds MP3 maximum; cap at 48kHz lameopts+=(--resample 48) else # Use the source file's own sample rate case $rate in 48000) lameopts+=(--resample 48) ;; 44100) lameopts+=(--resample 44.1) ;; 32000) lameopts+=(--resample 32) ;; 24000) lameopts+=(--resample 24) ;; 22050) lameopts+=(--resample 22.05) ;; 16000) lameopts+=(--resample 16) ;; 12000) lameopts+=(--resample 12) ;; 11025) lameopts+=(--resample 11.025) ;; 8000) lameopts+=(--resample 8) ;; esac fi fi # Append input WAV and output MP3 paths to complete the command lameopts+=("$tempdir/$tmpfile.wav" "${destinationpath[$destination]}/$destdir/$destfile.mp3") # Insert the encode task into the DB, linked to the decode (or sox) task # Depend on sox task if it exists, else decode task encodetaskid=$( Insert tasks <<-EOInsert key ${fileid}lame$destination requires ${soxtaskid:-$decodetaskid} fileid $destfileid filename $destdir/$destfile.mp3 $( for key in ${!lameopts[@]} do # Escape special characters that could # interfere with bash glob/brace # expansion cleanedopts="${lameopts[key]//\&/\\\&}" cleanedopts="${cleanedopts//\[/\\[}" cleanedopts="${cleanedopts//\]/\\]}" cleanedopts="${cleanedopts//\{/\\{}" cleanedopts="${cleanedopts//\}/\\\}}" echo "cmd_arg$key $cleanedopts" done ) source_file $fileid status 0 rename_pattern ${destinationrenamepath[$destination]}/${destinationrename[$destination]} fat32compat ${destinationfat32compat["$destination"]} ascii ${destinationascii["$destination"]} EOInsert ) # Increment parent task's required_by counter so it won't clean up # until all children finish parent_required=$( Select tasks required_by \ <<<"id = ${soxtaskid:-$decodetaskid}" ) Update tasks required_by $((++parent_required)) \ <<<"id = ${soxtaskid:-$decodetaskid}" progressSpin soxtaskid='' # Clear sox task ID so next destination starts fresh }