I have been trying for a long time to implement a crossfade to my html5 audio player that randomly plays a playlist. I have found this API Playlist crossfading that seems to be able to perfectly mix the audio between the two songs, overlapping the last 2 seconds. The code is the following:
var CrossfadePlaylistSample = {
FADE_TIME: 1, // Seconds
playing: false
};
CrossfadePlaylistSample.play = function() {
var ctx = this;
playHelper(BUFFERS.jam, BUFFERS.crowd);
function createSource(buffer) {
var source = context.createBufferSource();
var gainNode = context.createGain ? context.createGain() : context.createGainNode();
source.buffer = buffer;
// Connect source to gain.
source.connect(gainNode);
// Connect gain to destination.
gainNode.connect(context.destination);
return {
source: source,
gainNode: gainNode
};
}
function playHelper(bufferNow, bufferLater) {
var playNow = createSource(bufferNow);
var source = playNow.source;
ctx.source = source;
var gainNode = playNow.gainNode;
var duration = bufferNow.duration;
var currTime = context.currentTime;
// Fade the playNow track in.
gainNode.gain.linearRampToValueAtTime(0, currTime);
gainNode.gain.linearRampToValueAtTime(1, currTime + ctx.FADE_TIME);
// Play the playNow track.
source.start ? source.start(0) : source.noteOn(0);
// At the end of the track, fade it out.
gainNode.gain.linearRampToValueAtTime(1, currTime + duration-ctx.FADE_TIME);
gainNode.gain.linearRampToValueAtTime(0, currTime + duration);
// Schedule a recursive track change with the tracks swapped.
var recurse = arguments.callee;
ctx.timer = setTimeout(function() {
recurse(bufferLater, bufferNow);
}, (duration - ctx.FADE_TIME) * 1000);
}
};
CrossfadePlaylistSample.stop = function() {
clearTimeout(this.timer);
this.source.stop ? this.source.stop(0) : this.source.noteOff(0);
};
CrossfadePlaylistSample.toggle = function() {
this.playing ? this.stop() : this.play();
this.playing = !this.playing;
};
A demo of my player is this:
var reproductor = document.getElementById("audio");
function cargarCancion(numero){
// Carga la canción de forma dinámica
var source = reproductor;
source.src = lista[numero][0];
reproductor.load();
reproductor.play();
var titulo = document.getElementById("titulo");
titulo.innerHTML = lista[numero][1];
}
audio.addEventListener('timeupdate', (event) => {
if (audio.currentTime > (audio.duration - 1)){ // Finaliza el audio 1 seg. antes
cargarCancion(aleatorio()); // Recarga la lista para seguir reproduciendo
}
});
function aleatorio(){
return Math.round(Math.random() * (lista.length - 1));
}
// Inicio listado
var lista = [["http://www.sonidosmp3gratis.com/sounds/008576979_prev.mp3", "TEST UNO"],
["http://www.sonidosmp3gratis.com/sounds/short-circuit.mp3", "TEST DOS"],
["http://www.sonidosmp3gratis.com/sounds/whistle-campana-whatsapp.mp3", "TEST TRES"],
["http://www.sonidosmp3gratis.com/sounds/mario-bros%20vida.mp3", "TEST CUATRO"],
["http://www.sonidosmp3gratis.com/sounds/messenger-tono-mensaje-.mp3", "TEST CINCO"]];
// Fin listado
let listado = document.getElementById("listado");
for (let x of lista){
let item = document.createElement("li");
item.innerHTML = x[1];
listado.appendChild(item);
}
reproductor.addEventListener("ended", function(){
cargarCancion(aleatorio());
});
<audio id="audio"></audio>
<h3><div id="titulo"></div></h3>
<button id="play" onclick="cargarCancion(aleatorio());"> Play</button>
<ul id="listado"></ul>
I need help to know if it is possible to implement it in my audio player and how to do it. Any help I greatly appreciate in advance!!!
@Pablo Lozano, in my example, I start the timer with the variable var player = document.getElementById("audio"); and this is the code:
audio = document.getElementById('audio');
audio.addEventListener('play', play_evento, false);
audio.addEventListener('timeupdate', actualizar, false);
function play(){
audio.play();
}
function pause(){
audio.pause();
}
function stop(){
audio.pause();
audio.currentTime = 0;
}
function play_evento(){
document.getElementById('tiempo_actual').innerHTML = secToStr(audio.currentTime);
document.getElementById('tiempo_total').innerHTML = secToStr(audio.duration);
}
function actualizar(){
document.getElementById('tiempo_actual').innerHTML = secToStr(audio.currentTime);
document.getElementById('tiempo_total').innerHTML = secToStr(audio.duration);
}
function secToStr(sec_num){
sec_num = Math.floor(sec_num);
var horas = Math.floor(sec_num / 3600);
var minutos = Math.floor((sec_num - (horas * 3600)) / 60);
var segundos = sec_num - (horas * 3600) - (minutos * 60);
if (horas < 10) horas = '0'+horas;
if (minutos < 10) minutos = '0'+minutos;
if (segundos < 10) segundos = '0'+segundos;
var tiempo = minutos+':'+segundos;
return tiempo;
}
Now the problem arises that I don't know how to implement it in your code so that it shows me the elapsed playback time and the total, can you give me an idea? By the way, thanks for your interest.
You can do the following: detect when a song is ending and lower the volume and, at the same time, start the next one with another audio element with the volume at 0 and increase the volume for the duration of the crossfading time:
NOTE: I have not found two audios with an ending in which the change is very noticeable, but it should work from what you see in the console logs ;)