|
- /////////////////////////////////////////////////////////////////////////////
- // Copyright (C) 1998 by Jörg König
- // All rights reserved
- //
- // This file is part of the completely free tetris clone "CGTetris".
- //
- // This is free software.
- // You may redistribute it by any means providing it is not sold for profit
- // without the authors written consent.
- //
- // No warrantee of any kind, expressed or implied, is included with this
- // software; use at your own risk, responsibility for damages (if any) to
- // anyone resulting from the use of this software rests entirely with the
- // user.
- //
- // Send bug reports, bug fixes, enhancements, requests, flames, etc., and
- // I'll try to keep a version up to date. I can be reached as follows:
- // J.Koenig@adg.de (company site)
- // Joerg.Koenig@rhein-neckar.de (private site)
- /////////////////////////////////////////////////////////////////////////////
-
-
- // DirectSound.cpp: implementation of the CDirectSound class.
- //
- //////////////////////////////////////////////////////////////////////
-
- #include "stdafx.h"
- #include "DirectSound.h"
-
- // The following macro is defined since DirectX 5, but will work with
- // older versions too.
- #ifndef DSBLOCK_ENTIREBUFFER
- #define DSBLOCK_ENTIREBUFFER 0x00000002
- #endif
-
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[]=__FILE__;
- #define new DEBUG_NEW
- #endif
-
- static void DSError( HRESULT hRes ) {
- switch(hRes) {
- case DS_OK: TRACE0("NO ERROR\n"); break;
- case DSERR_ALLOCATED: TRACE0("ALLOCATED\n"); break;
- case DSERR_INVALIDPARAM: TRACE0("INVALIDPARAM\n"); break;
- case DSERR_OUTOFMEMORY: TRACE0("OUTOFMEMORY\n"); break;
- case DSERR_UNSUPPORTED: TRACE0("UNSUPPORTED\n"); break;
- case DSERR_NOAGGREGATION: TRACE0("NOAGGREGATION\n"); break;
- case DSERR_UNINITIALIZED: TRACE0("UNINITIALIZED\n"); break;
- case DSERR_BADFORMAT: TRACE0("BADFORMAT\n"); break;
- case DSERR_ALREADYINITIALIZED: TRACE0("ALREADYINITIALIZED\n"); break;
- case DSERR_BUFFERLOST: TRACE0("BUFFERLOST\n"); break;
- case DSERR_CONTROLUNAVAIL: TRACE0("CONTROLUNAVAIL\n"); break;
- case DSERR_GENERIC: TRACE0("GENERIC\n"); break;
- case DSERR_INVALIDCALL: TRACE0("INVALIDCALL\n"); break;
- case DSERR_OTHERAPPHASPRIO: TRACE0("OTHERAPPHASPRIO\n"); break;
- case DSERR_PRIOLEVELNEEDED: TRACE0("PRIOLEVELNEEDED\n"); break;
- default: TRACE1("%lu\n",hRes);break;
- }
- }
-
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
-
- LPDIRECTSOUND CDirectSound::m_lpDirectSound;
- DWORD CDirectSound::m_dwInstances;
-
-
- CDirectSound::CDirectSound()
- {
- m_lpDirectSound = 0;
- m_pDsb = 0;
- m_pTheSound = 0;
- m_dwTheSound = 0;
- m_bEnabled = TRUE;
-
- ++m_dwInstances;
- }
-
- CDirectSound::~CDirectSound()
- {
- if( m_pDsb )
- m_pDsb->Release();
-
- if( !--m_dwInstances && m_lpDirectSound ) {
- m_lpDirectSound->Release();
- m_lpDirectSound = 0;
- }
- }
-
- BOOL CDirectSound::Create(LPCTSTR pszResource, CWnd * pWnd)
- {
- //////////////////////////////////////////////////////////////////
- // load resource
- HINSTANCE hApp = ::GetModuleHandle(0);
- ASSERT(hApp);
-
- HRSRC hResInfo = ::FindResource(hApp, pszResource, TEXT("WAVE"));
- if(hResInfo == 0)
- return FALSE;
-
- HGLOBAL hRes = ::LoadResource(hApp, hResInfo);
- if(hRes == 0)
- return FALSE;
-
- LPVOID pTheSound = ::LockResource(hRes);
- if(pTheSound == 0)
- return FALSE;
-
- return Create(pTheSound, pWnd);
- }
-
-
- BOOL CDirectSound :: Create(LPVOID pSoundData, CWnd * pWnd) {
- if(pWnd == 0)
- pWnd = AfxGetApp()->GetMainWnd();
-
- ASSERT(pWnd != 0);
- ASSERT(::IsWindow(pWnd->GetSafeHwnd()));
-
- ASSERT(pSoundData != 0);
-
- //////////////////////////////////////////////////////////////////
- // create direct sound object
-
- if( m_lpDirectSound == 0 ) {
- // Someone might use sounds for starting apps. This may cause
- // DirectSoundCreate() to fail because the driver is used by
- // anyone else. So wait a little before starting with the work ...
- HRESULT hRes = DS_OK;
- short nRes = 0;
-
- do {
- if( nRes )
- ::Sleep(500);
- hRes = ::DirectSoundCreate(0, &m_lpDirectSound, 0);
- ++nRes;
- } while( nRes < 10 && (hRes == DSERR_ALLOCATED || hRes == DSERR_NODRIVER) );
-
- if( hRes != DS_OK )
- return FALSE;
-
- m_lpDirectSound->SetCooperativeLevel(pWnd->GetSafeHwnd(), DSSCL_NORMAL);
- }
-
- ASSERT(m_lpDirectSound != 0);
-
- WAVEFORMATEX * pcmwf;
- if( ! GetWaveData(pSoundData, pcmwf, m_pTheSound, m_dwTheSound) ||
- ! CreateSoundBuffer(pcmwf) ||
- ! SetSoundData(m_pTheSound, m_dwTheSound) )
- return FALSE;
-
- return TRUE;
- }
-
-
- BOOL CDirectSound :: GetWaveData(void * pRes, WAVEFORMATEX * & pWaveHeader, void * & pbWaveData, DWORD & cbWaveSize) {
- pWaveHeader = 0;
- pbWaveData = 0;
- cbWaveSize = 0;
-
- DWORD * pdw = (DWORD *)pRes;
- DWORD dwRiff = *pdw++;
- DWORD dwLength = *pdw++;
- DWORD dwType = *pdw++;
-
- if( dwRiff != mmioFOURCC('R', 'I', 'F', 'F') )
- return FALSE; // not even RIFF
-
- if( dwType != mmioFOURCC('W', 'A', 'V', 'E') )
- return FALSE; // not a WAV
-
- DWORD * pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
-
- while( pdw < pdwEnd ) {
- dwType = *pdw++;
- dwLength = *pdw++;
-
- switch( dwType ) {
- case mmioFOURCC('f', 'm', 't', ' '):
- if( !pWaveHeader ) {
- if( dwLength < sizeof(WAVEFORMAT) )
- return FALSE; // not a WAV
-
- pWaveHeader = (WAVEFORMATEX *)pdw;
-
- if( pbWaveData && cbWaveSize )
- return TRUE;
- }
- break;
-
- case mmioFOURCC('d', 'a', 't', 'a'):
- pbWaveData = LPVOID(pdw);
- cbWaveSize = dwLength;
-
- if( pWaveHeader )
- return TRUE;
- break;
- }
- pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
- }
-
- return FALSE;
- }
-
-
- BOOL CDirectSound::CreateSoundBuffer(WAVEFORMATEX * pcmwf)
- {
- DSBUFFERDESC dsbdesc;
-
- // Set up DSBUFFERDESC structure.
- memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
- dsbdesc.dwSize = sizeof(DSBUFFERDESC);
- // Need no controls (pan, volume, frequency).
- dsbdesc.dwFlags = DSBCAPS_STATIC; // assumes that the sound is played often
- dsbdesc.dwBufferBytes = m_dwTheSound;
- dsbdesc.lpwfxFormat = pcmwf; // Create buffer.
- HRESULT hRes;
- if( DS_OK != (hRes = m_lpDirectSound->CreateSoundBuffer(&dsbdesc, &m_pDsb, 0)) ) {
- // Failed.
- DSError(hRes);
- m_pDsb = 0;
- return FALSE;
- }
-
- return TRUE;
- }
-
-
- BOOL CDirectSound::SetSoundData(void * pSoundData, DWORD dwSoundSize) {
- LPVOID lpvPtr1;
- DWORD dwBytes1;
- // Obtain write pointer.
- HRESULT hr = m_pDsb->Lock(0, 0, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);
- // If DSERR_BUFFERLOST is returned, restore and retry lock.
- if(DSERR_BUFFERLOST == hr) {
- m_pDsb->Restore();
- hr = m_pDsb->Lock(0, 0, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);
- }
- if(DS_OK == hr) {
- // Write to pointers.
- ::CopyMemory(lpvPtr1, pSoundData, dwBytes1);
- // Release the data back to DirectSound.
- hr = m_pDsb->Unlock(lpvPtr1, dwBytes1, 0, 0);
- if(DS_OK == hr)
- return TRUE;
- }
- // Lock, Unlock, or Restore failed.
- return FALSE;
- }
-
- void CDirectSound::Play(DWORD dwStartPosition, BOOL bLoop)
- {
- if( ! IsValid() || ! IsEnabled() )
- return; // no chance to play the sound ...
-
- if( dwStartPosition > m_dwTheSound )
- dwStartPosition = m_dwTheSound;
- m_pDsb->SetCurrentPosition(dwStartPosition);
- if( DSERR_BUFFERLOST == m_pDsb->Play(0, 0, bLoop ? DSBPLAY_LOOPING : 0) ) {
- // another application had stolen our buffer
- // Note that a "Restore()" is not enough, because
- // the sound data is invalid after Restore().
- SetSoundData(m_pTheSound, m_dwTheSound);
-
- // Try playing again
- m_pDsb->Play(0, 0, bLoop ? DSBPLAY_LOOPING : 0);
- }
- }
-
- void CDirectSound::Stop()
- {
- if( IsValid() )
- m_pDsb->Stop();
- }
-
- void CDirectSound::Pause()
- {
- Stop();
- }
-
- void CDirectSound::Continue()
- {
- if( IsValid() ) {
- DWORD dwPlayCursor, dwWriteCursor;
- m_pDsb->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor);
- Play(dwPlayCursor);
- }
- }
-
- BOOL CDirectSound::IsValid() const
- {
- return (m_lpDirectSound && m_pDsb && m_pTheSound && m_dwTheSound) ? TRUE : FALSE;
- }
|