Split Audio with CUE Sheet Using FFmpeg

This article provides a straightforward guide on how to split a single large audio file into individual tracks using a .cue sheet and FFmpeg. Because FFmpeg does not natively support direct, automatic CUE-based splitting in a single command, we will show you how to automate the process using a simple Bash script, as well as how to use the popular shntool utility alongside FFmpeg for a quick alternative.


Method 1: Automated Splitting Using FFmpeg and Bash

To split an audio file using FFmpeg, you need to pass the start time (-ss) and stop time (-to) for each track. You can automate the parsing of the .cue file and execute the FFmpeg commands using the following Bash script.

Save this script as split_cue.sh and run it in the folder containing your audio file and .cue sheet:

#!/bin/bash

# Input files
CUE_FILE="$1"
AUDIO_FILE="$2"

if [ -z "$CUE_FILE" ] || [ -z "$AUDIO_FILE" ]; then
    echo "Usage: $0 <file.cue> <audio_file>"
    exit 1
fi

# Extract tracks, titles, and timestamps
grep -E 'TRACK|TITLE|INDEX 01' "$CUE_FILE" | while read -r line; do
    if [[ $line =~ TRACK ]]; then
        track_num=$(echo "$line" | awk '{print $2}')
    elif [[ $line =~ TITLE ]]; then
        # Clean quotes from title
        track_title=$(echo "$line" | cut -d'"' -f2)
    elif [[ $line =~ "INDEX 01" ]]; then
        time_raw=$(echo "$line" | awk '{print $3}')
        
        # Convert CUE MM:SS:FF (minutes:seconds:frames) to FFmpeg HH:MM:SS.ms
        m=$(echo "$time_raw" | cut -d':' -f1)
        s=$(echo "$time_raw" | cut -d':' -f2)
        f=$(echo "$time_raw" | cut -d':' -f3)
        
        # 75 frames per second
        ms=$((f * 1000 / 75))
        formatted_time=$(printf "00:%02d:%02d.%03d" $m $s $ms)
        
        # Store time and track info in a temporary array/file
        echo "$track_num|$track_title|$formatted_time" >> temp_tracks.txt
    fi
done

# Read the temporary file to calculate durations and split
IFS=$'\n' read -d '' -r -a tracks < temp_tracks.txt

for ((i=0; i<${#tracks[@]}; i++)); do
    current_track="${tracks[i]}"
    next_track="${tracks[i+1]}"
    
    num=$(echo "$current_track" | cut -d'|' -f1)
    title=$(echo "$current_track" | cut -d'|' -f2)
    start=$(echo "$current_track" | cut -d'|' -f3)
    
    output_name=$(printf "%02d - %s.${AUDIO_FILE##*.}" "$((10#$num))" "$title")
    
    if [ -n "$next_track" ]; then
        end=$(echo "$next_track" | cut -d'|' -f3)
        ffmpeg -y -i "$AUDIO_FILE" -ss "$start" -to "$end" -acodec copy "$output_name"
    else
        # Last track goes to the end of the file
        ffmpeg -y -i "$AUDIO_FILE" -ss "$start" -acodec copy "$output_name"
    fi
done

# Clean up
rm temp_tracks.txt

How to run the script:

  1. Make the script executable:

    chmod +x split_cue.sh
  2. Run the script by targeting your CUE sheet and audio file:

    ./split_cue.sh album.cue album.flac

Using -acodec copy ensures that the audio is split without re-encoding, preserving 100% of the original audio quality instantly.


Method 2: The Command-Line Alternative (shntool + FFmpeg)

If you do not want to use a custom script, the industry-standard way to split CUE sheets on Linux and macOS is using shntool (which utilizes FFmpeg under the hood for decoding various formats like FLAC, APE, and WV).

1. Install the required tools:

2. Split the file:

Run the following command to split your audio file using the timings from the CUE sheet:

shnsplit -f album.cue -o flac -t "%n - %t" album.flac

3. Apply metadata tags:

shnsplit does not write the metadata tags (like Artist and Album) to the split tracks automatically. To copy the tags from the CUE sheet directly to your newly split FLAC files, run:

cuetag.sh album.cue [0-9]*.flac