使用提示文件分割音频文件

使用提示文件分割音频文件

我有一个 FLAC 文件和一个 CUE 文件。我想使用命令行拆分此文件,每个文件一个音轨。

答案1

在 Windows 上执行此操作的最流行和最强大的软件是CUE工具,免费。它主要是一个 GUI 应用程序,无法通过命令行轻松配置,但它有一个命令行界面,您可以使用它在 GUI 中建立的设置来调用转换。

在 GUI 中,选择“转换”配置文件(选择器位于左上角)。记下 CUE 路径部分中的模板;这定义了新文件的去向。如果操作部分未变灰,请确保它处于编码状态,并选择“默认”脚本。在模式部分,选择曲目,然后取消选中 AccurateRip 框,除非您希望在转换之前进行验证。将音频输出设置为您想要的音频文件类型。在高级设置(右上角的齿轮图标)、CUETools 选项卡、间隙处理中,选择附加间隙或附加间隙 + HTOA,具体取决于您是否希望将曲目 01 之前的任何音频保存到单独的文件中或丢弃(通常它只是一瞬间的静音)。

现在关闭 GUI;您的设置将自动保存。在命令行上,您现在可以使用这些设置运行它:

CUETools /convert infile.cue

该命令将立即退出,并打开一个小的 GUI 窗口,显示进度和任何错误消息。此窗口将保持打开状态,直到您单击其关闭按钮。如果一切顺利,CUETools 将写入转换后的音频文件将转换后的提示表复制到新文件夹。与使用 shntool 相比,此提示表转换的主要优势在于;新的 .cue 文件将引用分割的音频文件。CUETools 还会将 .log 文件(如果有)复制到新文件夹。

答案2

我用 Go 写了一个实现:

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

它以 Cue 文件为参数。然后它使用 CSV 阅读器打开 Cue 文件,使用空格代替逗号和变量字段。然后它逐行读取 Cue 文件。首先,它找到输入的 FLAC 文件。然后,对于每个曲目,它获取标题、艺术家、开始时间和停止时间。

最后,它运行 FFmpeg 来创建每个曲目,用曲目号和曲目标题命名单独的文件,并添加艺术家、标题和曲目号的元数据。

答案3

我发现mac(这是 shntool 用于解码 APE 文件的命令)比ffmpeg源文件包含小错误的容忍度要低得多。

正常情况下ffmpeg仍会完全转换文件但mac很可能在处理过程中引发错误。

因此我最终编写了一个脚本,通过解析 CUE 文件并将 APE 文件转换为按标题分隔的 FLAC 文件来分割 APE 文件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)

答案4

我编写了一个 Python 脚本来完成这项工作,还编写了一些标签并接受专辑封面图像嵌入歌曲文件中。它使用 ffmpeg 进行分割。在 github 上查看:专辑分割器

要使用它,请像这样调用它:

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

这将为每首歌曲创建一个文件并从提示文件中获取标签。

安装 github 页面中描述的所有依赖项以使其正常工作。

相关内容