cue2audio
2016-02-02 23:26
495 查看
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就行) 链接:https://yunpan.cn/crD4UdhQRDZZQ (提取码:1d5f)我忘记是从哪来的了
TTA格式好像也不行,使用格式工厂转换成wav格式,修改cue里面音频路径就行了
cue2audio src是源代码,cue2audio是成品
链接:https://yunpan.cn/crDUm6WEKW7cw (提取码:d1e0)
这个是主要代码
其实应该叫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就行) 链接:https://yunpan.cn/crD4UdhQRDZZQ (提取码:1d5f)我忘记是从哪来的了
TTA格式好像也不行,使用格式工厂转换成wav格式,修改cue里面音频路径就行了
cue2audio src是源代码,cue2audio是成品
链接:https://yunpan.cn/crDUm6WEKW7cw (提取码:d1e0)
这个是主要代码
#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) + " "); }
相关文章推荐
- iOS开发之UIAlertView与UIAlertController的详尽用法说明
- iOS 7中使用UINavigationController进行pop崩溃
- 【XJBG】UESTCdp练习场 D 温泉旅馆
- iOS 【UIKit-UIImage渲染模式 imageWithRenderingMode:】
- iOS 【UIKit-文本属性 Attributes】
- CDOJ 1273 God Qing's circuital law
- Error installing mysql2: ERROR: Failed to build gem native extension
- Arduino接口-week4-Lesson1
- UITableView 查询结果为空,显示无数据的方法
- Fuel Openstack 7.0在Virtualbox中部署
- 1017. Queueing at Bank (25)
- 环状序列(Circular Sequence, ACM/ICPC Seoul 2004, UVa1584)
- JDBC获得数据库连接时写在URL上的?useUnicode=true&characterEncoding=utf-8的意义
- UESTC 1272 Final Pan's prime numbers(乱搞)
- Number Sequence
- Easyui datagrid行内【添加】、【编辑】、【上移】、【下移】
- 查看磁盘UUID
- HDU 1005 Number Sequence 数学题
- uiview的绘画
- ABP框架实践基础篇之开发UI层