科技行者

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

知识库

知识库 安全导航

至顶网软件频道基础软件利用Directsound编程实现实时混音

利用Directsound编程实现实时混音

  • 扫一扫
    分享文章到微信

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

将多个音频文件或多路音频数据同时输出到音频输出设备上,就可同时听到多个不同的声音,这就是混音。

作者:李强 来源:天极开发 2007年10月16日

关键字:

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

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

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

  3、偏移量为0的地址

  4、从起始点开始的字节数,也就是10,000字节,你要将这个字节数的内容写入第二个地址。

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

  当然,你也有可能锁定buffer的全部内存,建议你在播放的时候不要这么做,通过你只是更新所有buffer中的一部份,例如,你可能在播放广标到达1/2位置前要将第一个1/4内存更新成新的数据,你一定不要更新play光标和Write光标间的内容。

  下面的这个函数演示了如果向streaming buffer中填充音频数据,在调用这个函数之前,你一定要确保你的streaming buffer是空的,但如何知道buffer是空闲没有数据呢?一个更有效的方法采用通知机制,通过IDirectSoundNotify8::SetNotificationPositions方法,你可以设置任何一个小于buffer的位置来触发一个事件,然后响应处理函数中调用下面的函数将音频数据copy到Directsound的Streaming buffer中。

BOOL AppWriteDataToBuffer(
 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)
  {
   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;
}

  将音频数据复制到Directsound 的辅助缓冲区中,剩下的工作就是play buffer了,play很简单的,只是简单地调用Buffer提供的Play函数就可以了,复杂的工作Directsound会替我们做好的。

void Play(LPDIRECTSOUNDBUFFER lpdsbStatic)
{
 if ( lpdsbStatic == NULL ) return;

 lpdsbStatic->SetCurrentPosition(0);
 lpdsbStatic->Play(0,0,0);
}

  现在混音的主要代码已经完成,你可以用下面的代码来对三段wave文件进行实时混音了。

Void StartMixer()
{
 InitDirectSound();
 g_pDsbuffer[0] = LoadWaveFile("test1.wav");
 g_pDsbuffer[1] = LoadWaveFile("test2.wav");
 g_pDsbuffer[2] = LoadWaveFile("test3.wav");
 Play(g_pDsbuffer[0]);
 Play(g_pDsbuffer[1]);
 Play(g_pDsbuffer[2]);
}

  现在就可以同时听到三段wave音频了,利用Directsound进行混音是不是很简单啊,这里要提醒一下,如果你想将Directsound的混音用到网络视频会议中,你就要做一些额外的工作了,现在的网络视频会议系统一般都是用Directshow技术开发的,因为在Directshow用播放音频的都是通过一个filter来访问声卡的,所以你可以将DirectSound封装成一个filter,然后将这个filter加入到你的Graph图表中。

  好了,关于Directsound的混音我就简单介绍到这里,下一篇文档我会介绍一下,如何用Directsound 生成3D声音。

查看本文来源

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

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

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