loop/node-server/assets/script.js
2025-06-07 09:26:53 +02:00

211 lines
6.7 KiB
JavaScript

// 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');
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 currentDirection = 1; // 1 = forward, -1 = reverse
// Variables pour arrêter le son si pas de mouvement
let stopTimeout = null;
const STOP_DELAY = 1000; // ms sans mouvement avant arrêt
// Une fois les métadonnées chargées, on met la durée
audioForward.addEventListener('loadedmetadata', () => {
durationElem.textContent = formatTime(audioForward.duration);
progress.max = 100;
});
// 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();
isPlaying = false;
vinyl.style.animationPlayState = '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 pour synchroniser la position de reverse sur la base de forward
function syncReversePosition() {
audioReverse.currentTime = audioForward.duration - audioForward.currentTime;
}
// 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();
}
// 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;
}
// 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 {
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;
}
});
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