diff --git a/node-server/assets/script.js b/node-server/assets/script.js index 47b1a99..83eda63 100644 --- a/node-server/assets/script.js +++ b/node-server/assets/script.js @@ -1,7 +1,6 @@ // 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 audioForward = document.getElementById('audio'); const progress = document.getElementById('progress'); const currentTimeEl = document.getElementById('currentTime'); const durationEl = document.getElementById('duration'); @@ -12,184 +11,175 @@ const loopBtn = document.getElementById('loop'); // 2. Variables utiles let isPlaying = false; let isLooping = false; -let lastPosition = 0; -let stopTimeout = null; + +// Création de l'élément audio pour le son en reverse +const audioReverse = new Audio('muddy_files_reverse.mp3'); +audioReverse.preload = 'auto'; + +// Durée et mise à jour progressive +let duration = 0; +audioForward.addEventListener('loadedmetadata', () => { + duration = audioForward.duration; + durationEl.textContent = formatTime(duration); +}); +audioReverse.addEventListener('loadedmetadata', () => { + // en principe même durée que audioForward +}); // 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 +// Timer d'inactivité pour arrêt du son +let inactivityTimeout = null; +const INACTIVITY_DELAY = 1500; // ms + +// 3. Fonctions -// 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); - } + let currentTime = isPlaying + ? (audioForward.paused ? audioReverse.currentTime : audioForward.currentTime) + : 0; + + const progressPercent = (currentTime / duration) * 100; + progress.value = progressPercent; + currentTimeEl.textContent = formatTime(currentTime); } -// 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'; - } +function setProgress(e) { + const width = progress.clientWidth; + const clickX = e.offsetX; + const newTime = (clickX / width) * duration; + + audioForward.currentTime = newTime; + audioReverse.currentTime = newTime; } - -// 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.max(0.5, Math.abs(speed) * SENSITIVITY)); - - // On lit dans le bon sens - if (speed > 0) { - // Passage en lecture forward - - // Si on était en reverse, on récupère la position dans reverse et on la convertit en forward - if (!audioForward.paused) { - // on continue normalement - } else { - // on synchronise la position forward avec la position inverse actuelle - audioForward.currentTime = audioReverse.duration - audioReverse.currentTime; - audioReverse.pause(); - } - - audioForward.playbackRate = normalizedSpeed; - audioForward.play(); - isPlaying = true; - } else { - // Passage en lecture reverse - - if (!audioReverse.paused) { - // on continue normalement - } else { - // on synchronise la position reverse avec la position forward actuelle - audioReverse.currentTime = audioForward.duration - audioForward.currentTime; - audioForward.pause(); - } - - audioReverse.playbackRate = normalizedSpeed; - audioReverse.play(); - isPlaying = true; - } - - updateVinylAnimation(); -} - -// Fonction pour arrêter les deux audios -function stopAudio() { - audioForward.pause(); - audioReverse.pause(); - isPlaying = false; - 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', () => { +function togglePlay() { if (isPlaying) { stopAudio(); } else { - audioForward.playbackRate = 1; audioForward.play(); + vinyl.style.animationPlayState = 'running'; isPlaying = true; - updateVinylAnimation(); } +} + +function stopAudio() { + audioForward.pause(); + audioReverse.pause(); + vinyl.style.animationPlayState = 'paused'; + isPlaying = false; +} + +// Met à jour l'animation du vinyle selon l'état +function updateVinylAnimation(running) { + vinyl.style.animationPlayState = running ? 'running' : 'paused'; +} + +// Fonction principale pour contrôler la lecture selon la vitesse +function controlPlayback(speedRaw) { + const threshold = 0.02; + // Applique un filtre de sensibilité (ex: puissance 1.5 pour réduire les petites valeurs) + let speed = Math.sign(speedRaw) * Math.pow(Math.abs(speedRaw), 1.5); + + if (Math.abs(speed) > threshold) { + // Reset du timer d'inactivité + if (inactivityTimeout) clearTimeout(inactivityTimeout); + + if (!isPlaying) isPlaying = true; + + if (speed > 0) { + // Forward + if (!audioForward.paused) { + // synchronise la position reverse avec forward + audioReverse.pause(); + } else { + audioReverse.pause(); + audioForward.currentTime = audioReverse.currentTime; // même position + audioForward.play(); + } + audioForward.playbackRate = Math.min(2, Math.max(0.5, speed)); + updateVinylAnimation(true); + + } else { + // Reverse + if (!audioReverse.paused) { + audioForward.pause(); + } else { + audioForward.pause(); + audioReverse.currentTime = audioForward.currentTime; // même position + audioReverse.play(); + } + audioReverse.playbackRate = Math.min(2, Math.max(0.5, Math.abs(speed))); + updateVinylAnimation(true); + } + + // Lance un timer pour stopper la lecture si aucun mouvement détecté + inactivityTimeout = setTimeout(() => { + stopAudio(); + }, INACTIVITY_DELAY); + + } else { + // Si la vitesse est trop faible, on stoppe la lecture + stopAudio(); + } +} + +// socket.io écoute la position et contrôle la vitesse +socket.on('position', (position) => { + // Ici tu adaptes le mapping de position -> vitesse entre 0.5 et 2 par exemple + // Exemple simple, adapte selon ta plage réelle : + // position brut supposé entre -1000 et 1000 + const minPos = -1000; + const maxPos = 1000; + + // Mappe la position entre -2 et 2 + let mappedSpeed = ((position - minPos) / (maxPos - minPos)) * 4 - 2; + + // Par exemple pour réduire encore la sensibilité + mappedSpeed = Math.max(-2, Math.min(2, mappedSpeed)); + + controlPlayback(mappedSpeed); + + // Mise à jour de la progress bar + updateProgress(); }); -// Mise à jour de la barre de progression à chaque changement de temps (sur les deux audios) +// 4. Événements + +vinyl.addEventListener('click', togglePlay); audioForward.addEventListener('timeupdate', updateProgress); audioReverse.addEventListener('timeupdate', updateProgress); +progress.addEventListener('click', setProgress); -// 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(); + let newTime = Math.max(0, audioForward.currentTime - 10); + audioForward.currentTime = newTime; + audioReverse.currentTime = newTime; }); - -// Bouton avancer de 10s (sur piste forward) forwardBtn.addEventListener('click', () => { - audioForward.currentTime = Math.min(audioForward.duration, audioForward.currentTime + 10); - audioReverse.pause(); - updateProgress(); + let newTime = Math.min(duration, audioForward.currentTime + 10); + audioForward.currentTime = newTime; + audioReverse.currentTime = newTime; }); - -// 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'; + updateVinylAnimation(false); isPlaying = false; } }); @@ -198,7 +188,7 @@ audioReverse.addEventListener('ended', () => { audioReverse.currentTime = 0; audioReverse.play(); } else { - vinyl.style.animationPlayState = 'paused'; + updateVinylAnimation(false); isPlaying = false; } });