Web Audio API:为任意数量的源实现声像的布局
Web Audio API: Layout to Achieve Panning for an Arbitrary Number of Sources
我正在尝试为任意数量的同时网络音频源实现用户控制的平移。来源本身是单声道的。我正在 Javascript 中使用网络音频 API (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API).
目前,我 运行 遇到的问题是我正在尝试使用多通道输出(每个源一个),但通道解释覆盖了我的平移尝试(请参阅https://developer.mozilla.org/en-US/docs/Web/API/AudioNode/channelInterpretation), 让我觉得我在架构上做错了什么。
我想在这里停留在概念层面,因为我相信这就是我的问题所在。
当前设置
我的方法是让一个节点处理每个源的所有处理,这里称为 'scriptNode'。创建的通道数量等于音频源的数量,并且还创建了类似数量的声像器节点。该图如下所示:
The bundle size (the '=' segments) is the number of channels, set to be equal to the number of sources.
scriptNode == splitter =+-- panner1 --+= merger == destination
\-- panner. --/
\-- panner. --/
\-- pannerN --/
一些杂项,我正在调用此函数来设置 scriptNode:
scriptNode = firstPart.audioCtx.createScriptProcessor(2048, 0, numParts);
其中 numParts 是源数。我还将 scriptNode 的 channelCountMode 设置为 'explicit',将 channelInterpretation 设置为 'speakers'。其中一项设置可能最终变得很重要,但在尝试 fiddle 设置时我找不到任何东西。
问题
当我用这个架构实际测试我的代码时,我会根据我选择的部分数量得到以下行为。平移滑块与每个相应源的平移器节点的 "pan" 值相关联。
- numParts=1 :单声道输出,使用滑块平移不会做任何事情,只会影响输出的音量(向中间更强)。我想这是从声相器缩混到单声道的副产品。
- numParts=2 : 立体声输出,一个硬左,一个硬右。使用滑块平移两个频道没有任何作用。
- numParts=3 : 与=2相同,但第三通道无声。
- numParts=4 : 与=2 类似,现在所有通道都再次工作,它们按 L/R/L/R 顺序进行重摇。再次使用滑块平移不会执行任何操作。
此行为似乎符合 channelInterpretation 描述,但我想要的是分别对每个源进行平移工作,而不管我使用的通道数量如何。而且我仍然想 使用 通道,因为我的每个源都希望写入单声道缓冲区。
我是否可以进行架构调整以保持这种多渠道策略并实现我正在寻找的目标?
代码片段
当前代码的相关部分基于我上面的陈述以及修复问题的尝试。
编辑:感谢下面的评论,我设法找到了问题所在。我喊出了一行修复,所以这段代码可以作为以后的参考。
音频处理功能。只有第一个合成器(来源)设置此回调:
function customAudioProcessCallback( audioProcessingEvent )
{
// First synth - process audio for all synths!
const outputBuffer = audioProcessingEvent.outputBuffer;
for ( var i = 0; i < numParts; i++ ) {
// Each part writes to one channel.
synthParts[ i ].synthesize(outputBuffer.getChannelData( i ), outputBuffer.length);
}
}
播放功能的相关片段:
function play()
{
const contextClass = (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext);
synthParts[ 0 ].audioCtx = new contextClass();
synthParts[ 0 ].scriptNode = synthParts[ 0 ].audioCtx.createScriptProcessor ? synthParts[ 0 ].audioCtx.createScriptProcessor(2048, 0, numParts+1) : synthParts[ 0 ].audioCtx.createJavaScriptNode(2048, 0, numParts+1); // 2048, 0 input channels, ? outputs
synthParts[ 0 ].scriptNode.onaudioprocess = customAudioProcessCallback;
synthParts[ 0 ].scriptNode.channelCountMode = 'explicit';
synthParts[ 0 ].scriptNode.channelInterpretation = 'speakers';
// Set up splitter and panners for all channels
var splitter = synthParts[ 0 ].audioCtx.createChannelSplitter( numParts+1 );
for ( var i = 0; i < numParts; i++ ) {
panList[ i ] = synthParts[ 0 ].audioCtx.createStereoPanner();
panList[ i ].pan = panValues[ i ];
}
// Connection:
// scriptNode -- splitter -+-- panner1 --+- destination
// \-- panner. --/
// \-- pannerN --/
synthParts[ 0 ].scriptNode.connect(splitter);
for ( var i = 0; i < numParts; i++ ) {
splitter.connect( panList[ i ], i);
// This line used to read:
// panList[ i ].connect( synthParts[ 0 ].audioCtx.destination, 0, i );
// However, this was connecting multiple parts to the input of the audio context destination, which is limited to 1 input. The correct call is below.
panList[ i ].connect( synthParts[ 0 ].audioCtx.destination );
}
}
A PannerNode
始终产生立体声输出。当您将声相器输出连接到合并的输入之一时,声相器的立体声输出会缩混为单声道,从而有效地消除大部分声相效果。
缺少一些信息,但我不明白您为什么需要合并。您可以将每个声像器的立体声输出直接发送到目的地。目的地将适当地混合每个声相器的立体声输出,保留声相效果。
我正在尝试为任意数量的同时网络音频源实现用户控制的平移。来源本身是单声道的。我正在 Javascript 中使用网络音频 API (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API).
目前,我 运行 遇到的问题是我正在尝试使用多通道输出(每个源一个),但通道解释覆盖了我的平移尝试(请参阅https://developer.mozilla.org/en-US/docs/Web/API/AudioNode/channelInterpretation), 让我觉得我在架构上做错了什么。
我想在这里停留在概念层面,因为我相信这就是我的问题所在。
当前设置
我的方法是让一个节点处理每个源的所有处理,这里称为 'scriptNode'。创建的通道数量等于音频源的数量,并且还创建了类似数量的声像器节点。该图如下所示:
The bundle size (the '=' segments) is the number of channels, set to be equal to the number of sources.
scriptNode == splitter =+-- panner1 --+= merger == destination
\-- panner. --/
\-- panner. --/
\-- pannerN --/
一些杂项,我正在调用此函数来设置 scriptNode:
scriptNode = firstPart.audioCtx.createScriptProcessor(2048, 0, numParts);
其中 numParts 是源数。我还将 scriptNode 的 channelCountMode 设置为 'explicit',将 channelInterpretation 设置为 'speakers'。其中一项设置可能最终变得很重要,但在尝试 fiddle 设置时我找不到任何东西。
问题
当我用这个架构实际测试我的代码时,我会根据我选择的部分数量得到以下行为。平移滑块与每个相应源的平移器节点的 "pan" 值相关联。
- numParts=1 :单声道输出,使用滑块平移不会做任何事情,只会影响输出的音量(向中间更强)。我想这是从声相器缩混到单声道的副产品。
- numParts=2 : 立体声输出,一个硬左,一个硬右。使用滑块平移两个频道没有任何作用。
- numParts=3 : 与=2相同,但第三通道无声。
- numParts=4 : 与=2 类似,现在所有通道都再次工作,它们按 L/R/L/R 顺序进行重摇。再次使用滑块平移不会执行任何操作。
此行为似乎符合 channelInterpretation 描述,但我想要的是分别对每个源进行平移工作,而不管我使用的通道数量如何。而且我仍然想 使用 通道,因为我的每个源都希望写入单声道缓冲区。
我是否可以进行架构调整以保持这种多渠道策略并实现我正在寻找的目标?
代码片段
当前代码的相关部分基于我上面的陈述以及修复问题的尝试。 编辑:感谢下面的评论,我设法找到了问题所在。我喊出了一行修复,所以这段代码可以作为以后的参考。
音频处理功能。只有第一个合成器(来源)设置此回调:
function customAudioProcessCallback( audioProcessingEvent )
{
// First synth - process audio for all synths!
const outputBuffer = audioProcessingEvent.outputBuffer;
for ( var i = 0; i < numParts; i++ ) {
// Each part writes to one channel.
synthParts[ i ].synthesize(outputBuffer.getChannelData( i ), outputBuffer.length);
}
}
播放功能的相关片段:
function play()
{
const contextClass = (window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.oAudioContext || window.msAudioContext);
synthParts[ 0 ].audioCtx = new contextClass();
synthParts[ 0 ].scriptNode = synthParts[ 0 ].audioCtx.createScriptProcessor ? synthParts[ 0 ].audioCtx.createScriptProcessor(2048, 0, numParts+1) : synthParts[ 0 ].audioCtx.createJavaScriptNode(2048, 0, numParts+1); // 2048, 0 input channels, ? outputs
synthParts[ 0 ].scriptNode.onaudioprocess = customAudioProcessCallback;
synthParts[ 0 ].scriptNode.channelCountMode = 'explicit';
synthParts[ 0 ].scriptNode.channelInterpretation = 'speakers';
// Set up splitter and panners for all channels
var splitter = synthParts[ 0 ].audioCtx.createChannelSplitter( numParts+1 );
for ( var i = 0; i < numParts; i++ ) {
panList[ i ] = synthParts[ 0 ].audioCtx.createStereoPanner();
panList[ i ].pan = panValues[ i ];
}
// Connection:
// scriptNode -- splitter -+-- panner1 --+- destination
// \-- panner. --/
// \-- pannerN --/
synthParts[ 0 ].scriptNode.connect(splitter);
for ( var i = 0; i < numParts; i++ ) {
splitter.connect( panList[ i ], i);
// This line used to read:
// panList[ i ].connect( synthParts[ 0 ].audioCtx.destination, 0, i );
// However, this was connecting multiple parts to the input of the audio context destination, which is limited to 1 input. The correct call is below.
panList[ i ].connect( synthParts[ 0 ].audioCtx.destination );
}
}
A PannerNode
始终产生立体声输出。当您将声相器输出连接到合并的输入之一时,声相器的立体声输出会缩混为单声道,从而有效地消除大部分声相效果。
缺少一些信息,但我不明白您为什么需要合并。您可以将每个声像器的立体声输出直接发送到目的地。目的地将适当地混合每个声相器的立体声输出,保留声相效果。