18

I'm building a game in which a wav file plays on click - in this case it's a gun sound "bang".

The problem is if I rapid click, it won't play the sound once for each click - it's as if the clicks are ignored while the sound is playing, and once the sound is finished, it starts listening for clicks again. The delay seems to be about one second long, so you figure if someone clicks 4 or 5 times per second, I want 5 bangs, not 1.

Here's my HTML:

<audio id="gun_sound" preload>
    <source src="http://www.seancannon.com/_test/audio/gun_bang.wav" />
</audio>

Here's my JS:

$('#' + CANVAS_ID).bind(_click, function() {
    document.getElementById('gun_sound').play();
    adj_game_data(GAME_DATA_AMMO_ID, -1);
    check_ammo();
}); 

Ideas?

AlienWebguy
  • 73,720
  • 16
  • 109
  • 137

3 Answers3

16

Once the gun_bang.wav is preloaded, you can dynamically make new elements with that sound attached to it, play the audio, and then remove them when the audio has finished.

    function gun_bang(){
        var audio = document.createElement("audio");
        audio.src = "http://www.seancannon.com/_test/audio/gun_bang.wav";
        audio.addEventListener("ended", function () {
            document.removeChild(this);
        }, false);
        audio.play();   
    }

    $('#' + CANVAS_ID).bind(_click, function() {
        gun_bang();
        adj_game_data(GAME_DATA_AMMO_ID, -1);
        check_ammo();
    }); 
katspaugh
  • 15,752
  • 9
  • 61
  • 97
Maverick
  • 2,981
  • 5
  • 23
  • 34
  • This looks promising. My only fear is that there will be latency between the click and the audio while the element is being created. Do I still need my initial `audio` tag? I assume that's how it's preloaded? – AlienWebguy Aug 01 '11 at 00:22
  • Hah all fears debunked, thanks! Now when will JQuery start supporting these functions so I can do `$('selector').play()` and whatnot? – AlienWebguy Aug 01 '11 at 00:31
  • 2
    This is an overkill. Just set `currentTime` to `0`: http://stackoverflow.com/a/7005562/352796 – katspaugh Dec 22 '11 at 15:05
  • 2
    @AllenWebguy You can do it in jQuery with `$('selector')[0].play();` – Volomike Nov 02 '12 at 09:39
  • 2
    @katspaugh that would cut off the sound though. – Maverick Aug 08 '13 at 21:16
  • Hey @Maverick thanks! Just one question, should we remove the EventListener as well, or should it be fine? (memory leak?) – NiCk Newman Aug 31 '15 at 11:52
  • Actually, this method creates a new request each time which is not good. Is there a way to check if it's already loaded and still play repeatedly upon clicking? (without making a new request each click?) – NiCk Newman Aug 31 '15 at 11:56
14

I know it's a very late answer, I just wanted to , but seeking for a solution I found that in my case the best one was to preload the sound and then clone the node each time I want to play it, this allows me to play it even if the previous has not ended:

var sound = new Audio("click.mp3");
sound.preload = 'auto';
sound.load();

function playSound(volume) {
  var click=sound.cloneNode();
  click.volume=volume;
  click.play();
}
jmservera
  • 6,029
  • 1
  • 27
  • 40
  • This is great. Is there anyway to do the same thing but using multiple mp3's? – gravityboy Sep 04 '13 at 06:51
  • @jmservera This is nice, but each new click add's a HTTP request :( – NiCk Newman Aug 31 '15 at 12:14
  • Works like a charm in Chrome, but for some reason Firefox doesn't play. I do see the speaker icon on the firefox tab, so there is audio, and if I have ANY other audio playing from my PC (youtube video, skype call, etc.) then Firefox even plays it audibly - otherwise I cannot hear it :-/ any ideas? I'm shooting out many clones via a for loop, so think of it as a machine gun firing – Beezle-Bug Apr 22 '20 at 08:21
1

You can wrap the following with your own program-specific click logic, but the following demonstrates 3 gun sounds at the same time. If you want any kind of delay, you can introduce a minor sleep() function (many kludge hacks for this are easily found), or you can use setTimeout() to call subsequent ones.

<audio id="gun_sound" preload="preload">
    <source src="http://www.seancannon.com/_test/audio/gun_bang.wav" />
</audio>

<script type="text/javascript">
jQuery(document).ready(function($){

  $('#gun_sound').clone()[0].play();
  $('#gun_sound').clone()[0].play();
  $('#gun_sound').clone()[0].play();

});
</script>
Volomike
  • 21,378
  • 19
  • 99
  • 188