运用Directsound编制程序完成实时混音
2012-02-13 10:09
351 查看
摘要:将多个音频文件或多路音频数据同时输出到音频输出设备上,就可同时听到多个不同的声音,这就是混音。在游戏开发,网络视频会议开发中都会用到混音技术,本文详细介绍如何利用Directsound实现几路不同的音频进行实时的混音。 关键词:Directsound 混音 在游戏开发中比较常用的音效素材都是比较短的,所以一般常用的API是playsound()函数,比如我们要在游戏背景中播放一个test.wav音效素材,只要简单的调用下面的函数即可
在网络视频会议开发中,如果不同的客户端同时发言,如何将多个不同端点的话音数据经网络传输到达某一个端点,经该端点的Wave设备输出,能同时听到多个人的话音,从而实现局域网络中多方的话音交谈,这也需要用到混音技术。 在网络上实现话音交谈,特别强调实时性,要尽量保证话音的平滑、连续,因此为了保证话音数据连续,减少话音数据存储带来的延时,在具体实现中,话音的录制和播放都不采用文件的形式,录制和播放的话音数据都存在缓冲区中。在Windows系统中,一般情况下,高层Wave接口函数无法直接播放缓冲区中的话音数据,而必须用底层函数来实现,常用的是Windows API中的Wave函数。将Wave数据在Wave设备上输出使用的是WaveOutWrite函数,但是该函数不支持多路Wave数据的同时播放,为了能达到多路Wave数据同时播放的效果,对缓冲区中多路Wave数据进行必要的预处理后,再提交给Wave输出设备播放,实现原理如图1所示。 图1 多路Wave混音的实现原理 这种混音的方式效果跟你采用的算法有很大关系,但是如果我们采用Directsound进行混音,就简单多了,我们只需要将我们要混音的内容传给它,Directsound会在内部自动进行混音的。下面我们就进入Directsound混音编程。 在了解Directsound如何混音前我们先来看看DirectSound是如何播放一段wave音频的。 这里只是简单的介绍一下播放声音的步骤。 第一步,创建一个设备对象。 在你的代码中你可以通过调用DirectSoundCreat8函数来创建一个支持IDirectSound8接口的对象,这个对象通常代表缺省的播放设备。当然你可以枚举可用的设备,然后将设备的GUID传递给DirectSoundCreat8函数。 注意,Directsound虽然基于COM,但是你并不需要初始化com库,这些Directsound都帮你做好了,当然,如果你使用DMOs特技,你就要自己初始化com库了,切记。 第二步,创建一个辅助Buffer,也叫后备缓冲区 你可以通过IDirectSound8::CreateSoundBuffer来创建buffer对象,这个对象主要用来获取处理数据,这种buffer称作辅助缓冲区,以和主缓冲区区别开来,Direcsound通过把几个后备缓冲区的声音混合到主缓冲区中,然后输出到声音输出设备上,达到混音的效果。 第三步,获取PCM类型的数据 将WAV文件或者其他资源的数据读取到缓冲区中。 第四步,将数据读取到缓冲区 你可以通过 IDirectSoundBuffer8::Lock.方法来准备一个辅助缓冲区来进行写操作,通常这个方法返回一个内存地址,见数据从你的私人buffer中复制到这个地址中,然后调用IDirectSoundBuffer8::Unlock. 第五步,播放缓冲区中的数据 你可以通过IDirectSoundBuffer8::Play方法来播放缓冲区中的音频数据,你可以通过IDirectSoundBuffer8::Stop来暂停播放数据,你可以反复的莱停止,播放,音频数据,如果你同时创建了几个buffer,那么你就可以同时来播放这些数据,这些声音会自动进行混音的。 看到了吧,Directsound混音很简单,我们只要在一个设备上创建几个辅助的缓冲区,然后将数据读取到缓冲区中,同时的播放,Directsound就会自动在主缓冲区自动混音的。至于同时可以播放几个辅助缓冲区则有硬件设备的性能决定。 在WDM驱动模式下,混音的工作由核心混音器来完成,不同的辅助缓冲区可能具有不同的WAV格式(例如,不同的采样频率),在必要的时候,辅助缓冲区的格式要转换成主缓冲区,或者核心混音器的格式。 在VXD驱动模式下,如果你的辅助缓冲区都采用相同的音频格式,并且硬件的音频格式也和你的音频格式匹配,此时,混音器不用作任何的转换。你的应用程序可以创建一个主缓冲区,然后通过IDirectSoundBuffer8::SetFormat来设置硬件的输出格式。要注意,只有你的协作度一定要是Priority Cooperative Level.,并且,一定要创建辅助缓冲区前设置主缓冲区,DirectSound会将你的设置保存下来。 在WDM模式下,对主缓冲区的的设置没有作用,因为主缓冲区的格式是由内核混音器来决定的。 下面开始吧,让我们看看如何进行混音吧,假设我们的背景需要混音的素材是下面的三个wave文件,"test1 .wav" "test2.wav" "test3.wav"。首先定义一下我们需要的几个变量:
首先初始化Directsound
在Priority层次的协作度下,应用程序可以有优先权使用硬件资源,比如使用硬件进行混音,当然也可以设置主缓冲区的媒体格式,游戏程序应该采用这个层次的协作度,这个层次的协作度在允许应用程序控制采用频率和位深度的同时,也给应用程序很大的权力,这个层次的协作度允许其他应用程序的声音和游戏的音频同时被听到,不影响。 下面的函数加载wave文件,然后将音频数据读取到缓冲区中,然后通过Directsound创建了的静态辅助缓冲区,将音频数据copy到Directsound的静态辅助缓冲区,然后就可以play了。
上面创建的就是得静态的buffer,如果你要播放比较长的音频文件,你就要使用streaming buffer了。流缓冲区用来播放那些比较长的声音,因为数据比较长,没法一次填充到缓冲区中,一边播放,一边将新的数据填充到buffer中。 可以通过IDirectSoundBuffer8::Play函授来播放缓冲区中的内容,注意在该函数的参数中一定要设置DSBPLAY_LOOPING标志。 通过IDirectSoundBuffer8::Stop方法中断播放,该方法会立即停止缓冲区播放,因此你要确保所有的数据都被播放,你可以通过拖动播放位置或者设置通知位置来实现。 将音频流倒入缓冲区需要下面三个步骤 1、确保你的缓冲区已经做好接收新数据的准备。你可以拖放播放的光标位置或者等待通知 2、调用IDirectSoundBuffer8::Lock.函数锁住缓冲区的位置,这个函数返回一个或者两个可以写入数据的地址 3、使用标准的copy数据的方法将音频数据写入缓冲区中 4、IDirectSoundBuffer8::Unlock.,解锁 IDirectSoundBuffer8::Lock可能返回两个地址的原因在于你锁定内存的数量是随机的,有时你锁定的区域正好包含buffer的起始点,这时,就会给你返回两个地址,举个例子吧 假设你锁定了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中。
好了,关于Directsound的混音我就简单介绍到这里,下一篇文档我会介绍一下,如何用Directsound 生成3D声音。 |
相关文章推荐
- ASP编制程序完成迅速查询
- 通过注册表完成文件名后缀与运用程序相关联
- 利用Directsound编程实现实时混音
- 利用Directsound编程实现实时混音
- DirectSound编程实现实时混音
- 利用Directsound编程实现实时混音
- 用ASP编制程序完成迅速查询
- 利用Directsound编程实现实时混音
- 编制一个完成两个数的四则运算程序。如:用户输入34+56则输出结果90.00。要求运算结果保留两位小数,用户输入时一次将两个数和操作符输入。
- 利用Directsound编程实现实时混音
- 已知三个无符号数a,b,c,存放在ADR开始的连续单元,编制完成下列操作的程序:若a,b,c同时为偶数,将FLAG单元置1,若同时为奇数,FLAG置0,否则为全1
- 利用Directsound编程实现实时混音
- 多线程在Visual C#网络编制程序里面地运用
- 利用Directsound编程实现实时混音
- 通过DirectSound实时播放PCM+混音
- VC编制程序完成文本语音转换
- 最近完成的足球比赛实时采集和分析程序
- python写的树莓派实时监控温度,cpu使用率的小程序
- 一个有用的Windows服务小程序——用来完成Server端的Socket通信
- 编制程序将AL中的第i,i+1位写入MEM单元的第i,i+1位,其他位不变