diff --git a/node-server/assets/Roman.html b/node-server/assets/Roman.html index d942ba0..ebf5296 100644 --- a/node-server/assets/Roman.html +++ b/node-server/assets/Roman.html @@ -43,8 +43,8 @@ - - + + diff --git a/node-server/assets/hell_even.html b/node-server/assets/hell_even.html index eff3b9e..44e4ae6 100644 --- a/node-server/assets/hell_even.html +++ b/node-server/assets/hell_even.html @@ -44,7 +44,7 @@ - + diff --git a/node-server/assets/muddy_files.html b/node-server/assets/muddy_files.html index 0fd3320..2c5bf7f 100644 --- a/node-server/assets/muddy_files.html +++ b/node-server/assets/muddy_files.html @@ -28,7 +28,7 @@
- +
0:00
@@ -43,8 +43,10 @@
- - + + diff --git a/node-server/assets/muddy_files reverse.mp3 b/node-server/assets/muddy_files_reverse.mp3 similarity index 100% rename from node-server/assets/muddy_files reverse.mp3 rename to node-server/assets/muddy_files_reverse.mp3 diff --git a/node-server/assets/paradisev2 reverse.mp3 b/node-server/assets/paradisev2_reverse.mp3 similarity index 100% rename from node-server/assets/paradisev2 reverse.mp3 rename to node-server/assets/paradisev2_reverse.mp3 diff --git a/node-server/assets/script.js b/node-server/assets/script.js index 83eda63..88f542e 100644 --- a/node-server/assets/script.js +++ b/node-server/assets/script.js @@ -1,194 +1,210 @@ -// 1. Sélection des éléments du DOM -const vinyl = document.getElementById('vinyl'); +// 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 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 currentTimeElem = document.getElementById('currentTime'); +const durationElem = document.getElementById('duration'); -// 2. Variables utiles +const vinyl = document.getElementById('vinyl'); + +const btnForward = document.getElementById('forward'); +const btnBackward = document.getElementById('backward'); +const btnLoop = document.getElementById('loop'); + +let lastPosition = 0; let isPlaying = false; -let isLooping = false; +let currentDirection = 1; // 1 = forward, -1 = reverse -// Création de l'élément audio pour le son en reverse -const audioReverse = new Audio('muddy_files_reverse.mp3'); -audioReverse.preload = 'auto'; +// Variables pour arrêter le son si pas de mouvement +let stopTimeout = null; +const STOP_DELAY = 1000; // ms sans mouvement avant arrêt -// Durée et mise à jour progressive -let duration = 0; +// Une fois les métadonnées chargées, on met la durée audioForward.addEventListener('loadedmetadata', () => { - duration = audioForward.duration; - durationEl.textContent = formatTime(duration); -}); -audioReverse.addEventListener('loadedmetadata', () => { - // en principe même durée que audioForward + durationElem.textContent = formatTime(audioForward.duration); + progress.max = 100; }); -// socket.io & arduino serial info -const socket = io(); - -// Timer d'inactivité pour arrêt du son -let inactivityTimeout = null; -const INACTIVITY_DELAY = 1500; // ms - -// 3. Fonctions - -function formatTime(time) { - const minutes = Math.floor(time / 60); - const seconds = Math.floor(time % 60); - return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; -} - -function updateProgress() { - let currentTime = isPlaying - ? (audioForward.paused ? audioReverse.currentTime : audioForward.currentTime) - : 0; - - const progressPercent = (currentTime / duration) * 100; - progress.value = progressPercent; - currentTimeEl.textContent = formatTime(currentTime); -} - -function setProgress(e) { - const width = progress.clientWidth; - const clickX = e.offsetX; - const newTime = (clickX / width) * duration; - - audioForward.currentTime = newTime; - audioReverse.currentTime = newTime; -} - -function togglePlay() { - if (isPlaying) { - stopAudio(); - } else { - audioForward.play(); - vinyl.style.animationPlayState = 'running'; - isPlaying = true; - } +// 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}`; } +// Fonction pour arrêter les audios function stopAudio() { audioForward.pause(); audioReverse.pause(); - vinyl.style.animationPlayState = 'paused'; isPlaying = false; + vinyl.style.animationPlayState = 'paused'; } -// Met à jour l'animation du vinyle selon l'état -function updateVinylAnimation(running) { - vinyl.style.animationPlayState = running ? 'running' : 'paused'; +// 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); } -// 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); +// Fonction pour synchroniser la position de reverse sur la base de forward +function syncReversePosition() { + audioReverse.currentTime = audioForward.duration - audioForward.currentTime; +} - if (Math.abs(speed) > threshold) { - // Reset du timer d'inactivité - if (inactivityTimeout) clearTimeout(inactivityTimeout); +// Fonction pour synchroniser la position de forward sur la base de reverse +function syncForwardPosition() { + audioForward.currentTime = audioReverse.duration - audioReverse.currentTime; +} - if (!isPlaying) isPlaying = true; +// 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); + } +}); - 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); +// 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; - } 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); + // 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(); } - // 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(); + // Mise à jour progress en miroir + const forwardTime = audioReverse.duration - audioReverse.currentTime; + updateProgress(forwardTime, audioReverse.duration); } + + // Animation vinyle + if (!isPlaying) { + vinyl.style.animationPlayState = 'running'; + isPlaying = true; + } + + lastPosition = position; } -// 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(); -}); - -// 4. Événements - -vinyl.addEventListener('click', togglePlay); -audioForward.addEventListener('timeupdate', updateProgress); -audioReverse.addEventListener('timeupdate', updateProgress); -progress.addEventListener('click', setProgress); - -backwardBtn.addEventListener('click', () => { - let newTime = Math.max(0, audioForward.currentTime - 10); - audioForward.currentTime = newTime; - audioReverse.currentTime = newTime; -}); -forwardBtn.addEventListener('click', () => { - let newTime = Math.min(duration, audioForward.currentTime + 10); - audioForward.currentTime = newTime; - audioReverse.currentTime = newTime; -}); -loopBtn.addEventListener('click', () => { - isLooping = !isLooping; - loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent'; - loopBtn.style.color = isLooping ? '#18344b' : 'white'; -}); - -audioForward.addEventListener('ended', () => { - if (isLooping) { - audioForward.currentTime = 0; - audioForward.play(); +// 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(); } else { - updateVinylAnimation(false); - isPlaying = false; + audioReverse.currentTime = Math.min(audioReverse.duration, 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; } }); -audioReverse.addEventListener('ended', () => { - if (isLooping) { - audioReverse.currentTime = 0; - audioReverse.play(); + +btnBackward.addEventListener('click', () => { + if (currentDirection === 1) { + audioForward.currentTime = Math.max(0, audioForward.currentTime - 10); + updateProgress(audioForward.currentTime, audioForward.duration); + syncReversePosition(); } else { - updateVinylAnimation(false); - isPlaying = false; + 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 + diff --git a/node-server/assets/song to song v4.mp3 b/node-server/assets/song_to_song_v4.mp3 similarity index 100% rename from node-server/assets/song to song v4.mp3 rename to node-server/assets/song_to_song_v4.mp3 diff --git a/node-server/assets/song to song v4 reverse.mp3 b/node-server/assets/song_to_song_v4_reverse.mp3 similarity index 100% rename from node-server/assets/song to song v4 reverse.mp3 rename to node-server/assets/song_to_song_v4_reverse.mp3 diff --git a/node-server/assets/stamina-v17 reverse.mp3 b/node-server/assets/stamina-v17_reverse.mp3 similarity index 100% rename from node-server/assets/stamina-v17 reverse.mp3 rename to node-server/assets/stamina-v17_reverse.mp3 diff --git a/node-server/assets/stamina.html b/node-server/assets/stamina.html index b75d784..889f376 100644 --- a/node-server/assets/stamina.html +++ b/node-server/assets/stamina.html @@ -44,7 +44,7 @@
- +