I am needing to add a volume slider to my javascript player, and I have tried it this way:
//Slider control de volumen
let volume = document.getElementById('volume');
volume.addEventListener("change", function(e) {
source.volume = e.currentTarget.value / 100;
})
<input type="range" id="volume">
The problem that appears to me is that once the volume is adjusted, it works correctly, but when the fader is made between songs, the volume is no longer active as it has been adjusted, my question is, how can I get the volume to Once adjusted from the bar, is it constant once the songs change? Is it possible? I leave player code:
let play2 = false;
const fading= 10; // segundos de crossfading
function time_convert(num)
{
var hours = Math.floor(num / 60);
var minutes = num % 60;
return hours + ":" + minutes;
}
function cargarCancion(numero) {
// Carga la canción de forma dinámica
var source = new Audio(lista[numero][0]);
source.load();
source.play();
var titulo = document.getElementById("titulo");
titulo.innerHTML = lista[numero][1];
//mientras esta sonando...
source.addEventListener('timeupdate', (event) => {
let time1 = parseInt(source.currentTime)
let time2 = parseInt(source.duration)
document.getElementById("time").innerHTML =
time_convert(time1) + "/" + time_convert(time2);
//let volume = 1; //max
//Slider control de volumen
let volume = document.getElementById('volume');
volume.addEventListener("change", function(e) {
source.volume = e.currentTarget.value / 100;
})
// si estamos empezando y hay dos canciones sonando,
// el volumen empieza en cero y va subiendo
if (source.currentTime < fading && play2) {
volume = source.currentTime / fading;
console.log('Volumen subiendo');
} else if (source.currentTime > (source.duration - fading)) {
// ¿Ha empezado otra canción?
if (!play2) {
cargarCancion(aleatorio()); // Si no, carga la siguiente canción
play2 = true; //ya hay dos!
}
// estamos bajando el volumen...
volume = 1 - (source.duration - source.currentTime) / fading;
console.log('Volumen bajando');
}
source.volume = volume;
});
//canción terminada, no hay dos canciones a la vez sonando
source.addEventListener('ended', () => play2=false);
}
function aleatorio(){
return Math.round(Math.random() * (lista.length - 1));
}
var lista = [["https://storage.googleapis.com/media-session/sintel/snow-fight.mp3", "TEST UNO"],
["https://storage.googleapis.com/media-session/big-buck-bunny/prelude.mp3", "TEST DOS"]];
// Fin listado
let listado = document.getElementById("listado");
for (let x of lista){
let item = document.createElement("li");
item.innerHTML = x[1];
listado.appendChild(item);
}
<h3>
<div id="titulo"></div>
</h3>
<button id="play" onclick="cargarCancion(aleatorio());">Play</button>
<ul id="listado"></ul>
<div id="time"></div>
<input type="range" id="volume">
Thank you and I look forward to any help or suggestion.
As I understand it, you want the songs to intersect at one point and that at the beginning and end of each song there is a variation in volume
We will call the interval where the volume variation will exist: "Fader_Duration"
Then we have to understand the issue of volume, where there are up to 3 different ones:
Audio1 and Audio2 are modified according to the currentTime of the audio. This modification is conditional on the current volume.
For example, if you defined that the fade reaches volume 0.2, but the current volume is 0.1, you would be raising the volume to the user, which is not what is desired. So the equation to determine the volume and fading of an audio must have the current volume as a variable.
1) Method by javascript
With this method we will obtain a linear variation
Where I created the following structure:
where Fader_hasta indicates that the volume is raised at the beginning from 0.3 to the current volume. And at the end of the audio from the current to Fader_until. You can place from 0 to 1.
We must consider that the volume of an audio will behave as follows:
Where we can separate the behavior into 3 linear functions
And here we apply some mathematics: The formula of a linear function is given by: y = mx + b Where:
So our first linear function is: (remember that Actual is the volume set by the user)
The second function, has no slope, is always the current volume
The third function is:
With this, we complete the structure:
So the Volume.GetVolume function is the function you needed. It receives as parameters the duration of the audio and the current time of the audio. And it returns the volume it should have,
The rest of the code with some minor changes
2) Alternative method by CSS
With this method we use CSS (animations) to obtain the variation, the benefit of this method is that we can make the variation as a curve, that is, we could make the volume start to decrease slowly and increase faster when reaching the end
For this I will use CSS Houdini , unfortunately this method is not supported by all browsers and it is not supported by Stackoverflow either, so the "run" button does not work.
There are two things to correct in your code. One is the way you handle the current volume to adjust transitions to it. The other is the way you turn down the volume, you're misjudging the fade.
To correct the first one you must properly obtain the value of the current volume by means of the following instruction:
So that in the end this assignment is consistent:
And now we can calculate the volume by multiplying the same thing that you calculated before by the maximum that it can reach:
And also:
Fíjate que esta última línea te la he cambiado y le he quitado el
1 -
que tenías, ya que al ir avanzando hacia la duración, el valor va disminuyendo, por lo que no es necesario hacer el1 -
al valor calculado.Para comprobar esto último he agregado a los
console.log
el valor del volumen para que veas que ahora sí que se reduce paulatinamente y si le agregas tu resta anterior lo que hace es subir.Puedes ver el código funcionando a continuación:
PD: No es necesario obtener el valor de
volume
a través de ungetElementById("volume")
. Te recuerdo que el DOM genera una variable en el ámbito global y enwindow
con el nombre de cada elemento con una propiedadid
definida.Aunque ya tienes una respuesta al problema, y tal como digo en mi comentario, es posible hacerlo guardando el estado del volumen. Sin embargo, y si estoy entendiendo bien tu pregunta, tu código tiene algunos detalles de implementación que mejorar.
En primer lugar, y basado en mi experiencia, es mejor usar los eventos del elemento multimedia (audio o video). De esta forma el control que ganamos sobre la aplicación es mayor.
Por otro lado, la forma de calcular el volumen no es correcta. El volumen de cualquier elemento multimedia, es un valor flotante entre 0 y 1 (ambos incluidos). Para calcular este valor, usando una barra tipo
slide
como la que muestras en tu pregunta, debes convertir el rango de amplitud de la misma en un rango entre 0 y 1.Por último, y dado que deseas encadenar 2 canciones (audio) con un efecto
fade in
yfade out
, podrías usar una cola de máximo 2 elementos, que permiten reproducir los 2 audios al mismo tiempo. Uno de ellos (el que está finalizando) ejecutará el efectofade out
y el otro hará el efectofade in
.Los eventos del elemento de audio que usaremos serán:
timeupdate
con este evento sabremos en qué momento aplicar el efecto defade-in
/fade-out
y podremos calcular el tiempo transcurrido para mostrarlo en pantalla.canplaythrough
con este evento podemos comenzar la reproducción de un nuevo elemento multimedia creado cuando tenemos la certeza que la misma puede llevarse a cabo de forma contínua (suficientes datos en el buffer).ended
con este evento podemos determinar cuando una pista de audio ha terminado su reproducción y procedemos a sacarla de la lista.Cuando hablo de cola, me refiero a crear una lista de rerpoducción que permita una cantidad de pistas reproduciéndose al mismo tiempo. Como se desea hacer un efecto de entrada y salida entre 2 pistas de audio durante un tiempo determinado, esta será la cantidad máxima de pistas de audio que contendrá nuestra lista durante un tiempo determinado.
Además, le he dado una utilidad un poco más grande al botón de reproducción. No sólo permite reproducir la pista, sino que puedes pausar la reproducción al volver a hacer clic en el mismo.
He tratado de evitar cambios en el aspecto actual en tu pregunta para enfocarme en lo esencial.
Volúmen
Para calcular el volúmen dado el valor actual del
slider
, utilizo el valor máximo del elementslider
o 100 si el mismo no está definido en el elemento. Así, si deseo un valor entre 0 y 1 que sea aceptado por el elemento de audio, simplemente debo dividir el valor actual delslider
entre el valor máximo del mismo.Por ejemplo:
En el código anterior puedo reutilizar la función que captura el cambio en el
slider
. La idea es mostrar cómo obtener el valor correcto del volumen del audio basados en dos propiedades delslider
, que son su valor actual y su valor máximo.Timeupdate
La parte de lógica que puede llegar a costar trabajo de entender es la que se produce cuando hay un cambio en la propiedad
currentTime
. Basicamente lo que haremos cuando se dispara este evento es calcular el volumen de forma progresiva tanto para el efectofade-in
como para el efectofade-out
. Este incremento y decremento es practicamente "lineal" (no entraré en detalles sobre los tipos de transformaciones que se pueden aplicar).Pero para poder aplicar esta transformación "lineal" al efecto, debemos realizar algunos cálculos no tan complicados. En estos cálculos, capturamos el volumen indicado por el
slider
durante el tiempo que dure el efecto, incrementando su valor desde cero hasta el valor que indica elslider
y viceversa en cada pista de audio, según la misma esté entrando o saliendo de la cola.En cada cambio de
currentTime
detectado, calcularemos el volumen de la siguiente forma:en ambos casos,
currentVolume
se refiere al volúmen actual calculado para el audio usando el método visto anteriormente:El efecto de
fade-in
yfade-out
se aplicará detectando si estamos en los primeros segundos de reproducción o en los últimos:Finally, only once will we verify that the volume of the track is indicated by the
slider
, otherwise we must adjust it, since the volume calculation will never be exact as we are doing it here.With this clear, every time an audio track starts playing, its volume will be adjusted from 0 to the volume indicated by
slider
it for the duration of the effect, and when the track is about to end, the same thing will happen but in reverse. .The complete code may look similar to the following:
I hope this helps you solve the problem.