Last active
September 19, 2025 20:26
-
-
Save jethrojones/f4f6f930e3bb62971b607dcafb4b6080 to your computer and use it in GitHub Desktop.
One-drop splitter for RØDECaster Pro (fw 2.x) poly-WAVs. Outputs mono stems for selected mics (defaults: Mic1=ch2, Mic2=ch3). macOS Shortcuts-friendly; logs to /tmp/rode_split.log. Includes a “channel finder” mode to discover which channel index your mics are on.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Split RØDECaster Pro multitrack poly-WAVs into per-channel stems (macOS Shortcuts friendly) | |
| # ----------------------------------------------------------------------------- | |
| # REQUIREMENTS | |
| # - ffmpeg & ffprobe installed (e.g., Homebrew: `brew install ffmpeg`) | |
| # | |
| # DEFAULTS (tuned for RØDECaster Pro 1, fw 2.1.x) | |
| # - Mic 1 is on channel index 2 (zero-based; i.e., 3rd channel in the file) | |
| # - Mic 2 is on channel index 3 | |
| # - Outputs go to a single sibling folder named "split" | |
| # | |
| # QUICK USE | |
| # bash rodecaster_split.sh /path/to/file.wav | |
| # | |
| # TWEAKS (set as environment variables, or edit below) | |
| # MIC1_CH_INDEX : default 2 (e.g., MIC1_CH_INDEX=0 for first channel) | |
| # MIC2_CH_INDEX : default 3 | |
| # NAME1 / NAME2 : default mic1 / mic2 (e.g., NAME1=host NAME2=guest) | |
| # OUTDIR_NAME : default split | |
| # INCLUDE_STEREO : default false (set to true to also export stereo mix as one stereo file) | |
| # FIND_CHANNELS : default false (set to true to export 3-second previews for *every* channel) | |
| # NORM : default false (set to true to add EBU R128 loudness normalization per mic) | |
| # | |
| # EXAMPLES | |
| # # Use different mapping (e.g., mics on ch0 and ch1), and friendly names: | |
| # MIC1_CH_INDEX=0 MIC2_CH_INDEX=1 NAME1=host NAME2=guest bash rodecaster_split.sh file.wav | |
| # | |
| # # Also export the stereo mix and run loudness normalization: | |
| # INCLUDE_STEREO=true NORM=true bash rodecaster_split.sh file.wav | |
| # | |
| # # Not sure which channels your mics are on? Generate 3s previews of every channel: | |
| # FIND_CHANNELS=true bash rodecaster_split.sh file.wav | |
| # | |
| # NOTES | |
| # - Works inside macOS Shortcuts: set shell to /bin/bash, pass input "as arguments". | |
| # - Logs to /tmp/rode_split.log | |
| # - Uses ffmpeg pan filter (works on more builds than -map_channel). | |
| # ----------------------------------------------------------------------------- | |
| set -euo pipefail | |
| # Ensure Homebrew binaries are visible (important when run via Shortcuts) | |
| export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" | |
| FFMPEG="${FFMPEG_PATH:-$(command -v ffmpeg || true)}" | |
| FFPROBE="${FFPROBE_PATH:-$(command -v ffprobe || true)}" | |
| LOG="/tmp/rode_split.log" | |
| # ---- CONFIG ---- | |
| MIC1_CH_INDEX="${MIC1_CH_INDEX:-2}" # zero-based channel index for Mic 1 | |
| MIC2_CH_INDEX="${MIC2_CH_INDEX:-3}" # zero-based channel index for Mic 2 | |
| NAME1="${NAME1:-mic1}" # suffix label for Mic 1 output | |
| NAME2="${NAME2:-mic2}" # suffix label for Mic 2 output | |
| OUTDIR_NAME="${OUTDIR_NAME:-split}" # shared output folder | |
| INCLUDE_STEREO="${INCLUDE_STEREO:-false}"# true|false -> also export stereo mix | |
| FIND_CHANNELS="${FIND_CHANNELS:-false}" # true|false -> export 3s previews for each channel | |
| NORM="${NORM:-false}" # true|false -> apply EBU loudness normalization | |
| # Loudness settings (used if NORM=true) | |
| # Target dialog norm around podcast standards; tweak as desired. | |
| LOUD_I="${LOUD_I:--16}" | |
| LOUD_TP="${LOUD_TP:--1.5}" | |
| LOUD_LRA="${LOUD_LRA:-11}" | |
| if [[ -z "$FFMPEG" || -z "$FFPROBE" ]]; then | |
| echo "ffmpeg/ffprobe not found on PATH" >> "$LOG" | |
| echo "Install with: brew install ffmpeg" | |
| exit 1 | |
| fi | |
| for f in "$@"; do | |
| [[ -f "$f" ]] || { echo "Skip (not a file): $f" >> "$LOG"; continue; } | |
| # Case-insensitive .wav check (Bash 3.2 compatible) | |
| ext="${f##*.}" | |
| shopt -s nocasematch | |
| if [[ ! "$ext" =~ ^wav$ ]]; then | |
| shopt -u nocasematch | |
| echo "Skip non-WAV: $f" >> "$LOG" | |
| continue | |
| fi | |
| shopt -u nocasematch | |
| dir="$(cd "$(dirname "$f")" && pwd)" | |
| base="$(basename "$f")" | |
| name="${base%.*}" | |
| outdir="$dir/$OUTDIR_NAME" | |
| mkdir -p "$outdir" | |
| # Probe channel count | |
| channels="$("$FFPROBE" -v error -select_streams a:0 -show_entries stream=channels \ | |
| -of default=nw=1:nk=1 "$f" | tr -d '[:space:]' || true)" | |
| echo "[$(date)] $base → channels=$channels" >> "$LOG" | |
| if [[ ! "$channels" =~ ^[0-9]+$ ]]; then | |
| echo "No channel info from ffprobe, skipping: $f" >> "$LOG" | |
| continue | |
| fi | |
| # Optional: FIND_CHANNELS preview (3s mono WAV for each channel) | |
| if [[ "$FIND_CHANNELS" == "true" ]]; then | |
| i=0 | |
| while [ "$i" -lt "$channels" ]; do | |
| "$FFMPEG" -hide_banner -loglevel error -y -t 3 -i "$f" \ | |
| -filter_complex "[0:a]pan=mono|c0=c${i}[ch]" \ | |
| -map "[ch]" -c:a pcm_s16le "$outdir/${name}_ch${i}_preview.wav" | |
| i=$((i+1)) | |
| done | |
| echo "Preview stems written under: $outdir" >> "$LOG" | |
| # Continue to full export as well (comment 'continue' in if you only want previews) | |
| fi | |
| # Guard against out-of-range channel indexes | |
| if (( MIC1_CH_INDEX >= channels || MIC2_CH_INDEX >= channels )); then | |
| echo "Not enough channels ($channels) for indexes $MIC1_CH_INDEX/$MIC2_CH_INDEX in $base" >> "$LOG" | |
| continue | |
| fi | |
| # Optional: export stereo mix as a single stereo file (uses c0/c1) | |
| if [[ "$INCLUDE_STEREO" == "true" && "$channels" -ge 2 ]]; then | |
| "$FFMPEG" -hide_banner -loglevel error -y -i "$f" \ | |
| -filter_complex "[0:a]pan=stereo|c0=c0|c1=c1[st]" \ | |
| -map "[st]" -c:a pcm_s24le "$outdir/${name}_stereo_mix.wav" | |
| fi | |
| # Build optional loudness filter | |
| norm_filter="" | |
| if [[ "$NORM" == "true" ]]; then | |
| norm_filter=",loudnorm=I=$LOUD_I:TP=$LOUD_TP:LRA=$LOUD_LRA" | |
| fi | |
| # MIC 1 | |
| "$FFMPEG" -hide_banner -loglevel error -y -i "$f" \ | |
| -filter_complex "[0:a]pan=mono|c0=c${MIC1_CH_INDEX}${norm_filter}[m1]" \ | |
| -map "[m1]" -c:a pcm_s24le "$outdir/${name}_${NAME1}.wav" | |
| # MIC 2 | |
| "$FFMPEG" -hide_banner -loglevel error -y -i "$f" \ | |
| -filter_complex "[0:a]pan=mono|c0=c${MIC2_CH_INDEX}${norm_filter}[m2]" \ | |
| -map "[m2]" -c:a pcm_s24le "$outdir/${name}_${NAME2}.wav" | |
| echo "Wrote: $outdir/${name}_${NAME1}.wav, ${name}_${NAME2}.wav" >> "$LOG" | |
| done | |
| echo "OK" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment