如何控制(音频缓冲区)AudioContext() 的音量?

Posted

技术标签:

【中文标题】如何控制(音频缓冲区)AudioContext() 的音量?【英文标题】:How to control the sound volume of (audio buffer) AudioContext()? 【发布时间】:2017-04-13 07:38:31 【问题描述】:

我在 javascript 中有以下 AudioContext() 声音对象。 它的音量是 100%。我想以 10% 的音量播放(其中音量 = 0.1)。 我怎样才能将它的音量减少到 10%?

const aCtx = new AudioContext();
let source = aCtx.createBufferSource();
let buf;
fetch('https://dl.dropboxusercontent.com/s/knpo4d2yooe2u4h/tank_driven.wav') // can be XHR as well
  .then(resp => resp.arrayBuffer())
  .then(buf => aCtx.decodeAudioData(buf)) // can be callback as well
  .then(decoded => 
    source.buffer = buf = decoded;
    source.loop = true;
    source.connect(aCtx.destination);
    check.disabled = false;
  );

check.onchange = e => 
  if (check.checked) 
    source.start(0); // start our bufferSource
   else 
    source.stop(0); // this destroys the buffer source
    source = aCtx.createBufferSource(); // so we need to create a new one
    source.buffer = buf;
    source.loop = true;
    source.connect(aCtx.destination);
  
;
<label>Start Playing</label>
<input type="checkbox" id="check" disabled><br>
<br>Its volume is 100%. Please help me to reduce it to 10%.

【问题讨论】:

所以我在这里认出了my code,如果你完整地阅读了答案,你会看到在第二个sn-p中我使用了gainNode,它会给你控制权在输出音量上。 【参考方案1】:

我们使用GainNodes来控制音量。

var gainNode = aCtx.createGain()
gainNode.gain.value = 0.1 // 10 %
gainNode.connect(aCtx.destination)

// now instead of connecting to aCtx.destination, connect to the gainNode
source.connect(gainNode)

解决方案

const aCtx = new AudioContext();

const gainNode = aCtx.createGain();
gainNode.gain.value = 0.1; // setting it to 10%
gainNode.connect(aCtx.destination);

let source = aCtx.createBufferSource();
let buf;
fetch('https://dl.dropboxusercontent.com/s/knpo4d2yooe2u4h/tank_driven.wav') // can be XHR as well
  .then(resp => resp.arrayBuffer())
  .then(buf => aCtx.decodeAudioData(buf)) // can be callback as well
  .then(decoded => 
    source.buffer = buf = decoded;
    source.loop = true;
    source.connect(gainNode);

    check.disabled = false;
  );

check.onchange = e => 
  if (check.checked) 
    source.start(0); // start our bufferSource
   else 
    source.stop(0); // this destroys the buffer source
    source = aCtx.createBufferSource(); // so we need to create a new one
    source.buffer = buf;
    source.loop = true;
    source.connect(gainNode);
    
  
;
<label>Start Playing</label>
<input type="checkbox" id="check" disabled><br>
<br>Its volume is 100%. Please help me to reduce it to 10%.

【讨论】:

@Kaiido 谢谢。应该看到的。我也很痛……现在我看到了。【参考方案2】:

您可以为此目的使用 AudioContext 的 createGain。

如下图,

欲了解更多信息,请查看createGain

https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createGain

    const aCtx = new AudioContext();
    let source = aCtx.createBufferSource();
    let buf;

    var gainNode = aCtx.createGain(); // Create a gainNode reference.
    gainNode.connect(aCtx.destination); // Add context to gainNode

fetch('https://dl.dropboxusercontent.com/s/knpo4d2yooe2u4h/tank_driven.wav') // can be XHR as well
      .then(resp => resp.arrayBuffer())
      .then(buf => aCtx.decodeAudioData(buf)) // can be callback as well
      .then(decoded => 
        source.buffer = buf = decoded;
        source.loop = true;

        source.connect(gainNode);   //Connecting gain to source
        gainNode.gain.value = 1;  // 100% VOLUME RANGE OF VALUE IS 0-1

        check.disabled = false;
      );


   check.onchange = e => 
      if (check.checked) 
        source.start(0); // start our bufferSource
       else 
        source.stop(0); // this destroys the buffer source
        source = aCtx.createBufferSource(); // so we need to create a new one
        source.buffer = buf;
        source.loop = true;

        source.connect(gainNode);   //Connecting gain to source
        gainNode.gain.value = 0.1;  // 10% VOLUME RANGE OF VALUE IS 0-1
      
    ;

【讨论】:

你也需要在check.onchange中把buffer source连接到gainNode,否则第二次修改后就不行了 您不需要将 gainNode 重新连接到上下文,只需执行一次,例如在 gloabl 范围内。您还仍然将缓冲区直接连接到上下文的目的地,这一点都不好。 这只是为了演示使用 gainNode 来控制音量,可以通过多种方式进行优化。 我不是在谈论优化。您的代码不起作用,在 gainNode 演示的范围内。只需尝试将其 gain.value 设置为低于 1,您就会看到,由于您将缓冲区源直接连接到音频上下文,因此该缓冲区源仍将以音量 1 播放。=> 只需删除所有 source.connect(aCtx.destination); 这不是我添加的代码的一部分。检查问题。

以上是关于如何控制(音频缓冲区)AudioContext() 的音量?的主要内容,如果未能解决你的问题,请参考以下文章

web技术分享| AudioContext 实现音频可视化

尝试运行 AudioContext.createMediaElementSource() 时如何解决“音频无法识别调用‘连接’的对象”错误?

使用 AudioContext restart 音频

音频与 AudioContext

使用来自音频标签的源使用 AudioContext

在 iframe 中启动 AudioContext