您的位置:首页 > 编程语言 > C语言/C++

通过DirectSound实时播放PCM+混音

2016-09-22 11:01 267 查看
#include "StdAfx.h"
#include "AudioPlayer.h"

#define AUDIO_SECOND_COUNT		1		//10秒缓冲区

CAudioPlayer::CAudioPlayer(void)
{

for (int i = 0; i < AUDIO_MIX_COUNT; ++i)
{
m_pDS[i] = NULL;
m_pDsb[i] = NULL;
m_pDsb8[i] = NULL;
m_dwCurPos[i] = 0;
m_bStop[i] = TRUE;
}
}

CAudioPlayer::~CAudioPlayer(void)
{
Uninit();
}

BOOL CAudioPlayer::PlayerInit(DWORD dwChannel, DWORD dwSamplesPerSec, DWORD dwBitsPerSample,HWND wnd, int deviceindex)
{
/*缓存数据块格式*/
m_wfe.wFormatTag = WAVE_FORMAT_PCM;
m_wfe.nChannels = dwChannel;
m_wfe.nSamplesPerSec = dwSamplesPerSec;
m_wfe.wBitsPerSample = dwBitsPerSample;
m_wfe.nBlockAlign = (dwBitsPerSample/8)*dwChannel;
m_wfe.nAvgBytesPerSec = dwSamplesPerSec*(dwBitsPerSample/8)*dwChannel;
m_wfe.cbSize = 0;

/*第一个参数代表应用程序的主窗口,而第二个参数则设定使用资源的优*/

//
// Create Sound Buffer
//
DSBUFFERDESC dsbd;
memset(&dsbd, 0, sizeof(DSBUFFERDESC));
dsbd.dwSize = sizeof(DSBUFFERDESC);
//dsbd.dwBufferBytes = AUDIO_PLAYBUF_LEN;		//40960
dsbd.dwBufferBytes = m_wfe.nBlockAlign*m_wfe.nAvgBytesPerSec;
dsbd.lpwfxFormat = (LPWAVEFORMATEX) (&m_wfe);
//其中GLOBALFOCUS标志位保证当程序窗口不在前面时仍能够播放
/*Pan(左右正道的差值)*/
// 	DSBCAPS_CTRL3D   //缓冲区具有的3D音效控制能力,不能与DSBCAPS_CTRLPAN一起使用
// 		DSBCAPS_CTRLFREQUENCY   //可设置采样频率
// 		DSBCAPS_CTRLFX  //缓冲区支持特效处理,但缓冲区必须够大,可容纳更多的数据
// 		DSBCAPS_CTRLPAN  //缓冲区可以控制声道
// 		DSBCAPS_CTRLPOSITIONNOTIFY  //缓冲区具有播放位置通知能力
// 		DSBCAPS_CTRLVOLUME  //缓冲区可设置音量大小
// 		DSBCAPS_GLOBALFOCUS  //缓冲是一个全局声音资源,当前程序切换到其他程序依然可以继续播放.
// 		DSBCAPS_LOCDEFER  //缓冲区可绑定硬件内存或者软件内存来播放声音
// 		DSBCAPS_LOCHARDWARE  //缓冲区必须使用硬件的混声器,如果不支持硬件内存或者混声器,都会导致创建缓冲区失败.
// 		DSBCAPS_LOCSOFTWARE  //缓冲区使用软件内存或者使用软件混音
// 		DSBCAPS_MUTE3DATMAXDISTANCE  //超过声音可听的最大距离,将停止播放声音
// 		DSBCAPS_PRIMARYBUFFER  //说明缓冲区的为主缓冲区(如果没说明,则用作次缓冲区)
// 		DSBCAPS_STATIC  //自动使用硬件内存做缓冲区
// 		DSBCAPS_STICKYFOCUS  //当程序切换到其他不使用DIRECTSOUND 的程序时,缓冲区继续播放声音,但无法如常进行其他处理
//dsbd.dwFlags =  DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
dsbd.dwFlags =  DSBCAPS_LOCSOFTWARE  | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME;

/*在设置协调层级时,标志位必须设定为DSSCL_PRIORITY.
次缓冲区则存储播放声音的文件。在加载声音文件后,
只要调用Play()方法,声音就会自动的送入主缓冲区中并进行播放*/

HRESULT result = 0;

AdoAudioDevices adoad;
int ncount = adoad.getDevCount(AdoAudioDevices::audio_render);

for (int i = 0; i < AUDIO_MIX_COUNT; ++i)
{
result = DirectSoundCreate(&adoad.sysAudioDevIndex2DevGuid(deviceindex,AdoAudioDevices::audio_render), &m_pDS[i], NULL);
if(result != DS_OK)
{
return FALSE;
}
result = m_pDS[i]->SetCooperativeLevel(wnd, DSSCL_PRIORITY);
if(result != DS_OK)
{
return FALSE;
}
/*建立次缓冲区*/
/*每一个声音对应一个辅助缓冲区,可以有多个辅助缓冲区*/
if( FAILED(m_pDS[i]->CreateSoundBuffer(&dsbd,&m_pDsb[i],NULL))){
return FALSE;
}
}
return TRUE;
}

BOOL CAudioPlayer::Start(int nCase)
{

/*
播放声音要通过以下步骤:
1、锁定辅助缓冲的一部分以获得你所需要的那部分缓冲的基址。
2、向缓冲写数据。
3、解锁。
4、使用IDirectSoundBuffer::Play方法来播放声音。
如果是使用的流缓冲,还需要反复的执行1-3步骤。*/

LPDIRECTSOUNDBUFFER pDsb;
if ( ( nCase>=0 ) && ( nCaseGetStatus(&dwStatus))
{
return FALSE;
}
if((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING)
{
/**/
pDsb->SetCurrentPosition(0);

hr = pDsb->Play(0, 0,0);//DSBPLAY_LOOPING);
//hr = pDsb->Play(0, 0, 0);

if (DS_OK != hr)
{
m_bStop[nCase] = TRUE;
return FALSE;
}
m_bStop[nCase] = FALSE;
}
return TRUE;
}

BOOL CAudioPlayer::Pause(int nCase)
{
LPDIRECTSOUNDBUFFER pDsb;
if (m_bStop[nCase])
{
return FALSE;
}

if ( ( nCase>=0 ) && ( nCaseStop();

if (rs != DS_OK)
{
Sleep(1);
pDsb->Stop();
}
FillBlankToBuf(0, nCase);
m_bStop[nCase] = TRUE;
return TRUE;
}

BOOL CAudioPlayer::Stop(int nCase)
{
if (m_bStop[nCase])
{
return FALSE;
}
LPDIRECTSOUNDBUFFER pDsb;

if( (nCase>=0) && (nCaseGetStatus(&dwStatus))
{
return FALSE;
}

if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
MMRESULT rs;
rs = pDsb->Stop();
if(rs != DS_OK)
{
Sleep(1);
pDsb->Stop();
}
FillBlankToBuf(0, nCase);
m_bStop[nCase] = TRUE;
}
return TRUE;
}

BOOL CAudioPlayer::Uninit(void)
{
for( int i = 0 ; i < AUDIO_MIX_COUNT ; i++ )
{
Stop(i);
}
return TRUE;
}

void CAudioPlayer::SetVolume(long nNewValue)
{
nNewValue *= -1;
if ( nNewValue < DSBVOLUME_MIN )
{
nNewValue = DSBVOLUME_MIN ;
}
if ( nNewValue > DSBVOLUME_MAX )
{
nNewValue = DSBVOLUME_MAX ;
}
for ( int i = 0; i < AUDIO_MIX_COUNT; i++ )
{
m_pDsb[i]->SetVolume(nNewValue);
}
}

long CAudioPlayer::GetVolume(void)
{
long vol;
m_pDsb[0]->GetVolume(&vol);
return vol;
}

BOOL CAudioPlayer::FillBlankToBuf(ULONG pos , int nCase) // nCase 0基
{
DWORD len = m_wfe.nAvgBytesPerSec;

LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;

LPDIRECTSOUNDBUFFER pDsb;
if( (nCase>=0) && (nCaseLock(pos, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
if (DSERR_BUFFERLOST == hr)
{
pDsb->Restore();
hr = pDsb->Lock(pos, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
}
if (DS_OK == hr)
{
ZeroMemory(lpvPtr1, dwBytes1);
if (NULL != lpvPtr2)
{
ZeroMemory(lpvPtr2, dwBytes2);
}
hr=pDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
return TRUE;
}

pDsb->SetCurrentPosition(0);

return TRUE;
}

BOOL CAudioPlayer::FillBuffer(unsigned char *pdata, DWORD len, int nCase) // nCase 0基
{
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;

/* 首先要建立一个代表声卡的DirectSound对象*/
LPDIRECTSOUNDBUFFER pDsb;
DWORD curpos;
if( ( nCase >= 0 ) && ( nCase < AUDIO_MIX_COUNT ) )
{
pDsb = m_pDsb[nCase];
curpos = m_dwCurPos[nCase];
}
else
{
return FALSE;
}

// *********** ptr modify ***********
DWORD wp1 , wp2 ;
pDsb->GetCurrentPosition(&wp1, &wp2);
//TRACE("[%d]",curpos);
//DWORD dwCount = 0;
// *********** end ptr modify *******
pDsb->SetCurrentPosition(0);
hr = pDsb->Lock(wp2, len, &lpvPtr1, &dwBytes1,&lpvPtr2, &dwBytes2, DSBLOCK_FROMWRITECURSOR );
if (DSERR_BUFFERLOST == hr)
{
pDsb->Restore();
hr = pDsb->Lock(wp2, len, &lpvPtr1, &dwBytes1,&lpvPtr2, &dwBytes2, DSBLOCK_FROMWRITECURSOR );
}
if (DS_OK == hr)
{
CopyMemory(lpvPtr1, pdata, len);
if (NULL != lpvPtr2)
{
CopyMemory(lpvPtr2, pdata, len);
}
hr = pDsb->Unlock(lpvPtr1, dwBytes1,lpvPtr2, dwBytes2);
if (hr != DS_OK)
{
return FALSE;
}
return TRUE;
}
pDsb->Restore();
pDsb->SetCurrentPosition(0);
return FALSE;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ DirectSound