科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件利用DirectSound实现声卡录音

利用DirectSound实现声卡录音

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文详细讲述了如何利用DirectSound对经过声卡和麦克风的数据进行捕获,进行录音,并保存为wave格式的文件。

作者:智慧的鱼 来源:天极网 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
创建设备对象

  你可以通过DirectSoundCaptureCreate8或者DirectSoundFullDuplexCreate8函数直接创建设备对象,该函数返回一个指向IDirectSoundCapture8接口的指针

if( FAILED( hr = CoInitialize(NULL) ) )
return hr;
if(pDeviceGuid)
{
 if(FAILED( hr = DirectSoundCaptureCreate(pDeviceGuid,&g_pDSCapture,NULL)))
  return hr;
}
else
{
 if(FAILED(hr= DirectSoundCaptureCreate(&DSDEVID_DefaultCapture ,&g_pDSCapture,NULL)))
  return hr
}

  其中pDeviceGuid是从枚举的combox中选择的设备的ID。

  现在创建了设备对象你可以通过IDirectSoundCapture8::GetCaps方法来获取录音设备的性能,这个函数的参数是一个DSCCAPS类型的结构,在传递这个参数之前,一定要初始化该结构的dwSize成员变量。同时,你可以通过这个结构返回设备支持的声道数,以及类似WAVEINCAPS结构的其他设备属性

  创建录音的缓冲区对象

  我们可以通过IDirectSoundCapture8::CreateCaptureBuffer来创建一个录音的buffer对象,这个函数的一个参数采用DSCBUFFERDESC类型的结构来说明buffer的一些特性,这个结构的最后一个成员变量是一个WAVEFORMATEX结构,这个结构一定要初始化成泥需要的wav格式。
说明一下,如果你的应用程序一边播放的同时进行录制,如果你录制的buffer格式和你的主缓冲buffer不一样,那么你创建录制buffer对象就会失败,原因在于,有些声卡只支持一种时钟,不能同时支持录音和播放同时以两种不同的格式进行。

  下面的函数,演示了如何创建一个录音的buffer对象,这个buffer对象能够处理1秒的数据,注意,这里传递的录音设备对象参数一定要通过DirectSoundCaptureCreate8来创建,而不是早期的DirectSoundCaptureCreate接口,否则,buffer对象不支持IDirectSoundCaptureBuffer8接口。

HRESULT CreateCaptureBuffer(LPDIRECTSOUNDCAPTURE8 pDSC,
LPDIRECTSOUNDCAPTUREBUFFER8* ppDSCB8)
{
 HRESULT hr;
 DSCBUFFERDESC dscbd;
 LPDIRECTSOUNDCAPTUREBUFFER pDSCB;
 WAVEFORMATEX wfx ={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;
 dscbd.dwReserved = 0;
 dscbd.lpwfxFormat = &wfx; //设置录音用的wave格式
 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;
}

  你可以通过IDirectSoundCaptureBuffer8::GetCaps方法来获取录音buffer的大小,但一定要记得初始化DSCBCAPS结构类型参数的dwSize成员变量。

  为了获取buffer中数据的格式,你可以通过IDirectSoundCaptureBuffer8::GetFormat.方法来获取buffer中的数据格式,这个函数通过WAVEFORMATEX结构返回音频数据的信息,如果我们想知道一个录音buffer目前的状态如何,可以通过IDirectSoundCaptureBuffer8::GetStatus来获取,这个函数通过一个DWORD类型的参数来表示该buffer是否正在录音,
IDirectSoundCaptureBuffer8::GetCurrentPosition方法可以获取buffer中read指针和录制指针的偏差。Read指针指向填充到该buffer中的数据的最末端,capture指针则指向复制到硬件的数据的末端,你read指针指向的前段数据都是安全数据,你都可以安全的复制。

  录音buffer对象通知机制

  为了安全的定期的从录音buffer中copy数据,你的应用程序就要知道,什么时候read指针指向了特定的位置,一个方法是通过IDirectSoundCaptureBuffer8::GetCurrentPosition.方法来获取read指针的位置,另外一个更有效的方法采用通知机制,通过IDirectSoundNotify8::SetNotificationPositions方法,你可以设置任何一个小于buffer的位置来触发一个事件,切记,当buffer正在running的时候,不要设置。

  如何来设置一个触发事件呢,首先要得到IDirectSoundNotify8接口指针,你可以通过buffer对象的QuerInterface来获取这个指针接口,对于你指定的任何一个position,你都要通过CreateEvent方法,创建一个win32内核对象, 然后将内核对象的句柄赋给DSBPOSITIONNOTIFY结构的hEventNotify成员,通过该结构的dwOffset来设置需要通知的位置在buffer中的偏移量。

  最后将这个结构或者结构数组,传递给SetNotificationPositions函数,下面的例子设置了NUM_REC_NOTIFICATIONS个通知,当position达到g_dwNotifySize时会触发一个通知,依次类推。

HRESULT InitNotifications()
{
 HRESULT hr ;
 g_hNotificationEvent = CreateEvent(NULL,FALSE,FALSE,NULL); //创建事件
 if(g_pDSBCapture == NULL)
  return E_FAIL;
 if(FAILED(hr = g_pDSBCapture ->QueryInterface(IID_IDirectSoundNotify,(VOID**)&g_pDSNotify)))
  return hr;

 for( INT i = 0; i < NUM_REC_NOTIFICATIONS; i++ )
 {
  g_aPosNotify[i].dwOffset = (g_dwNotifySize * i) + g_dwNotifySize - 1;
  g_aPosNotify[i].hEventNotify = g_hNotificationEvent;
 }

 if(FAILED( hr =g_pDSNotify->SetNotificationPositions( NUM_REC_NOTIFICATIONS, g_aPosNotify ) ) )
  return hr;
 return S_OK;
}
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章