PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/boxvivid/bazaar/plugin/wav/wave.cpp

http://boxvivid.googlecode.com/
C++ | 575 lines | 425 code | 100 blank | 50 comment | 120 complexity | ab24e20e318935fc5776b859752abb7b MD5 | raw file
Possible License(s): LGPL-2.1, BSD-2-Clause, BSD-3-Clause, LGPL-3.0
  1. /* wave.cpp
  2. Copyright (c) 1996-2002 by Timothy J. Weber.
  3. See WAVE.txt for documentation.
  4. */
  5. #ifndef _MSC_VER
  6. #include <stdlib.h>
  7. #else
  8. // Microsoft doesn't include min, though it's part of the standard library!
  9. template<class T>
  10. T min(T a, T b) { return a < b? a: b; }
  11. #endif
  12. #include "wave.h"
  13. using namespace std;
  14. /***************************************************************************
  15. macros and constants
  16. ***************************************************************************/
  17. // constants for the canonical WAVE format
  18. const int fmtChunkLength = 16; // length of fmt contents
  19. const int waveHeaderLength = 4 + 8 + fmtChunkLength + 8; // from "WAVE" to sample data
  20. /***************************************************************************
  21. typedefs and class definitions
  22. ***************************************************************************/
  23. /***************************************************************************
  24. prototypes for static functions
  25. ***************************************************************************/
  26. /***************************************************************************
  27. static variables
  28. ***************************************************************************/
  29. /***************************************************************************
  30. public member functions for WaveFile
  31. ***************************************************************************/
  32. WaveFile::WaveFile():
  33. readFile(0),
  34. writeFile(0),
  35. formatType(0),
  36. numChannels(0),
  37. sampleRate(0),
  38. bytesPerSecond(0),
  39. bytesPerSample(0),
  40. bitsPerChannel(0),
  41. dataLength(0),
  42. error(0),
  43. changed(true)
  44. {
  45. }
  46. WaveFile::~WaveFile()
  47. {
  48. Close();
  49. }
  50. bool WaveFile::OpenRead(const char* name)
  51. {
  52. if (readFile || writeFile)
  53. Close();
  54. try {
  55. // open the RIFF file
  56. readFile = new RiffFile(name);
  57. if (!readFile->filep())
  58. throw error = "Couldn't open file";
  59. // read the header information
  60. if (strcmp(readFile->chunkName(), "RIFF")
  61. || strcmp(readFile->subType(), "WAVE")
  62. || !readFile->push("fmt "))
  63. throw error = "Couldn't find RIFF, WAVE, or fmt";
  64. size_t dwFmtSize = size_t(readFile->chunkSize());
  65. char* fmtChunk = new char[dwFmtSize];
  66. try {
  67. if (fread(fmtChunk, dwFmtSize, 1, readFile->filep()) != 1)
  68. throw error = "Error reading format chunk";
  69. readFile->pop();
  70. // set the format attribute members
  71. formatType = *((short*) fmtChunk);
  72. numChannels = *((short*) (fmtChunk + 2));
  73. sampleRate = *((long*) (fmtChunk + 4));
  74. bytesPerSecond = *((long*) (fmtChunk + 8));
  75. bytesPerSample = *((short*) (fmtChunk + 12));
  76. bitsPerChannel = *((short*) (fmtChunk + 14));
  77. // position at the data chunk
  78. if (!readFile->push("data"))
  79. throw error = "Couldn't find data chunk";
  80. // get the size of the data chunk
  81. dataLength = readFile->chunkSize();
  82. delete[] fmtChunk;
  83. } catch (...) {
  84. delete[] fmtChunk;
  85. throw error;
  86. }
  87. } catch (...) {
  88. Close();
  89. return false;
  90. }
  91. return true;
  92. }
  93. bool WaveFile::OpenWrite(const char* name)
  94. {
  95. if (readFile || writeFile)
  96. Close();
  97. // open the file
  98. writeFile = fopen(name, "wb");
  99. if (!writeFile) {
  100. error = "Couldn't open output file";
  101. return false;
  102. }
  103. dataLength = 0;
  104. // write the header
  105. return WriteHeaderToFile(writeFile);
  106. }
  107. bool WaveFile::ResetToStart()
  108. {
  109. if (readFile) {
  110. // pop out of the data chunk
  111. if (!readFile->rewind()
  112. || !readFile->push("data"))
  113. {
  114. error = "Couldn't find data chunk on reset";
  115. return false;
  116. } else
  117. return true;
  118. } else if (writeFile) {
  119. return fseek(writeFile, waveHeaderLength, SEEK_SET) == 0;
  120. } else
  121. return false;
  122. }
  123. bool WaveFile::Close()
  124. {
  125. bool retval = true;
  126. if (readFile) {
  127. delete readFile; // closes the file before it's destroyed
  128. readFile = 0;
  129. } else if (writeFile) {
  130. // write the header information at the start of the file, if necessary
  131. if (changed) {
  132. long currentSpot = ftell(writeFile); // save the position
  133. retval = WriteHeaderToFile(writeFile);
  134. fseek(writeFile, currentSpot, SEEK_SET); // restore the old position
  135. // this is necessary so the file gets the right length--otherwise,
  136. // all the data we wrote would be truncated.
  137. }
  138. // close the file
  139. fclose(writeFile);
  140. writeFile = 0;
  141. }
  142. return retval;
  143. }
  144. bool WaveFile::FormatMatches(const WaveFile& other)
  145. {
  146. return formatType == other.formatType
  147. && numChannels == other.numChannels
  148. && sampleRate == other.sampleRate
  149. && bytesPerSecond == other.bytesPerSecond
  150. && bytesPerSample == other.bytesPerSample
  151. && bitsPerChannel == other.bitsPerChannel;
  152. }
  153. void WaveFile::CopyFormatFrom(const WaveFile& other)
  154. {
  155. formatType = other.formatType;
  156. numChannels = other.numChannels;
  157. sampleRate = other.sampleRate;
  158. bytesPerSecond = other.bytesPerSecond;
  159. bytesPerSample = other.bytesPerSample;
  160. bitsPerChannel = other.bitsPerChannel;
  161. }
  162. void WaveFile::SetupFormat(int sampleRate, short bitsPerChannel, short channels)
  163. {
  164. SetFormatType(1);
  165. SetNumChannels(channels);
  166. SetSampleRate(sampleRate);
  167. SetBytesPerSample((unsigned short)((bitsPerChannel >> 3) * channels));
  168. SetBytesPerSecond(sampleRate * GetBytesPerSample());
  169. SetBitsPerChannel(bitsPerChannel);
  170. SetNumSamples(0);
  171. }
  172. bool WaveFile::GetFirstExtraItem(string& type, string& value)
  173. {
  174. if (readFile)
  175. return readFile->rewind() && readFile->getNextExtraItem(type, value);
  176. else
  177. return false;
  178. }
  179. bool WaveFile::GetNextExtraItem(string& type, string& value)
  180. {
  181. if (readFile)
  182. return readFile->getNextExtraItem(type, value);
  183. else
  184. return false;
  185. }
  186. bool WaveFile::CopyFrom(WaveFile& other)
  187. {
  188. const size_t transferBufSize = 4096;
  189. if (!writeFile) {
  190. error = "Copy to an unopened file";
  191. return false;
  192. } else if (!other.readFile) {
  193. error = "Copy from an unopened file";
  194. return false;
  195. }
  196. try {
  197. // allocate the transfer buffer
  198. char* transferBuffer = new char[transferBufSize];
  199. unsigned long bytesRead = 0;
  200. try {
  201. if (!other.ResetToStart())
  202. throw error = "Couldn't reset input file to start";
  203. while (bytesRead < other.dataLength) {
  204. // calculate the size of the next buffer
  205. size_t bytesToRead = (size_t) min(transferBufSize,
  206. size_t(other.dataLength - bytesRead));
  207. // read the buffer
  208. if (fread(transferBuffer, 1, bytesToRead, other.readFile->filep())
  209. != bytesToRead)
  210. throw error = "Error reading samples from input file";
  211. bytesRead += bytesToRead;
  212. // write the buffer
  213. if (fwrite(transferBuffer, 1, bytesToRead, writeFile) != bytesToRead)
  214. throw error = "Error writing samples to output file";
  215. dataLength += bytesToRead;
  216. changed = true;
  217. }
  218. // delete the transfer buffer
  219. delete[] transferBuffer;
  220. } catch (...) {
  221. delete[] transferBuffer;
  222. throw error;
  223. }
  224. } catch (...) {
  225. return false;
  226. }
  227. return true;
  228. }
  229. bool WaveFile::WriteHeaderToFile(FILE* fp)
  230. {
  231. // seek to the start of the file
  232. if (fseek(fp, 0, SEEK_SET) != 0)
  233. return false;
  234. // write the file header
  235. unsigned long wholeLength = waveHeaderLength + dataLength;
  236. unsigned long chunkLength = fmtChunkLength;
  237. if (fputs("RIFF", fp) == EOF
  238. || fwrite(&wholeLength, sizeof(wholeLength), 1, fp) != 1
  239. || fputs("WAVE", fp) == EOF
  240. || fputs("fmt ", fp) == EOF
  241. || fwrite(&chunkLength, sizeof(chunkLength), 1, fp) != 1
  242. || fwrite(&formatType, sizeof(formatType), 1, fp) != 1
  243. || fwrite(&numChannels, sizeof(numChannels), 1, fp) != 1
  244. || fwrite(&sampleRate, sizeof(sampleRate), 1, fp) != 1
  245. || fwrite(&bytesPerSecond, sizeof(bytesPerSecond), 1, fp) != 1
  246. || fwrite(&bytesPerSample, sizeof(bytesPerSample), 1, fp) != 1
  247. || fwrite(&bitsPerChannel, sizeof(bitsPerChannel), 1, fp) != 1
  248. || fputs("data", fp) == EOF
  249. || fwrite(&dataLength, sizeof(dataLength), 1, fp) != 1)
  250. {
  251. error = "Error writing header";
  252. return false;
  253. }
  254. // if it's the same file, now we don't have to write it again unless it's
  255. // been changed.
  256. if (fp == writeFile)
  257. changed = false;
  258. return true;
  259. }
  260. bool WaveFile::ReadSample(float& sample)
  261. {
  262. double fSample;
  263. bool retval = ReadSample(fSample);
  264. sample = fSample;
  265. return retval;
  266. }
  267. bool WaveFile::WriteSample(float sample)
  268. {
  269. return WriteSample(double(sample));
  270. }
  271. bool WaveFile::ReadSample(double& sample)
  272. {
  273. bool retval = false;
  274. if (GetBitsPerChannel() == 8) {
  275. unsigned char cSample;
  276. retval = ReadSample(cSample);
  277. sample = double(cSample) / ((1 << (8 - 1)) - 1) - 1;
  278. } else if (GetBitsPerChannel() == 16) {
  279. short sSample;
  280. retval = ReadSample(sSample);
  281. sample = double(sSample) / ((1 << (16 - 1)) - 1);
  282. } else
  283. error = "Floats can be written only as 8 or 16-bit samples";
  284. return retval;
  285. }
  286. bool WaveFile::WriteSample(double sample)
  287. {
  288. if (GetBitsPerChannel() == 8)
  289. return WriteSample((unsigned char)((sample + 1) * ((1 << (8 - 1)) - 1)));
  290. else if (GetBitsPerChannel() == 16)
  291. return WriteSample(short(sample * ((1 << (16 - 1)) - 1)));
  292. else {
  293. error = "Floats can be written only as 8 or 16-bit samples";
  294. return false;
  295. }
  296. }
  297. bool WaveFile::ReadSample(unsigned char& sample)
  298. {
  299. if (GetBitsPerChannel() != 8) {
  300. error = "Sample size mismatch";
  301. return false;
  302. }
  303. return ReadRaw((char*) &sample);
  304. };
  305. bool WaveFile::WriteSample(unsigned char sample)
  306. {
  307. if (GetBitsPerChannel() != 8) {
  308. error = "Sample size mismatch";
  309. return false;
  310. }
  311. return WriteRaw((char*) &sample);
  312. };
  313. bool WaveFile::ReadSample(short& sample)
  314. {
  315. if (GetBitsPerChannel() != 16) {
  316. error = "Sample size mismatch";
  317. return false;
  318. }
  319. return ReadRaw((char*) &sample, 2);
  320. };
  321. bool WaveFile::WriteSample(short sample)
  322. {
  323. if (GetBitsPerChannel() != 16) {
  324. error = "Sample size mismatch";
  325. return false;
  326. }
  327. return WriteRaw((char*) &sample, 2);
  328. };
  329. bool WaveFile::ReadSamples(unsigned char* samples, size_t count)
  330. {
  331. if (GetBitsPerChannel() != 8) {
  332. error = "Sample size mismatch";
  333. return false;
  334. }
  335. return ReadRaw((char*) samples, GetNumChannels() * count);
  336. }
  337. bool WaveFile::WriteSamples(unsigned char* samples, size_t count)
  338. {
  339. if (GetBitsPerChannel() != 8) {
  340. error = "Sample size mismatch";
  341. return false;
  342. }
  343. return WriteRaw((char*) samples, GetNumChannels() * count);
  344. }
  345. bool WaveFile::ReadSamples(short* samples, size_t count)
  346. {
  347. if (GetBitsPerChannel() != 16) {
  348. error = "Sample size mismatch";
  349. return false;
  350. }
  351. return ReadRaw((char*) samples, 2 * GetNumChannels() * count);
  352. }
  353. bool WaveFile::WriteSamples(short* samples, size_t count)
  354. {
  355. if (GetBitsPerChannel() != 16) {
  356. error = "Sample size mismatch";
  357. return false;
  358. }
  359. return WriteRaw((char*) samples, 2 * GetNumChannels() * count);
  360. }
  361. bool WaveFile::ReadRaw(char* buffer, size_t numBytes)
  362. {
  363. if (fread(buffer, 1, numBytes, GetFile()) != numBytes) {
  364. error = "Couldn't read samples";
  365. return false;
  366. }
  367. return true;
  368. }
  369. bool WaveFile::WriteRaw(char* buffer, size_t numBytes)
  370. {
  371. if (fwrite(buffer, 1, numBytes, writeFile) != numBytes) {
  372. error = "Couldn't write samples";
  373. return false;
  374. }
  375. SetDataLength(GetDataLength() + numBytes);
  376. return true;
  377. }
  378. /***************************************************************************
  379. private member functions for WaveFile
  380. ***************************************************************************/
  381. /***************************************************************************
  382. main()
  383. ***************************************************************************/
  384. #ifdef TEST_WAVE
  385. #include <iostream>
  386. static void reportProblem()
  387. {
  388. cout << " *** ERROR: Result incorrect." << endl;
  389. }
  390. static void checkResult(bool got, bool expected)
  391. {
  392. if (got)
  393. cout << "success." << endl;
  394. else
  395. cout << "fail." << endl;
  396. if (got != expected)
  397. reportProblem();
  398. }
  399. static void pause()
  400. {
  401. cout << "Press Enter to continue." << endl;
  402. cin.get();
  403. }
  404. static void ShowErrors(WaveFile& from, WaveFile& to)
  405. {
  406. bool any = from.GetError() || to.GetError();
  407. if (from.GetError())
  408. cout << "Error on input: " << from.GetError() << "." << endl;
  409. if (to.GetError())
  410. cout << "Error on output: " << to.GetError() << "." << endl;
  411. if (!any)
  412. cout << "Success." << endl;
  413. }
  414. static void ShowFormat(WaveFile& wave, bool details = true)
  415. {
  416. cout
  417. << "Format: " << wave.GetFormatType()
  418. << (wave.IsCompressed()? " (compressed)" : " (PCM)") << endl
  419. << "Channels: " << wave.GetNumChannels() << endl
  420. << "Sample rate: " << wave.GetSampleRate() << endl
  421. << "Bytes per second: " << wave.GetBytesPerSecond() << endl
  422. << "Bytes per sample: " << wave.GetBytesPerSample() << endl
  423. << "Bits per channel: " << wave.GetBitsPerChannel() << endl
  424. << "Bytes: " << wave.GetDataLength() << endl
  425. << "Samples: " << wave.GetNumSamples() << endl
  426. << "Seconds: " << wave.GetNumSeconds() << endl;
  427. if(wave.GetFile())
  428. cout << "File pointer: " << ftell(wave.GetFile()) << endl;
  429. else
  430. cout << "File pointer: null" << endl;
  431. if (details) {
  432. string type, value;
  433. if (wave.GetFirstExtraItem(type, value)) {
  434. cout << "Extra data:" << endl;
  435. do {
  436. cout << " " << type << ": " << value << endl;
  437. } while (wave.GetNextExtraItem(type, value));
  438. }
  439. wave.ResetToStart();
  440. }
  441. pause();
  442. }
  443. int main(int argc, const char* argv[])
  444. {
  445. if (argc < 3)
  446. cout << "Copies one WAVE file to another, in canonical form." << endl;
  447. else {
  448. WaveFile From, To;
  449. cout << "Opening input..." << endl;
  450. From.OpenRead(argv[1]);
  451. ShowErrors(From, To);
  452. ShowFormat(From);
  453. cout << "Setting formats..." << endl;
  454. To.CopyFormatFrom(From);
  455. ShowFormat(To);
  456. cout << "Opening output..." << endl;
  457. To.OpenWrite(argv[2]);
  458. ShowErrors(From, To);
  459. cout << "Copying..." << endl;
  460. To.CopyFrom(From);
  461. ShowErrors(From, To);
  462. cout << "Resulting format: " << endl;
  463. ShowFormat(To);
  464. cout << "Source format: " << endl;
  465. ShowFormat(From);
  466. cout << "Closing..." << endl;
  467. To.Close();
  468. From.Close();
  469. ShowErrors(From, To);
  470. }
  471. return 0;
  472. }
  473. #endif