184 lines
5.8 KiB
JavaScript
184 lines
5.8 KiB
JavaScript
// 1. Sélection des éléments du DOM
|
||
const vinyl = document.getElementById('vinyl');
|
||
const audioForward = document.getElementById('audio-forward');
|
||
const audioReverse = document.getElementById('audio-reverse');
|
||
const progress = document.getElementById('progress');
|
||
const currentTimeEl = document.getElementById('currentTime');
|
||
const durationEl = document.getElementById('duration');
|
||
const backwardBtn = document.getElementById('backward');
|
||
const forwardBtn = document.getElementById('forward');
|
||
const loopBtn = document.getElementById('loop');
|
||
|
||
// 2. Variables utiles
|
||
let isPlaying = false;
|
||
let isLooping = false;
|
||
let lastPosition = 0;
|
||
let stopTimeout = null;
|
||
|
||
// socket.io & arduino serial info
|
||
const socket = io();
|
||
|
||
const MIN_SPEED = 0.1; // seuil minimal pour commencer la lecture
|
||
const MAX_SPEED = 2; // vitesse max
|
||
const SENSITIVITY = 0.01; // ajuste la sensibilité du mapping
|
||
|
||
// Fonction pour formater le temps (min:sec)
|
||
function formatTime(time) {
|
||
const minutes = Math.floor(time / 60);
|
||
const seconds = Math.floor(time % 60);
|
||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||
}
|
||
|
||
// Mise à jour de la barre de progression à partir de la piste active
|
||
function updateProgress() {
|
||
let activeAudio = isPlaying ? (audioForward.paused ? audioReverse : audioForward) : null;
|
||
if (activeAudio && activeAudio.duration) {
|
||
const progressPercent = (activeAudio.currentTime / activeAudio.duration) * 100;
|
||
progress.value = progressPercent;
|
||
currentTimeEl.textContent = formatTime(activeAudio.currentTime);
|
||
durationEl.textContent = formatTime(activeAudio.duration);
|
||
}
|
||
}
|
||
|
||
// Met à jour l’animation du vinyle selon lecture en cours
|
||
function updateVinylAnimation() {
|
||
if (!audioForward.paused || !audioReverse.paused) {
|
||
vinyl.style.animationPlayState = 'running';
|
||
} else {
|
||
vinyl.style.animationPlayState = 'paused';
|
||
}
|
||
}
|
||
|
||
// Fonction pour arrêter les deux audios
|
||
function stopAudio() {
|
||
audioForward.pause();
|
||
audioReverse.pause();
|
||
isPlaying = false;
|
||
updateVinylAnimation();
|
||
}
|
||
|
||
// Fonction pour contrôler la lecture en fonction de la vitesse (peut être négative)
|
||
function controlPlayback(speed) {
|
||
// Nettoyer l’ancien timeout d’arrêt
|
||
if (stopTimeout) clearTimeout(stopTimeout);
|
||
|
||
// Si vitesse proche de 0, on arrête la lecture après 1.5s d’inactivité
|
||
if (Math.abs(speed) < MIN_SPEED) {
|
||
// Lance le timeout d'arrêt si plus de mouvement
|
||
stopTimeout = setTimeout(() => {
|
||
stopAudio();
|
||
}, 1500);
|
||
return;
|
||
}
|
||
|
||
// Ici, on a une vitesse suffisante => on arrête les deux audios d'abord
|
||
audioForward.pause();
|
||
audioReverse.pause();
|
||
|
||
// Calcule la vitesse normalisée (sensibilité appliquée)
|
||
let normalizedSpeed = Math.min(MAX_SPEED, Math.abs(speed) * SENSITIVITY);
|
||
|
||
// On lit dans le bon sens
|
||
if (speed > 0) {
|
||
audioForward.playbackRate = normalizedSpeed;
|
||
audioForward.currentTime = Math.min(audioForward.currentTime, audioForward.duration);
|
||
audioForward.play();
|
||
} else {
|
||
audioReverse.playbackRate = normalizedSpeed;
|
||
audioReverse.currentTime = Math.min(audioReverse.currentTime, audioReverse.duration);
|
||
audioReverse.play();
|
||
}
|
||
|
||
isPlaying = true;
|
||
updateVinylAnimation();
|
||
}
|
||
|
||
// socket.io reçoit la position de l’encodeur
|
||
socket.on('position', (position) => {
|
||
// Calcule la vitesse par rapport au dernier mouvement
|
||
let speed = position - lastPosition;
|
||
lastPosition = position;
|
||
|
||
controlPlayback(speed);
|
||
});
|
||
|
||
// 3. Événements généraux
|
||
|
||
// Clique sur le vinyle pour basculer lecture/pauses sur les deux audios
|
||
vinyl.addEventListener('click', () => {
|
||
if (isPlaying) {
|
||
stopAudio();
|
||
} else {
|
||
audioForward.playbackRate = 1;
|
||
audioForward.play();
|
||
isPlaying = true;
|
||
updateVinylAnimation();
|
||
}
|
||
});
|
||
|
||
// Mise à jour de la barre de progression à chaque changement de temps (sur les deux audios)
|
||
audioForward.addEventListener('timeupdate', updateProgress);
|
||
audioReverse.addEventListener('timeupdate', updateProgress);
|
||
|
||
// Mise à jour de la durée du titre dès que l'audio est chargé (sur les deux)
|
||
audioForward.addEventListener('loadedmetadata', () => {
|
||
durationEl.textContent = formatTime(audioForward.duration);
|
||
});
|
||
audioReverse.addEventListener('loadedmetadata', () => {
|
||
durationEl.textContent = formatTime(audioReverse.duration);
|
||
});
|
||
|
||
// Permet de cliquer sur la barre de progression (pour avancer dans la piste forward)
|
||
progress.addEventListener('click', (e) => {
|
||
const width = progress.clientWidth;
|
||
const clickX = e.offsetX;
|
||
const duration = audioForward.duration;
|
||
audioForward.currentTime = (clickX / width) * duration;
|
||
// En cas d'avancer, on arrête le reverse
|
||
audioReverse.pause();
|
||
updateProgress();
|
||
});
|
||
|
||
// Bouton reculer de 10s (sur piste forward)
|
||
backwardBtn.addEventListener('click', () => {
|
||
audioForward.currentTime = Math.max(0, audioForward.currentTime - 10);
|
||
audioReverse.pause();
|
||
updateProgress();
|
||
});
|
||
|
||
// Bouton avancer de 10s (sur piste forward)
|
||
forwardBtn.addEventListener('click', () => {
|
||
audioForward.currentTime = Math.min(audioForward.duration, audioForward.currentTime + 10);
|
||
audioReverse.pause();
|
||
updateProgress();
|
||
});
|
||
|
||
// Bouton pour activer/désactiver la boucle (LOOP)
|
||
loopBtn.addEventListener('click', () => {
|
||
isLooping = !isLooping;
|
||
loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent';
|
||
loopBtn.style.color = isLooping ? '#18344b' : 'white';
|
||
audioForward.loop = isLooping;
|
||
audioReverse.loop = isLooping;
|
||
});
|
||
|
||
// Lorsque l'audio est terminé, on répète si la boucle est activée
|
||
audioForward.addEventListener('ended', () => {
|
||
if (isLooping) {
|
||
audioForward.currentTime = 0;
|
||
audioForward.play();
|
||
} else {
|
||
vinyl.style.animationPlayState = 'paused';
|
||
isPlaying = false;
|
||
}
|
||
});
|
||
audioReverse.addEventListener('ended', () => {
|
||
if (isLooping) {
|
||
audioReverse.currentTime = 0;
|
||
audioReverse.play();
|
||
} else {
|
||
vinyl.style.animationPlayState = 'paused';
|
||
isPlaying = false;
|
||
}
|
||
});
|