Skip to content

Instantly share code, notes, and snippets.

@carlwilson
Created March 15, 2021 14:08
Show Gist options
  • Save carlwilson/958e4c7945d6608781898c5ffb69f22e to your computer and use it in GitHub Desktop.
Save carlwilson/958e4c7945d6608781898c5ffb69f22e to your computer and use it in GitHub Desktop.
MUX shell script for Zaireeka
#!/usr/bin/env bash
#
# Script to mix multiple CDs (< 10) into all combinations (order considered unimportant).
# Mixing to a set of 2 channel mixes where all lefts are combined to the final left
# channel and all right channels are combined to the final right.
#
# While I've tried to make it reasonably forgiving failure to follow these rules
# may have unexpected results.
#
# CD Directory rules:
# - each ripped CD Directory must share a single parent dir.
# - only one disc number in each CD Directory name.
# - disc number can be any number above zero (64bit int limit?)
# - CD Directory names must consistently start OR end with their disc number
# NO digits in the middle, no mix and matching
# - NO duplicate disc numbers
#
# Track file rules:
# - all track files must share the same CD Diretory parent
# - files are mixed across all combinations of CD
# - NO duplicate track numbers
# - to be mixable track files must have the same sample rate, and format
# formats could vary between different tracks, but not across copies of the
# same track (matched by track number)
# - if mixed track files have different duration, result will truncate at the shortest
#
combine() {
# Create the combinations for mixing the discs
# Thanks to 'Nominal Animal' on Linux Questions
# Taken from https://www.linuxquestions.org/questions/programming-9/strings-combinations-945160/
local limit=$[ 1 << $# ]
local args=("$@")
for ((value = 1; value < limit; value++)); do
local parts=()
for ((i = 0; i < $#; i++)); do
[ $[(1<<i) & value] -ne 0 ] && parts[${#parts[@]}]="${args[i]}"
done
# If we have combinations then mix the discs
if [ "${#parts[@]}" -gt 1 ]; then
mix_discs "${parts[@]}"
fi
done
}
mix_discs() {
# Perform the mixing from the combos
local args=("$@")
# Create combo disk number from the array parts
discno=`quick_join '' "$@"`
# Get the pre/post fix info and create the ouput directory name
discindex="${args[0]} - 1"
[[ "${fixtype[$discindex]}" =~ post ]] && primesrc=`echo "${args[0]}""${fixes[$discindex]}"` || primesrc=`echo "${fixes[$discindex]}""${args[0]}"`
[[ "${fixtype[$discindex]}" =~ post ]] && destdir=`echo "MUXED""${discno}""${fixes[$discindex]}"` || destdir=`echo "MUXED""${fixes[$discindex]}""${discno}"`
# Make the output dir if it doesn't exist
[[ -d $destdir ]] || mkdir "$destdir"
# Loop through the tracks and grab the track number
find "${primesrc}" -type f -print0 | while IFS= read -r -d '' track; do
# Grap the track number
trackname=${track##*/}
if [[ ${trackname} =~ ^[0-9] ]]; then
# Assume it's a track (it starts with a number
# Start building the ffmpeg command
local ffmpegcmd=(ffmpeg -i "${track}")
# grab the track number
trackno=`grep -o '^[0-9]\+' <<< ${trackname}`
for (( i=1; i<${#args[@]}; i++ ));
# Loop through the to be muxed directory entries
do
supdiscidx="${args[$i]} - 1"
[[ "${fixtype[$supdiscidx]}" =~ post ]] && suppsrc=`echo "${args[$i]}""${fixes[$supdiscidx]}"` || suppsrc=`echo "${fixes[$supdiscidx]}""${args[$i]}"`
suptrack=`ls ${suppsrc}/${trackno}*`
# If we find the track add the input file
ffmpegcmd+=(-i "${suptrack}")
done
# add input and filter stuff, keep it stereo for now
ffmpegcmd+=(-filter_complex amerge=inputs=${#args[@]} -ac 2 "${destdir}/${trackname}")
echo "${ffmpegcmd[@]}"
# Execute the ffmpeg command for this MUX
"${ffmpegcmd[@]}" < /dev/null
fi
done
}
# Quick efficient array join
# Courtesy of https://dev.to/meleu/how-to-join-array-elements-in-a-bash-script-303a
quick_join () { local IFS="$1"; shift; echo "$*"; }
# EXECUTION STARTS HERE
# Use param as root dir or use current directory if no param
rootdir="."
[[ ! -z "$1" ]] && rootdir=$1
# Go to root, bail if it doesn't exist
cd $rootdir || exit
# Get the directory listing, looking for the individual disc dirs
dirs=(*)
for (( i=0; i<${#dirs[@]}; i++ ));
# Loop through directory entries
do
if [[ -d ${dirs[$i]} ]] && [[ ! ${dirs[$i]} =~ ^MUXED ]] && ([[ ${dirs[$i]} =~ ^[0-9] ]] || [[ ${dirs[$i]} =~ [0-9]$ ]]); then
# if it's a directory, it doesn't start with MUXED (previous output) and
# it's name starts or ends with a number, work out the prefix/postfix type
[[ ${dirs[$i]} =~ ^[0-9] ]] && fixtype[$i]="post" || fixtype[$i]="pre"
# Get the Disc number
cdnums[$i]=`grep -o '[0-9]\+' <<< ${dirs[$i]}`
# grab the pre/post fix value
fixes[$i]=`grep -o '[^0-9]\+' <<< ${dirs[$i]}`
fi
done
# Let the combination fun begin...
combine "${cdnums[@]}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment