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 answers as well, but they are not my preferred method.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityI'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 answers as well, but they are not my preferred method.
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.
cuetag file.cue [0-9]*.flac
Aug 28, 2014 at 14:41
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.
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
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
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.
Here is a PHP script:
<?php
$s_cue = $argv[1];
$a_cue = file($s_cue);
$n_row = -1;
foreach ($a_cue as $s_row) {
$s_trim = trim($s_row);
$a_row = str_getcsv($s_trim, ' ');
if (preg_match('/^FILE\s/', $s_row) == 1) {
$s_file = $a_row[1];
}
if (preg_match('/^\s+TRACK\s/', $s_row) == 1) {
$n_row++;
$a_table[$n_row]['track'] = $a_row[1];
}
if (preg_match('/^\s+TITLE\s/', $s_row) == 1) {
$a_table[$n_row]['title'] = $a_row[1];
}
if (preg_match('/^\s+PERFORMER\s/', $s_row) == 1) {
$a_table[$n_row]['artist'] = $a_row[1];
}
if (preg_match('/^\s+INDEX\s/', $s_row) == 1) {
$s_dur = $a_row[2];
$a_frame = sscanf($s_dur, '%d:%d:%d', $n_min, $n_sec, $n_fra);
$n_index = $n_min * 60 + $n_sec + $n_fra / 75;
$a_table[$n_row]['ss'] = $n_index;
if ($n_row > 0) {
$a_table[$n_row - 1]['to'] = $n_index;
}
}
}
$a_table[$n_row]['to'] = 10 * 60 * 60;
foreach ($a_table as $m_row) {
$a_cmd = [
'ffmpeg',
'-i', $s_file,
'-ss', $m_row['ss'],
'-to', $m_row['to'],
'-metadata', 'artist=' . $m_row['artist'],
'-metadata', 'title=' . $m_row['title'],
'-metadata', 'track=' . $m_row['track'],
$m_row['track'] . ' ' . $m_row['title'] . '.m4a'
];
$a_esc = array_map('escapeshellarg', $a_cmd);
$s_esc = implode(' ', $a_esc);
system($s_esc);
}
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.
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)
shntool
on Ubuntu 14.04
snhtool
is missing the mac
(Monkey's Audio Console) executable dependency, and the only package I could find it was in the flacon
PPA:
sudo add-apt-repository -y ppa:flacon
sudo apt-get update
sudo apt-get install -y flacon shntool
shntool split -f *.cue -o flac -t '%n - %p - %t' *.ape
flacon
is a GUI for shntool
, but it comes with all the codecs it needs... otherwise I got the error:
shnsplit: warning: failed to read data from input file using format: [ape]
shnsplit: + you may not have permission to read file: [example.ape]
shnsplit: + arguments may be incorrect for decoder: [mac]
shnsplit: + verify that the decoder is installed and in your PATH
shnsplit: + this file may be unsupported, truncated or corrupt
shnsplit: error: cannot continue due to error(s) shown above
monkeys-audio
package did the trick.
Jul 12, 2021 at 22:07
unflac automatically splits into flac
and also does the tagging right!
You need go
installed and then run it by giving the cue
as input: ~/go/bin/unflac filename.cue
.
I found out about it after files I split with other tools where not playable.