home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Multimedia Jumpstart 1.1a / CD_ROM.BIN / develpmt / source / waveconv / waveio.c < prev    next >
C/C++ Source or Header  |  1992-11-04  |  23KB  |  914 lines

  1. /** waveio.c
  2.  *
  3.  *
  4.      (C) Copyright Microsoft Corp. 1991, 1992.  All rights reserved.
  5.  
  6.      You have a royalty-free right to use, modify, reproduce and 
  7.      distribute the Sample Files (and/or any modified version) in 
  8.      any way you find useful, provided that you agree that 
  9.      Microsoft has no warranty obligations or liability for any 
  10.      Sample Application Files which are modified. 
  11.      
  12.      If you did not get this from Microsoft Sources, then it may not be the
  13.      most current version.  This sample code in particular will be updated
  14.      and include more documentation.  
  15.  
  16.      Sources are:
  17.          The MM Sys File Transfer BBS: The phone number is 206 936-4082.
  18.     CompuServe: WINSDK forum, MDK section.
  19.     Anonymous FTP from ftp.uu.net vendor\microsoft\multimedia
  20.  *
  21.  **  */
  22.  
  23.  
  24. #define STRICT
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <mmsystem.h>
  28. #include <memory.h>
  29. #include <mmreg.h>
  30. #include "waveconv.h"
  31. #include "riffsup.h"
  32. #include "wavesup.h"
  33. #include "waveio.h"
  34.  
  35. extern LPWAVEIOCB      glpwio;
  36. LPINFOCHUNK glpInfo;
  37.  
  38. BOOL NEAR PASCAL FreeWaveHeaders(const LPWAVEIOCB lpwio);
  39.  
  40. #if (_MSC_VER < 700)
  41. //
  42. //  this silly stuff is to get around a bug in the C6 compiler's optimizer
  43. //
  44. #ifdef GlobalFreePtr
  45. #undef GlobalFreePtr
  46. #define GlobalFreePtr(x)    GlobalFree((HGLOBAL)SELECTOROF(x))
  47. #endif
  48.  
  49. #endif
  50.  
  51. /** LRESULT WIOAPI wioFileOpen(LPHWIO lphwio, LPCSTR lpszFilePath, DWORD dwFlags)
  52.  *
  53.  *  DESCRIPTION:
  54.  *      
  55.  *
  56.  *  ARGUMENTS:
  57.  *      (LPHWIO lphwio, LPSTR lpszFilePath, DWORD dwFlags)
  58.  *
  59.  *  RETURN (LRESULT WIOAPI):
  60.  *
  61.  *
  62.  *  NOTES:
  63.  *
  64.  **  */
  65.  
  66. LRESULT WIOAPI wioFileOpen(LPWAVEIOCB FAR * lplpwio, LPCSTR lpszFilePath, DWORD dwFlags)
  67. {
  68.     HMMIO       hmmio;
  69.     WAVEIOCB    wio;
  70.     LPWAVEIOCB  lpwio;
  71.     MMCKINFO    ckRIFF;
  72.     MMCKINFO    ck;
  73.     DWORD       dw;
  74.     LRESULT     lr;
  75.     LRESULT    lrt;
  76.  
  77.     //
  78.     //  validate a couple of things...
  79.     //
  80.     if (!lplpwio)
  81.         return (WIOERR_BADPARAM);
  82.  
  83.     *lplpwio = NULL;
  84.  
  85.     //
  86.     //  default our error return (assume the worst)
  87.     //
  88.     lr    = WIOERR_FILEERROR;
  89.     lpwio = NULL;
  90.  
  91.     //
  92.     //  first try to open the file, etc.. open the given file for reading
  93.     //  using buffered I/O
  94.     //
  95.     hmmio = mmioOpen((LPSTR)lpszFilePath, NULL, MMIO_READ | MMIO_ALLOCBUF);
  96.     if (!hmmio)
  97.         goto wio_Open_Error;
  98.  
  99.     //
  100.     //  locate a 'WAVE' form type...
  101.     //
  102.     ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  103.     if (mmioDescend(hmmio, (LPMMCKINFO)&ckRIFF, NULL, MMIO_FINDRIFF))
  104.         goto wio_Open_Error;
  105.  
  106.     //
  107.     //  we found a WAVE chunk--now go through and get all subchunks that
  108.     //  we know how to deal with...
  109.     //
  110.     //
  111.     lr = WIOERR_FILEERROR;
  112.     
  113.     _fmemset(&wio, 0, sizeof(wio));
  114.  
  115.     wio.dwDataSamples  = (DWORD)-1L;
  116.  
  117.     if(lrt=riffInitINFO(&wio.pInfo))
  118.     {
  119.     lr=lrt;
  120.     goto wio_Open_Error;
  121.     }
  122.     
  123.     while (mmioDescend(hmmio, &ck, &ckRIFF, 0) == 0)
  124.     {
  125.         //
  126.         //  quickly check for corrupt RIFF file--don't ascend past end!
  127.         //
  128.         if ((ck.dwDataOffset + ck.cksize) > (ckRIFF.dwDataOffset + ckRIFF.cksize))
  129.             goto wio_Open_Error;
  130.  
  131.         switch (ck.ckid)
  132.         {
  133.             case mmioFOURCC('L', 'I', 'S', 'T'):
  134.         if(ck.fccType==mmioFOURCC('I', 'N', 'F', 'O'))
  135.             if(lrt=riffReadINFO(hmmio, &ck, wio.pInfo))
  136.             {
  137.             lr=lrt;
  138.             goto wio_Open_Error;
  139.             }
  140.         break;
  141.         
  142.             case mmioFOURCC('D', 'I', 'S', 'P'):
  143.         riffReadDISP(hmmio, &ck, &(wio.pDisp));
  144.         break;
  145.         
  146.             case mmioFOURCC('f', 'm', 't', ' '):
  147.                 //
  148.                 //  !?! another format chunk !?!
  149.                 //
  150.                 if (lpwio)
  151.                     break;
  152.  
  153.                 //
  154.                 //  get size of the format chunk, allocate and lock memory
  155.                 //  for it. we always alloc a complete extended format header
  156.                 //  (even for PCM headers that do not have the cbSize field
  157.                 //  defined--we just set it to zero).
  158.                 //
  159.                 dw = ck.cksize;
  160.                 if (dw < sizeof(WAVEFORMATEX))
  161.                     dw = sizeof(WAVEFORMATEX);
  162.  
  163.                 dw += sizeof(WAVEIOCB) - sizeof(WAVEFORMATEX);
  164.  
  165.                 lpwio = (LPWAVEIOCB)GlobalAllocPtr(GHND, dw);
  166.                 if (!lpwio)
  167.                 {
  168.                     lr = WIOERR_NOMEM;
  169.                     goto wio_Open_Error;
  170.                 }
  171.  
  172.                 lpwio->dwSize = dw;
  173.  
  174.                 //
  175.                 //  read the format chunk
  176.                 //
  177.                 lr = WIOERR_FILEERROR;
  178.                 dw = ck.cksize;
  179.                 if (mmioRead(hmmio, (HPSTR)&lpwio->wfx, dw) != (LONG)dw)
  180.                     goto wio_Open_Error;
  181.                 break;
  182.  
  183.  
  184.             case mmioFOURCC('d', 'a', 't', 'a'):
  185.                 //
  186.                 //  !?! multiple data chunks !?!
  187.                 //
  188.                 if (wio.dwDataBytes)
  189.                     break;
  190.  
  191.                 //
  192.                 //  just hang on to the total length in bytes of this data
  193.                 //  chunk..
  194.                 //
  195.                 wio.dwDataBytes = ck.cksize;
  196.         wio.dwDataOffset= ck.dwDataOffset;  // offset of data portion
  197.                             // of data chunk
  198.                 break;
  199.  
  200.  
  201.             case mmioFOURCC('f', 'a', 'c', 't'):
  202.                 //
  203.                 //  !?! multiple fact chunks !?!
  204.                 //
  205.                 if (wio.dwDataSamples != -1L)
  206.                     break;
  207.  
  208.                 //
  209.                 //  read the first dword in the fact chunk--it's the only
  210.                 //  info we need (and is currently the only info defined for
  211.                 //  the fact chunk...)
  212.                 //
  213.                 //  if this fails, dwDataSamples will remain -1 so we will
  214.                 //  deal with it later...
  215.                 //
  216.                 mmioRead(hmmio, (HPSTR)&wio.dwDataSamples, sizeof(DWORD));
  217.                 break;
  218.         }
  219.  
  220.         //
  221.         //  step up to prepare for next chunk..
  222.         //
  223.         mmioAscend(hmmio, &ck, 0);
  224.     }
  225.  
  226.     //
  227.     //  if no fmt chunk was found, then die!
  228.     //
  229.     if (!lpwio)
  230.     {
  231.         lr = WIOERR_ERROR;
  232.         goto wio_Open_Error;
  233.     }
  234.  
  235.     //
  236.     //  all wave files other than PCM are _REQUIRED_ to have a fact chunk
  237.     //  telling the number of samples that are contained in the file. it
  238.     //  is optional for PCM (and if not present, we compute it here).
  239.     //
  240.     //  if the file is not PCM and the fact chunk is not found, then fail!
  241.     //
  242.     if (wio.dwDataSamples == -1L)
  243.     {
  244.         if (lpwio->wfx.wFormatTag != WAVE_FORMAT_PCM)
  245.         {
  246. #if 0
  247.             goto wio_Open_Error;
  248. #else
  249.             UINT    u;
  250.  
  251.             //
  252.             //  !!! HACK HACK HACK !!!
  253.             //
  254.             //  although this should be considered an invalid wave file, we
  255.             //  will bring up a message box describing the error--hopefully
  256.             //  people will start realizing that something is missing???
  257.             //
  258.             u = MessageBox(NULL, "This wave file does not have a 'fact' chunk and requires one! This is completely invalid and MUST be fixed! Attempt to load it anyway?",
  259.                             "wioFileOpen", MB_YESNO | MB_ICONEXCLAMATION | MB_TASKMODAL);
  260.             if (u == IDNO)
  261.         {
  262.         lr=WIOERR_BADFILE;
  263.                 goto wio_Open_Error;
  264.         }
  265.  
  266.             //
  267.             //  !!! need to hack stuff in here !!!
  268.             //
  269.             wio.dwDataSamples = 0L;
  270. #endif
  271.         }
  272.         else
  273.         {
  274.             wio.dwDataSamples = wsupBytesToSamples(&lpwio->wfx, wio.dwDataBytes);
  275.         }
  276.     }
  277.  
  278.     //
  279.     //  cool! no problems.. 
  280.     //
  281.     lpwio->hmmio          = NULL;
  282.  
  283.  
  284.     lpwio->dwFlags        = wio.dwFlags;
  285.     lpwio->dwDataBytes    = wio.dwDataBytes;
  286.     lpwio->dwDataSamples  = wio.dwDataSamples;
  287.     lpwio->dwDataOffset   = wio.dwDataOffset;
  288.     lpwio->pDisp      = wio.pDisp;
  289.     lpwio->pInfo      = wio.pInfo;
  290.  
  291.     if (hmmio)
  292.         mmioClose(hmmio, 0);
  293.  
  294.     *lplpwio = lpwio;
  295.  
  296.     return (WIOERR_NOERROR);
  297.  
  298.  
  299.     //
  300.     //  return error (after minor cleanup)
  301.     //
  302. wio_Open_Error:
  303.  
  304.     wioFileClose(&lpwio,0);
  305. #if 0    
  306.     if (lpwio)
  307.         GlobalFreePtr(lpwio);
  308.  
  309.     if (hmmio)
  310.         mmioClose(hmmio, 0);
  311. #endif
  312.     return (lr);
  313. } /* wioFileOpen() */
  314.  
  315.  
  316. /** LRESULT WIOAPI wioFileClose(HWIO hwio, DWORD dwFlags)
  317.  *
  318.  *  DESCRIPTION:
  319.  *      
  320.  *
  321.  *  ARGUMENTS:
  322.  *      (HWIO hwio, DWORD dwFlags)
  323.  *
  324.  *  RETURN (LRESULT WIOAPI):
  325.  *
  326.  *
  327.  *  NOTES:
  328.  *
  329.  **  */
  330.  
  331. LRESULT WIOAPI wioFileClose(LPWAVEIOCB FAR * lplpwio, DWORD dwFlags)
  332. {
  333.     LPWAVEIOCB  lpwio;
  334.  
  335.     //
  336.     //  validate a couple of things...
  337.     //
  338.     if (!lplpwio)
  339.         return (WIOERR_BADPARAM);
  340.  
  341.     lpwio=*lplpwio;
  342.     if(!lpwio)
  343.     return (WIOERR_BADPARAM);
  344.  
  345.     //
  346.     //  get rid of stuff...
  347.     //
  348.  
  349.     wioStopWave(lpwio);
  350.     
  351.     if (lpwio->hmmio)
  352.     {
  353.         mmioClose(lpwio->hmmio, 0);
  354.     lpwio->hmmio=NULL;
  355.     }
  356.     
  357.     FreeWaveHeaders(lpwio);
  358.  
  359.     if(lpwio->pInfo)
  360.     riffFreeINFO(&(lpwio->pInfo));
  361.     
  362.     if(lpwio->pDisp)
  363.     riffFreeDISP(&(lpwio->pDisp));
  364.  
  365.     GlobalFreePtr(lpwio);
  366.  
  367.     return (WIOERR_NOERROR);
  368. } /* wioFileClose() */
  369.  
  370.  
  371.  
  372. ///////////////////////////////////////////////////////////////////////////////
  373.  
  374.  
  375. static BOOL fStopping=FALSE;
  376. static BOOL fSyncDriver=FALSE;
  377.  
  378.  
  379.  
  380. /* wioWaveOutDone(lpwio, pWaveHdr)
  381.  *
  382.  * Called when wave block with header <pWaveHdr> is finished playing.
  383.  * This function causes playing to end.
  384.  *
  385.  * Call when window receives MM_WOM_DONE message.
  386.  *
  387.  */
  388. void WIOAPI wioWaveOutDone(const LPWAVEIOCB lpwio, const LPWAVEHDR pWaveHdr)
  389. {
  390.     WORD w;
  391.  
  392.     // Search for which header this is
  393.     for(w=0;w<MAX_WAVEHDRS;w++)
  394.     {
  395.     if(pWaveHdr==lpwio->apWaveHdr[w])
  396.         break;
  397.     }
  398.  
  399.     if(w>=MAX_WAVEHDRS)
  400.     return;    //this was not one of our buffers
  401.  
  402.     if(lpwio->hwo)
  403.     {
  404.     // we are done with the buffer
  405.     waveOutUnprepareHeader(lpwio->hwo, pWaveHdr, sizeof(WAVEHDR));
  406.     lpwio->apWHUsed[w]=FALSE;
  407.     }
  408.     
  409.     if(lpwio->dwBytesLeft && !fStopping)
  410.     {
  411.     lpwio->apWaveHdr[w]->dwBufferLength = min(lpwio->dwBytesPerBuffer,lpwio->dwBytesLeft);
  412.     lpwio->apWaveHdr[w]->dwFlags        = 0L;
  413.     lpwio->apWaveHdr[w]->dwLoops        = 0L;
  414.  
  415.     // read the data from the file
  416.     if (mmioRead(lpwio->hmmio, (HPSTR)lpwio->apWaveHdr[w]->lpData,
  417.         lpwio->apWaveHdr[w]->dwBufferLength) !=
  418.               (LONG)lpwio->apWaveHdr[w]->dwBufferLength)
  419.     {
  420.         return;
  421.     }
  422.  
  423.     // kep track of how much is left to read
  424.     lpwio->dwBytesLeft-=lpwio->apWaveHdr[w]->dwBufferLength;
  425.  
  426.     // prepare the header
  427.     if (waveOutPrepareHeader(lpwio->hwo, lpwio->apWaveHdr[w], sizeof(WAVEHDR)) != 0)
  428.         return;
  429.  
  430.     // put it into the queue to play.  If output is not paused,
  431.     // playback will start immediately if the driver is async
  432.     //
  433.     // if the driver is synchronous, this call will not return
  434.     // until buffer has been played.
  435.     //
  436.     if (waveOutWrite(lpwio->hwo, lpwio->apWaveHdr[w], sizeof(WAVEHDR)) != 0)
  437.         return;
  438.  
  439.     // we are using it
  440.     lpwio->apWHUsed[w]=TRUE;
  441.  
  442.     }
  443.     else
  444.     {
  445.     // if no more data to play and all buffers are done playing,
  446.     // or we have been asked to stop
  447.  
  448.     for(w=0;w<MAX_WAVEHDRS;w++)
  449.     {
  450.         // find out if all buffers are free
  451.         if(lpwio->apWHUsed[w])
  452.         break;
  453.     }
  454.  
  455.     // all buffers are free, close the device
  456.     if(w>=MAX_WAVEHDRS)
  457.     {
  458.         if(lpwio->hwo)
  459.         if(!waveOutClose(lpwio->hwo))
  460.             // clear only if we actually closed (no error)
  461.             lpwio->hwo = NULL;
  462.     }
  463.     // else data is still playing from the buffers...
  464.     }
  465. }
  466.  
  467.  
  468. /** BOOL NEAR PASCAL FreeWaveHeaders(const LPWAVEIOCV lpwio)
  469.  *
  470.  *  DESCRIPTION:
  471.  *      
  472.  *
  473.  *  ARGUMENTS:
  474.  *      (void)
  475.  *
  476.  *  RETURN (BOOL NEAR PASCAL):
  477.  *
  478.  *
  479.  *  NOTES:
  480.  *
  481.  **  */
  482.  
  483. BOOL NEAR PASCAL FreeWaveHeaders(const LPWAVEIOCB lpwio)
  484. {
  485.     UINT    i;
  486.  
  487.     DPF("FreeWaveHeaders!\n");
  488.  
  489.     //
  490.     //  free any previously allocated wave headers..
  491.     //
  492.     for (i = 0; i < MAX_WAVEHDRS; i++)
  493.     {
  494.         if (lpwio->apWaveHdr[i])
  495.         {
  496.             GlobalFreePtr(lpwio->apWaveHdr[i]);
  497.             lpwio->apWaveHdr[i] = NULL;
  498.         }
  499.     lpwio->apWHUsed[i]=FALSE;
  500.     }
  501.  
  502.     return (TRUE);
  503. } /* FreeWaveHeaders() */
  504.  
  505.  
  506. /** BOOL NEAR PASCAL AllocWaveHeaders(LPWAVEIOCV lpwio)
  507.  *
  508.  *  DESCRIPTION:
  509.  *      
  510.  *
  511.  *  ARGUMENTS:
  512.  *      (WAVEFORMATEX *pwfx)
  513.  *
  514.  *  RETURN (BOOL NEAR PASCAL):
  515.  *
  516.  *
  517.  *  NOTES:
  518.  *
  519.  **  */
  520.  
  521. BOOL NEAR PASCAL AllocWaveHeaders(const LPWAVEIOCB lpwio)
  522. {
  523.     UINT        i;
  524.     WORD        wBytes;
  525.     LPWAVEHDR   pwh;
  526.     WAVEFORMATEX FAR *pwfx;
  527.  
  528.     if(lpwio->apWaveHdr[0])
  529.     {
  530.     for(i=0;i<MAX_WAVEHDRS; i++)
  531.         lpwio->apWHUsed[i]  = FALSE;
  532.     return TRUE;
  533.     }
  534.     
  535.     pwfx=&(lpwio->wfx);
  536.  
  537.     DPF("AllocWaveHeaders: allocating %u buffers\n", MAX_WAVEHDRS);
  538.  
  539.     //
  540.     // get how many bytes we want to have in each buffer
  541.     //
  542.     wBytes = (WORD)wsupTimeToSamples(pwfx, AVG_BUF_MS);
  543.     wBytes = (WORD)wsupSamplesToBytes(pwfx, wBytes);
  544.  
  545.     // need to align on block alignment...
  546.     lpwio->dwBytesPerBuffer = wBytes;
  547.  
  548.     //
  549.     //  allocate all of the wave headers/buffers for streaming
  550.     //
  551.     for (i = 0; i < MAX_WAVEHDRS; i++)
  552.     {
  553.         // Add DWORD to size make sure data does not use up a partial DWORD boundary
  554.         pwh = GlobalAllocPtr(GMEM_FIXED|GMEM_SHARE, wBytes + sizeof(WAVEHDR) + sizeof(DWORD));
  555.         if (pwh == NULL)
  556.             goto AWH_ERROR_NOMEM;
  557.  
  558.         // Initialize header information
  559.         pwh->lpData         = (LPSTR)(pwh + 1); // Data occurs directly after the header
  560.         pwh->dwBufferLength = wBytes;
  561.         pwh->dwFlags        = 0L;
  562.         pwh->dwLoops        = 0L;
  563.  
  564.         lpwio->apWaveHdr[i] = pwh;
  565.     lpwio->apWHUsed[i]  = FALSE;
  566.     }
  567.  
  568.     return (TRUE);
  569.  
  570. AWH_ERROR_NOMEM:
  571.     FreeWaveHeaders(lpwio);
  572.     return (FALSE);
  573. } /* AllocWaveHeaders() */
  574.  
  575. /** UINT NEAR PASCAL wioWaveOpen(hwnd, lphwave, lpwfx, fInput)
  576.  *
  577.  *  DESCRIPTION:
  578.  *      
  579.  *
  580.  *  ARGUMENTS:
  581.  *      (LPHWAVE lphwave, LPWAVEFORMATEX lpwfx, BOOL fInput)
  582.  *
  583.  *  RETURN (UINT NEAR PASCAL):
  584.  *
  585.  *
  586.  *  NOTES: C#
  587.  *
  588.  **  */
  589.  
  590. UINT NEAR PASCAL wioWaveOpen(HWND hwnd, HWAVEOUT FAR * lphwave, const LPWAVEFORMATEX lpwfx, BOOL fInput)
  591. {
  592.     UINT    uErr;
  593.  
  594.     if (!lphwave || !lpwfx)
  595.         return (1);
  596.  
  597.     *lphwave = NULL;
  598.  
  599.     //
  600.     //  first open the wave device DISALLOWING sync drivers (sync drivers
  601.     //  do not work with a streaming buffer scheme; which is our preferred
  602.     //  mode of operation)
  603.     //
  604.     //  if we cannot open a non-sync driver, then we will attempt for
  605.     //  a sync driver and handle the situation
  606.     //
  607.     fSyncDriver = FALSE;
  608.     if (fInput)
  609.     {
  610.         uErr = waveInOpen((HWAVEIN FAR *)lphwave, (UINT)WAVE_MAPPER, (WAVEFORMAT FAR* )lpwfx,
  611.                             (DWORD)(UINT)hwnd, 0L, CALLBACK_WINDOW);
  612.         if (uErr)
  613.         {
  614.             if (uErr == WAVERR_SYNC)
  615.             {
  616.                 uErr = waveInOpen((HWAVEIN FAR *)lphwave, (UINT)WAVE_MAPPER,
  617.                                    (WAVEFORMAT FAR* )lpwfx, (DWORD)(UINT)hwnd,
  618.                     0L, CALLBACK_WINDOW|WAVE_ALLOWSYNC);
  619.                 if (uErr == MMSYSERR_NOERROR)
  620.                 {
  621.                     fSyncDriver = TRUE;
  622.                 }
  623.             }
  624.         }
  625.     }
  626.     else
  627.     {
  628.         uErr = waveOutOpen(lphwave, (UINT)WAVE_MAPPER, (LPWAVEFORMAT)lpwfx,
  629.                             (DWORD)(UINT)hwnd, 0L, CALLBACK_WINDOW);
  630.         if (uErr)
  631.         {
  632.             if (uErr == WAVERR_SYNC)
  633.             {
  634.                 uErr = waveOutOpen(lphwave, (UINT)WAVE_MAPPER,
  635.                                    (LPWAVEFORMAT)lpwfx, (DWORD)(UINT)hwnd, 0L,
  636.                                    CALLBACK_WINDOW|WAVE_ALLOWSYNC);
  637.                 if (uErr == MMSYSERR_NOERROR)
  638.                 {
  639.                     fSyncDriver = TRUE;
  640.                 }
  641.             }
  642.         }
  643.     }
  644.  
  645.     return (uErr);
  646. }
  647.  
  648. BOOL WIOAPI wioIsPlaying(const LPWAVEIOCB lpwio)
  649. {
  650.     if(!lpwio)
  651.     return FALSE;
  652.     
  653.     return lpwio->hwo !=0;
  654. }
  655.  
  656.  
  657. /* fOK = wioPlayWave()
  658.  *
  659.  * Start playing from the current position.
  660.  *
  661.  * On success, return TRUE.  On failure, display an error message
  662.  * and return FALSE.
  663.  */
  664. LRESULT WIOAPI wioPlayWave(HWND hwnd, LPWAVEIOCB lpwio, LPCSTR lpszFilePath, DWORD dwFlags)
  665. {
  666.     WORD        w;
  667.     UINT    u;
  668.     LRESULT    lr;
  669.     MMCKINFO    ck;
  670.  
  671.     DPF("wioPlayWave called\n");
  672.  
  673.     lr=WIOERR_NOERROR;
  674.     
  675.     if(!lpwio)
  676.     lr=wioFileOpen(&lpwio, lpszFilePath, dwFlags);
  677.     
  678.     if(!lpwio)
  679.     return lr;
  680.  
  681.     /* we are currently playing....*/
  682.     if (lpwio->hwo != NULL)
  683.     return TRUE;
  684.  
  685.     /* stop playing or recording */
  686.     wioStopWave(lpwio);
  687.  
  688.     /* open the wave output device */
  689.     u = wioWaveOpen(hwnd, &lpwio->hwo, &(lpwio->wfx), FALSE);
  690.     if (u)
  691.     {
  692.     /* cannot open the waveform output device -- if the problem
  693.      * is that the wave format is not supported, tell the caller
  694.      */
  695.     if (u == MMSYSERR_NOTSUPPORTED || (u == WAVERR_BADFORMAT))
  696.     {
  697.         lr=WIOERR_NOTSUPPORTED;
  698.         goto wio_Play_Error;
  699.     }
  700.     else if (u == MMSYSERR_ALLOCATED)
  701.     {
  702.         lr=WIOERR_ALLOCATED;
  703.         goto wio_Play_Error;
  704.     }
  705.     else
  706.     {
  707.         /* unknown error */
  708.         lr=WIOERR_ERROR;
  709.         goto wio_Play_Error;
  710.     }
  711.     }
  712.     // we now have the output wave device open
  713.  
  714.     //
  715.     //  (re)open the file
  716.     //
  717.     if (!lpwio->hmmio)
  718.     lpwio->hmmio = mmioOpen((LPSTR)lpszFilePath, NULL, MMIO_READ | MMIO_ALLOCBUF);
  719.     
  720.     if (!lpwio->hmmio)
  721.         return WIOERR_FILEERROR;
  722.  
  723.     // get to the 'data' chunk
  724.     if(mmioSeek(lpwio->hmmio, lpwio->dwDataOffset-sizeof(CHUNK), SEEK_SET)!=(LONG)(lpwio->dwDataOffset-sizeof(CHUNK)))
  725.     {
  726.     lr=WIOERR_FILEERROR;
  727.     goto wio_Play_Error;
  728.     }
  729.  
  730.     // now we are at start of 'data' chunk, descend into the chunk
  731.     if (mmioDescend(lpwio->hmmio, &ck, NULL, 0))
  732.     {
  733.     lr=WIOERR_FILEERROR;
  734.     goto wio_Play_Error;
  735.     }
  736.  
  737.     if(fSyncDriver)
  738.     {
  739.     // driver is synchronous and will only take one buffer
  740.     // at a time to play.... (speaker driver should be only synch driver)
  741.     //
  742.     WORD        wBytes;
  743.     LPWAVEHDR   pwh=NULL;
  744.  
  745.     //
  746.     // get how many bytes we want to have in the only buffer
  747.     //
  748.     wBytes = (WORD)wsupTimeToSamples(&(lpwio->wfx), SYNC_BUF_MS);
  749.     wBytes = (WORD)wsupSamplesToBytes(&(lpwio->wfx), wBytes);
  750.  
  751.     
  752.         pwh = GlobalAllocPtr(GMEM_FIXED|GMEM_SHARE, wBytes + sizeof(WAVEHDR) + sizeof(DWORD));
  753.     if(!pwh)
  754.     {
  755.         pwh->lpData         = (LPSTR)(pwh + 1); // Data occurs directly after the header
  756.         pwh->dwBufferLength = min(lpwio->dwBytesPerBuffer,lpwio->dwBytesLeft);
  757.         pwh->dwFlags    = 0L;
  758.         pwh->dwLoops    = 0L;
  759.         
  760.         // read the data from the file...
  761.         if (mmioRead(lpwio->hmmio, (HPSTR)lpwio->apWaveHdr[w]->lpData,
  762.         lpwio->apWaveHdr[w]->dwBufferLength) !=
  763.               (LONG)lpwio->apWaveHdr[w]->dwBufferLength)
  764.         {
  765.         lr=WIOERR_FILEERROR;
  766.         goto wio_Play_Sync_Error;
  767.         }
  768.         
  769.         // prepare the buffer and header
  770.         if (waveOutPrepareHeader(lpwio->hwo, pwh, sizeof(WAVEHDR)) != 0)
  771.         {
  772.         lr=WIOERR_ERROR;
  773.         goto wio_Play_Sync_Error;
  774.         }
  775.  
  776.         // since the driver is synchronous, this call will not return
  777.         // until buffer has been played.
  778.         //
  779.         if (waveOutWrite(lpwio->hwo, pwh, sizeof(WAVEHDR)) != 0)
  780.         {
  781.         lr=WIOERR_ERROR;
  782.         goto wio_Play_Sync_Error;
  783.         }
  784.  
  785.         // data has been played...
  786.         
  787.     }
  788. wio_Play_Sync_Error:
  789.     if(pwh)
  790.         GlobalFreePtr(pwh);
  791.     waveOutClose(lpwio->hwo);
  792.     lpwio->hwo=NULL;
  793.     
  794.     goto wio_Play_NoError;
  795.     }
  796.  
  797.     // else it is an asynch driver (almost all are)
  798.     
  799.     AllocWaveHeaders(lpwio);
  800.  
  801.     // initialize to play entire file
  802.     lpwio->dwBytesLeft=lpwio->dwDataBytes;
  803.  
  804.     // pause the output so the buffers won't play until we tell it to
  805.     waveOutPause(lpwio->hwo);
  806.  
  807.     for(w=0;w<MAX_WAVEHDRS;w++)
  808.     {
  809.     // setup wave header
  810.     lpwio->apWaveHdr[w]->dwBufferLength= min(lpwio->dwBytesPerBuffer,lpwio->dwBytesLeft);
  811.     lpwio->apWaveHdr[w]->dwFlags = 0L;
  812.     lpwio->apWaveHdr[w]->dwLoops = 0L;
  813.  
  814.     // read the data from the file...
  815.     if (mmioRead(lpwio->hmmio, (HPSTR)lpwio->apWaveHdr[w]->lpData,
  816.         lpwio->apWaveHdr[w]->dwBufferLength) !=
  817.               (LONG)lpwio->apWaveHdr[w]->dwBufferLength)
  818.     {
  819.         lr=WIOERR_FILEERROR;
  820.         goto wio_Play_Error;
  821.     }
  822.  
  823.     // set the buffer length to play
  824.     lpwio->dwBytesLeft-=lpwio->apWaveHdr[w]->dwBufferLength;
  825.  
  826.     // prepare the buffer and header
  827.     if (waveOutPrepareHeader(lpwio->hwo, lpwio->apWaveHdr[w], sizeof(WAVEHDR)) != 0)
  828.         goto wio_Play_Error_WAVEOUT;
  829.  
  830.     // put it into the queue to play.  If output is not paused,
  831.     // playback will start immediately if the driver is async
  832.     //
  833.     if (waveOutWrite(lpwio->hwo, lpwio->apWaveHdr[w], sizeof(WAVEHDR)) != 0)
  834.         goto wio_Play_Error_WAVEOUT;
  835.  
  836.     // the system is using this buffer
  837.     lpwio->apWHUsed[w]=TRUE;
  838.  
  839.     // if no more data to read, stop getting more
  840.     if(!lpwio->dwBytesLeft)
  841.         break;
  842.     }
  843.  
  844.     // start the buffers playing (unpause)
  845.     waveOutRestart(lpwio->hwo);
  846.  
  847.     // we are done starting the file to play.  return success
  848.     fStopping = FALSE;
  849.     lr=WIOERR_NOERROR;
  850.     goto wio_Play_NoError;
  851.  
  852. wio_Play_Error_WAVEOUT:
  853.  
  854.     // there was an error working with the wave buffers
  855.     wioStopWave(lpwio);
  856.     for(w=0;w<MAX_WAVEHDRS;w++)
  857.     {
  858.     if(lpwio->apWHUsed[w])
  859.         waveOutUnprepareHeader(lpwio->hwo, lpwio->apWaveHdr[w], sizeof(WAVEHDR));
  860.     lpwio->apWHUsed[w]=FALSE;
  861.     }
  862.  
  863.     if(lpwio->hwo)
  864.     if(!waveOutClose(lpwio->hwo))
  865.         lpwio->hwo = NULL;
  866.  
  867.     // fall through...
  868.         
  869. wio_Play_Error:
  870.  
  871. wio_Play_NoError:
  872.  
  873.     return lr;
  874.  
  875. }
  876.  
  877.  
  878. /* wioStopWave(lpwio)
  879.  *
  880.  * Request waveform playback to stop.
  881.  */
  882. void WIOAPI wioStopWave(const LPWAVEIOCB lpwio)
  883. {
  884.     MSG             msg;
  885.  
  886.     if(!lpwio)
  887.     return;
  888.     
  889.     if (lpwio->hwo != NULL)
  890.     {
  891.     waveOutReset(lpwio->hwo);
  892.     fStopping = TRUE;
  893.     }
  894.  
  895.     if (lpwio->hwo != NULL)
  896.     {
  897.     /* get messages from event queue and dispatch them,
  898.      * until all the MM_WOM_DONE messages are processed
  899.      */
  900.     while (GetMessage(&msg, NULL, 0, 0))
  901.     {
  902.         TranslateMessage(&msg);
  903.         DispatchMessage(&msg);
  904.         
  905.         if (lpwio->hwo == NULL)
  906.         break;
  907.     }
  908.     }
  909. }
  910.  
  911.  
  912.  
  913. /** EOF: waveio.c **/
  914.