home *** CD-ROM | disk | FTP | other *** search
/ NEXT Generation 27 / NEXT27.iso / pc / demos / emperor / dx3.exe / SDK / SAMPLES / DSSTREAM / DSTRTIME.C < prev    next >
C/C++ Source or Header  |  1996-08-28  |  14KB  |  329 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:               Dstrtime.c
  6.  *  Content:    This source file contains a Multimedia Timer Callback
  7.  *             procedure which is used by the DirectSound Stream Sample
  8.  *             application to update the playback buffer at regular intervals
  9.  *
  10.  ***************************************************************************/
  11. #define WIN32_LEAN_AND_MEAN
  12. #include <windows.h>
  13. #include <windowsx.h>
  14. #include <mmsystem.h>
  15. #include <dsound.h>
  16. #include <commctrl.h>
  17. #include <commdlg.h>
  18. #include <memory.h>
  19. #include <cderr.h>
  20.  
  21. #include "dsstream.h"
  22.  
  23. extern HWND  hWndMain; 
  24. extern char  szDebug[];
  25. extern WAVEINFOCA wiWave;
  26.  
  27. LONG lInTimer = FALSE;
  28.  
  29. void CALLBACK TimeFunc( UINT uTimerID, UINT uMsg, DWORD dwUser,
  30.                                                         DWORD dw1, DWORD dw2 )
  31.     {
  32.     LPBYTE      lpWrite1, lpWrite2, lpTemp;
  33.     DWORD       dwLen1, dwLen2, dwPlay, dwWrite, dwPlayedLength, dwWriteLength;
  34.     DWORD       dwLeftToRead, dwStatus;
  35.     int         nChkErr;
  36.     UINT        uChkErr;
  37.     BOOL        fRefillLostBuffer = FALSE;
  38.     HRESULT     hr;
  39.  
  40.     if (InterlockedExchange(&lInTimer, TRUE)) return;
  41.  
  42.     /* See if the buffer has been lost */
  43.     IDirectSoundBuffer_GetStatus( wiWave.lpDSBStreamBuffer, &dwStatus );
  44.     if( DSBSTATUS_BUFFERLOST & dwStatus )
  45.         {
  46.         // Restore the buffer and set some variables that will cause it
  47.         // to be filled again and replayed
  48.         hr = IDirectSoundBuffer_Restore( wiWave.lpDSBStreamBuffer );
  49.         if( FAILED( hr ))
  50.             {
  51.             InterlockedExchange( &lInTimer, FALSE );
  52.             return;
  53.             }
  54.         wiWave.dwNextWriteOffset = 0;
  55.         fRefillLostBuffer = TRUE;
  56.         }
  57.  
  58.     /* Get and print the current position of the play cursor */
  59.     wiWave.lpDSBStreamBuffer->lpVtbl->GetCurrentPosition( 
  60.                     wiWave.lpDSBStreamBuffer, &dwPlay, &dwWrite );
  61.     
  62.     /* If the play cursor is at the same spot as the last call, there are two
  63.      * possibilities.  The first is that we were called extremely late and
  64.      * happened to land on an integer number of complete buffer cycles.  This
  65.      * is not very likely.  The other is that the play cursor didn't move.
  66.      * Since we're oversampling, this is very likely.  In this case, we should
  67.      * bail.
  68.      */
  69.  
  70.     if( dwPlay == wiWave.dwNextWriteOffset && !fRefillLostBuffer )
  71.         {
  72. #ifdef DEBUG
  73.         PostMessage( hWndMain, WM_DSSTREAM_DEBUG,
  74.                 MAKEWPARAM( DEBUGF_SKIP, 0 ), 0 );
  75. #endif
  76.         InterlockedExchange(&lInTimer, FALSE);
  77.         return;
  78.         }
  79.  
  80. #ifdef DEBUG
  81.     PostMessage( hWndMain, WM_DSSTREAM_DEBUG,
  82.                 MAKEWPARAM( DEBUGF_PLAYPOSITION, 0 ), dwPlay );
  83. #endif
  84.  
  85. #ifdef DEBUG
  86.     PostMessage( hWndMain, WM_DSSTREAM_DEBUG,
  87.                     MAKEWPARAM( DEBUGF_WRITEPOSITION, 0 ),
  88.                     wiWave.dwNextWriteOffset );
  89. #endif
  90.  
  91.     /* Have we found the end of the file and passed the buffer end? */
  92.     if( wiWave.bFoundEnd && !wiWave.dwBytesRemaining )
  93.         {
  94.         if( !wiWave.bDonePlaying )
  95.             {
  96.             wiWave.bDonePlaying = TRUE;
  97.             PostMessage( hWndMain, WM_DSSTREAM_DONE, (WPARAM)0, (LPARAM)0 );
  98.             }
  99.         InterlockedExchange(&lInTimer, FALSE);
  100.         return;
  101.         }
  102.  
  103.     if( dwPlay < wiWave.dwNextWriteOffset )
  104.         {
  105.         /* Calculate how many writeable bytes there are behind the play cursor */
  106.         dwPlayedLength = (dwPlay + wiWave.dwBufferSize - wiWave.dwNextWriteOffset);
  107.         }
  108.     else
  109.         {
  110.         /* Calculate how many writeable bytes there are behind the play cursor */
  111.         dwPlayedLength = (dwPlay - wiWave.dwNextWriteOffset);
  112.         }
  113.  
  114.     // If the buffer was lost, then we need to start filling data at the start of
  115.     //   the buffer, but we can decrease startup latency by only filling a segment
  116.     //   or two this time around.
  117.     if( fRefillLostBuffer )
  118.         dwWriteLength = 2 * wiWave.dwBufferSize / NUM_BUFFER_SEGMENTS;
  119.     else
  120.         dwWriteLength = dwPlayedLength;
  121.  
  122.     wiWave.dwProgress += dwPlayedLength;
  123.  
  124.     PostMessage( hWndMain, WM_DSSTREAM_PROGRESS, 0L, wiWave.dwProgress );
  125.  
  126.  
  127.     /*
  128.      *  If wiWave.bFoundEnd == TRUE, then we've finished reading in the file,
  129.      * but we need to wait until the buffer's play cursor passes the point we
  130.      * were at when we found out we were done reading.
  131.      */
  132.     if( wiWave.bFoundEnd && wiWave.dwBytesRemaining )
  133.         {
  134.         // Decrement the count of how many bytes we have to wait for before
  135.         // we can kill the timer procedure safely
  136.         if( dwPlayedLength > wiWave.dwBytesRemaining )
  137.             wiWave.dwBytesRemaining = 0;
  138.         else
  139.             wiWave.dwBytesRemaining -= dwPlayedLength;
  140.  
  141.         if( wiWave.lpDSBStreamBuffer->lpVtbl->Lock( wiWave.lpDSBStreamBuffer,
  142.                                                 wiWave.dwNextWriteOffset,
  143.                                                 dwWriteLength,
  144.                                                 &((LPVOID)lpWrite1), &dwLen1,
  145.                                                 &((LPVOID)lpWrite2), &dwLen2,
  146.                                                 0 ) != 0 )
  147.             {
  148.             OutputDebugString( "TimeFunc() could not lock DirectSoundBuffer" );
  149.             InterlockedExchange(&lInTimer, FALSE);
  150.             return;
  151.             }
  152.  
  153.         /* Silence out both parts of the locked buffer */
  154.         memset( lpWrite1, wiWave.pwfx->wBitsPerSample == 8 ? 128 : 0, dwLen1 );
  155.  
  156.         if( lpWrite2 && dwLen2 )
  157.             memset( lpWrite2,
  158.                     wiWave.pwfx->wBitsPerSample == 8 ? 128 : 0,
  159.                     dwLen2 );
  160.  
  161.         wiWave.lpDSBStreamBuffer->lpVtbl->Unlock( wiWave.lpDSBStreamBuffer,
  162.                                                     (LPVOID)lpWrite1, dwLen1,
  163.                                                     (LPVOID)lpWrite2, dwLen2 );
  164.     /*
  165.      * This code is stolen from the end of the routine -- we need to keep
  166.      * zeroing out buffer segments while we're waiting for the play cursor to
  167.      * catch up to the end of the WAVE data.
  168.      */
  169.         wiWave.dwNextWriteOffset += dwWriteLength;
  170.         if( wiWave.dwNextWriteOffset >= wiWave.dwBufferSize )
  171.             wiWave.dwNextWriteOffset -= wiWave.dwBufferSize;
  172.  
  173. #ifdef DEBUG
  174.     PostMessage( hWndMain, WM_DSSTREAM_DEBUG,
  175.                     MAKEWPARAM( DEBUGF_NEXTWRITE, 0 ),
  176.                     wiWave.dwNextWriteOffset );
  177. #endif
  178.         InterlockedExchange(&lInTimer, FALSE);
  179.         return;
  180.         }
  181.  
  182.     /* Lock a segment of memory that is behind the play cursor */
  183.     if( wiWave.lpDSBStreamBuffer->lpVtbl->Lock( wiWave.lpDSBStreamBuffer,
  184.                                             wiWave.dwNextWriteOffset,
  185.                                             dwWriteLength,
  186.                                             &((LPVOID)lpWrite1), &dwLen1,
  187.                                             &((LPVOID)lpWrite2), &dwLen2,
  188.                                             0 ) != 0 )
  189.         {
  190.         OutputDebugString( "TimeFunc() could not lock DirectSoundBuffer" );
  191.         InterlockedExchange(&lInTimer, FALSE);
  192.         return;
  193.         }
  194.         
  195.     if( dwLen1 && !wiWave.bDonePlaying )
  196.         {
  197.         nChkErr = WaveReadFile( wiWave.hmmio, (UINT)dwLen1, lpWrite1,
  198.                                 &wiWave.mmck, &uChkErr );
  199.         if( uChkErr < (UINT)dwLen1 )
  200.             {
  201.             if( !wiWave.bLoopFile )
  202.                 {
  203.                 /* Zero out the rest of this block */
  204.                 if( wiWave.pwfx->wBitsPerSample == 8 )
  205.                     memset( lpWrite1+uChkErr, 128, ((UINT)dwLen1-uChkErr));
  206.                 else if( wiWave.pwfx->wBitsPerSample == 16 )
  207.                     memset( lpWrite1+uChkErr, 0, ((UINT)dwLen1-uChkErr));
  208.  
  209. /* Enable play completion detection code at the beginning of the next call */
  210.  
  211.                 wiWave.bFoundEnd = TRUE;
  212.                 if( dwPlay > wiWave.dwNextWriteOffset )
  213.                     wiWave.dwBytesRemaining = (wiWave.dwNextWriteOffset
  214.                                             + wiWave.dwBufferSize - dwPlay);
  215.                 else
  216.                     wiWave.dwBytesRemaining = (wiWave.dwNextWriteOffset
  217.                                             - dwPlay);
  218.                 }
  219.              else
  220.                 {
  221.                 lpTemp = lpWrite1;
  222.                 dwLeftToRead = dwLen1;
  223.                 do
  224.                     {
  225.                     /* Continue decrementing our count and moving our temp
  226.                      * pointer forward until we've read the file enough times
  227.                      * to fill the buffer.  NOTE: It's probably not efficient
  228.                      * to bother with the overhead of streaming a file that's
  229.                      * not at least as large as the buffer... */
  230.                     lpTemp += uChkErr;
  231.                     dwLeftToRead -= uChkErr;
  232.                     nChkErr = WaveStartDataRead( &wiWave.hmmio,
  233.                                                     &wiWave.mmck,
  234.                                                     &wiWave.mmckInRIFF );
  235.                     nChkErr = WaveReadFile( wiWave.hmmio, (UINT)dwLeftToRead,
  236.                                             lpTemp,
  237.                                             &wiWave.mmck, &uChkErr );
  238.                     } while( uChkErr < dwLeftToRead );
  239.                 }
  240.             }
  241.         }
  242.     /*
  243.     * The bDonePlaying flag is set by the caller if the user stops playback
  244.     * before the end of the WAVE file is encountered.  It tells us to cut this
  245.     * racket out and play nothing in case it takes the caller a couple
  246.     * interrupts to shut off the timer.
  247.     */
  248.     else if( dwLen1 && wiWave.bDonePlaying )
  249.         {
  250.         // Set the appropriate silence value
  251.         _fmemset( lpWrite1,
  252.                     wiWave.pwfx->wBitsPerSample == 8 ? 128 : 0,
  253.                     dwLen1);
  254.         }
  255.  
  256.     if( dwLen2 && !wiWave.bDonePlaying )
  257.         {
  258.         nChkErr = WaveReadFile( wiWave.hmmio, (UINT)dwLen2, lpWrite2,
  259.                                 &wiWave.mmck, &uChkErr );
  260.         if( uChkErr < (UINT)dwLen2 )
  261.             {
  262.             if( !wiWave.bLoopFile )
  263.                 {
  264.                 /* Zero out the rest of this block */
  265.                 if( wiWave.pwfx->wBitsPerSample == 8 )
  266.                     memset( lpWrite2+uChkErr, 128, ((UINT)dwLen2-uChkErr));
  267.                 else if( wiWave.pwfx->wBitsPerSample == 16 )
  268.                     memset( lpWrite2+uChkErr, 0, ((UINT)dwLen2-uChkErr));
  269.                 /* Enable play completion detection code at the beginning
  270.                  * of the next call
  271.                  */
  272.                 wiWave.bFoundEnd = TRUE;
  273.                 if( dwPlay > wiWave.dwNextWriteOffset )
  274.                     wiWave.dwBytesRemaining = (wiWave.dwNextWriteOffset
  275.                                             + wiWave.dwBufferSize - dwPlay);
  276.                 else
  277.                     wiWave.dwBytesRemaining = (wiWave.dwNextWriteOffset
  278.                                             - dwPlay);
  279.                 }
  280.             else
  281.                 {
  282.                 lpTemp = lpWrite2;
  283.                 dwLeftToRead = dwLen2;
  284.                 do
  285.                     {
  286.                     /* Continue decrementing our count and moving our temp
  287.                      * pointer forward until we've read the file enough times
  288.                      * to fill the buffer.  NOTE: It's probably not efficient
  289.                      * to bother with the overhead of streaming a file that's
  290.                      * not at least as large as the buffer... */
  291.                     lpTemp += uChkErr;
  292.                     dwLeftToRead -= uChkErr;
  293.                     nChkErr = WaveStartDataRead( &wiWave.hmmio,
  294.                                                     &wiWave.mmck,
  295.                                                     &wiWave.mmckInRIFF );
  296.                     nChkErr = WaveReadFile( wiWave.hmmio, (UINT)dwLeftToRead,
  297.                                             lpTemp,
  298.                                             &wiWave.mmck, &uChkErr );
  299.                     } while( uChkErr < dwLeftToRead );
  300.                 }
  301.             }
  302.         }
  303.     else if( lpWrite2 && dwLen2 && wiWave.bDonePlaying )
  304.         {
  305.         // Set the appropriate silence value
  306.         _fmemset( lpWrite2,
  307.                     wiWave.pwfx->wBitsPerSample == 8 ? 128 : 0,
  308.                     dwLen2 );
  309.         }
  310.  
  311.     wiWave.lpDSBStreamBuffer->lpVtbl->Unlock( wiWave.lpDSBStreamBuffer,
  312.                                                 (LPVOID)lpWrite1, dwLen1,
  313.                                                 (LPVOID)lpWrite2, dwLen2 );
  314.  
  315.     wiWave.dwNextWriteOffset += dwWriteLength;
  316.     if( wiWave.dwNextWriteOffset >= wiWave.dwBufferSize )
  317.         wiWave.dwNextWriteOffset -= wiWave.dwBufferSize;
  318.  
  319. #ifdef DEBUG
  320.     PostMessage( hWndMain, WM_DSSTREAM_DEBUG,
  321.                     MAKEWPARAM( DEBUGF_NEXTWRITE, 0 ),
  322.                     wiWave.dwNextWriteOffset );
  323. #endif
  324.     if( fRefillLostBuffer )
  325.         IDirectSoundBuffer_Play( wiWave.lpDSBStreamBuffer, 0, 0, DSBPLAY_LOOPING );
  326.     InterlockedExchange(&lInTimer, FALSE);
  327.     return;
  328.     }
  329.