How to play multiple audio files one by one in html 5? - html5-audio

I would like to play multiple audio files one by one. I have read the same question, but I have found the links to the original answer not working and question unanswered.
Original answer
<audio id="mySound" controls><source src="http://www.hvalur.org/audio/uploaded_files/ds_umkomuleysi_0_0.mp3" type="audio/mpeg"></audio>
<audio id="mySound1" ><source src="http://www.hvalur.org/audio/uploaded_files/ds_ljosmyndavel_0_0.mp3" type="audio/mpeg"></audio>
I want the first sound started by the user action (pressing the play button) and then the following sound(s) playing one by one.
The usage of this example will be practising of understanding of the telephone numbers read by native speaker.

I would do something like that:
var mySound = document.getElementById("mySound");
var mySound1 = document.getElementById("mySound1");
var mySound2 = document.getElementById("mySound2");
var mySound3 = document.getElementById("mySound3");
var mySoundArray = [mySound, mySound1, mySound2, mySound3];
var mySoundArrayPos = 0;
var myButton = document.getElementById("myButton");
myButton.addEventListener("click", function(event) {
mySound.play();
mySoundArrayPos = 0;
startSoundTimer();
});
const startSoundTimer = () => {
var mySoundTimer = setInterval(() => {
if (mySoundArray[mySoundArrayPos].currentTime >= mySoundArray[mySoundArrayPos].duration) {
if (mySoundArrayPos < mySoundArray.length -1) {
mySoundArrayPos += 1;
mySoundArray[mySoundArrayPos].play();
} else {
clearInterval(mySoundTimer);
}
}
}, 10);
};
I don't know if the 10ms are a bit too fast, but I think, it's legit.

Javascript
=============== `playaudio(i) {
var thisme = this;
var audio = new Audio(thisme.model.audioFiles[i].audioUrl);
audio.play();
audio.addEventListener("ended", function () {
i = i + 1;
console.log(i);
if (i < thisme.model.audioFiles.length) {
audio.src = thisme.model.audioFiles[i].audioUrl;
audio.play();
}
}, false);
}
}`
HTML
====`<span class='chunkAudio' (click)="playaudio(0)">
<img class='playbtn' src="{{model.playerImageUrl}}" />
</span>`

Related

1 Volume controller for multiple players?

Is there an easy way to repeat this code to create a volume controller that works for 4 different players simultaneously? I've managed to get it to work for one player at any given point by changing the myAudio(x) value but any more than that seems to confuse it.
// Global variables and controls
var vid = document.getElementById("myVideo");
var volumeControl = document.getElementById("vol-control");
var setVolume = function(){
vid.volume = this.value / 100;
};
var audio = document.getElementById("myAudio(1)");
var volumeControl2 = document.getElementById("vol-control2");
var setVolume2 = function(){
audio.volume = this.value / 100;
};
//event listeners
volumeControl.addEventListener('change',setVolume);
volumeControl.addEventListener('input',setVolume);
volumeControl2.addEventListener('change',setVolume2);
volumeControl2.addEventListener('input',setVolume2);
Delegate
HTML
<div id="audvid">
<video.../>
<audeo.../>
</div>
event listeners
document.getElementById("audvid").addEventListener("change", setVolume)
document.getElementById("audvid").addEventListener("input", setVolume)
change whatever is accessed
const setVolume = function(e) {
const tgt = e.target;
if (["AUDIO", "VIDEO"].includes(tgt.tagName)) {
tgt.volume = tgt.value / 100;
}
};
change any audio/video
const setVolume = function(e) {
const tgt = e.target;
[...document.querySelectorAll("AUDIO", "VIDEO")].forEach(ele => {
ele.volume = tgt.value / 100;
})
};

Audio Level Meter for Web RTC Stream

I would like to create a decibel meter for the audio that is playing in a video element. The video element is playing a WebRTC stream.
At the moment WebRTC streams cannot be passed into a Web Audio Analyzer. (Although this might change soon … ) (see Web Audio API analyser node getByteFrequencyData returning blank array)
Is there currently another way to get decibel information from a remote mediastream?
Chrome 50 was released: As of the 13th of April 2016 using an Analyser Node with a MediaStreamAudioSourceNode works fine to get audio levels. The resulting audioLevels value can be animated or simply passed into a html meter element.
var _mediaStream = SOME_LOCAL_OR_RTP_MEDIASTREAM;
var _audioContext = new AudioContext();
var _audioAnalyser = [];
var _freqs = [];
var audioLevels = [0];
var _audioSource = _audioContext.createMediaStreamSource(_mediaStream);
var _audioGain1 = _audioContext.createGain();
var _audioChannelSplitter = _audioContext.createChannelSplitter(_audioSource.channelCount);
_audioSource.connect(_audioGain1);
_audioGain1.connect(_audioChannelSplitter);
_audioGain1.connect(_audioContext.destination);
for (let i = 0; i < _audioSource.channelCount; i++) {
_audioAnalyser[i] = _audioContext.createAnalyser();
_audioAnalyser[i].minDecibels = -100;
_audioAnalyser[i].maxDecibels = 0;
_audioAnalyser[i].smoothingTimeConstant = 0.8;
_audioAnalyser[i].fftSize = 32;
_freqs[i] = new Uint8Array(_audioAnalyser[i].frequencyBinCount);
_audioChannelSplitter.connect(_audioAnalyser[i], i, 0);
}
function calculateAudioLevels() {
setTimeout(() => {
for (let channelI = 0; channelI < _audioAnalyser.length; channelI++) {
_audioAnalyser[channelI].getByteFrequencyData(_freqs[channelI]);
let value = 0;
for (let freqBinI = 0; freqBinI < _audioAnalyser[channelI].frequencyBinCount; freqBinI++) {
value = Math.max(value, _freqs[channelI][freqBinI]);
}
audioLevels[channelI] = value / 256;
}
requestAnimationFrame(calculateAudioLevels.bind(this));
}, 1000 / 15); // Max 15fps — not more needed
}
This is a good example:
https://webrtc.github.io/samples/src/content/getusermedia/volume/
And this is the source code:
https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/volume
And this is a sample:
function recordAudio() {
try {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.audioContext = new AudioContext();
const instantMeter = document.querySelector('#sound-meter');
const constraints = {'video': false, 'audio': true};
const stream = await navigator.mediaDevices.getUserMedia(constraints);
window.stream = stream;
const soundMeter = window.soundMeter = new SoundMeter(window.audioContext);
soundMeter.connectToSource(stream, function(e) {
if (e) {
alert(e);
return;
}
setInterval(() => {
instantMeter.value = soundMeter.instant.toFixed(2);
}, 200);
});
$('#sound-meter').show();
$('#audio-icon').hide()
} catch(error) {
console.error('Error recording audio.', error);
}
}

audio won't work on safari browser

could someone please help me to find out why this won't work on safari browser? It seems to work really well in all other browsers apart from Safari. I really could not work it out.
Any help will be most appreciated.
function loadPlayer()
{
var audioPlayer = new Audio();
audioPlayer.controls="";
audioPlayer.setAttribute("data-index", -1); //set default index to -1.
audioPlayer.addEventListener('ended',nextSong,false);
audioPlayer.addEventListener('error',errorFallback,true);
document.getElementById("player").appendChild(audioPlayer);
}
function nextSong(index, e)
{
var next;
var audioPlayer = document.getElementsByTagName('audio')[0];
//check for index. If so load from index. If not, index is defined auto iterate to next value.
if (index >= 0)
{
next = index;
}
else
{
next = parseInt(audioPlayer.getAttribute("data-index"))+1;
next >= urls.length ? next = 0 : null;
}
audioPlayer.src=urls[next][0]; //load the url.
audioPlayer.setAttribute("data-index", next);
//disable the player.
var audioPlayerControls = document.getElementById("playerControls");
audioPlayer.removeEventListener('canplay',enablePlayerControls,false);
audioPlayerControls.setAttribute("disabled", true);
audioPlayer.addEventListener('canplay',enablePlayerControls,false);
audioPlayer.load();
//show the image:
var image = document.getElementById("playerList").querySelectorAll("a")[next].querySelector("img").cloneNode();
image.style.width = "30px";
if(audioPlayerControls.querySelector("img"))
{
audioPlayerControls.replaceChild(image, audioPlayerControls.querySelector("img"));
}
else
{
audioPlayerControls.insertBefore(image, audioPlayerControls.querySelector("a"));
}
}
function enablePlayerControls()
{
//File has loaded, so we can start playing the audio.
//Enable the player options.
var audioPlayer = document.getElementsByTagName('audio')[0];
audioPlayer.removeEventListener('canplay',enablePlayerControls,false);
document.getElementById("playerControls").removeAttribute("disabled");
audioPlayer.play();
}
function errorFallback() {
nextSong();
}
function playPause()
{
var audioPlayer = document.getElementsByTagName('audio')[0];
if (audioPlayer.paused)
{
audioPlayer.play();
} else
{
audioPlayer.pause();
}
}
function pickSong(e)
{
//we want the correct target. Select it via the event (e).
var target;
//pickSong does the selecting:
if (e && e.target && e.target.tagName && e.target.tagName.toLowerCase() == "img")
{
//The event target = the img element.
target = e.target.parentElement;
}
else
{
//the event target is the a element
target = e.target;
}
var index = target.getAttribute("data-index"); //get the song index stored in the data-index attribute.
nextSong(index);
}
var urls = new Array();
urls[0] = ['http://mp3lg4.tdf-cdn.com/9079/jet_143844.mp3', 'http://radio-maghreb.net/radio/radio almazighia.png'];
urls[1] = ['http://mp3lg4.tdf-cdn.com/9077/jet_143651.mp3', "http://radio-maghreb.net/radio/alwatania.png"];
urls[2] = ['http://mp3lg4.tdf-cdn.com/9080/jet_144136.mp3', "http://radio-maghreb.net/radio/inter.jpg"];
function startAudioPlayer()
{
loadPlayer();
for (var i = 0; i < urls.length; ++i)
{
//this for loop runs through all urls and appends them to the player list. This smooths the adding off new items. You only have
//to declare them in the array, the script does the rest.
var link = document.createElement("a");
link.href = "javascript: void(0)";
link.addEventListener("click", pickSong, false);
link.setAttribute("data-index", i);
link.img = document.createElement("img");
link.img.src = urls[i][1];
link.appendChild(link.img);
document.getElementById("playerList").appendChild(link);
}
}
//Event that starts the audio player.
window.addEventListener("load", startAudioPlayer, false);
#playerControls[disabled=true] > a{
color: #c3c3c3;
}
<span id="playerControls" disabled="true">
Play
Stop
</span>
Next Track
<!-- player ends -->
<br>
<br>
<!-- img links start -->
<div id="playerList">
</div>

Weird behaviour with fabric.util.loadImage() when looping through objects loaded via loadFromJSON()

In order to try and get around the odd issue in having with CORS (here) I am attempting to reload any images loaded via canvas.loadFromJSON()
But, I am experiencing weird issues. Sometimes only one image is replaced, other times I get duplicates of one image.
Here is my code:
canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
var objArray = canvas.getObjects();
for (var i = 0; i < objArray.length; i++) {
canvas.setActiveObject(objArray[i]);
var activeObject = canvas.getActiveObject();
if(activeObject.type === 'image') {
fabric.util.loadImage(activeObject.src, function(img) {
var object = new fabric.Image(img);
object.hasControls = true;
object.lockUniScaling = true;
object.scaleX = activeObject.scaleX;
object.scaleY = activeObject.scaleY;
object.originX = activeObject.originX;
object.originY = activeObject.originY;
object.centeredRotation = true;
object.centeredScaling = true;
canvas.add(object);
}, null, {crossOrigin: 'Anonymous'});
canvas.remove(activeObject);
}
activeObject.setCoords();
}
canvas.deactivateAll();
canvas.renderAll();
canvas.calcOffset();
});
Any ideas why I'm getting these weird issues?
First glance at your code I don't see anything wrong... But I'm also thinking the code might be a bit inefficient? Is there a need to create a new image instance?
I believe you should be able to just set the crossOrigin property on the image object.
This code is untested, but I'd try something like this:
canvas.loadFromJSON(<?php echo json_encode($objects); ?>, function() {
var objArray = canvas.getObjects();
for (var i = 0; i < objArray.length; i++) {
canvas.setActiveObject(objArray[i]);
var activeObject = canvas.getActiveObject();
if(activeObject.type === 'image') {
activeObject.crossOrigin = 'Anonymous';
}
}
canvas.deactivateAll();
canvas.renderAll();
canvas.calcOffset();
});
I had the same problem and overcome it downloading again the image then reassign it to object._element once each fabric object was created using loadFromJSON.
export const getImage = url => {
return new Promise((resolve, reject) => {
let img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.setAttribute('crossOrigin', 'anonymous');
img.src = url;
});
}
canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), async (o, object) => {
if (object.type === "image") {
let imagecore = await getImage(object.src);
object._element = imagecore;
}
});

Randomly choose track from jquery html5 audio playlist on page refresh

I'm building an audio player for a web experience, that has a list of tracks. Here is the code controlling the audio player.
$( document ).ready(function() {
jQuery(function($) {
var supportsAudio = !!document.createElement('audio').canPlayType;
if(supportsAudio) {
var index = 0,
playing = false;
mediaPath = 'audio/',
extension = '',
tracks = [
{"track":1,"name":"track1","length":"00:55","file":"track1"},
{"track":2,"name":"track2","length":"00:55","file":"track2"},
{"track":3,"name":"track3","length":"00:55","file":"track3"},
{"track":4,"name":"track4","length":"00:55","file":"track4"},
{"track":5,"name":"track5","length":"00:55","file":"track5"}
],
trackCount = tracks.length,
npAction = $('#npAction'),
npTitle = $('#npTitle'),
audio = $('#audio1').bind('play', function() {
playing = true;
npAction.text('Now Playing:');
}).bind('pause', function() {
playing = false;
npAction.text('Paused:');
}).bind('ended', function() {
npAction.text('Paused:');
if((index + 1) < trackCount) {
index++;
loadTrack(index);
audio.play();
} else {
audio.pause();
index = 0;
loadTrack(index);
}
}).get(0),
li = $('#plUL li').click(function() {
var id = parseInt($(this).index());
if(id !== index) {
playTrack(id);
}
}),
loadTrack = function(id) {
$('.plSel').removeClass('plSel');
$('#plUL li:eq(' + id + ')').addClass('plSel');
npTitle.text(tracks[id].name);
index = id;
audio.src = mediaPath + tracks[id].file + extension;
},
playTrack = function(id) {
loadTrack(id);
audio.play();
};
extension = audio.canPlayType('audio/mpeg') ? '.mp3' : audio.canPlayType('audio/ogg') ? '.ogg' : '';
loadTrack(index);
}
});
});
Is there a way to reorder the list inside of the variable named tracks? Generating the list of 1 through 5 in a random pull? for example, the items named track2 track3 track4 ect. could potentially be played first? I'm looking for that to be random on a page refresh.
Thanks for the help!
You could add a playOrder field to the tracks variable, and have a function go through each on on load and assign it a random unused playOrder number.