loop/node-server/assets/script.js

184 lines
5.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 lanimation 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 lancien timeout darrêt
if (stopTimeout) clearTimeout(stopTimeout);
// Si vitesse proche de 0, on arrête la lecture après 1.5s dinactivité
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 lencodeur
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;
}
});