前面已经发布了一篇音频特效播放相关的文章,今天开始学习DirectSound录音编码实现,这是DirectSound中另一个重要的地方。学会之后受益无穷啊!不过DirectSound设备录音编码其实不难,只要是调用Windows API按照一定的顺序和方法都不难。
利用DirectSound录音,有三个非常重要的对象,如下;
IDirectSoundCapture:设备对象,根据用户录音的设备创建的设备对象,利用该对象可以获取录音设备的属性。
IDirectSoundCaptureBuffer8:缓冲区对象,该对象由设备对象创建,主要用来操作音频数据。
IDirectSoundNotify8:事件通知对象,该对象用来通知应用程序从缓冲区中将数据取走,写入文件保存起来。
枚举录音设备
在录音之前需要枚举录音设备,如果调用DirectSoundCaptureCreate8和DirectSoundFullDuplexCreate8可以获取默认的录音设备对象,这也是常用的一种方法,但是如果你的电脑有多个录音设备时,碰巧这个时候,你又想制定录音设备录音时,你就需要先枚举你的录音设备。枚举的过程代码实现也是很简单的,调用DirectSoundCaptureEnumerate函数,制定回调函数即可,该函数原型如下;
DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)DSoundEnumCallback,
(VOID*)hCaptureDeviceCombo );
回调函数
INT_PTR CALLBACK DSoundEnumCallback( GUID* pGUID, LPSTR strDesc, LPSTR strDrvName,
VOID* pContext )
{
static GUID AudioDriverGUIDs[20];
static DWORD dwAudioDriverIndex = 0;
GUID* pTemp = NULL;
if( pGUID )
{
if( dwAudioDriverIndex >= 20 )
return TRUE;
pTemp = &AudioDriverGUIDs[dwAudioDriverIndex++];
memcpy( pTemp, pGUID, sizeof(GUID) );
}
HWND hSoundDeviceCombo = (HWND)pContext;
// 添加到指定的Combo文件当中
SendMessage( hSoundDeviceCombo, CB_ADDSTRING,
0, (LPARAM) (LPCTSTR) strDesc );
return TRUE;
}
创建设备对象
完成设备枚举之后,获取需要的GUID就可以开始创建设备对象,创建设备对象创建调用IDirectSoundCapture8函数进行,该函数原型如下;
创建设备对象代码如下;if( FAILED( hr = CoInitialize(NULL) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("CoInitialize"), hr );
return -1;
} // m_guidCaptureDevice从枚举设备操作中获取
if( FAILED( hr = DirectSoundCaptureCreate8((LPGUID)&m_guidCaptureDevice, &m_pDSCapture, NULL ) ) )
{
DXTRACE_ERR_MSGBOX( TEXT("DirectSoundCaptureCreate"), hr );
MessageBox( NULL, "Error initializing DirectSound. Sample will now exit.",
"DirectSound Sample", MB_OK | MB_ICONERROR );
return -2;
}
创建设备缓冲区对象,并设置事件通知
创建设备缓冲区调用CreateCaptureBuffer函数,该函数原型如下;
if( FAILED( hr = theApp.m_pDSBCapture->QueryInterface( IID_IDirectSoundNotify,
(VOID**)&(theApp.m_pDSNotify )) ) )
return DXTRACE_ERR_MSGBOX( TEXT("QueryInterface"), hr );
// Setup the notification positions
for( INT i = 0; i {
// 分16次通知,NUM_REC_NOTIFICATIONS 为16
theApp.m_aPosNotify[i].dwOffset = (theApp.m_dwNotifySize * i) + theApp.m_dwNotifySize - 1;
theApp.m_aPosNotify[i].hEventNotify = theApp.m_hNotificationEvent;
}
// Tell DirectSound when to notify us. the notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = theApp.m_pDSNotify->SetNotificationPositions( NUM_REC_NOTIFICATIONS,
theApp.m_aPosNotify ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("SetNotificationPositions"), hr );
接收通知,捕获数据
// 捕获通知
EventResult = WaitForMultipleObjects(
sizeof(hArray)/sizeof(HANDLE),
hArray,
FALSE,
INFINITE);
if(WAIT_OBJECT_0+1 == EventResult)
break;
if(WAIT_OBJECT_0 == EventResult)
{
pApp->RecordCapturedData();
ResetEvent(pApp->m_hNotificationEvent);
}
//捕获数据,并写入到文件当中
if( FAILED( hr = m_pDSBCapture->Lock( m_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Lock"), hr );
// Write the data into the wav file
if( FAILED( hr = m_pWaveFile->Write( dwCaptureLength,
(BYTE*)pbCaptureData,
&dwDataWrote ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Write"), hr );
// Move the capture offset along
m_dwNextCaptureOffset += dwCaptureLength;
m_dwNextCaptureOffset %= m_dwCaptureBufferSize; // Circular buffer
if( pbCaptureData2 != NULL )
{
// Write the data into the wav file
if( FAILED( hr = m_pWaveFile->Write( dwCaptureLength2,
(BYTE*)pbCaptureData2,
&dwDataWrote ) ) )
return DXTRACE_ERR_MSGBOX( TEXT("Write"), hr );
// Move the capture offset along
m_dwNextCaptureOffset += dwCaptureLength2;
m_dwNextCaptureOffset %= m_dwCaptureBufferSize; // Circular buffer
}
// Unlock the capture buffer
m_pDSBCapture->Unlock( pbCaptureData, dwCaptureLength,
pbCaptureData2, dwCaptureLength2 );
退出处理
SAFE_DELETE( m_pWaveFile );
// Release DirectSound interfaces
SAFE_RELEASE( m_pDSNotify );
SAFE_RELEASE( m_pDSBCapture );
SAFE_RELEASE( m_pDSCapture );
// Release COM
CoUninitialize();
……
Windows 中DirectSound调用API进行录音操作,按照一定的步骤其实不难!