diff --git a/node-server/assets/script.js b/node-server/assets/script.js index 88f542e..afe817d 100644 --- a/node-server/assets/script.js +++ b/node-server/assets/script.js @@ -1,210 +1,176 @@ -// Récupération des éléments -const audioForward = document.getElementById('audio'); -const reverseSrc = audioForward.getAttribute('data-reverse-src'); -const audioReverse = new Audio(reverseSrc); - -const progress = document.getElementById('progress'); -const currentTimeElem = document.getElementById('currentTime'); -const durationElem = document.getElementById('duration'); - +// 1. Sélection des éléments du DOM const vinyl = document.getElementById('vinyl'); +const audio = document.getElementById('audio'); +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'); -const btnForward = document.getElementById('forward'); -const btnBackward = document.getElementById('backward'); -const btnLoop = document.getElementById('loop'); - -let lastPosition = 0; +// 2. Variables utiles let isPlaying = false; -let currentDirection = 1; // 1 = forward, -1 = reverse +let isLooping = false; +let idleTimeout = null; +let reverseInterval = null; -// Variables pour arrêter le son si pas de mouvement -let stopTimeout = null; -const STOP_DELAY = 1000; // ms sans mouvement avant arrêt +// 3. Variables pour calculer la vitesse de rotation +let lastPosition = null; +let lastTime = null; -// Une fois les métadonnées chargées, on met la durée -audioForward.addEventListener('loadedmetadata', () => { - durationElem.textContent = formatTime(audioForward.duration); - progress.max = 100; -}); +// 4. Connexion Socket.io +const socket = io(); -// Formatage temps en mm:ss -function formatTime(seconds) { - const m = Math.floor(seconds / 60); - const s = Math.floor(seconds % 60); - return `${m}:${s < 10 ? '0' + s : s}`; -} +socket.on('position', (position) => { + const now = Date.now(); -// Fonction pour arrêter les audios -function stopAudio() { - audioForward.pause(); - audioReverse.pause(); - isPlaying = false; - vinyl.style.animationPlayState = 'paused'; -} + if (lastPosition !== null && lastTime !== null) { + const deltaPos = position - lastPosition; + const deltaTime = (now - lastTime) / 1000; -// Met à jour la barre de progression et le timer courant -function updateProgress(currentTime, duration) { - const percent = (currentTime / duration) * 100; - progress.value = percent; - currentTimeElem.textContent = formatTime(currentTime); -} + const speed = deltaPos / deltaTime; + console.log('instant speed:', speed); -// Fonction pour synchroniser la position de reverse sur la base de forward -function syncReversePosition() { - audioReverse.currentTime = audioForward.duration - audioForward.currentTime; -} + clearTimeout(idleTimeout); -// Fonction pour synchroniser la position de forward sur la base de reverse -function syncForwardPosition() { - audioForward.currentTime = audioReverse.duration - audioReverse.currentTime; -} - -// Gestion du slider pour contrôle manuel -progress.addEventListener('input', () => { - const seekTime = (progress.value / 100) * audioForward.duration; - audioForward.currentTime = seekTime; - audioReverse.currentTime = audioForward.duration - seekTime; - // Si pause, on reste en pause - if (!isPlaying) { - updateProgress(seekTime, audioForward.duration); - } -}); - -// Fonction principale pour gérer la lecture en fonction de la position de l'encodeur -function handlePosition(position) { - const speedFactor = 0.1; // ajuster la vitesse de lecture ici - const delta = position - lastPosition; - - // Si pas de mouvement détecté (delta petit), on stoppe après un délai - if (Math.abs(delta) < 0.01) { - if (stopTimeout === null) { - stopTimeout = setTimeout(() => { - stopAudio(); - stopTimeout = null; - }, STOP_DELAY); - } - return; - } else { - // Mouvement détecté => clear timeout arrêt - if (stopTimeout !== null) { - clearTimeout(stopTimeout); - stopTimeout = null; - } - } - - // Calcul vitesse lecture - let playbackRate = Math.min(Math.abs(delta) * speedFactor, 2); // max 2x vitesse - - if (delta > 0) { - // Lecture forward - if (currentDirection !== 1) { - // Switch direction: garder la position - audioForward.currentTime = audioReverse.duration - audioReverse.currentTime; - audioReverse.pause(); - currentDirection = 1; - } - if (audioForward.paused) audioForward.play(); - audioForward.playbackRate = playbackRate; - audioReverse.pause(); - - // Avance le temps - audioForward.currentTime += delta * speedFactor; - - // Clamp currentTime - if (audioForward.currentTime > audioForward.duration) { - audioForward.currentTime = audioForward.duration; - stopAudio(); - } - updateProgress(audioForward.currentTime, audioForward.duration); - - } else if (delta < 0) { - // Lecture reverse - if (currentDirection !== -1) { - // Switch direction: garder la position - audioReverse.currentTime = audioForward.duration - audioForward.currentTime; - audioForward.pause(); - currentDirection = -1; - } - if (audioReverse.paused) audioReverse.play(); - audioReverse.playbackRate = playbackRate; - audioForward.pause(); - - // Recul temps (en tenant compte que currentTime augmente dans les deux) - audioReverse.currentTime += -delta * speedFactor; - - // Clamp currentTime - if (audioReverse.currentTime > audioReverse.duration) { - audioReverse.currentTime = audioReverse.duration; - stopAudio(); + if (Math.abs(speed) < 15) { + stopPlayback(); + return; } - // Mise à jour progress en miroir - const forwardTime = audioReverse.duration - audioReverse.currentTime; - updateProgress(forwardTime, audioReverse.duration); - } + const isReverse = speed < 0; - // Animation vinyle - if (!isPlaying) { - vinyl.style.animationPlayState = 'running'; - isPlaying = true; + // Simuler reverse + if (isReverse) { + simulateReverse(Math.abs(speed)); + } else { + stopReverse(); + let playbackSpeed = 1 + speed * 0.0003; + playbackSpeed = Math.max(0.5, Math.min(1.5, playbackSpeed)); + controlPlayback(playbackSpeed); + } + } lastPosition = position; + lastTime = now; + + // Détecter l'inactivité : si pas de mise à jour pendant 300ms → stop + idleTimeout = setTimeout(() => { + stopPlayback(); + }, 300); +}); + +// 5. Fonctions + +function togglePlay() { + if (isPlaying) { + audio.pause(); + vinyl.style.animationPlayState = 'paused'; + } else { + audio.play(); + vinyl.style.animationPlayState = 'running'; + } + isPlaying = !isPlaying; } -// Gestion boutons +10s, -10s -btnForward.addEventListener('click', () => { - if (currentDirection === 1) { - audioForward.currentTime = Math.min(audioForward.duration, audioForward.currentTime + 10); - updateProgress(audioForward.currentTime, audioForward.duration); - syncReversePosition(); +function updateProgress() { + const progressPercent = (audio.currentTime / audio.duration) * 100; + progress.value = progressPercent; + currentTimeEl.textContent = formatTime(audio.currentTime); +} + +function formatTime(time) { + const minutes = Math.floor(time / 60); + const seconds = Math.floor(time % 60); + return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; +} + +function setProgress(e) { + const width = progress.clientWidth; + const clickX = e.offsetX; + const duration = audio.duration; + audio.currentTime = (clickX / width) * duration; +} + +// Fonction pour régler la lecture selon la vitesse + +function controlPlayback(speed) { + stopReverse(); // On stoppe le reverse si actif + if (speed > 0) { + if (!isPlaying) { + audio.play(); + vinyl.style.animationPlayState = 'running'; + isPlaying = true; + } + audio.playbackRate = speed; + } +} + +function stopPlayback() { + audio.pause(); + vinyl.style.animationPlayState = 'paused'; + isPlaying = false; +} + +function simulateReverse(speed) { + // vitesse = ticks/sec → convertir en vitesse de recul + const reverseSpeed = Math.min(speed * 0.01, 2); // seconds per step + + if (!reverseInterval) { + reverseInterval = setInterval(() => { + if (audio.currentTime > 0.05) { + audio.currentTime -= reverseSpeed * 0.1; + vinyl.style.animationPlayState = 'running'; + } else { + stopPlayback(); + } + }, 100); + + if (!isPlaying) { + isPlaying = true; + } + } + + audio.pause(); // on met en pause le vrai son pour éviter conflit +} + +function stopReverse() { + if (reverseInterval) { + clearInterval(reverseInterval); + reverseInterval = null; + } +} + +// 6. Événements + +vinyl.addEventListener('click', togglePlay); +audio.addEventListener('timeupdate', updateProgress); +audio.addEventListener('loadedmetadata', () => { + durationEl.textContent = formatTime(audio.duration); +}); +progress.addEventListener('click', setProgress); + +backwardBtn.addEventListener('click', () => { + audio.currentTime = Math.max(0, audio.currentTime - 10); +}); + +forwardBtn.addEventListener('click', () => { + audio.currentTime = Math.min(audio.duration, audio.currentTime + 10); +}); + +loopBtn.addEventListener('click', () => { + isLooping = !isLooping; + loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent'; + loopBtn.style.color = isLooping ? '#18344b' : 'white'; +}); + +audio.addEventListener('ended', () => { + if (isLooping) { + audio.currentTime = 0; + audio.play(); } else { - audioReverse.currentTime = Math.min(audioReverse.duration, audioReverse.currentTime + 10); - updateProgress(audioReverse.duration - audioReverse.currentTime, audioReverse.duration); - syncForwardPosition(); + vinyl.style.animationPlayState = 'paused'; + isPlaying = false; } - if (!isPlaying) { - if (currentDirection === 1) audioForward.play(); - else audioReverse.play(); - vinyl.style.animationPlayState = 'running'; - isPlaying = true; - } -}); - -btnBackward.addEventListener('click', () => { - if (currentDirection === 1) { - audioForward.currentTime = Math.max(0, audioForward.currentTime - 10); - updateProgress(audioForward.currentTime, audioForward.duration); - syncReversePosition(); - } else { - audioReverse.currentTime = Math.max(0, audioReverse.currentTime - 10); - updateProgress(audioReverse.duration - audioReverse.currentTime, audioReverse.duration); - syncForwardPosition(); - } - if (!isPlaying) { - if (currentDirection === 1) audioForward.play(); - else audioReverse.play(); - vinyl.style.animationPlayState = 'running'; - isPlaying = true; - } -}); - -// Toggle loop -btnLoop.addEventListener('click', () => { - const newLoop = !audioForward.loop; - audioForward.loop = newLoop; - audioReverse.loop = newLoop; - btnLoop.textContent = newLoop ? 'LOOP ON' : 'LOOP'; -}); - -// Exemple : simulateur de position venant de l'encodeur (juste pour test) -// Remplace cette fonction par ta vraie récupération de la position de l'encodeur -let testPosition = 0; -setInterval(() => { - // Simule un mouvement avec des valeurs entre -20 et 20 - // Ici, rien ne bouge (position stable) pour test arrêt - handlePosition(testPosition); -}, 100); - -// Tu peux appeler handlePosition(positionEncoder) quand tu as la position réelle - +}); \ No newline at end of file