javascript - 网络音频 API : Layout to Achieve Panning for an Arbitrary Number of Sources

标签 javascript audio web web-audio-api

我正在尝试为任意数量的同时网络音频源实现用户控制的平移。来源本身是单声道的。我在 Javascript 中使用网络音频 API ( https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API )。

目前,我遇到的问题是我正在尝试使用多 channel 输出(每个源一个),但 channel 解释压倒了我的平移尝试(参见 https://developer.mozilla.org/en-US/docs/Web/API/AudioNode/channelInterpretation),导致我认为我在架构上做错了什么。

我想在这里将大部分内容留在概念层面,因为我相信这就是我的问题所在。

当前设置

我的方法是让一个节点处理每个源的所有处理,这里称为“scriptNode”。创建的 channel 数量等于音频源的数量,并且还创建了类似数量的声像器节点。该图如下所示:

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”。这些设置中的一个可能最终变得很重要,但我在尝试摆弄这些设置时找不到任何东西。

问题

当我用这个架构实际测试我的代码时,我会根据我选择的部分数量得到以下行为。平移 slider 与每个相应源的平移器节点的“平移”值相关联。

  • numParts=1 :单声道输出,使用 slider 平移不会做任何事情,只会影响输出音量(向中间变强)。我想这是从声相器缩混到单声道的副产品。
  • numParts=2 :立体声输出,一个硬左,一个硬右。使用 slider 平移两个 channel 不会执行任何操作。
  • numParts=3 : 同=2,但第三个 channel 是无声的。
  • numParts=4 :与=2 类似,现在所有 channel 都再次工作,它们按 L/R/L/R 顺序进行重声相。再次使用 slider 平移不会执行任何操作。

此行为似乎符合 channelInterpretation 描述,但我想要的是分别对每个源进行平移工作,而不管我使用的 channel 数量如何。而且我仍然希望使用 channel ,因为我的每个源都希望写入单声道缓冲区。

我是否可以进行架构调整以保持这种多 channel 策略并实现我正在寻找的目标?

代码片段

当前代码的相关部分基于我上面的陈述以及修复问题的尝试。 编辑:感谢下面的评论,我设法找到了问题所在。我调用了一行修复程序,以便稍后可以将此代码用作引用。

音频处理函数。只有第一个合成器(来源)设置此回调:

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 );

    }
}

最佳答案

PannerNode 总是产生立体声输出。当您将声相器输出连接到合并的输入之一时,声相器的立体声输出会缩混为单声道,从而有效地消除大部分声相效果。

缺少一些信息,但我不明白您为什么需要合并。您可以将每个声像器的立体声输出直接发送到目的地。目的地将适本地混合来自每个声像器的立体声输出,从而保留声像效果。

关于javascript - 网络音频 API : Layout to Achieve Panning for an Arbitrary Number of Sources,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52152608/

相关文章:

c# - Console.Beep可以替代Win8 x64吗?

java - 如何以与制作音频的方法不同的方法暂停和恢复音频?

google-cloud-platform - Google Cloud Speech API的异步问题

javascript - Angularjs - ng-switch 是否有内容加载事件?

c# - 如何保护我的 C# 程序不被未经授权地安装在不同的系统上

javascript - 如何制作一个屏幕计数器来阻止该功能直到计数器完成

javascript - 将变量添加到字符串中

javascript - 使 Ramda.js 函数全局可访问(无需 R.)

javascript - 触发点击处理程序后隐藏元素

javascript - 在 Javascript 中使用 Ajax 检索 JSON 数据