How to control the sound volume of (audio buffer) AudioContext()?
Asked Answered
J

2

13

I have following AudioContext() sound object in JavaScript.
Its volume is 100%. I want to play its volume in 10% (where volume = 0.1).
How can I reduce its volume to 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%.
Jaramillo answered 13/4, 2017 at 7:38 Comment(1)
So I recognize my code here, and if you read the answer in its entirety, you'd see that in the second snippet I use an gainNode, which will give you the control on the output volume.Unavoidable
Q
23

We use GainNodes to control the volume.

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)

solution

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%.
Quirinus answered 13/4, 2017 at 7:45 Comment(0)
A
0

You can use createGain of AudioContext for that puporse.

As shown below,

For more information checkout on 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
      }
    };
Alfie answered 13/4, 2017 at 7:51 Comment(6)
You need to connect the buffer source to the gainNode in the check.onchange too, otherwise after second change it won't work anymoreUnavoidable
You don't need to re-connect the gainNode to the context, do it once, e.g on gloabl scope. You are also still connecting the buffer to the context's destination directly, this is not good at all.Unavoidable
This is just for demonstration purpose of using gainNode for manipulating volume, optimizations can be done in many ways.Alfie
I'm not talking about optimizations. Your code doesn't work, in the scope of gainNode demo. Simply try to set it's gain.value to lower than 1 and you'll see that since you are connecting directly the buffersource to the audio context, this buffersource will still play at volume 1. => just remove all source.connect(aCtx.destination);Unavoidable
This is not the part of the code I added. Checkout the question.Alfie
I know this, I am the author of the code in the question. When I wrote it, I didn't used a gainNode, so I did connect the buffer source directly to the context. But now that you are implementing this gainNode, you must remove these lines.Unavoidable

© 2022 - 2024 — McMap. All rights reserved.