195 lines
5.6 KiB
JavaScript
195 lines
5.6 KiB
JavaScript
// 1. Sélection des éléments du DOM
|
|
const vinyl = document.getElementById('vinyl');
|
|
const audioForward = 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');
|
|
|
|
// 2. Variables utiles
|
|
let isPlaying = false;
|
|
let isLooping = false;
|
|
|
|
// 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();
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
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();
|
|
});
|
|
|
|
// 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();
|
|
} else {
|
|
updateVinylAnimation(false);
|
|
isPlaying = false;
|
|
}
|
|
});
|
|
audioReverse.addEventListener('ended', () => {
|
|
if (isLooping) {
|
|
audioReverse.currentTime = 0;
|
|
audioReverse.play();
|
|
} else {
|
|
updateVinylAnimation(false);
|
|
isPlaying = false;
|
|
}
|
|
});
|