引言
Web 上的音频技术在这一点之前一直相当原始,直到最近还不得不通过 Flash 和 QuickTime 等插件进行交付。HTML5 中 audio 元素的引入非常重要,它实现了基本的流式音频播放。但是,它不足以处理更复杂的音频应用。对于复杂的 Web 游戏或交互式应用程序,需要另一种解决方案。本规范的目标之一是包含现代游戏音频引擎中的功能,以及现代桌面音频制作应用程序中常见的混音、处理和滤波任务。
这些 API 在设计时考虑了各种各样的用例 [webaudio-usecases]。理想情况下,它应该能够支持任何能够合理地通过脚本控制、在浏览器中运行的优化 C++ 引擎所能实现的功能。话虽如此,现代桌面音频软件可能具有非常先进的功能,其中一些用本系统构建将很困难或不可能。Apple 的 Logic Audio 就是这样一种应用程序,它支持外部 MIDI 控制器、任意插件音频效果和合成器、高度优化的直接到磁盘音频文件读写、紧密集成的变速变调等等。尽管如此,本系统将完全有能力支持大量的、相当复杂的游戏和交互式应用程序,包括音乐类的。它还可以作为 WebGL 提供的更高级图形功能的良好补充。该 API 的设计旨在让更高级的功能可以在以后添加。
特性
本 API 支持以下主要特性:
-
模块化路由,用于简单或复杂的混音/效果架构。
-
高动态范围,内部处理使用 32 位浮点数。
-
采样精确的调度声音播放,并具有低延迟,适用于对节奏精度要求极高的音乐应用(如鼓机和定序器)。这还包括动态创建效果的可能性。
-
音频参数的自动化,适用于包络、淡入/淡出、颗粒效果、滤波器扫描、LFO 等。
-
音频流中声道的灵活处理,允许拆分和合并。
-
使用来自
getUserMedia()的MediaStream处理实时音频输入。 -
与 WebRTC 集成。
-
使用
MediaStreamTrackAudioSourceNode和 [webrtc] 处理从远程对端接收的音频。 -
使用
MediaStreamAudioDestinationNode和 [webrtc] 将生成的或处理后的音频流发送到远程对端。
-
-
直接使用脚本进行音频流合成和处理。
-
空间化音频,支持各种 3D 游戏和沉浸式环境。
-
声像定位模型:equalpower (等功率)、HRTF、pass-through (直通)。
-
距离衰减。
-
声锥。
-
遮挡 / 掩蔽。
-
基于源 / 监听者。
-
-
用于各种线性效果的卷积引擎,特别是极高质量的室内效果。以下是可能效果的一些示例:
-
小 / 大房间
-
大教堂
-
音乐厅
-
洞穴
-
隧道
-
走廊
-
森林
-
露天剧场
-
通过门口传来的远距离房间声音
-
极端滤波器
-
奇异的反向效果
-
极端梳状滤波器效果
-
-
用于整体控制和优化混音的动态压缩。
-
用于低通、高通和其他常见滤波的高效双二阶滤波器。
-
用于失真和其他非线性效果的波形塑形效果。
-
振荡器。
模块化路由。
模块化路由允许在不同的 AudioNode 对象之间建立任意连接。每个节点都可以有输入和/或输出。源节点没有输入,只有一个输出。目标节点有一个输入,没有输出。其他节点(如滤波器)可以放置在源节点和目标节点之间。当两个对象连接在一起时,开发人员不必担心低级别的流格式细节;系统会自动处理。例如,如果单声道音频流连接到立体声输入,它应该恰当地混合到左声道和右声道。
在最简单的情况下,单个源可以直接路由到输出。所有路由都在包含一个 AudioDestinationNode 的 AudioContext 内进行。
为了说明这种简单的路由,这里有一个播放单个声音的简单示例。
const context= new AudioContext(); function playSound() { const source= context. createBufferSource(); source. buffer= dogBarkingBuffer; source. connect( context. destination); source. start( 0 ); }
这是一个更复杂的示例,包含三个源和一个卷积混响发送,在最终输出阶段带有一个动态压缩器。
let context; let compressor; let reverb; let source1, source2, source3; let lowpassFilter; let waveShaper; let panner; let dry1, dry2, dry3; let wet1, wet2, wet3; let mainDry; let mainWet; function setupRoutingGraph() { context= new AudioContext(); // Create the effects nodes. lowpassFilter= context. createBiquadFilter(); waveShaper= context. createWaveShaper(); panner= context. createPanner(); compressor= context. createDynamicsCompressor(); reverb= context. createConvolver(); // Create main wet and dry. mainDry= context. createGain(); mainWet= context. createGain(); // Connect final compressor to final destination. compressor. connect( context. destination); // Connect main dry and wet to compressor. mainDry. connect( compressor); mainWet. connect( compressor); // Connect reverb to main wet. reverb. connect( mainWet); // Create a few sources. source1= context. createBufferSource(); source2= context. createBufferSource(); source3= context. createOscillator(); source1. buffer= manTalkingBuffer; source2. buffer= footstepsBuffer; source3. frequency. value= 440 ; // Connect source1 dry1= context. createGain(); wet1= context. createGain(); source1. connect( lowpassFilter); lowpassFilter. connect( dry1); lowpassFilter. connect( wet1); dry1. connect( mainDry); wet1. connect( reverb); // Connect source2 dry2= context. createGain(); wet2= context. createGain(); source2. connect( waveShaper); waveShaper. connect( dry2); waveShaper. connect( wet2); dry2. connect( mainDry); wet2. connect( reverb); // Connect source3 dry3= context. createGain(); wet3= context. createGain(); source3. connect( panner); panner. connect( dry3); panner. connect( wet3); dry3. connect( mainDry); wet3. connect( reverb); // Start the sources now. source1. start( 0 ); source2. start( 0 ); source3. start( 0 ); }
模块化路由还允许将 AudioNode 的输出路由到控制另一个 AudioNode 行为的 AudioParam 参数。在这种情况下,节点的输出可以作为调制信号,而不是输入信号。
function setupRoutingGraph() { const context= new AudioContext(); // Create the low frequency oscillator that supplies the modulation signal const lfo= context. createOscillator(); lfo. frequency. value= 1.0 ; // Create the high frequency oscillator to be modulated const hfo= context. createOscillator(); hfo. frequency. value= 440.0 ; // Create a gain node whose gain determines the amplitude of the modulation signal const modulationGain= context. createGain(); modulationGain. gain. value= 50 ; // Configure the graph and start the oscillators lfo. connect( modulationGain); modulationGain. connect( hfo. detune); hfo. connect( context. destination); hfo. start( 0 ); lfo. start( 0 ); }
API 概览
定义的接口包括:
-
一个 AudioContext 接口,包含一个代表
AudioNode之间连接的音频信号图。 -
一个
AudioNode接口,代表音频源、音频输出和中间处理模块。AudioNode可以以模块化方式动态连接在一起。AudioNode存在于AudioContext的上下文中。 -
一个
AnalyserNode接口,一种用于音乐可视化或其他可视化应用的AudioNode。 -
一个
AudioBuffer接口,用于处理内存驻留的音频资产。这些可以代表单次播放的声音,或较长的音频剪辑。 -
一个
AudioBufferSourceNode接口,一种从 AudioBuffer 生成音频的AudioNode。 -
一个
AudioDestinationNode接口,一个代表所有渲染音频最终目的地的AudioNode子类。 -
一个
AudioParam接口,用于控制AudioNode功能的各个方面,如音量。 -
一个
AudioListener接口,与PannerNode配合使用进行空间化。 -
一个
AudioWorklet接口,代表用于创建自定义节点的工厂,这些节点可以直接使用脚本处理音频。 -
一个
AudioWorkletGlobalScope接口,即 AudioWorkletProcessor 处理脚本运行的上下文。 -
一个
AudioWorkletNode接口,一种代表在 AudioWorkletProcessor 中处理的节点的AudioNode。 -
一个
AudioWorkletProcessor接口,代表音频 worker 内部的单个节点实例。 -
一个
BiquadFilterNode接口,一种用于常见低阶滤波器的AudioNode,例如:-
低通
-
高通
-
带通
-
低频搁架滤波器
-
高频搁架滤波器
-
峰值滤波器
-
陷波滤波器
-
全通滤波器
-
-
一个
ChannelMergerNode接口,一种用于将来自多个音频流的声道合并为单个音频流的AudioNode。 -
一个
ChannelSplitterNode接口,一种用于在路由图中访问音频流各个声道的AudioNode。 -
一个
ConstantSourceNode接口,一种用于生成名义上恒定的输出值的AudioNode,带有AudioParam以允许对该值进行自动化。 -
一个
ConvolverNode接口,一种用于应用实时线性效果(如音乐厅的声音)的AudioNode。 -
一个
DynamicsCompressorNode接口,一种用于动态压缩的AudioNode。 -
一个
IIRFilterNode接口,一种通用 IIR 滤波器的AudioNode。 -
一个
MediaElementAudioSourceNode接口,一种来自audio、video或其他媒体元素的音频源AudioNode。 -
一个
MediaStreamAudioSourceNode接口,一种来自MediaStream(如实时音频输入或远程对端)的音频源AudioNode。 -
一个
MediaStreamTrackAudioSourceNode接口,一种来自MediaStreamTrack的音频源AudioNode。 -
一个
MediaStreamAudioDestinationNode接口,一种用于发送到远程对端的MediaStream的音频目的地AudioNode。 -
一个
PannerNode接口,一种用于在 3D 空间中进行空间化/定位音频的AudioNode。 -
一个
PeriodicWave接口,用于指定供OscillatorNode使用的自定义周期性波形。 -
一个
OscillatorNode接口,一种用于生成周期性波形的AudioNode。 -
一个
StereoPannerNode接口,一种用于在立体声流中进行等功率音频输入定位的AudioNode。 -
一个
WaveShaperNode接口,一种应用非线性波形塑形效果以产生失真和其他更微妙温和效果的AudioNode。
还有一些功能已从 Web Audio API 中弃用,但尚未移除,等待其替代品的实现经验。
-
一个
ScriptProcessorNode接口,一种直接使用脚本生成或处理音频的AudioNode。 -
一个
AudioProcessingEvent接口,这是与ScriptProcessorNode对象一起使用的事件类型。
1. 音频 API
1.1. BaseAudioContext 接口
此接口代表一组 AudioNode 对象及其连接。它允许将信号任意路由到 AudioDestinationNode。节点从上下文创建,然后连接在一起。
BaseAudioContext 不直接实例化,而是由具体接口 AudioContext(用于实时渲染)和 OfflineAudioContext(用于离线渲染)扩展。
BaseAudioContext 创建时带有一个内部槽 [[pending promises]],它是一个最初为空的有序 Promise 列表。
每个 BaseAudioContext 都有一个唯一的 媒体元素事件任务源。此外,BaseAudioContext 还有几个私有槽 [[rendering thread state]] 和 [[control thread state]],它们取自 AudioContextState,并且初始都设置为 "suspended",以及一个私有槽 [[render quantum size]],它是一个无符号整数。
enum {AudioContextState "suspended" ,"running" ,"closed" };
| 枚举值 | 描述 |
|---|---|
"suspended" | 此上下文当前处于挂起状态(上下文时间不推进,音频硬件可能已下电/释放)。 |
"running" | 音频正在被处理。 |
"closed" | 此上下文已被释放,不能再用于处理音频。所有系统音频资源已释放。 |
enum {AudioContextRenderSizeCategory "default" ,"hardware" };
| 枚举描述 | |
|---|---|
"default" | AudioContext 的渲染量子大小是 128 帧的默认值。 |
"hardware" | 用户代理选择一个最适合当前配置的渲染量子大小。 注意:这会暴露有关主机的信息,可用于指纹识别。 |
callback DecodeErrorCallback =undefined (DOMException );error callback DecodeSuccessCallback =undefined (AudioBuffer ); [decodedData Exposed =Window ]interface BaseAudioContext :EventTarget {readonly attribute AudioDestinationNode destination ;readonly attribute float sampleRate ;readonly attribute double currentTime ;readonly attribute AudioListener listener ;readonly attribute AudioContextState state ;readonly attribute unsigned long renderQuantumSize ; [SameObject ,SecureContext ]readonly attribute AudioWorklet audioWorklet ;attribute EventHandler onstatechange ;AnalyserNode createAnalyser ();BiquadFilterNode createBiquadFilter ();AudioBuffer createBuffer (unsigned long ,numberOfChannels unsigned long ,length float );sampleRate AudioBufferSourceNode createBufferSource ();ChannelMergerNode createChannelMerger (optional unsigned long numberOfInputs = 6);ChannelSplitterNode createChannelSplitter (optional unsigned long numberOfOutputs = 6);ConstantSourceNode createConstantSource ();ConvolverNode createConvolver ();DelayNode createDelay (optional double maxDelayTime = 1.0);DynamicsCompressorNode createDynamicsCompressor ();GainNode createGain ();IIRFilterNode createIIRFilter (sequence <double >,feedforward sequence <double >);feedback OscillatorNode createOscillator ();PannerNode createPanner ();PeriodicWave createPeriodicWave (sequence <float >,real sequence <float >,imag optional PeriodicWaveConstraints = {});constraints ScriptProcessorNode createScriptProcessor (optional unsigned long bufferSize = 0,optional unsigned long numberOfInputChannels = 2,optional unsigned long numberOfOutputChannels = 2);StereoPannerNode createStereoPanner ();WaveShaperNode createWaveShaper ();Promise <AudioBuffer >decodeAudioData (ArrayBuffer ,audioData optional DecodeSuccessCallback ?,successCallback optional DecodeErrorCallback ?); };errorCallback
1.1.1. 属性
audioWorklet, 类型 AudioWorklet, 只读-
允许访问
Worklet对象,该对象可以通过 [HTML] 和AudioWorklet定义的算法导入包含AudioWorkletProcessor类定义的脚本。 currentTime, 类型 double, 只读-
这是紧随上下文渲染图最近处理的音频块中最后一个采样帧之后的采样帧的时间(以秒为单位)。如果上下文的渲染图尚未处理音频块,则
currentTime的值为零。在
currentTime的时间坐标系中,零值对应于图中处理的第一个块中的第一个采样帧。此系统中的已过时间对应于BaseAudioContext生成的音频流中的已过时间,它可能与其他系统时钟不同步。(对于OfflineAudioContext,由于流没有被任何设备主动播放,甚至不存在对实时时间的近似。)Web Audio API 中的所有调度时间均相对于
currentTime的值。当
BaseAudioContext处于 "running" 状态时,此属性的值单调递增,并由渲染线程以统一的增量(对应于一个渲染量子)进行更新。因此,对于运行中的上下文,currentTime随着系统处理音频块而稳定增加,并始终代表下一个要处理的音频块的开始时间。这也是当前状态下调度任何更改可能生效的最早时间。在返回之前,
currentTime必须在控制线程上原子地读取。 destination, 类型 AudioDestinationNode, 只读-
一个带有单个输入的
AudioDestinationNode,代表所有音频的最终目的地。通常这将代表实际的音频硬件。所有主动渲染音频的AudioNode都将直接或间接地连接到destination。 listener, 类型 AudioListener, 只读-
一个用于 3D 空间化的
AudioListener。 onstatechange, 类型 EventHandler-
一个用于为事件设置事件处理程序的属性,该事件在 AudioContext 状态发生变化(即相应 promise 应该解析时)时分发给
BaseAudioContext。此事件处理程序的事件类型为statechange。一个使用Event接口的事件将分发给该事件处理程序,它可以直接查询 AudioContext 的状态。一个新创建的 AudioContext 将始终以suspended状态开始,每当状态变为不同状态时,都会触发一个状态更改事件。此事件在complete事件触发之前触发。 sampleRate, 类型 float, 只读-
BaseAudioContext处理音频的采样率(每秒采样帧数)。假设上下文中的所有AudioNode都以此速率运行。基于此假设,实时处理中不支持采样率转换器或“变速”处理器。奈奎斯特频率 (Nyquist frequency) 是此采样率值的一半。 state, 类型 AudioContextState, 只读-
描述
BaseAudioContext的当前状态。获取此属性会返回[[control thread state]]槽的内容。 renderQuantumSize, 类型 unsigned long, 只读-
获取此属性会返回
[[render quantum size]]槽的值。
1.1.2. 方法
createAnalyser()-
工厂方法,用于创建一个
AnalyserNode。无参数。返回类型:AnalyserNode createBiquadFilter()-
工厂方法,用于创建一个代表二阶滤波器的
BiquadFilterNode,该滤波器可配置为多种常见滤波器类型之一。无参数。返回类型:BiquadFilterNode createBuffer(numberOfChannels, length, sampleRate)-
创建一个给定大小的 AudioBuffer。缓冲区中的音频数据将被零初始化(静音)。如果任何参数为负数、零或超出其标称范围,则必须抛出
NotSupportedError异常。BaseAudioContext.createBuffer() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 numberOfChannelsunsigned long✘ ✘ 确定缓冲区将具有多少个声道。实现必须至少支持 32 个声道。 lengthunsigned long✘ ✘ 确定缓冲区的大小(以采样帧为单位)。这必须至少为 1。 sampleRatefloat✘ ✘ 描述缓冲区中线性 PCM 音频数据的采样率(以每秒采样帧数为单位)。实现必须至少支持 8000 到 96000 范围内的采样率。 返回类型:AudioBuffer createBufferSource()-
工厂方法,用于创建一个
AudioBufferSourceNode。无参数。返回类型:AudioBufferSourceNode createChannelMerger(numberOfInputs)-
工厂方法,用于创建一个代表声道合并器的
ChannelMergerNode。如果numberOfInputs小于 1 或大于支持的声道数,则必须抛出IndexSizeError异常。BaseAudioContext.createChannelMerger(numberOfInputs) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 numberOfInputsunsigned long✘ ✔ 确定输入数量。必须支持最多 32 个输入。如果未指定,则使用 6。返回类型:ChannelMergerNode createChannelSplitter(numberOfOutputs)-
工厂方法,用于创建一个代表声道拆分器的
ChannelSplitterNode。如果numberOfOutputs小于 1 或大于支持的声道数,则必须抛出IndexSizeError异常。BaseAudioContext.createChannelSplitter(numberOfOutputs) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 numberOfOutputsunsigned long✘ ✔ 输出数量。必须支持最多 32 个输出。如果未指定,则使用 6。返回类型:ChannelSplitterNode createConstantSource()-
工厂方法,用于创建一个
ConstantSourceNode。无参数。返回类型:ConstantSourceNode createConvolver()-
工厂方法,用于创建一个
ConvolverNode。无参数。返回类型:ConvolverNode createDelay(maxDelayTime)-
工厂方法,用于创建一个
DelayNode。初始默认延迟时间为 0 秒。BaseAudioContext.createDelay(maxDelayTime) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 maxDelayTimedouble✘ ✔ 指定允许延迟线使用的最大延迟时间(以秒为单位)。如果指定,该值必须大于零且小于三分钟,否则必须抛出 NotSupportedError异常。如果未指定,则使用1。返回类型:DelayNode createDynamicsCompressor()-
工厂方法,用于创建一个
DynamicsCompressorNode。无参数。返回类型:DynamicsCompressorNode createGain()-
无参数。返回类型:
GainNode createIIRFilter(feedforward, feedback)-
BaseAudioContext.createIIRFilter() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 feedforwardsequence<double>✘ ✘ IIR 滤波器传递函数的前馈(分子)系数数组。此数组的最大长度为 20。如果所有值均为零,必须抛出 InvalidStateError。如果数组长度为 0 或大于 20,必须抛出NotSupportedError。feedbacksequence<double>✘ ✘ IIR 滤波器传递函数的反馈(分母)系数数组。此数组的最大长度为 20。如果数组的第一个元素为 0,必须抛出 InvalidStateError。如果数组长度为 0 或大于 20,必须抛出NotSupportedError。返回类型:IIRFilterNode createOscillator()-
工厂方法,用于创建一个
OscillatorNode。无参数。返回类型:OscillatorNode createPanner()-
工厂方法,用于创建一个
PannerNode。无参数。返回类型:PannerNode createPeriodicWave(real, imag, constraints)-
工厂方法,用于创建一个
PeriodicWave。调用此方法时,请执行以下步骤:-
如果
real和imag长度不一致,则必须抛出IndexSizeError。 -
令 o 为一个新的
PeriodicWaveOptions类型对象。 -
将 o 上的
disableNormalization属性设置为传递给该工厂方法的constraints属性的disableNormalization属性值。 -
构造一个新的
PeriodicWave对象 p,将调用此工厂方法的BaseAudioContext作为第一个参数传入,以及 o。 -
返回 p。
BaseAudioContext.createPeriodicWave() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 realsequence<float>✘ ✘ 余弦参数序列。有关更详细的描述,请参见其 real构造函数参数。imagsequence<float>✘ ✘ 正弦参数序列。有关更详细的描述,请参见其 imag构造函数参数。constraintsPeriodicWaveConstraints✘ ✔ 如果不提供,波形将被归一化。否则,波形将根据 constraints给出的值进行归一化。返回类型:PeriodicWave -
createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels)-
ScriptProcessorNode的工厂方法。此方法已弃用,旨在被AudioWorkletNode取代。创建用于通过脚本进行直接音频处理的ScriptProcessorNode。如果bufferSize、numberOfInputChannels或numberOfOutputChannels超出有效范围,则必须抛出IndexSizeError异常。numberOfInputChannels和numberOfOutputChannels同时为零是不合法的。在这种情况下,必须抛出IndexSizeError。BaseAudioContext.createScriptProcessor(bufferSize, numberOfInputChannels, numberOfOutputChannels) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 bufferSizeunsigned long✘ ✔ bufferSize参数决定了缓冲区的大小(以采样帧为单位)。如果不传递该值,或者如果该值为 0,实现将根据给定环境选择最佳的缓冲区大小,该值在节点生命周期内将保持为 2 的幂。如果作者明确指定了 bufferSize,则它必须是以下值之一:256、512、1024、2048、4096、8192、16384。此值控制audioprocess事件的分发频率以及每次调用需要处理多少采样帧。较低的bufferSize值会导致更低(更好)的延迟。更高的值对于避免音频中断和故障是必要的。建议作者不要指定此缓冲区大小,而应让实现选择一个好的缓冲区大小,以平衡延迟和音频质量。如果该参数的值不是上述列出的允许的 2 的幂值之一,则必须抛出IndexSizeError。numberOfInputChannelsunsigned long✘ ✔ 此参数确定此节点的输入通道数。默认值为 2。必须支持最多 32 个通道。如果不支持通道数,则必须抛出 NotSupportedError。numberOfOutputChannelsunsigned long✘ ✔ 此参数确定此节点的输出通道数。默认值为 2。必须支持最多 32 个通道。如果不支持通道数,则必须抛出 NotSupportedError。返回类型:ScriptProcessorNode createStereoPanner()-
无参数。返回类型:
StereoPannerNode createWaveShaper()-
表示非线性失真的
WaveShaperNode的工厂方法。无参数。返回类型:WaveShaperNode decodeAudioData(audioData, successCallback, errorCallback)-
异步解码
ArrayBuffer中包含的音频文件数据。ArrayBuffer例如可以在将responseType设置为"arraybuffer"后从XMLHttpRequest的response属性加载。音频文件数据可以是audio元素支持的任何格式。传递给decodeAudioData()的缓冲区其内容类型由嗅探确定,如 [mimesniff] 中所述。虽然与此函数交互的主要方法是通过其返回的 Promise 值,但仍出于遗留原因提供了回调参数。
鼓励实现在文件损坏时警告作者。无法抛出异常,因为这会是一个破坏性更改。
注意:如果压缩的音频数据字节流已损坏,但解码仍可继续,则鼓励实现通过开发人员工具等方式警告作者。当调用decodeAudioData时,必须在控制线程上执行以下步骤-
如果 this 的 相关全局对象的 关联文档不是 完全活跃的,则返回一个以 "
InvalidStateError"DOMException拒绝的 Promise。 -
设 promise 为一个新的 Promise。
-
-
将 promise 添加到
[[pending promises]]中。 -
分离
audioDataArrayBuffer。如果此操作抛出异常,跳转至第 3 步。 -
将解码操作排队,以便在另一个线程上执行。
-
-
否则,执行以下错误步骤
-
令 error 为
DataCloneError。 -
使用 error 拒绝 promise,并将其从
[[pending promises]]中移除。 -
排队一个媒体元素任务,以使用 error 调用
errorCallback。
-
-
返回 promise。
当排队一个要在另一个线程上执行的解码操作时,以下步骤必须在一个既不是控制线程也不是渲染线程的线程上发生,该线程称为解码线程。注意: 多个
解码线程可以并行运行,以服务于对decodeAudioData的多次调用。-
令 can decode 为一个布尔标志,初始设置为 true。
-
尝试使用 MIME 嗅探 § 6.2 匹配音频或视频类型模式来确定
audioData的 MIME 类型。如果音频或视频类型模式匹配算法返回undefined,则将 can decode 设置为 false。 -
如果 can decode 为 true,尝试将编码后的
audioData解码为 线性 PCM。如果失败,将 can decode 设置为 false。如果媒体字节流包含多个音频轨道,则仅将第一个轨道解码为 线性 pcm。
注意: 需要对解码过程有更多控制的作者可以使用 [WEBCODECS]。
-
如果 can decode 为
false, 排队一个媒体元素任务以执行以下步骤-
令 error 为一个名称为
EncodingError的DOMException。-
使用 error 拒绝 promise,并将其从
[[pending promises]]中移除。
-
-
如果
errorCallback未缺失,则使用 error 调用errorCallback。
-
-
否则
-
获取表示解码后的 线性 PCM 音频数据的结果,如果其采样率与
audioData的采样率不同,则将其重采样为BaseAudioContext的采样率。 -
排队一个媒体元素任务以执行以下步骤
-
令 buffer 为包含最终结果(在可能执行重采样后)的
AudioBuffer。 -
使用 buffer 解析 promise。
-
如果
successCallback未缺失,则使用 buffer 调用successCallback。
-
-
BaseAudioContext.decodeAudioData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 audioDataArrayBuffer✘ ✘ 包含压缩音频数据的 ArrayBuffer。 successCallbackDecodeSuccessCallback?✔ ✔ 解码完成时调用的回调函数。此回调的唯一参数是一个 AudioBuffer,表示解码后的 PCM 音频数据。 errorCallbackDecodeErrorCallback?✔ ✔ 如果解码音频文件时出现错误,将调用的回调函数。 返回类型:Promise<AudioBuffer> -
1.1.3. 回调 DecodeSuccessCallback() 参数
decodedData,类型为AudioBuffer-
包含解码后的音频数据的 AudioBuffer。
1.1.4. 回调 DecodeErrorCallback() 参数
error,类型为DOMException-
解码时发生的错误。
1.1.5. 生命周期
一旦创建,AudioContext 将持续播放声音,直到没有声音可播放,或者页面关闭。
1.1.6. 缺乏内省或序列化原语
Web Audio API 对音频源调度采取发后即忘的方法。也就是说,在 AudioContext 的生命周期内,每个音符都会创建源节点,并且永远不会显式地从图中移除。这与序列化 API 不兼容,因为没有一组可以序列化的稳定节点。
此外,拥有内省 API 将允许内容脚本能够观察垃圾回收。
1.1.7. 与 BaseAudioContext 子类关联的系统资源
子类 AudioContext 和 OfflineAudioContext 应被视为昂贵的对象。创建这些对象可能涉及创建高优先级线程,或使用低延迟系统音频流,这两者都会对能源消耗产生影响。在一个文档中通常没有必要创建多个 AudioContext。
构建或恢复 BaseAudioContext 子类涉及获取该上下文的系统资源。对于 AudioContext,这还需要创建一个系统音频流。当上下文开始从其关联的音频图中生成输出时,这些操作返回。
此外,用户代理可以具有实现定义的 AudioContext 最大数量,超过该数量后,任何创建新 AudioContext 的尝试都将失败,并抛出 NotSupportedError。
suspend 和 close 允许作者释放系统资源,包括线程、进程和音频流。挂起 BaseAudioContext 允许实现释放其部分资源,并允许通过调用 resume 稍后继续操作。关闭 AudioContext 允许实现释放其所有资源,之后它将无法再次使用或恢复。
Note: 例如,这可能涉及等待音频回调定期触发,或等待硬件准备好进行处理。
1.2. AudioContext 接口
此接口表示一个音频图,其 AudioDestinationNode 被路由到产生导向用户的信号的实时输出设备。在大多数用例中,每个文档仅使用单个 AudioContext。
enum {AudioContextLatencyCategory "balanced" ,"interactive" ,"playback" };
| 枚举值 | 描述 |
|---|---|
"balanced" | 平衡音频输出延迟和功耗。 |
"interactive" | 在不产生故障的前提下提供尽可能低的音频输出延迟。这是默认值。 |
"playback" | 优先考虑持续播放而不中断,而不是音频输出延迟。最低功耗。 |
enum {AudioSinkType "none" };
| 枚举值 | 描述 |
|---|---|
"none" | 音频图将在不通过音频输出设备播放的情况下进行处理。 |
[Exposed =Window ]interface AudioContext :BaseAudioContext {constructor (optional AudioContextOptions contextOptions = {});readonly attribute double baseLatency ;readonly attribute double outputLatency ; [SecureContext ]readonly attribute (DOMString or AudioSinkInfo )sinkId ; [SecureContext ]readonly attribute AudioRenderCapacity renderCapacity ;attribute EventHandler onsinkchange ;attribute EventHandler onerror ;AudioTimestamp getOutputTimestamp ();Promise <undefined >resume ();Promise <undefined >suspend ();Promise <undefined >close (); [SecureContext ]Promise <undefined >((setSinkId DOMString or AudioSinkOptions ));sinkId MediaElementAudioSourceNode createMediaElementSource (HTMLMediaElement );mediaElement MediaStreamAudioSourceNode createMediaStreamSource (MediaStream );mediaStream MediaStreamTrackAudioSourceNode createMediaStreamTrackSource (MediaStreamTrack );mediaStreamTrack MediaStreamAudioDestinationNode createMediaStreamDestination (); };
如果用户代理允许上下文状态从 "suspended" 转换为 "running",则称 AudioContext 被允许启动。用户代理可以禁止此初始转换,并仅当 AudioContext 的 相关全局对象具有 粘性激活时才允许它。
AudioContext 具有以下内部槽位
[[suspended by user]]-
一个布尔标志,表示上下文是否由用户代码挂起。初始值为
false。 [[sink ID]]-
一个分别表示当前音频输出设备标识符或信息的
DOMString或AudioSinkInfo。初始值为"",表示默认音频输出设备。 [[pending resume promises]]
1.2.1. 构造函数
AudioContext(contextOptions)-
如果 当前设置对象的 相关全局对象的 关联文档不是 完全活跃的,抛出一个 "
创建InvalidStateError" 并中止这些步骤。AudioContext时,执行这些步骤-
令 context 为一个新的
AudioContext对象。 -
在 context 上设置一个
[[控制线程状态]]为suspended。 -
在 context 上设置一个
[[渲染线程状态]]为suspended。 -
令 messageChannel 为一个新的
MessageChannel。 -
令 controlSidePort 为 messageChannel 的
port1属性的值。 -
令 renderingSidePort 为 messageChannel 的
port2属性的值。 -
令 serializedRenderingSidePort 为 StructuredSerializeWithTransfer(renderingSidePort, « renderingSidePort ») 的结果。
-
将此
audioWorklet的port设置为 controlSidePort。 -
排队一个控制消息,以在 AudioContextGlobalScope 上设置 MessagePort,使用 serializedRenderingSidePort。
-
如果提供了
contextOptions,执行以下子步骤-
如果指定了
sinkId,令 sinkId 为contextOptions.的值,并运行以下子步骤sinkId-
如果 sinkId 和
[[sink ID]]均为DOMString类型,且它们彼此相等,中止这些子步骤。 -
如果 sinkId 为
AudioSinkOptions类型,而[[sink ID]]为AudioSinkInfo类型,且 sinkId 中的type与[[sink ID]]中的type相等,中止这些子步骤。 -
令 validationResult 为 sink 标识符验证 sinkId 的返回值。
-
如果 validationResult 为
DOMException类型,抛出一个带有 validationResult 的异常并中止这些子步骤。 -
如果 sinkId 为
DOMString类型,将[[sink ID]]设置为 sinkId 并中止这些子步骤。 -
如果 sinkId 为
AudioSinkOptions类型,将[[sink ID]]设置为使用 sinkId 的type值创建的AudioSinkInfo的新实例。
-
-
根据
contextOptions.设置 context 的内部延迟,如latencyHintlatencyHint中所述。 -
如果指定了
contextOptions.,将 context 的sampleRatesampleRate设置为此值。否则,遵循这些子步骤-
如果 sinkId 是空字符串或
AudioSinkOptions类型,使用默认输出设备的采样率。中止这些子步骤。 -
如果 sinkId 为
DOMString,使用 sinkId 标识的输出设备的采样率。中止这些子步骤。
如果
contextOptions.与输出设备的采样率不同,用户代理必须对音频输出进行重采样以匹配输出设备的采样率。sampleRateNote: 如果需要重采样,context 的延迟可能会受到影响,可能幅度很大。
-
-
-
返回 context。
发送一个控制消息以开始处理意味着执行以下步骤-
尝试获取系统资源,以根据
[[sink ID]]使用以下音频输出设备进行渲染-
空字符串的默认音频输出设备。
-
由
[[sink ID]]标识的音频输出设备。
-
如果资源获取失败,执行以下步骤
-
如果 document 不被允许使用由
"speaker-selection"标识的功能,中止这些子步骤。 -
排队一个媒体元素任务,以在
AudioContext上触发一个名为error的事件,并中止以下步骤。
-
-
-
在
AudioContext上设置 this 的[[渲染线程状态]]为running。 -
排队一个媒体元素任务以执行以下步骤
NOTE: 在
AudioContext无参数构造且资源获取失败的情况下,用户代理将尝试使用模拟音频输出设备的机制静默渲染音频图。发送一个控制消息以在AudioWorkletGlobalScope上设置MessagePort意味着在渲染线程上执行以下步骤,并使用已传输到AudioWorkletGlobalScope的 serializedRenderingSidePort-
令 deserializedPort 为 StructuredDeserialize(serializedRenderingSidePort, 当前 Realm) 的结果。
-
将
port设置为 deserializedPort。
AudioContext.constructor(contextOptions) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextOptionsAudioContextOptions✘ ✔ 用户指定的控制 AudioContext应如何构建的选项。 -
1.2.2. 属性
baseLatency, 类型为 double,只读-
这表示
AudioContext将音频从AudioDestinationNode传递到音频子系统所产生的处理延迟(以秒为单位)。它不包括AudioDestinationNode的输出与音频硬件之间的任何其他处理可能导致的额外延迟,特别是不包括音频图本身产生的任何延迟。例如,如果音频上下文以 44.1 kHz 运行,且具有默认渲染量子大小,并且
AudioDestinationNode在内部实现双缓冲,并且每个 渲染量子 都可以处理和输出音频,那么处理延迟约为 \((2\cdot128)/44100 = 5.805 \mathrm{ ms}\)。 outputLatency, 类型为 double,只读-
音频输出延迟的秒数估计,即 UA 请求宿主系统播放缓冲区的时间与缓冲区中的第一个采样实际被音频输出设备处理的时间之间的时间间隔。对于产生声学信号的扬声器或耳机等设备,后者时间指声音产生的时间。
outputLatency属性值取决于平台和连接的音频输出设备硬件。outputLatency属性值在上下文运行或相关音频输出设备更改时可能会发生变化。当需要精确同步时,经常查询此值很有用。 renderCapacity, 类型为 AudioRenderCapacity,只读-
返回与
AudioContext关联的AudioRenderCapacity实例。 sinkId, 类型为(DOMString or AudioSinkInfo),只读-
返回
[[sink ID]]内部槽位的值。此属性在更新时被缓存,并且在缓存后返回相同的对象。 onsinkchange, 类型为 EventHandler-
setSinkId()的事件处理程序。此事件处理程序的事件类型为sinkchange。当更改输出设备完成时,将分发此事件。NOTE: 这不会为
AudioContext构建时的初始设备选择分发。statechange事件可用于检查初始输出设备的就绪状态。 onerror, 类型为 EventHandler-
从
AudioContext分发的Event的事件处理程序。此处理程序的事件类型为error,用户代理可以在以下情况下分发此事件-
初始化和激活所选音频设备时遇到失败。
-
当
AudioContext在running时其关联的音频输出设备断开连接。 -
当操作系统报告音频设备故障时。
-
1.2.3. 方法
close()-
关闭
AudioContext,释放正在使用的系统资源。这不会自动释放所有AudioContext创建的对象,但会挂起AudioContext的currentTime的进程,并停止处理音频数据。当调用 close 时,执行这些步骤-
如果 this 的 相关全局对象的 关联文档不是 完全活跃的,则返回一个以 "
InvalidStateError"DOMException拒绝的 Promise。 -
设 promise 为一个新的 Promise。
-
如果
AudioContext上的[[控制线程状态]]标志为closed,使用InvalidStateError拒绝该 promise,中止这些步骤并返回 promise。 -
将
AudioContext上的[[控制线程状态]]标志设置为closed。 -
排队一个控制消息以关闭
AudioContext。 -
返回 promise。
运行一个控制消息以关闭AudioContext意味着在渲染线程上运行这些步骤-
尝试释放系统资源。
-
将
[[渲染线程状态]]设置为suspended。这将停止渲染。 -
如果此控制消息是作为对文档卸载的反应而运行的,则中止此算法。
在这种情况下,无需通知控制线程。 -
排队一个媒体元素任务以执行以下步骤
-
解析 promise。
-
如果
AudioContext的state属性尚未为 "closed"
-
当一个
AudioContext被关闭时,任何连接到AudioContext的MediaStream和HTMLMediaElement的输出将被忽略。也就是说,它们将不再导致扬声器或其他输出设备发出任何输出。为了获得更灵活的行为,请考虑使用HTMLMediaElement.captureStream()。Note: 当一个
AudioContext被关闭时,实现可以选择比挂起时更积极地释放资源。无参数。 -
createMediaElementSource(mediaElement)-
根据
HTMLMediaElement创建一个MediaElementAudioSourceNode。作为调用此方法的结果,来自HTMLMediaElement的音频播放将被重新路由到AudioContext的处理图中。AudioContext.createMediaElementSource() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 mediaElementHTMLMediaElement✘ ✘ 将被重新路由的媒体元素。 createMediaStreamDestination()-
创建一个
MediaStreamAudioDestinationNode无参数。 createMediaStreamSource(mediaStream)-
创建一个
MediaStreamAudioSourceNode。AudioContext.createMediaStreamSource() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 mediaStreamMediaStream✘ ✘ 将作为源的媒体流。 createMediaStreamTrackSource(mediaStreamTrack)-
创建一个
MediaStreamTrackAudioSourceNode。AudioContext.createMediaStreamTrackSource() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 mediaStreamTrackMediaStreamTrack✘ ✘ 将作为源的 MediaStreamTrack。其kind属性的值必须等于"audio",否则必须抛出InvalidStateError异常。 getOutputTimestamp()-
返回一个新的
AudioTimestamp实例,其中包含两个上下文相关的音频流位置值:contextTime成员包含当前由音频输出设备渲染的采样帧的时间(即输出音频流位置),其单位和原点与上下文的currentTime相同;performanceTime成员包含估计的时间,表示存储的contextTime值对应的采样帧由音频输出设备渲染的时刻,其单位和原点与performance.now()相同(如 [hr-time-3] 中所述)。如果上下文的渲染图尚未处理音频块,则
getOutputTimestamp调用返回一个两个成员都包含零的AudioTimestamp实例。在上下文的渲染图开始处理音频块后,其
currentTime属性值总是超过从getOutputTimestamp方法调用获得的contextTime值。从getOutputTimestamp方法返回的值可用于获取稍后上下文时间值的性能时间估计function outputPerformanceTime( contextTime) { const timestamp= context. getOutputTimestamp(); const elapsedTime= contextTime- timestamp. contextTime; return timestamp. performanceTime+ elapsedTime* 1000 ; } 在上述示例中,估计的准确性取决于参数值与当前输出音频流位置的接近程度:给定的
contextTime越接近timestamp.contextTime,获得的估计准确性越高。Note: 上下文的
currentTime值与从getOutputTimestamp方法调用获得的contextTime值之间的差值不能视为可靠的输出延迟估计,因为currentTime可能会以非均匀的时间间隔递增,因此应使用outputLatency属性。无参数。返回类型:AudioTimestamp resume()-
在挂起时恢复
AudioContext的currentTime的进程。当调用 resume 时,执行这些步骤-
如果 this 的 相关全局对象的 关联文档不是 完全活跃的,则返回一个以 "
InvalidStateError"DOMException拒绝的 Promise。 -
设 promise 为一个新的 Promise。
-
如果
AudioContext上的[[控制线程状态]]为closed,使用InvalidStateError拒绝该 promise,中止这些步骤并返回 promise。 -
将
[[suspended by user]]设置为false。 -
如果上下文未被允许启动,将 promise 添加到
[[pending promises]]和[[pending resume promises]]中,并中止这些步骤,返回 promise。 -
将
AudioContext上的[[控制线程状态]]设置为running。 -
排队一个控制消息以恢复
AudioContext。 -
返回 promise。
运行一个控制消息以恢复AudioContext意味着在渲染线程上运行这些步骤-
尝试获取系统资源。
-
将
AudioContext上的[[渲染线程状态]]设置为running。 -
开始渲染音频图。
-
如果失败, 排队一个媒体元素任务以执行以下步骤
-
按顺序拒绝来自
[[pending resume promises]]的所有 promise,然后清除[[pending resume promises]]。 -
此外,从
[[pending promises]]中移除这些 promise。
-
-
排队一个媒体元素任务以执行以下步骤
-
按顺序解析来自
[[pending resume promises]]的所有 promise。 -
清除
[[pending resume promises]]。此外,从[[pending promises]]中移除这些 promise。 -
解析 promise。
-
如果
AudioContext的state属性尚未为 "running"
-
无参数。 -
suspend()-
挂起
AudioContext的currentTime的进程,允许将已处理的任何当前上下文处理块播放到目的地,然后允许系统释放其对音频硬件的占用。这通常在应用程序知道它将在一段时间内不需要AudioContext,并希望暂时释放系统资源与AudioContext相关联时非常有用。当帧缓冲区为空(已移交给硬件)时,promise 解析;如果上下文已处于suspended状态,则立即解析(无其他效果)。如果上下文已关闭,promise 将被拒绝。当调用 suspend 时,执行这些步骤-
如果 this 的 相关全局对象 的 关联文档 不是 完全活动 的,则返回一个被 "
InvalidStateError"DOMException拒绝的 promise。 -
设 promise 为一个新的 Promise。
-
如果
AudioContext上的[[control thread state]]为closed,则用InvalidStateError拒绝该 promise,中止这些步骤,并返回 promise。 -
将 promise 添加到
[[pending promises]]中。 -
将
[[suspended by user]]设置为true。 -
将
AudioContext上的[[control thread state]]设置为suspended。 -
排队一个控制消息以挂起
AudioContext。 -
返回 promise。
运行一个用于挂起AudioContext的 控制消息,意味着在 渲染线程 上执行以下步骤-
尝试 释放系统资源。
-
将
AudioContext上的[[rendering thread state]]设置为suspended。 -
排队一个媒体元素任务以执行以下步骤
-
解析 promise。
-
如果
AudioContext的state属性尚不是 "suspended"-
将
AudioContext的state属性设置为 "suspended"。 -
排队一个媒体元素任务,以在
AudioContext上触发一个名为statechange的事件。
-
-
当
AudioContext被挂起时,MediaStream的输出将被忽略;也就是说,由于媒体流的实时特性,数据将会丢失。HTMLMediaElement的输出也将被忽略,直到系统恢复。AudioWorkletNode和ScriptProcessorNode在挂起时将停止调用其处理程序,但会在上下文恢复时恢复。就AnalyserNode窗口函数而言,数据被视为连续流——即resume()/suspend()不会导致AnalyserNode的数据流中出现静音。特别是,当AudioContext挂起时,重复调用AnalyserNode函数必须返回相同的数据。无参数。 -
setSinkId((DOMString or AudioSinkOptions) sinkId)-
设置输出设备的标识符。当此方法被调用时,用户代理必须运行以下步骤
-
令 sinkId 为该方法的第一个参数。
-
如果 sinkId 等于
[[sink ID]],则返回一个 promise,立即将其解析并中止这些步骤。 -
令 validationResult 为 sinkId 的 sink 标识符验证 的返回值。
-
如果 validationResult 不为
null,则返回一个被 validationResult 拒绝的 promise。中止这些步骤。 -
令 p 为一个新的 promise。
-
发送一个包含 p 和 sinkId 的 控制消息 以开始处理。
-
返回 p。
在setSinkId()期间发送一个用于开始处理的 控制消息,意味着执行以下步骤-
令 p 为传递给此算法的 promise。
-
令 sinkId 为传递给此算法的 sink 标识符。
-
如果 sinkId 和
[[sink ID]]均为DOMString类型,且它们彼此相等,则 排队一个媒体元素任务 以解析 p 并中止这些步骤。 -
如果 sinkId 为
AudioSinkOptions类型,[[sink ID]]为AudioSinkInfo类型,且 sinkId 中的type与[[sink ID]]中的type相等,则 排队一个媒体元素任务 以解析 p 并中止这些步骤。 -
令 wasRunning 为 true。
-
如果
AudioContext上的[[rendering thread state]]为"suspended",则将 wasRunning 设置为 false。 -
在处理完当前渲染量子(render quantum)后暂停渲染器。
-
尝试 释放系统资源。
-
如果 wasRunning 为 true
-
将
AudioContext上的[[rendering thread state]]设置为"suspended"。 -
排队一个媒体元素任务以执行以下步骤
-
如果
AudioContext的state属性尚不是 "suspended"-
将
AudioContext的state属性设置为 "suspended"。 -
触发一个名为
statechange的事件,并在关联的AudioContext上触发。
-
-
-
-
尝试 获取系统资源,以基于
[[sink ID]]使用后续音频输出设备进行渲染-
空字符串的默认音频输出设备。
-
由
[[sink ID]]标识的音频输出设备。
如果失败,则用 "
InvalidAccessError" 拒绝 p,中止以下步骤。 -
-
排队一个媒体元素任务以执行以下步骤
-
如果 sinkId 是
DOMString类型,将[[sink ID]]设置为 sinkId。中止这些步骤。 -
如果 sinkId 是
AudioSinkOptions类型,且[[sink ID]]是DOMString类型,将[[sink ID]]设置为使用 sinkId 的type值创建的AudioSinkInfo的新实例。 -
如果 sinkId 是
AudioSinkOptions类型,且[[sink ID]]是AudioSinkInfo类型,将[[sink ID]]的type设置为 sinkId 的type值。 -
解析 p。
-
触发一个名为
sinkchange的事件,并在关联的AudioContext上触发。
-
-
如果 wasRunning 为 true
-
将
AudioContext上的[[rendering thread state]]设置为"running"。 -
排队一个媒体元素任务以执行以下步骤
-
如果
AudioContext的state属性尚不是 "running"-
将
AudioContext的state属性设置为 "running"。 -
触发一个名为
statechange的事件,并在关联的AudioContext上触发。
-
-
-
-
1.2.4. 验证 sinkId
此算法用于验证为修改 sinkId 而提供的信息
-
令 document 为当前设置对象的 关联文档。
-
令 sinkIdArg 为传递给此算法的值。
-
如果 document 不被允许使用由
"speaker-selection"标识的功能,则返回一个新的DOMException,其名称为 "NotAllowedError"。 -
如果 sinkIdArg 是
DOMString类型,但它既不是空字符串,也不匹配任何由enumerateDevices()提供结果所标识的音频输出设备,则返回一个新的DOMException,其名称为 "NotFoundError"。 -
返回
null。
1.2.5. AudioContextOptions
AudioContextOptions 字典用于指定 AudioContext 的用户自定义选项。
dictionary AudioContextOptions { (AudioContextLatencyCategory or double )latencyHint = "interactive";float sampleRate ; (DOMString or AudioSinkOptions )sinkId ; (AudioContextRenderSizeCategory or unsigned long )renderSizeHint = "default"; };
1.2.5.1. 字典 AudioContextOptions 成员
latencyHint, 类型为(AudioContextLatencyCategory 或 double),默认为"interactive"-
标识播放类型,这会影响音频输出延迟与功耗之间的权衡。
latencyHint的首选值是来自AudioContextLatencyCategory的值。但是,也可以指定一个 double 类型的值作为延迟秒数,以更精细地控制延迟与功耗的平衡。浏览器有权自行解释该数值。实际使用的延迟由AudioContext的baseLatency属性给出。 sampleRate, 类型为 float-
将创建的
AudioContext的sampleRate设置为此值。支持的值与AudioBuffer的采样率相同。如果不支持指定的采样率,则必须抛出NotSupportedError异常。如果未指定
sampleRate,则使用此AudioContext的输出设备的首选采样率。 sinkId, 类型为(DOMString 或 AudioSinkOptions)-
音频输出设备的标识符或相关信息。更多详情请参阅
sinkId。 renderSizeHint, 类型为(AudioContextRenderSizeCategory 或 unsigned long),默认为"default"-
这允许用户在传入整数时请求特定的 渲染量子大小,在不传参或传入
"default"时使用默认的 128 帧,或者在指定"hardware"时请求用户代理选择一个合适的 渲染量子大小。这只是一个提示,可能不被采纳。
1.2.6. AudioSinkOptions
AudioSinkOptions 字典用于为 sinkId 指定选项。
dictionary AudioSinkOptions {required AudioSinkType type ; };
1.2.6.1. 字典 AudioSinkOptions 成员
type, 类型为 AudioSinkType-
AudioSinkType的一个值,用于指定设备的类型。
1.2.7. AudioSinkInfo
AudioSinkInfo 接口用于通过 sinkId 获取当前音频输出设备的信息。
[Exposed =Window ]interface AudioSinkInfo {readonly attribute AudioSinkType type ; };
1.2.7.1. 属性
type, 类型为 AudioSinkType,只读-
表示设备类型的一个
AudioSinkType值。
1.2.8. AudioTimestamp
dictionary AudioTimestamp {double contextTime ;DOMHighResTimeStamp performanceTime ; };
1.2.8.1. 字典 AudioTimestamp 成员
contextTime, 类型为 double-
表示 BaseAudioContext 的
currentTime时间坐标系中的一个点。 performanceTime, 类型为 DOMHighResTimeStamp-
表示
Performance接口实现的时间坐标系中的一个点(详见 [hr-time-3])。
1.2.9. AudioRenderCapacity
[Exposed =Window ]interface :AudioRenderCapacity EventTarget {undefined start (optional AudioRenderCapacityOptions = {});options undefined stop ();attribute EventHandler onupdate ; };
此接口提供了 AudioContext 的渲染性能指标。为了计算这些指标,渲染器会针对每个 系统级音频回调 收集一个 负载值。
1.2.9.1. 属性
onupdate, 类型为 EventHandler-
此事件处理程序的事件类型是
update。分发给此事件处理程序的事件将使用AudioRenderCapacityEvent接口。
1.2.9.2. 方法
start(options)-
开始指标收集和分析。这将根据
AudioRenderCapacityOptions中给定的更新间隔,反复在AudioRenderCapacity上触发一个名为update的事件,并使用AudioRenderCapacityEvent。 stop()-
停止指标收集和分析。它也会停止分发
update事件。
1.2.10. AudioRenderCapacityOptions
AudioRenderCapacityOptions 字典可用于为 AudioRenderCapacity 提供用户选项。
dictionary {AudioRenderCapacityOptions double updateInterval = 1; };
1.2.10.1. 字典 AudioRenderCapacityOptions 成员
updateInterval, 类型为 double,默认为1-
用于分发
AudioRenderCapacityEvent的更新间隔(以秒为单位)。针对每个 系统级音频回调 计算一个 负载值,并且会在指定的间隔周期内收集多个负载值。例如,如果渲染器以 48Khz 的采样率运行,且 系统级音频回调 的缓冲区大小为 192 帧,则在 1 秒的间隔内将收集 250 个负载值。如果给定值小于 系统级音频回调 的持续时间,则抛出
NotSupportedError。
1.2.11. AudioRenderCapacityEvent
[Exposed =Window ]interface :AudioRenderCapacityEvent Event {(constructor DOMString ,type optional AudioRenderCapacityEventInit = {});eventInitDict readonly attribute double timestamp ;readonly attribute double averageLoad ;readonly attribute double peakLoad ;readonly attribute double underrunRatio ; };dictionary :AudioRenderCapacityEventInit EventInit {double = 0;timestamp double = 0;averageLoad double = 0;peakLoad double = 0; };underrunRatio
1.2.11.1. 属性
timestamp, 类型为 double,只读-
数据收集周期的开始时间,以关联的
AudioContext的currentTime表示。 averageLoad, 类型为 double,只读-
在给定更新间隔内收集的负载值的平均值。精度限制为 1/100。
peakLoad, 类型为 double,只读-
在给定更新间隔内收集的负载值中的最大值。精度同样限制为 1/100。
underrunRatio, 类型为 double,只读-
在给定更新间隔内,缓冲区欠载(负载值大于 1.0)次数与 系统级音频回调 总次数之间的比率。
其中 \(u\) 是缓冲区欠载次数,\(N\) 是在给定更新间隔内 系统级音频回调 的总次数,缓冲区欠载比率为
-
如果 \(u\) = 0,则为 0.0。
-
否则,计算 \(u/N\) 并取最接近 100 分之一的向上取整值。
-
1.3. OfflineAudioContext 接口
OfflineAudioContext 是一种特殊的 BaseAudioContext,用于(可能)比实时更快的渲染/混音。它不渲染到音频硬件,而是尽可能快地进行渲染,并将渲染结果作为 AudioBuffer 履行返回的 promise。
[Exposed =Window ]interface OfflineAudioContext :BaseAudioContext {constructor (OfflineAudioContextOptions contextOptions );constructor (unsigned long numberOfChannels ,unsigned long length ,float sampleRate );Promise <AudioBuffer >startRendering ();Promise <undefined >resume ();Promise <undefined >suspend (double );suspendTime readonly attribute unsigned long length ;attribute EventHandler oncomplete ; };
1.3.1. 构造函数
OfflineAudioContext(contextOptions)-
如果 当前设置对象 的 相关全局对象 的 关联文档 不是 完全活动 的,则抛出
令 c 为一个新的InvalidStateError并中止这些步骤。OfflineAudioContext对象。按如下方式初始化 c-
将 c 的
[[control thread state]]设置为"suspended"。 -
将 c 的
[[rendering thread state]]设置为"suspended"。 -
基于
renderSizeHint的值,确定此OfflineAudioContext的[[render quantum size]]-
如果其默认值为
"default"或"hardware",则将[[render quantum size]]私有槽位设置为 128。 -
否则,如果传入的是一个整数,则用户代理可以决定通过将其设置为
[[render quantum size]]私有槽位来采纳此值。
-
-
构建一个
AudioDestinationNode,其channelCount设置为contextOptions.numberOfChannels。 -
令 messageChannel 为一个新的
MessageChannel。 -
令 controlSidePort 为 messageChannel 的
port1属性的值。 -
令 renderingSidePort 为 messageChannel 的
port2属性的值。 -
令 serializedRenderingSidePort 为 StructuredSerializeWithTransfer(renderingSidePort, « renderingSidePort ») 的结果。
-
将此
audioWorklet的port设置为 controlSidePort。 -
排队一个控制消息以在
AudioContext上设置 AudioContextGlobalScope 上的 MessagePort,并传入 serializedRenderingSidePort。
OfflineAudioContext.constructor(contextOptions) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextOptions构建此上下文所需的初始参数。 -
OfflineAudioContext(numberOfChannels, length, sampleRate)-
OfflineAudioContext可以使用与 AudioContext.createBuffer 相同的参数进行构建。如果任何参数为负数、零或超出其标称范围,则必须抛出NotSupportedError异常。构建 OfflineAudioContext 的过程等同于
new OfflineAudioContext({ numberOfChannels: numberOfChannels, length: length, sampleRate: sampleRate}) 调用以下方法。
OfflineAudioContext.constructor(numberOfChannels, length, sampleRate) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 numberOfChannelsunsigned long✘ ✘ 确定缓冲区将具有多少个通道。支持的通道数请参阅 createBuffer()。lengthunsigned long✘ ✘ 确定以采样帧为单位的缓冲区大小。 sampleRatefloat✘ ✘ 描述缓冲区中 线性 PCM 音频数据的采样率(以每秒采样帧数为单位)。有效采样率请参阅 createBuffer()。
1.3.2. 属性
length, 类型为 unsigned long,只读-
缓冲区的大小(以采样帧为单位)。这与构造函数中
length参数的值相同。 oncomplete, 类型为 EventHandler-
此事件处理程序的事件类型是
complete。分发给此事件处理程序的事件将使用OfflineAudioCompletionEvent接口。这是在OfflineAudioContext上触发的最后一个事件。
1.3.3. 方法
startRendering()-
基于当前的连接和预定的更改,开始渲染音频。
虽然获取渲染音频数据的主要方法是通过其 promise 返回值,但出于遗留原因,该实例也会触发一个名为
complete的事件。令[[rendering started]]为此OfflineAudioContext的一个内部槽位。将此槽位初始化为 false。当调用
startRendering时,必须在 控制线程 上执行以下步骤- 如果 this 的 相关全局对象 的 关联文档 不是 完全活动 的,则返回一个被 "
InvalidStateError"DOMException拒绝的 promise。 - 如果
OfflineAudioContext上的[[rendering started]]槽位为 true,则返回一个被InvalidStateError拒绝的 promise,并中止这些步骤。 - 将
OfflineAudioContext的[[rendering started]]槽位设置为 true。 - 设 promise 为一个新的 Promise。
- 创建一个新的
AudioBuffer,其通道数、长度和采样率分别等于在contextOptions参数中传递给此实例构造函数的numberOfChannels、length和sampleRate值。将此缓冲区分配给OfflineAudioContext中的一个内部槽位[[rendered buffer]]。 - 如果在前面的
AudioBuffer构造函数调用期间抛出了异常,则用该异常拒绝 promise。 - 否则,如果缓冲区构建成功,则 开始离线渲染。
- 将 promise 添加到
[[pending promises]]中。 - 返回 promise。
要 开始离线渲染,必须在为此专门创建的 渲染线程 上执行以下步骤。- 基于当前的连接和预定的更改,开始将
length个音频采样帧渲染到[[rendered buffer]]中 - 对于每个 渲染量子,检查并在必要时
挂起渲染。 - 如果挂起的上下文恢复,则继续渲染缓冲区。
- 一旦渲染完成, 排队一个媒体元素任务以执行以下步骤
- 用
[[rendered buffer]]解析由startRendering()创建的 promise。 - 排队一个媒体元素任务,以在
OfflineAudioContext上触发一个名为complete的事件,使用OfflineAudioCompletionEvent,并将其renderedBuffer属性设置为[[rendered buffer]]。
- 用
无参数。返回类型:Promise<AudioBuffer> - 如果 this 的 相关全局对象 的 关联文档 不是 完全活动 的,则返回一个被 "
resume()-
在
OfflineAudioContext的currentTime被挂起时,恢复其进程。当调用 resume 时,执行这些步骤-
如果 this 的 相关全局对象 的 关联文档 不是 完全活动 的,则返回一个被 "
InvalidStateError"DOMException拒绝的 promise。 -
设 promise 为一个新的 Promise。
-
当以下任一条件为真时,中止这些步骤并用
InvalidStateError拒绝 promise-
OfflineAudioContext上的[[control thread state]]为closed。 -
OfflineAudioContext上的[[rendering started]]槽位为 false。
-
-
将
OfflineAudioContext上的[[control thread state]]标志设置为running。 -
返回 promise。
运行一个用于恢复OfflineAudioContext的 控制消息,意味着在 渲染线程 上执行这些步骤-
将
OfflineAudioContext上的[[rendering thread state]]设置为running。 -
开始渲染音频图。
-
如果失败, 排队一个媒体元素任务以拒绝 promise 并中止剩余步骤。
-
排队一个媒体元素任务以执行以下步骤
-
解决(Resolve)promise。
-
如果
OfflineAudioContext的state属性尚不是 "running"-
将
OfflineAudioContext的state属性设置为 "running"。 -
排队一个媒体元素任务,以在
OfflineAudioContext上触发一个名为statechange的事件。
-
-
无参数。 -
suspend(suspendTime)-
在指定时间安排音频上下文的时间进度挂起,并返回一个 promise。这在
OfflineAudioContext上同步操作音频图时通常很有用。注意,挂起的最大精度是 渲染量子 的大小,指定的挂起时间将被四舍五入到最近的 渲染量子 边界。因此,不允许在同一个量化帧安排多次挂起。此外,为了确保精确的挂起,应在上下文未运行时进行安排。
OfflineAudioContext.suspend() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 suspendTimedouble✘ ✘ 安排在指定时间挂起渲染,该时间将被量化并向上取整至 渲染量子 大小。如果量化后的帧数 - 为负数,或
- 小于或等于当前时间,或
- 大于或等于总渲染持续时间,或
- 由另一个挂起操作安排在同一时间,
InvalidStateError拒绝。
1.3.4. OfflineAudioContextOptions
这指定了在构建 OfflineAudioContext 时使用的选项。
dictionary OfflineAudioContextOptions {unsigned long numberOfChannels = 1;required unsigned long length ;required float sampleRate ; (AudioContextRenderSizeCategory or unsigned long )renderSizeHint = "default"; };
1.3.4.1. 字典 OfflineAudioContextOptions 成员
length, 类型为 unsigned long-
渲染出的
AudioBuffer的长度(以采样帧为单位)。 numberOfChannels, 类型为 unsigned long,默认为1-
此
OfflineAudioContext的通道数。 sampleRate, 类型为 float-
此
OfflineAudioContext的采样率。 renderSizeHint, 类型为(AudioContextRenderSizeCategory 或 unsigned long),默认为"default"-
此
OfflineAudioContext的 渲染量子大小 提示。
1.3.5. OfflineAudioCompletionEvent 接口
这是一个 Event 对象,出于遗留原因,它被分发给 OfflineAudioContext。
[Exposed =Window ]interface OfflineAudioCompletionEvent :Event {(constructor DOMString ,type OfflineAudioCompletionEventInit );eventInitDict readonly attribute AudioBuffer renderedBuffer ; };
1.3.5.1. 属性
renderedBuffer, 类型为 AudioBuffer,只读-
包含渲染出的音频数据的
AudioBuffer。
1.3.5.2. OfflineAudioCompletionEventInit
dictionary OfflineAudioCompletionEventInit :EventInit {required AudioBuffer renderedBuffer ; };
1.3.5.2.1. 字典 OfflineAudioCompletionEventInit 成员
renderedBuffer, 类型为 AudioBuffer-
要分配给事件的
renderedBuffer属性的值。
1.4. AudioBuffer 接口
此接口表示驻留在内存中的音频资源。它可以包含一个或多个通道,每个通道呈现为标称范围为 \([-1,1]\) 的 32 位浮点 线性 PCM 值,但数值不限于此范围。通常,PCM 数据的长度预计会比较短(通常少于一分钟)。对于较长的声音(例如电影原声带),应使用 audio 元素和 MediaElementAudioSourceNode 进行流式传输。
AudioBuffer 可以被一个或多个 AudioContext 使用,并且可以在 OfflineAudioContext 和 AudioContext 之间共享。
AudioBuffer 有四个内部槽位
[[number of channels]]-
此
AudioBuffer的音频通道数,是一个 unsigned long。 [[length]]-
此
AudioBuffer中每个通道的长度,是一个 unsigned long。 [[sample rate]]-
此
AudioBuffer的采样率(以 Hz 为单位),是一个 float。 [[internal data]]-
一个保存音频样本数据的 数据块。
[Exposed =Window ]interface AudioBuffer {constructor (AudioBufferOptions );options readonly attribute float sampleRate ;readonly attribute unsigned long length ;readonly attribute double duration ;readonly attribute unsigned long numberOfChannels ;Float32Array getChannelData (unsigned long );channel undefined copyFromChannel (Float32Array ,destination unsigned long ,channelNumber optional unsigned long = 0);bufferOffset undefined copyToChannel (Float32Array ,source unsigned long ,channelNumber optional unsigned long = 0); };bufferOffset
1.4.1. 构造函数
AudioBuffer(options)-
-
如果
options中的任何值超出其标称范围,则抛出NotSupportedError异常并中止以下步骤。 -
令 b 为一个新的
AudioBuffer对象。 -
分别将构造函数中传入的
AudioBufferOptions的numberOfChannels、length、sampleRate属性值分配给内部槽位[[number of channels]]、[[length]]、[[sample rate]]。 -
将此
AudioBuffer的内部槽位[[internal data]]设置为调用CreateByteDataBlock(的结果。[[length]]*[[number of channels]])注意:这将底层存储初始化为零。
-
返回 b。
AudioBuffer.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 optionsAudioBufferOptions✘ ✘ 一个确定此 AudioBuffer属性的AudioBufferOptions。 -
1.4.2. 属性
duration, 类型为 double,只读-
PCM 音频数据的持续时间(以秒为单位)。
这是通过将
AudioBuffer的[[length]]除以[[sample rate]]计算得出的。 length, 类型为 unsigned long,只读-
PCM 音频数据的长度(以采样帧为单位)。这必须返回
[[length]]的值。 numberOfChannels, 类型为 unsigned long,只读-
离散音频通道的数量。这必须返回
[[number of channels]]的值。 sampleRate, 类型为 float,只读-
PCM 音频数据的采样率(以每秒采样数为单位)。这必须返回
[[sample rate]]的值。
1.4.3. 方法
copyFromChannel(destination, channelNumber, bufferOffset)-
copyFromChannel()方法将样本从AudioBuffer的指定通道复制到destination数组中。设
buffer为包含 \(N_b\) 帧的AudioBuffer,设 \(N_f\) 为destination数组中的元素数量,设 \(k\) 为bufferOffset的值。那么从buffer复制到destination的帧数为 \(\max(0, \min(N_b - k, N_f))\)。如果该值小于 \(N_f\),则destination的其余元素不会被修改。AudioBuffer.copyFromChannel() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationFloat32Array✘ ✘ 将要复制通道数据到的数组。 channelNumberunsigned long✘ ✘ 要复制数据的通道索引。如果 channelNumber大于或等于AudioBuffer的通道数,则必须抛出IndexSizeError。bufferOffsetunsigned long✘ ✔ 一个可选的偏移量,默认为 0。从该偏移量开始的 AudioBuffer数据将被复制到destination。返回类型:undefined copyToChannel(source, channelNumber, bufferOffset)-
copyToChannel()方法将source数组中的采样点复制到AudioBuffer的指定通道。如果无法将
source复制到缓冲区,可能会抛出UnknownError。设
buffer为包含 \(N_b\) 帧的AudioBuffer,设 \(N_f\) 为source数组中的元素数量,设 \(k\) 为bufferOffset的值。那么从source复制到buffer的帧数为 \(\max(0, \min(N_b - k, N_f))\)。如果该值小于 \(N_f\),则buffer的其余元素不会被修改。AudioBuffer.copyToChannel() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 sourceFloat32Array✘ ✘ 将要从中复制通道数据的数组。 channelNumberunsigned long✘ ✘ 要复制数据到的通道索引。如果 channelNumber大于或等于AudioBuffer的通道数,则必须抛出IndexSizeError。bufferOffsetunsigned long✘ ✔ 一个可选的偏移量,默认为 0。来自 source的数据将从该偏移量开始复制到AudioBuffer。返回类型:undefined getChannelData(channel)-
根据 获取内容 中描述的规则,允许 写入 或 获取副本 存储在
[[internal data]]中的字节,并返回一个新的Float32Array。如果无法创建
[[internal data]]或新的Float32Array,可能会抛出UnknownError。AudioBuffer.getChannelData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 channelunsigned long✘ ✘ 此参数是一个索引,表示要获取数据的特定通道。索引值 0 表示第一个通道。此索引值必须小于 [[number of channels]],否则必须抛出IndexSizeError异常。返回类型:Float32Array
注意: 方法 copyToChannel() 和 copyFromChannel() 可用于填充数组的一部分,通过传入一个更大的数组的 Float32Array 视图。当从 AudioBuffer 的通道中读取数据,并且可以分块处理数据时,应优先使用 copyFromChannel(),而不是调用 getChannelData() 并访问生成的数组,因为这样可以避免不必要的内存分配和复制。
当某些 API 实现需要 AudioBuffer 的内容时,会调用内部操作 获取 AudioBuffer 的内容。此操作向调用者返回不可变的通道数据。
AudioBuffer 上发生 获取内容 操作时,执行以下步骤-
如果任何
AudioBuffer的ArrayBuffer已 分离 (detached),则返回true,中止这些步骤,并向调用者返回一个零长度的通道数据缓冲区。 -
分离 该
AudioBuffer上先前通过getChannelData()返回的所有数组的ArrayBuffer。注意: 因为
AudioBuffer只能通过createBuffer()或AudioBuffer构造函数创建,所以这不会抛出异常。 -
保留来自这些
ArrayBuffer的底层[[internal data]],并将它们的引用返回给调用者。 -
将包含数据副本的
ArrayBuffer附加到AudioBuffer,以便在下一次调用getChannelData()时返回。
获取 AudioBuffer 的内容 操作在以下情况下被调用
-
当调用
AudioBufferSourceNode.start时,它会 获取 节点的buffer内容。如果操作失败,则不会播放任何内容。 -
当设置
AudioBufferSourceNode的buffer并且之前已经调用了AudioBufferSourceNode.start时,设置器会 获取AudioBuffer的内容。如果操作失败,则不会播放任何内容。 -
当
ConvolverNode的buffer被设置为AudioBuffer时,它会 获取AudioBuffer的内容。 -
当
AudioProcessingEvent的分发完成时,它会 获取 其outputBuffer的内容。
注意: 这意味着 copyToChannel() 不能用于更改当前正被某个 AudioNode 使用的 AudioBuffer 的内容,因为该 AudioNode 已经 获取了 AudioBuffer 的内容,并且将继续使用先前获取的数据。
1.4.4. AudioBufferOptions
这指定了用于构建 AudioBuffer 的选项。length 和 sampleRate 成员是必需的。
dictionary AudioBufferOptions {unsigned long numberOfChannels = 1;required unsigned long length ;required float sampleRate ; };
1.4.4.1. 字典 AudioBufferOptions 成员
此字典成员的允许值受到限制。请参阅 createBuffer()。
length, 类型为 unsigned long-
缓冲区的采样帧长度。请参阅
length了解限制。 numberOfChannels, 类型为 unsigned long,默认为1-
缓冲区的通道数。请参阅
numberOfChannels了解限制。 sampleRate, 类型为 float-
缓冲区的采样率(以 Hz 为单位)。请参阅
sampleRate了解限制。
1.5. AudioNode 接口
AudioNode 是 AudioContext 的构建块。此接口代表音频源、音频目标和中间处理模块。这些模块可以连接在一起,形成 处理图 以便将音频渲染到音频硬件。每个节点可以有 输入 和/或 输出。源节点 没有输入,只有一个输出。大多数处理节点(如滤波器)有一个输入和一个输出。每种类型的 AudioNode 在处理或合成音频的具体细节上有所不同。但是,通常情况下,AudioNode 会处理其输入(如果有的话),并为其输出生成音频(如果有的话)。
每个输出都有一个或多个通道。确切的通道数取决于特定 AudioNode 的细节。
一个输出可以连接到一个或多个 AudioNode 输入,因此支持 扇出 (fan-out)。一个输入最初没有连接,但可以从一个或多个 AudioNode 输出连接,因此支持 扇入 (fan-in)。当调用 connect() 方法将 AudioNode 的输出连接到 AudioNode 的输入时,我们将此称为到该输入的 连接。
每个 AudioNode 的 输入 在任何给定时间都有特定数量的通道。这个数字可能会随着对该输入进行的 连接 而改变。如果输入没有连接,则它有一个静音的通道。
对于每个 输入,AudioNode 对所有到该输入的连接进行混合。有关规范要求和详细信息,请参阅 § 4 通道上混和下混。
无论节点是否连接了输出,也无论这些输出最终是否到达 AudioContext 的 AudioDestinationNode,AudioNode 的输入处理和内部操作都会相对于 AudioContext 时间持续进行。
[Exposed =Window ]interface AudioNode :EventTarget {AudioNode connect (AudioNode destinationNode ,optional unsigned long output = 0,optional unsigned long input = 0);undefined connect (AudioParam destinationParam ,optional unsigned long output = 0);undefined disconnect ();undefined disconnect (unsigned long output );undefined disconnect (AudioNode destinationNode );undefined disconnect (AudioNode destinationNode ,unsigned long output );undefined disconnect (AudioNode destinationNode ,unsigned long output ,unsigned long input );undefined disconnect (AudioParam destinationParam );undefined disconnect (AudioParam destinationParam ,unsigned long output );readonly attribute BaseAudioContext context ;readonly attribute unsigned long numberOfInputs ;readonly attribute unsigned long numberOfOutputs ;attribute unsigned long channelCount ;attribute ChannelCountMode channelCountMode ;attribute ChannelInterpretation channelInterpretation ; };
1.5.1. AudioNode 创建
AudioNode 可以通过两种方式创建:使用该特定接口的构造函数,或使用 BaseAudioContext 或 AudioContext 上的 工厂方法。
作为 AudioNode 构造函数的第一个参数传递的 BaseAudioContext 被称为要创建的 AudioNode 的 关联 BaseAudioContext。类似地,使用工厂方法时,AudioNode 的 关联 BaseAudioContext 就是调用该工厂方法的 BaseAudioContext。
AudioNode 的对象 o,意味着给定传递给该接口构造函数的参数 context 和 dict,执行以下步骤。-
将 o 的关联
BaseAudioContext设置为 context。 -
将其
numberOfInputs、numberOfOutputs、channelCount、channelCountMode和channelInterpretation的值设置为每个AudioNode章节中概述的该特定接口的默认值。 -
对于传递进来的 dict 的每个成员,执行这些步骤,其中 k 为成员的键,v 为其值。如果在执行这些步骤时抛出任何异常,则中止迭代并将异常传播给算法的调用者(构造函数或工厂方法)。
-
如果 k 是此接口上某个
AudioParam的名称,则将该AudioParam的value属性设置为 v。 -
否则,如果 k 是此接口上某个属性的名称,则将与该属性关联的对象设置为 v。
-
工厂方法的 关联接口 是该方法返回的对象的接口。关联选项对象 是可以传递给该接口构造函数的选项对象。
AudioNode 是 EventTarget,如 [DOM] 中所述。这意味着可以像其他 EventTarget 接受事件一样,向 AudioNode 分发事件。
enum {ChannelCountMode "max" ,"clamped-max" ,"explicit" };
ChannelCountMode 结合节点的 channelCount 和 channelInterpretation 值,用于确定控制如何混合到节点输入的 computedNumberOfChannels(计算出的通道数)。computedNumberOfChannels 的确定方式如下所示。有关如何进行混合的更多信息,请参阅 § 4 通道上混和下混。
| 枚举值 | 描述 |
|---|---|
"max" | computedNumberOfChannels 是所有到输入的连接中通道数的最大值。在此模式下,channelCount 被忽略。 |
"clamped-max" | computedNumberOfChannels 的确定方式与 "max" 相同,然后被限制为给定的 channelCount 的最大值。 |
"explicit" | computedNumberOfChannels 是由 channelCount 指定的精确值。 |
enum {ChannelInterpretation "speakers" ,"discrete" };
| 枚举值 | 描述 |
|---|---|
"speakers" | 使用 上混公式 或 下混公式。如果通道数与任何这些基本扬声器布局不匹配,则回退到 "discrete"。 |
"discrete" | 通过填充通道直到耗尽来上混,然后将剩余通道置零。通过填充尽可能多的通道来下混,然后丢弃剩余通道。 |
1.5.2. AudioNode 尾音 (Tail-Time)
AudioNode 可以具有 尾音时长。这意味着即使在 AudioNode 被输入静音时,输出也可能不是静音的。
如果 AudioNode 具有内部处理状态,使得过去的输入会影响未来的输出,则它具有非零的尾音时长。AudioNode 即使在输入从非静音变为静音后,也可能在计算出的尾音时长内继续产生非静音输出。
1.5.3. AudioNode 生命周期
如果满足以下任一条件,AudioNode 在 渲染量子 (render quantum) 期间可以是 主动处理的。
-
当且仅当
AudioScheduledSourceNode在当前渲染量子的至少一部分期间正在 播放 时,它就是 主动处理的。 -
当且仅当
MediaElementAudioSourceNode的mediaElement在当前渲染量子的至少一部分期间正在播放时,它就是 主动处理的。 -
当关联的
MediaStreamTrack对象的readyState属性等于"live",muted属性等于false且enabled属性等于true时,MediaStreamAudioSourceNode或MediaStreamTrackAudioSourceNode是 主动处理的。 -
仅当当前 渲染量子 的任何输出采样的绝对值大于或等于 \( 2^{-126} \) 时,循环中的
DelayNode才是 主动处理的。 -
当其输入或输出已连接时,
ScriptProcessorNode是 主动处理的。 -
当其
AudioWorkletProcessor的[[callable process]]返回true,且其 活动源 标志为true,或者连接到其输入之一的任何AudioNode是 主动处理的 时,AudioWorkletNode是 主动处理的。 -
当连接到其输入之一的任何
AudioNode是 主动处理的 时,所有其他AudioNode开始 主动处理;当从其他 主动处理的AudioNode接收到的输入不再影响输出时,停止 主动处理。
1.5.4. 属性
channelCount, 类型为 unsigned long-
channelCount是上混和下混到节点任何输入的连接时使用的通道数。默认值为 2,但特定节点除外,其值是专门确定的。此属性对于没有输入的节点无效。如果此值设置为零或大于实现的最大通道数的值,实现必须抛出NotSupportedError异常。此外,某些节点对通道数可能的值有额外的 channelCount 约束
AudioDestinationNode-
行为取决于目标节点是
AudioContext还是OfflineAudioContext的目标AudioContext-
通道数必须在 1 和
maxChannelCount之间。任何在此时范围之外设置通道数的尝试都必须抛出IndexSizeError异常。 OfflineAudioContext-
通道数无法更改。任何尝试更改该值的行为都必须抛出
InvalidStateError异常。
AudioWorkletNodeChannelMergerNode-
通道数无法更改,且任何尝试更改该值的行为都必须抛出
InvalidStateError异常。 ChannelSplitterNode-
通道数无法更改,且任何尝试更改该值的行为都必须抛出
InvalidStateError异常。 ConvolverNode-
通道数不能大于 2,且任何尝试将其更改为大于 2 的值的行为都必须抛出
NotSupportedError异常。 DynamicsCompressorNode-
通道数不能大于 2,且任何尝试将其更改为大于 2 的值的行为都必须抛出
NotSupportedError异常。 PannerNode-
通道数不能大于 2,且任何尝试将其更改为大于 2 的值的行为都必须抛出
NotSupportedError异常。 ScriptProcessorNode-
通道数无法更改,且任何尝试更改该值的行为都必须抛出
NotSupportedError异常。 StereoPannerNode-
通道数不能大于 2,且任何尝试将其更改为大于 2 的值的行为都必须抛出
NotSupportedError异常。
有关此属性的更多信息,请参阅 § 4 通道上混和下混。
channelCountMode, 类型为 ChannelCountMode-
channelCountMode决定了在对节点任何输入的连接进行上混和下混时如何计算通道。默认值为 "max"。此属性对于没有输入的节点无效。此外,某些节点对通道计数模式可能的值有额外的 channelCountMode 约束
AudioDestinationNode-
如果
AudioDestinationNode是OfflineAudioContext的destination节点,则通道计数模式无法更改。任何尝试更改该值的行为都必须抛出InvalidStateError异常。 ChannelMergerNode-
通道计数模式无法从 "
explicit" 更改,且任何尝试更改该值的行为都必须抛出InvalidStateError异常。 ChannelSplitterNode-
通道计数模式无法从 "
explicit" 更改,且任何尝试更改该值的行为都必须抛出InvalidStateError异常。 ConvolverNode-
通道计数模式无法设置为 "
max",且任何尝试将其设置为 "max" 的行为都必须抛出NotSupportedError异常。 DynamicsCompressorNode-
通道计数模式无法设置为 "
max",且任何尝试将其设置为 "max" 的行为都必须抛出NotSupportedError异常。 PannerNode-
通道计数模式无法设置为 "
max",且任何尝试将其设置为 "max" 的行为都必须抛出NotSupportedError异常。 ScriptProcessorNode-
通道计数模式无法从 "
explicit" 更改,且任何尝试更改该值的行为都必须抛出NotSupportedError异常。 StereoPannerNode-
通道计数模式无法设置为 "
max",且任何尝试将其设置为 "max" 的行为都必须抛出NotSupportedError异常。
有关此属性的更多信息,请参阅 § 4 通道上混和下混 章节。
channelInterpretation, 类型为 ChannelInterpretation-
channelInterpretation决定了在对节点任何输入的连接进行上混和下混时如何对待各个通道。默认值为 "speakers"。此属性对于没有输入的节点无效。此外,某些节点对通道解释可能的值有额外的 channelInterpretation 约束
ChannelSplitterNode-
通道解释无法从 "
discrete" 更改,且任何尝试更改该值的行为都必须抛出InvalidStateError异常。
有关此属性的更多信息,请参阅 § 4 通道上混和下混。
context, 类型为 BaseAudioContext,只读-
拥有此
AudioNode的BaseAudioContext。 numberOfInputs, 类型为 unsigned long,只读-
馈入
AudioNode的输入数量。对于 源节点,此值为 0。此属性对于许多AudioNode类型是预先确定的,但某些AudioNode(如ChannelMergerNode和AudioWorkletNode)具有可变的输入数量。 numberOfOutputs, 类型为 unsigned long,只读-
来自
AudioNode的输出数量。此属性对于某些AudioNode类型是预先确定的,但可以是可变的,例如ChannelSplitterNode和AudioWorkletNode。
1.5.5. 方法
connect(destinationNode, output, input)-
一个特定节点的给定输出与另一个特定节点的给定输入之间只能有一个连接。具有相同端点的多个连接将被忽略。
此方法返回
destinationAudioNode对象。AudioNode.connect(destinationNode, output, input) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationNodedestination参数是要连接到的AudioNode。如果destination参数是使用另一个AudioContext创建的AudioNode,则必须抛出InvalidAccessError。 也就是说,AudioNode不能在AudioContext之间共享。多个AudioNode可以连接到同一个AudioNode,这在 通道上混和下混 章节中有描述。outputunsigned long✘ ✔ output参数是一个索引,描述要连接AudioNode的哪个输出。如果此参数越界,则必须抛出IndexSizeError异常。 可以通过多次调用 connect() 将一个AudioNode输出连接到多个输入。因此,支持 "扇出"。input (输入)input参数是一个索引,描述要连接到目标AudioNode的哪个输入。如果此参数越界,则必须抛出IndexSizeError异常。 可以将一个AudioNode连接到另一个AudioNode,从而创建一个 循环 (cycle):一个AudioNode可以连接到另一个AudioNode,该节点又连接回第一个AudioNode的输入或AudioParam。返回类型:AudioNode connect(destinationParam, output)-
将
AudioNode连接到AudioParam,使用 a-rate 信号控制参数值。可以通过多次调用 connect() 将一个
AudioNode输出连接到多个AudioParam。因此,支持 "扇出"。可以通过多次调用 connect() 将多个
AudioNode输出连接到单个AudioParam。因此,支持 "扇入"。AudioParam将从连接到它的任何AudioNode输出中获取渲染后的音频数据,如果不已经是单声道,则通过下混 将其转换为单声道,然后将其与其他此类输出混合,最后与 固有 (intrinsic) 参数值(在没有任何音频连接的情况下AudioParam通常具有的value)进行混合,包括为该参数调度的任何时间轴更改。下混至单声道等同于
AudioNode的下混,其中channelCount= 1,channelCountMode= "explicit",并且channelInterpretation= "speakers"。一个特定节点的给定输出与特定
AudioParam之间只能有一个连接。具有相同端点的多个连接将被忽略。AudioNode.connect(destinationParam, output) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationParamAudioParam✘ ✘ destination参数是要连接到的AudioParam。此方法不返回destinationAudioParam对象。如果destinationParam属于一个AudioNode,而该节点又属于一个与调用此方法的BaseAudioContext不同的BaseAudioContext,则必须抛出InvalidAccessError。outputunsigned long✘ ✔ output参数是一个索引,描述要连接AudioNode的哪个输出。如果parameter越界,则必须抛出IndexSizeError异常。返回类型:undefined disconnect()-
断开
AudioNode的所有传出连接。无参数。返回类型:undefined disconnect(output)-
断开
AudioNode的单个输出与它连接到的任何其他AudioNode或AudioParam对象之间的连接。AudioNode.disconnect(output) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 outputunsigned long✘ ✘ 此参数是一个索引,描述要断开 AudioNode的哪个输出。它断开从给定输出发出的所有传出连接。如果此参数越界,则必须抛出IndexSizeError异常。返回类型:undefined disconnect(destinationNode)-
断开
AudioNode指向特定目标AudioNode的所有输出。AudioNode.disconnect(destinationNode) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationNodedestinationNode参数是要断开连接的AudioNode。它断开所有指向给定destinationNode的传出连接。如果没有到destinationNode的连接,则必须抛出InvalidAccessError异常。返回类型:undefined disconnect(destinationNode, output)-
断开
AudioNode的特定输出与某些目标AudioNode的任何和所有输入之间的连接。AudioNode.disconnect(destinationNode, output) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationNodedestinationNode参数是要断开连接的AudioNode。如果给定输出没有到destinationNode的连接,则必须抛出InvalidAccessError异常。outputunsigned long✘ ✘ output参数是一个索引,描述要断开AudioNode的哪个输出。如果此参数越界,则必须抛出IndexSizeError异常。返回类型:undefined disconnect(destinationNode, output, input)-
断开
AudioNode的特定输出与某些目标AudioNode的特定输入之间的连接。AudioNode.disconnect(destinationNode, output, input) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationNodedestinationNode参数是要断开连接的AudioNode。如果给定输出没有到给定输入的destinationNode的连接,则必须抛出InvalidAccessError异常。outputunsigned long✘ ✘ output参数是一个索引,描述要断开AudioNode的哪个输出。如果此参数越界,则必须抛出IndexSizeError异常。input (输入)input参数是一个索引,描述要断开目标AudioNode的哪个输入。如果此参数越界,则必须抛出IndexSizeError异常。返回类型:undefined disconnect(destinationParam)-
断开
AudioNode指向特定目标AudioParam的所有输出。当此操作生效时,此AudioNode对计算参数值的贡献变为 0。固有参数值不受此操作的影响。AudioNode.disconnect(destinationParam) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationParamAudioParam✘ ✘ destinationParam参数是要断开连接的AudioParam。如果没有到destinationParam的连接,则必须抛出InvalidAccessError异常。返回类型:undefined disconnect(destinationParam, output)-
断开
AudioNode的特定输出与特定目标AudioParam之间的连接。当此操作生效时,此AudioNode对计算参数值的贡献变为 0。固有参数值不受此操作的影响。AudioNode.disconnect(destinationParam, output) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 destinationParamAudioParam✘ ✘ destinationParam参数是要断开连接的AudioParam。如果没有到destinationParam的连接,则必须抛出InvalidAccessError异常。outputunsigned long✘ ✘ output参数是一个索引,描述要断开AudioNode的哪个输出。如果parameter越界,则必须抛出IndexSizeError异常。返回类型:undefined
1.5.6. AudioNodeOptions
这指定了可用于构建所有 AudioNode 的选项。所有成员都是可选的。但是,每个节点使用的具体值取决于实际节点。
dictionary AudioNodeOptions {unsigned long channelCount ;ChannelCountMode channelCountMode ;ChannelInterpretation channelInterpretation ; };
1.5.6.1. 字典 AudioNodeOptions 成员
channelCount, 类型为 unsigned long-
channelCount属性所需的通道数。 channelCountMode, 类型为 ChannelCountMode-
channelCountMode属性所需的模式。 channelInterpretation, 类型为 ChannelInterpretation-
channelInterpretation属性所需的模式。
1.6. AudioParam 接口
AudioParam 控制 AudioNode 功能的各个方面,例如音量。参数可以使用 value 属性立即设置为特定值。或者,可以安排在非常精确的时间点(在 AudioContext 的 currentTime 属性坐标系中)进行值更改,用于包络、音量淡入淡出、LFO、滤波器扫描、颗粒窗口等。通过这种方式,可以在任何 AudioParam 上设置任意基于时间轴的自动化曲线。此外,来自 AudioNode 输出的音频信号可以连接到 AudioParam,并与 固有 参数值求和。
一些合成和处理 AudioNode 具有作为属性的 AudioParam,其值必须在每个音频采样基础上考虑。对于其他 AudioParam,采样精度并不重要,值更改可以更粗略地采样。每个单独的 AudioParam 将指定它是 a-rate 参数(意味着其值必须在每个音频采样基础上考虑),还是 k-rate 参数。
实现必须使用块处理,每个 AudioNode 处理一个 渲染量子。
对于每个 渲染量子,k-rate 参数的值必须在第一个采样帧时采样,并且该值必须用于整个块。a-rate 参数必须为块的每个采样帧进行采样。根据 AudioParam,其速率可以通过将 automationRate 属性设置为 "a-rate" 或 "k-rate" 来控制。有关更多详细信息,请参阅各个 AudioParam 的说明。
每个 AudioParam 都包含 minValue 和 maxValue 属性,它们共同构成了参数的简单标称范围。实际上,参数的值会被钳位(clamp)到范围 \([\mathrm{minValue}, \mathrm{maxValue}]\) 中。详细信息请参阅 § 1.6.3 数值计算。
对于许多 AudioParam 而言,minValue 和 maxValue 旨在被设置为最大可能的范围。在这种情况下,maxValue 应设置为 最大正单精度浮点数,即 3.4028235e38。(然而,在仅支持 IEEE-754 双精度浮点值的 JavaScript 中,必须写作 3.4028234663852886e38。)同样地,minValue 应设置为 最小负单精度浮点数,即 最大正单精度浮点数 的负值:-3.4028235e38。(类似地,在 JavaScript 中必须写作 -3.4028234663852886e38。)
AudioParam 维护一个包含零个或多个 自动化事件 的列表。每个自动化事件指定了参数值在特定时间范围内的变化,该时间是相对于 AudioContext 的 currentTime 属性所处时间坐标系下的 自动化事件时间。自动化事件列表按自动化事件时间的升序进行维护。
给定自动化事件的行为是 AudioContext 当前时间,以及该事件和列表中相邻事件的自动化事件时间的函数。以下 自动化方法 通过向事件列表添加特定于该方法类型的事件来更改事件列表:
-
setValueAtTime()-SetValue -
linearRampToValueAtTime()-LinearRampToValue -
exponentialRampToValueAtTime()-ExponentialRampToValue -
setTargetAtTime()-SetTarget -
setValueCurveAtTime()-SetValueCurve
调用这些方法时适用以下规则:
-
自动化事件时间不会根据当前采样率进行量化。计算曲线和斜坡的公式适用于调度事件时给出的精确数值时间。
-
如果在一个已经存在一个或多个事件的时间点添加其中一个事件,则该事件将被放置在列表中的这些事件之后,但在时间晚于该事件的事件之前。
-
如果为时间 \(T\) 和持续时间 \(D\) 调用了 setValueCurveAtTime(),且存在时间严格大于 \(T\) 但严格小于 \(T + D\) 的任何事件,则必须抛出
NotSupportedError异常。 换句话说,不允许在包含其他事件的时间段内调度值曲线,但允许在与其他事件完全相同的时间点调度值曲线。 -
类似地,如果任何 自动化方法 在包含于 \([T, T+D)\) 的时间内被调用(\(T\) 为曲线的时间,\(D\) 为其持续时间),则必须抛出
NotSupportedError异常。
注意: AudioParam 属性除 value 属性外均为只读。
AudioParam 的自动化速率可以通过设置 automationRate 属性并赋予以下值之一来选择。然而,一些 AudioParam 对能否更改自动化速率有约束。
enum {AutomationRate "a-rate" ,"k-rate" };
| 枚举值 | 描述 |
|---|---|
"a-rate" | 此 AudioParam 设置为 a-rate 处理。 |
"k-rate" | 此 AudioParam 设置为 k-rate 处理。 |
每个 AudioParam 都有一个内部槽位 [[current value]],初始值设为 AudioParam 的 defaultValue。
[Exposed =Window ]interface AudioParam {attribute float value ;attribute AutomationRate automationRate ;readonly attribute float defaultValue ;readonly attribute float minValue ;readonly attribute float maxValue ;AudioParam setValueAtTime (float ,value double );startTime AudioParam linearRampToValueAtTime (float ,value double );endTime AudioParam exponentialRampToValueAtTime (float ,value double );endTime AudioParam setTargetAtTime (float ,target double ,startTime float );timeConstant AudioParam setValueCurveAtTime (sequence <float >,values double ,startTime double );duration AudioParam cancelScheduledValues (double );cancelTime AudioParam cancelAndHoldAtTime (double ); };cancelTime
1.6.1. 属性
automationRate, 类型为 AutomationRate-
AudioParam的自动化速率。默认值取决于具体的AudioParam;关于默认值,请参阅每个单独AudioParam的描述。某些节点具有额外的 自动化速率约束,如下所示:
AudioBufferSourceNode-
AudioParam的playbackRate和detune必须为 "k-rate"。 如果速率更改为 "a-rate",则必须抛出InvalidStateError。 DynamicsCompressorNode-
AudioParam的threshold、knee、ratio、attack和release必须为 "k-rate"。 如果速率更改为 "a-rate",则必须抛出InvalidStateError。 PannerNode-
如果
panningModel为 "HRTF",则PannerNode的任何AudioParam的automationRate设置都将被忽略。同样,AudioListener的任何AudioParam的automationRate设置也会被忽略。在这种情况下,AudioParam的行为表现得就像automationRate被设置为 "k-rate" 一样。
defaultValue, 类型为 float,只读-
value属性的初始值。 maxValue, 类型为 float,只读-
参数可以取的标称最大值。与
minValue一起,构成了该参数的 标称范围。 minValue, 类型为 float,只读-
参数可以取的标称最小值。与
maxValue一起,构成了该参数的 标称范围。 value, 类型为 float-
参数的浮点数值。此属性初始化为
defaultValue。获取此属性将返回
[[current value]]槽位的内容。关于返回值的算法,请参阅 § 1.6.3 数值计算。设置此属性的效果是将请求的值分配给
[[current value]]槽位,并以当前AudioContext的currentTime和[[current value]]调用 setValueAtTime() 方法。setValueAtTime()抛出的任何异常也将在设置此属性时抛出。
1.6.2. 方法
cancelAndHoldAtTime(cancelTime)-
这与
cancelScheduledValues()类似,都会取消所有时间大于或等于cancelTime的计划参数更改。然而,它额外将本应在cancelTime发生的自动化值保持,并持续到引入其他自动化事件为止。当自动化正在运行,并且可以在调用
cancelAndHoldAtTime()之后且达到cancelTime之前的任何时间点引入新自动化时,时间线的行为非常复杂。因此,cancelAndHoldAtTime()的行为在以下算法中指定。设 \(t_c\) 为cancelTime的值。那么:-
设 \(E_1\) 为时间 \(t_1\) 处的事件(如果存在),其中 \(t_1\) 是满足 \(t_1 \le t_c\) 的最大数。
-
设 \(E_2\) 为时间 \(t_2\) 处的事件(如果存在),其中 \(t_2\) 是满足 \(t_c \lt t_2\) 的最小数。
-
如果 \(E_2\) 存在
-
如果 \(E_2\) 是线性或指数斜坡,
-
实际上将 \(E_2\) 重写为同类型的斜坡,结束于时间 \(t_c\),且结束值应为原始斜坡在时间 \(t_c\) 时的值。
-
转至第 5 步。
-
-
否则,转至第 4 步。
-
-
如果 \(E_1\) 存在
-
如果 \(E_1\) 是
setTarget事件,-
在时间 \(t_c\) 处隐式插入一个
setValueAtTime事件,其值为setTarget在时间 \(t_c\) 时应有的值。 -
转至第 5 步。
-
-
如果 \(E_1\) 是开始时间为 \(t_3\)、持续时间为 \(d\) 的
setValueCurve-
如果 \(t_c \gt t_3 + d\),转至第 5 步。
-
否则,
-
实际上将此事件替换为开始时间为 \(t_3\)、新持续时间为 \(t_c-t_3\) 的
setValueCurve事件。然而,这不是真正的替换;此自动化必须确保产生与原始输出相同的输出,而不是使用不同持续时间计算出的输出。(那会导致以略微不同的方式对值曲线进行采样,从而产生不同的结果。) -
转至第 5 步。
-
-
-
-
移除所有时间大于 \(t_c\) 的事件。
如果没有添加任何事件,则
cancelAndHoldAtTime()之后的自动化值即为原始时间线在时间 \(t_c\) 时的常量值。AudioParam.cancelAndHoldAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 cancelTimedouble✘ ✘ 在此时间之后,任何先前计划的参数更改都将被取消。它与 AudioContext的currentTime属性处于相同的时间坐标系中。 如果cancelTime为负数,则必须抛出RangeError异常。如果cancelTime小于currentTime,则将其钳位到currentTime。返回类型:AudioParam -
cancelScheduledValues(cancelTime)-
取消所有时间大于或等于
cancelTime的计划参数更改。取消计划的参数更改意味着从事件列表中删除该计划的事件。任何 自动化事件时间 小于cancelTime的活动自动化也会被取消,此类取消可能会导致不连续性,因为原始值(在此类自动化之前的值)会立即恢复。如果由cancelAndHoldAtTime()计划的保持值在cancelTime之后发生,则也会被移除。对于
setValueCurveAtTime(),设 \(T_0\) 和 \(T_D\) 分别为该事件的相应startTime和duration。那么,如果cancelTime在范围 \([T_0, T_0 + T_D]\) 内,则从时间线中移除该事件。AudioParam.cancelScheduledValues() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 cancelTimedouble✘ ✘ 在此时间之后,任何先前计划的参数更改都将被取消。它与 AudioContext的currentTime属性处于相同的时间坐标系中。 如果cancelTime为负数,则必须抛出RangeError异常。 如果cancelTime小于currentTime,则将其钳位到currentTime。返回类型:AudioParam exponentialRampToValueAtTime(value, endTime)-
计划从上一个计划参数值到给定值的指数连续参数值变化。由于人类感知声音的方式,代表滤波器频率和播放速率的参数最好以指数方式进行更改。
时间间隔 \(T_0 \leq t < T_1\) 内的值(其中 \(T_0\) 是上一个事件的时间,\(T_1\) 是传入此方法的
endTime参数)将按如下计算:$$ v(t) = V_0 \left(\frac{V_1}{V_0}\right)^\frac{t - T_0}{T_1 - T_0} $$其中 \(V_0\) 是时间 \(T_0\) 处的值,\(V_1\) 是传入此方法的
value参数。如果 \(V_0\) 和 \(V_1\) 符号相反,或者 \(V_0\) 为零,则对于 \(T_0 \leq t < T_1\),\(v(t) = V_0\)。这也意味着指数斜坡到 0 是不可能的。使用
setTargetAtTime()和适当选择的时间常数可以实现很好的近似。如果在此 ExponentialRampToValue 事件之后没有更多事件,则对于 \(t \geq T_1\),\(v(t) = V_1\)。
如果没有事件在该事件之前,指数斜坡的行为就好像调用了
setValueAtTime(value, currentTime),其中value是属性的当前值,而currentTime是调用exponentialRampToValueAtTime()时上下文的currentTime。如果前一个事件是
SetTarget事件,则 \(T_0\) 和 \(V_0\) 从SetTarget自动化的当前时间和值中选择。即,如果SetTarget事件尚未开始,\(T_0\) 为该事件的开始时间,\(V_0\) 为SetTarget事件开始前的值。在这种情况下,ExponentialRampToValue事件有效地取代了SetTarget事件。如果SetTarget事件已经开始,\(T_0\) 为当前的上下文时间,\(V_0\) 为时间 \(T_0\) 处SetTarget自动化的当前值。在这两种情况下,自动化曲线都是连续的。AudioParam.exponentialRampToValueAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 valuefloat✘ ✘ 参数将在给定时间指数级斜坡到达的值。 如果此值等于 0,则必须抛出 RangeError异常。endTimedouble✘ ✘ 与 AudioContext的currentTime属性处于相同时间坐标系下指数斜坡结束的时间。 如果endTime为负数或不是有限数字,则必须抛出RangeError异常。 如果 endTime 小于currentTime,则将其钳位到currentTime。返回类型:AudioParam linearRampToValueAtTime(value, endTime)-
计划从上一个计划参数值到给定值的线性连续参数值变化。
时间间隔 \(T_0 \leq t < T_1\) 内的值(其中 \(T_0\) 是上一个事件的时间,\(T_1\) 是传入此方法的
endTime参数)将按如下计算:$$ v(t) = V_0 + (V_1 - V_0) \frac{t - T_0}{T_1 - T_0} $$其中 \(V_0\) 是时间 \(T_0\) 处的值,\(V_1\) 是传入此方法的
value参数。如果在此 LinearRampToValue 事件之后没有更多事件,则对于 \(t \geq T_1\),\(v(t) = V_1\)。
如果没有事件在该事件之前,线性斜坡的行为就好像调用了
setValueAtTime(value, currentTime),其中value是属性的当前值,而currentTime是调用linearRampToValueAtTime()时上下文的currentTime。如果前一个事件是
SetTarget事件,则 \(T_0\) 和 \(V_0\) 从SetTarget自动化的当前时间和值中选择。即,如果SetTarget事件尚未开始,\(T_0\) 为该事件的开始时间,\(V_0\) 为SetTarget事件开始前的值。在这种情况下,LinearRampToValue事件有效地取代了SetTarget事件。如果SetTarget事件已经开始,\(T_0\) 为当前的上下文时间,\(V_0\) 为时间 \(T_0\) 处SetTarget自动化的当前值。在这两种情况下,自动化曲线都是连续的。AudioParam.linearRampToValueAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 valuefloat✘ ✘ 参数将在给定时间线性斜坡到达的值。 endTimedouble✘ ✘ 与 AudioContext的currentTime属性处于相同时间坐标系下,自动化结束的时间。 如果endTime为负数或不是有限数字,则必须抛出RangeError异常。 如果 endTime 小于currentTime,则将其钳位到currentTime。返回类型:AudioParam setTargetAtTime(target, startTime, timeConstant)-
在给定时间以给定的时间常数开始以指数方式趋向于目标值。除其他用途外,这对于实现 ADSR 包络的“衰减”和“释放”部分非常有用。请注意,参数值在给定时间不会立即变为目标值,而是逐渐变为目标值。
在时间间隔 \(T_0 \leq t\) 期间,其中 \(T_0\) 是
startTime参数:$$ v(t) = V_1 + (V_0 - V_1)\, e^{-\left(\frac{t - T_0}{\tau}\right)} $$其中 \(V_0\) 是 \(T_0\) (
startTime参数)时的初始值([[current value]]属性),\(V_1\) 等于target参数,\(\tau\) 是timeConstant参数。如果
LinearRampToValue或ExponentialRampToValue事件跟随此事件,其行为分别在linearRampToValueAtTime()或exponentialRampToValueAtTime()中描述。对于所有其他事件,SetTarget事件在下一个事件的时间结束。AudioParam.setTargetAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 targetfloat✘ ✘ 参数将在给定时间开始更改到的值。 startTimedouble✘ ✘ 指数趋近开始的时间,与 AudioContext的currentTime属性处于相同时间坐标系中。 如果start为负数或不是有限数字,则必须抛出RangeError异常。 如果 startTime 小于currentTime,则将其钳位到currentTime。timeConstantfloat✘ ✘ 一阶滤波器(指数)趋向目标值的时间常数值。此值越大,过渡越慢。 该值必须是非负数,否则必须抛出 RangeError异常。 如果timeConstant为零,输出值会立即跳变至最终值。更准确地说,timeConstant 是一阶线性连续时不变系统在给定阶跃输入响应(从 0 到 1 值的过渡)时达到值 \(1 - 1/e\)(约 63.2%)所需的时间。返回类型:AudioParam setValueAtTime(value, startTime)-
计划在给定时间更改参数值。
如果在此
SetValue事件之后没有更多事件,则对于 \(t \geq T_0\),\(v(t) = V\),其中 \(T_0\) 是startTime参数,\(V\) 是value参数。换句话说,该值将保持不变。如果此
SetValue事件之后的下一个事件(时间为 \(T_1\))不是LinearRampToValue或ExponentialRampToValue类型,则对于 \(T_0 \leq t < T_1\)$$ v(t) = V $$换句话说,该值在此时间间隔内将保持不变,允许创建“阶梯”函数。
如果此
SetValue事件之后的下一个事件是LinearRampToValue或ExponentialRampToValue类型,请分别参阅linearRampToValueAtTime()或exponentialRampToValueAtTime()。AudioParam.setValueAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 valuefloat✘ ✘ 参数将在给定时间更改到的值。 startTimedouble✘ ✘ 与 BaseAudioContext的currentTime属性处于相同时间坐标系下,参数更改为给定值的时间。 如果startTime为负数或不是有限数字,则必须抛出RangeError异常。 如果 startTime 小于currentTime,则将其钳位到currentTime。返回类型:AudioParam setValueCurveAtTime(values, startTime, duration)-
设置一系列任意参数值,从给定时间开始持续给定持续时间。值的数量将被缩放以适合所需的持续时间。
设 \(T_0\) 为
startTime,\(T_D\) 为duration,\(V\) 为values数组,\(N\) 为values数组的长度。那么,在时间间隔 \(T_0 \le t < T_0 + T_D\) 期间,设$$ \begin{align*} k &= \left\lfloor \frac{N - 1}{T_D}(t-T_0) \right\rfloor \\ \end{align*} $$那么 \(v(t)\) 通过在 \(V[k]\) 和 \(V[k+1]\) 之间进行线性插值计算得出,
在曲线时间间隔结束(\(t \ge T_0 + T_D\))之后,该值将保持在最终曲线值不变,直到出现另一个自动化事件(如果有)。
在时间 \(T_0 + T_D\) 处对
setValueAtTime()进行隐式调用,值为 \(V[N-1]\),以便后续自动化将从setValueCurveAtTime()事件的末尾开始。AudioParam.setValueCurveAtTime() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 值sequence<float>✘ ✘ 代表参数值曲线的浮点值序列。这些值将从给定时间开始应用,并持续给定的持续时间。当调用此方法时,会出于自动化目的创建曲线的内部副本。因此,后续对传入数组内容的修改对 AudioParam没有影响。 如果此属性是一个长度小于 2 的sequence<float>对象,则必须抛出InvalidStateError异常。startTimedouble✘ ✘ 与 AudioContext的currentTime属性处于相同时间坐标系下,将应用值曲线的开始时间。 如果startTime为负数或不是有限数字,则必须抛出RangeError异常。 如果 startTime 小于currentTime,则将其钳位到currentTime。durationdouble✘ ✘ (在 startTime参数之后)值将根据values参数计算的时间秒数。 如果duration不是严格正数或不是有限数字,则必须抛出RangeError异常。返回类型:AudioParam
1.6.3. 数值计算
AudioParam 有两种不同类型,简单参数和复合参数。简单参数(默认值)单独使用,用于计算 AudioNode 的最终音频输出。复合参数 是与其他 AudioParam 一起使用的 AudioParam,用于计算一个值,该值随后被用作输入来计算 AudioNode 的输出。
computedValue 是控制音频 DSP 的最终值,由音频渲染线程在每个渲染时间量(render quantum)内进行计算。
AudioParam 值的计算由两部分组成:-
作为控制音频 DSP 的最终值,由音频渲染线程在每个 渲染时间量 内计算出的 paramComputedValue。
这些值必须按如下方式计算:
-
paramIntrinsicValue 将在每个时间点进行计算,该值要么直接设置为
value属性,要么如果有任何在此时间或之前的时间点发生的 自动化事件,则计算出的值源自这些事件。如果从给定时间范围中移除了自动化事件,则 paramIntrinsicValue 值将保持不变,直到直接设置value属性或为该时间范围添加了自动化事件。 -
在该 渲染时间量 的开始时,将
[[current value]]设置为 paramIntrinsicValue 的值。 -
paramComputedValue 是 paramIntrinsicValue 值和 输入 AudioParam 缓冲区 值之和。如果和为
NaN,则用defaultValue替换该和。 -
如果此
AudioParam是一个 复合参数,则与其他AudioParam一起计算其最终值。 -
将 computedValue 设置为 paramComputedValue。
computedValue 的 标称范围 是此参数可以有效具有的低值和高值。对于 简单参数,computedValue 被钳位到该参数的 简单标称范围。复合参数在根据它们组成的各种 AudioParam 值计算后,其最终值被钳位到它们的 标称范围。
当使用自动化方法时,仍然适用钳位。然而,自动化的运行就好像完全没有钳位一样。只有当自动化值要应用于输出时,才按照上述指定进行钳位。
N. p. setValueAtTime( 0 , 0 ); N. p. linearRampToValueAtTime( 4 , 1 ); N. p. linearRampToValueAtTime( 0 , 2 );
曲线的初始斜率为 4,直到达到最大值 1,此时输出保持恒定。最后,在时间 2 附近,曲线斜率为 -4。这在下图中得到说明,其中虚线表示没有裁切时会发生的情况,实线表示由于钳位到标称范围而导致的 audioparam 的实际预期行为。
1.6.4. AudioParam 自动化示例
const curveLength= 44100 ; const curve= new Float32Array( curveLength); for ( const i= 0 ; i< curveLength; ++ i) curve[ i] = Math. sin( Math. PI* i/ curveLength); const t0= 0 ; const t1= 0.1 ; const t2= 0.2 ; const t3= 0.3 ; const t4= 0.325 ; const t5= 0.5 ; const t6= 0.6 ; const t7= 0.7 ; const t8= 1.0 ; const timeConstant= 0.1 ; param. setValueAtTime( 0.2 , t0); param. setValueAtTime( 0.3 , t1); param. setValueAtTime( 0.4 , t2); param. linearRampToValueAtTime( 1 , t3); param. linearRampToValueAtTime( 0.8 , t4); param. setTargetAtTime( .5 , t4, timeConstant); // Compute where the setTargetAtTime will be at time t5 so we can make // the following exponential start at the right point so there’s no // jump discontinuity. From the spec, we have // v(t) = 0.5 + (0.8 - 0.5)*exp(-(t-t4)/timeConstant) // Thus v(t5) = 0.5 + (0.8 - 0.5)*exp(-(t5-t4)/timeConstant) param. setValueAtTime( 0.5 + ( 0.8 - 0.5 ) * Math. exp( - ( t5- t4) / timeConstant), t5); param. exponentialRampToValueAtTime( 0.75 , t6); param. exponentialRampToValueAtTime( 0.05 , t7); param. setValueCurveAtTime( curve, t7, t8- t7);
1.7. AudioScheduledSourceNode 接口
该接口代表了源节点的共同特征,例如 AudioBufferSourceNode、ConstantSourceNode 和 OscillatorNode。
在源开始(通过调用 start())之前,源节点必须输出静音(0)。在源停止(通过调用 stop())之后,源必须输出静音(0)。
AudioScheduledSourceNode 不能直接实例化,而是由源节点的具体接口扩展。
当 AudioScheduledSourceNode 关联的 BaseAudioContext 的 currentTime 大于或等于设置的开始时间,且小于设置的停止时间时,称该 AudioScheduledSourceNode 为 正在播放。
AudioScheduledSourceNode 创建时带有一个内部布尔槽位 [[source started]],初始值设为 false。
[Exposed =Window ]interface AudioScheduledSourceNode :AudioNode {attribute EventHandler onended ;undefined start (optional double when = 0);undefined stop (optional double when = 0); };
1.7.1. 属性
onended, 类型为 EventHandler-
用于设置
ended事件类型 事件处理器 的属性,该事件类型被分发给AudioScheduledSourceNode节点类型。当源节点停止播放时(由具体节点确定),将向事件处理器分发一个使用Event接口的事件。对于所有
AudioScheduledSourceNode,当达到由stop()确定的停止时间时,将分发ended事件。对于AudioBufferSourceNode,如果达到了duration,或者如果整个buffer已播放完毕,也会分发该事件。
1.7.2. 方法
start(when)-
计划在精确的时间播放声音。
调用此方法时,执行以下步骤:-
如果此
AudioScheduledSourceNode内部槽位[[source started]]为 true,则必须抛出InvalidStateError异常。 -
检查是否因下述参数约束而必须抛出任何错误。如果在执行此步骤期间抛出任何异常,请中止这些步骤。
-
将此
AudioScheduledSourceNode上的内部槽位[[source started]]设置为true。 -
排队一个控制消息以启动
AudioScheduledSourceNode,并在消息中包含参数值。 -
仅在满足以下所有条件时,向关联的
AudioContext发送一条 控制消息 以 开始运行其渲染线程:-
该上下文的
[[control thread state]]为 "suspended"。 -
上下文 允许启动。
-
[[suspended by user]]标志为false。
注意: 这允许
start()启动一个当前 允许启动 但先前被阻止启动的AudioContext。 -
AudioScheduledSourceNode.start(when) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 whendouble✘ ✔ when参数描述声音应在何时(以秒为单位)开始播放。它与AudioContext的currentTime属性处于相同时间坐标系中。当AudioScheduledSourceNode发出的信号取决于声音的开始时间时,when的精确值始终被使用,而不会四舍五入到最近的采样帧。如果此值传入 0,或者如果该值小于currentTime,则声音将立即开始播放。 如果when为负数,则必须抛出RangeError异常。返回类型:undefined -
stop(when)-
计划在精确的时间停止声音播放。如果已经调用过
stop后再次调用,则只有最后一次调用会被应用;先前的调用设置的停止时间将不会被应用,除非缓冲区在随后的任何调用之前已经停止。如果缓冲区已经停止,则后续调用stop将无效。如果停止时间早于计划的开始时间,则声音不会播放。调用此方法时,执行以下步骤:-
如果此
AudioScheduledSourceNode内部槽位[[source started]]不为true,则必须抛出InvalidStateError异常。 -
检查是否因下述参数约束而必须抛出任何错误。
-
排队一个控制消息以停止
AudioScheduledSourceNode,并在消息中包含参数值。
AudioScheduledSourceNode.stop(when) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 whendouble✘ ✔ when参数描述源应在何时(以秒为单位)停止播放。它与AudioContext的currentTime属性处于相同时间坐标系中。如果此值传入 0,或者如果该值小于currentTime,则声音将立即停止播放。 如果when为负数,则必须抛出RangeError异常。返回类型:undefined -
1.8. AnalyserNode 接口
此接口代表一个能够提供实时频率和时域分析信息的节点。音频流将未经处理地从输入传送到输出。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | 此输出可以保持未连接。 |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
[Exposed =Window ]interface AnalyserNode :AudioNode {constructor (BaseAudioContext ,context optional AnalyserOptions = {});options undefined getFloatFrequencyData (Float32Array );array undefined getByteFrequencyData (Uint8Array );array undefined getFloatTimeDomainData (Float32Array );array undefined getByteTimeDomainData (Uint8Array );array attribute unsigned long fftSize ;readonly attribute unsigned long frequencyBinCount ;attribute double minDecibels ;attribute double maxDecibels ;attribute double smoothingTimeConstant ; };
1.8.1. 构造函数
AnalyserNode(context, options)-
当使用
BaseAudioContextc 和一个选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。AnalyserNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 AnalyserNode将 关联 的BaseAudioContext。optionsAnalyserOptions✘ ✔ 此 AnalyserNode的可选初始参数值。
1.8.2. 属性
fftSize, 类型为 unsigned long-
用于频域分析的 FFT 大小(以采样帧为单位)。 这必须是 32 到 32768 范围内的 2 的幂,否则必须抛出
IndexSizeError异常。 默认值为 2048。注意,较大的 FFT 大小计算成本较高。如果
fftSize更改为不同的值,则与频率数据平滑相关的所有状态(对于getByteFrequencyData()和getFloatFrequencyData())都将重置。也就是说,用于 随时间平滑 的 前一个块 \(\hat{X}_{-1}[k]\) 被设置为所有 \(k\) 的 0。注意,增加
fftSize确实意味着必须扩展 当前时域数据 以包含其之前未包含的过去帧。这意味着AnalyserNode有效地必须保留最后 32768 个采样帧,且 当前时域数据 是其中最近的fftSize个采样帧。 frequencyBinCount, 类型为 unsigned long,只读-
FFT 大小的一半。
maxDecibels, 类型为 double-
maxDecibels是 FFT 分析数据转换为无符号字节值时缩放范围内的最大功率值。默认值为 -30。 如果此属性的值设置为小于或等于minDecibels的值,则必须抛出IndexSizeError异常。 minDecibels, 类型为 double-
minDecibels是 FFT 分析数据转换为无符号字节值时缩放范围内的最小功率值。默认值为 -100。 如果此属性的值设置为大于或等于maxDecibels的值,则必须抛出IndexSizeError异常。 smoothingTimeConstant, 类型为 double-
一个从 0 到 1 的值,其中 0 表示不与上一个分析帧进行时间平均。默认值为 0.8。 如果此属性的值设置为小于 0 或大于 1,则必须抛出
IndexSizeError异常。
1.8.3. 方法
getByteFrequencyData(array)-
将 当前频率数据 写入 到 array 中。如果 array 的 字节长度 小于
frequencyBinCount,多出的元素将被丢弃。如果 array 的 字节长度 大于frequencyBinCount,多出的元素将被忽略。计算频率数据时使用最近的fftSize个帧。如果另一次
getByteFrequencyData()或getFloatFrequencyData()调用发生在与上一次调用相同的 渲染时间量 内,则 当前频率数据 不会使用相同数据更新。相反,返回先前计算的数据。存储在无符号字节数组中的值按以下方式计算。设 \(Y[k]\) 为 FFT 窗口与平滑 中描述的 当前频率数据。那么字节值 \(b[k]\) 为:
$$ b[k] = \left\lfloor \frac{255}{\mbox{dB}_{max} - \mbox{dB}_{min}} \left(Y[k] - \mbox{dB}_{min}\right) \right\rfloor $$其中 \(\mbox{dB}_{min}\) 为
minDecibels,\(\mbox{dB}_{max}\) 为。如果 \(b[k]\) 超出 0 到 255 的范围,则将 \(b[k]\) 钳位到该范围内。maxDecibelsAnalyserNode.getByteFrequencyData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 arrayUint8Array✘ ✘ 此参数是存储频域分析数据的目标位置。 返回类型:undefined getByteTimeDomainData(array)-
将 当前时域数据(波形数据)写入 到 array 中。如果 array 的 字节长度 小于
fftSize,多出的元素将被丢弃。如果 array 的 字节长度 大于fftSize,多出的元素将被忽略。计算字节数据时使用最近的fftSize个帧。存储在无符号字节数组中的值按以下方式计算。设 \(x[k]\) 为时域数据。那么字节值 \(b[k]\) 为:
$$ b[k] = \left\lfloor 128(1 + x[k]) \right\rfloor. $$如果 \(b[k]\) 超出 0 到 255 的范围,则将 \(b[k]\) 钳位到该范围内。
AnalyserNode.getByteTimeDomainData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 arrayUint8Array✘ ✘ 此参数是存储时域采样数据的目标位置。 返回类型:undefined getFloatFrequencyData(array)-
将 当前频率数据 写入 到 array 中。如果 array 的元素少于
frequencyBinCount,多出的元素将被丢弃。如果 array 的元素多于frequencyBinCount,多出的元素将被忽略。计算频率数据时使用最近的fftSize个帧。如果另一次
getFloatFrequencyData()或getByteFrequencyData()调用发生在与上一次调用相同的 渲染时间量 内,则 当前频率数据 不会使用相同数据更新。相反,返回先前计算的数据。频率数据以 dB 为单位。
AnalyserNode.getFloatFrequencyData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 arrayFloat32Array✘ ✘ 此参数是存储频域分析数据的目标位置。 返回类型:undefined getFloatTimeDomainData(array)-
写入当前时域数据(波形数据)到 array 中。如果 array 的元素个数少于
fftSize的值,多余的元素将被丢弃。如果 array 的元素个数多于fftSize的值,多余的元素将被忽略。写入的是最近的fftSize帧(在降混之后)。AnalyserNode.getFloatTimeDomainData() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 arrayFloat32Array✘ ✘ 此参数是存储时域采样数据的目标位置。 返回类型:undefined
1.8.4. AnalyserOptions
此项指定构造 AnalyserNode 时使用的选项。所有成员均为可选;如果未指定,则使用正常的默认值来构造节点。
dictionary AnalyserOptions :AudioNodeOptions {unsigned long fftSize = 2048;double maxDecibels = -30;double minDecibels = -100;double smoothingTimeConstant = 0.8; };
1.8.4.1. 字典 AnalyserOptions 成员
fftSize,类型为 unsigned long,默认为2048-
用于频域分析的期望 FFT 初始大小。
maxDecibels,类型为 double,默认为-30-
用于 FFT 分析的期望初始最大功率(dB)。
minDecibels,类型为 double,默认为-100-
用于 FFT 分析的期望初始最小功率(dB)。
smoothingTimeConstant,类型为 double,默认为0.8-
用于 FFT 分析的期望初始平滑常数。
1.8.5. 时域降混
当计算当前时域数据时,输入信号必须降混为单声道,就如同 channelCount 为 1,channelCountMode 为 "max",且 channelInterpretation 为 "speakers" 一样。这与 AnalyserNode 本身的设置无关。最近的 fftSize 帧被用于降混操作。
1.8.6. FFT 加窗与时间平滑
当计算当前频率数据时,应执行以下操作
-
计算当前时域数据。
-
对加窗后的时域输入数据应用傅里叶变换,以获取实数和虚数频率数据。
在下文中,令 \(N\) 为该 AnalyserNode 的 fftSize 属性值。
$$
\begin{align*}
\alpha &= \mbox{0.16} \\ a_0 &= \frac{1-\alpha}{2} \\
a_1 &= \frac{1}{2} \\
a_2 &= \frac{\alpha}{2} \\
w[n] &= a_0 - a_1 \cos\frac{2\pi n}{N} + a_2 \cos\frac{4\pi n}{N}, \mbox{ for } n = 0, \ldots, N - 1
\end{align*}
$$
加窗后的信号 \(\hat{x}[n]\) 为
$$
\hat{x}[n] = x[n] w[n], \mbox{ for } n = 0, \ldots, N - 1
$$
$$
X[k] = \frac{1}{N} \sum_{n = 0}^{N - 1} \hat{x}[n]\, W^{-kn}_{N}
$$
对于 \(k = 0, \dots, N/2-1\),其中 \(W_N = e^{2\pi i/N}\)。
-
令 \(\hat{X}_{-1}[k]\) 为前一个数据块上执行该操作的结果。前一个数据块定义为上一次时间平滑操作所计算出的缓冲区,如果这是第一次进行时间平滑,则定义为包含 \(N\) 个零的数组。
-
令 \(\tau\) 为该
AnalyserNode的smoothingTimeConstant属性值。 -
令 \(X[k]\) 为对当前数据块应用傅里叶变换的结果。
则平滑后的值 \(\hat{X}[k]\) 计算方式为
$$
\hat{X}[k] = \tau\, \hat{X}_{-1}[k] + (1 - \tau)\, \left|X[k]\right|
$$
-
如果 \(\hat{X}[k]\) 为
NaN、正无穷大或负无穷大,则将 \(\hat{X}[k]\) 设为 0。
对于 \(k = 0, \ldots, N - 1\)。
$$
Y[k] = 20\log_{10}\hat{X}[k]
$$
对于 \(k = 0, \ldots, N-1\)。
该数组 \(Y[k]\) 被复制到 getFloatFrequencyData() 的输出数组中。对于 getByteFrequencyData(),\(Y[k]\) 会被裁剪在 minDecibels 和 之间,并进行缩放以适应无符号字节(unsigned byte),使得 maxDecibelsminDecibels 对应值 0,而 对应值 255。maxDecibels
1.9. AudioBufferSourceNode 接口
此接口表示来自内存中 AudioBuffer 音频资产的音频源。它对于播放需要高度调度灵活性和准确性的音频资产非常有用。如果需要对网络或磁盘上的资产进行精确采样播放,实现者应使用 AudioWorkletNode 来实现播放。
start() 方法用于调度声音何时开始播放。start() 方法不能被多次调用。当缓冲区的音频数据完全播放完毕(如果 loop 属性为 false),或者当调用了 stop() 方法且到达了指定时间时,播放将自动停止。请参阅 start() 和 stop() 的描述以了解更多详情。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
输出的通道数等于分配给 buffer 属性的 AudioBuffer 的通道数,如果 buffer 为 null,则为一个通道的静音。
此外,如果缓冲区具有多于一个通道,那么 AudioBufferSourceNode 的输出必须在满足以下任一条件的渲染量子(render quantum)开始时变为单通道静音
AudioBufferSourceNode 的 播放头位置 定义为任何表示以秒为单位的时间偏移量,相对于缓冲区中第一采样帧的时间坐标。此类值应独立于节点的 playbackRate 和 detune 参数来考虑。通常,播放头位置可能是亚采样(subsample)精度的,无需引用确切的采样帧位置。它们可以取 0 到缓冲区持续时间之间的有效值。
playbackRate 和 detune 属性构成一个 复合参数。它们共同用于确定一个 computedPlaybackRate 值。
computedPlaybackRate(t) = playbackRate(t) * pow(2, detune(t) / 1200)
此 复合参数 的 标称范围 为 \((-\infty, \infty)\)。
AudioBufferSourceNode 在创建时带有一个内部布尔槽 [[buffer set]],初始设置为 false。
[Exposed =Window ]interface AudioBufferSourceNode :AudioScheduledSourceNode {constructor (BaseAudioContext ,context optional AudioBufferSourceOptions = {});options attribute AudioBuffer ?buffer ;readonly attribute AudioParam playbackRate ;readonly attribute AudioParam detune ;attribute boolean loop ;attribute double loopStart ;attribute double loopEnd ;undefined start (optional double when = 0,optional double offset ,optional double duration ); };
1.9.1. 构造函数
AudioBufferSourceNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须使用 context 和 options 作为参数初始化 AudioNode this。AudioBufferSourceNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 AudioBufferSourceNode将关联到的BaseAudioContext。optionsAudioBufferSourceOptions✘ ✔ 此 AudioBufferSourceNode的可选初始参数值。
1.9.2. 属性
buffer,类型为 AudioBuffer,可为空(nullable)-
表示要播放的音频资产。
要设置buffer属性,请执行以下步骤-
令 new buffer 为要分配给
buffer的AudioBuffer或null值。 -
如果 new buffer 不为
null且[[buffer set]]为 true,则抛出InvalidStateError并中止这些步骤。 -
如果 new buffer 不为
null,将[[buffer set]]设置为 true。 -
将 new buffer 分配给
buffer属性。
-
detune,类型为 AudioParam,只读-
一个额外的参数(以音分为单位),用于调制渲染音频流的速度。此参数是与
playbackRate组合形成的复合参数,用于形成 computedPlaybackRate。参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" k-rate"具有自动化速率约束 loop,类型为 booleanloopEnd,类型为 double-
如果
loop属性为 true,则为可选的播放头位置,循环应在此处结束。其值不包含循环内容。其默认value为 0,通常可设置为 0 与缓冲区持续时间之间的任意值。如果loopEnd小于或等于 0,或者大于缓冲区持续时间,循环将在缓冲区末尾结束。 loopStart,类型为 double-
如果
loop属性为 true,则为可选的播放头位置,循环应在此处开始。其默认value为 0,通常可设置为 0 与缓冲区持续时间之间的任意值。如果loopStart小于 0,循环将在 0 处开始。如果loopStart大于缓冲区持续时间,循环将在缓冲区末尾开始。 playbackRate,类型为 AudioParam,只读-
渲染音频流的速度。这是一个与
detune结合使用的复合参数,用于形成 computedPlaybackRate。参数 值 注 defaultValue1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" k-rate"具有自动化速率约束
1.9.3. 方法
start(when, offset, duration)-
计划在精确的时间播放声音。
调用此方法时,执行以下步骤:-
如果此
AudioBufferSourceNode的内部槽[[source started]]为true,则必须抛出InvalidStateError异常。 -
检查是否因下述参数约束而必须抛出任何错误。如果在执行此步骤期间抛出任何异常,请中止这些步骤。
-
将此
AudioBufferSourceNode上的内部槽[[source started]]设置为true。 -
排队一个控制消息以启动
AudioBufferSourceNode,并在消息中包含参数值。 -
仅在满足以下所有条件时,向关联的
AudioContext发送控制消息以开始运行其渲染线程-
上下文的
[[control thread state]]为suspended。 -
上下文被允许启动。
-
[[suspended by user]]标志为false。
注意:这可以允许
start()启动一个当前被允许启动但之前被阻止启动的AudioContext。 -
AudioBufferSourceNode.start(when, offset, duration) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 whendouble✘ ✔ when参数描述声音应在什么时间(以秒为单位)开始播放。它与AudioContext的currentTime属性处于相同的时间坐标系中。如果为此值传入 0,或者如果该值小于 currentTime,则声音将立即开始播放。 如果when为负数,则必须抛出RangeError异常。offsetdouble✘ ✔ offset参数提供了一个播放将要开始的播放头位置。如果为此值传入 0,则播放将从缓冲区开头开始。如果offset为负数,则必须抛出RangeError异常。 如果offset大于loopEnd,且playbackRate为正数或零,并且loop为true,则播放将从loopEnd开始。如果offset大于loopStart,且playbackRate为负数,并且loop为true,则播放将从loopStart开始。当到达startTime时,offset会被静默截断为 [0,duration],其中duration是设置为此AudioBufferSourceNode的buffer属性的AudioBuffer的duration属性值。durationdouble✘ ✔ duration参数描述要播放的声音持续时间,表示为要输出的缓冲区内容的总秒数,包括任何完整或部分的循环迭代。duration的单位独立于playbackRate的影响。例如,持续时间为 5 秒且播放速率为 0.5 时,将以半速输出 5 秒的缓冲区内容,产生 10 秒的可听输出。如果duration为负数,则必须抛出RangeError异常。返回类型:undefined -
1.9.4. AudioBufferSourceOptions
此项指定用于构造 AudioBufferSourceNode 的选项。所有成员均为可选;如果未指定,则使用正常的默认值来构造节点。
dictionary AudioBufferSourceOptions {AudioBuffer ?buffer ;float detune = 0;boolean loop =false ;double loopEnd = 0;double loopStart = 0;float playbackRate = 1; };
1.9.4.1. 字典 AudioBufferSourceOptions 成员
buffer,类型为 AudioBuffer,可为空-
要播放的音频资产。这等同于将
buffer分配给AudioBufferSourceNode的buffer属性。 detune,类型为 float,默认为0-
detuneAudioParam 的初始值。 loop,类型为 boolean,默认为false-
loop属性的初始值。 loopEnd,类型为 double,默认为0-
loopEnd属性的初始值。 loopStart,类型为 double,默认为0-
loopStart属性的初始值。 playbackRate,类型为 float,默认为1-
playbackRateAudioParam 的初始值。
1.9.5. 循环
本节是非规范性的。请参阅播放算法以了解规范性要求。
一旦播放了循环区域的任何部分,将 loop 属性设置为 true,将导致由终点 loopStart 和 loopEnd 定义的缓冲区区域无限期循环播放。当 loop 保持为 true 时,循环播放将持续,直到发生以下情况之一
循环主体被视为占据从 loopStart 到但不包括 loopEnd 的区域。循环区域的播放方向遵循节点的播放速率的符号。对于正向播放速率,循环从 loopStart 到 loopEnd 进行;对于负向速率,循环从 loopEnd 到 loopStart 进行。
循环不会影响 start() 的 offset 参数的解释。播放始终从请求的偏移量开始,循环仅在播放期间遇到循环主体时才开始。
有效的循环起点和终点必须位于零和缓冲区持续时间的范围内,如下面的算法中所述。 loopEnd 进一步被限制为必须在 loopStart 处或之后。如果违反了这些限制中的任何一个,循环将被视为包含整个缓冲区内容。
循环端点具有亚采样精度。当端点未落在精确的采样帧偏移量上,或者当播放速率不等于 1 时,循环播放会进行插值以拼接循环的开头和结尾,就像循环音频出现在缓冲区中连续、非循环的区域中一样。
循环相关属性可能会在缓冲区播放期间变化,通常在下一个渲染量子生效。确切结果由下文的规范性播放算法定义。
loopStart 和 loopEnd 属性的默认值均为 0。由于 loopEnd 为零等同于缓冲区的长度,因此默认端点会导致整个缓冲区被包含在循环中。
注意,循环端点的值表示为相对于缓冲区采样率的时间偏移量,这意味着这些值独立于节点的 playbackRate 参数,该参数在播放过程中可能会动态变化。
1.9.6. AudioBuffer 内容的播放
此规范性部分规定了缓冲区内容的播放,考虑到播放受到以下因素共同影响的事实
-
起始偏移量,可以以亚采样精度表示。
-
循环点,可以以亚采样精度表示,并在播放期间动态变化。
-
播放速率和失谐(detuning)参数,它们组合产生一个单一的 computedPlaybackRate,该值可以取正数或负数的有限值。
内部遵循以从 AudioBufferSourceNode 生成输出的算法符合以下原则
-
UA 可能在任何期望的点随意执行缓冲区的重采样,以提高输出的效率或质量。
-
亚采样起始偏移量或循环点可能需要在采样帧之间进行额外的插值。
-
循环缓冲区的播放行为应与包含循环音频内容连续出现的非循环缓冲区行为相同,不包括插值的影响。
该算法的描述如下
let buffer; // AudioBuffer employed by this node let context; // AudioContext employed by this node // The following variables capture attribute and AudioParam values for the node. // They are updated on a k-rate basis, prior to each invocation of process(). let loop; let detune; let loopStart; let loopEnd; let playbackRate; // Variables for the node's playback parameters let start= 0 , offset= 0 , duration= Infinity ; // Set by start() let stop= Infinity ; // Set by stop() // Variables for tracking node's playback state let bufferTime= 0 , started= false , enteredLoop= false ; let bufferTimeElapsed= 0 ; let dt= 1 / context. sampleRate; // Handle invocation of start method call function handleStart( when, pos, dur) { if ( arguments. length>= 1 ) { start= when; } offset= pos; if ( arguments. length>= 3 ) { duration= dur; } } // Handle invocation of stop method call function handleStop( when) { if ( arguments. length>= 1 ) { stop= when; } else { stop= context. currentTime; } } // Interpolate a multi-channel signal value for some sample frame. // Returns an array of signal values. function playbackSignal( position) { /* This function provides the playback signal function for buffer, which is a function that maps from a playhead position to a set of output signal values, one for each output channel. If |position| corresponds to the location of an exact sample frame in the buffer, this function returns that frame. Otherwise, its return value is determined by a UA-supplied algorithm that interpolates sample frames in the neighborhood of |position|. If |position| is greater than or equal to |loopEnd| and there is no subsequent sample frame in buffer, then interpolation should be based on the sequence of subsequent frames beginning at |loopStart|. */ ... } // Generate a single render quantum of audio to be placed // in the channel arrays defined by output. Returns an array // of |numberOfFrames| sample frames to be output. function process( numberOfFrames) { let currentTime= context. currentTime; // context time of next rendered frame const output= []; // accumulates rendered sample frames // Combine the two k-rate parameters affecting playback rate const computedPlaybackRate= playbackRate* Math. pow( 2 , detune/ 1200 ); // Determine loop endpoints as applicable let actualLoopStart, actualLoopEnd; if ( loop&& buffer!= null ) { if ( loopStart>= 0 && loopEnd> 0 && loopStart< loopEnd) { actualLoopStart= loopStart; actualLoopEnd= Math. min( loopEnd, buffer. duration); } else { actualLoopStart= 0 ; actualLoopEnd= buffer. duration; } } else { // If the loop flag is false, remove any record of the loop having been entered enteredLoop= false ; } // Handle null buffer case if ( buffer== null ) { stop= currentTime; // force zero output for all time } // Render each sample frame in the quantum for ( let index= 0 ; index< numberOfFrames; index++ ) { // Check that currentTime and bufferTimeElapsed are // within allowable range for playback if ( currentTime< start|| currentTime>= stop|| bufferTimeElapsed>= duration) { output. push( 0 ); // this sample frame is silent currentTime+= dt; continue ; } if ( ! started) { // Take note that buffer has started playing and get initial // playhead position. if ( loop&& computedPlaybackRate>= 0 && offset>= actualLoopEnd) { offset= actualLoopEnd; } if ( computedPlaybackRate< 0 && loop&& offset< actualLoopStart) { offset= actualLoopStart; } bufferTime= offset; started= true ; } // Handle loop-related calculations if ( loop) { // Determine if looped portion has been entered for the first time if ( ! enteredLoop) { if ( offset< actualLoopEnd&& bufferTime>= actualLoopStart) { // playback began before or within loop, and playhead is // now past loop start enteredLoop= true ; } if ( offset>= actualLoopEnd&& bufferTime< actualLoopEnd) { // playback began after loop, and playhead is now prior // to the loop end enteredLoop= true ; } } // Wrap loop iterations as needed. Note that enteredLoop // may become true inside the preceding conditional. if ( enteredLoop) { while ( bufferTime>= actualLoopEnd) { bufferTime-= actualLoopEnd- actualLoopStart; } while ( bufferTime< actualLoopStart) { bufferTime+= actualLoopEnd- actualLoopStart; } } } if ( bufferTime>= 0 && bufferTime< buffer. duration) { output. push( playbackSignal( bufferTime)); } else { output. push( 0 ); // past end of buffer, so output silent frame } bufferTime+= dt* computedPlaybackRate; bufferTimeElapsed+= dt* computedPlaybackRate; currentTime+= dt; } // End of render quantum loop if ( currentTime>= stop) { // End playback state of this node. No further invocations of process() // will occur. Schedule a change to set the number of output channels to 1. } return output; }
以下非规范性图表展示了算法在各种关键场景下的行为。未考虑缓冲区的动态重采样,但只要循环位置的时间不发生变化,这不会实质性影响最终的播放。在所有图表中,适用以下约定
-
上下文采样率为 1000 Hz
-
AudioBuffer内容显示在 x 原点处具有第一采样帧。 -
输出信号显示在 x 原点处具有位于
start时间的采样帧。 -
通篇描绘了线性插值,尽管 UA 可以采用其他插值技术。
-
图中注明的
duration值是指buffer,而不是start()的参数。
此图展示了缓冲区的基本播放,带有一个简单的循环,该循环在缓冲区中的最后一个采样帧之后结束。
AudioBufferSourceNode 基本播放此图展示了 playbackRate 插值,显示了缓冲区内容的半速播放,其中每隔一个输出采样帧都经过插值。特别值得注意的是循环输出中的最后一个采样帧,它是使用循环起点进行插值的。
AudioBufferSourceNode playbackRate 插值此图展示了采样率插值,显示了采样率为上下文采样率 50% 的缓冲区的播放,导致计算出的播放速率为 0.5,该速率修正了缓冲区和上下文之间采样率的差异。最终的输出与前一个示例相同,但原因不同。
AudioBufferSourceNode 采样率插值。此图展示了亚采样偏移播放,其中缓冲区内的偏移量从正好半个采样帧处开始。因此,每个输出帧都经过了插值。
AudioBufferSourceNode 亚采样偏移播放此图展示了亚采样循环播放,显示循环端点中的分数帧偏移量如何映射到缓冲区中的插值数据点,这些数据点尊重这些偏移量,就像它们是对确切采样帧的引用一样。
AudioBufferSourceNode 亚采样循环播放1.10. AudioDestinationNode 接口
这是一个表示最终音频目的地的 AudioNode,是用户最终将听到的内容。它通常可以被认为是一个连接到扬声器的音频输出设备。所有待听取的已渲染音频都将路由到此节点,这是 AudioContext 路由图中的一个“终端”节点。每个 AudioContext 只有一个 AudioDestinationNode,通过 AudioContext 的 destination 属性提供。
AudioDestinationNode 的输出是通过对其输入进行求和产生的,从而可以将 AudioContext 的输出捕获到例如 MediaStreamAudioDestinationNode 或 MediaRecorder(详见 [mediastream-recording])中。
AudioDestinationNode 可以是 AudioContext 或 OfflineAudioContext 的目的地,通道属性取决于上下文的类型。
对于 AudioContext,默认值为
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "explicit" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
channelCount 可以设置为小于或等于 maxChannelCount 的任何值。如果该值不在有效范围内,则必须抛出 IndexSizeError 异常。 给出一个具体示例,如果音频硬件支持 8 通道输出,那么我们可以将 channelCount 设置为 8,并渲染 8 个通道的输出。
对于 OfflineAudioContext,默认值为
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| numberOfChannels | |
channelCountMode
| "explicit" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
其中 numberOfChannels 是构造 OfflineAudioContext 时指定的通道数。此值不能更改;如果 channelCount 被更改为不同的值,必须抛出 NotSupportedError 异常。
[Exposed =Window ]interface AudioDestinationNode :AudioNode {readonly attribute unsigned long maxChannelCount ; };
1.10.1. 属性
maxChannelCount,类型为 unsigned long,只读-
channelCount属性可以设置为的最大通道数。如果音频硬件是多通道的,则表示音频硬件终点(通常情况)的AudioDestinationNode可能输出超过 2 个通道的音频。maxChannelCount是此硬件能够支持的最大通道数。
1.11. The AudioListener Interface
此接口表示收听音频场景的人的位置和方向。所有 PannerNode 对象都相对于 BaseAudioContext 的 listener 进行空间化。有关空间化的更多详细信息,请参阅 § 6 空间化/声像控制。
positionX、positionY 和 positionZ 参数表示收听者在 3D 笛卡尔坐标空间中的位置。PannerNode 对象使用此位置相对于单个音频源进行空间化。
forwardX、forwardY 和 forwardZ 参数表示 3D 空间中的方向向量。forward 向量和 up 向量都用于确定收听者的方向。用简单的人类语言来说,forward 向量表示人鼻子指向的方向。up 向量表示人头顶指向的方向。这两个向量应是线性独立的。关于如何解释这些值的规范性要求,请参阅 § 6 空间化/声像控制 部分。
[Exposed =Window ]interface AudioListener {readonly attribute AudioParam positionX ;readonly attribute AudioParam positionY ;readonly attribute AudioParam positionZ ;readonly attribute AudioParam forwardX ;readonly attribute AudioParam forwardY ;readonly attribute AudioParam forwardZ ;readonly attribute AudioParam upX ;readonly attribute AudioParam upY ;readonly attribute AudioParam upZ ;undefined setPosition (float ,x float ,y float );z undefined setOrientation (float ,x float ,y float ,z float ,xUp float ,yUp float ); };zUp
1.11.1. 属性
forwardX,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的前向方向的 x 坐标分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" forwardY,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的前向方向的 y 坐标分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" forwardZ,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的前向方向的 z 坐标分量。
参数 值 注 defaultValue-1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" positionX,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置音频收听者的 x 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" positionY,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置音频收听者的 y 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" positionZ,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置音频收听者的 z 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" upX,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的上方方向的 x 坐标分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" upY,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的上方方向的 y 坐标分量。
参数 值 注 defaultValue1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate" upZ,类型为 AudioParam,只读-
在 3D 笛卡尔坐标空间中设置收听者指向的上方方向的 z 坐标分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"
1.11.2. 方法
setOrientation(x, y, z, xUp, yUp, zUp)-
此方法已弃用。它等同于直接使用给定的
x、y、z、xUp、yUp和zUp值分别设置forwardX.value、forwardY.value、forwardZ.value、upX.value、upY.value和upZ.value。因此,如果在调用此方法时,
forwardX、forwardY、forwardZ、upX、upY和upZAudioParam中的任何一个已使用setValueCurveAtTime()设置了自动化曲线,则必须抛出NotSupportedError异常。setOrientation()描述了收听者在 3D 笛卡尔坐标空间中指向的方向。同时提供了前向向量和向上向量。用简单的人类语言来说,前向向量表示人鼻子指向的方向。 向上 向量表示人头顶指向的方向。这两个向量应是线性独立的。关于如何解释这些值的规范性要求,请参阅 § 6 空间化/声像控制。x、y和z参数表示 3D 空间中的前向方向向量,默认值为 (0,0,-1)。xUp、yUp和zUp参数表示 3D 空间中的向上方向向量,默认值为 (0,1,0)。AudioListener.setOrientation() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 xfloat✘ ✘ AudioListener的前向 x 方向yfloat✘ ✘ AudioListener的前向 y 方向zfloat✘ ✘ AudioListener的前向 z 方向xUpfloat✘ ✘ AudioListener的向上 x 方向yUpfloat✘ ✘ AudioListener的向上 y 方向zUpfloat✘ ✘ AudioListener的向上 z 方向返回类型:undefined setPosition(x, y, z)-
此方法已弃用。它等同于直接使用给定的
x、y和z值分别设置positionX.value、positionY.value和positionZ.value。因此,如果在调用此方法时,该
AudioListener的任何positionX、positionY和positionZAudioParams 已使用setValueCurveAtTime()设置了自动化曲线,则必须抛出NotSupportedError异常。setPosition()在 3D 笛卡尔坐标空间中设置收听者的位置。PannerNode对象使用此位置相对于单个音频源进行空间化。默认值为 (0,0,0)。
AudioListener.setPosition() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 xfloat✘ ✘ AudioListener位置的 x 坐标yfloat✘ ✘ AudioListener位置的 y 坐标zfloat✘ ✘ AudioListener位置的 z 坐标
1.11.3. 处理
由于 AudioListener 的参数可以与 AudioNode 连接,并且它们还会影响同一图中 PannerNode 的输出,因此节点排序算法在计算处理顺序时应考虑 AudioListener。出于这个原因,图中的所有 PannerNode 均以 AudioListener 作为输入。
1.12. The AudioProcessingEvent Interface - 已弃用
这是一个被分发给 ScriptProcessorNode 节点的 Event 对象。当 ScriptProcessorNode 被移除时,它也将被移除,因为替代品 AudioWorkletNode 使用了不同的方法。
事件处理程序通过访问 inputBuffer 属性中的音频数据来处理来自输入(如果有)的音频。处理结果产生的音频数据(如果没有输入,则为合成数据)随后被放置到 outputBuffer 中。
[Exposed =Window ]interface AudioProcessingEvent :Event {(constructor DOMString ,type AudioProcessingEventInit );eventInitDict readonly attribute double playbackTime ;readonly attribute AudioBuffer inputBuffer ;readonly attribute AudioBuffer outputBuffer ; };
1.12.1. 属性
inputBuffer,类型为 AudioBuffer,只读-
一个包含输入音频数据的 AudioBuffer。它将具有与 createScriptProcessor() 方法的
numberOfInputChannels参数相等的通道数。此 AudioBuffer 仅在audioprocess事件处理函数的作用域内有效。其值在此作用域之外将毫无意义。 outputBuffer,类型为 AudioBuffer,只读-
一个必须写入输出音频数据的 AudioBuffer。它将具有与 createScriptProcessor() 方法的
numberOfOutputChannels参数相等的通道数。audioprocess事件处理函数作用域内的脚本代码应修改此 AudioBuffer 中表示通道数据的Float32Array数组。在此作用域之外对该 AudioBuffer 进行的任何脚本修改都不会产生任何可听效果。 playbackTime,类型为 double,只读-
音频将在与
AudioContext的currentTime相同的时间坐标系中播放的时间。
1.12.2. AudioProcessingEventInit
dictionary AudioProcessingEventInit :EventInit {required double playbackTime ;required AudioBuffer inputBuffer ;required AudioBuffer outputBuffer ; };
1.12.2.1. 字典 AudioProcessingEventInit 成员
inputBuffer,类型为 AudioBuffer-
要分配给事件的
inputBuffer属性的值。 outputBuffer,类型为 AudioBuffer-
要分配给事件的
outputBuffer属性的值。 playbackTime,类型为 double-
要分配给事件的
playbackTime属性的值。
1.13. The BiquadFilterNode Interface
BiquadFilterNode 是实现非常常见的低阶滤波器的 AudioNode 处理器。
低阶滤波器是基本音调控制(低音、中音、高音)、图形均衡器和更高级滤波器的构建块。可以将多个 BiquadFilterNode 滤波器组合起来形成更复杂的滤波器。滤波器的参数(如 frequency)可以随时间改变,用于滤波器扫描等。每个 BiquadFilterNode 都可以配置为多种常见滤波器类型中的一种,如下面的 IDL 所示。默认滤波器类型为 "lowpass"。
frequency 和 detune 均构成一个复合参数,且两者均为a-rate。它们共同用于确定一个 computedFrequency 值。
computedFrequency(t) = frequency(t) * pow(2, detune(t) / 1200)
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | 是 | 继续在无输入的情况下输出非静音音频。由于这是一个 IIR 滤波器,该滤波器会永远产生非零输入,但在实践中,这可以在某个有限时间后限制,此时输出已足够接近零。实际时间取决于滤波器系数。 |
输出的通道数始终等于输入的通道数。
enum {BiquadFilterType "lowpass" ,"highpass" ,"bandpass" ,"lowshelf" ,"highshelf" ,"peaking" ,"notch" ,"allpass" };
| 枚举值 | 描述 |
|---|---|
"lowpass" | 低通滤波器 (lowpass filter) 允许截止频率以下的频率通过,并衰减截止频率以上的频率。它实现了一个标准的二阶谐振低通滤波器,滚降斜率为 12dB/倍频程。
|
"highpass" | 高通滤波器 (highpass filter) 与低通滤波器相反。它允许截止频率以上的频率通过,而衰减截止频率以下的频率。它实现了一个标准的二阶谐振高通滤波器,滚降斜率为 12dB/倍频程。
|
"bandpass" | 带通滤波器 (bandpass filter) 允许一定范围内的频率通过,并衰减此频率范围之外(以下和以上)的频率。它实现了一个二阶带通滤波器。
|
"lowshelf" | 低架滤波器 (lowshelf filter) 允许所有频率通过,但会对较低频率进行增强(或衰减)。它实现了一个二阶低架滤波器。
|
"highshelf" | 高架滤波器 (highshelf filter) 与低架滤波器相反,允许所有频率通过,但会对较高频率进行增强。它实现了一个二阶高架滤波器。
|
"peaking" | 峰值滤波器 (peaking filter) 允许所有频率通过,但会对一定范围内的频率进行增强(或衰减)。
|
"notch" | 陷波滤波器 (notch filter)(也称为 带阻滤波器)与带通滤波器相反。它允许除一组特定频率之外的所有频率通过。
|
"allpass" | 全通滤波器 (allpass filter) 允许所有频率通过,但会改变各频率之间的相位关系。它实现了一个二阶全通滤波器。
|
BiquadFilterNode 的所有属性均为 a-rate AudioParam。
[Exposed =Window ]interface BiquadFilterNode :AudioNode {(constructor BaseAudioContext ,context optional BiquadFilterOptions = {});options attribute BiquadFilterType type ;readonly attribute AudioParam frequency ;readonly attribute AudioParam detune ;readonly attribute AudioParam Q ;readonly attribute AudioParam gain ;undefined getFrequencyResponse (Float32Array ,frequencyHz Float32Array ,magResponse Float32Array ); };phaseResponse
1.13.1. 构造函数
BiquadFilterNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。BiquadFilterNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 BiquadFilterNode将 关联 到的BaseAudioContext。optionsBiquadFilterOptions✘ ✔ 此 BiquadFilterNode的可选初始参数值。
1.13.2. 属性
Q, 类型为 AudioParam, 只读-
滤波器的 Q 值 (Q factor)。
对于
lowpass和highpass滤波器,Q值被解释为以 dB 为单位。对于这些滤波器,标称范围是 \([-Q_{lim}, Q_{lim}]\),其中 \(Q_{lim}\) 是 \(10^{Q/20}\) 不会溢出的最大值。这大约是 \(770.63678\)。对于
bandpass、notch、allpass和peaking滤波器,该值是一个线性值。该值与滤波器的带宽相关,因此应为正值。标称范围是 \([0, 3.4028235e38]\),上限为 最大正单精度浮点数。此属性不用于
lowshelf和highshelf滤波器。参数 值 注 defaultValue1 minValuemost-negative-single-float 大约 -3.4028235e38,但请参阅上文了解不同滤波器的实际限制。 maxValuemost-positive-single-float 大约 3.4028235e38,但请参阅上文了解不同滤波器的实际限制。 automationRate" a-rate" detune, 类型为 AudioParam, 只读-
频率的失谐值(以音分为单位)。它与
frequency形成一个 复合参数,构成 计算频率 (computedFrequency)。参数 值 注 defaultValue0 minValue\(\approx -153600\) maxValue\(\approx 153600\) 该值大约为 \(1200\ \log_2 \mathrm{FLT\_MAX}\),其中 FLT_MAX 是最大的 float值。automationRate" a-rate" frequency, 类型为 AudioParam, 只读-
BiquadFilterNode工作的频率(以 Hz 为单位)。它与detune形成一个 复合参数,构成 计算频率。参数 值 注 defaultValue350 minValue0 maxValue奈奎斯特频率 automationRate" a-rate" gain, 类型为 AudioParam, 只读-
滤波器的增益。其值以 dB 为单位。增益仅用于
lowshelf、highshelf和peaking滤波器。参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValue\(\approx 1541\) 该值大约为 \(40\ \log_{10} \mathrm{FLT\_MAX}\),其中 FLT_MAX 是最大的 float值。automationRate" a-rate" type, 类型为 BiquadFilterType-
此
BiquadFilterNode的类型。其默认值为 "lowpass"。其他参数的确切含义取决于type属性的值。
1.13.3. 方法
getFrequencyResponse(frequencyHz, magResponse, phaseResponse)-
给定每个滤波器参数的
[[当前值]],同步计算指定频率的频率响应。这三个参数必须是相同长度的Float32Array,否则必须抛出InvalidAccessError。返回的频率响应必须使用当前处理块中采样的
AudioParam计算。BiquadFilterNode.getFrequencyResponse() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 frequencyHzFloat32Array✘ ✘ 此参数指定一个频率数组(以 Hz 为单位),响应值将在这些频率下计算。 magResponseFloat32Array✘ ✘ 此参数指定一个输出数组,用于接收线性幅值响应值。如果 frequencyHz参数中的某个值不在 [0, sampleRate/2] 范围内(其中sampleRate是AudioContext的sampleRate属性值),则magResponse数组中对应索引处的值必须为NaN。phaseResponseFloat32Array✘ ✘ 此参数指定一个输出数组,用于接收弧度制的相位响应值。如果 frequencyHz参数中的某个值不在 [0, sampleRate/2] 范围内(其中sampleRate是AudioContext的sampleRate属性值),则phaseResponse数组中对应索引处的值必须为NaN。返回类型:undefined
1.13.4. BiquadFilterOptions
这指定了构建 BiquadFilterNode 时使用的选项。所有成员均为可选;如果未指定,则使用正常的默认值构建节点。
dictionary BiquadFilterOptions :AudioNodeOptions {BiquadFilterType type = "lowpass";float Q = 1;float detune = 0;float frequency = 350;float gain = 0; };
1.13.4.1. 字典 BiquadFilterOptions 成员
Q, 类型为 float, 默认值为1-
Q的期望初始值。 detune, 类型为 float, 默认值为0-
detune的期望初始值。 frequency, 类型为 float, 默认值为350-
frequency的期望初始值。 gain, 类型为 float, 默认值为0-
gain的期望初始值。 type, 类型为 BiquadFilterType, 默认值为"lowpass"-
滤波器的期望初始类型。
1.13.5. 滤波器特性
通过 BiquadFilterNode 可用的滤波器类型有多种实现方式,每种都有非常不同的特性。本节中的公式描述了 符合规范的实现 必须实现的滤波器,因为它们决定了不同滤波器类型的特性。它们灵感来源于 Audio EQ Cookbook 中的公式。
BiquadFilterNode 处理音频的传递函数为
$$
H(z) = \frac{\frac{b_0}{a_0} + \frac{b_1}{a_0}z^{-1} + \frac{b_2}{a_0}z^{-2}}
{1+\frac{a_1}{a_0}z^{-1}+\frac{a_2}{a_0}z^{-2}}
$$
这等同于以下时域方程
$$
a_0 y(n) + a_1 y(n-1) + a_2 y(n-2) =
b_0 x(n) + b_1 x(n-1) + b_2 x(n-2)
$$
初始滤波器状态为 0。
注意: 虽然固定滤波器是稳定的,但使用 AudioParam 的自动化功能可能会创建不稳定的双二阶 (biquad) 滤波器。开发者有责任管理这一点。
注意: 用户代理 (UA) 可能会产生警告,通知用户滤波器状态中出现了 NaN 值。这通常表明滤波器不稳定。
上述传递函数中的系数对于每种节点类型都是不同的。基于 BiquadFilterNode 的 AudioParam 的 计算值,计算它们需要以下中间变量。
-
令 \(F_s\) 为此
AudioContext的sampleRate属性值。 -
令 \(f_0\) 为 计算频率 的值。
-
令 \(G\) 为
gainAudioParam的值。 -
令 \(Q\) 为
QAudioParam的值。 -
最后令
$$ \begin{align*} A &= 10^{\frac{G}{40}} \\ \omega_0 &= 2\pi\frac{f_0}{F_s} \\ \alpha_Q &= \frac{\sin\omega_0}{2Q} \\ \alpha_{Q_{dB}} &= \frac{\sin\omega_0}{2 \cdot 10^{Q/20}} \\ S &= 1 \\ \alpha_S &= \frac{\sin\omega_0}{2}\sqrt{\left(A+\frac{1}{A}\right)\left(\frac{1}{S}-1\right)+2} \end{align*} $$
每种滤波器类型的六个系数 (\(b_0, b_1, b_2, a_0, a_1, a_2\)) 为
- "
lowpass" -
$$ \begin{align*} b_0 &= \frac{1 - \cos\omega_0}{2} \\ b_1 &= 1 - \cos\omega_0 \\ b_2 &= \frac{1 - \cos\omega_0}{2} \\ a_0 &= 1 + \alpha_{Q_{dB}} \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \alpha_{Q_{dB}} \end{align*} $$ - "
highpass" -
$$ \begin{align*} b_0 &= \frac{1 + \cos\omega_0}{2} \\ b_1 &= -(1 + \cos\omega_0) \\ b_2 &= \frac{1 + \cos\omega_0}{2} \\ a_0 &= 1 + \alpha_{Q_{dB}} \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \alpha_{Q_{dB}} \end{align*} $$ - "
bandpass" -
$$ \begin{align*} b_0 &= \alpha_Q \\ b_1 &= 0 \\ b_2 &= -\alpha_Q \\ a_0 &= 1 + \alpha_Q \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \alpha_Q \end{align*} $$ - "
notch" -
$$ \begin{align*} b_0 &= 1 \\ b_1 &= -2\cos\omega_0 \\ b_2 &= 1 \\ a_0 &= 1 + \alpha_Q \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \alpha_Q \end{align*} $$ - "
allpass" -
$$ \begin{align*} b_0 &= 1 - \alpha_Q \\ b_1 &= -2\cos\omega_0 \\ b_2 &= 1 + \alpha_Q \\ a_0 &= 1 + \alpha_Q \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \alpha_Q \end{align*} $$ - "
peaking" -
$$ \begin{align*} b_0 &= 1 + \alpha_Q\, A \\ b_1 &= -2\cos\omega_0 \\ b_2 &= 1 - \alpha_Q\,A \\ a_0 &= 1 + \frac{\alpha_Q}{A} \\ a_1 &= -2 \cos\omega_0 \\ a_2 &= 1 - \frac{\alpha_Q}{A} \end{align*} $$ - "
lowshelf" -
$$ \begin{align*} b_0 &= A \left[ (A+1) - (A-1) \cos\omega_0 + 2 \alpha_S \sqrt{A})\right] \\ b_1 &= 2 A \left[ (A-1) - (A+1) \cos\omega_0 )\right] \\ b_2 &= A \left[ (A+1) - (A-1) \cos\omega_0 - 2 \alpha_S \sqrt{A}) \right] \\ a_0 &= (A+1) + (A-1) \cos\omega_0 + 2 \alpha_S \sqrt{A} \\ a_1 &= -2 \left[ (A-1) + (A+1) \cos\omega_0\right] \\ a_2 &= (A+1) + (A-1) \cos\omega_0 - 2 \alpha_S \sqrt{A}) \end{align*} $$ - "
highshelf" -
$$ \begin{align*} b_0 &= A\left[ (A+1) + (A-1)\cos\omega_0 + 2\alpha_S\sqrt{A} )\right] \\ b_1 &= -2A\left[ (A-1) + (A+1)\cos\omega_0 )\right] \\ b_2 &= A\left[ (A+1) + (A-1)\cos\omega_0 - 2\alpha_S\sqrt{A} )\right] \\ a_0 &= (A+1) - (A-1)\cos\omega_0 + 2\alpha_S\sqrt{A} \\ a_1 &= 2\left[ (A-1) - (A+1)\cos\omega_0\right] \\ a_2 &= (A+1) - (A-1)\cos\omega_0 - 2\alpha_S\sqrt{A} \end{align*} $$
1.14. ChannelMergerNode 接口
ChannelMergerNode 用于更高级的应用程序,通常与 ChannelSplitterNode 结合使用。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 参见注释 | 默认值为 6,但由 ChannelMergerOptions、numberOfInputs 或 createChannelMerger 指定的值决定。 |
numberOfOutputs
| 1 | |
channelCount
| 1 | 具有 channelCount 约束 |
channelCountMode
| "explicit" | 具有 channelCountMode 约束 |
channelInterpretation
| "speakers" | |
| tail-time | No |
此接口表示一个用于将来自多个音频流的通道合并为单个音频流的 AudioNode。它具有可变数量的输入(默认为 6),但并非所有输入都需要连接。它有一个单一的输出,当任何输入处于 活动处理 状态时,其音频流具有与输入数量相等的通道数。如果没有任何输入处于 活动处理 状态,则输出为单个静音通道。
要将多个输入合并为一个流,每个输入都会根据指定的混合规则向下混合为单个通道(单声道)。未连接的输入在输出中仍计为 一个静音通道。更改输入流 不会 影响输出通道的顺序。
ChannelMergerNode 有两个连接的立体声输入,第一个和第二个输入将在合并前分别向下混合为单声道。输出将是一个 6 通道流,其前两个通道由前两个(向下混合的)输入填充,其余通道将保持静音。此外,ChannelMergerNode 可用于为多通道扬声器阵列(例如 5.1 环绕声设置)按特定顺序排列多个音频流。合并器不解释通道标识(例如左、右等),而只是按它们输入的顺序合并通道。
[Exposed =Window ]interface ChannelMergerNode :AudioNode {constructor (BaseAudioContext ,context optional ChannelMergerOptions = {}); };options
1.14.1. 构造函数
ChannelMergerNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。ChannelMergerNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 ChannelMergerNode将 关联 到的BaseAudioContext。optionsChannelMergerOptions✘ ✔ 此 ChannelMergerNode的可选初始参数值。
1.14.2. ChannelMergerOptions
dictionary ChannelMergerOptions :AudioNodeOptions {unsigned long numberOfInputs = 6; };
1.14.2.1. 字典 ChannelMergerOptions 成员
numberOfInputs, 类型为 unsigned long, 默认值为6-
ChannelMergerNode的输入数量。有关此值的约束,请参阅createChannelMerger()。
1.15. ChannelSplitterNode 接口
ChannelSplitterNode 用于更高级的应用程序,通常与 ChannelMergerNode 结合使用。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 参见注释 | 此值默认为 6,但通过 ChannelSplitterOptions.numberOfOutputs 或 createChannelSplitter 指定的值,或 numberOfOutputs 成员在 constructor 的 ChannelSplitterOptions 字典中确定。 |
channelCount
| numberOfOutputs
| 具有 channelCount 约束 |
channelCountMode
| "explicit" | 具有 channelCountMode 约束 |
channelInterpretation
| "discrete" | 具有 channelInterpretation 约束 |
| tail-time | No |
此接口表示一个用于访问路由图中音频流的各个通道的 AudioNode。它有一个单一的输入和若干“活动”输出,输出数量等于输入音频流中的通道数。例如,如果将立体声输入连接到 ChannelSplitterNode,则活动输出的数量将为两个(一个来自左声道,一个来自右声道)。总输出数量始终为 N(由 AudioContext 方法 createChannelSplitter() 的 numberOfOutputs 参数决定),如果未提供该值,则默认数量为 6。任何非“活动”的输出都将输出静音,且通常不会连接到任何内容。
ChannelSplitterNode 的一个应用是进行“矩阵混合”,其中需要对每个通道进行单独的增益控制。
[Exposed =Window ]interface ChannelSplitterNode :AudioNode {constructor (BaseAudioContext ,context optional ChannelSplitterOptions = {}); };options
1.15.1. 构造函数
ChannelSplitterNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。ChannelSplitterNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 ChannelSplitterNode将 关联 到的BaseAudioContext。optionsChannelSplitterOptions✘ ✔ 此 ChannelSplitterNode的可选初始参数值。
1.15.2. ChannelSplitterOptions
dictionary ChannelSplitterOptions :AudioNodeOptions {unsigned long numberOfOutputs = 6; };
1.15.2.1. 字典 ChannelSplitterOptions 成员
numberOfOutputs, 类型为 unsigned long, 默认值为6-
ChannelSplitterNode的输出数量。有关此值的约束,请参阅createChannelSplitter()。
1.16. ConstantSourceNode 接口
此接口表示一个恒定音频源,其输出通常是一个恒定值。它通常作为一种通用的恒定源节点,并且可以通过自动控制其 offset 或将其他节点连接到它,像可构建的 AudioParam 一样使用。
此节点的单个输出由一个通道(单声道)组成。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
[Exposed =Window ]interface ConstantSourceNode :AudioScheduledSourceNode {constructor (BaseAudioContext ,context optional ConstantSourceOptions = {});options readonly attribute AudioParam offset ; };
1.16.1. 构造函数
ConstantSourceNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。ConstantSourceNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 ConstantSourceNode将 关联 到的BaseAudioContext。optionsConstantSourceOptions✘ ✔ 此 ConstantSourceNode的可选初始参数值。
1.16.2. 属性
offset, 类型为 AudioParam, 只读-
源的恒定值。
参数 值 注 defaultValue1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"
1.16.3. ConstantSourceOptions
这指定了用于构建 ConstantSourceNode 的选项。所有成员均为可选;如果未指定,则使用正常的默认值构建节点。
dictionary ConstantSourceOptions {float offset = 1; };
1.16.3.1. 字典 ConstantSourceOptions 成员
offset, 类型为 float, 默认值为1-
此节点的 offset AudioParam 的初始值。
1.17. ConvolverNode 接口
此接口表示一个应用给定脉冲响应进行线性卷积效果的处理节点。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | 具有 channelCount 约束 |
channelCountMode
| "clamped-max" | 具有 channelCountMode 约束 |
channelInterpretation
| "speakers" | |
| tail-time | 是 | 在输入为零时,继续输出非静音音频,时长为 buffer 的长度。 |
此节点的输入是单声道(1 通道)或立体声(2 通道),不能增加。来自具有更多通道的节点的连接将被 适当向下混合。
该节点有 channelCount 约束 和 channelCountMode 约束。这些约束确保该节点的输入是单声道或立体声。
[Exposed =Window ]interface ConvolverNode :AudioNode {constructor (BaseAudioContext ,context optional ConvolverOptions = {});options attribute AudioBuffer ?buffer ;attribute boolean normalize ; };
1.17.1. 构造函数
ConvolverNode(context, options)-
当使用
BaseAudioContextcontext 和选项对象 options 调用构造函数时,执行这些步骤。-
将属性
normalize设置为disableNormalization值的倒数。 -
如果
buffer存在,将buffer属性设置为其值。注意: 这意味着缓冲区将根据
normalize属性的值进行归一化。 -
令 o 为新的
AudioNodeOptions字典。 -
如果 options 中 存在
channelCount,则将 o 上的channelCount设置为相同值。 -
如果 options 中 存在
channelCountMode,则将 o 上的channelCountMode设置为相同值。 -
如果 options 中 存在
channelInterpretation,则将 o 上的channelInterpretation设置为相同值。 -
初始化 AudioNode this,并以 c 和 o 作为参数。
ConvolverNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 ConvolverNode将 关联 到的BaseAudioContext。optionsConvolverOptions✘ ✔ 此 ConvolverNode的可选初始参数值。 -
1.17.2. 属性
buffer, 类型为 AudioBuffer, 可为空-
设置此属性时,
buffer和normalize属性的状态将用于配置ConvolverNode,使该脉冲响应具有给定的归一化。此属性的初始值为 null。设置buffer 属性时,请 同步执行以下步骤。-
如果缓冲区的
通道数不是 1、2 或 4,或者缓冲区的采样率与其 关联 的BaseAudioContext的采样率不同,则必须抛出NotSupportedError。 -
获取
AudioBuffer的内容。
注意: 如果
buffer设置为新缓冲区,音频可能会出现故障。如果这是不可取的,建议创建一个新的ConvolverNode来替换旧的,可能需要两者之间进行交叉淡入淡出。注意:
ConvolverNode仅在存在单个输入通道和单通道buffer的特定情况下产生单声道输出。在所有其他情况下,输出均为立体声。特别是,当buffer有四个通道且有两个输入通道时,ConvolverNode执行矩阵“真实”立体声卷积。有关规范信息,请参阅 通道配置图。 -
normalize, 类型为 boolean-
控制设置
buffer属性时,是否通过等功率归一化对缓冲区中的脉冲响应进行缩放。其默认值为true,以便在加载不同的脉冲响应时从卷积器获得更均匀的输出电平。如果normalize设置为false,则卷积将渲染而不对脉冲响应进行任何预处理/缩放。对此值的更改在下次设置buffer属性之前不会生效。如果设置
buffer属性时normalize属性为 false,则ConvolverNode将使用buffer中包含的确切脉冲响应执行线性卷积。否则,如果设置
buffer属性时normalize属性为 true,则ConvolverNode将首先对buffer中包含的音频数据执行缩放的 RMS 功率分析,以根据此算法计算 normalizationScale。function calculateNormalizationScale( buffer) { const GainCalibration= 0.00125 ; const GainCalibrationSampleRate= 44100 ; const MinPower= 0.000125 ; // Normalize by RMS power. const numberOfChannels= buffer. numberOfChannels; const length= buffer. length; let power= 0 ; for ( let i= 0 ; i< numberOfChannels; i++ ) { let channelPower= 0 ; const channelData= buffer. getChannelData( i); for ( let j= 0 ; j< length; j++ ) { const sample= channelData[ j]; channelPower+= sample* sample; } power+= channelPower; } power= Math. sqrt( power/ ( numberOfChannels* length)); // Protect against accidental overload. if ( ! isFinite( power) || isNaN( power) || power< MinPower) power= MinPower; let scale= 1 / power; // Calibrate to make perceived volume same as unprocessed. scale*= GainCalibration; // Scale depends on sample-rate. if ( buffer. sampleRate) scale*= GainCalibrationSampleRate/ buffer. sampleRate; // True-stereo compensation. if ( numberOfChannels== 4 ) scale*= 0.5 ; return scale; } 在处理过程中,ConvolverNode 将获取此计算出的 normalizationScale 值,并将其与输入与脉冲响应(由
buffer表示)处理后产生的线性卷积结果相乘,从而产生最终输出。或者可以使用任何数学上等效的操作,例如通过 normalizationScale 预乘输入,或通过 normalizationScale 预乘脉冲响应的某个版本。
1.17.3. ConvolverOptions
这指定了用于构建 ConvolverNode 的选项。所有成员均为可选;如果未指定,则节点使用正常的默认值构建。
dictionary ConvolverOptions :AudioNodeOptions {AudioBuffer ?buffer ;boolean disableNormalization =false ; };
1.17.3.1. 字典 ConvolverOptions 成员
buffer, 类型为 AudioBuffer, 可为空-
ConvolverNode的期望缓冲区。此缓冲区将根据disableNormalization的值进行归一化。 disableNormalization, 类型为 boolean, 默认值为false-
ConvolverNode的normalize属性期望初始值的相反值。
1.17.4. 输入、脉冲响应和输出的通道配置
实现必须支持 ConvolverNode 中允许的脉冲响应通道配置,以实现 1 或 2 个输入通道的各种混响效果。
如下图所示,单通道卷积在单声道音频输入上运行,使用单声道脉冲响应并生成单声道输出。图中的其余图像说明了支持的单声道和立体声播放情况,其中输入通道数为 1 或 2,buffer 中的通道数为 1、2 或 4。希望进行更复杂和任意矩阵化的开发者可以使用 ChannelSplitterNode、多个单通道 ConvolverNode 和一个 ChannelMergerNode。
如果此节点未处于 活动处理 状态,则输出为单个静音通道。
注意: 下面的图示显示了 活动处理 时的输出。
ConvolverNode 时支持的输入和输出通道数可能性的图形表示。1.18. DelayNode 接口
延迟线是音频应用程序中的基本构建块。此接口是一个具有单个输入和单个输出的 AudioNode。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | 是 | 在输入为零时,继续输出非静音音频,时长可达节点的 maxDelayTime。 |
输出的通道数始终等于输入的通道数。
它将输入的音频信号延迟一定量。具体来说,在每个时间 t,输入信号为 input(t),延迟时间为 delayTime(t),输出信号为 output(t),输出将为 output(t) = input(t - delayTime(t))。默认的 delayTime 为 0 秒(无延迟)。
当 DelayNode 的输入通道数发生变化时(从而也改变了输出通道数),可能会有延迟的音频采样尚未被节点输出,并且是其内部状态的一部分。如果这些采样是在之前以不同的通道数接收的,则在与新接收的输入合并之前,必须对它们进行上混或下混,以便所有内部延迟线混合都使用单一主流的通道布局进行。
注意: 根据定义,DelayNode 会引入等于延迟量的音频处理延迟。
[Exposed =Window ]interface DelayNode :AudioNode {constructor (BaseAudioContext ,context optional DelayOptions = {});options readonly attribute AudioParam delayTime ; };
1.18.1. 构造函数
DelayNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。DelayNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 DelayNode将 关联 到的BaseAudioContext。optionsDelayOptions✘ ✔ 此 DelayNode的可选初始参数值。
1.18.2. 属性
delayTime, 类型为 AudioParam, 只读-
表示要应用的延迟量(以秒为单位)的
AudioParam对象。其默认value为 0(无延迟)。最小值为 0,最大值由maxDelayTime参数在AudioContext方法createDelay()中确定,或由maxDelayTime成员在DelayOptions字典中为constructor确定。如果
DelayNode是 循环 的一部分,则delayTime属性的值被限制为至少一个 渲染量子。参数 值 注 defaultValue0 minValue0 maxValuemaxDelayTimeautomationRate" a-rate"
1.18.3. DelayOptions
这指定了用于构建 DelayNode 的选项。所有成员均为可选;如果未给出,则节点使用正常的默认值构建。
dictionary DelayOptions :AudioNodeOptions {double maxDelayTime = 1;double delayTime = 0; };
1.18.3.1. 字典 DelayOptions 成员
delayTime, 类型为 double, 默认值为0-
节点的初始延迟时间。
maxDelayTime, 类型为 double, 默认值为1-
节点的最大延迟时间。有关约束,请参阅
createDelay(maxDelayTime)。
1.18.4. 处理
DelayNode 拥有一个内部缓冲区,用于保存 delayTime 秒的音频。
DelayNode 的处理分为两部分:写入延迟线和从延迟线读取。这是通过两个内部 AudioNode 完成的(作者无法访问这些节点,它们仅用于简化对节点内部工作的描述)。两者都是从 DelayNode 创建的。
为 DelayNode 创建 DelayWriter 意味着创建一个对象,该对象具有与 AudioNode 相同的接口,并将输入音频写入 DelayNode 的内部缓冲区。它与创建它的 DelayNode 具有相同的输入连接。
为 DelayNode 创建 DelayReader 意味着创建一个对象,该对象具有与 AudioNode 相同的接口,并且可以从 DelayNode 的内部缓冲区读取音频数据。它连接到与创建它的 DelayNode 相同的 AudioNode。 DelayReader 是一个 源节点。
处理输入缓冲区时,DelayWriter 必须将音频写入 DelayNode 的内部缓冲区。
产生输出缓冲区时,DelayReader 必须完全产生 delayTime 秒前写入相应 DelayWriter 的音频。
注意: 这意味着通道数的变化会在延迟时间过去后反映出来。
1.19. DynamicsCompressorNode 接口
DynamicsCompressorNode 是一个实现动态压缩效果的 AudioNode 处理器。
动态压缩在音乐制作和游戏音频中非常常用。它降低了信号最响亮部分的音量,并提高了最柔和部分的音量。总体而言,可以实现更响亮、更丰富、更饱满的声音。这在同时播放大量单个声音的游戏和音乐应用程序中尤为重要,可以控制整体信号电平并有助于避免音频输出到扬声器时出现削波(失真)。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | 具有 channelCount 约束 |
channelCountMode
| "clamped-max" | 具有 channelCountMode 约束 |
channelInterpretation
| "speakers" | |
| tail-time | 是 | 此节点具有 尾部时间 (tail-time),使得该节点由于预读延迟,在输入为零时继续输出非静音音频。 |
[Exposed =Window ]interface DynamicsCompressorNode :AudioNode {constructor (BaseAudioContext ,context optional DynamicsCompressorOptions = {});options readonly attribute AudioParam threshold ;readonly attribute AudioParam knee ;readonly attribute AudioParam ratio ;readonly attribute float reduction ;readonly attribute AudioParam attack ;readonly attribute AudioParam release ; };
1.19.1. 构造函数
DynamicsCompressorNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须 初始化 AudioNode this,并以 context 和 options 作为参数。令
[[内部衰减]]为 this 上的一个私有插槽,用于保存以分贝为单位的浮点数。将[[内部衰减]]设置为 0.0。DynamicsCompressorNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 这个新的 DynamicsCompressorNode将 关联 到的BaseAudioContext。optionsDynamicsCompressorOptions✘ ✔ 此 DynamicsCompressorNode的可选初始参数值。
1.19.2. 属性
attack, 类型为 AudioParam, 只读-
将增益降低 10dB 所需的时间量(以秒为单位)。
参数 值 注 defaultValue.003 minValue0 maxValue1 automationRate" k-rate"具有 自动速率约束 knee, 类型为 AudioParam, 只读-
表示阈值以上、曲线平滑过渡到“比率”部分的范围的分贝值。
参数 值 注 defaultValue30 minValue0 maxValue40 automationRate" k-rate"具有 自动速率约束 ratio, 类型为 AudioParam, 只读-
输入中的 dB 变化量对应于输出中 1 dB 的变化。
参数 值 注 defaultValue12 minValue1 maxValue20 automationRate" k-rate"具有 自动速率约束 reduction, 类型为 float, 只读-
一个用于计量目的的只读分贝值,表示压缩器当前应用于信号的增益衰减量。如果没有输入信号,该值为 0(无增益衰减)。读取此属性时,返回私有插槽
[[内部衰减]]的值。 release, 类型为 AudioParam, 只读-
将增益增加 10dB 所需的时间量(以秒为单位)。
参数 值 注 defaultValue.25 minValue0 maxValue1 automationRate" k-rate"具有 自动速率约束 threshold, 类型为 AudioParam, 只读-
超过该值时压缩将开始生效的分贝值。
参数 值 注 defaultValue-24 minValue-100 maxValue0 automationRate" k-rate"具有 自动速率约束
1.19.3. DynamicsCompressorOptions
这指定了用于构建 DynamicsCompressorNode 的选项。所有成员均为可选;如果未指定,则节点使用正常的默认值构建。
dictionary DynamicsCompressorOptions :AudioNodeOptions {float attack = 0.003;float knee = 30;float ratio = 12;float release = 0.25;float threshold = -24; };
1.19.3.1. 字典 DynamicsCompressorOptions 成员
attack, 类型为 float, 默认值为0.003-
attackAudioParam 的初始值。 knee, 类型为 float, 默认值为30-
kneeAudioParam 的初始值。 ratio, 类型为 float, 默认值为12-
ratioAudioParam 的初始值。 release, 类型为 float,默认值为0.25-
releaseAudioParam 的初始值。 threshold, 类型为 float,默认值为-24-
thresholdAudioParam 的初始值。
1.19.4. 处理
动态压缩可以通过多种方式实现。DynamicsCompressorNode 实现了一个具有以下特性的动态处理器:
-
固定前瞻(fixed look-ahead)(这意味着
DynamicsCompressorNode会为信号链增加固定的延迟)。 -
可配置的启动速度(attack speed)、释放速度(release speed)、阈值(threshold)、拐点硬度(knee hardness)和压缩比(ratio)。
-
不支持侧链(Side-chaining)。
-
增益衰减通过
DynamicsCompressorNode上的reduction属性报告。 -
压缩曲线包含三个部分:
-
第一部分是恒等式:\(f(x) = x\)。
-
第二部分是软拐点(soft-knee)部分,必须是单调递增函数。
-
第三部分是线性函数:\(f(x) = \frac{1}{ratio} \cdot x \)。
该曲线必须是连续且分段可导的,并根据输入电平对应一个目标输出电平。
-
在图形上,这样的曲线看起来大致如下:
在内部,DynamicsCompressorNode 通过结合其他 AudioNode 以及一种特殊算法来描述,以计算增益衰减值。
内部使用以下 AudioNode 图,其中 input 和 output 分别是输入和输出 AudioNode,context 是此 DynamicsCompressorNode 的 BaseAudioContext,以及一个名为 EnvelopeFollower 的新类,它实例化一个表现得像 AudioNode 的特殊对象,描述如下:
const delay = new DelayNode(context, {delayTime: 0.006});
const gain = new GainNode(context);
const compression = new EnvelopeFollower();
input.connect(delay).connect(gain).connect(output);
input.connect(compression).connect(gain.gain);
DynamicsCompressorNode 处理算法一部分的内部 AudioNode 图。注:这实现了预延迟和衰减增益的应用。
以下算法描述了 EnvelopeFollower 对象执行的处理,该处理应用于输入信号以产生增益衰减值。EnvelopeFollower 有两个插槽用于存放浮点值。这些值在算法调用期间保持不变。
-
令
[[detector average]]为一个浮点数,初始化为 0.0。 -
令
[[compressor gain]]为一个浮点数,初始化为 1.0。
-
令 attack 和 release 分别为在处理时采样(这些是 k-rate 参数)的
attack和release的值,并乘以该DynamicsCompressorNode所 关联 的BaseAudioContext的采样率。 -
令 detector average 为插槽
[[detector average]]的值。 -
令 compressor gain 为插槽
[[compressor gain]]的值。 -
对于要处理的渲染量子的每个样本 input,执行以下步骤:
-
如果 input 的绝对值小于 0.0001,令 attenuation 为 1.0。否则,令 shaped input 为将 压缩曲线 应用于 input 的绝对值所得的值。令 attenuation 为 shaped input 除以 input 的绝对值。
-
令 releasing 为
true(如果 attenuation 大于 compressor gain),否则为false。 -
令 detector rate 为将 检测器曲线 应用于 attenuation 的结果。
-
从 attenuation 中减去 detector average,并将结果乘以 detector rate。将此新结果加到 detector average 上。
-
将 detector average 钳位(Clamp)至最大值 1.0。
-
令 envelope rate 为基于 attack 和 release 值 计算包络速率 的结果。
-
如果 releasing 为
true,将 compressor gain 设置为 compressor gain 和 envelope rate 的乘积,并钳位至最大值 1.0。 -
否则,如果 releasing 为
false,令 gain increment 为 detector average 减去 compressor gain。将 gain increment 乘以 envelope rate,并将结果加到 compressor gain 上。 -
计算 reduction gain 为 compressor gain 乘以 计算补偿增益 的返回值。
-
计算 metering gain 为 reduction gain 转换为分贝 的结果。
-
-
将
[[compressor gain]]设置为 compressor gain。 -
将
[[detector average]]设置为 detector average。 -
原子地将内部插槽
[[internal reduction]]设置为 metering gain 的值。注:此步骤使测量增益在每个块结束时更新一次。
补偿增益(makeup gain)是一个固定的增益级,仅取决于压缩器的压缩比、拐点和阈值参数,而不取决于输入信号。其目的是增加压缩器的输出电平,使其与输入电平相当。
-
令 full range gain 为通过将 压缩曲线 应用于值 1.0 所返回的值。
-
令 full range makeup gain 为 full range gain 的倒数。
-
返回 full range makeup gain 的 0.6 次幂的结果。
-
包络速率必须根据 compressor gain 与 detector average 之比进行计算。
注:当进行攻击(attacking)时,此数字小于或等于 1;当进行释放(releasing)时,此数字严格大于 1。
-
攻击曲线必须是区间 \([0, 1]\) 上的连续单调递增函数。此曲线的形状可以由
attack控制。 -
释放曲线必须是始终大于 1 的连续单调递减函数。此曲线的形状可以由
release控制。
此操作返回通过将该函数应用于 compressor gain 与 detector average 之比所计算出的值。
将 检测器曲线 应用于攻击或释放时的变化率,允许实现 自适应释放(adaptive release)。该函数必须遵守以下约束:
-
函数的输出必须在 \([0,1]\) 范围内。
-
函数必须是单调递增且连续的。
注:例如,允许拥有一个执行 自适应释放 的压缩器,即压缩越强,释放越快;或者拥有形状不同的攻击和释放曲线。
-
令 threshold 和 knee 分别为
threshold和knee的值,转换为线性单位 并在此块处理时采样(作为 k-rate 参数)。 -
令 knee end threshold 为此总和 转换为线性单位 的值。
-
该函数在达到线性 threshold 值之前是恒等式(即 \(f(x) = x\))。
-
从 threshold 到 knee end threshold,用户代理可以选择曲线形状。整个函数必须是单调递增且连续的。
注:如果 knee 为 0,则
DynamicsCompressorNode被称为硬拐点(hard-knee)压缩器。 -
该函数在 threshold 和软拐点之后基于 ratio 呈线性(即 \(f(x) = \frac{1}{ratio} \cdot x \))。
-
如果 \(v\) 等于 0,返回 -1000。
-
否则,返回 \( 20 \, \log_{10}{v} \)。
1.20. GainNode 接口
改变音频信号的增益是音频应用程序中的基本操作。此接口是一个具有单个输入和单个输出的 AudioNode。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
GainNode 输入数据的每个通道的每个样本必须乘以 gain AudioParam 的 计算值(computedValue)。
[Exposed =Window ]interface GainNode :AudioNode {constructor (BaseAudioContext ,context optional GainOptions = {});options readonly attribute AudioParam gain ; };
1.20.1. 构造函数
GainNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须使用 context 和 options 作为参数 初始化 AudioNode this。GainNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 GainNode将与之 关联 的BaseAudioContext。optionsGainOptions✘ ✔ 此 GainNode的可选初始参数值。
1.20.2. 属性
gain, 类型为 AudioParam,只读-
表示要应用的增益量。
参数 值 注 defaultValue1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"
1.20.3. GainOptions
这指定了构建 GainNode 时使用的选项。所有成员都是可选的;如果未指定,则在构建节点时使用常规默认值。
dictionary GainOptions :AudioNodeOptions {float gain = 1.0; };
1.20.3.1. 字典 GainOptions 成员
gain, 类型为 float,默认值为1.0-
gainAudioParam 的初始增益值。
1.21. IIRFilterNode 接口
IIRFilterNode 是实现通用 IIR 滤波器 的 AudioNode 处理器。通常,最好使用 BiquadFilterNode 来实现高阶滤波器,原因如下:
-
通常对数值问题不太敏感。
-
滤波器参数可以自动化。
-
可用于创建所有偶数阶 IIR 滤波器。
然而,无法创建奇数阶滤波器,因此如果需要此类滤波器,或者不需要自动化,则 IIR 滤波器可能是合适的。
一旦创建,IIR 滤波器的系数就无法更改。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | 是 | 继续在无输入的情况下输出非静音音频。由于这是一个 IIR 滤波器,该滤波器会永远产生非零输入,但在实践中,这可以在某个有限时间后限制,此时输出已足够接近零。实际时间取决于滤波器系数。 |
输出的通道数始终等于输入的通道数。
[Exposed =Window ]interface IIRFilterNode :AudioNode {constructor (BaseAudioContext ,context IIRFilterOptions );options undefined getFrequencyResponse (Float32Array ,frequencyHz Float32Array ,magResponse Float32Array ); };phaseResponse
1.21.1. 构造函数
IIRFilterNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须使用 context 和 options 作为参数 初始化 AudioNode this。IIRFilterNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 IIRFilterNode将与之 关联 的BaseAudioContext。optionsIIRFilterOptions✘ ✘ 此 IIRFilterNode的初始参数值。
1.21.2. 方法
getFrequencyResponse(frequencyHz, magResponse, phaseResponse)-
给定当前的滤波器参数设置,同步计算指定频率下的频率响应。这三个参数必须是长度相同的
Float32Array,否则必须抛出InvalidAccessError。IIRFilterNode.getFrequencyResponse() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 frequencyHzFloat32Array✘ ✘ 此参数指定一个频率数组(以 Hz 为单位),响应值将在这些频率下计算。 magResponseFloat32Array✘ ✘ 此参数指定用于接收线性幅值响应值的输出数组。如果 frequencyHz参数中的值不在 [0, sampleRate/2] 范围内(其中sampleRate是AudioContext的sampleRate属性的值),则magResponse数组中相应索引处的值必须为NaN。phaseResponseFloat32Array✘ ✘ 此参数指定用于接收以弧度为单位的相位响应值的输出数组。如果 frequencyHz参数中的值不在 [0; sampleRate/2] 范围内(其中sampleRate是AudioContext的sampleRate属性的值),则phaseResponse数组中相应索引处的值必须为NaN。返回类型:undefined
1.21.3. IIRFilterOptions
IIRFilterOptions 字典用于指定 IIRFilterNode 的滤波器系数。
dictionary IIRFilterOptions :AudioNodeOptions {required sequence <double >feedforward ;required sequence <double >feedback ; };
1.21.3.1. 字典 IIRFilterOptions 成员
feedforward, 类型为 sequence<double>-
IIRFilterNode的前馈(feedforward)系数。此成员是必需的。有关其他约束,请参见createIIRFilter()的feedforward参数。 feedback, 类型为 sequence<double>-
IIRFilterNode的反馈(feedback)系数。此成员是必需的。有关其他约束,请参见createIIRFilter()的feedback参数。
1.21.4. 滤波器定义
令 \(b_m\) 为 feedforward 系数,\(a_n\) 为由 createIIRFilter() 或 constructor 的 IIRFilterOptions 字典指定的 feedback 系数。则通用 IIR 滤波器的传递函数由下式给出:
$$
H(z) = \frac{\sum_{m=0}^{M} b_m z^{-m}}{\sum_{n=0}^{N} a_n z^{-n}}
$$
其中 \(M + 1\) 是 \(b\) 数组的长度,\(N + 1\) 是 \(a\) 数组的长度。系数 \(a_0\) 不能为 0(参见 createIIRFilter() 的 feedback parameter)。至少有一个 \(b_m\) 必须非零(参见 createIIRFilter() 的 feedforward parameter)。
等效地,时域方程为:
$$
\sum_{k=0}^{N} a_k y(n-k) = \sum_{k=0}^{M} b_k x(n-k)
$$
初始滤波器状态为全零状态。
注意: 用户代理 (UA) 可能会产生警告,通知用户滤波器状态中出现了 NaN 值。这通常表明滤波器不稳定。
1.22. MediaElementAudioSourceNode 接口
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
| 尾部时间(tail-time)引用 | No |
输出的通道数对应于 HTMLMediaElement 所引用的媒体的通道数。因此,媒体元素的 src 属性的更改可能会改变此节点输出的通道数。
如果 HTMLMediaElement 的采样率与相关联的 AudioContext 的采样率不同,则来自 HTMLMediaElement 的输出必须重新采样以匹配上下文的 采样率(sample rate)。
MediaElementAudioSourceNode 是在给定 HTMLMediaElement 的情况下,使用 AudioContext 的 createMediaElementSource() 方法或 mediaElement 的 MediaElementAudioSourceOptions 字典(用于 constructor)创建的。
单个输出的通道数等于作为参数传递给 createMediaElementSource() 的 HTMLMediaElement 所引用的音频通道数;如果 HTMLMediaElement 没有音频,则为 1。
HTMLMediaElement 在创建 MediaElementAudioSourceNode 后必须以相同的方式表现,除了 渲染的音频将不再直接听到,而是作为 MediaElementAudioSourceNode 通过路由图连接的结果而被听到。因此,如果没有与 MediaElementAudioSourceNode 一起使用,暂停、定位(seeking)、音量、src 属性更改以及 HTMLMediaElement 的其他方面都必须表现得像通常一样。
const mediaElement= document. getElementById( 'mediaElementID' ); const sourceNode= context. createMediaElementSource( mediaElement); sourceNode. connect( filterNode);
[Exposed =Window ]interface MediaElementAudioSourceNode :AudioNode {constructor (AudioContext ,context MediaElementAudioSourceOptions ); [options SameObject ]readonly attribute HTMLMediaElement mediaElement ; };
1.22.1. 构造函数
MediaElementAudioSourceNode(context, options)-
-
使用 context 和 options 作为参数 初始化 AudioNode this。
MediaElementAudioSourceNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextAudioContext✘ ✘ 此新 MediaElementAudioSourceNode将与之 关联 的AudioContext。optionsMediaElementAudioSourceOptions✘ ✘ 此 MediaElementAudioSourceNode的初始参数值。 -
1.22.2. 属性
mediaElement, 类型为 HTMLMediaElement,只读-
构建此
MediaElementAudioSourceNode时使用的HTMLMediaElement。
1.22.3. MediaElementAudioSourceOptions
这指定了构建 MediaElementAudioSourceNode 时使用的选项。
dictionary MediaElementAudioSourceOptions {required HTMLMediaElement mediaElement ; };
1.22.3.1. 字典 MediaElementAudioSourceOptions 成员
mediaElement, 类型为 HTMLMediaElement-
将被重新路由的媒体元素。此项必须指定。
1.22.4. MediaElementAudioSourceNode 和跨源资源的安全性
HTMLMediaElement 允许播放跨源资源。由于 Web Audio 允许检查资源的内容(例如,使用 MediaElementAudioSourceNode 以及 AudioWorkletNode 或 ScriptProcessorNode 读取样本),如果来自一个 源(origin) 的脚本检查来自另一个 源 的资源内容,则可能会发生信息泄露。
为了防止这种情况,如果 MediaElementAudioSourceNode 使用的 HTMLMediaElement 在执行 获取算法(fetch algorithm) [FETCH] 时将资源标记为 CORS-cross-origin,则它必须输出 静音(silence),而不是 HTMLMediaElement 的正常输出。
1.23. MediaStreamAudioDestinationNode 接口
此接口是一个音频目的地,表示一个具有单个 MediaStreamTrack(其 kind 为 "audio")的 MediaStream。此 MediaStream 在节点创建时创建,并通过 stream 属性访问。此流的使用方式类似于通过 getUserMedia() 获得的 MediaStream,并且例如可以使用 [webrtc] 中描述的 RTCPeerConnection 的 addStream() 方法发送到远程对等方。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 0 | |
channelCount
| 2 | |
channelCountMode
| "explicit" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
输入端的默认通道数为 2(立体声)。
[Exposed =Window ]interface MediaStreamAudioDestinationNode :AudioNode {constructor (AudioContext ,context optional AudioNodeOptions = {});options readonly attribute MediaStream stream ; };
1.23.1. 构造函数
MediaStreamAudioDestinationNode(context, options)-
-
使用 context 和 options 作为参数 初始化 AudioNode this。
MediaStreamAudioDestinationNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextAudioContext✘ ✘ 此新 MediaStreamAudioDestinationNode将与之 关联 的BaseAudioContext。optionsAudioNodeOptions✘ ✔ 此 MediaStreamAudioDestinationNode的可选初始参数值。 -
1.23.2. 属性
stream, 类型为 MediaStream,只读-
一个
MediaStream,包含一个具有与节点本身相同通道数的单个MediaStreamTrack,其kind属性值为"audio"。
1.24. MediaStreamAudioSourceNode 接口
此接口表示来自 MediaStream 的音频源。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
| 尾部时间(tail-time)引用 | No |
输出的通道数对应于 MediaStreamTrack 的通道数。当 MediaStreamTrack 结束时,此 AudioNode 输出一个通道的静音。
如果 MediaStreamTrack 的采样率与相关联的 AudioContext 的采样率不同,则 MediaStreamTrack 的输出将被重新采样以匹配上下文的 采样率(sample rate)。
[Exposed =Window ]interface MediaStreamAudioSourceNode :AudioNode {constructor (AudioContext ,context MediaStreamAudioSourceOptions ); [options SameObject ]readonly attribute MediaStream mediaStream ; };
1.24.1. 构造函数
MediaStreamAudioSourceNode(context, options)-
-
如果
options的mediaStream成员未引用一个至少包含一个kind属性值为"audio"的MediaStreamTrack的MediaStream,则抛出InvalidStateError并中止这些步骤。否则,令此流为 inputStream。 -
令 tracks 为 inputStream 中所有
kind为"audio"的MediaStreamTrack列表。 -
根据 tracks 元素的
id属性,使用 代码单元(code unit) 值序列的排序对它们进行排序。 -
使用 context 和 options 作为参数 初始化 AudioNode this。
-
在此
MediaStreamAudioSourceNode上设置一个内部插槽[[input track]],使其成为 tracks 的第一个元素。这是用作此MediaStreamAudioSourceNode输入音频的轨道。
构造后,对传递给构造函数的
MediaStream的任何更改都不会影响此AudioNode的底层输出。插槽
[[input track]]仅用于保留对MediaStreamTrack的引用。注:这意味着当从传递到此构造函数的
MediaStream中移除由MediaStreamAudioSourceNode构造函数选择的轨道时,MediaStreamAudioSourceNode仍将从同一轨道获取输入。注:由于传统原因,选择输出轨道的行为是任意的。可以使用
MediaStreamTrackAudioSourceNode来明确指定使用哪个轨道作为输入。MediaStreamAudioSourceNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextAudioContext✘ ✘ 此新 MediaStreamAudioSourceNode将与之 关联 的AudioContext。optionsMediaStreamAudioSourceOptions✘ ✘ 此 MediaStreamAudioSourceNode的初始参数值。 -
1.24.2. 属性
mediaStream, 类型为 MediaStream,只读-
构建此
MediaStreamAudioSourceNode时使用的MediaStream。
1.24.3. MediaStreamAudioSourceOptions
这指定了构建 MediaStreamAudioSourceNode 时使用的选项。
dictionary MediaStreamAudioSourceOptions {required MediaStream mediaStream ; };
1.24.3.1. 字典 MediaStreamAudioSourceOptions 成员
mediaStream, 类型为 MediaStream-
将充当源的媒体流。此项必须指定。
1.25. MediaStreamTrackAudioSourceNode 接口
此接口表示来自 MediaStreamTrack 的音频源。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
| 尾部时间(tail-time)引用 | No |
输出的通道数对应于 mediaStreamTrack 的通道数。
如果 MediaStreamTrack 的采样率与相关联的 AudioContext 的采样率不同,则 mediaStreamTrack 的输出将被重新采样以匹配上下文的 采样率(sample rate)。
[Exposed =Window ]interface MediaStreamTrackAudioSourceNode :AudioNode {constructor (AudioContext ,context MediaStreamTrackAudioSourceOptions ); };options
1.25.1. 构造函数
MediaStreamTrackAudioSourceNode(context, options)-
-
如果
mediaStreamTrack的kind属性不是"audio",则抛出InvalidStateError并中止这些步骤。 -
使用 context 和 options 作为参数 初始化 AudioNode this。
MediaStreamTrackAudioSourceNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextAudioContext✘ ✘ 此新 MediaStreamTrackAudioSourceNode将与之 关联 的AudioContext。optionsMediaStreamTrackAudioSourceOptions✘ ✘ 此 MediaStreamTrackAudioSourceNode的初始参数值。 -
1.25.2. MediaStreamTrackAudioSourceOptions
这指定了构建 MediaStreamTrackAudioSourceNode 时使用的选项。此项是必需的。
dictionary MediaStreamTrackAudioSourceOptions {required MediaStreamTrack mediaStreamTrack ; };
1.25.2.1. 字典 MediaStreamTrackAudioSourceOptions 成员
mediaStreamTrack, 类型为 MediaStreamTrack-
将充当源的媒体流轨道。 如果此
MediaStreamTrack的kind属性不是"audio",则必须抛出InvalidStateError。
1.26. OscillatorNode 接口
OscillatorNode 表示生成周期性波形的音频源。它可以设置为几种常用的波形。此外,通过使用 PeriodicWave 对象,它可以被设置为任意周期性波形。
振荡器是音频合成中常见的基础构建模块。OscillatorNode 将在 start() 方法指定的时间开始发声。
从数学上讲,当在频域考虑时,连续时间周期波形可以包含非常高(或无限高)的频率信息。当该波形以特定采样率作为离散时间数字音频信号进行采样时,必须注意在将波形转换为数字形式之前丢弃(滤除)高于 奈奎斯特频率(Nyquist frequency) 的高频信息。如果不这样做,则高于 奈奎斯特频率 的更高频率的 混叠(aliasing) 将作为镜像折叠回低于 奈奎斯特频率 的频率。在许多情况下,这将导致听觉上令人反感的伪影。这是音频 DSP 的一个基本且众所周知的原理。
实现可以通过几种实际方法来避免这种混叠。无论采用哪种方法,理想的离散时间数字音频信号在数学上都是定义明确的。实现的权衡是实现成本(就 CPU 使用率而言)与实现这种理想的保真度之间的问题。
预期实现将对实现这种理想给予一定的关注,但在较低端的硬件上考虑质量较低、成本较低的方法是合理的。
frequency 和 detune 都是 a-rate 参数,并形成一个 复合参数(compound parameter)。它们一起使用以确定 computedOscFrequency 值。
computedOscFrequency(t) = frequency(t) * pow(2, detune(t) / 1200)
OscillatorNode 在每个时间的瞬时相位是 computedOscFrequency 的定积分,假设在节点的精确开始时间相位角为零。其 标称范围 为 [-奈奎斯特频率, 奈奎斯特频率]。
此节点的单个输出由一个通道(单声道)组成。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 0 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | No |
enum {OscillatorType "sine" ,"square" ,"sawtooth" ,"triangle" ,"custom" };
| 枚举值 | 描述 |
|---|---|
"sine" | 正弦波 |
"square" | 占空比为 0.5 的方波 |
"sawtooth" | 锯齿波 |
"triangle" | 三角波 |
"custom" | 自定义周期波 |
[Exposed =Window ]interface OscillatorNode :AudioScheduledSourceNode {constructor (BaseAudioContext ,context optional OscillatorOptions = {});options attribute OscillatorType type ;readonly attribute AudioParam frequency ;readonly attribute AudioParam detune ;undefined setPeriodicWave (PeriodicWave ); };periodicWave
1.26.1. 构造函数
OscillatorNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须使用 context 和 options 作为参数 初始化 AudioNode this。OscillatorNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 OscillatorNode将与之 关联 的BaseAudioContext。optionsOscillatorOptions✘ ✔ 此 OscillatorNode的可选初始参数值。
1.26.2. 属性
detune, 类型为 AudioParam,只读-
一种失谐值(以 音分(cents) 为单位),它将通过给定金额抵消
frequency。其默认value为 0。此参数是 a-rate 的。它与frequency形成一个 复合参数,以形成 computedOscFrequency。下面列出的标称范围允许此参数在整个可能的频率范围内对frequency进行失谐。参数 值 注 defaultValue0 minValue\(\approx -153600\) maxValue\(\approx 153600\) 该值约为 \(1200\ \log_2 \mathrm{FLT\_MAX}\),其中 FLT_MAX 是最大的 float值。automationRate" a-rate" frequency, 类型为 AudioParam,只读-
周期波形的频率(以赫兹为单位)。其默认
value为 440。此参数是 a-rate 的。它与detune形成一个 复合参数,以形成 computedOscFrequency。其 标称范围 为 [-奈奎斯特频率, 奈奎斯特频率]。参数 值 注 defaultValue440 minValue-奈奎斯特频率 maxValue奈奎斯特频率 automationRate" a-rate" type, 类型为 OscillatorType-
周期波形的形状。它可以直接设置为除 "
custom" 之外的任何类型常量值。这样做必须抛出InvalidStateError异常。setPeriodicWave()方法可用于设置自定义波形,这将导致此属性设置为 "custom"。默认值为 "sine"。设置此属性时,振荡器的相位必须保持不变。
1.26.3. 方法
setPeriodicWave(periodicWave)-
根据给定的
PeriodicWave设置任意的自定义周期波形。OscillatorNode.setPeriodicWave() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 periodicWavePeriodicWave✘ ✘ 振荡器将使用的自定义波形 返回类型:undefined
1.26.4. OscillatorOptions
这指定了在构建 OscillatorNode 时使用的选项。所有成员都是可选的;如果未指定,则使用常规默认值来构建振荡器。
dictionary OscillatorOptions :AudioNodeOptions {OscillatorType type = "sine";float frequency = 440;float detune = 0;PeriodicWave periodicWave ; };
1.26.4.1. 字典 OscillatorOptions 成员
detune, 类型为 float,默认值为0-
OscillatorNode的初始失谐值。 frequency, 类型为 float,默认值为440-
OscillatorNode的初始频率。 periodicWave, 类型为 PeriodicWave-
OscillatorNode的PeriodicWave。如果指定了此项,则type的任何有效值都将被忽略;它将被视为指定了 "custom"。 type, 类型为 OscillatorType,默认值为"sine"-
要构建的振荡器类型。如果将其设置为 "custom" 而未同时指定
periodicWave,则 必须抛出InvalidStateError异常。如果指定了periodicWave,则type的任何有效值都将被忽略;它将被视为已设置为 "custom"。
1.26.5. 基本波形相位
各种振荡器类型的理想数学波形定义如下。总之,所有波形在数学上定义为在时间 0 时具有正斜率的奇函数。振荡器产生的实际波形可能不同,以防止混叠影响。
振荡器产生的效果必须与使用具有适当 傅里叶级数 且 disableNormalization 设置为 false 的 PeriodicWave 来创建这些基本波形的结果相同。
- "
sine" -
正弦振荡器的波形为:
$$ x(t) = \sin t $$ - "
square" -
方波振荡器的波形为:
$$ x(t) = \begin{cases} 1 & \mbox{for } 0≤ t < \pi \\ -1 & \mbox{for } -\pi < t < 0. \end{cases} $$通过利用波形是周期为 \(2\pi\) 的奇函数这一事实,将其扩展到所有 \(t\)。
- "
sawtooth" -
锯齿波振荡器的波形是斜坡:
$$ x(t) = \frac{t}{\pi} \mbox{ for } -\pi < t ≤ \pi; $$通过利用波形是周期为 \(2\pi\) 的奇函数这一事实,将其扩展到所有 \(t\)。
- "
triangle" -
三角波振荡器的波形为:
$$ x(t) = \begin{cases} \frac{2}{\pi} t & \mbox{for } 0 ≤ t ≤ \frac{\pi}{2} \\ 1-\frac{2}{\pi} \left(t-\frac{\pi}{2}\right) & \mbox{for } \frac{\pi}{2} < t ≤ \pi. \end{cases} $$通过利用波形是周期为 \(2\pi\) 的奇函数这一事实,将其扩展到所有 \(t\)。
1.27. PannerNode 接口
此接口表示一个处理节点,它在三维空间中 定位/空间化 传入的音频流。空间化是相对于 BaseAudioContext 的 AudioListener(listener 属性)而言的。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | 具有 channelCount 约束 |
channelCountMode
| "clamped-max" | 具有 channelCountMode 约束 |
channelInterpretation
| "speakers" | |
| tail-time | 也许 | 如果 panningModel 设置为 "HRTF",由于头部响应的固有处理,该节点将为静音输入产生非静音输出。否则,尾部时间为零。 |
此节点的输入为单声道(1 通道)或立体声(2 通道),且无法增加。来自通道数较少或较多节点的连接将进行 适当的上混或下混。
如果节点正在 主动处理,则此节点的输出硬编码为立体声(2 通道),且无法配置。如果节点没有 主动处理,则输出为单个通道的静音。
PanningModelType 枚举决定将使用哪种空间化算法来在 3D 空间中定位音频。默认值为 "equalpower"。
enum {PanningModelType "equalpower" ,"HRTF" };
| 枚举值 | 描述 |
|---|---|
"equalpower" | 一种使用等功率平移(equal-power panning)的简单且高效的空间化算法。 注:使用此平移模型时,用于计算此节点输出的所有 |
"HRTF" | 一种更高质量的空间化算法,使用与人类受试者测得的脉冲响应进行卷积。此平移方法渲染立体声输出。 注:使用此平移模型时,用于计算此节点输出的所有 |
PannerNode 的 AudioParam 的有效自动化速率(effective automation rate)由该 AudioParam 的 panningModel 和 automationRate 决定。如果 panningModel 为“HRTF”,则有效自动化速率为“k-rate”,与 automationRate 的设置无关。否则,有效自动化速率即为 automationRate 的值。
DistanceModelType 枚举决定了当音频源远离听者时,用于降低其音量的算法。默认值为“inverse”。
在下面对每个距离模型的描述中,令 \(d\) 为听者与声源之间的距离;\(d_{ref}\) 为 refDistance 属性的值;\(d_{max}\) 为 maxDistance 属性的值;以及 \(f\) 为 rolloffFactor 属性的值。
enum {DistanceModelType "linear" ,"inverse" ,"exponential" };
| 枚举值 | 描述 |
|---|---|
"linear" | 线性距离模型,根据以下公式计算 distanceGain$$
1 - f\ \frac{\max\left[\min\left(d, d’_{max}\right), d’_{ref}\right] - d’_{ref}}{d’_{max} - d’_{ref}}
$$
其中 \(d’_{ref} = \min\left(d_{ref}, d_{max}\right)\) 且 \(d’_{max} = \max\left(d_{ref}, d_{max}\right)\)。在 \(d’_{ref} = d’_{max}\) 的情况下,线性模型的值取为 \(1-f\)。 注意 \(d\) 被限制在区间 \(\left[d’_{ref},\, d’_{max}\right]\) 内。 |
"inverse" | 反向距离模型,根据以下公式计算 distanceGain$$
\frac{d_{ref}}{d_{ref} + f\ \left[\max\left(d, d_{ref}\right) - d_{ref}\right]}
$$
即 \(d\) 被限制在区间 \(\left[d_{ref},\, \infty\right)\) 内。如果 \(d_{ref} = 0\),则反向模型的值取为 0,与 \(d\) 和 \(f\) 的值无关。 |
"exponential" | 指数距离模型,根据以下公式计算 distanceGain$$
\left[\frac{\max\left(d, d_{ref}\right)}{d_{ref}}\right]^{-f}
$$
即 \(d\) 被限制在区间 \(\left[d_{ref},\, \infty\right)\) 内。如果 \(d_{ref} = 0\),则指数模型的值取为 0,与 \(d\) 和 \(f\) 无关。 |
[Exposed =Window ]interface PannerNode :AudioNode {constructor (BaseAudioContext ,context optional PannerOptions = {});options attribute PanningModelType panningModel ;readonly attribute AudioParam positionX ;readonly attribute AudioParam positionY ;readonly attribute AudioParam positionZ ;readonly attribute AudioParam orientationX ;readonly attribute AudioParam orientationY ;readonly attribute AudioParam orientationZ ;attribute DistanceModelType distanceModel ;attribute double refDistance ;attribute double maxDistance ;attribute double rolloffFactor ;attribute double coneInnerAngle ;attribute double coneOuterAngle ;attribute double coneOuterGain ;undefined setPosition (float ,x float ,y float );z undefined setOrientation (float ,x float ,y float ); };z
1.27.1. 构造函数
PannerNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须初始化 AudioNode this,并以 context 和 options 作为参数。PannerNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 PannerNode将与之关联的BaseAudioContext。optionsPannerOptions✘ ✔ 此 PannerNode的可选初始参数值。
1.27.2. 属性
coneInnerAngle, 类型为 double-
定向音频源的参数,为一个角度(单位:度),在此角度内音量不会降低。默认值为 360。如果角度在区间 [0, 360] 之外,则行为未定义。
coneOuterAngle, 类型为 double-
定向音频源的参数,为一个角度(单位:度),在此角度外音量将降低至
coneOuterGain的恒定值。默认值为 360。如果角度在区间 [0, 360] 之外,则行为未定义。 coneOuterGain, 类型为 double-
定向音频源的参数,表示
coneOuterAngle之外的增益。默认值为 0。这是一个范围在 [0, 1] 内的线性值(非 dB)。如果参数在此范围之外,必须抛出InvalidStateError。 distanceModel, 类型为 DistanceModelType-
指定此
PannerNode使用的距离模型。默认为“inverse”。 maxDistance, 类型为 double-
声源与听者之间的最大距离,超过该距离后音量将不再降低。默认值为 10000。如果将其设置为非正值,必须抛出
RangeError异常。 orientationX, 类型为 AudioParam,只读-
描述 3D 笛卡尔坐标空间中音频源指向的向量的 \(x\) 分量。
参数 值 注 defaultValue1 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 orientationY, 类型为 AudioParam,只读-
描述 3D 笛卡尔坐标空间中音频源指向的向量的 \(y\) 分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 orientationZ, 类型为 AudioParam,只读-
描述 3D 笛卡尔坐标空间中音频源指向的向量的 \(z\) 分量。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 panningModel, 类型为 PanningModelType-
指定此
PannerNode使用的平移模型。默认为“equalpower”。 positionX, 类型为 AudioParam,只读-
设置 3D 笛卡尔系统中音频源的 \(x\) 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 positionY, 类型为 AudioParam,只读-
设置 3D 笛卡尔系统中音频源的 \(y\) 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 positionZ, 类型为 AudioParam,只读-
设置 3D 笛卡尔系统中音频源的 \(z\) 坐标位置。
参数 值 注 defaultValue0 minValuemost-negative-single-float 约为 -3.4028235e38 maxValuemost-positive-single-float 约为 3.4028235e38 automationRate" a-rate"具有自动化速率限制 refDistance, 类型为 double-
用于当声源远离听者时降低音量的参考距离。对于小于此值的距离,音量不会降低。默认值为 1。如果设置为负值,必须抛出
RangeError异常。 rolloffFactor, 类型为 double-
描述当声源远离听者时音量降低的快慢。默认值为 1。如果设置为负值,必须抛出
RangeError异常。rolloffFactor的标称范围指定了rolloffFactor可取的最小值和最大值。超出范围的值会被限制在此范围内。标称范围取决于distanceModel,具体如下- "
linear" -
标称范围为 \([0, 1]\)。
- "
inverse" -
标称范围为 \([0, \infty)\)。
- "
exponential" -
标称范围为 \([0, \infty)\)。
注意,限制操作作为距离计算处理的一部分发生。属性本身反映了设置的值,且不会被修改。
- "
1.27.3. 方法
setOrientation(x, y, z)-
此方法已弃用。它等同于直接设置
orientationX.value、orientationY.value和orientationZ.value属性,并分别传入x、y和z参数。因此,如果在调用此方法时,
orientationX、orientationY或orientationZAudioParam中的任何一个通过setValueCurveAtTime()设置了自动化曲线,则必须抛出NotSupportedError。描述 3D 笛卡尔坐标空间中音频源指向的方向。根据声音的定向性(由 cone 属性控制),背离听者的声音可能会变得非常小或完全静音。
x, y, z参数表示 3D 空间中的方向向量。默认值为 (1,0,0)。
PannerNode.setOrientation() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 xfloat✘ ✘ yfloat✘ ✘ zfloat✘ ✘ 返回类型:undefined setPosition(x, y, z)-
此方法已弃用。它等同于直接设置
positionX.value、positionY.value和positionZ.value属性,并分别传入x、y和z参数。因此,如果在调用此方法时,
positionX、positionY或positionZAudioParam中的任何一个通过setValueCurveAtTime()设置了自动化曲线,则必须抛出NotSupportedError。设置音频源相对于
listener属性的位置。使用 3D 笛卡尔坐标系。x, y, z参数表示 3D 空间中的坐标。默认值为 (0,0,0)。
PannerNode.setPosition() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 xfloat✘ ✘ yfloat✘ ✘ zfloat✘ ✘ 返回类型:undefined
1.27.4. PannerOptions
这指定了构建 PannerNode 的选项。所有成员均为可选;如果未指定,则使用构建该节点的正常默认值。
dictionary PannerOptions :AudioNodeOptions {PanningModelType panningModel = "equalpower";DistanceModelType distanceModel = "inverse";float positionX = 0;float positionY = 0;float positionZ = 0;float orientationX = 1;float orientationY = 0;float orientationZ = 0;double refDistance = 1;double maxDistance = 10000;double rolloffFactor = 1;double coneInnerAngle = 360;double coneOuterAngle = 360;double coneOuterGain = 0; };
1.27.4.1. 字典 PannerOptions 成员
coneInnerAngle, 类型为 double,默认为360-
该节点的
coneInnerAngle属性的初始值。 coneOuterAngle, 类型为 double,默认为360-
该节点的
coneOuterAngle属性的初始值。 coneOuterGain, 类型为 double,默认为0-
该节点的
coneOuterGain属性的初始值。 distanceModel, 类型为 DistanceModelType,默认为"inverse"-
用于该节点的距离模型。
maxDistance, 类型为 double,默认为10000-
该节点的
maxDistance属性的初始值。 orientationX, 类型为 float,默认为1-
orientationXAudioParam 的初始 \(x\) 分量值。 orientationY, 类型为 float,默认为0-
orientationYAudioParam 的初始 \(y\) 分量值。 orientationZ, 类型为 float,默认为0-
orientationZAudioParam 的初始 \(z\) 分量值。 panningModel, 类型为 PanningModelType,默认为"equalpower"-
用于该节点的平移模型。
positionX, 类型为 float,默认为0-
positionXAudioParam 的初始 \(x\) 坐标值。 positionY, 类型为 float,默认为0-
positionYAudioParam 的初始 \(y\) 坐标值。 positionZ, 类型为 float,默认为0-
positionZAudioParam 的初始 \(z\) 坐标值。 refDistance, 类型为 double,默认为1-
该节点的
refDistance属性的初始值。 rolloffFactor, 类型为 double,默认为1-
该节点的
rolloffFactor属性的初始值。
1.27.5. 声道限制
StereoPannerNode 的声道限制集同样适用于 PannerNode。
1.28. PeriodicWave 接口
PeriodicWave 表示用于 OscillatorNode 的任意周期波形。
符合要求的实现必须支持至少 8192 个元素的 PeriodicWave。
[Exposed =Window ]interface PeriodicWave {constructor (BaseAudioContext ,context optional PeriodicWaveOptions = {}); };options
1.28.1. 构造函数
PeriodicWave(context, options)-
-
令 p 为新的
PeriodicWave对象。令[[real]]和[[imag]]为两个类型为Float32Array的内部槽位,并令[[normalize]]为一个内部槽位。 -
根据以下情况之一处理
options-
如果同时提供了
options.real和options.imag-
如果
options.real和options.imag的长度不同,或者任何一个长度小于 2,则抛出IndexSizeError并终止此算法。 -
将
[[real]]和[[imag]]设置为与options.real长度相同的新数组。 -
将
options.real中的所有元素复制到[[real]],并将options.imag复制到[[imag]]。
-
-
如果仅提供了
options.real-
如果
options.real的长度小于 2,则抛出IndexSizeError并终止此算法。 -
将
[[real]]和[[imag]]设置为与options.real长度相同的数组。 -
将
options.real复制到[[real]],并将[[imag]]设置为全零数组。
-
-
如果仅提供了
options.imag-
如果
options.imag的长度小于 2,则抛出IndexSizeError并终止此算法。 -
将
[[real]]和[[imag]]设置为与options.imag长度相同的数组。 -
将
options.imag复制到[[imag]],并将[[real]]设置为全零数组。
-
-
否则
注意: 在
OscillatorNode上设置此PeriodicWave等同于使用内置类型“sine”。
-
-
将
[[normalize]]初始化为PeriodicWaveOptions中PeriodicWaveConstraints的disableNormalization属性的逆值。 -
返回 p。
PeriodicWave.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 PeriodicWave将与之关联的BaseAudioContext。与AudioBuffer不同,PeriodicWave不能跨AudioContext或OfflineAudioContext共享。它与特定的BaseAudioContext关联。optionsPeriodicWaveOptions✘ ✔ 此 PeriodicWave的可选初始参数值。 -
1.28.2. PeriodicWaveConstraints
PeriodicWaveConstraints 字典用于指定波形如何进行归一化。
dictionary PeriodicWaveConstraints {boolean disableNormalization =false ; };
1.28.2.1. 字典 PeriodicWaveConstraints 成员
disableNormalization, 类型为 boolean,默认为false-
控制周期波是否归一化。如果为
true,则不对波形进行归一化;否则,对波形进行归一化。
1.28.3. PeriodicWaveOptions
PeriodicWaveOptions 字典用于指定如何构建波形。如果仅指定了 real 或 imag 中的一个,另一个将被视为长度相同且全为零的数组,具体如字典成员描述中所述。如果两者均未给出,则创建的 PeriodicWave 必须等同于 OscillatorNode 且 type 为“sine”。如果两者均给出,则序列必须具有相同的长度;否则必须抛出 NotSupportedError 类型的错误。
dictionary PeriodicWaveOptions :PeriodicWaveConstraints {sequence <float >real ;sequence <float >imag ; };
1.28.3.1. 字典 PeriodicWaveOptions 成员
imag, 类型为 sequence<float>-
imag参数表示sine项的数组。第一个元素(索引 0)在傅里叶级数中不存在。第二个元素(索引 1)代表基频。第三个代表第一个泛音,依此类推。 real, 类型为 sequence<float>-
real参数表示cosine项的数组。第一个元素(索引 0)是周期波形的直流偏移(DC-offset)。第二个元素(索引 1)代表基频。第三个代表第一个泛音,依此类推。
1.28.4. 波形生成
createPeriodicWave() 方法采用两个数组来指定 PeriodicWave 的傅里叶系数。令 \(a\) 和 \(b\) 分别表示长度为 \(L\) 的 [[real]] 和 [[imag]] 数组。则基本时域波形 \(x(t)\) 可以通过以下公式计算
$$
x(t) = \sum_{k=1}^{L-1} \left[a[k]\cos2\pi k t + b[k]\sin2\pi k t\right]
$$
这是基本(未归一化)波形。
1.28.5. 波形归一化
如果此 PeriodicWave 的内部槽位 [[normalize]] 为 true(默认值),则上一节中定义的波形将进行归一化,使得最大值为 1。归一化过程如下。
令
$$
\tilde{x}(n) = \sum_{k=1}^{L-1} \left(a[k]\cos\frac{2\pi k n}{N} + b[k]\sin\frac{2\pi k n}{N}\right)
$$
其中 \(N\) 是 2 的幂。(注意:\(\tilde{x}(n)\) 可以通过使用反傅里叶变换 (IFFT) 方便地计算出来。)固定归一化因子 \(f\) 计算如下。
$$
f = \max_{n = 0, \ldots, N - 1} |\tilde{x}(n)|
$$
因此,实际的归一化波形 \(\hat{x}(n)\) 为
$$
\hat{x}(n) = \frac{\tilde{x}(n)}{f}
$$
该固定归一化因子必须应用于所有生成的波形。
1.28.6. 振荡器系数
内置振荡器类型使用 PeriodicWave 对象创建。为完整起见,此处给出了每种内置振荡器类型的 PeriodicWave 系数。这在需要内置类型但不需要默认归一化时非常有用。
在以下描述中,令 \(a\) 为 createPeriodicWave() 的实系数数组,\(b\) 为虚系数数组。在所有情况下,由于波形是奇函数,所有 \(n\) 的 \(a[n] = 0\)。此外,所有情况下 \(b[0] = 0\)。因此,下面仅指定 \(n \ge 1\) 时的 \(b[n]\)。
- "
sine" -
$$ b[n] = \begin{cases} 1 & \mbox{for } n = 1 \\ 0 & \mbox{otherwise} \end{cases} $$ - "
square" -
$$ b[n] = \frac{2}{n\pi}\left[1 - (-1)^n\right] $$ - "
sawtooth" -
$$ b[n] = (-1)^{n+1} \dfrac{2}{n\pi} $$ - "
triangle" -
$$ b[n] = \frac{8\sin\dfrac{n\pi}{2}}{(\pi n)^2} $$
1.29. ScriptProcessorNode 接口 - 已弃用
此接口是一个 AudioNode,可以使用脚本直接生成、处理或分析音频。此节点类型已弃用,将由 AudioWorkletNode 取代;此文本仅保留供参考,直到实现中移除此节点类型为止。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| numberOfInputChannels
| 这是构建此节点时指定的声道数。存在声道计数约束。 |
channelCountMode
| "explicit" | 具有声道计数模式约束 |
channelInterpretation
| "speakers" | |
| tail-time | No |
ScriptProcessorNode 构建时带有 bufferSize,其值必须为以下之一:256、512、1024、2048、4096、8192、16384。此值控制 audioprocess 事件的分发频率以及每次调用需要处理多少样本帧。audioprocess 事件仅在 ScriptProcessorNode 至少连接了一个输入或一个输出时才会分发。bufferSize 的数值越小,延迟就越低(越好)。数值越大,越能避免音频中断和故障(glitches)。如果未将 createScriptProcessor() 的 bufferSize 参数传入,或者设置为 0,则此值将由实现方选择。
numberOfInputChannels 和 numberOfOutputChannels 决定输入和输出的声道数。numberOfInputChannels 和 numberOfOutputChannels 同时为零是无效的。
[Exposed =Window ]interface ScriptProcessorNode :AudioNode {attribute EventHandler onaudioprocess ;readonly attribute long bufferSize ; };
1.29.1. 属性
bufferSize, 类型为 long,只读-
每次触发
audioprocess时需要处理的缓冲区大小(以样本帧为单位)。合法值为 (256, 512, 1024, 2048, 4096, 8192, 16384)。 onaudioprocess, 类型为 EventHandler-
用于设置 事件处理程序的属性,该处理程序用于分发到
ScriptProcessorNode节点类型的audioprocess事件类型。分发到事件处理程序的事件使用AudioProcessingEvent接口。
1.30. StereoPannerNode 接口
此接口表示一个处理节点,它使用低成本平移算法在立体声图像中定位传入的音频流。这种平移效果在立体声流中定位音频组件时非常常见。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | 具有声道计数约束 |
channelCountMode
| "clamped-max" | 具有声道计数模式约束 |
channelInterpretation
| "speakers" | |
| tail-time | No |
此节点的输入为立体声(2 声道),无法增加。来自声道更少或更多的节点的连接将适当地进行上混或下混。
此节点的输出硬编码为立体声(2 声道),无法配置。
[Exposed =Window ]interface StereoPannerNode :AudioNode {constructor (BaseAudioContext ,context optional StereoPannerOptions = {});options readonly attribute AudioParam pan ; };
1.30.1. 构造函数
StereoPannerNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须初始化 AudioNode this,并以 context 和 options 作为参数。StereoPannerNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 StereoPannerNode将与之关联的BaseAudioContext。optionsStereoPannerOptions✘ ✔ 此 StereoPannerNode的可选初始参数值。
1.30.2. 属性
pan, 类型为 AudioParam,只读-
输入在输出立体声图像中的位置。-1 表示完全左侧,+1 表示完全右侧。
参数 值 注 defaultValue0 minValue-1 maxValue1 automationRate" a-rate"
1.30.3. StereoPannerOptions
这指定了构建 StereoPannerNode 时使用的选项。所有成员均为可选;如果未指定,则使用构建该节点的正常默认值。
dictionary StereoPannerOptions :AudioNodeOptions {float pan = 0; };
1.30.3.1. 字典 StereoPannerOptions 成员
pan, 类型为 float,默认为0-
panAudioParam 的初始值。
1.30.4. 声道限制
由于其处理受到上述定义的限制,StereoPannerNode 限制为混合不超过 2 个声道音频,并产生恰好 2 个声道。可以使用 ChannelSplitterNode、通过 GainNode 和/或其他节点组成的子图进行中间处理,以及通过 ChannelMergerNode 进行重组,来实现任意平移和混音方法。
1.31. WaveShaperNode 接口
WaveShaperNode 是一个实现非线性失真效果的 AudioNode 处理器。
非线性波形重塑失真通常用于微妙的非线性暖化,或更明显的失真效果。可以指定任意的非线性重塑曲线。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | 也许 | 仅当 oversample 属性设置为“2x”或“4x”时,才存在尾部时间(tail-time)。此尾部时间的实际持续时间取决于具体实现。 |
输出的通道数始终等于输入的通道数。
enum {OverSampleType "none" ,"2x" ,"4x" };
| 枚举值 | 描述 |
|---|---|
"none" | 不进行过采样 |
"2x" | 进行 2 倍过采样 |
"4x" | 进行 4 倍过采样 |
[Exposed =Window ]interface WaveShaperNode :AudioNode {constructor (BaseAudioContext ,context optional WaveShaperOptions = {});options attribute Float32Array ?curve ;attribute OverSampleType oversample ; };
1.31.1. 构造函数
WaveShaperNode(context, options)-
当使用
BaseAudioContextc 和选项对象 option 调用构造函数时,用户代理必须初始化 AudioNode this,并以 context 和 options 作为参数。此外,令
[[curve set]]为此WaveShaperNode的内部槽位。将此槽位初始化为false。如果给出了options并指定了curve,则将[[curve set]]设置为true。WaveShaperNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 WaveShaperNode将与之关联的BaseAudioContext。optionsWaveShaperOptions✘ ✔ 此 WaveShaperNode的可选初始参数值。
1.31.2. 属性
curve, 类型为 Float32Array,可为空-
用于波形重塑效果的重塑曲线。输入信号通常在 [-1, 1] 范围内。在此范围内的每个输入样本都将索引到重塑曲线中,如果曲线数组中的条目数为奇数,则零信号电平对应数组的中心值;如果数组中的条目数为偶数,则在两个最中心的值之间进行插值。任何小于 -1 的样本值将对应曲线数组中的第一个值。任何大于 +1 的样本值将对应曲线数组中的最后一个值。
实现必须在曲线的相邻点之间执行线性插值。最初
curve属性为 null,这意味着WaveShaperNode将原样传递输入到输出,不做修改。曲线的值在 [-1, 1] 范围内均匀分布。这意味着具有偶数个值的
curve在信号为零时将没有对应值,而具有奇数个值的curve在信号为零时将有对应值。输出由以下算法确定。-
令 \(x\) 为输入样本,\(y\) 为节点的对应输出,\(c_k\) 为
curve的第 \(k\) 个元素,\(N\) 为curve的长度。 -
令
$$ \begin{align*} v &= \frac{N-1}{2}(x + 1) \\ k &= \lfloor v \rfloor \\ f &= v - k \end{align*} $$ -
然后
$$ \begin{align*} y &= \begin{cases} c_0 & v \lt 0 \\ c_{N-1} & v \ge N - 1 \\ (1-f)\,c_k + fc_{k+1} & \mathrm{otherwise} \end{cases} \end{align*} $$
如果此属性设置为长度小于 2 的
Float32Array,则必须抛出InvalidStateError。设置此属性时,
WaveShaperNode会创建曲线的内部副本。因此,后续修改用于设置该属性的数组内容将不会产生任何影响。要设置curve属性,请执行以下步骤-
令 new curve 为要分配给
curve的Float32Array或null。 -
如果 new curve 不为
null且[[curve set]]为 true,则抛出InvalidStateError并终止这些步骤。 -
如果 new curve 不为
null,则将[[curve set]]设置为 true。 -
将 new curve 分配给
curve属性。
注意: 使用在输入为零时产生非零输出值的曲线,将导致此节点产生直流信号,即使没有输入连接到此节点。这种现象将持续到该节点与下游节点断开连接为止。
-
oversample, 类型为 OverSampleType-
指定应用重塑曲线时应使用哪种类型的过采样(如果有)。默认值为“
none”,表示曲线将直接应用于输入样本。值为“2x”或“4x”可以通过避免某些混叠来提高处理质量,其中“4x”值可产生最高质量。对于某些应用,最好不使用过采样以获得非常精确的重塑曲线。值为“2x”或“4x”意味着必须执行以下步骤-
将输入样本上采样至
AudioContext采样率的 2 倍或 4 倍。因此,对于每个渲染量子(render quantum),生成两倍(2x)或四倍(4x)的样本。 -
应用重塑曲线。
-
将结果下采样回
AudioContext的采样率。从而获取先前处理过的样本,生成单个渲染量子长度的样本作为最终结果。
确切的上采样和下采样滤波器未指定,可以针对音质(低混叠等)、低延迟或性能进行调优。
注意: 使用过采样由于上采样和下采样滤波器而引入了一定程度的音频处理延迟。这种延迟量在不同实现之间可能有所不同。
-
1.31.3. WaveShaperOptions
这指定了构建 WaveShaperNode 的选项。所有成员均为可选;如果未指定,则使用构建该节点的正常默认值。
dictionary WaveShaperOptions :AudioNodeOptions {sequence <float >curve ;OverSampleType oversample = "none"; };
1.31.3.1. 字典 WaveShaperOptions 成员
curve, 类型为 sequence<float>-
重塑效果的重塑曲线。
oversample, 类型为 OverSampleType,默认为"none"-
用于重塑曲线的过采样类型。
1.32. AudioWorklet 接口
[Exposed =Window ,SecureContext ]interface AudioWorklet :Worklet {readonly attribute MessagePort port ; };
1.32.1. 属性
port, 类型为 MessagePort,只读-
连接到
AudioWorkletGlobalScope上端口的MessagePort。注意: 在此
port的"message"事件上注册事件监听器的作者,应在MessageChannel的任意一端(在AudioWorklet或AudioWorkletGlobalScope端)调用close,以允许资源被回收。
1.32.2. 概念
AudioWorklet 对象允许开发者提供脚本(如 JavaScript 或 WebAssembly 代码)在渲染线程上处理音频,支持自定义 AudioNode。此处理机制确保了脚本代码与音频图中其他内置 AudioNode 的同步执行。
为了实现此机制,必须定义一对关联对象:AudioWorkletNode 和 AudioWorkletProcessor。前者表示主全局作用域的接口,类似于其他 AudioNode 对象;后者在名为 AudioWorkletGlobalScope 的特殊作用域内实现内部音频处理。
AudioWorkletNode 和 AudioWorkletProcessor每个 BaseAudioContext 拥有恰好一个 AudioWorklet。
AudioWorklet 的工作线程全局作用域类型为 AudioWorkletGlobalScope。
AudioWorklet 的工作线程目标类型为 "audioworklet"。
通过 addModule(moduleUrl) 方法导入脚本,可以在 AudioWorkletGlobalScope 下注册 AudioWorkletProcessor 的类定义。对于导入的类构造函数和从该构造函数创建的活动实例,有两个内部存储区域。
AudioWorklet 有一个内部槽位
-
节点名称到参数描述符的映射,这是一个映射,包含与节点名称到处理器构造函数映射中相同的一组字符串键,这些键关联着匹配的 parameterDescriptors 值。此内部存储是在渲染线程中调用
registerProcessor()方法后填充的。保证该填充操作在上下文的audioWorklet上调用addModule()所返回的 promise 解析之前完成。
// bypass-processor.js script file, runs on AudioWorkletGlobalScope class BypassProcessorextends AudioWorkletProcessor{ process( inputs, outputs) { // Single input, single channel. const input= inputs[ 0 ]; const output= outputs[ 0 ]; output[ 0 ]. set( input[ 0 ]); // Process only while there are active inputs. return false ; } }; registerProcessor( 'bypass-processor' , BypassProcessor);
// The main global scope const context= new AudioContext(); context. audioWorklet. addModule( 'bypass-processor.js' ). then(() => { const bypassNode= new AudioWorkletNode( context, 'bypass-processor' ); });
在主全局作用域实例化 AudioWorkletNode 时,对应的 AudioWorkletProcessor 也将在 AudioWorkletGlobalScope 中创建。这两个对象通过 § 2 处理模型 中描述的异步消息传递进行通信。
1.32.3. AudioWorkletGlobalScope 接口
此特殊执行上下文旨在利用音频渲染线程中的脚本直接启用音频数据的生成、处理和分析。用户提供的脚本代码在此作用域中执行,以定义一个或多个 AudioWorkletProcessor 子类,进而用于实例化 AudioWorkletProcessor,与主作用域中的 AudioWorkletNode 建立 1:1 的关联。
对于每个包含一个或多个 AudioWorkletNode 的 AudioContext,均存在且仅存在一个 AudioWorkletGlobalScope。导入脚本的运行由用户代理按照 [HTML] 中的定义执行。作为对 [HTML] 中指定的默认行为的覆盖,用户代理不得随意终止 AudioWorkletGlobalScope。
AudioWorkletGlobalScope 具有以下内部槽位
-
节点名称到处理器构造函数映射,这是一个映射,存储 处理器名称 →
AudioWorkletProcessorConstructor实例的键值对。初始时该映射为空,在调用registerProcessor()方法时进行填充。 -
挂起的处理器构造数据,存储由
AudioWorkletNode构造函数生成的临时数据,用于实例化对应的AudioWorkletProcessor。挂起的处理器构造数据包含以下项-
节点引用,初始为空。此存储用于存放从
AudioWorkletNode构造函数传输过来的AudioWorkletNode引用。 -
传输端口,初始为空。此存储用于存放从
AudioWorkletNode构造函数传输过来的反序列化后的MessagePort。
-
注:AudioWorkletGlobalScope 还可以包含由这些实例共享的任何其他数据和代码。例如,多个处理器可以共享一个定义波表或脉冲响应的 ArrayBuffer。
注:AudioWorkletGlobalScope 与单个 BaseAudioContext 关联,并与该上下文的单个音频渲染线程关联。这可以防止在并发线程中运行的全局作用域代码出现数据竞争。
callback =AudioWorkletProcessorConstructor AudioWorkletProcessor (object ); [options Global =(Worklet ,AudioWorklet ),Exposed =AudioWorklet ]interface AudioWorkletGlobalScope :WorkletGlobalScope {undefined registerProcessor (DOMString name ,AudioWorkletProcessorConstructor processorCtor );readonly attribute unsigned long long currentFrame ;readonly attribute double currentTime ;readonly attribute float sampleRate ;readonly attribute unsigned long renderQuantumSize ;readonly attribute MessagePort port ; };
1.32.3.1. 属性
currentFrame,类型为 unsigned long long,只读-
正在处理的音频块的当前帧。此值必须等于
BaseAudioContext的[[current frame]]内部槽位的值。 currentTime,类型为 double,只读-
正在处理的音频块的上下文时间。根据定义,此值将等于在控制线程中最近观察到的
BaseAudioContext的currentTime属性值。 sampleRate,类型为 float,只读-
关联的
BaseAudioContext的采样率。 renderQuantumSize,类型为 unsigned long,只读-
关联的
BaseAudioContext的私有槽位 [[render quantum size]] 的值。 port,类型为 MessagePort,只读-
一个连接到
AudioWorklet上端口的MessagePort。注:在此
port的"message"事件上注册事件监听器的作者,应在MessageChannel的任一端(AudioWorklet或AudioWorkletGlobalScope端)调用close,以允许资源被回收。
1.32.3.2. 方法
registerProcessor(name, processorCtor)-
注册一个派生自
AudioWorkletProcessor的类构造函数。当调用registerProcessor(name, processorCtor)方法时,执行以下步骤。如果在任何步骤中抛出异常,则中止剩余步骤。-
如果 name 为空字符串,则抛出
NotSupportedError。 -
如果 name 已作为键存在于 节点名称到处理器构造函数映射中,则抛出
NotSupportedError。 -
如果
IsConstructor(argument=processorCtor)的结果为false,则抛出TypeError。 -
令
prototype为Get(O=processorCtor, P="prototype")的结果。 -
令 parameterDescriptorsValue 为
Get(O=processorCtor, P="parameterDescriptors")的结果。 -
如果 parameterDescriptorsValue 不为
undefined,执行以下步骤-
令 parameterDescriptorSequence 为将 parameterDescriptorsValue 转换为
sequence<AudioParamDescriptor>类型的 IDL 值的结果。 -
令 paramNames 为一个空数组。
-
对于 parameterDescriptorSequence 中的每个 descriptor
-
令 paramName 为 descriptor 中成员
name的值。如果 paramNames 已包含 paramName 值,则抛出NotSupportedError。 -
将 paramName 追加到 paramNames 数组中。
-
令 defaultValue 为 descriptor 中成员
defaultValue的值。 -
令 minValue 为 descriptor 中成员
minValue的值。 -
令 maxValue 为 descriptor 中成员
maxValue的值。 -
如果表达式 minValue <= defaultValue <= maxValue 为假,则抛出
InvalidStateError。
-
-
-
将键值对 name → processorCtor 追加到关联的
AudioWorkletGlobalScope的节点名称到处理器构造函数映射中。 -
队列化一个媒体元素任务,将键值对 name → parameterDescriptorSequence 追加到关联的
BaseAudioContext的节点名称到参数描述符的映射中。
注:类构造函数只应查找一次,因此它没有在注册后动态更改的机会。
AudioWorkletGlobalScope.registerProcessor(name, processorCtor) 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 nameDOMString✘ ✘ 表示要注册的类构造函数的字符串键。在构建 AudioWorkletNode时,此键用于查找AudioWorkletProcessor的构造函数。processorCtorAudioWorkletProcessorConstructor✘ ✘ 扩展自 AudioWorkletProcessor的类构造函数。返回类型:undefined -
1.32.3.3. AudioWorkletProcessor 的实例化
在 AudioWorkletNode 构造结束时,将准备一个名为 处理器构造数据 的结构体,用于跨线程传输。此结构体包含以下项
-
name,一个要在节点名称到处理器构造函数映射中进行查找的
DOMString。 -
node,对所创建的
AudioWorkletNode的引用。 -
options,提供给
AudioWorkletNode的constructor的序列化AudioWorkletNodeOptions。 -
port,与
AudioWorkletNode的port配对的序列化MessagePort。
当传输的数据到达 AudioWorkletGlobalScope 时,渲染线程将调用以下算法
-
令 processorName、nodeReference 和 serializedPort 分别为 constructionData 的名称、节点和端口。
-
令 serializedOptions 为 constructionData 的选项。
-
令 deserializedPort 为 StructuredDeserialize(serializedPort, 当前领域) 的结果。
-
令 deserializedOptions 为 StructuredDeserialize(serializedOptions, 当前领域) 的结果。
-
令 processorCtor 为在
AudioWorkletGlobalScope的节点名称到处理器构造函数映射中查找 processorName 的结果。 -
将 nodeReference 和 deserializedPort 分别存储到此
AudioWorkletGlobalScope的挂起的处理器构造数据中的节点引用和传输端口。 -
构建一个回调函数,该函数来自 processorCtor,参数为 deserializedOptions。如果回调中抛出任何异常,则队列化一个任务到控制线程,以使用
ErrorEvent在 nodeReference 上触发一个名为processorerror的事件。 -
清空挂起的处理器构造数据槽位。
1.32.4. AudioWorkletNode 接口
此接口代表一个存在于控制线程上的用户定义 AudioNode。用户可以从 BaseAudioContext 创建 AudioWorkletNode,并且此类节点可以与其他内置 AudioNode 连接以形成音频图。
| 属性 | 值 | 注 |
|---|---|---|
numberOfInputs
| 1 | |
numberOfOutputs
| 1 | |
channelCount
| 2 | |
channelCountMode
| "max" | |
channelInterpretation
| "speakers" | |
| tail-time | 参见注 | 任何尾部时间均由节点自身处理 |
每个 AudioWorkletProcessor 都带有一个关联的活动源标志,初始为 true。该标志使节点保留在内存中,即使在没有连接输入的情况下也执行音频处理。
从 AudioWorkletNode 发出的所有任务均被发送到其关联的 BaseAudioContext 的任务队列。
[Exposed =Window ]interface {AudioParamMap readonly maplike <DOMString ,AudioParam >; };
此接口具有由 readonly maplike 带来的 "entries"、"forEach"、"get"、"has"、"keys"、"values"、@@iterator 方法和一个 "size" 获取器。
[Exposed =Window ,SecureContext ]interface AudioWorkletNode :AudioNode {constructor (BaseAudioContext ,context DOMString ,name optional AudioWorkletNodeOptions = {});options readonly attribute AudioParamMap parameters ;readonly attribute MessagePort port ;attribute EventHandler onprocessorerror ; };
1.32.4.1. 构造函数
AudioWorkletNode(context, name, options)-
AudioWorkletNode.constructor() 方法的参数。 参数 类型 可为空 (Nullable) 可选 (Optional) 描述 contextBaseAudioContext✘ ✘ 此新 AudioWorkletNode将与之关联的BaseAudioContext。nameDOMString✘ ✘ 一个字符串,它是 BaseAudioContext的节点名称到参数描述符映射的键。optionsAudioWorkletNodeOptions✘ ✔ 此 AudioWorkletNode的可选初始参数值。当调用构造函数时,用户代理必须在控制线程上执行以下步骤
当使用 context、nodeName、options 调用AudioWorkletNode构造函数时-
如果 nodeName 不作为
BaseAudioContext的节点名称到参数描述符映射中的键存在,则抛出InvalidStateError异常并中止这些步骤。 -
令 node 为此值。
-
初始化 AudioNode node,并以 context 和 options 为参数。
-
配置 node 的输入、输出和输出通道(参数为 options)。如果抛出任何异常,则中止剩余步骤。
-
令 messageChannel 为一个新的
MessageChannel。 -
令 nodePort 为 messageChannel 的
port1属性的值。 -
令 processorPortOnThisSide 为 messageChannel 的
port2属性的值。 -
令 serializedProcessorPort 为 StructuredSerializeWithTransfer(processorPortOnThisSide, « processorPortOnThisSide ») 的结果。
-
将 options 字典转换为 optionsObject。
-
令 serializedOptions 为 StructuredSerialize(optionsObject) 的结果。
-
将 node 的
port设置为 nodePort。 -
令 parameterDescriptors 为从节点名称到参数描述符映射中检索 nodeName 的结果。
-
令 audioParamMap 为一个新的
AudioParamMap对象。 -
对于 parameterDescriptors 中的每个 descriptor
-
令 paramName 为 descriptor 中
name成员的值。 -
令 audioParam 为一个新的
AudioParam实例,其automationRate、defaultValue、minValue和maxValue的值等于 descriptor 上相应成员的值。 -
将键值对 paramName → audioParam 追加到 audioParamMap 的条目中。
-
-
如果 options 上存在
parameterData,则执行以下步骤-
令 parameterData 为
parameterData的值。 -
对于 parameterData 中的每个 paramName → paramValue
-
如果 audioParamMap 上存在键为 paramName 的映射条目,令 audioParamInMap 为该条目。
-
将 audioParamInMap 的
value属性设置为 paramValue。
-
-
-
将 node 的
parameters设置为 audioParamMap。
-
-
队列化一条控制消息,以调用对应
AudioWorkletProcessor的constructor,并传入由以下内容组成的处理器构造数据:nodeName、node、serializedOptions 和 serializedProcessorPort。
-
1.32.4.2. 属性
onprocessorerror,类型为 EventHandler-
当处理器的
constructor、process方法或任何用户定义的类方法抛出未捕获的异常时,处理器将队列化一个媒体元素任务,以使用ErrorEvent在关联的AudioWorkletNode上触发一个名为processorerror的事件。ErrorEvent是在控制线程上创建并适当初始化其message、filename、lineno、colno属性的。注意,一旦抛出未捕获的异常,处理器在其生命周期内将输出静音。
parameters,类型为 AudioParamMap,只读-
parameters属性是一组带有关联名称的AudioParam对象的集合。此映射类对象在实例化时,由AudioWorkletProcessor类构造函数中的AudioParamDescriptor列表填充。 port,类型为 MessagePort,只读-
每个
AudioWorkletNode都有一个关联的port,即MessagePort。它连接到相应AudioWorkletProcessor对象上的端口,允许AudioWorkletNode与其AudioWorkletProcessor之间进行双向通信。注:在此
port的"message"事件上注册事件监听器的作者,应在MessageChannel的任一端(AudioWorkletProcessor或AudioWorkletNode端)调用close,以允许资源被回收。
1.32.4.3. AudioWorkletNodeOptions
AudioWorkletNodeOptions 字典可用于初始化 AudioWorkletNode 实例中的属性。
dictionary AudioWorkletNodeOptions :AudioNodeOptions {unsigned long numberOfInputs = 1;unsigned long numberOfOutputs = 1;sequence <unsigned long >outputChannelCount ;record <DOMString ,double >parameterData ;object processorOptions ; };
1.32.4.3.1. 字典 AudioWorkletNodeOptions 成员
numberOfInputs,类型为 unsigned long,默认为1-
此成员用于初始化
AudioNode的numberOfInputs属性值。 numberOfOutputs,类型为 unsigned long,默认为1-
此成员用于初始化
AudioNode的numberOfOutputs属性值。 outputChannelCount,类型为sequence<unsigned long>-
此数组用于配置每个输出中的通道数。
parameterData,类型为 record<DOMString, double>-
这是一组用户定义的键值对,用于设置
AudioWorkletNode中匹配名称的AudioParam的初始value。 processorOptions,类型为 object-
此成员保存任何用户定义的数据,该数据可用于初始化与
AudioWorkletNode关联的AudioWorkletProcessor实例中的自定义属性。
1.32.4.3.2. 使用 AudioWorkletNodeOptions 配置通道
以下算法描述了如何使用 AudioWorkletNodeOptions 来配置各种通道设置。
-
令 node 为提供给此算法的
AudioWorkletNode实例。 -
如果
numberOfInputs和numberOfOutputs均为零,则抛出NotSupportedError并中止剩余步骤。 -
如果
outputChannelCount存在,-
如果
outputChannelCount中的任何值小于零或大于实现允许的最大通道数,则抛出NotSupportedError并中止剩余步骤。 -
如果
outputChannelCount的长度不等于numberOfOutputs,则抛出IndexSizeError并中止剩余步骤。 -
如果
numberOfInputs和numberOfOutputs均为 1,则将 node 输出的通道计数设置为outputChannelCount中的唯一值。 -
否则,将 node 的第 k 个输出的通道计数设置为
outputChannelCount序列的第 k 个元素并返回。
-
-
如果
outputChannelCount不存在,-
如果
numberOfInputs和numberOfOutputs均为 1,则将 node 输出的初始通道计数设置为 1 并返回。NOTE: 对于这种情况,输出通道计数将在运行时根据输入和
channelCountMode动态变为 computedNumberOfChannels。 -
否则,将 node 每个输出的通道计数设置为 1 并返回。
-
1.32.5. AudioWorkletProcessor 接口
此接口代表在音频渲染线程上运行的音频处理代码。它存在于 AudioWorkletGlobalScope 中,类的定义体现了实际的音频处理。请注意,AudioWorkletProcessor 的构建只能作为 AudioWorkletNode 构建的结果发生。
[Exposed =AudioWorklet ]interface AudioWorkletProcessor {constructor ();readonly attribute MessagePort port ; };callback AudioWorkletProcessCallback =boolean (FrozenArray <FrozenArray <Float32Array >>,inputs FrozenArray <FrozenArray <Float32Array >>,outputs object );parameters
AudioWorkletProcessor 具有两个内部槽位
[[node reference]]-
对关联
AudioWorkletNode的引用。 [[callable process]]-
一个布尔标志,表示 process() 是否为可调用的有效函数。
1.32.5.1. 构造函数
AudioWorkletProcessor()-
当调用
AudioWorkletProcessor的构造函数时,在渲染线程上执行以下步骤。-
令 nodeReference 为在当前
AudioWorkletGlobalScope的挂起的处理器构造数据中查找节点引用的结果。如果该槽位为空,则抛出TypeError异常。 -
令 processor 为此值。
-
将 processor 的
[[node reference]]设置为 nodeReference。 -
将 processor 的
[[callable process]]设置为true。 -
令 deserializedPort 为从挂起的处理器构造数据中查找传输端口的结果。
-
将 processor 的
port设置为 deserializedPort。 -
清空挂起的处理器构造数据槽位。
-
1.32.5.2. 属性
port,类型为 MessagePort,只读-
每个
AudioWorkletProcessor都有一个关联的port,即MessagePort。它连接到相应AudioWorkletNode对象上的端口,允许AudioWorkletNode与其AudioWorkletProcessor之间进行双向通信。注:在此
port的"message"事件上注册事件监听器的作者,应在MessageChannel的任一端(AudioWorkletProcessor或AudioWorkletNode端)调用close,以允许资源被回收。
1.32.5.3. 回调 AudioWorkletProcessCallback
用户可以通过扩展 AudioWorkletProcessor 来定义自定义音频处理器。子类必须定义一个名为 process() 的 AudioWorkletProcessCallback,用于实现音频处理算法,并且可以有一个名为 parameterDescriptors 的静态属性,该属性是一个 AudioParamDescriptor 的可迭代对象。
AudioWorkletProcessor 关联 AudioWorkletNode 的生命周期。此生命周期策略可以支持内置节点中发现的多种方法,包括以下几种
-
变换其输入且仅在连接了输入和/或脚本引用存在时才处于活动状态的节点。此类节点应从 process() 返回
false,这允许通过是否有连接的输入来确定AudioWorkletNode是否处于主动处理状态。 -
在输入断开后仍保留一段时间尾部时间的节点。在这种情况下,当发现
inputs包含零个通道时,process() 应返回true一段时间。当前时间可以从全局作用域的currentTime获取,以衡量此尾部时间间隔的开始和结束,或者该间隔可以根据处理器的内部状态动态计算。 -
充当输出源(通常具有特定生命周期)的节点。此类节点应从 process() 返回
true,直到它们不再产生输出为止。
请注意,上述定义意味着当 process() 的实现未提供返回值时,其效果与返回 false 相同(因为有效的返回值是 falsy 值 undefined)。对于任何仅在有活动输入时才处于活动状态的 AudioWorkletProcessor,这是一种合理的行为。
下面的示例展示了如何在 AudioWorkletProcessor 中定义和使用 AudioParam。
class MyProcessorextends AudioWorkletProcessor{ static get parameterDescriptors() { return [{ name: 'myParam' , defaultValue: 0.5 , minValue: 0 , maxValue: 1 , automationRate: "k-rate" }]; } process( inputs, outputs, parameters) { // Get the first input and output. const input= inputs[ 0 ]; const output= outputs[ 0 ]; const myParam= parameters. myParam; // A simple amplifier for single input and output. Note that the // automationRate is "k-rate", so it will have a single value at index [0] // for each render quantum. for ( let channel= 0 ; channel< output. length; ++ channel) { for ( let i= 0 ; i< output[ channel]. length; ++ i) { output[ channel][ i] = input[ channel][ i] * myParam[ 0 ]; } } } }
1.32.5.3.1. 回调 AudioWorkletProcessCallback 参数
以下描述了 AudioWorkletProcessCallback 函数的参数。通常,inputs 和 outputs 数组会在多次调用之间重复使用,因此不会进行内存分配。但是,如果拓扑结构发生变化(例如,输入或输出中的通道数量发生变化),则会重新分配新的数组。如果 inputs 或 outputs 数组的任何部分被传输,也会重新分配新的数组。
inputs,类型为FrozenArray<FrozenArray<Float32Array>>-
用户代理提供的来自传入连接的输入音频缓冲区。
inputs[n][m]是一个Float32Array,包含第 \(n\) 个输入的第 \(m\) 个通道的音频采样。虽然输入数量在构建时是固定的,但通道数量可以根据 computedNumberOfChannels 动态更改。如果对于当前的渲染量(render quantum),没有连接到
AudioWorkletNode第 \(n\) 个输入的主动处理状态AudioNode,则inputs[n]的内容是一个空数组,表示没有可用的输入通道。这是inputs[n]元素数量可以为零的唯一情况。 outputs,类型为FrozenArray<FrozenArray<Float32Array>>-
由用户代理消费的输出音频缓冲区。
outputs[n][m]是一个包含第 \(n\) 个输出的第 \(m\) 个通道音频采样的Float32Array对象。每个Float32Array均已初始化为零。仅当节点具有单个输出时,输出中的通道数才会与 computedNumberOfChannels 匹配。 parameters,类型为object-
一个 name → parameterValues 的有序映射。
parameters["name"]返回 parameterValues,这是一个FrozenArray<Float32Array>,其中包含该 nameAudioParam的自动控制值。对于每个数组,该数组包含渲染量中所有帧参数的计算值。但是,如果在此渲染量期间没有预定自动控制,则数组的长度可以为 1,数组元素为该渲染量内
AudioParam的恒定值。此对象根据以下步骤被冻结
-
令 parameter 为名称和参数值的有序映射。
-
SetIntegrityLevel(parameter, frozen)
算法中计算出的此冻结有序映射被传递给
parameters参数。注:这意味着该对象无法被修改,因此除非数组长度发生变化,否则同一个对象可以用于连续的调用。
-
1.32.5.4. AudioParamDescriptor
AudioParamDescriptor 字典用于指定在 AudioWorkletNode 中使用的 AudioParam 对象的属性。
dictionary AudioParamDescriptor {required DOMString name ;float defaultValue = 0;float minValue = -3.4028235e38;float maxValue = 3.4028235e38;AutomationRate automationRate = "a-rate"; };
1.32.5.4.1. 字典 AudioParamDescriptor 成员
这些成员的值存在约束。有关约束,请参见处理 AudioParamDescriptor 的算法。
automationRate,类型为 AutomationRate,默认为"a-rate"-
表示默认自动控制速率。
defaultValue,类型为 float,默认为0-
表示参数的默认值。
maxValue,类型为 float,默认为3.4028235e38-
表示最大值。
minValue,类型为 float,默认为-3.4028235e38-
表示最小值。
name,类型为 DOMString-
表示参数的名称。
1.32.6. AudioWorklet 事件序列
下图展示了与 AudioWorklet 相关联的理想事件序列
AudioWorklet 序列图中描述的步骤是涉及创建 AudioContext 和关联的 AudioWorkletGlobalScope,随后创建 AudioWorkletNode 及其关联的 AudioWorkletProcessor 的一种可能事件序列。
-
创建
AudioContext。 -
在主作用域中,请求
context.audioWorklet添加一个脚本模块。 -
由于尚不存在,因此创建一个新的
AudioWorkletGlobalScope并与该上下文关联。这是将评估AudioWorkletProcessor类定义的全局作用域。(在后续调用中,将使用此先前创建的作用域。) -
导入的脚本在新创建的全局作用域中运行。
-
作为运行导入脚本的一部分,
AudioWorkletProcessor在AudioWorkletGlobalScope内的一个键(在上图中为"custom")下注册。这会填充全局作用域和AudioContext中的映射。 -
addModule()调用的 promise 已解析。 -
在主作用域中,使用用户指定的键以及选项字典创建一个
AudioWorkletNode。 -
作为节点创建的一部分,此键用于查找正确的
AudioWorkletProcessor子类以进行实例化。 -
AudioWorkletProcessor子类的一个实例使用相同选项字典的结构化克隆进行实例化。此实例与先前创建的AudioWorkletNode配对。
1.32.7. AudioWorklet 示例
1.32.7.1. BitCrusher 节点
Bitcrushing 是一种通过量化采样值(模拟较低的位深度)和量化时间分辨率(模拟较低的采样率)来降低音频流质量的机制。此示例展示了如何在 AudioWorkletProcessor 内部使用 AudioParam(在此情况下视为 a-rate)。
const context= new AudioContext(); context. audioWorklet. addModule( 'bitcrusher.js' ). then(() => { const osc= new OscillatorNode( context); const amp= new GainNode( context); // Create a worklet node. 'BitCrusher' identifies the // AudioWorkletProcessor previously registered when // bitcrusher.js was imported. The options automatically // initialize the correspondingly named AudioParams. const bitcrusher= new AudioWorkletNode( context, 'bitcrusher' , { parameterData: { bitDepth: 8 } }); osc. connect( bitcrusher). connect( amp). connect( context. destination); osc. start(); });
class Bitcrusherextends AudioWorkletProcessor{ static get parameterDescriptors() { return [{ name: 'bitDepth' , defaultValue: 12 , minValue: 1 , maxValue: 16 }, { name: 'frequencyReduction' , defaultValue: 0.5 , minValue: 0 , maxValue: 1 }]; } constructor () { super (); this . _phase= 0 ; this . _lastSampleValue= 0 ; } process( inputs, outputs, parameters) { const input= inputs[ 0 ]; const output= outputs[ 0 ]; const bitDepth= parameters. bitDepth; const frequencyReduction= parameters. frequencyReduction; if ( bitDepth. length> 1 ) { for ( let channel= 0 ; channel< output. length; ++ channel) { for ( let i= 0 ; i< output[ channel]. length; ++ i) { let step= Math. pow( 0.5 , bitDepth[ i]); // Use modulo for indexing to handle the case where // the length of the frequencyReduction array is 1. this . _phase+= frequencyReduction[ i% frequencyReduction. length]; if ( this . _phase>= 1.0 ) { this . _phase-= 1.0 ; this . _lastSampleValue= step* Math. floor( input[ channel][ i] / step+ 0.5 ); } output[ channel][ i] = this . _lastSampleValue; } } } else { // Because we know bitDepth is constant for this call, // we can lift the computation of step outside the loop, // saving many operations. const step= Math. pow( 0.5 , bitDepth[ 0 ]); for ( let channel= 0 ; channel< output. length; ++ channel) { for ( let i= 0 ; i< output[ channel]. length; ++ i) { this . _phase+= frequencyReduction[ i% frequencyReduction. length]; if ( this . _phase>= 1.0 ) { this . _phase-= 1.0 ; this . _lastSampleValue= step* Math. floor( input[ channel][ i] / step+ 0.5 ); } output[ channel][ i] = this . _lastSampleValue; } } } // No need to return a value; this node's lifetime is dependent only on its // input connections. } }; registerProcessor( 'bitcrusher' , Bitcrusher);
注:在 AudioWorkletProcessor 类的定义中,如果作者提供的构造函数具有显式的非 this 返回值或未正确调用 super(),则会抛出 InvalidStateError。
1.32.7.2. VU 表节点
这个简单的声音电平表示例进一步说明了如何创建一个像原生 AudioNode 一样工作的 AudioWorkletNode 子类,它接受构造函数选项并封装 AudioWorkletNode 和 AudioWorkletProcessor 之间的跨线程通信(异步)。此节点不使用任何输出。
/* vumeter-node.js: Main global scope */ export default class VUMeterNodeextends AudioWorkletNode{ constructor ( context, updateIntervalInMS) { super ( context, 'vumeter' , { numberOfInputs: 1 , numberOfOutputs: 0 , channelCount: 1 , processorOptions: { updateIntervalInMS: updateIntervalInMS|| 16.67 } }); // States in AudioWorkletNode this . _updateIntervalInMS= updateIntervalInMS; this . _volume= 0 ; // Handles updated values from AudioWorkletProcessor this . port. onmessage= event=> { if ( event. data. volume) this . _volume= event. data. volume; } this . port. start(); } get updateInterval() { return this . _updateIntervalInMS; } set updateInterval( updateIntervalInMS) { this . _updateIntervalInMS= updateIntervalInMS; this . port. postMessage({ updateIntervalInMS: updateIntervalInMS}); } draw() { // Draws the VU meter based on the volume value // every |this._updateIntervalInMS| milliseconds. } };
/* vumeter-processor.js: AudioWorkletGlobalScope */ const SMOOTHING_FACTOR= 0.9 ; const MINIMUM_VALUE= 0.00001 ; registerProcessor( 'vumeter' , class extends AudioWorkletProcessor{ constructor ( options) { super (); this . _volume= 0 ; this . _updateIntervalInMS= options. processorOptions. updateIntervalInMS; this . _nextUpdateFrame= this . _updateIntervalInMS; this . port. onmessage= event=> { if ( event. data. updateIntervalInMS) this . _updateIntervalInMS= event. data. updateIntervalInMS; } } get intervalInFrames() { return this . _updateIntervalInMS/ 1000 * sampleRate; } process( inputs, outputs, parameters) { const input= inputs[ 0 ]; // Note that the input will be down-mixed to mono; however, if no inputs are // connected then zero channels will be passed in. if ( input. length> 0 ) { const samples= input[ 0 ]; let sum= 0 ; let rms= 0 ; // Calculated the squared-sum. for ( let i= 0 ; i< samples. length; ++ i) sum+= samples[ i] * samples[ i]; // Calculate the RMS level and update the volume. rms= Math. sqrt( sum/ samples. length); this . _volume= Math. max( rms, this . _volume* SMOOTHING_FACTOR); // Update and sync the volume property with the main thread. this . _nextUpdateFrame-= samples. length; if ( this . _nextUpdateFrame< 0 ) { this . _nextUpdateFrame+= this . intervalInFrames; this . port. postMessage({ volume: this . _volume}); } } // Keep on processing if the volume is above a threshold, so that // disconnecting inputs does not immediately cause the meter to stop // computing its smoothed value. return this . _volume>= MINIMUM_VALUE; } });
/* index.js: Main global scope, entry point */ import VUMeterNodefrom './vumeter-node.js' ; const context= new AudioContext(); context. audioWorklet. addModule( 'vumeter-processor.js' ). then(() => { const oscillator= new OscillatorNode( context); const vuMeterNode= new VUMeterNode( context, 25 ); oscillator. connect( vuMeterNode); oscillator. start(); function drawMeter() { vuMeterNode. draw(); requestAnimationFrame( drawMeter); } drawMeter(); });
2. 处理模型
2.1. 背景
本节是非规范性的。
需要低延迟的实时音频系统通常使用回调函数实现,当需要计算更多音频以保持播放不间断时,操作系统会回调程序。此类回调理想情况下在优先级较高的线程上调用(通常是系统上的最高优先级)。这意味着处理音频的程序仅执行来自此回调的代码。跨越线程边界或在渲染线程和回调之间添加缓冲,自然会增加延迟或使系统对故障的抵御能力降低。
因此,Web 平台上执行异步操作的传统方式(事件循环)在此处不起作用,因为线程不是持续执行的。此外,传统的执行上下文(Windows 和 Workers)提供了许多不必要且可能阻塞的操作,这对于达到可接受的性能水平来说并不理想。
此外,Worker 模型使得为脚本执行上下文创建一个专用线程成为必要,而所有 AudioNode 通常共享同一个执行上下文。
注:本节规定了最终结果应该是什么样子,而不是应该如何实现。特别是,实现者可以使用线程之间共享的内存来代替使用消息队列,只要内存操作不被重新排序即可。
2.2. 控制线程和渲染线程
Web Audio API 必须使用控制线程和渲染线程来实现。
控制线程是实例化 AudioContext 的线程,也是作者操作音频图(即调用 BaseAudioContext 操作)的线程。渲染线程是根据控制线程的调用来计算实际音频输出的线程。如果为 AudioContext 计算音频,它可以是基于回调的实时音频线程;如果为 OfflineAudioContext 计算音频,则可以是普通线程。
从控制线程到渲染线程的通信是通过控制消息传递完成的。反方向的通信是通过常规事件循环任务完成的。
每个 AudioContext 都有一个单独的控制消息队列,这是一个控制消息列表,这些消息是在渲染线程上运行的操作。
队列化一条控制消息是指将消息添加到 BaseAudioContext 的控制消息队列末尾。
注:例如,成功在 AudioBufferSourceNode source 上调用 start(),会将一条控制消息添加到关联的 BaseAudioContext 的控制消息队列中。
控制消息在控制消息队列中按插入时间排序。因此,最早的消息就是位于控制消息队列前端的消息。
2.3. 异步操作
在 AudioNode 上调用方法实际上是异步的,且必须分两个阶段完成:同步部分和异步部分。对于每个方法,执行的一部分发生在控制线程上(例如,在参数无效时抛出异常),而另一部分发生在渲染线程上(例如,改变 AudioParam 的值)。
在 AudioNode 和 BaseAudioContext 的每项操作描述中,同步部分用 ⌛ 标记。所有其他操作均按照 [HTML] 中的描述并行执行。
同步部分在控制线程上执行,并立即发生。如果失败,方法执行会终止,并可能抛出异常。如果成功,一个编码了要在渲染线程上执行的操作的控制消息会被放入该渲染线程的控制消息队列中。
同步和异步部分相对于其他事件的顺序必须保持一致:给定两个操作 A 和 B,其各自的同步和异步部分分别为 ASync 和 AAsync,以及 BSync 和 BAsync,如果 A 发生在 B 之前,则 ASync 必须发生在 BSync 之前,且 AAsync 必须发生在 BAsync 之前。换句话说,同步部分和异步部分不能重排序。
2.4. 渲染音频图
音频图渲染以采样帧块(sample-frames)为单位进行,每个块的大小在 BaseAudioContext 的生命周期内保持不变。一个块中的采样帧数称为渲染量子大小(render quantum size),块本身称为渲染量子(render quantum)。其默认值为 128,可以通过设置 renderSizeHint 进行配置。
在给定线程上原子地发生的操作,只能在其他线程上没有其他原子操作运行时执行。
从 BaseAudioContext G(带有控制消息队列 Q)渲染音频块的算法由多个步骤组成,详细说明请参阅渲染图算法。
AudioContext 渲染线程由系统级音频回调驱动,该回调定期以固定的时间间隔触发。每次调用都有一个系统级音频回调缓冲区大小,这是一个可变的采样帧数,需要在下一个系统级音频回调到达之前计算完成。
为每个系统级音频回调计算一个负载值(load value),计算方法是将执行持续时间除以(系统级音频回调缓冲区大小除以 sampleRate)。
理想情况下,负载值低于 1.0,这意味着渲染音频所花费的时间少于播放它所需的时间。当负载值大于 1.0 时,会发生音频缓冲区欠载(audio buffer underrun):系统无法以足够快的速度渲染音频以实现实时播放。
请注意,系统级音频回调和负载值的概念不适用于 OfflineAudioContext。
音频回调也被作为一项任务放入控制消息队列中。UA 必须执行以下算法来处理渲染量子,通过填充请求的缓冲区大小来完成此任务。除了控制消息队列外,每个 AudioContext 都有一个常规的任务队列,称为其关联任务队列,用于处理从控制线程发送到渲染线程的任务。在处理完渲染量子后,会执行额外的微任务检查点,以运行在 AudioWorkletProcessor 的 process 方法执行期间可能已排入队列的任何微任务。
所有从 AudioWorkletNode 发送的任务都会被放入其关联 BaseAudioContext 的关联任务队列中。
-
将
BaseAudioContext的内部槽位[[current frame]]设置为 0。同时将currentTime设置为 0。
-
令 render result 为
false。 -
处理控制消息队列。
-
处理
BaseAudioContext的关联任务队列。-
令 task queue 为
BaseAudioContext的关联任务队列。 -
令 task count 为 task queue 中的任务数量
-
当 task count 不等于 0 时,执行以下步骤
-
令 oldest task 为 task queue 中的第一个可运行任务,并将其从 task queue 中移除。
-
将渲染循环当前运行的任务设置为 oldest task。
-
执行 oldest task 的步骤。
-
将渲染循环当前运行的任务设置回
null。 -
递减 task count
-
执行微任务检查点。
-
-
-
处理一个渲染量子。
-
如果
BaseAudioContext的[[rendering thread state]]不是running,则返回 false。 -
对要处理的
AudioNode进行排序。-
令 ordered node list 为一个空的
AudioNode和AudioListener列表。当此排序算法终止时,它将包含AudioNode和AudioListener的有序列表。 -
令 nodes 为此
BaseAudioContext创建且仍然存活的所有节点的集合。 -
将
AudioListener添加到 nodes 中。 -
对于 nodes 中的每个
AudioNodenode-
如果 node 是一个属于循环的
DelayNode,将其添加到 cycle breakers 并从 nodes 中移除。
-
-
对于 cycle breakers 中的每个
DelayNodedelay-
令 delayWriter 和 delayReader 分别为 delay 的 DelayWriter 和 DelayReader。将 delayWriter 和 delayReader 添加到 nodes。断开 delay 与其所有输入和输出的连接。
注:这打破了循环:如果一个
DelayNode处于循环中,它的两端可以分开考虑,因为在循环中延迟线不能小于一个渲染量子。
-
-
认为 nodes 中的所有元素均为未标记。当 nodes 中存在未标记元素时
-
在 nodes 中选择一个元素 node。
-
访问 node。
-
-
反转 ordered node list 的顺序。
-
-
计算此块中
AudioListener的AudioParam的值。 -
对于 ordered node list 中的每个
AudioNode-
对于此
AudioNode的每个AudioParam,执行以下步骤-
如果此
AudioParam连接有任何AudioNode,汇总所有连接到此AudioParam的AudioNode可供读取的缓冲区,将结果缓冲区下混(down mix)为单声道,并将此缓冲区称为输入 AudioParam 缓冲区。 -
计算此块中此
AudioParam的值。 -
将控制消息加入队列,根据 § 1.6.3 数值计算设置此
AudioParam的[[current value]]槽位。
-
-
如果此
AudioNode的输入连接有任何AudioNode,汇总所有连接到此AudioNode的AudioNode可供读取的缓冲区。结果缓冲区称为输入缓冲区。上混或下混(Up or down-mix)它以匹配此AudioNode的输入通道数。 -
如果此
AudioNode是一个AudioWorkletNode,执行这些子步骤-
令 processor 为
AudioWorkletNode的关联AudioWorkletProcessor实例。 -
令 O 为对应于 processor 的 ECMAScript 对象。
-
令 processCallback 为一个未初始化的变量。
-
令 completion 为一个未初始化的变量。
-
令 getResult 为 Get(O, "process")。
-
如果 getResult 是一个突然完成(abrupt completion),将 completion 设置为 getResult 并跳转到标记为 return 的步骤。
-
将 processCallback 设置为 getResult.[[Value]]。
-
如果 ! IsCallable(processCallback) 为
false,则-
将 completion 设置为新的 Completion {[[Type]]: throw, [[Value]]: 一个新创建的 TypeError 对象, [[Target]]: empty}。
-
跳转到标记为 return 的步骤。
-
-
将
[[callable process]]设置为true。 -
执行以下子步骤
-
令 args 为一个 Web IDL 参数列表,由
inputs、outputs和parameters组成。 -
令 esArgs 为将 args 转换为 ECMAScript 参数列表的结果。
-
令 callResult 为 Call(processCallback, O, esArgs)。此操作计算带有 esArgs 的音频块。函数调用成功后,包含通过
outputs传递的Float32Array元素副本的缓冲区被使其可供读取。在此调用中解决的任何Promise都将排入AudioWorkletGlobalScope的微任务队列。 -
如果 callResult 是一个突然完成,将 completion 设置为 callResult 并跳转到标记为 return 的步骤。
-
-
返回:此时 completion 将被设置为一个 ECMAScript 完成值。
-
如果 completion 是一个突然完成
-
将
[[callable process]]设置为false。 -
将 processor 的活动源标志设置为
false。 -
将任务放入队列到控制线程,以使用
ErrorEvent在关联的AudioWorkletNode上触发一个事件,名称为processorerror。
-
-
-
-
原子地执行以下步骤
-
将
[[current frame]]增加渲染量子大小。 -
将
currentTime设置为[[current frame]]除以sampleRate。
-
-
将 render result 设置为
true。
-
-
返回 render result。
静音一个 AudioNode 意味着其输出在渲染此音频块时必须为静音。
使缓冲区可供读取是指将缓冲区置于一种状态,使得其他连接到此 AudioNode 的 AudioNode 可以安全地从中读取数据。
注:例如,实现可以选择分配一个新缓冲区,或者使用更复杂的机制,重用当前未使用的现有缓冲区。
记录输入是指复制此 AudioNode 的输入数据以供将来使用。
计算音频块是指运行此 AudioNode 的算法以产生 [[render quantum size]] 个采样帧。
处理输入缓冲区是指运行 AudioNode 的算法,使用输入缓冲区和此 AudioNode 的 AudioParam 的值作为算法的输入。
2.5. 在 AudioContext 上处理系统音频资源错误
AudioContext audioContext 在发生系统音频资源错误时,在渲染线程上执行以下步骤。
-
如果 audioContext 的
[[rendering thread state]]为running-
尝试释放系统资源。
-
将 audioContext 的
[[rendering thread state]]设置为suspended。 -
将媒体元素任务放入队列以执行以下步骤
-
将 audioContext 的
[[suspended by user]]设置为false。 -
将 audioContext 的
[[control thread state]]设置为suspended。 -
在 audioContext 上触发一个事件,名称为
statechange。
-
中止这些步骤。
-
-
如果 audioContext 的
[[rendering thread state]]为suspended-
将媒体元素任务放入队列以执行以下步骤
-
注:系统音频资源错误的一个例子是外部或无线音频设备在 AudioContext 活动渲染期间断开连接。
2.6. 卸载文档
对于使用BaseAudioContext 的文档,定义了额外的卸载文档清理步骤-
对于相关全局对象与文档关联 Window 相同的每个
AudioContext和OfflineAudioContext,以InvalidStateError拒绝其[[pending promises]]中的所有 Promise。 -
停止所有
decoding thread。
3. 动态生命周期
3.1. 背景
注:AudioContext 和 AudioNode 生命周期特征的规范描述由 AudioContext 生命周期和 AudioNode 生命周期描述。
本节是非规范性的。
除了允许创建静态路由配置外,还应该能够对具有有限生命周期的动态分配的语音进行自定义效果路由。为了讨论的目的,我们称这些短生命周期的语音为“音符(notes)”。许多音频应用程序结合了音符的概念,例如鼓机、音序器以及根据游戏玩法触发许多一次性声音的 3D 游戏。
在传统的软件合成器中,音符是从可用资源池中动态分配和释放的。当接收到 MIDI 音符开启消息时,音符被分配。当音符播放结束时,它会被释放,这可能是因为它已经达到了采样数据的结尾(如果是非循环的)、它已经达到了包络线的持续阶段(为零),或者由于 MIDI 音符关闭消息使其进入了包络线的释放阶段。在 MIDI 音符关闭的情况下,音符不会立即释放,只有在释放包络线阶段完成后才会释放。在任何给定时间,可能有大量的音符在播放,但音符集会不断变化,因为新的音符被添加到路由图中,而旧的音符被释放。
音频系统会自动处理单个“音符”事件的路由图部分的拆除。“音符”由 AudioBufferSourceNode 表示,它可以直接连接到其他处理节点。当音符播放完成时,上下文会自动释放对 AudioBufferSourceNode 的引用,这反过来会释放对它连接的任何节点的引用,以此类推。这些节点将自动从图中断开,并在没有引用时被删除。图中长生命周期且在动态语音之间共享的节点可以明确管理。虽然听起来很复杂,但这都是自动发生的,不需要额外的处理。
3.2. 示例
低通滤波器、声相器和第二个增益节点直接从一次性声音连接。因此,当它播放完成时,上下文将自动释放它们(虚线内的所有内容)。如果不存任何对一次性声音和已连接节点的引用,它们将立即从图中删除并销毁。流源具有全局引用,并将保持连接,直到被明确断开。这是它在 JavaScript 中的样子
let context= 0 ; let compressor= 0 ; let gainNode1= 0 ; let streamingAudioSource= 0 ; // Initial setup of the "long-lived" part of the routing graph function setupAudioContext() { context= new AudioContext(); compressor= context. createDynamicsCompressor(); gainNode1= context. createGain(); // Create a streaming audio source. const audioElement= document. getElementById( 'audioTagID' ); streamingAudioSource= context. createMediaElementSource( audioElement); streamingAudioSource. connect( gainNode1); gainNode1. connect( compressor); compressor. connect( context. destination); } // Later in response to some user action (typically mouse or key event) // a one-shot sound can be played. function playSound() { const oneShotSound= context. createBufferSource(); oneShotSound. buffer= dogBarkingBuffer; // Create a filter, panner, and gain node. const lowpass= context. createBiquadFilter(); const panner= context. createPanner(); const gainNode2= context. createGain(); // Make connections oneShotSound. connect( lowpass); lowpass. connect( panner); panner. connect( gainNode2); gainNode2. connect( compressor); // Play 0.75 seconds from now (to play immediately pass in 0) oneShotSound. start( context. currentTime+ 0.75 ); }
4. 通道上混和下混
本节是规范性的。
AudioNode 输入具有混合规则,用于组合来自所有连接的通道。作为一个简单的例子,如果输入连接了单声道输出和立体声输出,那么单声道连接通常会被上混为立体声并与立体声连接求和。但是,当然,定义每个 AudioNode 的每个输入的精确混合规则非常重要。所有输入的默认混合规则都是为了使内容“直接工作”而无需过多考虑细节,特别是在单声道和立体声流非常常见的情况下。当然,规则可以针对高级用例进行更改,特别是多通道用例。
为了定义一些术语,上混(up-mixing) 是指将通道数较少的流转换为通道数较大的流的过程。下混(down-mixing) 是指将通道数较大的流转换为通道数较小的流的过程。
AudioNode 输入需要混合连接到此输入的所有输出。作为此过程的一部分,它计算一个内部值 computedNumberOfChannels,代表输入在任何给定时间的实际通道数。
AudioNode 的每个输入,实现必须-
对于每个输入连接
-
根据节点
channelInterpretation属性给出的ChannelInterpretation值,将连接上混或下混到 computedNumberOfChannels。
-
4.1. 扬声器通道布局
当 channelInterpretation 为 "speakers" 时,上混和下混是为特定通道布局定义的。
必须支持单声道(一个通道)、立体声(两个通道)、四声道(四个通道)和 5.1(六个通道)。其他通道布局可能在未来的本规范版本中得到支持。
4.2. 通道排序
通道排序由下表定义。个别多通道格式可能不支持所有中间通道。实现必须按照定义的顺序呈现通道,跳过那些不存在的通道。
| 顺序 | Label | 单声道 | 立体声 | 四声道 | 5.1 |
|---|---|---|---|---|---|
| 0 | SPEAKER_FRONT_LEFT | 0 | 0 | 0 | 0 |
| 1 | SPEAKER_FRONT_RIGHT | 1 | 1 | 1 | |
| 2 | SPEAKER_FRONT_CENTER | 2 | |||
| 3 | SPEAKER_LOW_FREQUENCY | 3 | |||
| 4 | SPEAKER_BACK_LEFT | 2 | 4 | ||
| 5 | SPEAKER_BACK_RIGHT | 3 | 5 | ||
| 6 | SPEAKER_FRONT_LEFT_OF_CENTER | ||||
| 7 | SPEAKER_FRONT_RIGHT_OF_CENTER | ||||
| 8 | SPEAKER_BACK_CENTER | ||||
| 9 | SPEAKER_SIDE_LEFT | ||||
| 10 | SPEAKER_SIDE_RIGHT | ||||
| 11 | SPEAKER_TOP_CENTER | ||||
| 12 | SPEAKER_TOP_FRONT_LEFT | ||||
| 13 | SPEAKER_TOP_FRONT_CENTER | ||||
| 14 | SPEAKER_TOP_FRONT_RIGHT | ||||
| 15 | SPEAKER_TOP_BACK_LEFT | ||||
| 16 | SPEAKER_TOP_BACK_CENTER | ||||
| 17 | SPEAKER_TOP_BACK_RIGHT |
4.3. 尾部时间对输入和输出通道计数的影响
当 AudioNode 具有非零 尾部时间(tail-time),且输出通道计数取决于输入通道计数时,在输入通道计数发生变化时,必须考虑 AudioNode 的 尾部时间。
当输入通道计数减少时,输出通道计数的更改必须在以更大通道计数接收的输入不再影响输出时发生。
当输入通道计数增加时,行为取决于 AudioNode 类型
-
对于
DelayNode或DynamicsCompressorNode,当以更大通道计数接收的输入开始影响输出时,输出通道数必须增加。 -
对于具有 尾部时间 的其他
AudioNode,输出通道数必须立即增加。注:对于
ConvolverNode,这仅适用于脉冲响应为单声道的情况。否则,无论其输入通道计数如何,ConvolverNode始终输出立体声信号。
注:直观地说,这允许在处理过程中不丢失立体声信息:当多个不同通道计数的输入渲染量子对输出渲染量子做出贡献时,输出渲染量子的通道计数是输入渲染量子输入通道计数的超集。
4.4. 上混扬声器布局
Mono up-mix:
1 -> 2 : up-mix from mono to stereo
output.L = input;
output.R = input;
1 -> 4 : up-mix from mono to quad
output.L = input;
output.R = input;
output.SL = 0;
output.SR = 0;
1 -> 5.1 : up-mix from mono to 5.1
output.L = 0;
output.R = 0;
output.C = input; // put in center channel
output.LFE = 0;
output.SL = 0;
output.SR = 0;
Stereo up-mix:
2 -> 4 : up-mix from stereo to quad
output.L = input.L;
output.R = input.R;
output.SL = 0;
output.SR = 0;
2 -> 5.1 : up-mix from stereo to 5.1
output.L = input.L;
output.R = input.R;
output.C = 0;
output.LFE = 0;
output.SL = 0;
output.SR = 0;
Quad up-mix:
4 -> 5.1 : up-mix from quad to 5.1
output.L = input.L;
output.R = input.R;
output.C = 0;
output.LFE = 0;
output.SL = input.SL;
output.SR = input.SR;
4.5. 下混扬声器布局
例如,如果正在处理 5.1 源材料,但播放为立体声,则需要进行下混。
Mono down-mix:
2 -> 1 : stereo to mono
output = 0.5 * (input.L + input.R);
4 -> 1 : quad to mono
output = 0.25 * (input.L + input.R + input.SL + input.SR);
5.1 -> 1 : 5.1 to mono
output = sqrt(0.5) * (input.L + input.R) + input.C + 0.5 * (input.SL + input.SR)
Stereo down-mix:
4 -> 2 : quad to stereo
output.L = 0.5 * (input.L + input.SL);
output.R = 0.5 * (input.R + input.SR);
5.1 -> 2 : 5.1 to stereo
output.L = L + sqrt(0.5) * (input.C + input.SL)
output.R = R + sqrt(0.5) * (input.C + input.SR)
Quad down-mix:
5.1 -> 4 : 5.1 to quad
output.L = L + sqrt(0.5) * input.C
output.R = R + sqrt(0.5) * input.C
output.SL = input.SL
output.SR = input.SR
4.6. 通道规则示例
// Set gain node to explicit 2-channels (stereo). gain. channelCount= 2 ; gain. channelCountMode= "explicit" ; gain. channelInterpretation= "speakers" ; // Set "hardware output" to 4-channels for DJ-app with two stereo output busses. context. destination. channelCount= 4 ; context. destination. channelCountMode= "explicit" ; context. destination. channelInterpretation= "discrete" ; // Set "hardware output" to 8-channels for custom multi-channel speaker array // with custom matrix mixing. context. destination. channelCount= 8 ; context. destination. channelCountMode= "explicit" ; context. destination. channelInterpretation= "discrete" ; // Set "hardware output" to 5.1 to play an HTMLAudioElement. context. destination. channelCount= 6 ; context. destination. channelCountMode= "explicit" ; context. destination. channelInterpretation= "speakers" ; // Explicitly down-mix to mono. gain. channelCount= 1 ; gain. channelCountMode= "explicit" ; gain. channelInterpretation= "speakers" ;
5. 音频信号值
5.1. 音频采样格式
线性脉冲编码调制(线性 PCM)描述了一种格式,其中音频值以规则的时间间隔采样,并且两个连续值之间的量化级别是线性均匀的。
每当在本规范中向脚本公开信号值时,它们都是线性 32 位浮点脉冲编码调制格式(线性 32 位浮点 PCM),通常以 Float32Array 对象的形式。
5.2. 渲染
任何音频图目标节点处所有音频信号的范围名义上为 [-1, 1]。此范围之外的信号值的音频再现,或值 NaN、正无穷大或负无穷大的音频再现,在本规范中是未定义的。
6. 空间化/声相定位
6.1. 背景
现代 3D 游戏的一个常见特性需求是能够动态地对 3D 空间中的多个音频源进行空间化和移动。例如 OpenAL 就具备这种能力。
使用 PannerNode,音频流可以相对于 AudioListener 进行空间化或定位。BaseAudioContext 将包含单个 AudioListener。声相器和监听器在 3D 空间中都有位置,使用右手笛卡尔坐标系。坐标系中使用的单位未定义,也不需要定义,因为使用这些坐标计算的效果独立于或不变量于任何特定单位(如米或英尺)。PannerNode 对象(代表源流)有一个方向向量,表示声音投影的方向。此外,它们有一个声音锥体,表示声音的方向性。例如,声音可以是全向的,在这种情况下,无论其方向如何,都可以在任何地方听到,或者它可以更具方向性,仅当面向监听器时才能听到。AudioListener 对象(代表人的耳朵)具有前向和上向向量,表示人面对的方向。
空间化的坐标系如下图所示,显示了默认值。AudioListener 和 PannerNode 的位置已从默认位置移动,以便我们可以更清楚地看到。
在渲染期间,PannerNode 计算方位角和仰角。这些值由实现内部使用,以便渲染空间化效果。有关这些值如何使用的详细信息,请参阅声相定位算法部分。
6.2. 方位角和仰角
必须使用以下算法来计算 PannerNode 的方位角和仰角。实现必须适当地考虑下方的各个 AudioParam 是 "a-rate" 还是 "k-rate"。
// Let |context| be a BaseAudioContext and let |panner| be a // PannerNode created in |context|. // Calculate the source-listener vector. const listener= context. listener; const sourcePosition= new Vec3( panner. positionX. value, panner. positionY. value, panner. positionZ. value); const listenerPosition= new Vec3( listener. positionX. value, listener. positionY. value, listener. positionZ. value); const sourceListener= sourcePosition. diff( listenerPosition). normalize(); if ( sourceListener. magnitude== 0 ) { // Handle degenerate case if source and listener are at the same point. azimuth= 0 ; elevation= 0 ; return ; } // Align axes. const listenerForward= new Vec3( listener. forwardX. value, listener. forwardY. value, listener. forwardZ. value); const listenerUp= new Vec3( listener. upX. value, listener. upY. value, listener. upZ. value); const listenerRight= listenerForward. cross( listenerUp); if ( listenerRight. magnitude== 0 ) { // Handle the case where listener's 'up' and 'forward' vectors are linearly // dependent, in which case 'right' cannot be determined azimuth= 0 ; elevation= 0 ; return ; } // Determine a unit vector orthogonal to listener's right, forward const listenerRightNorm= listenerRight. normalize(); const listenerForwardNorm= listenerForward. normalize(); const up= listenerRightNorm. cross( listenerForwardNorm); const upProjection= sourceListener. dot( up); const projectedSource= sourceListener. diff( up. scale( upProjection)). normalize(); azimuth= 180 * Math. acos( projectedSource. dot( listenerRightNorm)) / Math. PI; // Source in front or behind the listener. const frontBack= projectedSource. dot( listenerForwardNorm); if ( frontBack< 0 ) azimuth= 360 - azimuth; // Make azimuth relative to "forward" and not "right" listener vector. if (( azimuth>= 0 ) && ( azimuth<= 270 )) azimuth= 90 - azimuth; else azimuth= 450 - azimuth; elevation= 90 - 180 * Math. acos( sourceListener. dot( up)) / Math. PI; if ( elevation> 90 ) elevation= 180 - elevation; else if ( elevation< - 90 ) elevation= - 180 - elevation;
6.3. 声相定位算法
必须支持单声道转立体声和立体声转立体声声相定位。当输入的所有连接都是单声道时,使用单声道转立体声处理。否则,使用立体声转立体声处理。
6.3.1. PannerNode "equalpower" 声相定位
这是一种简单且相对便宜的算法,它提供了基本但合理的结果。当 panningModel 属性设置为 "equalpower" 时,它用于 PannerNode,此时仰角值被忽略。此算法必须使用 automationRate 指定的适当速率来实现。如果 PannerNode 的任何 AudioParam 或 AudioListener 的 AudioParam 是 "a-rate",则必须使用 a-rate 处理。
-
对于此
AudioNode要计算的每个采样-
令 azimuth 为在方位角和仰角部分计算的值。
-
azimuth 值首先被限制在范围 [-90, 90] 内,根据
// First, clamp azimuth to allowed range of [-180, 180]. azimuth= max( - 180 , azimuth); azimuth= min( 180 , azimuth); // Then wrap to range [-90, 90]. if ( azimuth< - 90 ) azimuth= - 180 - azimuth; else if ( azimuth> 90 ) azimuth= 180 - azimuth; -
归一化值 x 从 azimuth 计算得到,对于单声道输入为
x
= ( azimuth+ 90 ) / 180 ; 或者对于立体声输入为
if ( azimuth<= 0 ) { // -90 -> 0 // Transform the azimuth value from [-90, 0] degrees into the range [-90, 90]. x= ( azimuth+ 90 ) / 90 ; } else { // 0 -> 90 // Transform the azimuth value from [0, 90] degrees into the range [-90, 90]. x= azimuth/ 90 ; } -
左右增益值计算为
gainL
= cos( x* Math. PI/ 2 ); gainR= sin( x* Math. PI/ 2 ); -
对于单声道输入,立体声输出计算为
outputL
= input* gainL; outputR= input* gainR; 否则对于立体声输入,输出计算为
if ( azimuth<= 0 ) { outputL= inputL+ inputR* gainL; outputR= inputR* gainR; } else { outputL= inputL* gainL; outputR= inputR+ inputL* gainR; } -
应用距离增益和锥体增益,其中距离计算在 距离效果 中描述,锥体增益在 声音锥体 中描述
let distance= distance(); let distanceGain= distanceModel( distance); let totalGain= coneGain() * distanceGain(); outputL= totalGain* outputL; outputR= totalGain* outputR;
-
6.3.2. PannerNode "HRTF" 声相定位(仅限立体声)
这需要一套在各种方位角和仰角下记录的 HRTF(头相关传递函数)脉冲响应。实现需要一个高度优化的卷积函数。它比 "equalpower" 成本稍高,但提供了感知上更空间化的声音。
6.3.3. StereoPannerNode 声相定位
StereoPannerNode,必须实现以下算法。-
对于此
AudioNode要计算的每个采样-
令 pan 为此
StereoPannerNode的panAudioParam的 计算值。 -
将 pan 钳位到 [-1, 1]。
pan
= max( - 1 , pan); pan= min( 1 , pan); -
通过将 pan 值归一化到 [0, 1] 来计算 x。对于单声道输入
x
= ( pan+ 1 ) / 2 ; 对于立体声输入
if ( pan<= 0 ) x= pan+ 1 ; else x= pan; -
左右增益值计算为
gainL
= cos( x* Math. PI/ 2 ); gainR= sin( x* Math. PI/ 2 ); -
对于单声道输入,立体声输出计算为
outputL
= input* gainL; outputR= input* gainR; 否则对于立体声输入,输出计算为
if ( pan<= 0 ) { outputL= inputL+ inputR* gainL; outputR= inputR* gainR; } else { outputL= inputL* gainL; outputR= inputR+ inputL* gainR; }
-
6.4. 距离效果
较近的声音声音较大,而较远的声音声音较小。声音的音量随与监听器距离的变化而如何变化,取决于 distanceModel 属性。
在音频渲染期间,将基于声相器和监听器位置计算距离值,根据
function distance( panner) { const pannerPosition= new Vec3( panner. positionX. value, panner. positionY. value, panner. positionZ. value); const listener= context. listener; const listenerPosition= new Vec3( listener. positionX. value, listener. positionY. value, listener. positionZ. value); return pannerPosition. diff( listenerPosition). magnitude; }
距离随后将用于计算 distanceGain,这取决于 distanceModel 属性。有关如何为每个距离模型计算此值的详细信息,请参阅 DistanceModelType 部分。
作为其处理的一部分,PannerNode 将输入音频信号乘以 distanceGain,以使远处的声音更安静,近处的声音更大。
6.5. 声音锥体
监听器和每个声源都有一个方向向量,描述它们面对的方向。每个声源的声音投影特性由内部和外部“锥体”描述,描述声音强度作为声源/监听器相对于声源方向向量的角度的函数。因此,指向监听器的声源将比偏轴指向的声音更大。声源也可以是全向的。
下图说明了声源锥体与监听器的关系。在图中, 且 coneInnerAngle = 50。也就是说,内部锥体在方向向量的每一侧延伸 25 度。类似地,外部锥体在每一侧为 60 度。coneOuterAngle = 120
在给定声源(PannerNode)和监听器的情况下,必须使用以下算法来计算由于锥体效果产生的增益贡献
function coneGain() { const sourceOrientation= new Vec3( source. orientationX, source. orientationY, source. orientationZ); if ( sourceOrientation. magnitude== 0 || (( source. coneInnerAngle== 360 ) && ( source. coneOuterAngle== 360 ))) return 1 ; // no cone specified - unity gain // Normalized source-listener vector const sourcePosition= new Vec3( panner. positionX. value, panner. positionY. value, panner. positionZ. value); const listenerPosition= new Vec3( listener. positionX. value, listener. positionY. value, listener. positionZ. value); const sourceToListener= sourcePosition. diff( listenerPosition). normalize(); const normalizedSourceOrientation= sourceOrientation. normalize(); // Angle between the source orientation vector and the source-listener vector const angle= 180 * Math. acos( sourceToListener. dot( normalizedSourceOrientation)) / Math. PI; const absAngle= Math. abs( angle); // Divide by 2 here since API is entire angle (not half-angle) const absInnerAngle= Math. abs( source. coneInnerAngle) / 2 ; const absOuterAngle= Math. abs( source. coneOuterAngle) / 2 ; let gain= 1 ; if ( absAngle<= absInnerAngle) { // No attenuation gain= 1 ; } else if ( absAngle>= absOuterAngle) { // Max attenuation gain= source. coneOuterGain; } else { // Between inner and outer cones // inner -> outer, x goes from 0 -> 1 const x= ( absAngle- absInnerAngle) / ( absOuterAngle- absInnerAngle); gain= ( 1 - x) + source. coneOuterGain* x; } return gain; }
7. 性能注意事项
7.1. 延迟
对于 Web 应用程序,鼠标和键盘事件(keydown、mousedown 等)与听到声音之间的时间延迟非常重要。
这种时间延迟称为延迟,并由多种因素引起(输入设备延迟、内部缓冲延迟、DSP 处理延迟、输出设备延迟、用户耳朵与扬声器的距离等),并且是累积的。延迟越大,用户的体验就越不令人满意。在极端情况下,这会使音乐制作或游戏无法进行。在适度水平下,它会影响时机,并给人一种声音滞后或游戏无响应的印象。对于音乐应用程序,时机问题会影响节奏。对于游戏,时机问题会影响游戏玩法的精度。对于交互式应用程序,它通常以与非常低的动画帧率相同的方式降低用户体验。根据应用程序的不同,合理的延迟可以从低至 3-6 毫秒到 25-50 毫秒不等。
实现通常会寻求最小化整体延迟。
除了最小化整体延迟外,实现通常还会寻求最小化 AudioContext 的 currentTime 与 AudioProcessingEvent 的 playbackTime 之间的差异。随着 ScriptProcessorNode 的弃用,这一考虑将随时间变得不再那么重要。
此外,一些 AudioNode 可以在音频图的某些路径中增加延迟,特别是
-
AudioWorkletNode可以运行内部缓冲的脚本,从而增加信号路径的延迟。 -
DelayNode,其作用是增加受控的延迟时间。 -
BiquadFilterNode和IIRFilterNode滤波器设计可能会延迟传入的采样,这是因果滤波过程的自然结果。 -
ConvolverNode取决于脉冲响应,可能会延迟传入的采样,这是卷积操作的自然结果。 -
DynamicsCompressorNode具有一种前瞻算法,会导致信号路径中的延迟。 -
MediaStreamAudioSourceNode、MediaStreamTrackAudioSourceNode和MediaStreamAudioDestinationNode,根据实现,可能会在内部增加缓冲区,从而增加延迟。 -
ScriptProcessorNode在控制线程和渲染线程之间可能有缓冲区。 -
WaveShaperNode,在过采样时,根据过采样技术,会增加信号路径的延迟。
7.2. 音频缓冲区复制
当对 AudioBuffer 执行获取内容操作时,整个操作通常可以在不复制通道数据的情况下实现。特别是,最后一步应该在下一次 getChannelData() 调用时惰性执行。这意味着一系列连续的获取内容操作,且中间没有 getChannelData()(例如,多个播放相同 AudioBuffer 的 AudioBufferSourceNode),可以在没有任何分配或复制的情况下实现。
实现可以执行额外的优化:如果在 AudioBuffer 上调用了 getChannelData(),新的 ArrayBuffer 尚未分配,但对 AudioBuffer 上先前获取内容操作的所有调用者都已经停止使用 AudioBuffer 的数据,原始数据缓冲区可以被循环利用以用于新的 AudioBuffer,从而避免任何通道数据的重新分配或复制。
7.3. AudioParam 转换
虽然直接设置 AudioParam 的 value 属性时不会进行自动平滑处理,但对于某些参数,平滑转换优于直接设置值。
使用 setTargetAtTime() 方法并配合较小的 timeConstant,允许作者实现平滑的过渡。
7.4. 音频故障(Audio Glitching)
音频故障是由连续音频流的正常中断引起的,会导致响亮的咔嗒声和爆音。这被认为是多媒体系统的灾难性故障,必须避免。它可能是由于负责将音频流传送到硬件的线程出现问题所致,例如由于线程缺乏适当的优先级和时间约束而导致的调度延迟。它也可能是由音频 DSP 尝试执行的工作超出了 CPU 速度在实时环境下所能处理的限度所引起。
8. 安全与隐私考量
-
本规范是否处理个人身份信息?
使用 Web Audio API 执行听力测试是可能的,从而揭示一个人可听到的频率范围(这会随年龄增长而降低)。很难想象如何在用户不知情且未经同意的情况下做到这一点,因为它需要用户的积极参与。
-
本规范是否处理高价值数据?
否。Web Audio 中不使用信用卡信息等类似信息。虽然可以使用 Web Audio 处理或分析语音数据,这可能涉及隐私问题,但对用户麦克风的访问是通过
getUserMedia()基于权限的。 -
本规范是否为跨浏览会话持久化的源引入了新状态?
否。AudioWorklet 不会在浏览会话间持久化。
-
本规范是否向 Web 暴露了持久的、跨源的状态?
是,支持的音频采样率和输出设备通道数是公开的。请参阅
AudioContext。 -
本规范是否向一个源暴露了它目前无法访问的其他数据?
是。在提供有关可用
AudioNode的各种信息时,Web Audio API 可能会向任何使用AudioNode接口的页面暴露有关客户端特征(例如音频硬件采样率)的信息。此外,可以通过AnalyserNode或ScriptProcessorNode接口收集计时信息。这些信息随后可用于创建客户端的指纹。普林斯顿 CITP 的 Web 透明度和问责项目 的研究表明,
DynamicsCompressorNode和OscillatorNode可用于从客户端收集熵以对设备进行指纹识别。这是由于不同实现之间在 DSP 架构、重采样策略和舍入权衡方面存在微小且通常无法察觉的差异。使用的精确编译器标志以及 CPU 架构(ARM 与 x86)也对此熵有贡献。然而在实践中,这仅仅允许推导出可以通过更简单方式(User Agent 字符串)轻松获取的信息,例如“这是在平台 Y 上运行的浏览器 X”。但是,为了减少额外指纹识别的可能性,我们要求浏览器采取行动,减轻可能由任何节点输出产生的指纹识别问题。
通过时钟偏差进行的指纹识别 已被 Steven J Murdoch 和 Sebastian Zander 描述过。可能可以通过
getOutputTimestamp确定这一点。基于偏差的指纹识别也已由 Nakibly 等人针对 HTML 展示过。应查阅 高精度时间 § 10. 隐私考量 部分,以获取有关时钟分辨率和漂移的更多信息。通过延迟进行指纹识别也是可能的;可能可以通过
baseLatency和outputLatency推断出来。缓解策略包括添加抖动(dithering)和量化,使得精确的偏差被错误报告。但请注意,大多数音频系统旨在实现 低延迟,以将 WebAudio 生成的音频与其他音频或视频源或视觉提示同步(例如在游戏、音频录制或音乐制作环境中)。过高的延迟会降低可用性,并可能成为一个可访问性问题。通过
AudioContext的采样率进行指纹识别也是可能的。我们建议采取以下步骤将其最小化-
44.1 kHz 和 48 kHz 被允许作为默认速率;系统将在两者之间选择以获得最佳适用性。(显然,如果音频设备原生为 44.1,则会选择 44.1,以此类推,但系统也可能选择最“兼容”的速率——例如,如果系统原生为 96kHz,则可能会选择 48kHz 而不是 44.1kHz。)
-
对于原生处于不同速率的设备,系统应重采样到这两个速率之一,尽管由于重采样音频,这可能会导致额外的电池消耗。(同样,系统将选择最兼容的速率——例如,如果原生系统为 16kHz,预计会选择 48kHz。)
-
预计(尽管不是强制性的)浏览器将提供用户界面供用户强制使用原生速率——例如通过在设备上的浏览器中设置标志。此设置不会在 API 中暴露。
-
期望的行为是可以在
AudioContext的构造函数中明确请求不同的速率(这已经在规范中;它通常会导致音频渲染以请求的 sampleRate 完成,然后向上或向下采样到设备输出),并且如果该速率得到原生支持,则渲染可以直接通过。这将使应用程序能够无需用户干预即可渲染到更高的速率(尽管从 Web Audio 中无法观察到音频输出未在输出时进行下采样)——例如,如果MediaDevices功能被读取(经用户干预)并表明支持更高的速率。
通过
AudioContext的输出通道数进行指纹识别也是可能的。我们建议将maxChannelCount设置为二(立体声)。立体声是迄今为止最常见的通道数。 -
-
本规范是否启用了新的脚本执行/加载机制?
否。它确实使用了该规范中定义的 [HTML] 脚本执行方法。
-
本规范是否允许源访问用户位置?
不。
-
本规范是否允许源访问用户设备上的传感器?
不直接。目前,本文件中未指定音频输入,但它将涉及获得对客户端机器音频输入或麦克风的访问权限。这将需要以适当的方式征求用户许可,可能通过
getUserMedia()API。此外,应注意 媒体捕获与流(Media Capture and Streams) 规范中的安全与隐私考量。特别是,对环境音频的分析或播放独特的音频可能使识别用户位置精确到房间级别,甚至可能识别不同用户或设备同时占用一个房间的情况。对音频输出和音频输入的访问也可能使一个浏览器中原本隔离的上下文之间能够进行通信。
-
本规范是否允许源访问用户本地计算环境的各个方面?
不直接;所有请求的采样率均受支持,并在必要时进行向上采样。可以使用媒体捕获与流来探测支持的音频采样率,使用 MediaTrackSupportedConstraints。这需要明确的用户同意。这确实提供了一种小规模的指纹识别手段。然而,在实践中,大多数消费级和准专业级设备使用两种标准化采样率中的一种:44.1kHz(最初由 CD 使用)和 48kHz(最初由 DAT 使用)。资源高度受限的设备可能支持语音质量的 11kHz 采样率,高端设备通常支持 88.2、96 或甚至发烧级的 192kHz 速率。
要求所有实现都向上采样到单一的、普遍支持的速率(如 48kHz)会增加 CPU 开销却没有任何特殊好处,而要求高端设备使用较低速率只会导致 Web Audio 被贴上不适合专业用途的标签。
-
本规范是否允许源访问其他设备?
它通常不允许访问其他联网设备(高端录音室中的一个例外可能是 Dante 网络设备,尽管它们通常使用单独的专用网络)。它必然允许访问用户的音频输出设备,这些设备有时是与计算机分开的单元。
对于声控设备,Web Audio API 可能被用于控制其他设备。此外,如果声音驱动的设备对近超声波频率敏感,这种控制可能是无法听到的。这种可能性在 HTML 中也存在,通过 <audio> 或 <video> 元素。在常见的音频采样率下,(按设计)没有足够的余量来包含太多超声波信息。
人类听力的极限通常表述为 20kHz。对于 44.1kHz 的采样率,奈奎斯特极限为 22.05kHz。鉴于真正的砖墙滤波器无法物理实现,20kHz 和 22.05kHz 之间的空间用于快速滚降滤波器,以强烈衰减所有高于奈奎斯特频率的频率。
在 48kHz 采样率下,20kHz 到 24kHz 频带内仍然存在快速衰减(但更容易避免通带中的相位纹波误差)。
-
本规范是否允许源对用户代理的原生 UI 有一定程度的控制?
如果 UI 具有音频组件,例如语音助手或屏幕阅读器,Web Audio API 可能会被用于模拟本地 UI 的某些方面,使攻击看起来更像是本地系统事件。这种可能性也存在于 HTML 中,通过 <audio> 元素。
-
本规范是否向 Web 暴露临时标识符?
不。
-
本规范是否区分第一方和第三方上下文中的行为?
不。
-
本规范应如何在用户代理的“隐身”模式上下文中工作?
没有区别。
-
本规范是否将数据持久化到用户的本地设备?
不。
-
本规范是否有“安全考虑”和“隐私考虑”部分?
是的(你正在阅读它)。
-
本规范是否允许降低默认安全特性?
不。
9. 需求与用例
请参阅 [webaudio-usecases]。
10. 规范代码的通用定义
本节描述了本规范中使用的 JavaScript 代码所采用的通用函数和类。
// Three dimensional vector class. class Vec3{ // Construct from 3 coordinates. constructor ( x, y, z) { this . x= x; this . y= y; this . z= z; } // Dot product with another vector. dot( v) { return ( this . x* v. x) + ( this . y* v. y) + ( this . z* v. z); } // Cross product with another vector. cross( v) { return new Vec3(( this . y* v. z) - ( this . z* v. y), ( this . z* v. x) - ( this . x* v. z), ( this . x* v. y) - ( this . y* v. x)); } // Difference with another vector. diff( v) { return new Vec3( this . x- v. x, this . y- v. y, this . z- v. z); } // Get the magnitude of this vector. get magnitude() { return Math. sqrt( dot( this )); } // Get a copy of this vector multiplied by a scalar. scale( s) { return new Vec3( this . x* s, this . y* s, this . z* s); } // Get a normalized copy of this vector. normalize() { const m= magnitude; if ( m== 0 ) { return new Vec3( 0 , 0 , 0 ); } return scale( 1 / m); } }
11. 更新日志
12. 致谢
本规范是 W3C 音频工作组 的集体成果。
工作组成员、前成员及本规范贡献者包括(按撰写时字母顺序排列):
Adenot, Paul (Mozilla Foundation) - 规范共同编辑;Akhgari, Ehsan (Mozilla Foundation);Becker, Steven (Microsoft Corporation);Berkovitz, Joe (受邀专家,隶属于 Noteflight/Hal Leonard) - 2013 年 9 月至 2017 年 12 月任工作组共同主席;Bossart, Pierre (Intel Corporation);Borins, Myles (Google, Inc);Buffa, Michel (NSAU);Caceres, Marcos (受邀专家);Cardoso, Gabriel (INRIA);Carlson, Eric (Apple, Inc);Chen, Bin (Baidu, Inc);Choi, Hongchan (Google, Inc) - 规范共同编辑;Collichio, Lisa (Qualcomm);Geelnard, Marcus (Opera Software);Gehring, Todd (Dolby Laboratories);Goode, Adam (Google, Inc);Gregan, Matthew (Mozilla Foundation);Hikawa, Kazuo (AMEI);Hofmann, Bill (Dolby Laboratories);Jägenstedt, Philip (Google, Inc);Jeong, Paul Changjin (HTML5 融合技术论坛);Kalliokoski, Jussi (受邀专家);Lee, WonSuk (电子通信研究院);Kakishita, Masahiro (AMEI);Kawai, Ryoya (AMEI);Kostiainen, Anssi (Intel Corporation);Lilley, Chris (W3C 工作人员);Lowis, Chris (受邀专家) - 2012 年 12 月至 2013 年 9 月任工作组共同主席,隶属于英国广播公司 (BBC);MacDonald, Alistair (W3C 受邀专家) — 2011 年 3 月至 2012 年 7 月任工作组共同主席;Mandyam, Giridhar (Qualcomm Innovation Center, Inc);Michel, Thierry (W3C/ERCIM);Nair, Varun (Facebook);Needham, Chris (英国广播公司);Noble, Jer (Apple, Inc);O’Callahan, Robert (Mozilla Foundation);Onumonu, Anthony (英国广播公司);Paradis, Matthew (英国广播公司) - 2013 年 9 月至今任工作组共同主席;Pozdnyakov, Mikhail (Intel Corporation);Raman, T.V. (Google, Inc);Rogers, Chris (Google, Inc);Schepers, Doug (W3C/MIT);Schmitz, Alexander (JS Foundation);Shires, Glen (Google, Inc);Smith, Jerry (Microsoft Corporation);Smith, Michael (W3C/Keio);Thereaux, Olivier (英国广播公司);Toy, Raymond (Google, Inc.) - 2017 年 12 月至今任工作组共同主席;Toyoshima, Takashi (Google, Inc);Troncy, Raphael (Institut Telecom);Verdie, Jean-Charles (MStar Semiconductor, Inc.);Wei, James (Intel Corporation);Weitnauer, Michael (IRT);Wilson, Chris (Google, Inc);Zergaoui, Mohamed (INNOVIMAX)