fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <fstream>
  5. #include <algorithm>
  6. #include <iomanip>
  7.  
  8. struct tag_fileenum {
  9. std::string filename;
  10. /* RIFF */
  11. uint32_t totalSize;
  12. /* WAVE */
  13. /* fmt_ */
  14. /*uint16_t formatID;*/
  15. uint16_t channelNum;
  16. uint32_t samplingRate;
  17. uint32_t bytesPerSec;
  18. uint16_t bytesBlockAlign;
  19. uint16_t bitsPerSample;
  20. /*data*/
  21. uint32_t bytesDataNum;
  22. uint32_t posDataStart;
  23. };
  24.  
  25. uint32_t read_(std::fstream &fs, int n) {
  26. uint32_t byte, data = 0;
  27. for (int i = 0; i < n; i++) {
  28. byte = 0;
  29. fs.read((char *)&byte, 1);
  30. if (!fs)
  31. return 0;
  32. for (int j = 0; j < i; j++)
  33. byte = byte << 8;
  34. data = data | byte;
  35. }
  36. return data;
  37. }
  38.  
  39. int write_(std::fstream &fs, int n, uint32_t data) {
  40. uint32_t byte;
  41. for (int i = 0; i < n; i++) {
  42. byte = 0xff & data;
  43. fs.write((char *)&byte, 1);
  44. if (!fs)
  45. return 0;
  46. data = data >> 8;
  47. }
  48. return n;
  49. }
  50.  
  51.  
  52. void wavFileCheckAndReadParam(std::fstream &fs, struct tag_fileenum *fileenum) {
  53. uint32_t dummy, posDataStart = 0;
  54. uint32_t n;
  55. n = 4;
  56. if ((dummy = read_(fs, n)) != 0x46464952) { /* RIFF */
  57. std::cerr << "the file : " << fileenum->filename << " is not RIFF but " << std::setbase(16) << dummy << ", aborted." << std::endl;
  58. fs.close();
  59. exit(0);
  60. }
  61. posDataStart += n;
  62.  
  63. n = 4;
  64. if ((fileenum->totalSize = read_(fs, n)) == 0) {
  65. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  66. fs.close();
  67. exit(0);
  68. }
  69. posDataStart += n;
  70.  
  71. n = 4;
  72. if ((dummy = read_(fs, n)) != 0x45564157) { /* WAVE */
  73. std::cerr << "the file : " << fileenum->filename << " is not WAVE, aborted." << std::endl;
  74. fs.close();
  75. exit(0);
  76. }
  77. posDataStart += n;
  78.  
  79. n = 4;
  80. if ((dummy = read_(fs, n)) != 0x20746D66) {
  81. std::cerr << "the file : " << fileenum->filename << " has not format chunk partition, aborted." << std::endl;
  82. fs.close();
  83. exit(0);
  84. }
  85. posDataStart += n;
  86.  
  87. uint32_t fmt_ChunkSize;
  88. n = 4;
  89. if ((fmt_ChunkSize = read_(fs, n)) < 16) {
  90. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  91. fs.close();
  92. exit(0);
  93. }
  94. posDataStart += n;
  95.  
  96. uint32_t extraFmt_ChunkSize = fmt_ChunkSize - 16;
  97.  
  98. n = 2;
  99. if ((dummy = read_(fs, n)) != 0x0001) {
  100. std::cerr << "the file : " << fileenum->filename << " is not PCM format, aborted." << std::endl;
  101. fs.close();
  102. exit(0);
  103. }
  104. posDataStart += n;
  105.  
  106. n = 2;
  107. if ((fileenum->channelNum = read_(fs, n)) == 0) {
  108. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  109. fs.close();
  110. exit(0);
  111. }
  112. posDataStart += n;
  113.  
  114. n = 4;
  115. if ((fileenum->samplingRate = read_(fs, n)) != 0x0000ac44) {
  116. std::cerr << "the file : " << fileenum->filename << "'s sampling rate is" << dummy << ", not CD-like, aborted." << std::endl;
  117. fs.close();
  118. exit(0);
  119. }
  120. posDataStart += n;
  121.  
  122. n = 4;
  123. if ((fileenum->bytesPerSec = read_(fs, n)) == 0) {
  124. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  125. fs.close();
  126. exit(0);
  127. }
  128. posDataStart += n;
  129.  
  130. n = 2;
  131. if ((fileenum->bytesBlockAlign = read_(fs, n)) == 0) {
  132. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  133. fs.close();
  134. exit(0);
  135. }
  136. posDataStart += n;
  137.  
  138. n = 2;
  139. if ((fileenum->bitsPerSample = read_(fs, n)) == 0) {
  140. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  141. fs.close();
  142. exit(0);
  143. }
  144. posDataStart += n;
  145.  
  146. if (extraFmt_ChunkSize > 0) { dummy = read_(fs, extraFmt_ChunkSize); posDataStart += extraFmt_ChunkSize; }
  147.  
  148. n = 4;
  149. if ((dummy = read_(fs, n)) != 0x61746164) {
  150. std::cerr << "the file : " << fileenum->filename << " has not data chunk partition, aborted." << std::endl;
  151. fs.close();
  152. exit(0);
  153. }
  154. posDataStart += n;
  155.  
  156. n = 4;
  157. if ((fileenum->bytesDataNum = read_(fs, 4)) == 0) {
  158. std::cerr << "cannot read : " << fileenum->filename << ", aborted." << std::endl;
  159. fs.close();
  160. exit(0);
  161. }
  162. posDataStart += n;
  163. fileenum->posDataStart = posDataStart;
  164.  
  165. if ((fileenum->bitsPerSample/8) * fileenum->channelNum != fileenum->bytesBlockAlign) {
  166. std::cerr << "bad parameter : " << fileenum->bitsPerSample << " "
  167. << fileenum->channelNum << " "
  168. << fileenum->bytesBlockAlign << ", aborted." << std::endl;
  169. fs.close();
  170. exit(0);
  171. }
  172. if (fileenum->samplingRate * fileenum->bytesBlockAlign != fileenum->bytesPerSec) {
  173. std::cerr << "bad parameter : " << fileenum->samplingRate << " "
  174. << fileenum->bytesBlockAlign << " "
  175. << fileenum->bytesPerSec << ", aborted." << std::endl;
  176. fs.close();
  177. exit(0);
  178. }
  179. }
  180.  
  181. int32_t calcTotalDataSize(std::vector<tag_fileenum> input_files_elements) {
  182. int32_t total = 0;
  183. for (std::vector<tag_fileenum>::const_iterator p = input_files_elements.begin(); p != input_files_elements.end(); p++) {
  184. total += p->bytesDataNum;
  185. }
  186. return total;
  187. }
  188.  
  189. int32_t calcTotalSize(std::vector<tag_fileenum> input_files_elements) {
  190. int32_t n = calcTotalDataSize(input_files_elements);
  191. return n + 36; /* fix */
  192. }
  193.  
  194.  
  195.  
  196. void makeOutputWaveFileHeader(std::fstream &fout, std::vector<tag_fileenum> input_files_elements, std::string file_output) {
  197. int n;
  198. int32_t totalSize, totalDataSize;
  199. /* RIFF */
  200. n = 4; if (write_(fout, n, 0x46464952) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  201. totalSize = calcTotalSize(input_files_elements);
  202. n = 4; if (write_(fout, n, totalSize) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  203. /* WAVE */
  204. n = 4; if (write_(fout, n, 0x45564157) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  205. /* fmt_ */
  206. n = 4; if (write_(fout, n, 0x20746D66) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  207. /* fmt_ size */
  208. n = 4; if (write_(fout, n, 16) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  209. /* linear PCM */
  210. n = 2; if (write_(fout, n, 1) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  211. /* channnel = Stereo */
  212. n = 2; if (write_(fout, n, 2) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  213. /* sampling rate = input_file[0]'s data */
  214. n = 4; if (write_(fout, n, input_files_elements[0].samplingRate) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  215. /* dataNumPerSec = input_file[0]'s samplingRate * Stereo * 16bits*/
  216. n = 4; if (write_(fout, n, input_files_elements[0].samplingRate * 4) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  217. /* blocksize = 2 * 2(Steleo 16bits) */
  218. n = 2; if (write_(fout, n, 4) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  219. /* bitsPerSample = 16 */
  220. n = 2; if (write_(fout, n, 16) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  221. /* 'data' */
  222. n = 4; if (write_(fout, n, 0x61746164) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  223. /* data size */
  224. totalDataSize = calcTotalDataSize(input_files_elements);
  225. n = 4; if (write_(fout, n, totalDataSize) != n) { std::cerr << "cannot write: " << file_output <<", aborted" << std::endl; }
  226. }
  227.  
  228. int const N = 65536;
  229. int copyData(std::fstream &fin, std::fstream &fout, int32_t bytesDataNum, int16_t channelNum, int16_t bitsPerSample) {
  230. if (channelNum != 2) {
  231. std::cerr << "channel num: " << channelNum << ", not implemented, aborted." << std::endl;
  232. fin.close(); fout.close(); exit(0);
  233. }
  234. if (bitsPerSample != 16) {
  235. std::cerr << "data bits num: " << bitsPerSample << ", not implemented, aborted." << std::endl;
  236. fin.close(); fout.close(); exit(0);
  237. }
  238. uint8_t buffer[N];
  239. while (bytesDataNum > 0) {
  240. int n;
  241. fin.read((char *)&buffer, std::min(N, bytesDataNum));
  242. if (fin.fail())
  243. return 0;
  244. n = fin.gcount();
  245. fout.write((char *)&buffer, n);
  246. if (fout.fail())
  247. return 0;
  248. bytesDataNum -= n;
  249. }
  250. return 1;
  251. }
  252.  
  253. void body(std::string output_file, std::vector<std::string>input_files) {
  254. struct tag_fileenum fileenum;
  255. std::vector<tag_fileenum> input_files_elements;
  256. /* enum input file */
  257. for (std::vector<std::string>::iterator p = input_files.begin(); p != input_files.end(); p++) {
  258. std::fstream fs;
  259. fs.open(*p, std::ios::in | std::ios::binary);
  260. if (!fs.is_open()) {
  261. std::cerr << "cannot open the file: " << *p << ", aborted." << std::endl;
  262. exit(1);
  263. }
  264. fileenum.filename = *p;
  265. wavFileCheckAndReadParam(fs, &fileenum);
  266. std::cout << "file: " << fileenum.filename << " "
  267. << "channel: " << fileenum.channelNum << " "
  268. << "bits: " << fileenum.bitsPerSample << std::endl;
  269. input_files_elements.push_back(fileenum);
  270. fs.close();
  271. }
  272. /* copy input files to output/make output's header */
  273. std::fstream fout;
  274. fout.open(output_file, std::ios::out | std::ios::binary);
  275. if (!fout.is_open()) {
  276. std::cerr << "cannot open the file for output: " << output_file << ", aborted." << std::endl;
  277. exit(0);
  278. }
  279. makeOutputWaveFileHeader(fout, input_files_elements, output_file);
  280. for (std::vector<tag_fileenum>::const_iterator p = input_files_elements.begin(); p != input_files_elements.end(); p++) {
  281. /* copy input files to output/copy bodies */
  282. std::fstream fin;
  283. fin.open(p->filename, std::ios::in | std::ios::binary);
  284. if (!fin) {
  285. std::cerr << "cannot read open: " << p->filename << "." << std::endl;
  286. fin.close(); fout.close(); exit(0);
  287. }
  288. fin.seekg(p->posDataStart);
  289. std::cout << "copying: " << p->filename << "." << std::endl;
  290. if (copyData(fin, fout, p->bytesDataNum, p->channelNum, p->bitsPerSample) == 0) {
  291. std::cerr << "cannot write: " << output_file << " or cannot read: " << p->filename << "." << std::endl;
  292. fin.close(); fout.close(); exit(0);
  293. }
  294. fin.close();
  295. }
  296. fout.close();
  297. }
  298.  
  299. /*--------------------------------*/
  300. void help(char *cmd) {
  301. std::cerr << "usage: " << cmd << "output.wav input1.wav [input2.wav [...]]" << std::endl;
  302. std::cerr << " " << cmd << " : concatenate .wav files to one output.wav." << std::endl;
  303. }
  304.  
  305. int main(int argc, char *argv[]) {
  306. if (argc <= 2) {
  307. help(argv[0]);
  308. exit(0);
  309. }
  310. std::string output_file(argv[1]);
  311. std::vector<std::string> input_files;
  312. for (int i = 2; i < argc; i++)
  313. input_files.push_back(argv[i]);
  314. sort(input_files.begin(), input_files.end());
  315.  
  316. std::ifstream dummy;
  317. dummy.open(output_file, std::ios::in);
  318. if (dummy) {
  319. std::cerr << "file: " << output_file << " for output already exists" << std::endl;
  320. exit(0);
  321. }
  322.  
  323. body(output_file, input_files);
  324. return 0;
  325. }
  326. /* end */
  327.  
Success #stdin #stdout #stderr 0s 4460KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
usage: ./progoutput.wav input1.wav [input2.wav [...]]
       ./prog : concatenate .wav files to one output.wav.