作者littleshan (我要加入剑道社!)
看板GameDesign
标题[音乐] FMOD 快速上手
时间Sat Dec 30 16:00:02 2006
好像很少人讨论到声音这一块,因此我就献丑了。下面所说的是我使用
FMOD 第一天的小小成果,因为我并没有声音方面的专业知识,如有错误
请多多指教。
* * *
声音一向是游戏中不可或缺的一部份,不管是动人的背景音乐或营造气
氛的音效,少了声音就完全没有玩游戏的感觉,甚至许多游戏的重点就
放在声音上,比如说利用声音来判断敌人的位置等等。
从游戏开发者的角度来看,在声音方面至少有以下的需求:
1. 读取音乐/音效档案。当然,音乐资料不一定存在档案上,也可能
放在 CD 音轨上,甚至使用 streaming 的方式由网路传输(很少
见,但也并非不可能)。
2. 背景播放。除了把声音放出来,播放的同时也要能让游戏继续执行。
3. 混音。对於硬体来说,同一时间只能播放一个声音。有些硬体内建
混音的功能,因此可以同时播放多道声音,不过数量还是有上限。
超过上限时就需要把所有正在播出的声音进行混合後,再送到音效
卡上。
(在 Windows 上,送到音效卡之前似乎会自行帮你混音,所以这点
对 Windows 开发者也许不是太大的问题)
4. 各种声音效果,比如设定声源的位置以模拟方向与远近的不同,或
是设定速度来模拟运动物体的都卜勒效应 (Dopplar effect),甚至
各种 DSP 处理等等。
而我今天要讲的,称之为 FMOD 的音效函式库,正具备了以上所有功能。
除此之外,它也有跨平台的优点,除了 Windows 外,也支援 MacOS、
Linux 甚至所有的次世代主机,如 PS3、Xbox 360、Wii 等等。而且在
非商业用途下完全免费,是个很理想的音效解决方案。
废话不多说,下面就来讲 FMOD 的使用。
* * *
在 FMOD 中主要有三种物件:System、Sound 以及 Channel。因为我才
用一个晚上而已,所以像是 ChannelGroup、DSP 及 Geometry 的部份
就不深入了...
* System 管理与系统相关的工作,比如说从档案系统中读取声音檨本、
设定输出的音效卡(FMOD 可以同时控制多张音效卡)、设定 DSP
buffer 大小、或是载入其它的 plug-in 等。
* Sound 则是一段声音的样本 (sample),已经准备好送往音效卡播出。
Sound 的内部格式可能有三种:无压缩、压缩或串流:
* 无压缩 最单纯的格式,直接把所有资讯存在记忆体中,播放
时几乎不需要 CPU 资源,但也很吃记忆体。适合长度
短、会重覆播放许多次的音效。
* 压缩 如果使用 mp3 或 ogg 之类的格式储存声音,可以把
资料以尚未解压缩的方式先读进记忆体中,播放时再
即时解压缩。这会需要多一点 CPU 资源,但可以减少
记忆体用量,适合中等长度的声音。
* 串流 在串流模式下,读取和播放是同时进行的,而记忆体
中只会保留一小部分的样本,因此几乎不吃记忆体,
但缺点是无法重覆播放,必需重开档案或重新连线才
能再播放一次。适合很长的背景音乐或是由网路传输
的声音。
* Channel 代表正在播放声音的实体。对於 Channel,你可以设定它
的音量、播放的时间点、或是它在 3D 空间中的位置与速度。一个
Channel 只能播放一个 Sound,但同一个 Sound 可以让由不同的
Channel 共享并同时播放。
马上就来写一个简单的音乐播放程式。
* * *
一开始我们要先产生一个 System 物件,这可以用 FMOD_Create_System
达成:
FMOD_SYSTEM* sys;
FMOD_RESULT r = FMOD_Create_System(&sys);
if(r != FMOD_OK){
cerr << "Unable to create FMOD system: "
<< FMOD_ErrorString(r) << endl;
exit(1);
}
所有 FMOD 的函式都会传回 FMOD_RESULT 作为结果,我们可以检查它是
否等於 FMOD_OK 来判断是否有错误发生。为了简单起见,下面的 code
中我会把这些检查省略。(开始写游戏时可别省啊!)
接下来是对 System 初始化,并且载入一段 mp3 声音:
FMOD_System_Init(sys, 32, FMOD_INIT_NORMAL, 0);
FMOD_SOUND* sound;
FMOD_System_CreateSound(sys, "test.mp3", FMOD_DEFAULT, 0, &sound);
在 FMOD_System_Init 中,第一个参数是先前产生的 System 物件,第
二个 32 则表示这个系统最多可以有 32 的 Channel,也就是最多可以
同时播放 32 道声音。第三和第四个参数可以设定一些进阶的选项,在
这个例子中都使用预设值即可。
而 FMOD_System_CreateSound 则会产生一个 Sound 物件。第一个参数
同样是 System,第二个则是我们要载入的声音档名称,FMOD 会自行判
断档案格式并把它解压缩。如果想用压缩或串流的方式读档,则需要设
定第三个参数,这边我们就先使用预设值。
最後就是把声音放出来:
FMOD_CHANNEL* channel;
FMOD_System_PlaySound(sys, FMOD_CHANNEL_FREE, sound, 0, &channel);
FMOD_System_PlaySound 会让某个 channel 开始播放声音。其中第二个
参数可以指定我们要拿哪一个 Channel 来播放,传入 FMOD_CHANNEL_FREE
则是叫 FMOD 自行找一个可使用的 Channel 来播放。
但,程式并非到此就结束,别忘了声音播放是在背景执行的,如果在这
边就结束程式,声音也会马上停止。因为这只是个简单的播放程式,因
此只要进入一段回圈等声音播完即可:
FMOD_BOOL playing = 1;
while(playing){
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
FMOD_Channel_IsPlaying(channel, &playing);
FMOD_System_Update(sys);
}
我使用了 unix 上的 usleep,因此回圈中的程式码每 0.01 秒会执行一
次。Windows 上则改用 Sleep。
FMOD_Channel_IsPlaying 可以拿来检查 Channel 是否已经放完全部的
声音,因此声音播放完就可以跳出回圈。FMOD_System_Update 则是更新
System,包括呼叫 callback 或是设定声音的 3D 位置等。在这例子中
可能不太重要,但若使用到其它功能时就一定要呼叫 update 了。
最後播放完,则使用 FMOD_Sound_Release 与 FMOD_System_Release 释
放系统资源:
FMOD_Sound_Release(snd);
FMOD_System_Release(sys);
这麽一来这个简单的播放程式就完成了!接下来我们加上一点 3D 效果
吧。首先我们要在建立 Sound 时指定 3D 的功能:
FMOD_System_CreateSound(
sys,
"test.mp3",
FMOD_LOOP_OFF | FMOD_3D | FMOD_HARDWARE,
0,
&sound
);
这边看起来有点复杂,但其实只是指定这个声音并不重覆播放 (FMOD_LOOP_OFF)、
加入 3D 效果 (FMOD_3D) 以及使用硬体加速 (FMOD_HARDWARE)。先前所
使用的 FMOD_DEFAULT 其实只是把 3D 改成 2D 而已,其它选项完全相同。
接下来我们可以用 FMOD_Channel_Set3DAttributes 来设定 Channel 在
空间中的位置及速度:
FMOD_VECTOR pos;
pos.x = 0.0f;
pos.y = 0.0f;
pos.z = 2.0f;
FMOD_Channel_Set3DAttributes(channel, &pos, NULL);
第二个参数即为位置,使用者预设是位於 (0,0,0) 的地方,前方为正Z
轴,左方为正X,上方为正Y。第三个参数则是速度,如果不需要模拟
都卜勒效应,给 NULL 即可。
上面的程式码会把音源放在使用者前方两个单位的位置。当然,如果声
源不会移动,就没有意思了:
while(playing){
#ifdef WIN32
Sleep(10);
#else
usleep(10000);
#endif
FMOD_Channel_IsPlaying(channel, &playing);
unsigned int msec;
FMOD_Channel_GetPosition(channel, &msec, FMOD_TIMEUNIT_MS);
float angle = 3.1415926f * msec / 4000.0f;
pos.x = 2.0f * sin(angle);
pos.z = 2.0f * cos(angle);
FMOD_Channel_Set3DAttributes(channel, &pos, NULL);
FMOD_System_Update(sys);
}
这边我们会让声源绕着使用者转圈圈,使用 FMOD_Channel_GetPosition
可以得到目前播放的时间点,由这个时间乘上速度(八秒钟一圈,也就
是四秒钟所转动的弧度为 PI),即可得到转动角,再套上 sin/cos 就
可以得到新的位置了。
完整的程式码如下:
http://nopa.csie.org/bd9c9
完整程式加了一些错误处理,并且使用命令列参数当作播放档案。执行
时要先等一段时间(因为使用非压缩的方式),然後应该能听到声音在
绕着使用者转圈圈。
* * *
FMOD 在使用上还满简单的,复杂的解压缩、混音、硬体控制等全部都被
包装起来,因此游戏制作人员不需要再花额外的功夫处理。唯一不满的
地方就是它的 C++ interface 实在设计不良,完全没有用到 C++ 威力
(连 OOP 都沾不上边),这也是为什麽我都使用 C interface 的原因:
两者并没有明显的不同。
撇开这不谈,FMOD 功能够强、跨平台又免费,的确很适合制作游戏。当然
早有许多商业或免费游戏使用 FMOD 来播放声音。
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 61.62.3.35
※ 编辑: littleshan 来自: 140.112.29.131 (12/30 17:14)
1F:推 rigeltrue:这篇赞 推~ 12/30 17:16
2F:推 yoco315:感谢前辈的分享 12/31 04:22
3F:推 Attui:推 期待您的下一篇 12/31 11:13
4F:推 doomleika:刚刚查了一下,如果商业话化的话要3000USD ._.a 12/31 20:50
5F:推 meltice:便宜啊 你找个programmer付他3000USD还不见得写的出FMOD 01/01 00:10
6F:推 doomleika:也是._.a 01/01 20:22
7F:推 whereweare:push!!! 01/02 11:29
8F:推 moonjustin:push! 04/06 23:29