Playing audio files in javascript - javascript

I have many small audio files, and I want to play these files one after another, not all of them at the same time. I have used the object Audio in javascript like this
var audio_1 = new Audio();
var audio_2 = new Audio();
var audio_3 = new Audio();
audio_1.src = "/path1";
audio_2.src = "/path2";
audio_3.src = "/path3";
Now I just need to call the function play for every object, but I need to play the audio_1 alone, and play audio_2 when the first one ended.
The solution I found is to test on the property ended of every object
audio_1.ended; // returns true when it ends playing
I found an object onended inside the audio object, I thought it's a function but it's not, can someone help me and give me the best way to solve this problem.

use addEventListener instead of assigning a function to the onended property:
audio.addEventListener('ended', function() {}); // Do
audio.onended = function() {}; // Don't
So, a IMHO dirty way is this:
audio_1.play();
audio_1.addEventListener('ended', function() {
audio_2.play();
audio_2.addEventListener('ended', function() {
audio_3.play();
};
};

Related

Better way to call new Audio();

I am making game in browser and use sound effects for example shot, explosion and for every generated instance of classes there is also creating new Audio object which is eating memory so much and app is crashing after 2/3 minutes thats mean is getting very slow. Is any better way to do this? Maybe creating new Audio() in another place but just once and call it when need, not every time when generating new enemy, bullet etc.
For example:
class Bullet extends Common {
constructor() {
this.element = document.createElement("div");
this.audio = new Audio("./audio/LaserShot.wav");
}
And in upper class Spaceship I call it every time I shot pressing space:
executeShot() {
const bullet = new Bullet(this.getCurrentPosition(), this.element.offsetTop, this.area);
bullet.init();
this.bullets.push(bullet);
}
Not sure if this works great in all scenario, but you can try the following code, and see if it works.
<button class="btn">Click</button>
class AudioService {
constructor(initialsetup = 1) {
this._audios = [];
for (let i = 0; i < initialsetup; i++) {
this._audios.push(new Audio());
}
}
/**
* use to get available audio
*/
_getAudioElemToPlay() {
const audios = this._audios.filter(audio => {
// if the audio is empty, without a valid url or if the audio is ended
// TODO: not sure if these attributes are more than enough
return !audio.duration || audio.ended;
});
console.log('audios', audios);
if (audios.length == 0) {
const audio = new Audio();
this._audios.push(audio);
return audio;
}
return audios[0];
}
playAudio(url) {
const player = this._getAudioElemToPlay();
player.src = url;
player.load();
player.play();
}
}
const audioService = new AudioService();
let index = 0;
document.querySelector('.btn').addEventListener('click', function() {
index++;
const audioList = new Array(12).fill(0).map((value, index) => {
return `https://www.soundhelix.com/examples/mp3/SoundHelix-Song-${index}.mp3`;
});
audioService.playAudio(audioList[index % audioList.length]);
})
Here is the link to run the above code, https://codepen.io/hphchan/pen/xxqbezb.
You may also change the audio to other audio as you like.
My main idea to solve the issue, is by reusing the audio element created, by having an array to store it, and reuse the element once it finish playing.
Of course, for the demo, I am playing the audio by using a click button. But definitely, you can plug it into your game.
Hope the solution may help you. In case there are any cases not covering, as I have not much exposure to this area, it would be nice if you can post your modified solution here, so we can all learn together.
Have you looked at the Web Audio API? If it works for you, a single AudioBuffer can hold the audio data in memory for a given cue, and you can play it multiple times by spawning AudioBufferSourceNode objects. If you have many different sounds playing, this might not be much help, but if you are reusing sounds continuously (many laser shots), this could a big help. Another benefit is that this way of playing sounds is pretty low latency.
I just used this for the first time, getting it to work yesterday. But I'm loading it with raw PCM data (floats ranging from -1 to 1). There is surely a way to load this or an equivalent in-memory structure with a wav, but I'm too new to the API to know yet how to do this.

How to play many audio files in sequence

I have several long stories which for which the source audio is sentence-by-sentence audio files. I would like to create a web page where one could listen to individual sentences of a particular story many times, or listen to the whole story from start to finish.
To start, my web page has many <audio> elements, each of which is in a <p> with the corresponding text. Each of these <audio> elements corresponds to a single sentence of the story.
I was about to start coding up a javascript object which was going to allow some sort of "play all" functionality, you'd click the button and it would play audio[0], when that finished, audio[1], etc. It would also have a 'pause' button and keep track of where you were, etc. This way the individual sentences could still be played or enjoyed because they each have an audio element. Or, one could use my "play all" buttons at the top to treat the sequence of audio elements as if they were one big element.
Then I started asking myself if there's some better/easier/more canonical solution here. One thing I thought of doing would be to cat all of these individual audio files together into a big audio file and perhaps create 'chapter' <track> elements. Is this preferable?
What are the pros and cons to each approach? Is there some out-of-the-box solution already made for me which I simply haven't turned up?
You could use the ended event to play the next sound when the previous sound completes (Playing HTML 5 Audio sequentially via Javascript):
var sounds = new Array(new Audio("1.mp3"), new Audio("2.mp3"));
var i = -1;
playSnd();
function playSnd() {
i++;
if (i == sounds.length) return;
sounds[i].addEventListener('ended', playSnd);
sounds[i].play();
}
function playAudio(src) {
var audioElement = new Audio(src);
audioElement.play();
return audioElement
}
const sequences = ['./audio/person.m4a', './audio/4.m4a', './audio/5.m4a', './audio/6.m4a', './audio/6.m4a', './audio/6.m4a', './audio/room.m4a', './audio/3.m4a']
// play audio
let index = 0
const audioElement = playAudio(sequences[index])
audioElement.addEventListener('ended', (e) => {
index++
if (index < sequences.length) {
audioElement.src = sequences[index]
audioElement.play();
}
})
I use javascript to solve the problem, using Audio objects and a setInterval. Below an example:
var sndLetItSnow = new Audio("audio/letItSnow.m4a");
var sndSanta = new Audio("audio/snow.m4a");
var playlist = [sndLetItSnow, sndSanta];
var current = null;
var idx = 0;
function playSound() {
if (current === null || current.ended) {
// go to next
current = playlist[idx++];
// check if is the last of playlist and return to first
if (idx >= playlist.length)
idx = 0;
// return to begin
current.currentTime=0;
// play
current.play();
}
}
setInterval(playSound, 1000);
For more documentation on Audio object you can visit this page:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
I hope this help!

How to stop a video using stop function?

Alright, I have very little programming experience and just want to make controls for video and audio pieces together on one page. I have searched a lot and can't figure it out.
var stop = function (id) {
.pause();
.src = '';
};
I want to pass either the audio or videos' id as the parameter in my function but I don't understand how make code that can be used with either. I can't put id.pause(); into my function to pause whatever id I put in as a parameter, so I'm confused as to how to make it work. Any help is appreciated!!
You could use JQuery:
$('#playMovie1').click(function(){
$('#movie1').get(0).play();
});
Or you could do something like this:
function playVid(x) {
var vid = document.getElementById(x).pause();
}
You can use
var stop = function (htmlId) {
var vid = document.getElementById(htmlId);
vid.pause();
};
If you are passing the id then use that id to pause or play
var stop = function (id) {
$('#'+id).pause(); // to pause the video
.src = '';
};

Chrome issue changing source of audio element when using AudioContext

The Audio sound is distorded (like playing twice at the same time or something like that) when I change its source dynamically, if the element was used in the createMediaElementSource of an AudioContext.
Here is a minimalist example of the error: http://jsfiddle.net/BaliBalo/wkFpv/ (It works well at first but it is going crazy when you click a link to change the source).
var audio = document.getElementById('music');
var actx = new webkitAudioContext();
var node, processor = actx.createScriptProcessor(1024, 1, 1);
processor.onaudioprocess = function(e) { /* STUFF */ };
processor.connect(actx.destination);
audio.addEventListener('canplay', canPlayFired);
function canPlayFired(event)
{
node = actx.createMediaElementSource(audio);
node.connect(processor);
audio.removeEventListener('canplay', canPlayFired);
}
$('a.changeMusic').click(function(e){
e.preventDefault();
audio.src = $(this).attr('href');
});
If I put node.disconnect(0); before audio.src = ... it works but the data is no more processed. I tried a lot of thing like creating a new context but it seems not to erase the previously set javascript node.
Do you know how I could fix it ?
Thanks in advance.
I would suggest taking a look at this: jsbin.com/acolet/1
It seems to be doing the same thing you are looking for.
I found this from this post.

Javascript method pause() only works with audio element

So I have a function like this:
function music(song) {
var audio = new Audio("audio/" + song + ".ogg");
audio.play();
}
And the problem I'm having is that audio.play() works perfectly, but if I try audio.pause() later (after defining the same variable), it doesn't work. However, if I do this:
function music() {
var audio = document.getElementById("songname");
audio.play();
}
Then I can define the variable and later use audio.pause() to pause the track. The problem is that I want to do this within javascript because I have a lot of tracks and I don't want to create audio elements for each one.
Why doesn't the first piece of code allow me to pause the audio later? Is there any way I can let it pause the audio later? If not, are there any alternatives that involve playing the audio from javascript by passing a parameter which is the song title? I don't want to have to include the src in the html.
I suspect that jQuery might have an easy solution for this but form what I've researched I couldn't find anything.
audio only exists inside the function. if you need access to it outside the function then return the instance of the Audio object you are creating:
function getAudio(song, play) {
var audio = new Audio("audio/" + song + ".ogg");
if(play) {
audio.play();
}
return audio;
}
var theTrack = getAudio('my_song', true);
theTrack.pause(); // pause the song
theTrack.play(); // play the song
The second example refers to what i assume is an audio element which in turn exposes the functionality of the Audio object. The reason the second function works anywhere is because the DOM element is always present in the DOM and you are referencing that to get at the underlying Audio API, as opposed to a using the Audio object/API directly.
I just tested a snippet and it works as such
function music(song) {
var audio = new Audio("audio/" + song + ".ogg");
audio.play();
setTimeout(function() { audio.pause(); }, 5000);
}
You can create the audio variable before defining the function.
var audio = new Audio();
function playMusic(song) {
audio.src = "audio/" + song + ".ogg";
audio.play();
}
function pauseMusic() {
audio.pause();
}

Categories