3

I have a FLAC file and a CUE file. Using the command line, I would like to split this file, with one track per file.

5

The most popular and robust software for doing this on Windows is CUETools, which is free. It's primarily a GUI app, and it can't easily be configured from the command line, but it does have a command-line interface you can use to invoke the conversion with settings that were established in the GUI.

In the GUI, choose the "convert" profile (chooser is in the upper left corner). Take note of the Template in the CUE Paths section; this defines where the new files will go. If the Action section isn't greyed out, make sure it's on Encode, with the "default" script selected. In the Mode section, choose Tracks, and uncheck the AccurateRip box, unless you want it to verify before converting. Set the Audio Output to what type of audio files you want. In the Advanced Settings (gear icon in upper right corner), CUETools tab, Gaps handling, choose either Gaps Appended or Gaps Appended + HTOA, depending on whether you want any audio that comes before track 01 to be saved to a separate file or discarded (normally it'll just be a split-second of silence).

Now close the GUI; your settings are saved automatically. On the command line, you can now run it with those settings:

CUETools /convert infile.cue

The command will exit immediately, and a small GUI window will open to show you the progress and any error messages. This window will remain open until you click its close button. If all goes well, CUETools will write the converted audio file(s) and a converted cue sheet to a new folder. This cue sheet conversion is the main advantage over using shntool; the new .cue file will reference the split audio files. CUETools will also copy the .log file (if any) to the new folder.

1
  • Thanks for the detailed answer, 6 years old answer is still helpful! :) – varun May 10 '19 at 11:31
2

I wrote an implementation in Go:

https://github.com/89z/cove/tree/4a721f1a/cue-split

It takes a Cue file as argument. Then it opens the Cue file using a CSV reader, with spaces instead of Commas and variable fields. Then it reads the Cue file line by line. First it finds the input FLAC file. Then for each Track, it gets the Title, Artist, Start time and Stop time.

Finally it runs FFmpeg to create each track, naming the separate files with the track number and track Title, as well as adding Metadata for Artist, Title and track number.

0
1

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)
0

Get the MediaHuman Audio Converter program.

Drag and drop your FLAC file into the field and it will automatically unwind your FLAC file. You can then choose what you want to convert it to.

Hint: The file names of the FLAC and CUE files need to be exactly the same (except for the extension of course).

0
0

I coded a python script that does the job and also write some tags and accept an album cover image to embedded inside the song files. It uses ffmpeg for splitting. Check it out on github: albumSplitter.

To use it, supply call it like that:

./albumSplitter.py flacFile.flac cueFile.cue outputFolder coverImage.jpg

This would create one file per songs and get tags from cue file.

Install all dependencies described in the github page for it to work.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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