热门文章
阿标在线 动力3.62HTML生成3.62网站文件说明
动力3.62整合动网7.0 SP2插
MDAC2.8 下载!
动力3.62版 防止垃圾留言
动力3.6全方位改动方法
让3.62不同频道实现不同风
把3.62首页登陆为横向代码
动易3.6首页随机FLASH修改
362首页和文章频道页图文幻
个性化修改3.6宝典
3.62轻易实现网摘功能
如何正确统计中文字数?
弹出JAVASCRIPT语法错误对
后台使“网站顶部LOGO地址
最新图片文章横向移动的修
html 生成艺术字
3.6 Sp2 Logo和Banner及广
日期值的计算
汉字转拼音
首页“图片更新”图片滚动
简体中文转换为繁体中文的
如何在css中定义链接的下划
VB.NET实现DirectSound9 (8) 音效控制器
[ 录入:阿标 | 点击数: | 更新时间:2005-3-12 9:18:00]
关键字: DirectSound 9 VB.NET DirectX 声音控制 声音引擎 作者:董含君
转载请注明来自 http://blog.csdn.net/a11s
目的:制作一个声效控制器,减少内存占用量,封装directsound,低CPU消耗,满足人的实际需要,以及易用性提高.
本来不打算继续的,前几天跟denghe研究了一下相关的问题.讨论到太多的音效对机器的影响,尤其是内存占用以及释放.发现有必要做一个专门管理音效的控制器.
由于跟denghe的制作目的不同,所以实现起来大相径庭.他全部都要实现gameobject接口,对于游戏来说,这是可行的.但是我做控制器的目的并不仅仅是用于游戏.而是更加像是提供一个处理声音的服务.我还不敢称它为声音引擎.毕竟可以实现的功能还比较少.
问题的出现
1 当你打算播放音效的时候(就是wav),你可以new buffer(filename , ....) 这个我们都知道的. 但是new 之后,整个wav将会被装入内存.我们称之为静态载入.当你进攻敌人的时候,比如子弹的音效或者刀剑的音效.很多都是重复的.这时,你可以用刚才new 出来的 buffer 直接 play.
2 问题如果这么简单我就没有必要写此文了.当一个声音没有播放完成,另外一个重复的声音接着响起的时候,很显然不能直接play了,那么你怎么办?先stop它然后重新从头开始播放?很显然,也不行.那么直接再new 一个可以了吧.当然可以,除非你自己做混音(需要很多声学的知识,以及数学),否则只能使用两个buffer不同时间同时播放的方法.
3 看似解决了问题.我们把问题继续推广到多个音效(wav),以及大量重复播放的时候.用问题2的解决办法 new 出大量的buffer 就会出现问题了. 不但管理起来十分复杂,而且他会消耗掉恐怖的内存.并且你的系统资源开销非常可观. 看似这样的现象再游戏中是很容易出现的. 所以迫切需要一种管理方法应对这种现象.
于我不同的是,denghe提供了一个SoundPool方案,就是依赖游戏的脚本引擎.管理wav文件的载入以及卸载.每个有效的wav在每个场景载入的时候就创建多个备份,你可以给每个wav建立一定数目的缓冲buffer.比如建立4个,然后根据需要自动指向下一个.然后在4个之间循环.对于较短的音效而言,完全可以满足人类听觉的需要.所以对于游戏来说可以从根本上解决内存的无限浪费的局面,而且每种音效都不互相干扰..只要有可靠的脚本引擎负责加载以及释放即可.所需的总空间为 文件的总占用体积+ 每个文件的buffer数量*该文件的大小,实际上很多音效是与用户交互的,所以没办法预料某些音效的实际频率.做最坏的打算,你付出的实际内存=wav文件的个数*buffer数量.对于所需音效数量较小的程序来说,可以符合要求.但是某些较大的场景也许付出的代价需要重新考虑了.但是这个方案对游戏来说是比较好的方案.
4 我的解决方案:
4.1 建立Layer: 在我看来,声音可以分层次的.比如一个格斗游戏.Player1说得话,可以放在Layer1. Player 说的话可以放在Layer2,格斗时的声效--就是那些噼里啪啦的声音 可以放在Layer3 , 场景开始的时候 "Ready GO",以及"K.O." 都可以放在Layer4
4.2 建立Layer缓冲区:这样分类完成之后,你会发现,如果Layer之间相互影响是不合适的,但是Layer内部,人说话的时候,如果同时出现两句话是不是就有点不自然了?? 或者打斗的时候,那些噼里啪啦的声音过于常见,而且比较短.人们热火朝天的时候,不会可以在乎是否刚才的已经播放完?? 把这些互斥的因素放在一个同一个Layer里面是符合实际需要的.
4.3 建立步骤:
为了适应速度的需要,所以不能考虑再游戏进行的时候从硬盘加载.所以一开始就要全部加载到内存.播放的时候由于每个wav只有一个buffer,所以需要动态的创建副本进行播放.副本的管理可以交给控制器.比如play 方法.play( SoundKey,targetLayer)
4.4 性能分析: 主要是内存占用. 所需内存= 每个文件的大小的和 + Layer的数量*每个Layer中Buffer的数量
这些都是可控的,当然buffer越大,效果越好,而Layer往往是根据实际需要一开始就确定好的,所以内存使用可以稳定在一个数值,值得庆幸的是,这个数值是可控的,甚至可以根据计算机的内存容量临时改变buffer的数量(呵呵,一般不会有人会这么想的)
5 关键技术问题: 看似上面的想法不错,但是要实行起来,下列问题需要考虑
5.1 如何管理全部的buffer?对于习惯了面向对象的我们也许很少考虑这个问题,你可以用任何的高级手段,甚至想到用dataset.... 不是不可一,但是我比较古典,使用了一个buffer的二维数组,已经够用了.曾经想用arrylist,但是想不出他跟数组相比能给我带来多少实际的优势.
5.2 如何决定在哪个buffer播放? 既然buffer是数组或者其他形式,根据Layer的划分,从属于Layer.我仅仅针对二维数组来说,buffer[tarLayer][tarBuffer] 正好填充二维数组的两个参数.
5.3 既然是循环利用的,如何指定合适的buffer?
这个问题比较复杂,我封装在了控制器内部,用一个枚举的办法指定一个合适的buffer,一下是步骤
function enumBuffer(tarLayer as integer) as integer 传递过来要使用那个layer,返回合适的bufferID
a.循环检查当前layer是否有空闲的buffer,如果还有为nothing 或者 null 的buffer,毫无疑问他将会是最合适的buffer,所以直接退出循环返回他的id
b.如果不满足a,那么看看是否有disposed或者已经stop的buffer,他们已经不再播放了.也是合适的,找到一个之后也就没有必要继续循环,直接返回该ID
c. 如果不满足b,那么遍历当前layer的全部buffer,找到播放时间最长的buffer.播放时间长意味着来到的时间最长.我们可以请他休息了,返回这个id
d.如果满足c的有多个,那么按照第一个返回,或者最后一个返回.
5.4 播放的时候我们要注意什么?
为了节约空间当然要清空 刚才被枚举出来的buffer,然后创建一个wavbuffer列表的一个副本进行播放.
由于这时不能从硬盘得到资料,所以只能考虑用buffer.clone()的方法,或者直接new 一个新的buffer(利用wavbuffer的Stream)
6 具体结构说明
类: XSoundList 实质是一个filestream的hashtable,提供一个关键字,一个filename,创建一个filestream..起到了存储器的作用,将原始资料在这里集合,方便控制器读取
类:XBGMList 跟XSoundList类似,不过这里用来存储较大的文件,不使用静态加载,提供多种格式.用于背景音乐(难道你打算加载CD音轨或者几分钟的wav到内存?太疯狂了)
类:XSoundManEx 控制器.具体管里播放哪一个以及内部缓冲的数量,音量大小等等.也就是对directSound的封装类,使用它可以用layer的思想管理SoundBuffer
类:XSoundMan 标准控制器,由于XSoundManEx使用了太多的DirectSound特性,不符合OOP封装的思想,所以对于普通应用而言,应当使用这个来代替XSoundManEx,除非你打算重新封装原始的Ex.
类:XSoundSimp 简易控制器.只要有一个Layer就够用,超级简单的控制器,第一步加载,第二步播放 没了,已经重写了析构,不必担心泄漏,甚至每次新建一个XSoundSimp也比你直接new 多个buffer 节省内存,而且不必进行DirectSound的初始化
7 附加的功能
声音音量的调整,背景音乐与SoundBuffer的分离处理,动态加载wav(虽然不建议这么做).循环播放.等等,如果不够用可以从XSoundManEx继续封装
8 已知存在的不足以及下个版本的计划.
Layer之间的音量并没有独立,这点有悖于Layer之间的互不干涉.
BGM没有区分Layer,由于设计的时候,判定BGM划分Layer的意义不大.所以设定BGM只有一个Layer.中间使用也是竞争的.虽然用建立较大的BGMbuffer可以环节这方面的不足(没关系,动态加载,内存消耗不是很大).但是对于不了解其中机制的使用者来说会觉得不可思议.而且Layer内部竞争,一旦超出buffer最大值可能会影响背景音乐的使用.比如某些音效体积太大,程序人员将其作为BGM添加,这样看起来节约,但是存在隐患.除非你能确保满足枚举条件b.
9 程序演示以及源代码介绍
第一个简单应用,按下响应的键盘按键会发出音效,可以像弹钢琴一样.(你想做软波表么?)
第二个演示是利用文本驱动声音的播放,可以"录音"哦
第三个演示是频率的重复对内存以及CPU的影响(测试性能),包括背景音乐的播放以及Layer的使用
第四个被我隐藏了,本来做个游戏的.时间不是很多,没有完成,有兴趣的化可以继续完善
10 下载地址暂时无法提供,因为我找不到地方长时间稳定的存放我的代码,大约800k,而且CSDN的Blog暂时不提供rar的上传.需要的话,请加QQ群:589626 C#游戏开发,群的共享里面有rar的下载
==============End================