目录
- 3. Core API 指南
- 3.1 什么是 Core API ?
- 3.2 链接的插件
- 3.3 API 功能
- 3.3.1 初始化 - 简单启动,无需配置
- 3.3.2 音频设备 - 设备插入/移除的自动检测
- 3.3.3 音频设备-支持插件
- 3.3.4 文件格式-内置支持超过20音频格式
- 3.3.5 文件格式-支持游戏的最佳格式(FSB)
- 3.3.6 文件格式-插件支持
- 3.3.7 播放一个简单的声音 - `createSound` 和 `playSound`
- 3.3.8 高质量/高效的流和压缩样本
- 3.3.9 流
- 3.3.10 网络流
- 3.3.11 流设置
- 3.3.12 压缩样本回放
- 3.3.13 解压缩样本
- 3.3.14 声音/通道-“虚拟声音”-同时播放数千种声音
- 3.3.15 通道/分组-“通道组”和分层子混合
- 3.3.16 3D声音和空间化
- 3.3.17 基于3D多边形的几何遮挡
- 3.3.18 录音-从麦克风或线路录制声音
- 3.3.19 DSP 效果-支持超过30个特殊效果内置
- 3.3.20 DSP效果-混响类型和3D混响区
- 3.3.21 Standard Reverb 标准混响
- 3.3.22 卷积混响
- 3.3.23 虚拟3D混响系统
- 3.3.24 DSP效果-支持插件DSP
- 3.3.25 DSP引擎-灵活的、可编程的软件合成器架构
- 3.3.26 非阻塞加载、线程和线程安全
- 3.3.27 Performance 性能
- 3.4 配置-内存和文件系统
- 3.5 控制一个空间化DSP
- 3.6 上混 / 降混音行为
- 3.7 高级声音创作
- 3.8 从声音中提取PCM数据
3. Core API 指南
3.1 什么是 Core API ?
FMOD Core API 是一个程序员API,旨在涵盖声音的基础/原语。这包括'Channels'
, 'Sounds'
, 'DSP'
, 'ChannelGroups'
, 'Sound Groups'
, 'Recording'
以及3D声音和闭包等概念。
它是独立的,不需要任何声音设计工具的接口。这些特性都是由程序员用代码实现的。
3.2 链接的插件
你可以通过使用插件来扩展FMOD的功能,每种插件类型(编解码器,DSP和输出)都有自己的API可以使用。无论您是自己开发插件还是使用第三方插件,都有两种方法可以将其集成到FMOD中。
3.2.1 静态
当插件作为源代码提供给您时,您可以通过包含源文件并使用其中一个插件注册api将其连接到FMOD System::registerCodec, System::registerDSP
或者 System::registerOutput
。这些函数中的每一个都接受提供插件功能的相关描述结构。按照惯例,插件开发人员将创建一个函数来为您返回这个描述结构,例如:FMOD_AudioGaming_AudioMotors_GetDSPDescription
是我们一个合作伙伴的命名 (它遵循FMOD_[CompanyName]_[ProductName]_Get[PluginType]Description
的形式)。或者,如果你没有源代码,但你有一个静态库(如.lib或.a),这几乎是相同的过程,将静态库与你的项目链接起来,然后调用描述函数,将值传递给注册函数。
3.2.2 动态
另一种分发插件代码的方式是通过预构建的动态库(如.so, .dll或.dylib),这些库比静态库更容易集成到FMOD。首先确保插件文件位于应用程序的工作目录中,这通常与应用程序可执行文件位于同一位置。在你的代码中调用System::loadPlugin
传入库的名称,这就是它的全部。在底层,FMOD将打开库 搜索类似于上面提到的描述函数,一旦找到插件将注册备用。
3.3 API 功能
本节将给出FMOD核心API特性的概述。
3.3.1 初始化 - 简单启动,无需配置
FMOD Core API有一个自动配置功能,这使得它很容易启动。
在最基本的层次上,创建System对象并在其上调用System::init
。这就是所需要的一切。更详细的初始化描述可以在FMOD核心API入门白皮书中找到。
可以使用System::setDriver
函数手动选择声卡。可以配置更多的设置,例如FMOD系统的混音率,重采样方法或system::setSoftwareFormat
的扬声器模式。当修改混音器设置时,这只会调整内部混音格式。最后,音频流总是转换为用户设置的设置
3.3.2 音频设备 - 设备插入/移除的自动检测
FMOD核心API在播放过程中具有自动声卡检测和恢复功能。如果初始化后插入一个更高优先级的设备新设备,FMOD将无缝跳转到它。这方面的一个例子是插入USB耳机。
如果正在播放的设备被移除(如USB音频设备),它将自动跳转到下一个最重要的设备(即在Windows上,它将是新的“默认”设备)。
如果一个设备被插入,然后被移除,它将跳转到它最初播放的设备。
程序员可以用自定义回调覆盖声卡检测行为。这是FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED
回调。
3.3.3 音频设备-支持插件
FMOD核心API支持用户创建输出插件。开发人员可以创建一个插件,将FMOD音频输出到自定义目标。这可以是一个硬件设备,或者一个非标准的基于文件/内存/网络的系统。
输出模式可以实时运行,也可以非实时运行,这允许开发人员以比实时速率更快或更慢的速度运行FMOD的混频器/streamer/系统。
请参阅System::registerOutput
文档了解更多信息。
插件可以与应用程序内联创建,也可以编译为独立的动态库(如.dll或.so)。
3.3.4 文件格式-内置支持超过20音频格式
FMOD核心API有原生/内建的代码来支持许多开箱即用的文件格式。WAV
, MP3
和Ogg Vorbis
默认支持,但许多更晦涩的格式不支持,如AIFF
, FLAC
和其他。序列格式在实时回放与实时序列器也支持。例如MIDI/MOD/S3M/XM/IT
。
更全面的列表可以在FMOD_SOUND_TYPE
列表中找到。
3.3.5 文件格式-支持游戏的最佳格式(FSB)
FMOD还支持游戏的最佳格式,称为FSB (FMOD Sound Bank
).
许多音频文件格式并不适合游戏。它们效率不高,并且可能导致大量随机文件访问、大量内存开销和缓慢的加载时间。
FSB格式的好处是:
No-seek装载。FSB加载可以连续读取3个文件。1. 读取主标题。2. Sub-sound元数据。3. 原始音频数据。
“内存点”功能。用户可以将FSB加载到内存中,并简单地“指向”,以便FMOD使用它所在的内存,而不分配额外的内存。参见FMOD_OPENMEMORY_POINT
。
低内存开销。许多文件格式包含诸如标签和元数据之类的“无意义”内容。为了提高效率,FSB以压缩、位打包的格式存储信息。
多个声音在一个文件。数千个声音可以存储在一个文件中,并通过API函数Sound::getSubSound进
行选择。
高效的Ogg Vorbis。FSB去掉了“Ogg”,保留了“Vorbis”。1个码本可以在所有声音之间共享,节省了兆字节的内存(与单独加载.ogg文件相比)。
支持FADPCM编解码器。FMOD支持一种非常高效的ADPCM变体,称为FADPCM,它比标准ADPCM解码器(无分支)快很多倍,因此在移动设备上非常高效。质量也远远优于大多数ADPCM变体,并且没有在这些格式中明显的“嘶嘶声”。
3.3.6 文件格式-插件支持
FMOD核心API支持用户创建文件格式插件。开发人员可以为FMOD创建回调函数,以便在用户执行System::createSound
或System::createStream
时调用,或者在解码引擎请求数据时调用。
插件可以与应用程序内联创建,也可以编译为独立的动态库(如.dll或.so)。
请参阅System::registerCodec
文档了解更多信息。
3.3.7 播放一个简单的声音 - createSound
和 playSound
最简单的入门方法和FMOD Core API的基本功能是初始化FMOD系统,加载音频文件,并播放它。就是这样!
参考入门白皮书,了解如何使用FMOD Core API 初始化和加载/播放音频文件。
查看play_sound 示例,以参考简单播放音频文件的示例代码。
3.3.8 高质量/高效的流和压缩样本
FMOD Core API 得益于在数百万终端用户设备中超过15年的使用,使其成为了高度稳定和低延迟的混音/流引擎。
3.3.9 流
流式传输是一种获取大文件并一次以小块实时读取/播放它的能力,避免了将整个文件加载到内存中的需要。这通常用于:
- 音乐
- 旁白/对话
- 长氛围轨道
用户可以通过在System::createSound 函数中添加FMOD_CREATESTEAM标志,或者使用System::createSteam 函数,简单的将声音作为流播放。这两个选项执行的效果一致。
3.3.10 网络流
FMOD 流支持互联网地址。在文件名中提供http或者https将把FMOD切换到使用本地http、广播或者广播的流媒体。
支持播放列表文件(如ASX/PLS/M3U/WAX格式),包括重定向。
支持代理规范和身份验证,以及实时广播流交换、元数据检索和丢包通知。
3.3.11 流设置
流式传输行为可以通过几种方式进行调整。流式传输文件需要两个线程,一个用于文件读取,一个用于编解码器解码/解压缩。文件缓冲区大小可以通过System::setSteamBufferSize
来调整,编解码器解码缓冲区大小可以通过FMOD_CREATESOUNDEXINFO
中decodeBufferSize
成员或者FMOD_ADVANCEDSETTINGS::defaultDecodeBufferSize
来调整。
3.3.12 压缩样本回放
对于较短的声音,用户可能希望在内存中播放音频文件而不是将音频文件解压缩到内存中。
这比流更高效,因为它不需要磁盘访问,也不需要额外的线程来读取或解码。一个流限制一次只能有一个声音,但是压缩样本没有这样的限制。它可以同时播放多次。
如果平台支持如SP4上的AT9或Xbox One上的XMA等硬件格式,那么使用这些编解码器是最好的解决方案,因为数据的解码由单独的媒体芯片处理,将大部分处理从CPU中解放。
关于如何使用FMOD_CREATECOMPRESSEDSAMPLE
标志以及编解码器内存的配置,请参阅入门白皮书。
有关平台特定音频格式的详细信息,请参阅相关平台详细信息部分。
3.3.13 解压缩样本
默认情况下,使用System::createSound
加载音频,使得音频数据被解压缩到内存中,并以PCM格式播放。
PCM数据是原始的未压缩的音频数据,有关更多信息,参阅 Sample Data.
解压缩/未压缩的样本几乎不需要CPU时间来处理。PCM数据与FMOD混音引擎和音频设备本身使用的格式相同。如果在CPU周期有限的移动设备上有足够的内存,这是可取的。
例如,解压缩的PCM数据比Vorbis编码的FSB使用更多的内存,可能达到10倍以上。
移动开发者的一个典型用例是:为了分发而深度压缩音频数据(以减小下载大小),然后在启动/加载时解压缩它,以节省CPU时间,而不是压缩播放。
3.3.14 声音/通道-“虚拟声音”-同时播放数千种声音
FMOD Core 包含一个 “虚拟语音系统”。它允许开发者同时播放数百甚至数千个通道,但只有一小部分真正产生声音。剩余的是“虚拟的”或通过简单的位置更新模拟的,不会被听到,也不会消耗CPU时间。
举个例子:一个地下城可能有200个火把在不同位置的墙上燃烧,但只有最响的火把才会被听见。FMOD将动态的使通道“虚拟”或者“真实”,根据实时可听性计算(基于距离,音量,优先级,遮挡)。
一个正在播放的频道如果很远或者音量很低将会变成“虚拟”,当它变近或者由于调用了Channel或者ChannelGroup API而变得更响。
在虚拟语音白皮书上阅读关于虚拟语音系统的信息。
3.3.15 通道/分组-“通道组”和分层子混合
对通道分组,使得他们能够对他们产生单一的影响,可以通过通常称为“总线”或“子混合”的方式实现。在FMOD Core中,通道被分组到“通道组”中,这与总线或者子混合相同。
可以将效果添加到ChannelGroup中,它只处理多个Channel的子混合结果,而不是处理每个Channel。这大大减少了CPU的使用。
ChannelGroup音量可以被更改,这允许使用主音量组。音量是根据ChannelGroup内的一个调频器DSP进行播放的。所有Channel和ChannelGroup默认都有一个fader DSP。
ChannelGroup是分层的。ChannelGroup可以包含ChannelGroup,ChannelGroup 可以包含其他ChannelGroup和Channel。
许多属性可以应用到ChannelGroup,包括扬声器混合和3D位置。一个完整的频道组,以及他们下面的频道组,可以在一个调用中3D定位,而不是试图单独定位他们。
“主音量”、“SFX音量”和“音乐音量”是游戏中的典型设置。设置一个“SFX”频道组和一个“Music”频道组,并使它们成为主频道组的子频道组(参见System::getMasterChannelGroup
)。
3.3.16 3D声音和空间化
FMOD Core API 支持各种功能:允许声音被放置在3D空间中,通过平移,多普勒音调移动,以及体积缩放甚至特殊滤波衰减,使它们作为环境的一部分在听众周围移动。
FMOD 3D 空间化功能:
-
多个衰减滚降模型。滚降是声音在靠近或者远离听者时的音量变化。选择线性、反转、线性平方、逆锥形和自定义滚转模式。自定义滚转允许设置
FMOD_3D_ROLLOFF_CALLBACK
,以允许用户计算音量滚转是如何发生的。如果回调不方便,FMOD也允许线性差值点的数组,使用函数ChannelControl::set3DCustomRollof
来表示一个“曲线”。 -
多普勒音调平移。精确的音调移动由听者和Channel或者ChannelGroup的用户速度设置来控制,并由FMOD 3D空间化系统来飞速计算和设置。
-
基于矢量的振幅平移(VBAP).该系统实时平移用户扬声器中的声音,支持单声道、立体声 甚至 5.1和7.1环绕扬声器的设置。
-
阻塞。声音的底层通道或通道组可以应用低通滤波来模拟声音穿过墙壁或者被大型物体遮挡。
-
3D混响区混响平移。在3D混响部分查看更多关于这个。混响也可以被遮挡而不通过物体或者墙壁。
-
基于多边形的几何遮挡。将多边形数据添加到FMOD几何引擎中,FMOD将使用光线投射自动遮挡声音。查看更多,参见基于3D多边形几何遮挡章节。
-
多个监听器。在分配模式的游戏中,FMOD可以为每个玩家支持一个监听器,以便3D声音的正确衰减。
-
使用多通道音频格式在2D和3D之间进行变形。声音可以是一个点源,或者被用户变形为2D音频,这对基于距离的包围非常有用。声音离的越近,它就越能传播到其他扬声器中,而不是从一边传到另一边。参见
ChannelControl::set3Dlevel
函数,让用户改变这个混合。 -
立体声和多通道音频格式可以被用于3D音频。通常单音道音频格式用于3D音频。多通道音频格式可以给与额外的影响。默认情况下多通道样本数据被折叠为单声道点源。使用
ChannelControl::set3DSpread
来“扩展”多通道。这可以为一个来自确定个方向的声音提供更多的空间效果。声音在远处的细微传播可能会给人一直更有效的空间化印象,就好像它是从附件的表面反射出来的,或者是“大”的并且向不同的方向发射不同部分的声音。 -
空间化插件支持。第三方VR音频插件可以用来给耳机更现实的平移。要将声音加载为3D,只需将FMOD_3D标志添加到
System::createSound
或者System::createStream
函数中。
接下来要做的3件重要的事情是:
-
使用
System::set3DListenerAttributes
每帧设置一次‘监听器’的位置、方向和速度。 -
使用
ChannelControl::set3DAttributes
设置从System::playSound
返回句柄的通道3D属性。如果需要对一组Channel或者ChannelGroup的3D定位,请使用ChanelControl::setMode
将ChannelGroup设置为3D,然后调用ChannelControl::set3DAttributes
。 -
每帧调用
System::update
一次,这样3D计算就可以根据位置和其他属性进行更新。
在3D声音白皮书或者空间音频白皮书中阅读更多关于3D声音的信息。
3.3.17 基于3D多边形的几何遮挡
FMOD Core API 支持提供多边形网格数据,可以实时处理在真实3D世界中创建遮挡效果。在现实世界中,用户可以阻止声音穿过墙壁,甚至将混响限制在一个几何体积内,这样它就不会泄漏到其他区域。
要使用FMOD几何引擎,用System::createGeometry
创建一个网格对象。然后用Geometry::addPolygon
为每个网格添加多边形。每个对象的可以被平移、旋转和缩放以适应你的环境。
3.3.18 录音-从麦克风或线路录制声音
FMOD Core API 有能力直接从输入录制到一个FMOD声音对象。
这个声音可以在它被录制完成后回放,或者可以使用Sound::lock
和Sound::unlock
函数获取原始数据。
声音也可以在录制时播放,以实现实时效果。一个简单的实现这种效果的技术是开始录制,然后等等一小段时间,如50毫秒,然后播放声音。这将使播放光标始终在记录光标后面。关于如何操作的源代码和信息,参见录音示例。
3.3.19 DSP 效果-支持超过30个特殊效果内置
FMOD Core API 有原生/内置代码来支持很多开箱即用的效果,例如低通、压缩、混响、和参数EQ。一个更全面的列表可以在FMOD_DSP_TYPE列表中找到。
可以使用System::createDSPByType 创建一个效果,并使用
ChannelControl::addDSP添加到一个Channel或者ChannelGroup中
。
3.3.20 DSP效果-混响类型和3D混响区
FMOD Core API 有2个类型的混响可用,和一个只有一个混响的可以用于数百种甚至更多环境的虚拟3D混响系统。
3.3.21 Standard Reverb 标准混响
一个内建的高质量的符合I3DL2标准的混响,用于快速可配置环境模拟,也用于3D混响区系统,如下所述:
要简单设置环境,请使用System::setReverbProperties
函数。这允许你设置一个全局环境或者多达4个不同的环境,所有通道都被影响。
通过在ChannelControl::setReverbProperties
中设置级别,每个通道可以有一个不同的混响湿式混合。
在文档的混响笔记部分中阅读更多关于I3DL2配置的信息。为了避免开始时出现混乱,只在FMOD_REVERB_PRESETS
中使用环境预设列表。
3.3.22 卷积混响
还有一个更高质量的卷积混响,它运行用户导入一个脉冲响应文件(一个环境中的脉冲录音,用于卷积当时播放的信号),并且有环境听起来就像它是在空间中记录的脉冲。
这是一个昂贵的处理效果,FMOD支持GPU加速,将处理任务卸载到图形卡上。这大大减小了效果的开销使其几乎可以忽略不计。Xbox One 和PS4平台支持GPU加速。
卷积混响可以使用System::createDSPByType
和FMOD_DSP_TYPE_CONVOLUTIONREVERB
创建,并使用ChannelControl::addDSP
添加到一个ChannelGroup中。建议值实现一个或者有限个的这些效果,并将他们放置到子混合/组总线(ChannelGroup)上,而不是每个通道。
3.3.23 虚拟3D混响系统
一个虚拟3D混响区系统是支持的,使用主内建系统I3DL2混响。
虚拟的“3D混响球”可以在3D世界中创建和放置,数量不限,不会造成额外的CPU消耗。
当听者穿过这些球体时,FMOD会自动改变和衰减系统的混响水,使它听起来像你在不同的环境中就如你在满世界移动。
球体可以重叠并基于听者在每个球体中的位置。FMOD将改变混响到适当的环境混合。
一个3D混响球可以使用System::createReverb3D
创建,并使用System::Reverb3DAttributes
设置位置。要设置球体混响属性,可以使用Reverb3D::setProperties
。
有个3D混响区系统和实现信息的更多信息,请阅读3D混响白皮书。
3.3.24 DSP效果-支持插件DSP
FMOD Core API 支持用户创建DSP插件。开发者既可以加载一个已有的插件,也可以使用’回调’在应用内创建一个。
回调可以由用户指定,例如当System::createDSP
被调用时,或者当DSP运行并想要在FMOD的混频器中处理PCM数据时。
插件可以与应用内联开发,也可以编译为一个独立的动态库(如.dll 或者 .so)
要加载一个预先存在的插件可执行文件,使用 System::loadPlugin
函数。
要在一个程序中直接实现回调,可以使用System::registerDSP
。
要创建独立的动态库,使用相同的回调,但通过导出的FMODGetDSPDescription函数通过FMOD_DSP_DESCRIPTION结构导出符号。
参阅DSP Plugin API 白皮书,连接怎样制作插件,以及API发行版本中的/expamles/fmod_gain.cpp
作为工作示例。
3.3.25 DSP引擎-灵活的、可编程的软件合成器架构
FMOD Core API 运行在模块化合成器架构上,允许连接信号处理节点("FMOD DSP"概念)。
有向图处理树允许信号从“生成器”(例如System::playSound
播放的声音,或者从System::playDSP
创建的DSP)流向其他节点,混合在一起直到它们到达头节点,在那里最终结果被发送到声卡。
FMOD通常处理图形中的声音,在某些平台上以512个样本(10ms)为块,或者其他平台上以1024个样本(21ms)为块。这是系统的粒度,并影响如何平滑参数的变化,例如将会听到的音调或者音量。
FMOD 预构建的DSP效果可以通过DSP::addInput
和DSP::disconnectFrom
等函数插入到图形中。
有关详细信息,参阅DSP架构和使用白皮书。
3.3.26 非阻塞加载、线程和线程安全
FMOD Core API 指令时线程安全和队列的。根据指令的不同,它们可以立即处理,或者在后台线程处理。
默认情况下,诸如初始化、加载声音之类的事情是在主线程上处理的。
混音、流、几何处理、文件读取和文件加载都可以在后台线程中完成。尽一切努力避免意外阻塞主线程。
最慢的操作之一是加载声音。要将声音加载到后台,用户可以在System::createSound
或者System::createStream
方法中使用FMOD_NONBLOCKING
标志,这样它就不会影响主线程,
线程关联在某些平台上是可以配置的。
有关FMOD和线程的更多信息,请参阅线程和线程安全白皮书。
3.3.27 Performance 性能
FMOD Core API 经过多年的发展,拥有一套全面的效果和编解码器,只需要最小的内存和CPU开销。
所有平台都有节省性能的功能。例如矢量优化浮点数被大量应用。使用的一些技术包括:SSE、NEON、AVX、VMX 和VFP 汇编器。
通常,声音回放中最昂贵的部分时实时压缩样本回放。
FMOD Core API 允许配置一次应该听到多少通道,以减小CPU开销。这是可配置的,使用System::setAdvancedSettings
函数,就如在本文的的压缩样本回放部分提到的那样.
调整采样率质量、重采样质量、混音通道数和解码通道数是可以配置的,以让你的应用获得最佳的可扩展性。
要了解有关配置FMOD来节省CPU时间的更多信息,请参阅CPU性能白皮书,或者要了解各种平台上的核心性能参数,请参阅文档的性能参考部分。
3.4 配置-内存和文件系统
FMOD Core API 满足了应用程序及其内存和文件系统的需求。一个文件系统可以被插入,以便FMOD使用它,而不是它自己的系统,以及内存分配。
设置自定义文件系统是调用System::setFileSystem
的简单的过程
文件系统处理除了正常情况下打开、读取、查找、关闭,还添加了一个额外的对对优先级/延迟文件系统有用的功能,FMOD支持 FMOD_FILE_ASYNCREAD_CALLBACK
回调,实现延迟、优先级加载和读取,这是在高级游戏流引擎中一个常见的功能。
异步读取回调可以立即返回而不提供数据,然后当应用程序在稍后的时间提供数据时,即使在一个不同的线程中,它可以设置’done’标志到FMOD_ASYNCREADINFO
结构中消费它。必须考虑不要等待太久或者增加流缓冲区的大小,以便流不会听到断断续续/跳过。
要设置自定义内存分配器,可以调用Memory_Initialize
。这不是一个FMOD类成员函数因为它需要在FMOD对象(包括System对象)创建之前调用。
要了解更多关于内存池或者内存环境的信息,参阅内存管理白皮书。
3.5 控制一个空间化DSP
使用Core API 控制一个空间化DSP需要设置3D属性相关的数据参数,这将是FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES
或者 FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES_MULTI
数据参数类型。如果Studio::EventInstance
位置改变,Studio::System
会自动设置这个参数,如果使用Core System ,你必须显示设置此DSP参数。
这将与我们的3D空间化器、对象空间化器、共振源/声场空间化器和任何其他使用FMOD空间化器的第三方插件一起工作。
属性必须使用Y轴正向上,X轴正向右的坐标系统(左坐标系统)。使用FMOD_INIT_3D_RIGHTHANDED
标志初始化的坐标系统, FMOD将吧传递给插件的坐标从右坐标系统转为左坐标系统。
FMOD_DSP_PARAMETER_3DaTTRIBUTES
的绝对数据是直截了当的,然后相对部分需要一些计算工作。
/*
This code supposes the availability of a maths library with basic support for 3D and 4D vectors and 4x4 matrices:
// 3D vector
class Vec3f
{
public:
float x, y, z;
// Initialize x, y & z from the corresponding elements of FMOD_VECTOR
Vec3f(const FMOD_VECTOR &v);
};
// 4D vector
class Vec4f
{
public:
float x, y, z, w;
Vec4f(const Vec3f &v, float w);
// Initialize x, y & z from the corresponding elements of FMOD_VECTOR
Vec4f(const FMOD_VECTOR &v, float w);
// Copy x, y & z to the corresponding elements of FMOD_VECTOR
void toFMOD(FMOD_VECTOR &v);
};
// 4x4 matrix
class Matrix44f
{
public:
Vec4f X, Y, Z, W;
};
// 3D Vector cross product
Vec3f crossProduct(const Vec3f &a, const Vec3f &b);
// 4D Vector addition
Vec4f operator+(const Vec4f &a, const Vec4f &b);
// 4D Vector subtraction
Vec4f operator-(const Vec4f& a, const Vec4f& b);
// Matrix multiplication m * v
Vec4f operator*(const Matrix44f &m, const Vec4f &v);
// 4x4 Matrix inverse
Matrix44f inverse(const Matrix44f &m);
*/
void calculatePannerAttributes(const FMOD_3D_ATTRIBUTES &listenerAttributes, const FMOD_3D_ATTRIBUTES &emitterAttributes, FMOD_DSP_PARAMETER_3DATTRIBUTES &pannerAttributes)
{
// pannerAttributes.relative is the emitter position and orientation transformed into the listener's space:
// First we need the 3D transformation for the listener.
Vec3f right = crossProduct(listenerAttributes.up, listenerAttributes.forward);
Matrix44f listenerTransform;
listenerTransform.X = Vec4f(right, 0.0f);
listenerTransform.Y = Vec4f(listenerAttributes.up, 0.0f);
listenerTransform.Z = Vec4f(listenerAttributes.forward, 0.0f);
listenerTransform.W = Vec4f(listenerAttributes.position, 1.0f);
// Now we use the inverse of the listener's 3D transformation to transform the emitter attributes into the listener's space:
Matrix44f invListenerTransform = inverse(listenerTransform);
Vec4f position = invListenerTransform * Vec4f(emitterAttributes.position, 1.0f);
// Setting the w component of the 4D vector to zero means the matrix multiplication will only rotate the vector.
Vec4f forward = invListenerTransform * Vec4f(emitterAttributes.forward, 0.0f);
Vec4f up = invListenerTransform * Vec4f(emitterAttributes.up, 0.0f);
Vec4f velocity = invListenerTransform * (Vec4f(emitterAttributes.velocity, 0.0f) - Vec4f(listenerAttributes.velocity, 0.0f));
// We are now done computing the relative attributes.
position.toFMOD(pannerAttributes.relative.position);
forward.toFMOD(pannerAttributes.relative.forward);
up.toFMOD(pannerAttributes.relative.up);
velocity.toFMOD(pannerAttributes.relative.velocity);
// pannerAttributes.absolute is simply the emitter position and orientation:
pannerAttributes.absolute = emitterAttributes;
}
当使用FMOD_DSP_PARAMETER_3DATTRIBUTES_MULTI
时,您需要为每个侦听器调用calculatePannerAttributes
来填充适当的侦听器属性。
通过使用DSP::setParameterData
和FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES
的索引在DSP上设置它,您将需要与DSP的作者检查结构索引。使用DSP::setParameterData
将数据传递到DSP,并带有3D属性的索引,FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES
或FMOD_DSP_PARAMETER_DATA_TYPE_3DATTRIBUTES_MULTI
。
3.6 上混 / 降混音行为
上混(上混:将较低声道数量的音频信号重新混合,以创建具有更多声道的音频信号)
降混音(将多声道音频混合成较少声道的音频)行为
FMOD使用混合矩阵处理下混。下面您可以找到各种混合矩阵布局,每个表代表一个单独的输出格式。在每个表中“输出”列中的扬声器根据输入扬声器布局,从相关行的输入扬声器公式中分配级别。不同的混合矩阵布局可以使用ChannelControl::setMixMatrix
来设置。有关现有扬声器布局的更多详细信息,请参阅FMOD_SPEAKER
和FMOD_SPEAKERMODE
。
为了在立体声输出设备上使用5.1时获得更好的结果,可以通过在调用System::ini
t时指定FMOD_INIT_PREFER_DOLBY_DOWNMIX
作为init标志来选择杜比Pro Logic II downmix
算法。
Key | Value |
---|---|
M | Mono |
L | Left |
R | Right |
FL | Front Left |
FR | Front Right |
C | Center |
LFE | Low Frequency Effects |
SL | Surround Left |
SR | Surround Right |
BL | Back Left |
BR | Back Right |
TFL | Top Front Left |
TFR | Top Front Right |
TBL | Top Back Left |
TBR | Top Back Right |
3.6.1 FMOD_SPEAKERMODE_MONO
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
M | M | L x 0.707 + R x 0.707 | FL x 0.500 + FR x 0.500 + SL x 0.500 + SR x 0.500 | FL x 0.447 + FR x 0.447 + C x 0.447 + BL x 0.447 + BR x 0.447 | FL x 0.447 + FR x 0.447 + C x 0.447 + BL x 0.447 + BR x 0.447 | FL x 0.378 + FR x 0.378 + C x 0.378 + SL x 0.378 + SR x 0.378 + BL x 0.378 + BR x 0.378 | FL x 0.378 + FR x 0.378 + C x 0.378 + SL x 0.378 + SR x 0.378 + BL x 0.378 + BR x 0.378 |
3.6.2 FMOD_SPEAKERMODE_STEREO
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
L | M x 0.707 | L | FL + SL x 0.707 | FL + C x 0.707 + BL x 0.707 | FL + C x 0.707 + BL x 0.707 | FL + C x 0.707 + SL x 0.707 + BL x 0.596 | FL + C x 0.707 + SL x 0.707 + BL x 0.596 |
R | M x 0.707 | R | FR + SR x 0.707 | FR + C x 0.707 + BR x 0.707 | FR + C x 0.707 + BR x 0.707 | FR + C x 0.707 + SR x 0.707 + BR x 0.596 | FR + C x 0.707 + SR x 0.707 + BR x 0.596 |
3.6.3 FMOD_SPEAKERMODE_QUAD
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
FL | M x 0.707 | L | FL | FL + C x 0.707 | FL + C x 0.707 | FL x 0.965 + FR x 0.258 + C x 0.707 + SL x 0.707 | FL x 0.965 + FR x 0.258 + C x 0.707 + SL x 0.707 |
FR | M x 0.707 | R | FR | FR + C x 0.707 | FR + C x 0.707 | FL x 0.258 + FR x 0.965 + C x 0.707 + SR x 0.707 | FL x 0.258 + FR x 0.965 + C x 0.707 + SR x 0.707 |
SL | SL | BL | BL | SL x 0.707 + BL x 0.965 + BR x 0.258 | SL x 0.707 + BL x 0.965 + BR x 0.258 | ||
SR | SR | B | R | BR | SR x 0.707 + BL x 0.258 + BR x 0.965 |
3.6.4 FMOD_SPEAKERMODE_SURROUND
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
FL | M x 0.707 | L | FL x 0.961 | FL | FL | FL + SL x 0.367 | FL + SL x 0.367 |
FR | M x 0.707 | R | FR x 0.961 | FR | FR | FR + SR x 0.367 | FR + SR x 0.367 |
C | C | C | C | C | |||
BL | FL x 0.274 + SL x 0.960 + SR x 0.422 | BL | BL | SL x 0.930 + BL x 0.700 + BR x 0.460 | SL x 0.930 + BL x 0.700 + BR x 0.460 | ||
BR | FR x 0.274 + SL x 0.422 + SR x 0.960 | BR | BR | SR x 0.930 + BL x 0.460 + BR x 0.700 | SR x 0.930 + BL x 0.460 + BR x 0.700 |
3.6.5 FMOD_SPEAKERMODE_5POINT1
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
FL | M x 0.707 | L | FL x 0.961 | FL | FL | FL + SL x 0.367 | FL + SL x 0.367 |
FR | M x 0.707 | R | FR x 0.961 | FR | FR | FR + SR x 0.367 | FR + SR x 0.367 |
C | C | C | C | C | |||
LFE | LFE | LFE | LFE | ||||
BL | FL x 0.274 + SL x 0.960 + SR x 0.422 | BL | BL | SL x 0.930 + BL x 0.700 + BR x 0.460 | SL x 0.930 + BL x 0.700 + BR x 0.460 | ||
BR | FR x 0.274 + SL x 0.422 + SR x 0.960 | BR | BR | SR x 0.930 + BL x 0.460 + BR x 0.700 | SR x 0.930 + BL x 0.460 + BR x 0.700 |
3.6.6 FMOD_SPEAKERMODE_7POINT1
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
FL | M x 0.707 | L | FL x 0.939 | FL | FL | FL | FL |
FR | M x 0.707 | R | FR x 0.939 | FR | FR | FR | FR |
C | C | C | C | C | |||
LFE | LFE | LFE | LFE | ||||
SL | FL x 0.344 + SL x 0.344 | BL x 0.883 | BL x 0.883 | SL | SL | ||
SR | FR x 0.344 + SR x 0.344 | BR x 0.883 | BR x 0.883 | SR | SR | ||
BL | SL x 0.939 | BL x 0.470 | BL x 0.470 | BL | BL | ||
BR | SR x 0.939 | BR x 0.470 | BR x 0.470 | BR | BR |
3.6.7 FMOD_SPEAKERMODE_7POINT1POINT4
Output | Mono | Stereo | Quad | 5.0 | 5.1 | 7.1 | 7.1.4 |
---|---|---|---|---|---|---|---|
F | L M x 0.707 | L | FL x 0.939 | FL | FL | FL | FL |
FR | M x 0.707 | R | FR x 0.939 | FR | FR | FR | FR |
C | C | C | C | C | |||
LFE | LFE | LFE | LFE | ||||
SL | FL x 0.344 + SL x 0.344 | BL x 0.883 | BL x 0.883 | SL | SL | ||
SR | FR x 0.344 + SR x 0.344 | BR x 0.883 | BR x 0.883 | SR | SR | ||
BL | SL x 0.939 | BL x 0.470 | BL x 0.470 | BL | BL | ||
BR | SR x 0.939 | BR x 0.470 | BR x 0.470 | BR | BR | ||
TFL | TFL | ||||||
TFR | TFR | ||||||
TBL TBL | |||||||
TBR | TBR |
3.7 高级声音创作
FMOD有许多FMOD_MODE
模式用于声音创建,这些模式需要使用FMOD_CREATESOUNDEXINFO
来指定声音的各种属性,例如数据格式、频率、长度、回调等等。下面详细介绍了如何使用这些模式,并提供了使用每种模式创建声音的基本示例。
3.7.1 从内存创建声音
FMOD_OPENMEMORY
FMOD_OPENMEMORY导致FMOD将System::createSound
或System::createStream
的第一个参数解释为指向内存的指针而不是文件名。FMOD_CREATESOUNDEXINFO::length
用于指定声音的长度,特别是以字节为单位的声音数据占用的内存量。这些数据被复制到FMOD的缓冲区中,并且可以在声音创建后被释放。如果使用FMOD_CREATESTREAM
,数据将从您传入的指针指向的缓冲区中流化,因此您应该确保在完成并释放流之前不会释放内存。
C++
FMOD::Sound *sound;
FMOD_CREATESOUNDEXINFO exinfo;
void *buffer = 0;
int length = 0;
//
// Load your audio data to the "buffer" pointer here
//
// Create extended sound info struct
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); // Size of the struct.
exinfo.length = length; // Length of sound - PCM data in bytes
system->createSound((const char *)buffer, FMOD_OPENMEMORY, &exinfo, &sound);
// The audio data pointed to by "buffer" has been duplicated into FMOD's buffers, and can now be freed
// However, if loading as a stream with FMOD_CREATESTREAM or System::createStream, the memory must stay active, so do not free it!
FMOD_OPENMEMORY_POINT
FMOD_OPENMEMORY_POINT
还导致FMOD将System::createSound
或System::createStream
的第一个参数解释为指向内存的指针,而不是文件名。然而,与FMOD_OPENMEMORY
不同,FMOD将按原样使用内存,而不是将其复制到自己的缓冲区中。因此,只能在调用Sound::release
之后释放内存。FMOD_CREATESOUNDEXINFO::length
用于指定声音的长度,特别是以字节为单位的声音数据占用的内存量。
//C++
FMOD::Sound *sound;
FMOD_CREATESOUNDEXINFO exinfo;
void *buffer = 0;
int length = 0;
//
// Load your audio data to the "buffer" pointer here
//
// Create extended sound info struct
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); // Size of the struct
exinfo.length = length; // Length of sound - PCM data in bytes
system->createSound((const char *)buffer, FMOD_OPENMEMORY_POINT, &exinfo, &sound);
// As FMOD is using the data stored at the buffer pointer as is, without copying it into its own buffers, the memory cannot be freed until after Sound::release is called
3.7.2 从PCM数据创建声音
FMOD_OPENRAW
FMOD_OPENRAW
导致FMOD忽略所提供音频文件的格式,而将其作为原始PCM数据处理。使用FMOD_CREATESOUNDEXINFO
指定文件的频率、通道数和数据格式。
//C++
FMOD::Sound *sound;
FMOD_CREATESOUNDEXINFO exinfo;
// Create extended sound info struct
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); // Size of the struct
exinfo.numchannels = 2; // Number of channels in the sound
exinfo.defaultfrequency = 44100; // Playback rate of sound
exinfo.format = FMOD_SOUND_FORMAT_PCM16; // Data format of sound
system->createSound("./Your/File/Path/Here.raw", FMOD_OPENRAW, &exinfo, &sound);
3.7.3 通过手动提供样本数据创建声音
FMOD_OPENUSER
FMOD_OPENUSE
R导致FMOD忽略System::createSound
或System::createStream
的第一个参数,而是创建一个静态样本或流,你必须手动提供音频数据。使用FMOD_CREATESOUNDEXINFO
指定频率、通道数和数据格式。您可以选择提供一个read回调,它用于将您自己的音频数据放入FMOD的缓冲区。如果没有提供读回调,则示例将为空,因此必须使用Sound::lock
和Sound::unlock
//C++
FMOD::Sound *sound;
FMOD_CREATESOUNDEXINFO exinfo;
// Create extended sound info struct
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO); // Size of the struct
exinfo.numchannels = 2; // Number of channels in the sound
exinfo.defaultfrequency = 44100; // Default playback rate of sound
exinfo.length = exinfo.defaultfrequency * exinfo.numchannels * sizeof(signed short) * 5; // Length of sound - PCM data in bytes. 5 = seconds
exinfo.format = FMOD_SOUND_FORMAT_PCM16; // Data format of sound
exinfo.pcmreadcallback = MyReadCallbackFunction; // To read sound data, you must specify a read callback using the pcmreadcallback field
// Alternatively, use Sound::lock and Sound::unlock to submit sample data to the sound when playing it back
// As sample data is being loaded via callback or Sound::lock and Sound::unlock, pass null or equivalent as first argument
system->createSound(0, FMOD_OPENUSER, &exinfo, &sound);
3.8 从声音中提取PCM数据
下面演示了如何从声音中提取PCM数据,并使用Sound::readData
将其放入缓冲区。System::createSound
的mode参数必须使用FMOD_OPENONLY
,以确保文件句柄在读取时保持打开状态,因为其他模式将自动读取整个文件的数据并关闭文件句柄。此外,Sound::seekData
可用于在读入缓冲区之前查找声音的数据。
//c++
FMOD::Sound *sound;
unsigned int length;
char *buffer;
system->createSound("drumloop.wav", FMOD_OPENONLY, nullptr, &sound);
sound->getLength(&length, FMOD_TIMEUNIT_RAWBYTES);
buffer = new char[length];
sound->readData(buffer, length, nullptr);
delete[] buffer;
参见: FMOD_TIMEUNIT
, FMOD_MODE
, Sound::getLength
, System::createSound
. Sound::seekData
`