一个捕获音频并且播放的例子,可以用来唱歌^_^
写了半天才发现Direct SDK有个类似的例子,所以到了最后几乎都是照抄了。
声音效果不太好,修改一下加上网络传送功能做成语音聊天工具。不过这样肯定不行,真正的语音聊天可能都要音频数据处理啊等功能的。
我是想试这做个东西来唱歌,不过效果不好!程序错误很多,有很多地方可以改进的,不过我一贯的作风是浅尝即止。

#include "sound.h"
LPDIRECTSOUNDBUFFER8 lpDSBuffer8 = NULL; //播放缓冲区(第二缓冲区)
HANDLE soundEvent[3]; //播放通知
LPDIRECTSOUNDCAPTUREBUFFER8 lpDSBCapture = NULL;//捕获缓冲区对象指针
HANDLE captureEvent[3]; //播放通知
int SoundBufferLength=0; //播放缓冲的总长度, 一个缓冲设置分成3段,设置3个通知信号
int BufferSectionLength=0; //每一段的长度
//不过我懒的动态申请了,所以固定了,用于把临时保存捕获的音频数据,
//在从这里复制到播放缓存里面去。 其实直接复制也是可以的,不过加多一个缓存在这里,便于处理啊,网络传送等等。
bool SoundCreate(HWND hwnd )
{
{
MessageBox(hwnd,_T("创建DirectSound接口失败。"),_T("widebright"),MB_OK); // Add error-handling here.
return false;
}
{
MessageBox(hwnd,_T("设置DirectSound协作级别失败。"),_T("widebright"),MB_OK); // Add error-handling here.
lpDirectSound->Release (); // Add error-handling here.
return false;
}
{
MessageBox(hwnd,_T("创建DirectSound声音播放缓冲区失败。"),_T("widebright"),MB_OK); // Add error-handling here.
lpDirectSound->Release (); // Add error-handling here.
return false;
}
//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);
return true;
}
//
//The example function creates a streaming buffer large enough to hold 3 seconds of streaming data. Nonstreaming buffers should be made just large enough to accommodate the entire sound.
//
//The DSBCAPS_GLOBALFOCUS flag in the example ensures that the buffer will continue playing even when the application window is not in the foreground. Without this flag, the buffer will be muted when another application or even a dialog box has the input focus.
//
//If the location of a buffer is not specified, DirectSound places it in hardware-controlled memory if possible. Because hardware buffers are mixed by the sound card processor, they have much less impact on application performance.
//
//If you wish to specify the location of a buffer rather than letting DirectSound decide where it belongs, set either the DSBCAPS_LOCHARDWARE or DSBCAPS_LOCSOFTWARE flag in the DSBUFFERDESC structure. If the DSBCAPS_LOCHARDWARE flag is set and there are insufficient hardware resources, the buffer creation request fails.
//
//To take advantage of the voice management features of DirectSound, specify the DSBCAPS_LOCDEFER flag when creating the buffer. This flag defers the allocation of resources for the buffer until it is played. For more information, see Dynamic Voice Management.
//
//You can ascertain the location of an existing buffer by using the IDirectSoundBuffer8::GetCaps method and checking the dwFlags member of the DSBCAPS structure for either the DSBCAPS_LOCHARDWARE or DSBCAPS_LOCSOFTWARE flags. One or the other is always specified.
//
//Buffer objects are owned by the device object that created them. When the device object is released, all buffers created by that object are also released and should not be referenced.
{
WAVEFORMATEX wfx;
DSBUFFERDESC dsbdesc;
LPDIRECTSOUNDBUFFER pDsb = NULL;
HRESULT hr;
// Set up WAV format structure.
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 22050;
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
wfx.wBitsPerSample = 16;
// Set up DSBUFFERDESC structure.
memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags =
DSBCAPS_CTRLPAN //声源 是否可以左右移动
//DSBCAPS_CTRL3D //声源是否可以在 3D空移动。
//DSBCAPS_CTRLFX //特效处理支持
| DSBCAPS_CTRLVOLUME //音量控制
//| DSBCAPS_CTRLFREQUENCY //频率控制
| DSBCAPS_CTRLPOSITIONNOTIFY //可以设置播放位置通知
| DSBCAPS_GLOBALFOCUS; //在程序失去焦点的时候,依然播放声音
dsbdesc.dwBufferBytes = wfx.nAvgBytesPerSec/2; //设置缓冲区长度 为多少秒,就设置这里为wfx.nAvgBytesPerSec 乘以多少,这里和捕获的统一设置成一秒
dsbdesc.lpwfxFormat = &wfx;
BufferSectionLength = SoundBufferLength/3 ; //平均分成3段,每段的长度
BufferSectionLength -= BufferSectionLength % wfx.nBlockAlign; //内存对齐
hr = lpDirectSound->CreateSoundBuffer(&dsbdesc, &pDsb, NULL);
if (SUCCEEDED(hr))
{
hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*) ppDsb8);
pDsb->Release();
}
return hr;
}
//The buffer must be stopped when this method is called.
// hEventNotify ---Handle to the event to be signaled when the offset has been reached. 通知触发的event
{
LPDIRECTSOUNDNOTIFY8 lpDsNotify;
DSBPOSITIONNOTIFY PositionNotify[cEvents];
HRESULT hr;
if (FAILED( hr = lpDsbSecondary->QueryInterface(IID_IDirectSoundNotify8,
(LPVOID*)&lpDsNotify)))
{
return hr;
}
for (int i = 0; i < cEvents; ++i)
{
hEventNotify[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == hEventNotify[i])
{
hr = GetLastError();
return hr;
}
PositionNotify[i].hEventNotify = hEventNotify[i];
}
//注意没调用一次SetNotificationPositions函数就清除以前的通知对象,所以要设置多个通知对象只能使用一个PositionNotify数组,而不能调用多次SetNotificationPositions函数
hr = lpDsNotify->SetNotificationPositions(3, PositionNotify);
lpDsNotify->Release();
return hr;
}
LPDIRECTSOUNDBUFFER8 lpDsb, // The buffer.
DWORD dwOffset, // Our own write cursor.
LPBYTE lpbSoundData, // Start of our data.
DWORD dwSoundBytes) // Size of block to copy.
{
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
HRESULT hr;
// Obtain memory address of write block. This will be in two parts
// if the block wraps around.
hr = lpDsb->Lock(dwOffset, dwSoundBytes, &lpvPtr1,
&dwBytes1, &lpvPtr2, &dwBytes2, 0);
// If the buffer was lost, restore and retry lock.
if (DSERR_BUFFERLOST == hr)
{
lpDsb->Restore();
hr = lpDsb->Lock(dwOffset, dwSoundBytes,
&lpvPtr1, &dwBytes1,
&lpvPtr2, &dwBytes2, 0);
}
if (SUCCEEDED(hr))
{
// Write to pointers.
CopyMemory(lpvPtr1, lpbSoundData, dwBytes1);
if (NULL != lpvPtr2) //如果lpvPtr2不为NULL,说明要写的超出了缓冲的长度,这时lpvPtr2指向缓冲的开始部分,可以继续写进去
{
CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2);
}
// Release the data back to DirectSound.
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2,
dwBytes2);
if (SUCCEEDED(hr))
{
// Success.
return TRUE;
}
}
// Lock, Unlock, or Restore failed.
return FALSE;
}
// 启动 播放声音
bool SoundStart(HWND hwnd )
{
HRESULT hr;
//不采用 播放通知了,播放通知控制起来不方便,只需要的捕获通知里面复制 到播放缓存的相应位置好了
//
// HRESULT hr = SetNotification(soundEvent,lpDSBuffer8);
// if (FAILED(hr))
// {
// MessageBox(hwnd,_T("创建播放位置通知失败"),_T("widebright"),MB_OK);
// exit(0);
//}
ZeroMemory( SwapBuffer,29400); //无声
if (SUCCEEDED( hr = lpDSBuffer8->Play (0,0,DSBPLAY_LOOPING))) //开始播放
{
return true;
}else{
}
//while (1)
// {
// // DWORD notifyIndex = WaitForMultipleObjects(3,soundEvent,FALSE,INFINITE) ; //INFINITE 表示一直等待 ,除非hEvent产生了信号。 这里
// //
// //notifyIndex = notifyIndex - WAIT_OBJECT_0; //得到触发 通知对象序号
// // ResetEvent(soundEvent[ notifyIndex]);
//
// //FreeBufferSectionNum = notifyIndex;
// WaitForSingleObject(soundEvent[0], INFINITE);
// ResetEvent(soundEvent[ 0]);
// FreeBufferSectionNum =0;
// WaitForSingleObject(soundEvent[1], INFINITE);
// ResetEvent(soundEvent[1]);
// FreeBufferSectionNum =1;
// WaitForSingleObject(soundEvent[2], INFINITE);
// ResetEvent(soundEvent[ 2]);
// FreeBufferSectionNum =2;
//
//}
//停止播放声音
void SoundStop()
{
if ( ! lpDirectSound) lpDirectSound->Release ();
}
////////////////////////////////////下面是录音部分/////////////////////////////////////////////////////////////////////
{
HRESULT hr = DirectSoundCaptureCreate8 (&DSDEVID_DefaultCapture , &lpDSCapture,NULL);
{
MessageBox(hwnd,_T("创建DirectCapture接口失败。"),_T("widebright"),MB_OK); // Add error-handling here.
return false;
}
{
MessageBox(hwnd,_T("创建DirectCapture声音播放缓冲区失败。"),_T("widebright"),MB_OK); // Add error-handling here.
lpDSCapture->Release (); // Add error-handling here.
return false;
}
//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);
return true;
}
LPDIRECTSOUNDCAPTUREBUFFER8* ppDSCB8)
{
HRESULT hr;
DSCBUFFERDESC dscbd;
LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
WAVEFORMATEX wfx =
{WAVE_FORMAT_PCM, 2, 22050, 88200, 4, 16, 0};
// {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0};
// wFormatTag, nChannels, nSamplesPerSec, mAvgBytesPerSec,
// nBlockAlign, wBitsPerSample, cbSize
if ((NULL == pDSC) || (NULL == ppDSCB8)) return E_INVALIDARG;
dscbd.dwSize = sizeof(DSCBUFFERDESC);
dscbd.dwFlags = 0;
dscbd.dwBufferBytes = wfx.nAvgBytesPerSec/2; //*******保存多少秒的数据 就设置这里为多少乘以 wfx.nAvgBytesPerSec*********
dscbd.dwReserved = 0;
dscbd.lpwfxFormat = &wfx;
dscbd.dwFXCount = 0;
dscbd.lpDSCFXDesc = NULL;
if (SUCCEEDED(hr = pDSC->CreateCaptureBuffer(&dscbd, &pDSCB, NULL)))
{
hr = pDSCB->QueryInterface(IID_IDirectSoundCaptureBuffer8, (LPVOID*)ppDSCB8);
pDSCB->Release();
}
return hr;
}
{
#define cEvents 3
WAVEFORMATEX wfx;
//HANDLE rghEvent[cEvents] = {0};
DSBPOSITIONNOTIFY rgdsbpn[cEvents];
HRESULT hr;
if (FAILED(hr = pDSCB->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&pDSNotify)))
{
return hr;
}
if (FAILED(hr = pDSCB->GetFormat(&wfx, sizeof(WAVEFORMATEX), NULL)))
{
return hr;
}
for (int i = 0; i < cEvents; ++i)
{
rghEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == rghEvent[i])
{
hr = GetLastError();
return hr;
}
rgdsbpn[i].dwOffset = BufferSectionLength * (i+1) -1;
rgdsbpn[i].hEventNotify = rghEvent[0]; //rghEvent[i]; 可以多个通知对象共用一个event的
hr = pDSNotify->SetNotificationPositions(cEvents, rgdsbpn);
pDSNotify->Release();
return hr;
}
// 启动 播放声音
bool CaptureStart(HWND hwnd )
{
if( ! CaptureCreate(hwnd)) exit(0);
HRESULT hr = SetCaptureNotifications( captureEvent,lpDSBCapture );
if (FAILED(hr))
{
MessageBox(hwnd,_T("创建捕获位置通知失败"),_T("widebright"),MB_OK);
exit(0);
}
lpDSBCapture->Start (DSCBSTART_LOOPING); //开始捕获
DWORD playCursor=0,writeCursor=0;
int NextSoundOffset = 0; //播放缓存区 的偏移,
lpDSBuffer8->GetCurrentPosition(&playCursor,&writeCursor);
NextSoundOffset = (writeCursor + 600 )% SoundBufferLength;
{
// DWORD notifyIndex = WaitForMultipleObjects(3,captureEvent,FALSE,INFINITE) ; //INFINITE 表示一直等待 ,除非hEvent产生了信号。 这里
//
//notifyIndex = notifyIndex - WAIT_OBJECT_0; //得到触发 通知对象序号
// ResetEvent(captureEvent[ notifyIndex]);
VOID* pDSCaptureLockedBuffer = NULL;
DWORD dwDSCaptureLockedBufferSize;
ResetEvent(captureEvent[ 0]);
&pDSCaptureLockedBuffer,
&dwDSCaptureLockedBufferSize,
NULL, NULL, 0L ) ) )
{
CopyMemory( SwapBuffer,
pDSCaptureLockedBuffer,
dwDSCaptureLockedBufferSize );
lpDSBCapture->Unlock( pDSCaptureLockedBuffer, dwDSCaptureLockedBufferSize,
NULL, 0 );
lpDSBuffer8->GetCurrentPosition(&playCursor,&writeCursor);
// AppWriteDataToBuffer (lpDSBuffer8,writeCursor ,SwapBuffer,dwDSCaptureLockedBufferSize);
AppWriteDataToBuffer (lpDSBuffer8, NextSoundOffset ,SwapBuffer,dwDSCaptureLockedBufferSize);
}
NextSoundOffset +=dwDSCaptureLockedBufferSize;
NextSoundOffset %= SoundBufferLength; // Circular buffer
NextCaptureOffset += BufferSectionLength;
NextCaptureOffset %= SoundBufferLength; // Circular buffer
}
//停止播放声音
void CaptureStop()
{
if ( ! lpDSCapture ) lpDSCapture ->Release ();
}