一个vc++ direct sound播放wav文件的类
头文件
#if !defined(AFX_DIRECTSOUND_H__A20FE86F_118F_11D2_9AB3_0060B0CDC13E__INCLUDED_)
#define AFX_DIRECTSOUND_H__A20FE86F_118F_11D2_9AB3_0060B0CDC13E__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
#include
#include
#pragma message("linking with Microsoft's DirectSound library ...")
#pragma comment(lib, "dsound.lib")
class CDirectSound
{
public:
// 构造、析构函数
CDirectSound();
virtual ~CDirectSound();
//创建DirectSound对象
BOOL Create(LPCTSTR pszResource, CWnd * pWnd = 0);
BOOL Create(UINT uResourceID, CWnd * pWnd = 0) {
return Create(MAKEINTRESOURCE(uResourceID), pWnd);
}
BOOL Create(LPVOID pSoundData, CWnd * pWnd = 0);
public:
//操作函数
BOOL IsValid() const;
void Play(DWORD dwStartPosition = 0, BOOL bLoop = FALSE);
void Stop();
void Pause();
void Continue();
CDirectSound & EnableSound(BOOL bEnable = TRUE) {
m_bEnabled = bEnable;
if( ! bEnable )
Stop();
return * this;
}
BOOL IsEnabled() const { return m_bEnabled; }
protected:
//设置声音数据缓冲区
BOOL SetSoundData(LPVOID pSoundData, DWORD dwSoundSize);
//创建DirectSoundBuffer
BOOL CreateSoundBuffer(WAVEFORMATEX * pcmwf);
//获取Wave数据
BOOL GetWaveData(void * pRes, WAVEFORMATEX * & pWaveHeader, void * & pbWaveData, DWORD & cbWaveSize);
private:
//声音数据
LPVOID m_pTheSound;
//数据大小
DWORD m_dwTheSound;
//DirectSoundBuffer指针
LPDIRECTSOUNDBUFFER m_pDsb;
BOOL m_bEnabled;
//DirectSound对象
static LPDIRECTSOUND m_lpDirectSound;
static DWORD m_dwInstances;
};
#endif // !defined(AFX_DIRECTSOUND_H__A20FE86F_118F_11D2_9AB3_0060B0CDC13E__INCLUDED_)
类的主体
#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);
//创建DirectSound 对象
if( m_lpDirectSound == 0 )
{
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++;
//检验“RIFF”标志
if( dwRiff != mmioFOURCC('R', 'I', 'F', 'F') )
return FALSE;
//检验“WAVE”标志
if( dwType != mmioFOURCC('W', 'A', 'V', 'E') )
return FALSE;
//指向声音数据
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;
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;
//初始化DSBUFFERDESC structure.
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
// 不需要控制pan, volume, frequency
dsbdesc.dwFlags = DSBCAPS_STATIC;
dsbdesc.dwBufferBytes = m_dwTheSound;
dsbdesc.lpwfxFormat = pcmwf;
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;
// 获取一块内存
HRESULT hr = m_pDsb->Lock(0, 0, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);
//如果失败,重新分配
if(DSERR_BUFFERLOST == hr)
{
m_pDsb->Restore();
hr = m_pDsb->Lock(0, 0, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);
}
if(DS_OK == hr) {
// 复制声音数据
::CopyMemory(lpvPtr1, pSoundData, dwBytes1);
//释放锁定的内存块
hr = m_pDsb->Unlock(lpvPtr1, dwBytes1, 0, 0);
if(DS_OK == hr)
return TRUE;
}
return FALSE;
}
void CDirectSound::Play(DWORD dwStartPosition, BOOL bLoop)
{
if( ! IsValid() || ! IsEnabled() )
return;
//播放位置边界检验
if( dwStartPosition > m_dwTheSound )
dwStartPosition = m_dwTheSound;
//重新设置播放位置
m_pDsb->SetCurrentPosition(dwStartPosition);
//开始播放
if( DSERR_BUFFERLOST == m_pDsb->Play(0, 0, bLoop ? DSBPLAY_LOOPING : 0) ) {
SetSoundData(m_pTheSound, m_dwTheSound);
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;
}