【问题标题】:Webaudio panner crackling sound when position is changed位置更改时 Webaudio panner 噼啪声
【发布时间】:2021-09-28 10:18:30
【问题描述】:

我正在开发一个 3D 网络应用程序,我想在其中使用位置 3D 音频。

我开始注意到随着声源位置的改变,输出端会出现噼啪声。 最初我认为这可能是编程问题或库问题(我使用的是 howler.js)。

我做了一个基于普通 JS 和 Webaudio API 的非常基本的示例,如下所示

let params={        
        "xPosition":0,
        "zPosition":-1
    };

    let gui=new dat.GUI( { autoPlace: true, width: 500 });       

    const AudioContext = window.AudioContext || window.webkitAudioContext;
    
    let audioCtx;
    let panner;
    let listener;
    let source;
    let osc;
  

    function initWebAudio(){
    
        audioCtx = new AudioContext();
        panner = audioCtx.createPanner();
        listener = audioCtx.listener;

        osc = audioCtx.createOscillator();
        osc.frequency.value = 70;
        osc.connect(panner);
        osc.start(0);


        panner.connect(audioCtx.destination);

        panner.panningModel = 'HRTF';
        panner.distanceModel = 'linear';
        
        panner.maxDistance = 60;
        panner.refDistance = 1;
        panner.rolloffFactor = 1;
        panner.coneInnerAngle = 360;
        panner.coneOuterAngle = 360;
        panner.coneOuterGain = 0;
        
                panner.positionX.setValueAtTime(0,audioCtx.currentTime);
        panner.positionY.setValueAtTime(1,audioCtx.currentTime);
                panner.positionZ.setValueAtTime(1,audioCtx.currentTime);
        
        if(panner.orientationX) {
            panner.orientationX.value = 1;
            panner.orientationY.value = 0;
            panner.orientationZ.value = 0;
        } else {
            panner.setOrientation(1,0,0);
        }

        if(listener.forwardX) {
            listener.forwardX.value = 0;
            listener.forwardY.value = 0;
            listener.forwardZ.value = -1;

            listener.upX.value = 0;
            listener.upY.value = 1;
            listener.upZ.value = 0;
        } else {
            listener.setOrientation(0,0,-1,0,1,0);
        }


        if(listener.positionX) {
            listener.positionX.value = 0;
            listener.positionY.value = 0;
            listener.positionZ.value = 0;
        } else {
            listener.setPosition(0,0,0);
        }

    }

    function positionPanner() {
        
        if(panner.positionX) {
        
            panner.positionX.setValueAtTime(params.xPosition, audioCtx.currentTime);          
            
        } else {
        
            panner.setPosition(params.xPosition,0,params.zPosition);
        }       

    }
    

    function tick(){  
    
        positionPanner();  
        
    }
        
    function onClickStart(){

        initWebAudio();    
        
        gui.add(osc.frequency,"value",50,220).name("frequency");
        
        setInterval(tick,50);

    }
    
    function buildMenu(){

        gui.add(params,"xPosition",-3,3).step(0.001);
        gui.add(window,"onClickStart").name("start");
        
    }

    
    buildMenu();  
    

https://jsfiddle.net/fedeM75/t9vpm8so/23/

按下开始,然后当您更改 xPosition 滑块时,会出现噼啪声。 使用耳机时尤其明显。

我在google上搜索,有人说这与职位的变化率有关。但是我尝试了不同的值范围,但仍然会发生一些小的变化。

顺便说一句,如果使用平移器的条件是位置的变化速度非常慢,那么它在现实世界的情况下似乎没有用。

我使用计时器来更新位置,但使用 requestAnimationFrame() 也会发生同样的情况

有没有人知道为什么会发生这种情况以及如何解决它?

【问题讨论】:

  • 您能否简化/自动化音频更改,使它们不会突然?例如。如果我在音频播放器中构建播放/暂停功能,我实际上会快速淡入/淡出,以避免突然变化引起的爆裂声和点击声。想想波形在某个不为 0 的地方被截断……你会听到砰砰声。
  • 我尝试使用另一个变量作为 targetValue,因此该位置会慢慢尝试达到目标值,但弹出仍然存在。在现实世界的应用程序中,您将限制源在 3D 空间中的最大速度。在某些情况下,这是一个非常重要的限制,导致 3d 定位音频无法使用。想象一个动作游戏,物体需要非常缓慢地移动以防止那些爆裂声和咔嗒声......
  • 不,我仍在寻找解决方案。这似乎是一个错误,但并非 Chrome 独有,因为 Firefox 显示相同的问题
  • 我目前正在尝试为此寻找解决方案。我创建了一个 360 度移动声音的基本示例:jsfiddle.net/9pbn587L/98 我现在尝试了很多东西,但还没有找到
  • @NVRM 我实际上首先使用的是 howler.js。当我遇到 panner 的问题时,我意识到 Howler 只是使 WebAudio panner 节点可访问,但不会添加或更改任何功能。因此,我构建了基于 Webaudio 的最简单的示例。我尝试使用不同的更新间隔,但问题仍然存在。在 PC 上,问题发生在 Chrome、Firefox 和 Edge 中,但有人告诉我,在 Safari/Mac 上没有,所以可能是实施问题。这里我做了一个更简单的例子jsfiddle.net/fedeM75/bqtzcokm/1

标签: javascript web-audio-api


【解决方案1】:

我用一个简单的 GainNode 获得了这个噼啪作响的音频。这确实可能是一个错误,因为 ScriptProcessor 中的简单实现 确实 工作。或者是我/我们只是不明白应该如何处理 audioCtx.currentTime 的计时?

对我来说,解决方案是放弃增益节点并使用 ScriptProcessor(已弃用:您可以/应该使用 AudioWorkletNode)将我自己的增益直接应用于音频信号:

let myGain = 1.0; // change this as you like without crackling noises

let whiteNoise = audioCtx.createScriptProcessor(4096, 0, 1);
whiteNoise.onaudioprocess = function(e) {
    let output = e.outputBuffer.getChannelData(0);
    for (let i = 0; i < output.length; i++) {
        output[i] = (Math.random() * 2 - 1) * myGain;
    }
}

这不会直接解决您的问题,因为您在使用 3D 平移器时遇到此问题,但也许您可以找到此类平移器实现的源代码/示例并将其移植到 AudioWorkletNode?希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    相关资源
    最近更新 更多