home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 27 / IOPROG_27.ISO / SOFT / CDX.ZIP / Src / Cds / Stream.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-14  |  9.6 KB  |  393 lines

  1. //////////////////////////////////////////////////////////////////////////////////
  2. // CDS_Stream Implementation
  3. //////////////////////////////////////////////////////////////////////////////////
  4. #include "CDS.h"
  5.  
  6. //////////////////////////////////////////////////////////////////////////////////
  7. // Constructor
  8. //////////////////////////////////////////////////////////////////////////////////
  9. CDS_Stream::CDS_Stream(void)
  10. {
  11.     // Initialize data members
  12.     m_pass = NULL;
  13.     m_pwavefile = NULL;
  14.     m_pdsb = NULL;
  15.     m_ptimer = NULL;
  16.     m_fPlaying = m_fCued = FALSE;
  17.     m_lInService = FALSE;
  18.     m_cbBufOffset = 0;
  19.     m_nBufLength = 2000;
  20.     m_cbBufSize = 0;
  21.     m_nBufService = 250;
  22.     m_nDuration = 0;
  23.     m_nTimeStarted = 0;
  24.     m_nTimeElapsed = 0;
  25. }
  26.  
  27. //////////////////////////////////////////////////////////////////////////////////
  28. // Destructor
  29. //////////////////////////////////////////////////////////////////////////////////
  30. CDS_Stream::~CDS_Stream(void)
  31. {
  32.     Destroy();
  33. }
  34.  
  35. //////////////////////////////////////////////////////////////////////////////////
  36. // Create
  37. //////////////////////////////////////////////////////////////////////////////////
  38. BOOL CDS_Stream::Create(CDS_Sound* pass, LPSTR pszFilename)
  39. {
  40.     BOOL fRtn = TRUE;
  41.  
  42.     // Pass points to CDXSound object
  43.     m_pass = pass;
  44.  
  45.     if(pszFilename && m_pass)
  46.     {
  47.         // Create a new CWaveFile object
  48.         if(m_pwavefile = new CDS_WaveFile)
  49.         {
  50.             // Open given file
  51.             if(m_pwavefile->Open(pszFilename))
  52.             {
  53.                 // Calculate sound buffer size in bytes
  54.                 m_cbBufSize = (m_pwavefile->GetAvgDataRate() * m_nBufLength) / 1000;
  55.                 m_cbBufSize = (m_cbBufSize > m_pwavefile->GetDataSize()) ? m_pwavefile->GetDataSize() : m_cbBufSize;
  56.  
  57.                 // Get duration of sound
  58.                 m_nDuration = m_pwavefile->GetDuration();
  59.  
  60.                 // Create sound buffer
  61.                 HRESULT hr;
  62.                 memset(&m_dsbd, 0, sizeof (DSBUFFERDESC));
  63.                 m_dsbd.dwSize = sizeof (DSBUFFERDESC);
  64.                 m_dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
  65.                 m_dsbd.dwBufferBytes = m_cbBufSize;
  66.                 m_dsbd.lpwfxFormat = m_pwavefile->m_pFormat;
  67.  
  68.                 hr = m_pass->GetDS()->CreateSoundBuffer(&m_dsbd, &m_pdsb, NULL);
  69.                 if(hr == DS_OK)
  70.                 {
  71.                     // Cue for playback
  72.                     Cue();
  73.                 }
  74.                 else fRtn = FALSE;
  75.             }
  76.             else
  77.             {
  78.                 // Error opening file
  79.                 delete m_pwavefile;
  80.                 m_pwavefile = NULL;
  81.                 fRtn = FALSE;
  82.             }
  83.         }
  84.         else fRtn = FALSE;
  85.     }
  86.     else fRtn = FALSE;
  87.  
  88.     return fRtn;
  89. }
  90.  
  91. //////////////////////////////////////////////////////////////////////////////////
  92. // Destroy
  93. //////////////////////////////////////////////////////////////////////////////////
  94. BOOL CDS_Stream::Destroy(void)
  95. {
  96.     BOOL fRtn = TRUE;
  97.  
  98.     // Stop playback
  99.     Stop();
  100.  
  101.     // Release DirectSound buffer
  102.     SAFE_RELEASE(m_pdsb);
  103.  
  104.     // Delete CWaveFile object
  105.     if(m_pwavefile)
  106.     {
  107.         delete(m_pwavefile);
  108.         m_pwavefile = NULL;
  109.     }
  110.  
  111.     return fRtn;
  112. }
  113.  
  114. //////////////////////////////////////////////////////////////////////////////////
  115. // WriteWaveData
  116. //////////////////////////////////////////////////////////////////////////////////
  117. BOOL CDS_Stream::WriteWaveData(UINT size)
  118. {
  119.     HRESULT hr;
  120.     LPBYTE lpbuf1 = NULL;
  121.     LPBYTE lpbuf2 = NULL;
  122.     DWORD dwsize1 = 0;
  123.     DWORD dwsize2 = 0;
  124.     DWORD dwbyteswritten1 = 0;
  125.     DWORD dwbyteswritten2 = 0;
  126.     BOOL fRtn = TRUE;
  127.  
  128.     // Lock the sound buffer
  129.     hr = m_pdsb->Lock(m_cbBufOffset, size, (LPVOID*)&lpbuf1, &dwsize1, (LPVOID*)&lpbuf2, &dwsize2, 0);
  130.     if(hr == DS_OK)
  131.     {
  132.         // Write data to sound buffer
  133.         if((dwbyteswritten1 = m_pwavefile->Read(lpbuf1, dwsize1)) == dwsize1)
  134.         {
  135.             // Second write required?
  136.             if(lpbuf2)
  137.             {
  138.                 if((dwbyteswritten2 = m_pwavefile->Read(lpbuf2, dwsize2)) == dwsize2)
  139.                 {
  140.                     // Both write operations successful!
  141.                 }
  142.                 else fRtn = FALSE;
  143.             }
  144.         }
  145.         else fRtn = FALSE;
  146.  
  147.         // Update our buffer offset and unlock sound buffer
  148.         m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
  149.         m_pdsb->Unlock (lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
  150.     }
  151.     else fRtn = FALSE;
  152.  
  153.     return fRtn;
  154. }
  155.  
  156. //////////////////////////////////////////////////////////////////////////////////
  157. // WriteSilence
  158. //////////////////////////////////////////////////////////////////////////////////
  159. BOOL CDS_Stream::WriteSilence(UINT size)
  160. {
  161.     HRESULT hr;
  162.     LPBYTE lpbuf1 = NULL;
  163.     LPBYTE lpbuf2 = NULL;
  164.     DWORD dwsize1 = 0;
  165.     DWORD dwsize2 = 0;
  166.     DWORD dwbyteswritten1 = 0;
  167.     DWORD dwbyteswritten2 = 0;
  168.     BOOL fRtn = TRUE;
  169.  
  170.     // Lock the sound buffer
  171.     hr = m_pdsb->Lock(m_cbBufOffset, size, (LPVOID*)&lpbuf1, &dwsize1, (LPVOID*)&lpbuf2, &dwsize2, 0);
  172.     if(hr == DS_OK)
  173.     {
  174.         BYTE bSilence = m_pwavefile->GetSilenceData();
  175.  
  176.         // Write silence to sound buffer
  177.         memset (lpbuf1, bSilence, dwsize1);
  178.         dwbyteswritten1 = dwsize1;
  179.  
  180.         // Second write required?
  181.         if(lpbuf2)
  182.         {
  183.             memset(lpbuf1, bSilence, dwsize1);
  184.             dwbyteswritten2 = dwsize2;
  185.         }
  186.  
  187.         // Update our buffer offset and unlock sound buffer
  188.         m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
  189.         m_pdsb->Unlock(lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
  190.     }
  191.     else fRtn = FALSE;
  192.  
  193.     return fRtn;
  194. }
  195.  
  196. //////////////////////////////////////////////////////////////////////////////////
  197. // GetMaxWriteSize
  198. //////////////////////////////////////////////////////////////////////////////////
  199. DWORD CDS_Stream::GetMaxWriteSize(void)
  200. {
  201.     DWORD dwWriteCursor, dwPlayCursor, dwMaxSize;
  202.  
  203.     // Get current play position
  204.     if(m_pdsb->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor) == DS_OK)
  205.     {
  206.         if(m_cbBufOffset <= dwPlayCursor)
  207.         {
  208.             // Our write position trails play cursor
  209.             dwMaxSize = dwPlayCursor - m_cbBufOffset;
  210.         }
  211.         else
  212.         {
  213.             // Play cursor has wrapped
  214.             dwMaxSize = m_cbBufSize - m_cbBufOffset + dwPlayCursor;
  215.         }
  216.     }
  217.     else
  218.     {
  219.         // GetCurrentPosition call failed
  220.         dwMaxSize = 0;
  221.     }
  222.  
  223.     return dwMaxSize;
  224. }
  225.  
  226. //////////////////////////////////////////////////////////////////////////////////
  227. // Service Buffer
  228. //////////////////////////////////////////////////////////////////////////////////
  229. BOOL CDS_Stream::ServiceBuffer(void)
  230. {
  231.     BOOL fRtn = TRUE;
  232.  
  233.     // Check for reentrance
  234.     if(InterlockedExchange(&m_lInService, TRUE) == FALSE)
  235.     {
  236.         // Maintain elapsed time count
  237.         m_nTimeElapsed = timeGetTime() - m_nTimeStarted;
  238.  
  239.         // Stop if all of sound has played
  240.         if(m_nTimeElapsed < m_nDuration)
  241.         {
  242.             // All of sound not played yet, send more data to buffer
  243.             DWORD dwFreeSpace = GetMaxWriteSize();
  244.  
  245.             // Determine free space in sound buffer
  246.             if(dwFreeSpace)
  247.             {
  248.                 // See how much wave data remains to be sent to buffer
  249.                 DWORD dwDataRemaining = m_pwavefile->GetNumBytesRemaining();
  250.                 if(dwDataRemaining == 0)
  251.                 {
  252.                     // All wave data has been sent to buffer
  253.                     if(WriteSilence(dwFreeSpace) == FALSE)
  254.                     {
  255.                         // Error writing silence data
  256.                         fRtn = FALSE;
  257.                     }
  258.                 }
  259.                 else if(dwDataRemaining >= dwFreeSpace)
  260.                 {
  261.                     // Enough wave data remains to fill free space in buffer
  262.                     if(WriteWaveData(dwFreeSpace) == FALSE)
  263.                     {
  264.                         // Error writing wave data
  265.                         fRtn = FALSE;
  266.                     }
  267.                 }
  268.                 else
  269.                 {
  270.                     // Some wave data remains, but not enough to fill free space
  271.                     if(WriteWaveData(dwDataRemaining) == TRUE)
  272.                     {
  273.                         if(WriteSilence(dwFreeSpace - dwDataRemaining) == FALSE)
  274.                         {
  275.                             // Error writing silence data
  276.                             fRtn = FALSE;
  277.                         }
  278.                     }
  279.                     else
  280.                     {
  281.                         // Error writing wave data
  282.                         fRtn = FALSE;
  283.                     }
  284.                 }
  285.             }
  286.             else
  287.             {
  288.                 // No free space in buffer for some reason
  289.                 fRtn = FALSE;
  290.             }
  291.         }
  292.         else
  293.         {
  294.             // All of sound has played
  295.             Stop();
  296.         }
  297.  
  298.         // Reset reentrancy semaphore
  299.         InterlockedExchange(&m_lInService, FALSE);
  300.     }
  301.     else
  302.     {
  303.         // Service routine reentered. Do nothing
  304.         fRtn = FALSE;
  305.     }
  306.  
  307.     return fRtn;
  308. }
  309.  
  310. //////////////////////////////////////////////////////////////////////////////////
  311. // Cue
  312. //////////////////////////////////////////////////////////////////////////////////
  313. void CDS_Stream::Cue(void)
  314. {
  315.     if(!m_fCued)
  316.     {
  317.         // Reset buffer ptr
  318.         m_cbBufOffset = 0;
  319.  
  320.         // Reset file ptr
  321.         m_pwavefile->Cue();
  322.  
  323.         // Reset DirectSound buffer
  324.         m_pdsb->SetCurrentPosition(0);
  325.  
  326.         // Fill buffer with wave data
  327.         WriteWaveData(m_cbBufSize);
  328.  
  329.         m_fCued = TRUE;
  330.     }
  331. }
  332.  
  333. //////////////////////////////////////////////////////////////////////////////////
  334. // Play
  335. //////////////////////////////////////////////////////////////////////////////////
  336. void CDS_Stream::Play(void)
  337. {
  338.     if(m_pdsb)
  339.     {
  340.         // Stop if playing
  341.         if(m_fPlaying) Stop ();
  342.  
  343.         // Cue for playback if necessary
  344.         if(!m_fCued) Cue ();
  345.  
  346.         // Begin DirectSound playback
  347.         HRESULT hr = m_pdsb->Play(0, 0, DSBPLAY_LOOPING);
  348.         if(hr == DS_OK)
  349.         {
  350.             m_nTimeStarted = timeGetTime();
  351.  
  352.             // Kick off timer to service buffer
  353.             m_ptimer = new CDS_Timer;
  354.             if(m_ptimer)
  355.             {
  356.                 m_ptimer->Create(m_nBufService, m_nBufService, (DWORD)(this), TimerCallback);
  357.             }
  358.  
  359.             // Playback begun
  360.             m_fPlaying = TRUE;
  361.             m_fCued = FALSE;
  362.         }
  363.     }
  364. }
  365.  
  366. //////////////////////////////////////////////////////////////////////////////////
  367. // TimerCallback
  368. //////////////////////////////////////////////////////////////////////////////////
  369. BOOL CDS_Stream::TimerCallback(DWORD dwUser)
  370. {
  371.     // dwUser contains ptr to CDS_Stream object
  372.     CDS_Stream* pas = (CDS_Stream*) dwUser;
  373.  
  374.     return pas->ServiceBuffer();
  375. }
  376.  
  377. //////////////////////////////////////////////////////////////////////////////////
  378. // Stop
  379. //////////////////////////////////////////////////////////////////////////////////
  380. void CDS_Stream::Stop(void)
  381. {
  382.     if(m_fPlaying)
  383.     {
  384.         // Stop DirectSound playback
  385.         m_pdsb->Stop();
  386.  
  387.         // Delete Timer object
  388.         delete(m_ptimer);
  389.         m_ptimer = NULL;
  390.         m_fPlaying = FALSE;
  391.     }
  392. }
  393.