(DirectX系列02)DirectSound 录音编码实现

简介:       前面已经发布了一篇音频特效播放相关的文章,今天开始学习DirectSound录音编码实现,这是DirectSound中另一个重要的地方。学会之后受益无穷啊!不过DirectSound设备录音编码其实不难,只要是调用Windows API按照一定的顺序和方法都不难。

      前面已经发布了一篇音频特效播放相关的文章,今天开始学习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进行录音操作,按照一定的步骤其实不难!

目录
相关文章
|
存储 缓存 内存技术
SDL开发笔记(二):音频基础介绍、使用SDL播放音频
SDL开发笔记(二):音频基础介绍、使用SDL播放音频
SDL开发笔记(二):音频基础介绍、使用SDL播放音频
|
缓存 编解码 API
FFmpeg开发笔记(八):ffmpeg解码音频并使用SDL同步音频播放
FFmpeg开发笔记(八):ffmpeg解码音频并使用SDL同步音频播放
FFmpeg开发笔记(八):ffmpeg解码音频并使用SDL同步音频播放
|
缓存 Windows 内存技术
Windows PCM音频捕获与播放实现
在WINDOWS下,音频函数有多种类型,如MCI、多媒体OLE控制、高级音频等,使用方法都比较简单。但如果想编写一个功能较强大的音频处理程序,那就必须使用低级音频函数和多媒体文件I/O来控制音频设备的输入和输出。
2151 0
|
JavaScript 内存技术 前端开发
11.4、Libgdx的音频之录制PCM音效
(官网:www.libgdx.cn) 可以通过AudioRecorder接口访问PCM数据。通过如下方式创建一个接口实例: AudioRecorder recorder = Gdx.audio.newAudioRecorder(22050, true); 如果不能创建设备,将会抛出一个GdxRuntimeException异常。
1113 0