image01 image01 image01 image01 image01 image01 image01 image01

公司动态

当前位置:首页 > 公司动态 > 正文
游戏音频中间件FMOD介绍
作者:admin 时间:2016-11-08 浏览:56次

游戏音频中间件FMOD介绍



. 现在的游戏开发引擎内置了Audio功能,并且底层也是用FMOD来实现的。为什么还要不辞辛苦地学习FMOD插件,来进行音效管理呢?

之所以还要使用FMOD插件,是因为当游戏运行时,音效设计师可以使用它的界面进行编辑、混合及处理游戏。例如,当你使用FMOD studio后,你能够创建一个脚步声事件,它能够随机选定声音样本,而游戏本身除了事件名以外,不需知道其他内容。可以使用免费版本的FMOD,是因为它不含有商业目的。当然,用于商业场合的FMOD插件,它的价格也是物超所值的。
大多数的商业化游戏有超炫的音效设计和集中化的音效管理方法,要么使用了FMOD WWise或是其他自定义工具。Unity确实在音效中使用了fmod,但它并不提供任何混合工具。如果音效设计师不得不在Unity编辑器中管理成百上千个音效对象,那么他肯定会发狂。FMOD Studio integration的主要限制是其只能在iOS, , Windows, Mac平台上运行,无法在web player上运行。如果你想让你的声音也可在web player中运行,我建议你查看Clockstone Audio Toolkit,它提供了混音和Unity的内置声音系统的顶级处理。

. FMOD的基本使用过程
FMOD的使用过程比较简单,复杂之处在于FMOD Studio的使用,音效资源编辑完成后的使用较为简单。具体流程,请参见下图:


1. 使用FMOD Studio编辑器编辑原始音效资源,创建各种音效;
2.
导入Unity Game Project
3.
通过FMOD PluginAPI进行播放

. 简单事例FMOD Studio部分:
1. 下载FMOD Studio
2.
打开FMOD Studio即创建一个新工程,Ctrl + S 确定工程保存位置;
3. Window->Audio Bin
打开Audio Bin窗口,用于选择工程需要的声音文件,File->Import Audio Files选择工程需要的声音文件;
4. FMOD Studio
中左侧面板Event Tab栏中,右击选择New Event,表示创建一个新的音效(下图创建了一个test音效);

http://img.manew.com/data/attachment/forum/201412/25/170010s7lss0wk1vw74m44.jpg.thumb.jpg

5. 将Audio bin面板中的将音效文件拖到FMOD StudioAudio 1中,如下图所示,拖入了两个声音资源进去组成了一个音效:

http://img.manew.com/data/attachment/forum/201412/25/170017xbqgh8htznlzfgue.jpg.thumb.jpg

6. 右击test Event,选择Assign to Bank->Master bank
7. Ctrl + s
,然后File->Build,然后File->Export GUIDs

Unity部分:
1. 下载fmodstudio10402.unitypackage,并导入Unity,此时菜单栏会多出一个FMOD选项;
2. FMOD->Import Banks
,打开刚刚FMOD Studio创建的工程的Build目录,Import的资源会在Assets/StreamingAssets目录下;
3.
选择Main Camera,然后选择Component->Scripts->FMOD Listener
4.
创建一个Empty GameObject,然后Create And Add一个Script,附加如下代码内容,即可实现播放音效

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

using UnityEngine;

using System.Collections;

using FMOD.Studio;

public class TestFMOD : MonoBehaviour {

FMOD.Studio.EventInstance testInstance;

string snd = "event:/test";

// Use this for initialization

void Start () {

testInstance = FMOD_StudioSystem.instance.GetEvent(snd);

if (testInstance != null)

{

testInstance.start();

}

}

}



四、参数详解
FMOD Studio工程
FMOD Studio工程中,所有的声音文件都是以Event的形式存在的,这些Event都是通过字符串的形式进行表示。目前对FMOD Studio工具的使用只是创建一个简单的Event,在FMOD Studio的安装目录中有文档可以参考。
是否是STREAM类型:

http://img.manew.com/data/attachment/forum/201412/25/173123z01eqca1m4dmh6q4.jpg.thumb.jpg

音效是否loop

http://img.manew.com/data/attachment/forum/201412/25/173144grmp9rem9dr5x70d.jpg.thumb.jpg

EventInstance参数

http://img.manew.com/data/attachment/forum/201412/25/173503wc70kt2775y2kve7.jpg.thumb.jpg

position:决定音量,距离越远,音量越小;
velocity: 决定音高,速度越快,音量越大。
注意:需要封装的其实只有两个内容,一个是更新EventInstance.updateAttribute方法,FMOD的实现在其中不停的获取Transfrom Component,这是效率很低的地方,可以提供一个只需要Tranform参数的方法来供调用;另一个提供Play方法,供外部进行调用,参数是Event即可。

以前出现过的问题
连续播放多个声音的时候,后面的声音将前面的声音打断。初步估计是以为当时的系统中使用了对象池,每次都是从对象池中进行取得EventInstance,而不是创建新的。实际上如果对同一个EventInstance进行重复调用start函数时,会从头开始重新播放。例子中的声音文件播放的时长为2.6s,没有出现后面的声音阻断前面的声音的情况。

[C#] 纯文本查看 复制代码

?

1

2

3

4

5

6

7

8

IEnumerator Play2Sound()

{

for(int i=0; i<2; ++i)

{

EventInstance instance = FMOD_StudioSystem.instance.GetEvent(snd);

instance.start();

yield return new WaitForSeconds(1f);

}

}


而这个例子中,重复的start则会将上次的声音打断

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

IEnumerator Play2Sound()

{

for(int i=0; i<2; ++i)

{

if (null == testInstance)

{

testInstance = FMOD_StudioSystem.instance.GetEvent(snd);

}

testInstance.start();

yield return new WaitForSeconds(1f);

}

}


一个音乐多次重复播放的时候容易出现刺刺的声音。测试代码如下:

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

IEnumerator TestLargetScaleSnd()

{

while (true)

{

for(int i=0; i<26; ++i)

{

EventInstance instance = FMOD_StudioSystem.instance.GetEvent(snd);

instance.start();

yield return new WaitForSeconds(0.1f);

}

}

}


[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

IEnumerator TestLargetScaleSnd()

{

//while (true)

{

for(int i=0; i<5; ++i)

{

EventInstance instance = FMOD_StudioSystem.instance.GetEvent(snd);

instance.setCallback(callbackFunc);

instance.start();

yield return new WaitForSeconds(0.1f);

}

}

}

RESULT callbackFunc(EVENT_CALLBACK_TYPE type, IntPtr eventInstance, IntPtr parameters)

{

return RESULT.OK;

}


五、实践总结
FMOD的已知实验总结出以下三点:
1. Project只需要使用FMOD.Studio.EvenInstance就可以了,Unity Project中不需要对EventInstance的内存池管理,只需要对它的position属性进行管理;
2. 我们还需要一个封装的接口来提供声音的播放,这个接口为void Play(string snd);
3. _3D_ATTRIBUTES用于设置EventInstance的属性,我们设置的属性目前只有position属性,而这个属性由于需要随着角色的移动而更新,因此需要频繁调用。而_3D_ATTRIBUTESto3DAttributes方法每次都要去取GameObjectTransform,消耗较大,因此我们需要封装一个to3DAttributes(Transform)方法,根据缓存的Transform来进行。

to3DAttributes方法的封装如下:

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

public class FModUtils

{

static public _3D_ATTRIBUTES to3DAttributes(Transform go)

{

FMOD.Studio._3D_ATTRIBUTES attributes = new FMOD.Studio._3D_ATTRIBUTES();

attributes.forward = UnityUtil.toFMODVector(go.forward);

attributes.up = UnityUtil.toFMODVector(go.up);

attributes.position = UnityUtil.toFMODVector(go.position);

if (go.rigidbody)

attributes.velocity = UnityUtil.toFMODVector(go.gameObject.rigidbody.velocity);

return attributes;

}

}


总结:12则通过封装一个FModCom即可,需要播放声音的GameObject需要挂接这个脚本,并在需要播放声音的时候调用其中的Play接口,代码如下:

[C#] 纯文本查看 复制代码

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

using UnityEngine;

using System.Collections;

using System.Collections.Generic;

using FMOD.Studio;

using com.morefun.kl;

public class FMODCom : MonoBehaviour {

[HideInInspector]

public float updateTime = 0.5f;

private Listm_soundList;

private Transform m_trans;

void Awake()

{

m_trans = this.transform;

m_soundList = new List();

}

// Use this for initialization

void Start () {

StartCoroutine(updateSnd());

}

// 播放声音接口

public void Play(string snd)

{

EventInstance sndEvent = FMOD_StudioSystem.instance.GetEvent(snd);

if (null == sndEvent) return;

sndEvent.set3DAttributes(FModUtils.to3DAttributes(m_trans));

sndEvent.start();

addToUpdateAttribute(sndEvent);

}

IEnumerator updateSnd()

{

while (true)

{

PLAYBACK_STATE state;

//stopped的音效从soundList中删除

//在循环中要删除对象,因此不能用foreach

for (int i = 0; i < m_soundList.Count; ++i)

{

EventInstance eventIns = m_soundList[i];

eventIns.getPlaybackState(out state);

if (PLAYBACK_STATE.PLAYING == state)

{

eventIns.set3DAttributes(FModUtils.to3DAttributes(m_trans));

}

else if (PLAYBACK_STATE.STOPPED == state)

{

m_soundList.RemoveAt(i);

i--;

}

}

yield return new WaitForSeconds(updateTime);

}

}

void addToUpdateAttribute(EventInstance value)

{

if (!m_soundList.Contains(value))

{

m_soundList.Add(value);

}

}

}


工程使用FMOD的过程如下:1. Main CamereAttach一个FMOD Listener脚本(Component->Scripts->FMOD_Listener;2. 需要播放音效的GameObjectAttach FModCom脚本,需要播放音效的时候调用FModCom.Play接口。

Channel游戏音乐

快速链接

公司介绍

联系我们

欧美游戏音乐试听

中国游戏音乐试听

Q版休闲音乐试听

游戏音效试听

特价游戏音乐

Channel新闻