Reputation: 32354
I'm making a game, in which sounds are often played. I noticed that a sound wont play again while it is being played. For example, the player collides with a wall, a "thump" sound is played. But, if the player collides with one wall, and then quickly collides with another wall, only one "thump" sound is played, and I believe that this happens because the first sound didn't finish. Is that true? How should I avoid this? I thought of preloading the sound three times, always playing a different copy of that sound, but this seems rather stupid...
SOLVED:
Turns out I was right... You need to preload multiple versions of the sound and then circularly play them.
THE CODE:
var ns = 3; //The number of sounds to preload. This depends on how often the sounds need to be played, but if too big it will probably cause lond loading times.
var sounds = []; //This will be a matrix of all the sounds
for (i = 0; i < ns; i ++) //We need to have ns different copies of each sound, hence:
sounds.push([]);
for (i = 0; i < soundSources.length; i ++)
for (j = 0; j < ns; j ++)
sounds[j].push(new Audio(sources[i])); //Assuming that you hold your sound sauces in a "sources" array, for example ["bla.wav", "smile.dog" "scream.wav"]
var playing = []; //This will be our play index, so we know which version has been played the last.
for (i = 0; i < soundSources.length; i ++)
playing[i] = 0;
playSound = function(id, vol) //id in the sounds[i] array., vol is a real number in the [0, 1] interval
{
if (vol <= 1 && vol >= 0)
sounds[playing[id]][id].volume = vol;
else
sounds[playing[id]][id].volume = 1;
sounds[playing[id]][id].play();
++ playing[id]; //Each time a sound is played, increment this so the next time that sound needs to be played, we play a different version of it,
if (playing[id] >= ns)
playing[id] = 0;
}
Upvotes: 12
Views: 10783
Reputation: 11221
class SoundPool {
pool : HTMLAudioElement[] = [];
constructor(sound:HTMLAudioElement) {
this.pool.push(sound);
}
play() {
let found = false;
for(var i=0; i<this.pool.length; i++) {
if( this.pool[i].paused) {
this.pool[i].play();
found=true;
break;
}
}
if(!found) {
let a = this.pool[0].cloneNode() as HTMLAudioElement;
a.play();
this.pool.push(a);
}
}
}
Upvotes: 0
Reputation: 71
You can clone the audio element. I don't know if you can play them more than once simultaneously, but here is how you can play a sound more than once without downloading it more than once.
var sound = document.getElementById("incomingMessageSound")
var sound2 = sound.cloneNode()
sound.play()
sound2.play()
I know this works for chrome, which is the only place I needed it. Good luck!
Upvotes: 7
Reputation: 24136
Although it is only implemented in FireFox and Chrome right now, in the future you should use the WebAudio API, which is specifically designed for games and audio applications in the browser.
There you can play back any sound multiple times and do several other fun stuff with it.
A good tutorial for that is here: http://www.html5rocks.com/en/tutorials/webaudio/games/
Upvotes: 1
Reputation: 115910
Yes, a single <audio>
object can only play one track at a time. Consider that the <audio>
object has a currentTime
attribute that indicates the current position of the audio track: if an <audio>
object could play multiple tracks are once, what value would currentTime
reflect?
See my solution for a superset of this problem on Is playing sound in Javascript performance heavy?. (Basically, add duplicate <audio>
tags with the same sound.)
Upvotes: 1
Reputation: 4291
Load the sound several times to simulate polyphony. Play them in round-robin fashion. Check out my demo at matthewtoledo.com. Specifically, the function _initSoundBank()
Upvotes: 2