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 @@