探索Web Audio API中的空间音频技术
1. 空间音频概述
空间音频通常是指将声源放置在听众周围的三维空间中的任意位置。在Web Audio API里,空间音频的功能更强大,它允许听众和所有声源被放置在任意位置,拥有任意方向,还能定义声源的方向特性、声音强度随距离的衰减方式以及空间声音的最终渲染方式。这些功能主要通过
PannerNode
和音频上下文的
AudioListener
对象来实现。
1.1
PannerNode
的作用
PannerNode
可能是最复杂的节点之一,它有多个参数来控制声源的位置、方向、指向性(声锥)、距离渲染和全景模型。其输入可以是单声道(一个声道)或立体声(两个声道),当节点激活时,输出为两个声道。对于声道数不同的连接,会进行适当的上混或下混处理。
PannerNode
对输入进行一系列处理步骤以得到空间化的输出:
1.
距离衰减
:基于距离模型和源与听众之间的距离。
2.
指向性衰减
:基于声源的声锥参数以及声源方向向量与听众到声源向量之间的角度。
3.
声源的全景处理
:基于全景模型以及源与听众之间的方位角和仰角。
1.2 坐标系统
听众和空间化的声源(
PannerNode
)在三维空间中的位置使用右手笛卡尔坐标系。该坐标系的单位未定义,因为空间化依赖于方向角度和相对距离,而非绝对距离。通常,X表示水平方向(从左到右),Y表示垂直方向(从下到上),Z表示纵向方向(从前到后)。
2.
AudioListener
每个音频上下文都有一个单一的
AudioListener
,可以设置其属性,让实际听众感觉声音来自空间中的特定位置和方向。
AudioListener
有九个属性,代表三个三维向量:
| 属性 | 描述 | 默认值 |
| ---- | ---- | ---- |
|
positionX
,
positionY
,
positionZ
| 听众的水平/垂直/纵向位置 | (0, 0, 0) |
|
forwardX
,
forwardY
,
forwardZ
| 听众的向前方向的水平/垂直/纵向位置 | (0, 0, -1) |
|
upX
,
upY
,
upZ
| 听众头顶的水平/垂直/纵向位置 | (0, 1, 0) |
AudioListener
不是音频节点,但会影响同一图中所有
Panner
节点的输出。其参数是音频参数,可以有时间线事件,其他节点也可以连接到这些参数。每个上下文只有一个听众,这在Web Audio API在浏览器的客户端运行时不是问题,因为不同用户可以设置不同的听众参数,从而听到不同位置的声音。
3.
PannerNode
的几何特性
虽然只有一个听众,但可以有多个
PannerNode
,这样就能将多个声源放置在不同位置。
PannerNode
的位置和方向向量与听众的位置、向前和向上属性向量类似,定义了声源的位置和指向方向。
| 属性 | 描述 | 默认值 |
| ---- | ---- | ---- |
|
positionX
,
positionY
,
positionZ
| 音频源的水平、垂直和纵向位置 | (0, 0, 0) |
|
orientationX
,
orientationY
,
orientationZ
| 音频源的水平、垂直和纵向方向,声音向该方向传播 | (1, 0, 0) |
4. 指向性
每个声源的声音指向特性由内声锥和外声锥决定,它们将声音强度表示为声源/听众与声源方向向量夹角的函数。因此,直接指向听众的声源比偏离轴向的声源更响亮。声源也可以是全向的,即无论方向如何,听到的声音强度相同。
声锥由以下三个属性定义:
| 属性 | 描述 | 默认值 |
| ---- | ---- | ---- |
|
coneInnerAngle
| 无音量衰减的锥角(度) | 360 |
|
coneOuterAngle
| 超过该角度后,音量按
coneOuterGain
衰减的锥角(度) | 0 |
|
coneOuterGain
| 外声锥外应用的衰减 | 0 |
指定内锥和外锥后,空间被分为三个部分:
1. 内锥内部。
2. 内锥和外锥之间。
3. 外锥外部。
每个子空间都有一个增益乘数,计算方法如下:
假设S是声源位置向量,L是听众位置。首先定义从听众到声源的归一化向量,将问题转换到以听众为原点的坐标系,然后使用归一化向量计算角度。设SO是声源方向向量,CI是内锥角,CO是外锥角,GO是外锥增益。如果SO = 0或SIA = 360,则未指定声锥,声源是全向的,增益设为1。否则,声源方向向量与声源 - 听众向量之间的角度A为:
[A = \frac{180|\arccos(V \cdot SO)|}{\pi}]
声锥引起的增益G由下式确定:
[G = \begin{cases}
1, & A \leq CI/2 \
\frac{(CO - 2A) \cdot GO+(2A - CI)}{CO - CI}, & CI/2 < A \leq CO/2 \
GO, & A > CO/2
\end{cases}]
这里A乘以2是因为内、外角度是从负到正的整个范围。
例如,设置
CI = 10
,
CO = 30
,
GO = 0.1
可以产生高度定向的声音,声音在很窄的范围内无衰减,然后迅速过渡到严重衰减。而设置
CI = 180
,
CO = 270
,
GO = 0.4
则使听众前方的声音无衰减,声音过渡到完全在听众后方时只有轻微衰减。
5. 距离模型
前面讨论了源与听众之间的角度如何影响感知的源级别,现在来看距离对其的影响。为此引入四个属性:
| 属性 | 描述 | 默认值 |
| ---- | ---- | ---- |
|
distanceModel
| 源远离听众时降低音量的算法,可选值为
'linear'
、
'inverse'
和
'exponential'
|
'inverse'
|
|
refDistance
| 源与听众距离大于此值时,根据
rolloffFactor
和
distanceModel
降低音量 | 1 |
|
rolloffFactor
| 源远离听众时音量降低的速度 | 1 |
|
maxDistance
| 源与听众之间的最大距离,超过此距离后音量不再降低 | 10000 |
设d = |S - L|为源与听众之间的距离,R为衰减因子,dref为参考距离,dmax为最大距离。
distanceModel
属性决定了源远离听众时如何应用衰减,具体如下:
-
'inverse'
:[G=\frac{d_{ref}}{d_{ref}+R\cdot(d - d_{ref})}]
-
'linear'
:[G=\max(0,1 - R\cdot\frac{d - d_{ref}}{d_{max}-d_{ref}})]
-
'exponential'
:[G=(\frac{d}{d_{ref}})^{-R}]
对于线性模型,如果
dref = dmax
,G设为1 - R,且
dmax
仅在线性模型中使用。对于逆和指数模型,如果参考距离设为0,增益设为零。当
rolloffFactor
和
refDistance
的默认值都为1时,这两个模型等效。
6. 全景模型
6.1 方位角和仰角
方位角和仰角分别确定了听众与
PannerNode
在水平和垂直平面上的角度。假设从源到听众的归一化向量为V,听众的归一化向前方向为F,归一化向上方向为U。方位角α是F与V向右的夹角,(\cos(\alpha)=F\cdot V);仰角ε是水平平面(与向上方向正交)与V向上的夹角,或90度减去U与V之间的角度,(\cos(90^{\circ}-\varepsilon)=U\cdot V)。对于源在听众后方或下方的情况(即(|\alpha|>90^{\circ})或(|\varepsilon|>90^{\circ})),需要特别处理。
6.2 全景算法
panningModel
属性是将声音定位在相对于听众的三维空间中的空间化算法,有两个选项:
-
equalpower
:代表等功率全景算法,通常被认为简单高效,是默认值。它仅基于方位角,相当于
StereoPannerNode
的
pan
参数设置为(\cos(\alpha))时的全景算法。这意味着忽略仰角,且该算法无法区分源在听众前方还是后方。当输入为单声道时,使用单声道到立体声处理;当输入为立体声时,使用立体声到立体声处理。
-
HRTF
:代表“头部相关传递函数”,该模型在确定声音位置时考虑了人头的影响。声音会从头部、躯干和耳廓反射,根据声源的到达方向,每个耳朵的反射和滤波不同。将全景模型设置为
'HRTF'
需要一组对应于在不同方位角和仰角记录的HRTF的脉冲响应,并且实现需要优化的卷积函数。它比
equalpower
更复杂、计算量更大,但能提供更好的声音空间化效果。
6.3 空间化流程
空间化过程实际上是前面所述内容的简单组合,流程如下:
graph TD;
A[获取源和听众的位置] --> B[计算距离向量];
B --> C[根据距离、距离模型等应用增益];
C --> D[使用距离向量和声源方向计算源与听众的角度];
D --> E[根据角度、声锥参数应用增益];
E --> F[使用距离向量、听众向前和向上方向计算方位角和仰角];
F --> G[应用全景模型];
当然,用户无需手动计算这些,只需指定参数,
PannerNode
会完成工作。
6.4 代码示例:移动听众
以下是一个简单的
PannerNode
使用示例,其中声源固定,听众可以移动。
listener.html
X<input type='range' id='panX' oninput='panning()' min=-8 max=8 step='any'>
<br><br><br><br>
Z<input type='range' id='panZ' oninput='panning()' style='transform:rotate(90deg)' min=-8 max=8 value=-1 step='any'>
<script src='listener.js'></script>
listener.js
let context = new AudioContext()
let source = context.createOscillator()
let listener = context.listener
let panNode = new PannerNode(context)
source.start()
panNode.positionX.value = 0
panNode.positionY.value = 0
panNode.positionZ.value = -1
panNode.orientationX.value = 0
panNode.orientationY.value = 0
panNode.orientationZ.value = 1
panNode.coneInnerAngle = 45
panNode.coneOuterAngle = 90
panNode.coneOuterGain = 0.1
panNode.refDistance = 0.5
source.connect(panNode).connect(context.destination)
function panning() {
context.resume()
listener.positionX.value = panX.value
listener.positionZ.value = panZ.value
}
在这个示例中,有滑块控制声源的x和z位置,y未使用,因此没有高度空间化,假设声源和听众在同一水平面上。听众默认直视前方,位于原点。声源在听众前方(0, 0, -1)处,且指向听众。声锥设置为:如果声源向任一侧移动不超过45度(通过调整X滑块),则由于指向性没有衰减;如果在听众后方,则由于到达方向达到最大衰减。
如果一个滑块不变,另一个滑块左右移动,会观察到一个有趣的效果:滑块经过中心位置时会有声音丢失。这是因为滑块值变化不平稳,如果使用参数改变位置,这种效果大多会消失。
7. 参数总结与影响
7.1 参数列表
为了更好地理解和使用
PannerNode
和
AudioListener
,下面总结了所有可更改的参数及其用途和默认值:
| 节点 | 参数 | 描述 | 默认值 |
| ---- | ---- | ---- | ---- |
|
PannerNode
|
positionX
| 音频源的x坐标位置 | 0 |
|
PannerNode
|
positionY
| 音频源的y坐标位置 | 0 |
|
PannerNode
|
positionZ
| 音频源的z坐标位置 | 0 |
|
PannerNode
|
distanceModel
| 指定此
PannerNode
使用的距离模型 |
'inverse'
|
|
PannerNode
|
refDistance
| 源与听众距离大于此值时,开始根据
rolloffFactor
和
distanceModel
衰减音量 | 1 |
|
PannerNode
|
maxDistance
| 源与听众之间的最大距离,超过此距离后音量不再进一步衰减 | 10000 |
|
PannerNode
|
rolloffFactor
| 源远离听众时音量衰减的速度 | 1 |
|
PannerNode
|
coneInnerAngle
| 无增益衰减的锥角 | 360 |
|
PannerNode
|
coneOuterAngle
| 超过该角度后应用
coneOuterGain
的锥角 | 360 |
|
PannerNode
|
coneOuterGain
| 外声锥外应用的增益 | 0 |
|
PannerNode
|
orientationX
| 声源方向向量的x分量 | 1 |
|
PannerNode
|
orientationY
| 声源方向向量的y分量 | 0 |
|
PannerNode
|
orientationZ
| 声源方向向量的z分量 | 0 |
|
PannerNode
|
panningModel
| 指定使用的全景模型 |
'equalpower'
|
|
AudioListener
|
positionX
| 听众的x坐标位置 | 0 |
|
AudioListener
|
positionY
| 听众的y坐标位置 | 0 |
|
AudioListener
|
positionZ
| 听众的z坐标位置 | 0 |
|
AudioListener
|
forwardX
| 听众向前方向的x坐标 | 0 |
|
AudioListener
|
forwardY
| 听众向前方向的y坐标 | 0 |
|
AudioListener
|
forwardZ
| 听众向前方向的z坐标 | -1 |
|
AudioListener
|
upX
| 听众头顶方向的x坐标 | 0 |
|
AudioListener
|
upY
| 听众头顶方向的y坐标 | 1 |
|
AudioListener
|
upZ
| 听众头顶方向的z坐标 | 0 |
7.2 参数影响
改变这些参数会改变声源的空间化效果。例如:
-
位置参数
:调整
PannerNode
和
AudioListener
的位置参数,可以改变声源和听众在三维空间中的相对位置,从而影响声音的空间感。
-
距离模型参数
:不同的
distanceModel
、
refDistance
、
rolloffFactor
和
maxDistance
组合,会使声音随着距离的衰减呈现不同的效果。
-
指向性参数
:
coneInnerAngle
、
coneOuterAngle
和
coneOuterGain
决定了声源的指向特性,影响不同角度下声音的强度。
-
全景模型参数
:选择
equalpower
或
HRTF
全景模型,会带来不同的声音空间化质量和效果。
8. 实际应用场景
8.1 游戏开发
在游戏中,空间音频可以大大增强游戏的沉浸感。例如,在第一人称射击游戏中,玩家可以根据枪声、脚步声等声音的空间位置判断敌人的方向和距离。通过合理设置
PannerNode
和
AudioListener
的参数,可以模拟出真实的环境音效,让玩家仿佛置身于游戏世界中。
8.2 虚拟现实(VR)体验
VR应用需要高度逼真的音频效果来配合视觉体验,使玩家有身临其境的感觉。空间音频可以根据玩家的头部位置和方向实时调整声音的空间效果,让玩家感受到声音来自周围的真实环境。例如,在VR探险游戏中,风声、鸟鸣声等环境音效可以根据玩家的位置和朝向进行动态调整。
8.3 音乐欣赏
对于音乐作品,空间音频可以帮助展现音乐中的丰富细节。例如,在一场虚拟音乐会上,通过空间化处理,可以让听众感受到不同乐器在空间中的分布,仿佛置身于真实的音乐厅中。
9. 注意事项
9.1 耳机或立体声扬声器
在聆听代码示例的声音效果时,建议使用耳机或立体声扬声器,这样可以更好地感受左右声道的空间化转换效果。
9.2 向量的规范性
虽然
AudioListener
的
forward
和
up
向量不严格要求归一化和正交,但为了获得更准确的空间化效果,最好确保它们是归一化且正交的。
9.3 性能考虑
使用
HRTF
全景模型时,由于需要处理大量的脉冲响应和卷积计算,会增加计算量。在性能较低的设备上,可能会导致性能下降,因此需要根据实际情况选择合适的全景模型。
10. 总结
Web Audio API中的空间音频技术通过
PannerNode
和
AudioListener
提供了强大的声音空间化功能。通过合理设置各种参数,可以实现声源在三维空间中的精确定位和渲染,为游戏、VR、音乐等领域带来更加沉浸式的音频体验。在实际应用中,需要根据具体需求选择合适的参数和模型,并注意性能和兼容性等问题。同时,通过代码示例可以更好地理解和掌握空间音频的使用方法,不断探索和创新,创造出更加精彩的音频效果。
希望本文能够帮助你深入了解Web Audio API中的空间音频技术,开启更加丰富的音频创作之旅。
深入理解Web Audio空间音频
超级会员免费看

被折叠的 条评论
为什么被折叠?



