home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / Audio / WaveOutput.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  11.5 KB  |  440 lines

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