【发布时间】:2019-02-08 16:18:29
【问题描述】:
我正在尝试为任意数量的同时网络音频源实现用户控制的平移。源本身是单声道的。我正在使用 Web 音频 API (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) 使用 Javascript。
目前,我遇到的问题是我正在尝试使用多通道输出(每个源一个),但通道解释覆盖了我的平移尝试(请参阅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”。其中一项设置可能最终很重要,但在尝试修改设置时我找不到任何东西。
问题
当我用这个架构实际测试我的代码时,我会根据我选择的部件数量得到以下行为。平移滑块与每个相应源的平移器节点的“平移”值相关联。
- numParts=1 :单声道输出,使用滑块平移不会做任何事情,只会影响输出的音量(向中间更强)。我想这是从声像器向下混音到单声道的副产品。
- numParts=2 :立体声输出,左一硬,右一硬。使用滑块平移两个频道没有任何作用。
- numParts=3 :与 =2 相同,但第三个通道是静默的。
- numParts=4 :与 =2 类似,现在所有通道都重新工作了,它们按 L/R/L/R 的顺序努力平移。再次使用滑块平移没有任何作用。
这种行为似乎符合 channelInterpretation 描述,但我想要的是分别为每个源进行平移工作,而不管我使用的频道数量如何。而且我仍然希望使用通道,因为我的每个来源都希望写入单声道缓冲区。
我是否可以进行架构调整以保持这种多渠道策略并实现我的目标?
代码片段
当前代码的相关部分基于我上面的陈述以及解决问题的尝试。 编辑:感谢下面的 cmets,我设法找到了问题。我调用了单行修复,以便以后可以将此代码用作参考。
音频处理功能。只有第一个合成器(源)设置了这个回调:
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);
}
}
播放功能的相关sn-p:
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 );
}
}
【问题讨论】:
标签: javascript audio web web-audio-api