cue2audio
其实应该叫cue2mp3的
想快速转换cue的列表文件为mp3,有很多cd要转mp3,写这东西方便一下,嘛,就这些了
代码有的乱,不必介意
如果想转flac的话,自己改ffmpeg的参数吧,我还没用到所以就不理了
操作方法嘛,双击cue2audio.exe打开后,按提示操作,支持拖放,(不要打开非cue文件,可能导致死机)
cue转换mp3 320Kbps
当然有几个问题
1. cue格式要是 本机编码 的 ,我系统的是简体中文所以 本机编码 是 GB2312,推荐使用notepad++来转换编码;如果出现乱码,大半是你的编码没弄好
2. 对 音频文件 不能是 TAK 格式,因为这个 ffmpeg 不支持TAK格式的解码,你可以自己换一个支持TAK格式的ffmpeg,这样就没问题了
3. 输出文件在 output 文件夹里
4. 转换时,所有文件会一起转换,就是有多少首音乐就会弹出多少个窗口,自己试试便知,不要被一大堆窗口吓死
5. 如果新窗口一闪而过,或者有很多红字,一定会音频编码不支持,或者路径名太长了
音频编码不支持解决办法
TAK的话请使用TAK.exe解压为wav,同时修改cue里面音频路径(直接把.tak替换为.wav就行) 链接:http://cloud.189.cn/t/rMnqEjYfuIni (Tak.exe) 我忘记是从哪来的了
TTA格式好像也不行,使用格式工厂转换成wav格式,修改cue里面音频路径就行了
cue2audio src是源代码,cue2audio是成品
链接:http://cloud.189.cn/t/3IBrInYNzQba (cue2audio)
这个是主要代码
#include <Windows.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include "TFILE.h"
using namespace std;
struct TRACK
{
string title;
string performer;
vector<string> begintime;
string endtime = "00:00:00";
string control;
};
struct CUE
{
string performer;
string title;
string file;
vector<string> comment;
vector<TRACK> tracklist;
};
struct udiv_t
{
unsigned int quot;
unsigned int rem;
};
udiv_t mydiv(unsigned int a, unsigned int b)
{
udiv_t c;
c.quot = a / b;
c.rem = a % b;
return c;
}
//以空格为关键字分裂字符串
vector<string> DivideStringBySpace(string in)
{
vector<string> sv;
sv.reserve(20);
sv.resize(1);
bool indoublemark = false; //是否在双引号内
for (auto &i : in)
{
if ((i == '\x20' || i == '\x09') && !indoublemark)
sv.push_back(string());
else if (i == '\x22')
indoublemark = !indoublemark;
else
sv.back() += i;
}
for (auto i = sv.begin(); i != sv.end();)
{
if (*i == "")
i = sv.erase(i);
else
++i;
}
return sv;
}
//消除指定字符
string EatAllByChar(string in, char a)
{
for (auto i = in.begin(); i != in.end();)
{
if (*i == a)
i = in.erase(i);
else
++i;
}
return in;
}
void StringSplit(const string& src, const string& separator, vector<string>& dest)
{
string str = src;
string substring;
string::size_type start = 0, index;
do
{
index = str.find_first_of(separator, start);
if (index != string::npos)
{
substring = str.substr(start, index - start);
dest.push_back(substring);
start = str.find_first_not_of(separator, index);
if (start == string::npos) return;
}
} while (index != string::npos);
//the last token
substring = str.substr(start);
dest.push_back(substring);
}
UINT StringToMillisecond(string strtime) //字符串时间 分:秒:毫秒 转 毫秒
{
UINT ms = 0;
vector<string> sa;
vector<int> sai;
StringSplit(strtime, ":", sa);
if (sa.size() < 3)
{
MessageBoxA(0, 0, "时间格式错误,异常", 0);
DebugBreak();
} //如果少于3个,跳出
for (size_t i = 0; i < 3; ++i)
{
UINT t = strtoul(sa[i].c_str(), 0, 10);
switch (i)
{
case 0:
ms = t * 1000 * 60;
break;
case 1:
ms += t * 1000;
break;
case 2:
ms += t;
break;
}
}
return ms;
}
string MillisecondToString(UINT ms_) //毫秒 转字符串时间 时:分:秒.毫秒
{
string strtime;
udiv_t h = mydiv(ms_, 1000 * 60 * 60);
udiv_t m = mydiv(h.rem, 1000 * 60);
udiv_t s = mydiv(m.rem, 1000);
UINT ms = s.rem;
char str[20];
_ultoa_s(h.quot, str, sizeof(str), 10);
strtime += str + string(":");
_ultoa_s(m.quot, str, sizeof(str), 10);
strtime += str + string(":");
_ultoa_s(s.quot, str, sizeof(str), 10);
strtime += str + string(".");
_ultoa_s(ms, str, sizeof(str), 10);
strtime += str;
return strtime;
}
void main()
{
start_:
SetConsoleTitleA("cue2audio");
printf("本程序将cue文件转换为mp3\n");
printf("转换后文件在output文件夹内\n");
printf("支持拖拽\n");
printf("请输入cue文件路径\n");
CUE cue;
string str;
//cin >> str;
getline(cin, str, '\n');
cin.clear();
TFILE tf;
tf.Open(EatAllByChar(str, '\"'));
if (!tf.IsOpen())
{
printf("打开文件失败,请重试\n\n\n");
goto start_;
}
vector<string> sv;
while (!tf.IsEOF())
{
sv = DivideStringBySpace(tf.ReadLine());
if (sv.size() < 1)
continue;
if (sv[0] == "REM")
{
string comment;
for (size_t i = 0; i < sv.size(); ++i)
{
comment += sv[i];
comment += " ";
}
comment.erase(--comment.end(), comment.end());
cue.comment.push_back(comment);
}
else if (sv[0] == "PERFORMER")
{
if (sv.size() >= 2)
cue.performer = EatAllByChar(sv[1], '"');
}
else if (sv[0] == "TITLE")
{
if (sv.size() >= 2)
cue.title = EatAllByChar(sv[1], '"');
}
else if (sv[0] == "FILE")
{
if (sv.size() >= 2)
cue.file = EatAllByChar(sv[1], '"');
}
else if (sv[0] == "TRACK")
{
break;
}
}
cue.tracklist.reserve(20);
goto m2;
while (!tf.IsEOF())
{
sv = DivideStringBySpace(tf.ReadLine());
m2:
if (sv.size() < 1)
continue;
if (sv[0] == "TRACK")
{
cue.tracklist.push_back(TRACK());
}
else if (sv[0] == "PERFORMER")
{
if (sv.size() >= 2)
cue.tracklist.back().performer = EatAllByChar(sv[1], '"');
}
else if (sv[0] == "TITLE")
{
if (sv.size() >= 2)
cue.tracklist.back().title = EatAllByChar(sv[1], '"');
}
else if (sv[0] == "INDEX")
{
if (sv.size() >= 3)
cue.tracklist.back().begintime.push_back(sv[2]);
}
}
//生成结束时间
for (auto i = ++cue.tracklist.begin(); i != cue.tracklist.end(); ++i)
(i - 1)->endtime = i->begintime.front();
cue.tracklist.back().endtime = "00:00:00";
{
//这段代码执行的可能性基本为0
//消去时间为0的
//为没有名字的文件生成文件名
for (auto i = cue.tracklist.begin(); i != cue.tracklist.end();)
{
if (i->begintime.back() == i->endtime)
{
i = cue.tracklist.erase(i);
continue;
}
else
if (i->title == "")
i->title = "_";
++i;
}
}
//转换时间格式
for (auto i = cue.tracklist.begin(); i != cue.tracklist.end(); ++i)
{
i->begintime.back() = MillisecondToString(StringToMillisecond(i->begintime.back()));
i->endtime = MillisecondToString(StringToMillisecond(i->endtime));
}
//整理重名文件
for (auto i = cue.tracklist.begin(); i != cue.tracklist.end(); ++i)
{
again:
for (auto j = cue.tracklist.begin(); j != i; ++j)
{
if (i->title == j->title)
{
i->title += "_";
goto again;
}
}
}
//输出指示
printf("CUE TITLE: %s\n", cue.title.c_str());
printf("CUE PERFORMER:%s\n", cue.performer.c_str());
for (auto &i : cue.tracklist)
{
printf("TRACK: %s\n", i.title.c_str());
printf("PERFORMER:%s\n", i.performer.c_str());
}
//生成控制命令
string cdmusicoutdirpath = "output\\" + cue.title + "\\";
CreateDirectoryA("output", 0);
CreateDirectoryA(cdmusicoutdirpath.c_str(), 0);
for (auto &i : cue.tracklist)
{
//注意空格,不能漏
i.control += " -y -i ";
i.control += "\"" + tf.GetFolderName() + cue.file + "\"";
i.control += " -id3v2_version 3 -ar 44100 -ac 2 -ab 320k ";
i.control += " -ss " + i.begintime.back();
i.control += " -to " + i.endtime;
i.control += " \"" + cdmusicoutdirpath + i.title + ".mp3\"";
}
tf.Close(); //不能放在前面结束
//转换
vector<HANDLE> hv;
for (auto &i : cue.tracklist)
{
PROCESS_INFORMATION pi;
STARTUPINFO sp;
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&sp, sizeof(sp));
auto h = CreateProcessA("ffmpeg.exe", (char *)i.control.c_str(), 0, 0, 0, CREATE_NEW_CONSOLE, 0, 0, &sp, &pi);
hv.push_back(pi.hProcess);
}
WaitForMultipleObjects(hv.size(), hv.data(), true, INFINITE);
printf("操作完成, 按下回车键继续下一个文件,或者直接关闭本程序窗口退出\n\n\n");
getchar();
goto start_;
return;
}
void FFmpegRUN(string infile, bool isoverwrite, unsigned int audiosamplingrate, unsigned int audiochannel, string begintime, string endtime, bool isblock)
{
string control;
control += isoverwrite ? " -y " : "";
control += " -i \"" + infile + "\" ";
control += audiosamplingrate == 0 ? "" : (" -ar " + to_string(audiosamplingrate) + " ");
control += audiochannel == 0 ? "" : (" -ac " + to_string(audiochannel) + " ");
}