home *** CD-ROM | disk | FTP | other *** search
/ Game Audio Programming / GameAudioProgramming.iso / Extras / Sensaura / SDK1.0 / data1.cab / Example_Files / ZoomFX / WaveFile.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-13  |  8.0 KB  |  321 lines

  1. // WaveFile.cpp
  2.  
  3. #include <windows.h>
  4. #include <mmsystem.h>
  5. #include "WaveFile.h"
  6. #include "debug.h"
  7.  
  8. // WaveFile class implementation
  9. //
  10. ////////////////////////////////////////////////////////////
  11.  
  12. // Constructor
  13. WaveFile::WaveFile (void)
  14. {
  15.     TRACE(0, "WaveFile::WaveFile");
  16.  
  17.     // Init data members
  18.     m_pwfmt = NULL;
  19.     m_hmmio = NULL;
  20.     m_nBlockAlign= 0;
  21.     m_nAvgDataRate = 0;
  22.     m_nDataSize = 0;
  23.     m_nBytesPlayed = 0;
  24.     m_nDuration = 0;
  25.     memset (&m_mmckiRiff, 0, sizeof (MMCKINFO));
  26.     memset (&m_mmckiFmt, 0, sizeof (MMCKINFO));
  27.     memset (&m_mmckiData, 0, sizeof (MMCKINFO));
  28.  
  29. }
  30.  
  31. // Destructor
  32. WaveFile::~WaveFile (void)
  33. {
  34.     TRACE(0, "WaveFile::~WaveFile");
  35.  
  36.     // Free memory
  37.     if (m_pwfmt)
  38.     {
  39.         GlobalFree (m_pwfmt);
  40.     }
  41.     
  42.     // Close file
  43.     if (m_hmmio)
  44.     {
  45.         mmioClose (m_hmmio, 0);
  46.     }
  47.  
  48. }
  49.  
  50. // Open
  51. BOOL WaveFile::Open (const char *pszFilename)
  52. {
  53.     WORD cbExtra = 0;
  54.     TRACE(0, "WaveFile::Open");
  55.  
  56.     BOOL fRtn = SUCCESS;    // assume success
  57.     
  58.     // Open the requested file
  59.     if ((m_hmmio = mmioOpen ( (char *) pszFilename, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL)
  60.     {
  61.         m_mmr = MMIOERR_CANNOTOPEN;
  62.         goto OPEN_ERROR;
  63.     }
  64.     
  65.     // Descend into initial chunk ('RIFF')
  66.     if (m_mmr = mmioDescend (m_hmmio, &m_mmckiRiff, NULL, 0))
  67.     {
  68.         goto OPEN_ERROR;
  69.     }
  70.     
  71.     // Validate that it's a WAVE file
  72.     if ((m_mmckiRiff.ckid != FOURCC_RIFF) || (m_mmckiRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
  73.     {
  74.         m_mmr = MMIOERR_INVALIDFILE;
  75.         goto OPEN_ERROR;
  76.     }
  77.     
  78.     // Find format chunk ('fmt '), allocate and fill WAVEFORMATEX structure
  79.     m_mmckiFmt.ckid = mmioFOURCC('f', 'm', 't', ' ');
  80.     if (m_mmr = mmioDescend (m_hmmio, &m_mmckiFmt, &m_mmckiRiff, MMIO_FINDCHUNK))
  81.     {
  82.         goto OPEN_ERROR;
  83.     }
  84.     
  85.     // Read the format chunk into temporary structure
  86.     PCMWAVEFORMAT pcmwf;
  87.     if (mmioRead (m_hmmio, (CHAR *) &pcmwf, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
  88.     {
  89.         m_mmr = MMIOERR_CANNOTREAD;
  90.         goto OPEN_ERROR;
  91.     }
  92.  
  93.     // If format is not PCM, then there are extra bytes appended to WAVEFORMATEX
  94.     if (pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM)
  95.     {
  96.         // Read WORD specifying number of extra bytes
  97.         if (mmioRead (m_hmmio, (LPSTR) &cbExtra, sizeof (cbExtra)) != sizeof(cbExtra))
  98.         {
  99.             m_mmr = MMIOERR_CANNOTREAD;
  100.             goto OPEN_ERROR;
  101.         }
  102.     }
  103.  
  104.     // Allocate memory for WAVEFORMATEX structure + extra bytes
  105.     // UNDONE: GMEM_FIXED???? use malloc?
  106.     if (m_pwfmt = (WAVEFORMATEX *) GlobalAlloc (GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtra))
  107.     {
  108.         // Copy bytes from temporary format structure
  109.         memcpy (m_pwfmt, &pcmwf, sizeof(pcmwf));
  110.         m_pwfmt->cbSize = cbExtra;
  111.         
  112.         // Read those extra bytes, append to WAVEFORMATEX structure
  113.         if (cbExtra != 0)
  114.         {
  115.             if ((m_mmr = mmioRead (m_hmmio, (LPSTR) ((BYTE *)(m_pwfmt) + sizeof (WAVEFORMATEX)), cbExtra)) != cbExtra)
  116.             {
  117.                 // Error reading extra bytes
  118.                 m_mmr = MMIOERR_CANNOTREAD;
  119.                 goto OPEN_ERROR;
  120.             }
  121.         }
  122.     }
  123.     else
  124.     {
  125.         // Error allocating memory
  126.         m_mmr = MMIOERR_OUTOFMEMORY;
  127.         goto OPEN_ERROR;
  128.     }
  129.     
  130.             
  131.     // Init some member data from format chunk
  132.     m_nBlockAlign = m_pwfmt->nBlockAlign;
  133.     m_nAvgDataRate = m_pwfmt->nAvgBytesPerSec;
  134.  
  135.     // Ascend out of format chunk
  136.     if (m_mmr = mmioAscend (m_hmmio, &m_mmckiFmt, 0))
  137.     {
  138.         goto OPEN_ERROR;
  139.     }
  140.  
  141.     // Cue for streaming
  142.     Cue ();
  143.     
  144.     // Init some member data from data chunk
  145.     // Note cast to __int64 to prevent rollover error in calculation
  146.     m_nDataSize = m_mmckiData.cksize;
  147.     m_nDuration = (UINT)(((__int64) m_nDataSize * 1000) / m_nAvgDataRate);
  148.     
  149.     // Successful open!
  150.     goto OPEN_DONE;
  151.     
  152. OPEN_ERROR:
  153.     // Handle all errors here
  154.     fRtn = FAILURE;
  155.     if (m_hmmio)
  156.     {
  157.         // Close file
  158.         mmioClose (m_hmmio, 0);
  159.         m_hmmio = NULL;
  160.     }
  161.     if (m_pwfmt)
  162.     {
  163.         // UNDONE: Change here if using malloc
  164.         // Free memory
  165.         GlobalFree (m_pwfmt);
  166.         m_pwfmt = NULL;
  167.     }
  168.  
  169. OPEN_DONE:
  170.     return (fRtn);
  171. }
  172.  
  173.  
  174. // Cue
  175. //
  176. BOOL WaveFile::Cue (void)
  177. {
  178.     BOOL fRtn = SUCCESS;    // assume success
  179.  
  180.     TRACE(0, "WaveFile::Cue");
  181.  
  182.     // Seek to 'data' chunk from beginning of file
  183.     if (mmioSeek (m_hmmio, m_mmckiRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET) != -1)
  184.     {
  185.         // Descend into 'data' chunk
  186.         m_mmckiData.ckid = mmioFOURCC('d', 'a', 't', 'a');
  187.         if ((m_mmr = mmioDescend (m_hmmio, &m_mmckiData, &m_mmckiRiff, MMIO_FINDCHUNK)) == MMSYSERR_NOERROR)
  188.         {
  189.             // Reset byte counter
  190.             m_nBytesPlayed = 0;
  191.         }
  192.         else
  193.         {
  194.             // UNDONE: set m_mmr
  195.             fRtn = FAILURE;
  196.         }
  197.     }
  198.     else
  199.     {
  200.         // mmioSeek error
  201.         m_mmr = MMIOERR_CANNOTSEEK;
  202.         fRtn = FAILURE;
  203.     }
  204.  
  205.  
  206.     return fRtn;
  207. }
  208.  
  209.  
  210. // Read
  211. //
  212. // Returns number of bytes actually read.
  213. // On error, returns 0, MMIO error code in m_mmr.
  214. //
  215. UINT WaveFile::Read (BYTE * pbDest, UINT cbSize)
  216. {
  217.     MMIOINFO mmioinfo;
  218.     UINT cb;
  219.  
  220.     TRACE(0, "WaveFile::Read");
  221.  
  222.     // Use direct buffer access for reads to maximize performance
  223.     if (m_mmr = mmioGetInfo (m_hmmio, &mmioinfo, 0))
  224.     {
  225.         goto READ_ERROR;
  226.     }
  227.                 
  228.     // Limit read size to chunk size
  229.     cbSize = (cbSize > m_mmckiData.cksize) ? m_mmckiData.cksize : cbSize;
  230.  
  231.     // Adjust chunk size
  232.     m_mmckiData.cksize -= cbSize;
  233.  
  234.     // Copy bytes from MMIO buffer
  235.     for (cb = 0; cb < cbSize; cb++)
  236.     {
  237.         // Advance buffer if necessary
  238.         if (mmioinfo.pchNext == mmioinfo.pchEndRead)
  239.         {
  240.             if (m_mmr = mmioAdvance (m_hmmio, &mmioinfo, MMIO_READ))
  241.             {
  242.                 goto READ_ERROR;
  243.             }
  244.             
  245.             if (mmioinfo.pchNext == mmioinfo.pchEndRead)
  246.             {
  247.                 m_mmr = MMIOERR_CANNOTREAD;
  248.                 goto READ_ERROR;
  249.             }
  250.         }
  251.             
  252.         // Actual copy
  253. //      *((BYTE*)pbDest+cb) = *((BYTE*)mmioinfo.pchNext)++;
  254.         *(pbDest+cb) = *(mmioinfo.pchNext)++;
  255.     }
  256.  
  257.     // End direct buffer access
  258.     if (m_mmr = mmioSetInfo (m_hmmio, &mmioinfo, 0))
  259.     {
  260.         goto READ_ERROR;
  261.     }
  262.  
  263.     // Successful read, keep running total of number of data bytes read
  264.     m_nBytesPlayed += cbSize;
  265.     goto READ_DONE;
  266.     
  267. READ_ERROR:
  268.     cbSize = 0;
  269.  
  270. READ_DONE:
  271.     return (cbSize);
  272. }
  273.  
  274.  
  275. // GetSilenceData
  276. //
  277. // Returns 8 bits of data representing silence for the Wave file format.
  278. //
  279. // Since we are dealing only with PCM format, we can fudge a bit and take
  280. // advantage of the fact that for all PCM formats, silence can be represented
  281. // by a single byte, repeated to make up the proper word size. The actual size
  282. // of a word of wave data depends on the format:
  283. //
  284. // PCM Format       Word Size       Silence Data
  285. // 8-bit mono       1 byte          0x80
  286. // 8-bit stereo     2 bytes         0x8080
  287. // 16-bit mono      2 bytes         0x0000
  288. // 16-bit stereo    4 bytes         0x00000000
  289. //
  290. BYTE WaveFile::GetSilenceData (void)
  291. {
  292.     BYTE bSilenceData = 0;
  293.  
  294.     // Silence data depends on format of Wave file
  295.     if (m_pwfmt)
  296.     {
  297.         if (m_pwfmt->wBitsPerSample == 8)
  298.         {
  299.             // For 8-bit formats (unsigned, 0 to 255)
  300.             // Packed DWORD = 0x80808080;
  301.             bSilenceData = 0x80;
  302.         }
  303.         else if (m_pwfmt->wBitsPerSample == 16)
  304.         {
  305.             // For 16-bit formats (signed, -32768 to 32767)
  306.             // Packed DWORD = 0x00000000;
  307.             bSilenceData = 0x00;
  308.         }
  309.         else
  310.         {
  311.             ASSERT (0);
  312.         }
  313.     }
  314.     else
  315.     {
  316.         ASSERT (0);
  317.     }
  318.  
  319.     return (bSilenceData);
  320. }
  321.