|

楼主 |
发表于 2010-3-25 15:42:47
|
显示全部楼层
我们可以给DirectSound设置一个事件,并且设置buffer通知大小,如下:
HANDLE g_event[MAX_AUDIO_BUF];
for(int i =0; i< MAX_AUDIO_BUF;i++)
{
g_aPosNotify.dwOffset = i* BUFFERNOTIFYSIZE ;
g_aPosNotify.hEventNotify = g_event;
}
if(FAILED(hr = g_pDSBuffer8-> Q ueryInterface(IID_IDirectSoundNotify,(LPVOID *) &g_pDSNotify )))
return ;
g_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,g_aPosNotify);
g_pDSNotify->Release();
当DirectSound播放到buffer的1920,3840,5760,7680等位置时,Directsound就会通知应用程序,将g_ event,设置为通知态,应用程序就可以通过WaitForMultipleObjects 函数等待DirectSound的通知,将数据填充到DirectSoun的辅助缓冲区。
下面我给出Stream buffer 播放wave文件的代码。
#define MAX_AUDIO_BUF 4
#define BUFFERNOTIFYSIZE 1920
LPDIRECTSOUNDBUFFER8 g_pDSBuffer8 = NULL; //buffer
LPDIRECTSOUND8 g_pDsd = NULL; //dsound
CWaveFile *g_pWaveFile= NULL;
BOOL g_bPlaying = FALSE; //是否正在播放
LPDIRECTSOUNDNOTIFY8 g_pDSNotify = NULL;
DSBPOSITIONNOTIFY g_aPosNotify[MAX_AUDIO_BUF];//设置通知标志的数组
HANDLE g_event[MAX_AUDIO_BUF];
DWORD g_dwNextWriteOffset = 0;
//初始化DirectSound
HRESULT hr;
if(FAILED(hr = DirectSoundCreate8(NULL,&g_pDsd,NULL)))
return FALSE;
if(FAILED(hr = g_pDsd->SetCooperativeLevel(m_hWnd,DSSCL_PRIORITY)))
return FALSE;
g_pWaveFile = new CWaveFile;
g_pWaveFile->Open(_T("d:\\test.wav"),NULL,WAVEFILE_READ);
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY |DSBCAPS_GETCURRENTPOSITION2;
dsbd.dwBufferBytes = MAX_AUDIO_BUF * BUFFERNOTIFYSIZE ;
dsbd.lpwfxFormat = g_pWaveFile->m_pwfx;
LPDIRECTSOUNDBUFFER lpbuffer;
//创建DirectSound辅助缓冲区
if(FAILED(hr = g_pDsd->CreateSoundBuffer(&dsbd,&lpbuffer,NULL)))
return FALSE;
if( FAILED( hr = lpbuffer->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*) &g_pDSBuffer8) ) )
return FALSE;
lpbuffer->Release();
//设置DirectSound通知 机制
for(int i =0; i< MAX_AUDIO_BUF;i++)
{
g_aPosNotify.dwOffset = i* BUFFERNOTIFYSIZE ;
g_aPosNotify.hEventNotify = g_event;
}
if(FAILED(hr=g_pDSBuffer8->QueryInterface(IID_IDirectSoundNotify,(LPVOID*) g_pDSNotify )))
return ;
g_pDSNotify->SetNotificationPositions(MAX_AUDIO_BUF,g_aPosNotify);
g_pDSNotify->Release();
ok,在下面的play函数中,我们就要单独启动一个线程,来播放了
void OnBnClickedButtonPlay()
{
g_bPlaying =TRUE;
g_pWaveFile->ResetFile();
CreateThread(0,0,PlayThread,this,NULL,NULL);
}
//停止播放音频
void CDsoundEffectDemoDlg::OnBnClickedButtonStop()
{
// TODO: 在此添加控件通知处理程序代码
g_bPlaying =FALSE;
Sleep(500);
g_pDSBuffer8->Stop();
}
下面我们看看我们的播放线程,在线程里,我们首先将音频数据填充到DirectSound的辅助缓冲区中,然后调用DirectSound buffer 的play方法,开始播放,然后就在WaitForMultipleObjects 等待DirectSound的通知吧,然后读取wave文件将数据填充到DirectSound的空buffer中。
DWORD WINAPI PlayThread(LPVOID lpParame)
{
DWORD res;
LPVOID lplockbuf;
DWORD len;
DWORD dwWrite;
g_pDSBuffer8->Lock(0,0,&lplockbuf,&len,NULL,NULL,DSBLOCK_ENTIREBUFFER);
g_pWaveFile->Read((BYTE*)lplockbuf,len,&dwWrite);
g_pDSBuffer8->Unlock(lplockbuf,len,NULL,0);
g_pDSBuffer8->SetCurrentPosition(0);
g_pDSBuffer8->; Play(0,0,DSBPLAY_LOOPING);
g_dwNextWriteOffset = 0;
while(g_bPlaying)
{
res = WaitForMultipleObjects (MAX_AUDIO_BUF, g_event, FALSE, INFINITE);
if(res > WAIT_OBJECT_0)
ProcessBuffer();
}
return 0;
}
下面的函数主要是给空的DirectSound缓冲区填充 音频数据。
void ProcessBuffer()
{
DWORD dwBytesWrittenToBuffer = 0;
VOID* pDSLockedBuffer = NULL;
VOID* pDSLockedBuffer2 = NULL;
DWORD dwDSLockedBufferSize;
DWORD dwDSLockedBufferSize2;
HRESULT hr;
g_pDSBuffer8->Lock(g_dwNextWriteOffset,BUFFERNOTIFYSIZE,&pDSLockedBuffer,&dwDSLockedBufferSize, &pDSLockedBuffer2,&dwDSLockedBufferSize2,0);
if(hr == DSERR_BUFFERLOST)
{
g_pDSBuffer8->Restore();
g_pDSBuffer8->Lock(g_dwNextWriteOffset,BUFFERNOTIFYSIZE,&pDSLockedBuffer,&dwDSLockedBufferSize,
&pDSLockedBuffer2,&dwDSLockedBufferSize2,0);
}
if(SUCCEEDED(hr))
{
//write
g_pWaveFile->Read((BYTE*)pDSLockedBuffer,dwDSLockedBufferSize,&dwBytesWrittenToBuffer);
g_dwNextWriteOffset += dwBytesWrittenToBuffer;
if (NULL != pDSLockedBuffer2)
{
g_pWaveFile->Read((BYTE*)pDSLockedBuffer2,dwDSLockedBufferSize2,&dwBytesWrittenToBuffer);
g_dwNextWriteOffset += dwBytesWrittenToBuffer;
}
g_dwNextWriteOffset %= (BUFFERNOTIFYSIZE * MAX_AUDIO_BUF);
if(dwBytesWrittenToBuffer <BUFFERNOTIFYSIZE )
{
FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
BUFFERNOTIFYSIZE - dwBytesWrittenToBuffer,
(BYTE)(g_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
g_bPlaying = FALSE;
}
hr = g_pDSBuffer8->Unlock(pDSLockedBuffer,dwDSLockedBufferSize,
pDSLockedBuffer2,dwDSLockedBufferSize2);
}
} |
|