假设你锁定了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声音。
|