This commit is contained in:
El-yazide MOHAMED 2025-06-07 09:26:53 +02:00
parent e957de4d86
commit 2b54c71eae
10 changed files with 185 additions and 167 deletions

View File

@ -43,8 +43,8 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio-forward" src="song to song v4.mp3"></audio> <audio id="audio-forward" src="song_to_song_v4.mp3"></audio>
<audio id="audio-reverse" src="song to song v4 reverse.mp3"></audio> <audio id="audio-reverse" src="song_to_song_v4_reverse.mp3"></audio>
</main> </main>
<script src="socket.io.min.js"></script> <script src="socket.io.min.js"></script>

View File

@ -44,7 +44,7 @@
</div> </div>
<audio id="audio-forward" src="paradisev2.mp3"></audio> <audio id="audio-forward" src="paradisev2.mp3"></audio>
<audio id="audio-reverse" src="paradisev2 reverse.mp3"></audio> <audio id="audio-reverse" src="paradisev2_reverse.mp3"></audio>
</main> </main>
<script src="socket.io.min.js"></script> <script src="socket.io.min.js"></script>

View File

@ -28,7 +28,7 @@
</h2> </h2>
<div class="progress-container"> <div class="progress-container">
<input type="range" id="progress" value="0" /> <input type="range" id="progress" value="0" max="100" />
<div class="time-wrapper"> <div class="time-wrapper">
<div id="currentTime" class="time">0:00</div> <div id="currentTime" class="time">0:00</div>
@ -43,8 +43,10 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio-forward" src="muddy_files.mp3"></audio> <audio id="audio"
<audio id="audio-reverse" src="muddy_files reverse.mp3"></audio> src="muddy_files.mp3"
data-reverse-src="muddy_files_reverse.mp3"></audio>
</main> </main>

View File

@ -1,194 +1,210 @@
// 1. Sélection des éléments du DOM // Récupération des éléments
const vinyl = document.getElementById('vinyl');
const audioForward = document.getElementById('audio'); const audioForward = document.getElementById('audio');
const reverseSrc = audioForward.getAttribute('data-reverse-src');
const audioReverse = new Audio(reverseSrc);
const progress = document.getElementById('progress'); const progress = document.getElementById('progress');
const currentTimeEl = document.getElementById('currentTime'); const currentTimeElem = document.getElementById('currentTime');
const durationEl = document.getElementById('duration'); const durationElem = document.getElementById('duration');
const backwardBtn = document.getElementById('backward');
const forwardBtn = document.getElementById('forward');
const loopBtn = document.getElementById('loop');
// 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 isPlaying = false;
let isLooping = false; let currentDirection = 1; // 1 = forward, -1 = reverse
// Création de l'élément audio pour le son en reverse // Variables pour arrêter le son si pas de mouvement
const audioReverse = new Audio('muddy_files_reverse.mp3'); let stopTimeout = null;
audioReverse.preload = 'auto'; const STOP_DELAY = 1000; // ms sans mouvement avant arrêt
// Durée et mise à jour progressive // Une fois les métadonnées chargées, on met la durée
let duration = 0;
audioForward.addEventListener('loadedmetadata', () => { audioForward.addEventListener('loadedmetadata', () => {
duration = audioForward.duration; durationElem.textContent = formatTime(audioForward.duration);
durationEl.textContent = formatTime(duration); progress.max = 100;
});
audioReverse.addEventListener('loadedmetadata', () => {
// en principe même durée que audioForward
}); });
// socket.io & arduino serial info // Formatage temps en mm:ss
const socket = io(); function formatTime(seconds) {
const m = Math.floor(seconds / 60);
// Timer d'inactivité pour arrêt du son const s = Math.floor(seconds % 60);
let inactivityTimeout = null; return `${m}:${s < 10 ? '0' + s : s}`;
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;
}
} }
// Fonction pour arrêter les audios
function stopAudio() { function stopAudio() {
audioForward.pause(); audioForward.pause();
audioReverse.pause(); audioReverse.pause();
vinyl.style.animationPlayState = 'paused';
isPlaying = false; isPlaying = false;
vinyl.style.animationPlayState = 'paused';
} }
// Met à jour l'animation du vinyle selon l'état // Met à jour la barre de progression et le timer courant
function updateVinylAnimation(running) { function updateProgress(currentTime, duration) {
vinyl.style.animationPlayState = running ? 'running' : 'paused'; const percent = (currentTime / duration) * 100;
progress.value = percent;
currentTimeElem.textContent = formatTime(currentTime);
} }
// Fonction principale pour contrôler la lecture selon la vitesse // Fonction pour synchroniser la position de reverse sur la base de forward
function controlPlayback(speedRaw) { function syncReversePosition() {
const threshold = 0.02; audioReverse.currentTime = audioForward.duration - audioForward.currentTime;
// 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) { // Fonction pour synchroniser la position de forward sur la base de reverse
// Reset du timer d'inactivité function syncForwardPosition() {
if (inactivityTimeout) clearTimeout(inactivityTimeout); 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) { // Fonction principale pour gérer la lecture en fonction de la position de l'encodeur
// Forward function handlePosition(position) {
if (!audioForward.paused) { const speedFactor = 0.1; // ajuster la vitesse de lecture ici
// synchronise la position reverse avec forward const delta = position - lastPosition;
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 { // Si pas de mouvement détecté (delta petit), on stoppe après un délai
// Reverse if (Math.abs(delta) < 0.01) {
if (!audioReverse.paused) { if (stopTimeout === null) {
audioForward.pause(); stopTimeout = setTimeout(() => {
} else { stopAudio();
audioForward.pause(); stopTimeout = null;
audioReverse.currentTime = audioForward.currentTime; // même position }, STOP_DELAY);
audioReverse.play(); }
} return;
audioReverse.playbackRate = Math.min(2, Math.max(0.5, Math.abs(speed))); } else {
updateVinylAnimation(true); // 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é // Mise à jour progress en miroir
inactivityTimeout = setTimeout(() => { const forwardTime = audioReverse.duration - audioReverse.currentTime;
stopAudio(); updateProgress(forwardTime, audioReverse.duration);
}, INACTIVITY_DELAY);
} else {
// Si la vitesse est trop faible, on stoppe la lecture
stopAudio();
} }
// Animation vinyle
if (!isPlaying) {
vinyl.style.animationPlayState = 'running';
isPlaying = true;
}
lastPosition = position;
} }
// socket.io écoute la position et contrôle la vitesse // Gestion boutons +10s, -10s
socket.on('position', (position) => { btnForward.addEventListener('click', () => {
// Ici tu adaptes le mapping de position -> vitesse entre 0.5 et 2 par exemple if (currentDirection === 1) {
// Exemple simple, adapte selon ta plage réelle : audioForward.currentTime = Math.min(audioForward.duration, audioForward.currentTime + 10);
// position brut supposé entre -1000 et 1000 updateProgress(audioForward.currentTime, audioForward.duration);
const minPos = -1000; syncReversePosition();
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 { } else {
updateVinylAnimation(false); audioReverse.currentTime = Math.min(audioReverse.duration, audioReverse.currentTime + 10);
isPlaying = false; 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) { btnBackward.addEventListener('click', () => {
audioReverse.currentTime = 0; if (currentDirection === 1) {
audioReverse.play(); audioForward.currentTime = Math.max(0, audioForward.currentTime - 10);
updateProgress(audioForward.currentTime, audioForward.duration);
syncReversePosition();
} else { } else {
updateVinylAnimation(false); audioReverse.currentTime = Math.max(0, audioReverse.currentTime - 10);
isPlaying = false; 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

View File

@ -44,7 +44,7 @@
</div> </div>
<audio id="audio-forward" src="stamina-v17.mp3"></audio> <audio id="audio-forward" src="stamina-v17.mp3"></audio>
<audio id="audio-reverse" src="stamina-v17 reverse.mp3"></audio> <audio id="audio-reverse" src="stamina-v17_reverse.mp3"></audio>
</main> </main>
<script src="socket.io.min.js"></script> <script src="socket.io.min.js"></script>