home *** CD-ROM | disk | FTP | other *** search
- //////////////////////////////////////////////////////////////////////////////////
- // CDS_Stream Implementation
- //////////////////////////////////////////////////////////////////////////////////
- #include "CDS.h"
-
- //////////////////////////////////////////////////////////////////////////////////
- // Constructor
- //////////////////////////////////////////////////////////////////////////////////
- CDS_Stream::CDS_Stream(void)
- {
- // Initialize data members
- m_pass = NULL;
- m_pwavefile = NULL;
- m_pdsb = NULL;
- m_ptimer = NULL;
- m_fPlaying = m_fCued = FALSE;
- m_lInService = FALSE;
- m_cbBufOffset = 0;
- m_nBufLength = 2000;
- m_cbBufSize = 0;
- m_nBufService = 250;
- m_nDuration = 0;
- m_nTimeStarted = 0;
- m_nTimeElapsed = 0;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Destructor
- //////////////////////////////////////////////////////////////////////////////////
- CDS_Stream::~CDS_Stream(void)
- {
- Destroy();
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Create
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::Create(CDS_Sound* pass, LPSTR pszFilename)
- {
- BOOL fRtn = TRUE;
-
- // Pass points to CDXSound object
- m_pass = pass;
-
- if(pszFilename && m_pass)
- {
- // Create a new CWaveFile object
- if(m_pwavefile = new CDS_WaveFile)
- {
- // Open given file
- if(m_pwavefile->Open(pszFilename))
- {
- // Calculate sound buffer size in bytes
- m_cbBufSize = (m_pwavefile->GetAvgDataRate() * m_nBufLength) / 1000;
- m_cbBufSize = (m_cbBufSize > m_pwavefile->GetDataSize()) ? m_pwavefile->GetDataSize() : m_cbBufSize;
-
- // Get duration of sound
- m_nDuration = m_pwavefile->GetDuration();
-
- // Create sound buffer
- HRESULT hr;
- memset(&m_dsbd, 0, sizeof (DSBUFFERDESC));
- m_dsbd.dwSize = sizeof (DSBUFFERDESC);
- m_dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
- m_dsbd.dwBufferBytes = m_cbBufSize;
- m_dsbd.lpwfxFormat = m_pwavefile->m_pFormat;
-
- hr = m_pass->GetDS()->CreateSoundBuffer(&m_dsbd, &m_pdsb, NULL);
- if(hr == DS_OK)
- {
- // Cue for playback
- Cue();
- }
- else fRtn = FALSE;
- }
- else
- {
- // Error opening file
- delete m_pwavefile;
- m_pwavefile = NULL;
- fRtn = FALSE;
- }
- }
- else fRtn = FALSE;
- }
- else fRtn = FALSE;
-
- return fRtn;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Destroy
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::Destroy(void)
- {
- BOOL fRtn = TRUE;
-
- // Stop playback
- Stop();
-
- // Release DirectSound buffer
- SAFE_RELEASE(m_pdsb);
-
- // Delete CWaveFile object
- if(m_pwavefile)
- {
- delete(m_pwavefile);
- m_pwavefile = NULL;
- }
-
- return fRtn;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // WriteWaveData
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::WriteWaveData(UINT size)
- {
- HRESULT hr;
- LPBYTE lpbuf1 = NULL;
- LPBYTE lpbuf2 = NULL;
- DWORD dwsize1 = 0;
- DWORD dwsize2 = 0;
- DWORD dwbyteswritten1 = 0;
- DWORD dwbyteswritten2 = 0;
- BOOL fRtn = TRUE;
-
- // Lock the sound buffer
- hr = m_pdsb->Lock(m_cbBufOffset, size, (LPVOID*)&lpbuf1, &dwsize1, (LPVOID*)&lpbuf2, &dwsize2, 0);
- if(hr == DS_OK)
- {
- // Write data to sound buffer
- if((dwbyteswritten1 = m_pwavefile->Read(lpbuf1, dwsize1)) == dwsize1)
- {
- // Second write required?
- if(lpbuf2)
- {
- if((dwbyteswritten2 = m_pwavefile->Read(lpbuf2, dwsize2)) == dwsize2)
- {
- // Both write operations successful!
- }
- else fRtn = FALSE;
- }
- }
- else fRtn = FALSE;
-
- // Update our buffer offset and unlock sound buffer
- m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
- m_pdsb->Unlock (lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
- }
- else fRtn = FALSE;
-
- return fRtn;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // WriteSilence
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::WriteSilence(UINT size)
- {
- HRESULT hr;
- LPBYTE lpbuf1 = NULL;
- LPBYTE lpbuf2 = NULL;
- DWORD dwsize1 = 0;
- DWORD dwsize2 = 0;
- DWORD dwbyteswritten1 = 0;
- DWORD dwbyteswritten2 = 0;
- BOOL fRtn = TRUE;
-
- // Lock the sound buffer
- hr = m_pdsb->Lock(m_cbBufOffset, size, (LPVOID*)&lpbuf1, &dwsize1, (LPVOID*)&lpbuf2, &dwsize2, 0);
- if(hr == DS_OK)
- {
- BYTE bSilence = m_pwavefile->GetSilenceData();
-
- // Write silence to sound buffer
- memset (lpbuf1, bSilence, dwsize1);
- dwbyteswritten1 = dwsize1;
-
- // Second write required?
- if(lpbuf2)
- {
- memset(lpbuf1, bSilence, dwsize1);
- dwbyteswritten2 = dwsize2;
- }
-
- // Update our buffer offset and unlock sound buffer
- m_cbBufOffset = (m_cbBufOffset + dwbyteswritten1 + dwbyteswritten2) % m_cbBufSize;
- m_pdsb->Unlock(lpbuf1, dwbyteswritten1, lpbuf2, dwbyteswritten2);
- }
- else fRtn = FALSE;
-
- return fRtn;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // GetMaxWriteSize
- //////////////////////////////////////////////////////////////////////////////////
- DWORD CDS_Stream::GetMaxWriteSize(void)
- {
- DWORD dwWriteCursor, dwPlayCursor, dwMaxSize;
-
- // Get current play position
- if(m_pdsb->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor) == DS_OK)
- {
- if(m_cbBufOffset <= dwPlayCursor)
- {
- // Our write position trails play cursor
- dwMaxSize = dwPlayCursor - m_cbBufOffset;
- }
- else
- {
- // Play cursor has wrapped
- dwMaxSize = m_cbBufSize - m_cbBufOffset + dwPlayCursor;
- }
- }
- else
- {
- // GetCurrentPosition call failed
- dwMaxSize = 0;
- }
-
- return dwMaxSize;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Service Buffer
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::ServiceBuffer(void)
- {
- BOOL fRtn = TRUE;
-
- // Check for reentrance
- if(InterlockedExchange(&m_lInService, TRUE) == FALSE)
- {
- // Maintain elapsed time count
- m_nTimeElapsed = timeGetTime() - m_nTimeStarted;
-
- // Stop if all of sound has played
- if(m_nTimeElapsed < m_nDuration)
- {
- // All of sound not played yet, send more data to buffer
- DWORD dwFreeSpace = GetMaxWriteSize();
-
- // Determine free space in sound buffer
- if(dwFreeSpace)
- {
- // See how much wave data remains to be sent to buffer
- DWORD dwDataRemaining = m_pwavefile->GetNumBytesRemaining();
- if(dwDataRemaining == 0)
- {
- // All wave data has been sent to buffer
- if(WriteSilence(dwFreeSpace) == FALSE)
- {
- // Error writing silence data
- fRtn = FALSE;
- }
- }
- else if(dwDataRemaining >= dwFreeSpace)
- {
- // Enough wave data remains to fill free space in buffer
- if(WriteWaveData(dwFreeSpace) == FALSE)
- {
- // Error writing wave data
- fRtn = FALSE;
- }
- }
- else
- {
- // Some wave data remains, but not enough to fill free space
- if(WriteWaveData(dwDataRemaining) == TRUE)
- {
- if(WriteSilence(dwFreeSpace - dwDataRemaining) == FALSE)
- {
- // Error writing silence data
- fRtn = FALSE;
- }
- }
- else
- {
- // Error writing wave data
- fRtn = FALSE;
- }
- }
- }
- else
- {
- // No free space in buffer for some reason
- fRtn = FALSE;
- }
- }
- else
- {
- // All of sound has played
- Stop();
- }
-
- // Reset reentrancy semaphore
- InterlockedExchange(&m_lInService, FALSE);
- }
- else
- {
- // Service routine reentered. Do nothing
- fRtn = FALSE;
- }
-
- return fRtn;
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Cue
- //////////////////////////////////////////////////////////////////////////////////
- void CDS_Stream::Cue(void)
- {
- if(!m_fCued)
- {
- // Reset buffer ptr
- m_cbBufOffset = 0;
-
- // Reset file ptr
- m_pwavefile->Cue();
-
- // Reset DirectSound buffer
- m_pdsb->SetCurrentPosition(0);
-
- // Fill buffer with wave data
- WriteWaveData(m_cbBufSize);
-
- m_fCued = TRUE;
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Play
- //////////////////////////////////////////////////////////////////////////////////
- void CDS_Stream::Play(void)
- {
- if(m_pdsb)
- {
- // Stop if playing
- if(m_fPlaying) Stop ();
-
- // Cue for playback if necessary
- if(!m_fCued) Cue ();
-
- // Begin DirectSound playback
- HRESULT hr = m_pdsb->Play(0, 0, DSBPLAY_LOOPING);
- if(hr == DS_OK)
- {
- m_nTimeStarted = timeGetTime();
-
- // Kick off timer to service buffer
- m_ptimer = new CDS_Timer;
- if(m_ptimer)
- {
- m_ptimer->Create(m_nBufService, m_nBufService, (DWORD)(this), TimerCallback);
- }
-
- // Playback begun
- m_fPlaying = TRUE;
- m_fCued = FALSE;
- }
- }
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // TimerCallback
- //////////////////////////////////////////////////////////////////////////////////
- BOOL CDS_Stream::TimerCallback(DWORD dwUser)
- {
- // dwUser contains ptr to CDS_Stream object
- CDS_Stream* pas = (CDS_Stream*) dwUser;
-
- return pas->ServiceBuffer();
- }
-
- //////////////////////////////////////////////////////////////////////////////////
- // Stop
- //////////////////////////////////////////////////////////////////////////////////
- void CDS_Stream::Stop(void)
- {
- if(m_fPlaying)
- {
- // Stop DirectSound playback
- m_pdsb->Stop();
-
- // Delete Timer object
- delete(m_ptimer);
- m_ptimer = NULL;
- m_fPlaying = FALSE;
- }
- }
-