dsound(DSound音频播放「建议收藏」)

发布时间:2025-12-10 19:34:49 浏览次数:2

DSound音频播放「建议收藏」-dsound是什么意思

DSound音频播放「建议收藏」DSound是directx中的用来处理声音特性的一部分,播放音频需要准备的工作其实和waveout也是差不多啊,创建directxobject也就是创建一个LPDIRECTSOUND,这个结构的定义可以参考dsound.h头文件,接着需要一个声音的描述WAVEFORMATEX,这个声音的描述其实在DSound中是位于buffer里面的,DSound对WAVEFORMATEX进行了封装,具体可以参

DSound是directx中的用来处理声音特性的一部分,播放音频需要准备的工作其实和waveout也是差不多啊,创建directxobject也就是创建一个LPDIRECTSOUND,这个结构的定义可以参考dsound.h头文件,接着需要一个声音的描述WAVEFORMATEX,这个声音的描述其实在DSound中是位于buffer里面的,DSound对WAVEFORMATEX进行了封装,具体可以参考LPDIRECTSOUNDBUFFER结构的定义,同样是位于dsound.h中。播放音频需要一个窗口或者子窗口的句柄,否则播放不了,没有去很仔细的研究,只是实际遇到了所以提一下。

DSound的音频播放只需要使用初始化好的LPDIRECTSOUNDBUFFER进行控制,直接调用LPDIRECTSOUNDBUFFER的Play、Stop即可。需要涉及到的操作是buffer的Lock、填充数据、Unlock,这里的操作和WaveOut是类似的。和WaveOut一样在使用流播放的时候,我们还是分段缓冲,这样减少加载的时间间隔减少噪音。

DSound的缓冲的做饭时直接设置一块大的buffer,然后将这段buffer分段锁定然后填充数据解锁播放达到缓冲的效果。但在DSound中并不使用Waveout的回调函数提示播放完成,其实是有一个更加方便的办法。在LPDIRECTSOUNDBUFFER中我们是可以设置播放进度notify的,比回调好用多了。将buffer分段之后设置notify的偏移位置当播放到这个点的时候就会发送一个消息,捕获它完成相应的操作即可。可以使用注册buffer的com接口来获得notify。创建一个线程不断的捕获buffer发过来的播放进度notify,然后加载数据到指定的buffer空闲区。

具体看代码描述,下面是头文件的定义

//buffer的分段的个数#define BUFFERCOUNT 2//每段buffer的大小#define BUFFERNOTIFYSIZE (BLOCKSIZE)class CDxSound{public:CDxSound(HWND hWnd, char* pFileName);~CDxSound(void);int Play();private:int Initialize(void);int LoadAudioFormat(void);void ProcessBuffer();static DWORD WINAPI PlayThread(LPVOID lpParame);HWND m_hWnd;CWavInfo *m_pWavInfo;LPDIRECTSOUND m_pDirectObject;//dx objecctWAVEFORMATEX m_stWfx;//wav formatLPDIRECTSOUNDBUFFER m_pDSoundBuffer;//dx bufferDSBUFFERDESC m_stBufferDes;//buffer descLPDIRECTSOUNDNOTIFY m_pDSNotify;DSBPOSITIONNOTIFY m_pPosNotify[BUFFERCOUNT];HANDLE m_hEvent[BUFFERCOUNT];DWORD m_dwNextWriteOffset;int m_nIsPlaying;};

是否还在为Ide开发工具频繁失效而烦恼,来吧关注以下公众号获取最新激活方式。亲测可用!

为防止网络爬虫,请关注公众号回复”口令”

激活idea 激活CLion DataGrip DataSpell dotCover dotMemory dotTrace GoLand PhpStorm PyCharm ReSharper ReShaC++ Rider RubyMine WebStorm 全家桶 刷新

【正版授权,激活自己账号】:Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】:官方授权 正版激活 自己使用,支持Jetbrains家族下所有IDE…

函数等和上一篇的WaveOut是类似的。

DSound的初始化以及声音buffer的描述

int CDxSound::Initialize(void){int i;for(i = 0; i < BUFFERCOUNT; ++i){m_hEvent[i] = CreateEvent(NULL, FALSE, FALSE, NULL);}//创建directsound类型if(DirectSoundCreate(NULL, &m_pDirectObject, NULL) == DS_OK){m_pDirectObject->SetCooperativeLevel(m_hWnd, DSSCL_PRIORITY);}else{return -1;}if(LoadAudioFormat() != 0){return -1;}//声音的描述以及声音buffer的描述memset(&m_stBufferDes, 0, sizeof(DSBUFFERDESC));m_stBufferDes.lpwfxFormat   = &m_stWfx;m_stBufferDes.dwFlags       = DSBCAPS_GLOBALFOCUS        |   DSBCAPS_CTRLPOSITIONNOTIFY |  DSBCAPS_GETCURRENTPOSITION2;m_stBufferDes.dwSize        = sizeof(DSBUFFERDESC);m_stBufferDes.dwBufferBytes = BUFFERCOUNT * BUFFERNOTIFYSIZE;LPDIRECTSOUNDBUFFER lpbuffer;if(m_pDirectObject->CreateSoundBuffer(&m_stBufferDes, &lpbuffer, 0) != DS_OK){return -1;}//注册这个dsoundbuffer的com接口if(lpbuffer->QueryInterface(IID_IDirectSoundBuffer, (LPVOID*)&m_pDSoundBuffer) != DS_OK){return -1;}lpbuffer->Release();for(i = 0; i < BUFFERCOUNT; ++i){m_pPosNotify[i].dwOffset = i * BLOCKSIZE;m_pPosNotify[i].hEventNotify = m_hEvent[i];}if(m_pDSoundBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&m_pDSNotify) != DS_OK){return -1;}//设置播放进度notifyif(m_pDSNotify->SetNotificationPositions(BUFFERCOUNT, m_pPosNotify) != DS_OK){return -1;}m_pDSNotify->Release();return 0;}
不要以为上面的LPDIRECTSOUNDBUFFER lpbuffer这个没用,其实是不同的两个东西,对com不熟悉,不知道里面完成了什么。希望大神解释一下~

播放线程,不断的检查播放进度notify进行数据的填充。

DWORD WINAPI CDxSound::PlayThread(LPVOID lpParame){DWORD res;DWORD len;unsigned int dwWrite;LPVOID lplockbuf;CDxSound *dxSound = (CDxSound*)lpParame;dxSound->m_pDSoundBuffer->Lock(0, BUFFERNOTIFYSIZE, &lplockbuf, &len, NULL, NULL, DSBLOCK_ENTIREBUFFER);dxSound->m_pWavInfo->ReadABlockData(lplockbuf, &dwWrite);dxSound->m_pDSoundBuffer->Unlock(lplockbuf, len, NULL, 0);dxSound->m_pDSoundBuffer->SetCurrentPosition(0);dxSound->m_pDSoundBuffer->Play(0, 0, DSBPLAY_LOOPING);dxSound->m_dwNextWriteOffset = BUFFERNOTIFYSIZE;//一直读取数据播放直到文件结束while(dxSound->m_nIsPlaying == 1){//等待dsound的播放进度信号(这里设置了BUFFERCOUNT个播放进度信号),//如果捕获到信号那么读取数据到播放完的那一段缓冲区中res = WaitForMultipleObjects(BUFFERCOUNT, dxSound->m_hEvent, false, INFINITE);if(res >= WAIT_OBJECT_0){//读取数据到指定缓冲区dxSound->ProcessBuffer();}}return 0;}
数据填充函数:
void CDxSound::ProcessBuffer(void){DWORD dwBytesWrittenToBuffer = 0;void* pDSLockedBuffer = NULL;DWORD dwDSLockedBufferSize;unsigned int nSize;//锁定播放过完的一个BUFFERNOTIFYSIZE的缓冲区区域进行数据拷贝m_pDSoundBuffer->Lock(m_dwNextWriteOffset, BUFFERNOTIFYSIZE,&pDSLockedBuffer, &dwDSLockedBufferSize,NULL, NULL, 0);//读取数据,并检查是否到达文件结束位置if(m_pWavInfo->ReadABlockData(pDSLockedBuffer, &nSize) != 0){//文件结束,释放上面锁定的区域,播放结束m_pDSoundBuffer->Unlock(pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL);m_pDSoundBuffer->Stop();m_nIsPlaying = 0;}//设置下一次锁定的缓冲区位置m_dwNextWriteOffset += nSize;m_dwNextWriteOffset = m_dwNextWriteOffset % (BUFFERNOTIFYSIZE * BUFFERCOUNT);m_pDSoundBuffer->Unlock(pDSLockedBuffer, dwDSLockedBufferSize, NULL, NULL);}
最后是播放函数,主要是完成线程的启动还有消息的处理避免界面死掉:
int CDxSound::Play(void){if(m_pWavInfo == NULL){return -1;}m_nIsPlaying = 1;//创建播放线程HANDLE pHandle;pHandle = CreateThread(0, 0, PlayThread, this, NULL, NULL);if(pHandle == NULL){return -2;}DWORD result; MSG msg; while(true){//接收所有信号,避免主线程死掉result = MsgWaitForMultipleObjects(1, &pHandle, false, INFINITE, QS_ALLINPUT); if(result == (WAIT_OBJECT_0)){break;}//子线程结束返回else { PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);DispatchMessage(&msg); }//其他消息或者信号}return 0;}
完毕~~

As I am a beginner with DSound, please tell me if there are any mistakes in this article!


需要做网站?需要网络推广?欢迎咨询客户经理 13272073477