JellyTots
JellyTots

Reputation: 123

Volume controls and buffering issues with Web Audio API

I'm running into some issues writing an app using the Web Audio API.

I'm trying to play multiple sounds with Web Audio API, each with an individual volume control and able to have multiple different sounds playing at once., but I can't figure out how to implement it.

I can figure out how to implement a universal volume control, but would like to be able to increase/decrease individual sounds. I am also having the issue that when I have multiple sounds playing, I can't seem to stop them all.. one sounds seems to always get stuck somewhere.

Any advise on how to update the below code would be greatly appreciated.

    <head> 
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/loopy_styles.css" />
    <script>
        context = new (window.AudioContext || window.webkitAudioContext)();

        //We set up an array of buffers to store our sounds in, with an extra entry as dummy '0' entry
        var soundBuffers = [null,null,null,null,null,null];

        //We load our sounds into the buffer when the page is opened.
        window.onload = function() {
          loadSound('sounds/fire_test1.wav', 1);
          loadSound('sounds/wind_test.wav', 2);
          loadSound('sounds/rain_test1.wav', 3);
          loadSound('sounds/stream.mp3', 4);
          loadSound('sounds/spring_test.wav', 5);
        };


        var currentlyPlayingSoundNum = 0;
        var currentlyPlayingSound = null;

        //Function to play sound, take in a number to represent each sound icon.
        function play_sound(num){
          if (num) {
            //Shows the paused version of button, hides the play version of the button.
            document.getElementById('playBtn'+num+'_play').style.display = 'none';
            document.getElementById('playBtn'+num+'_stop').style.display = 'block';
            //Sets the currently playing sound to the number supplied to the function.
            currentlyPlayingSoundNum = num;
            //Creates buffer for sound.
            currentlyPlayingSound = context.createBufferSource();
            //Sets the sound to loop continuously so we have seemless play-back.
            currentlyPlayingSound.looping = true;
            //Sends the sound at spot num in our buffer array to the buffer for our currently playing sound.
            currentlyPlayingSound.buffer = soundBuffers[num];
            currentlyPlayingSound.connect(context.destination);
            //Start playing the sound.
            currentlyPlayingSound.start(0);
          }
        }
        //Function to stop sound, take in a number to represent each sound icon.
        function stop_sound(num){
          if(num){
            document.getElementById('playBtn'+num+'_play').style.display = 'block';
            document.getElementById('playBtn'+num+'_stop').style.display = 'none';
          }
          if (currentlyPlayingSound) {
            //Shows the play version of button, hides the paused version of the button.
            document.getElementById('playBtn'+currentlyPlayingSoundNum+'_play').style.display = 'block';
            document.getElementById('playBtn'+currentlyPlayingSoundNum+'_stop').style.display = 'none';
            //Stops playing the currently playing sound.
            currentlyPlayingSound.stop(0);
            currentlyPlayingSound = null;
            currentlyPlayingSoundNumber = 0;
          }
        }
        function loadSound(url, bufferNum) {
          var request = new XMLHttpRequest();
          request.open('GET', url, true);
          request.responseType = 'arraybuffer';

          request.onload = function() {
            var successCallback = function(buffer) {
              soundBuffers[bufferNum] = buffer;
            }
            var errorCallback = function(e) {
              console.log(e);
            }
            context.decodeAudioData(request.response, successCallback, errorCallback);
          }
          request.send();
        }
    </script>
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <title>Ambient Sound Generator</title>  
  </head>
<body>
<div class="background">
  <div id="intro-text">
    <h1 id="site-title">Ambient Sound Generator</h1>
    <p>Mix ambient sounds together to block out distractions and help you focus or relax</p>
    <p>Click the buttons below to begin</p>
  </div>
  <div id="button-container">
    <div id="btn1">
      <input type="image" class="pp_img" src="img/fire-pause.png" name="Fire" id="playBtn1_play" onclick="play_sound(1);"   />
      <input type="image" class="pp_img" src="img/fire-play.png" name="Fire" id="playBtn1_stop" onclick="stop_sound(1);" style="display:none"   />
      <p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
    </div>
    <div id="btn2">
      <input type="image" class="pp_img" src="img/wind-pause.png" name="Wind" id="playBtn2_play" onclick="play_sound(2);"  />
      <input type="image" class="pp_img" src="img/wind-play.png" name="Wind" id="playBtn2_stop" onclick="stop_sound(2);" style="display:none" />
      <p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
    </div>
    <div id="btn3">
      <input type="image" class="pp_img" src="img/rain-pause.png" name="Rain" id="playBtn3_play" onclick="play_sound(3);"/>
      <input type="image" class="pp_img" src="img/rain-play.png" name="Rain" id="playBtn3_stop" onclick="stop_sound(3);" style="display:none"/>
      <p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
    </div>
    <div id="btn4">
      <input type="image" class="pp_img" src="img/stream-pause.png" name="Stream" id="playBtn4_play" onclick="play_sound(4);"/>
      <input type="image" class="pp_img" src="img/stream-play.png" name="Stream" id="playBtn4_stop" onclick="stop_sound(4);" style="display:none"/>
      <p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
    </div>
    <div id="btn5">
      <input type="image" class="pp_img" src="img/forest-pause.png" name="Rain" id="playBtn5_play" onclick="play_sound(5);"/>
      <input type="image" class="pp_img" src="img/forest-play.png" name="Rain" id="playBtn5_stop" onclick="stop_sound(5);" style="display:none" />
      <p><input type="range" min="0" max="100" value="100" onchange="sample.changeVolume();">Volume</p>
    </div>
      </div>
    </div>
    </body>
    <script>
      function refreshData(){
        x = 1;  // x = seconds
        var d = new Date()
        var h = d.getHours();
        var m = d.getMinutes();
        var s = d.getSeconds();

        if (h<=9) {h = '0'+h};
        if (m<=9) {m = '0'+m};
        if (s<=9) {s = '0'+s};

        var color = '#'+h+m+s;

          $("div.background").css("background-color", color );
          $("p#hex").text(color);
          setTimeout(refreshData, x*1000);
      }
      refreshData(); // execute function
    </script>

Upvotes: 3

Views: 789

Answers (1)

cwilso
cwilso

Reputation: 13908

Instead of

currentlyPlayingSound.connect(context.destination);

You just need to create another GainNode and chain it in:

var gain = context.createGain();
gain.gain.value = /*insert your gain variable here */;
currentlyPlayingSound.connect(gain);
gain.connect(context.destination);

You'll probably want to cache the gain node somewhere (so you can have a slider, etc.)

Upvotes: 3

Related Questions