How to rapidly play multiple copies of a soundfile in javascript

人走茶凉 提交于 2020-05-17 06:36:32

问题


I'm building a wheel of fortune in html+js that spins rather quickly. Every time a new color flies by the mark, the wheel should play a click-sound. At top speed this sounds almost like a machine gun, so a new file starts playing before the old one is finished basically. The file itself is always the same: click.wav

It works fine in Chrome, only in chrome. Firefox has a weird bug, where it only plays the sound, if there is any other audio source active, such as a youtube video playing in a different tab. Edge and Safari kinda safe up the clicks to the end and then play them all simultaniously. It's a mess... I use the method described here which uses cloning an <audio> tag

I guess this is where the problem is:

var sound = new Audio("sounds/click.wav");
sound.preload = 'auto';
sound.load();

function playsound(){
    var click=sound.cloneNode();
    click.volume=1;
    click.play();
}

Here is a simplified version of my spinning function that just calls the playsound() function several times per second:

function rotateWheel(){
  angle = angle + acceleration
  while (angle >= 360) {
    angle = angle - 360
  } 
  var wheel = document.getElementById("wheel")
  wheel.style.transform = "rotate("+angle +"deg)"
  // play the click when a new segment rotates by
  if(Math.floor(angle/21) != previousSegment){
     playsound()
     previousSegment = Math.floor(angle/21)

}


回答1:


You used an answer from here this methods cause at some point to crash the browser process because you either create a memory issue or you fill up the DOM with elements the browser has to handle - so you should re-think your approach AND as you found out it will not work for heavy use in most browsers like safari or FireFox
Looking deeper into the <audio> tag specification, it becomes clear that there are many things that simply can't be done with it, which isn't surprising, since it was designed for media playback. One of the limitations includes -> No fine-grained timing of sound.

So you have to find another method for what you want we use Web Audio API designed for online video games.
Web Audio API
An AudioContext is for managing and playing all sounds. To produce a sound using the Web Audio API, create one or more sound sources and connect them to the sound destination provided by the AudioContext instance (usually the speaker). The AudioBuffer
With the Web Audio API, audio files can be played only after they’ve been loaded into a buffer. Loading sounds takes time, so assets that are used in the animation/game should be loaded on page load, at the start of the game or level, or incrementally while the player is playing.
The basic steps

  • We use an XMLHttpRequest to load data into a buffer from an audio file.
  • Next, we make an asynchronous callback and send the actual request to load.
  • Once a sound has been buffered and decoded, it can be triggered instantly.
  • Each time it is triggered, a different instance of the buffered sound is created.

A key feature of sound effects in games is that there can be many of them simultaneously. So to take your example of the "machine gun": Imagine you're in the middle of a gunfight a shooting machine gun. The machine gun fires many times per second, causing tens of sound effects to be played at the same time. This is where Web Audio API really shines. A simple example for your application:

/* global AudioContext:true,
*/

var clickingBuffer = null;
// Fix up prefixing
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();

function loadClickSound(url) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.responseType = 'arraybuffer';
    // Decode asynchronously
    request.onload = function() {
        context.decodeAudioData(request.response, function(buffer) {
            if (!buffer) {
                console.log('Error decoding file data: ' + url);
                return;
            }
        clickingBuffer = buffer;
        });
    request.onerror = function() {
        console.log('BufferLoader: XHR error');        
        };
    request.send();
    };
}

function playSound(buffer, time, volume) {              
  var source = context.createBufferSource();   // creates a sound source
  source.buffer = buffer;                     // tell the source which sound to play
  source.connect(context.destination);          // connect the source to the context's destination (the speakers)
  var gainNode = context.createGain();          // Create a gain node
  source.connect(gainNode);                     // Connect the source to the gain node
  gainNode.connect(context.destination);        // Connect the gain node to the destination
  gainNode.gain.value = volume;                  // Set the volume
  source.start(time);                           // play the source at the deisred time 0=now    
}

// You call with in your document ready
   loadClickSound('sounds/click.wav');
//and this plays the sound
   playSound(clickingBuffer, 0, 1);

Now you can play around with different timings and volume variations for example by intoducing a random factor If you need a more complex solution with different clicking sounds (stored in a buffer array) and volume/ distance variations this would be a longer piece of code.



来源:https://stackoverflow.com/questions/61453760/how-to-rapidly-play-multiple-copies-of-a-soundfile-in-javascript

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!