audio - 缓冲区和网络音频 API

标签 audio web-audio-api

我目前正在为一个大学项目构建一个环境声音发生器,但遇到了一个小问题。

基本上我目前有 3 个不同的文件,用户可以组合暂停/播放,并且每个暂停/播放都可以。唯一的问题是,如果我一次播放多个声音,则在停止后,我的 2 个声音之一会继续播放。

也许有人可以指出我出错的方向和/或我可以了解有关 API 的更多信息的资源。

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

        var soundBuffer1 = null;
        var soundBuffer2 = null;
        var soundBuffer3 = null;
        var soundBuffer4 = null;
        var soundBuffer5 = null;

        window.onload = function() {
          create_buffers();
        };

        function create_buffers(){
          soundBufferSourceNode1 = context.createBufferSource();
          soundBufferSourceNode1.looping = true;
          soundBufferSourceNode2 = context.createBufferSource();
          soundBufferSourceNode2.looping = true;
          soundBufferSourceNode3 = context.createBufferSource();
          soundBufferSourceNode3.looping = true;
          soundBufferSourceNode4 = context.createBufferSource();
          soundBufferSourceNode4.looping = true;
          soundBufferSourceNode5 = context.createBufferSource();
          soundBufferSourceNode5.looping = true;
        };

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


        function play_sound1(){
          document.getElementById('playBtn1_play').style.display = 'none';
          document.getElementById('playBtn1_stop').style.display = 'block';

          playSound(soundBuffer1, soundBufferSourceNode1);
        }
        function stop_sound1(){
          document.getElementById('playBtn1_play').style.display = 'block';
          document.getElementById('playBtn1_stop').style.display = 'none';

          stopSound(soundBufferSourceNode1);
          create_buffers();
        }
        function play_sound2(){
          document.getElementById('playBtn2_play').style.display = 'none';
          document.getElementById('playBtn2_stop').style.display = 'block';
          playSound(soundBuffer2, soundBufferSourceNode2);
          p2=true;
        };
        function stop_sound2(){
          document.getElementById('playBtn2_play').style.display = 'block';
          document.getElementById('playBtn2_stop').style.display = 'none';
          p2=false;
          stopSound(soundBufferSourceNode2);
          create_buffers();
        };
        function play_sound3(){
          document.getElementById('playBtn3_play').style.display = 'none';
          document.getElementById('playBtn3_stop').style.display = 'block';
          p3=true;
          playSound(soundBuffer3, soundBufferSourceNode3);
        }
        function stop_sound3(){
          document.getElementById('playBtn3_play').style.display = 'block';
          document.getElementById('playBtn3_stop').style.display = 'none';
          p3=false;
          stopSound(soundBufferSourceNode3);
          create_buffers();
        }

        function playSound(buffer, bufferSourceNode) {
          bufferSourceNode.buffer = buffer;
          bufferSourceNode.connect(context.destination);
          bufferSourceNode.noteOn(0);
        };
        function stopSound(bufferSourceNode) {
          bufferSourceNode.noteOff(0);
        };
        function loadSound(url, bufferNum) {
          var request = new XMLHttpRequest();
          request.open('GET', url, true);
          request.responseType = 'arraybuffer';

          request.onload = function() {
            var successCallback = function(buffer) {
              switch(bufferNum) {
                case 1:
                  soundBuffer1 = buffer;
                break;
                case 2:
                      soundBuffer2 = buffer;
                break;
                case 3:
                  soundBuffer3 = buffer;
                break;
                case 4:
                  soundBuffer4 = buffer;
                break;
                case 5:
                  soundBuffer5 = buffer;
                break;
              }
            }
            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_sound1();"   />
      <input type="image" class="pp_img" src="img/fire-play.png" name="Fire" id="playBtn1_stop" onclick="stop_sound1();" 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_sound2();"  />
      <input type="image" class="pp_img" src="img/wind-play.png" name="Wind" id="playBtn2_stop" onclick="stop_sound2();" 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_sound3();"/>
      <input type="image" class="pp_img" src="img/rain-play.png" name="Rain" id="playBtn3_stop" onclick="stop_sound3();" 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_sound4();"/>
      <input type="image" class="pp_img" src="img/stream-play.png" name="Stream" id="playBtn4_stop" onclick="stop_sound4();" 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_sound5();"/>
      <input type="image" class="pp_img" src="img/forest-play.png" name="Rain" id="playBtn5_stop" onclick="stop_sound5();" 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>

最佳答案

您需要在 playSound 中缓存当前正在播放的任何声音,并在开始新声音之前停止它。

您不应该在事前创建所有这些缓冲区源节点;当您想开始玩时只需创建一个即可。

此外,您应该使用 start() 和 stop(),而不是 noteOn() 和 noteOff() - 后者已被弃用。

试试这个:

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

        var soundBuffers = [null,null,null,null,null,null];  // extra entry in array as dummy '0' entry

        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 play_sound(num){
          stop_any_currently_playing_sound();

          if (num) {
            document.getElementById('playBtn'+num+'_play').style.display = 'none';
            document.getElementById('playBtn'+num+'_stop').style.display = 'block';

            currentlyPlayingSoundNum = num;
            currentlyPlayingSound = context.createBufferSource();
            currentlyPlayingSound.looping = true;
            currentlyPlayingSound.buffer = soundBuffers[num];
            currentlyPlayingSound.connect(context.destination);
            currentlyPlayingSound.start(0);
          }
        }

        function stop_sound(){
          if (currentlyPlayingSound) {
            document.getElementById('playBtn'+currentlyPlayingSoundNum+'_play').style.display = 'block';
            document.getElementById('playBtn'+currentlyPlayingSoundNum+'_stop').style.display = 'none';

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

关于audio - 缓冲区和网络音频 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27238105/

相关文章:

javascript - wavesurfer.js play([start[, end]]) end 不起作用

streaming - 通过客户端 XHR 打开 Soundcloud Track 的 stream_url?

javascript - 如何获取增益节点

windows - Windows 7中的声音和手势移动口吃

bash - 使用 FFmpeg 混契约(Contract)名音频和视频文件的脚本

c# - 录制语音,直到用户停止讲话?

web-audio-api - 如何在网络音频 API 中生成起始和偏移余弦平方斜坡?

ios - 单击后退按钮iOS 6时如何继续播放音频

javascript - Javascript-我可以一次更改所有音频元素的音量吗?

javascript - 网络音频,createMediaElementSource 变量源