科技行者

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

知识库

知识库 安全导航

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

利用DirectSound实现声卡录音

  • 扫一扫
    分享文章到微信

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

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

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

关键字:

  • 评论
  • 分享微博
  • 分享邮件
创建工作线程,用来将缓冲区的数据写入文件

::CreateThread(NULL,0,ThreadRecord,this,0,NULL);

  看看线程内的工作吧

DWORD WINAPI ThreadRecord(LPVOID lpParameter)
{
 DWORD dwResult =0;
 g_bRecording = TRUE;
 while(g_bRecording)
 {
  dwResult = WaitForMultipleObjects(1, &g_hNotificationEvent,FALSE,INFINITE );
  switch( dwResult )
  {
   case WAIT_OBJECT_0 + 0:
    RecordCapturedData();
  }
 }
 return 0;
}

  这个线程一直在等待通知事件的触发,当缓冲区的数据填充到设定的位置时就会触发线程,这里主要有一个函数RecordCaptureedData()。这个函数主要做了下面的事情:

  1) 调用IDirectSoundCaptureBuffer8::Start使buffer对象开始工作,通过你要给这个函数dwFlags传递一个DSCBSTART_LOOPING参数,注意,buffer就会不停工作,而不是当buffer填充满了就停止工作,当缓冲区满了后,就会从头重新填充。

  2) 等待你期望的事件通知,当buffer被填充到某个你期望的位置时,会触发通知。

  3) 当你收到通知的时,你就要调用IDirectSoundCaptureBuffer8::Lock来锁住bufer的一部份,切记,不要将capture指针指向的内存锁住,你可以调用IDirectSoundCaptureBuffer8::GetCurrentPosition方法来获取read指针的位置。在传递给Lock函数的参数中,你一定要指定内存的大小和偏移量,这个函数会返回你锁住的内存的起始地址,以及block的大小。

  4) 在锁住的内存中复制data。

  5) 复制完成后要记得IDirectSoundCaptureBuffer8::Unlock方法来解锁内存。

  6)在你停止录音之前,你可以反复的重复2~5步骤,如果你想停止录音了,你可以调用IDirectSoundCaptureBuffer8::Stop方法。 将录音写入wav文件WAV文件是采用RIFF格式的文件,在文件中包含一系列的chunks,来描述头信息和数据信息,win32API提供一套mmio系列函数用来操作RIFF格式的文件,但是Directsound并没有提供读写wav格式文件的函数,但是,Directsound里封装了一个CWaveFile类用来操作wav文件,可以通过open来写入文件的头信息,write来写入文件的数据,close函数写入文件的长度,关闭文件。你可以在DirectSound的路径下找到这个类的定义(SDK root)\samples\C++\Common\Src\Dsutil.cpp。

  下面是代码,如何创建一个wav格式的文件

CWaveFile g_pWaveFile;
WAVEFORMATEX wfxInput;

ZeroMemory( &wfxInput, sizeof(wfxInput));
wfxInput.wFormatTag = WAVE_FORMAT_PCM;
wfxInput.nSamplesPerSec = 22050
wfxInput.wBitsPerSample = 8;
wfxInput.nChannels = 1;
wfxInput.nBlockAlign =
wfxInput.nChannels * (wfxInput.wBitsPerSample / 8);
wfxInput.nAvgBytesPerSec =
wfxInput.nBlockAlign * wfxInput.nSamplesPerSec;

g_pWaveFile = new CWaveFile;
if (FAILED(g_pWaveFile->Open("mywave.wav", &wfxInput,
WAVEFILE_WRITE)))
{
g_pWaveFile->Close();
}

  下面的代码就演示了是RecordCapturedData()函数的完整定义

HRESULT CCaptureSoundDlg::RecordCapturedData()
{
 HRESULT hr;
 VOID *pbCaptureData = NULL;
 DWORD dwCaptureLength;
 VOID *pbCaptureData2 = NULL;
 DWORD dwCaptureLength2;
 UINT dwDataWrote;
 DWORD dwReadPos;
 DWORD dwCapturePos;
 LONG lLockSize;


 if(g_pDSBCapture == NULL )
  return S_FALSE;

 if( NULL == g_pWaveFile )
  return S_FALSE;

 if(FAILED( hr = g_pDSBCapture->GetCurrentPosition(&dwCapturePos,&dwReadPos)))
  return hr;

 lLockSize = dwReadPos -g_dwNextCaptureOffset;

 if( lLockSize < 0 )
  lLockSize += g_dwCaptureBufferSize;

 //锁住内存的大小
 //这里取模是为了使得我们读取的数据大小为g_dwNotifySize整数倍,这样buffer里剩下的也是notify的倍数
 lLockSize -= (lLockSize % g_dwNotifySize);

 if( lLockSize == 0 )
  return S_FALSE;

 //锁住内存
 if( FAILED( hr = g_pDSBCapture->Lock( g_dwNextCaptureOffset, lLockSize,
&pbCaptureData, &dwCaptureLength,
&pbCaptureData2, &dwCaptureLength2, 0L ) ) )
  return hr;

 // 将内存中的数据拷贝到wave文件中
 if( FAILED( hr = g_pWaveFile->Write( dwCaptureLength, (BYTE*)pbCaptureData,
&dwDataWrote ) ) )
  return hr;

 // 移动偏移标志,循环移动
 g_dwNextCaptureOffset += dwCaptureLength;
 g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer

 if( pbCaptureData2 != NULL )
 {
  // 将内存中的数据拷贝到wave文件中
  if( FAILED( hr = g_pWaveFile->Write( dwCaptureLength2, (BYTE*)pbCaptureData2,
&dwDataWrote ) ) )
   return hr;

  // 移动偏移标志
  g_dwNextCaptureOffset += dwCaptureLength2;
  g_dwNextCaptureOffset %= g_dwCaptureBufferSize; // Circular buffer
 }

 //内存解锁
 g_pDSBCapture->Unlock( pbCaptureData, dwCaptureLength, pbCaptureData2, dwCaptureLength2 );

 return S_OK;
}

  这里解释一下,IDirectSoundBuffer8::Lock可能返回两个地址的原因在于你锁定内存的数量是随机的,有时你锁定的区域正好包含buffer的起始点,这时,就会给你返回两个地址,举个例子吧。

  假设你锁定了30,000字节,偏移位置为20,000字节,也就是开始位置,如果你的缓冲区的大小为40,000字节,此时就会给你返回四个数据:

  ·内存地址的偏移位置20,000,

  ·从偏移位置到buffer的最末端的字节数,也是20,000,你要在第一个地址读取20,000个字节的内容

  ·偏移量为0的地址

  ·从起始点开始的字节数,也就是10,000字节,你要从第二个地址,也就是从0点开始读取10,000字节。

  如果不包含零点,最后两个数值返回为NULL和0,

  关于DirectSound对声卡录音就简单介绍介绍到这里,留下msn :aooang@hotmail.com,欢迎和大家交流,我在天机的blog, 里面有关于DirectSound和DirectShow的不少资料,我翻译了DirectShow和DirectSound的SDK文档,欢迎来信索取,共同学习。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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