Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I've got a full album flac, and a cue file for it. How can I split this into a flac per track. I'm a KDE user, so I would prefer a KDE/QT way, I would like to see command line and other gui answer's as well, but they are not my preferred method.

share|improve this question

Shnsplit can read a cue file directly, which also means it can access the other data from the cue file (not just the breakpoints) and generate nicer filenames than 'split-*.flac':

shnsplit -f file.cue -t %n-%t -o flac file.flac

Granted, this makes it more difficult to use cuetag.sh if the original flac file is in the same directory.

share|improve this answer
    
The most simple solution. – Paulo Fidalgo Jul 24 '13 at 9:32
3  
Fellow debian users: sudo apt-get install cuetools shntool – jwbensley May 3 '14 at 12:47
3  
You probably also want to tag the files with cuetag file.cue [0-9]*.flac – August Karlstrom Aug 28 '14 at 14:41
    
I also needed: sudo apt-get install flac – becko Mar 28 at 10:13

I only know a CLI way. You will need cuetools and shntool.

cuebreakpoints file.cue | shnsplit -o flac file.flac
cuetag.sh file.cue "split-*".flac
share|improve this answer
2  
Thanks for this Kambus. I've been using cuebreakpoints file.cue | shnsplit -o flac file.flac for a long time. The 2nd bit is going to help a lot! – boehj Apr 12 '11 at 6:44
1  
cuetag seems to break on filenames containing spaces but after removing them it worked. – scai Nov 20 '13 at 17:40

Flacon is an intuitive open-source GUI that does exactly that: split a FLAC with a CUE.

Flacon extracts individual tracks from one big audio file containing the entire album of music and saves them as separate audio files. To do this, it uses information from the appropriate CUE file.

It supports among other things:

Supported input formats: WAV, FLAC, APE, WavPack, True Audio (TTA).

Supported out formats: FLAC, WAV, WavPack, AAC, OGG or MP3.

Automatic character set detection for CUE files.

To use it you only need to open the *.cue file with flacon, it should then automatically detect the big FLAC file (if not, you can specify this manually), and then you should select FLAC output format (and optionally configure the encoder), and start the conversion process.

enter image description here

share|improve this answer
1  
Welcome to Unix & Linux Stack Exchange! Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. – slm Nov 3 '13 at 15:55
up vote 2 down vote accepted

If you have cue set to use k3b in in the filetype settings, k3b will automatically split the file if you open the cue file, and allow you to re-rip.

share|improve this answer

if high-quality files are being used, shnsplit is happily erroring out with

shnsplit: error: m:ss.ff format can only be used with CD-quality files

fortunately the flac binary supports --skip=mm:ss.ss and --until=mm:ss.ss so a script can use cuebreakpoints like this:

[..]
time[0]="00:00.00"
c=1
for ts in $(cuebreakpoints "${cue_file}"); do
    time[${c}]=${ts}
    c=$((c+1))
done
time[${c}]='-0'
for ((i=0;i<$((${#time[@]}-1));i++)); do
    trackno=$(($i+1))
    TRACKNUMBER="$(printf %02d ${trackno})"
    title="$(cueprint --track-number ${trackno} -t '%t' "${cue_file}")"
    flac --silent --exhaustive-model-search --skip=${time[$i]} --until=${time[$(($i+1))]} --tag=ARTIST="${ARTIST}" --tag=ALBUM="${ALBUM}" --tag=DATE="${DATE}" --tag=TITLE="${title}" --tag=TRACKNUMBER="${TRACKNUMBER}" "${aud_file}" --output-name="${TRACKNUMBER}-${title}.flac"
done
share|improve this answer
    
Thanks for this! – imiric Mar 7 '14 at 14:16

There is a project that works for several input files: split2flac

From the project description:

split2flac splits one big APE/FLAC/TTA/WV/WAV audio image (or a collection of such files, recursively) with CUE sheet into FLAC/M4A/MP3/OGG_VORBIS/WAV tracks with tagging, renaming, charset conversion of cue sheet, album cover images. It also uses configuration file, so no need to pass a lot of arguments every time, only an input file. Should work in any POSIX-compliant shell.

share|improve this answer

I found mac (which is the command that shntool used for decoding APE files) is way less tolerant than ffmpeg if the source file contains minor errors.

Normally ffmpeg would still convert the file completely while mac very likely throws an error during the processing.

So I ended up writing a script for spliting APE file by parsing the CUE file and converting the APE file to FLAC files separated by titles using ffmpeg:

#!/usr/bin/env python2.7

import subprocess as subp
import sys
import os
from os.path import splitext, basename
import random
import glob

records = []
filename = ""
album=''
alb_artist=''
codec = 'flac'
ffmpeg_exec = 'ffmpeg'
encodingList = ('utf-8','euc-kr', 'shift-jis', 'cp936', 'big5')

filecontent = open(sys.argv[1]).read()
for enc in encodingList:
    try:
        lines = filecontent.decode(enc).split('\n')
        encoding = enc
        break
    except UnicodeDecodeError as e:
        if enc == encodingList[-1]:
            raise e
        else:
            pass

for l in lines:
    a = l.split()
    if not a:
        continue
    if a[0] == "FILE":
        filename = ' '.join(a[1:-1]).strip('\'"')
    elif a[0]=='TRACK':
        records.append({})
        records[-1]['index'] = a[1]
    elif a[0]=='TITLE':
        if len(records)>0:
            records[-1]['title'] = ' '.join(a[1:]).strip('\'"')
        else:
            album =  ' '.join(a[1:]).strip('\'"')
    elif a[0]=='INDEX' and a[1]=='01':
        timea = a[2].split(':')
        if len(timea) == 3 and int(timea[0]) >= 60:
            timea.insert(0, str(int(timea[0])/60))
            timea[1] = str(int(timea[1])%60)
        times = '{0}.{1}'.format(':'.join(timea[:-1]), timea[-1])
        records[-1]['start'] = times
    elif a[0]=='PERFORMER':
        if len(records)>1:
            records[-1]['artist'] = ' '.join(a[1:]).strip('\'"')
        else:
            alb_artist = ' '.join(a[1:]).strip('\'"')

for i, j in enumerate(records):
    try:
        j['stop'] = records[i+1]['start']
    except IndexError:
        pass

if not os.path.isfile(filename):
    tmpname = splitext(basename(sys.argv[1]))[0]+splitext(filename)[1]
    if os.path.exists(tmpname):
        filename = tmpname
        del tmpname
    else:
        for ext in ('.ape', '.flac', '.wav', '.mp3'):
            tmpname = splitext(filename)[0] + ext
            if os.path.exists(tmpname):
                filename = tmpname
                break

if not os.path.isfile(filename):
    raise IOError("Can't not find file: {0}".format(filename))

fstat = os.stat(filename)
atime = fstat.st_atime
mtime = fstat.st_mtime

records[-1]['stop'] = '99:59:59'

if filename.lower().endswith('.flac'):
    tmpfile = filename
else:
    tmpfile = splitext(filename)[0] + str(random.randint(10000,90000)) + '.flac'

try:
    if filename != tmpfile:
        ret = subp.call([ffmpeg_exec, '-hide_banner', '-y', '-i', filename, 
            '-c:a', codec,'-compression_level','12','-f','flac',tmpfile])

        if ret != 0:
            raise SystemExit('Converting failed.')

    for i in records:
        output = i['index'] +' - '+ i['title']+'.flac'
        commandline = [ffmpeg_exec, '-hide_banner', 
        '-y', '-i', tmpfile,
        '-c', 'copy', 
        '-ss', i['start'], '-to', i['stop'],
        '-metadata', u'title={0}'.format(i['title']), 
        '-metadata', u'artist={0}'.format(i.get('artist', '')),
        '-metadata', u'performer={0}'.format(i.get('artist', '')),
        '-metadata', u'album={0}'.format(album), 
        '-metadata', 'track={0}/{1}'.format(i['index'], len(records)), 
        '-metadata', u'album_artist={0}'.format(alb_artist), 
        '-metadata', u'composer={0}'.format(alb_artist), 
        '-metadata', 'encoder=Meow', 
        '-write_id3v1', '1', 
        output]
        ret = subp.call(commandline)
        if ret == 0:
            os.utime(output, (atime, mtime))
finally:
    if os.path.isfile(tmpfile):
        os.remove(tmpfile)
share|improve this answer

Here is a solution with Awk and FFmpeg:

#!/bin/sh
if [ "$#" != 1 ]
then
  echo 'ff-split.sh [cue file]'
  exit
fi
awk '
$1 == "FILE" {
  split($0, i, /"/)
  file = i[2]
}
$1 == "TRACK" {
  tracks[++j] = $2
}
$1 == "TITLE" && j {
  split($0, i, /"/)
  titles[j] = i[2]
}
$1 == "INDEX" && $2 {
  split($3, i, ":")
  indexes[j] = sprintf("%d:%02d:%06.3f", i[1]/60, i[1]%60, i[2]+i[3]/75)
}
END {
  for (each in tracks) {
    print file
    print tracks[each]
    print titles[each]
    print indexes[each]
    print indexes[each+1]
  }
}
' "$1" |
while
  read file
  read track
  read title
  read start
  read stop
do
  ffmpeg -nostdin -i "$file" -ss $start ${stop:+-to $stop} "$track $title".m4a
done

Source

share|improve this answer

protected by Community Dec 22 '14 at 9:16

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.