audio reverse add

This commit is contained in:
El-yazide MOHAMED 2025-06-07 07:52:01 +02:00
parent 98f3a4a02f
commit a9c1f21fe3
9 changed files with 147 additions and 136 deletions

View File

@ -43,7 +43,8 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio" 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>
</main> </main>
<script src="socket.io.min.js"></script> <script src="socket.io.min.js"></script>

View File

@ -43,7 +43,8 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio" src="paradisev2.mp3"></audio> <audio id="audio-forward" src="paradisev2.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>

Binary file not shown.

View File

@ -43,7 +43,8 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio" src="muddy_files.mp3"></audio> <audio id="audio-forward" src="muddy_files.mp3"></audio>
<audio id="audio-reverse" src="muddy_files reverse.mp3"></audio>
</main> </main>

Binary file not shown.

View File

@ -1,6 +1,7 @@
// 1. Sélection des éléments du DOM // 1. Sélection des éléments du DOM
const vinyl = document.getElementById('vinyl'); const vinyl = document.getElementById('vinyl');
const audio = document.getElementById('audio'); const audioForward = document.getElementById('audio-forward');
const audioReverse = document.getElementById('audio-reverse');
const progress = document.getElementById('progress'); const progress = document.getElementById('progress');
const currentTimeEl = document.getElementById('currentTime'); const currentTimeEl = document.getElementById('currentTime');
const durationEl = document.getElementById('duration'); const durationEl = document.getElementById('duration');
@ -11,164 +12,170 @@ const loopBtn = document.getElementById('loop');
// 2. Variables utiles // 2. Variables utiles
let isPlaying = false; let isPlaying = false;
let isLooping = false; let isLooping = false;
let idleTimeout = null; let lastPosition = 0;
let reverseInterval = null; let stopTimeout = null;
// 3. Variables pour calculer la vitesse de rotation // socket.io & arduino serial info
let lastPosition = null;
let lastTime = null;
// 4. Connexion Socket.io
const socket = io(); const socket = io();
socket.on('position', (position) => { const MIN_SPEED = 0.1; // seuil minimal pour commencer la lecture
const now = Date.now(); const MAX_SPEED = 2; // vitesse max
const SENSITIVITY = 0.01; // ajuste la sensibilité du mapping
if (lastPosition !== null && lastTime !== null) {
const deltaPos = position - lastPosition;
const deltaTime = (now - lastTime) / 1000;
const speed = deltaPos / deltaTime;
console.log('instant speed:', speed);
clearTimeout(idleTimeout);
if (Math.abs(speed) < 15) {
stopPlayback();
return;
}
const isReverse = speed < 0;
// Simuler reverse
if (isReverse) {
simulateReverse(Math.abs(speed));
} else {
stopReverse();
let playbackSpeed = 1 + speed * 0.0003;
playbackSpeed = Math.max(0.5, Math.min(1.5, playbackSpeed));
controlPlayback(playbackSpeed);
}
}
lastPosition = position;
lastTime = now;
// Détecter l'inactivité : si pas de mise à jour pendant 300ms → stop
idleTimeout = setTimeout(() => {
stopPlayback();
}, 300);
});
// 5. Fonctions
function togglePlay() {
if (isPlaying) {
audio.pause();
vinyl.style.animationPlayState = 'paused';
} else {
audio.play();
vinyl.style.animationPlayState = 'running';
}
isPlaying = !isPlaying;
}
function updateProgress() {
const progressPercent = (audio.currentTime / audio.duration) * 100;
progress.value = progressPercent;
currentTimeEl.textContent = formatTime(audio.currentTime);
}
// Fonction pour formater le temps (min:sec)
function formatTime(time) { function formatTime(time) {
const minutes = Math.floor(time / 60); const minutes = Math.floor(time / 60);
const seconds = Math.floor(time % 60); const seconds = Math.floor(time % 60);
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`; return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
} }
function setProgress(e) { // Mise à jour de la barre de progression à partir de la piste active
function updateProgress() {
let activeAudio = isPlaying ? (audioForward.paused ? audioReverse : audioForward) : null;
if (activeAudio && activeAudio.duration) {
const progressPercent = (activeAudio.currentTime / activeAudio.duration) * 100;
progress.value = progressPercent;
currentTimeEl.textContent = formatTime(activeAudio.currentTime);
durationEl.textContent = formatTime(activeAudio.duration);
}
}
// Met à jour lanimation du vinyle selon lecture en cours
function updateVinylAnimation() {
if (!audioForward.paused || !audioReverse.paused) {
vinyl.style.animationPlayState = 'running';
} else {
vinyl.style.animationPlayState = 'paused';
}
}
// Fonction pour arrêter les deux audios
function stopAudio() {
audioForward.pause();
audioReverse.pause();
isPlaying = false;
updateVinylAnimation();
}
// Fonction pour contrôler la lecture en fonction de la vitesse (peut être négative)
function controlPlayback(speed) {
// Nettoyer lancien timeout darrêt
if (stopTimeout) clearTimeout(stopTimeout);
// Si vitesse proche de 0, on arrête la lecture après 1.5s dinactivité
if (Math.abs(speed) < MIN_SPEED) {
// Lance le timeout d'arrêt si plus de mouvement
stopTimeout = setTimeout(() => {
stopAudio();
}, 1500);
return;
}
// Ici, on a une vitesse suffisante => on arrête les deux audios d'abord
audioForward.pause();
audioReverse.pause();
// Calcule la vitesse normalisée (sensibilité appliquée)
let normalizedSpeed = Math.min(MAX_SPEED, Math.abs(speed) * SENSITIVITY);
// On lit dans le bon sens
if (speed > 0) {
audioForward.playbackRate = normalizedSpeed;
audioForward.currentTime = Math.min(audioForward.currentTime, audioForward.duration);
audioForward.play();
} else {
audioReverse.playbackRate = normalizedSpeed;
audioReverse.currentTime = Math.min(audioReverse.currentTime, audioReverse.duration);
audioReverse.play();
}
isPlaying = true;
updateVinylAnimation();
}
// socket.io reçoit la position de lencodeur
socket.on('position', (position) => {
// Calcule la vitesse par rapport au dernier mouvement
let speed = position - lastPosition;
lastPosition = position;
controlPlayback(speed);
});
// 3. Événements généraux
// Clique sur le vinyle pour basculer lecture/pauses sur les deux audios
vinyl.addEventListener('click', () => {
if (isPlaying) {
stopAudio();
} else {
audioForward.playbackRate = 1;
audioForward.play();
isPlaying = true;
updateVinylAnimation();
}
});
// Mise à jour de la barre de progression à chaque changement de temps (sur les deux audios)
audioForward.addEventListener('timeupdate', updateProgress);
audioReverse.addEventListener('timeupdate', updateProgress);
// Mise à jour de la durée du titre dès que l'audio est chargé (sur les deux)
audioForward.addEventListener('loadedmetadata', () => {
durationEl.textContent = formatTime(audioForward.duration);
});
audioReverse.addEventListener('loadedmetadata', () => {
durationEl.textContent = formatTime(audioReverse.duration);
});
// Permet de cliquer sur la barre de progression (pour avancer dans la piste forward)
progress.addEventListener('click', (e) => {
const width = progress.clientWidth; const width = progress.clientWidth;
const clickX = e.offsetX; const clickX = e.offsetX;
const duration = audio.duration; const duration = audioForward.duration;
audio.currentTime = (clickX / width) * duration; audioForward.currentTime = (clickX / width) * duration;
} // En cas d'avancer, on arrête le reverse
audioReverse.pause();
// Fonction pour régler la lecture selon la vitesse updateProgress();
function controlPlayback(speed) {
stopReverse(); // On stoppe le reverse si actif
if (speed > 0) {
if (!isPlaying) {
audio.play();
vinyl.style.animationPlayState = 'running';
isPlaying = true;
}
audio.playbackRate = speed;
}
}
function stopPlayback() {
audio.pause();
vinyl.style.animationPlayState = 'paused';
isPlaying = false;
}
function simulateReverse(speed) {
// vitesse = ticks/sec → convertir en vitesse de recul
const reverseSpeed = Math.min(speed * 0.01, 2); // seconds per step
if (!reverseInterval) {
reverseInterval = setInterval(() => {
if (audio.currentTime > 0.05) {
audio.currentTime -= reverseSpeed * 0.1;
vinyl.style.animationPlayState = 'running';
} else {
stopPlayback();
}
}, 100);
if (!isPlaying) {
isPlaying = true;
}
}
audio.pause(); // on met en pause le vrai son pour éviter conflit
}
function stopReverse() {
if (reverseInterval) {
clearInterval(reverseInterval);
reverseInterval = null;
}
}
// 6. Événements
vinyl.addEventListener('click', togglePlay);
audio.addEventListener('timeupdate', updateProgress);
audio.addEventListener('loadedmetadata', () => {
durationEl.textContent = formatTime(audio.duration);
}); });
progress.addEventListener('click', setProgress);
// Bouton reculer de 10s (sur piste forward)
backwardBtn.addEventListener('click', () => { backwardBtn.addEventListener('click', () => {
audio.currentTime = Math.max(0, audio.currentTime - 10); audioForward.currentTime = Math.max(0, audioForward.currentTime - 10);
audioReverse.pause();
updateProgress();
}); });
// Bouton avancer de 10s (sur piste forward)
forwardBtn.addEventListener('click', () => { forwardBtn.addEventListener('click', () => {
audio.currentTime = Math.min(audio.duration, audio.currentTime + 10); audioForward.currentTime = Math.min(audioForward.duration, audioForward.currentTime + 10);
audioReverse.pause();
updateProgress();
}); });
// Bouton pour activer/désactiver la boucle (LOOP)
loopBtn.addEventListener('click', () => { loopBtn.addEventListener('click', () => {
isLooping = !isLooping; isLooping = !isLooping;
loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent'; loopBtn.style.backgroundColor = isLooping ? 'white' : 'transparent';
loopBtn.style.color = isLooping ? '#18344b' : 'white'; loopBtn.style.color = isLooping ? '#18344b' : 'white';
audioForward.loop = isLooping;
audioReverse.loop = isLooping;
}); });
audio.addEventListener('ended', () => { // Lorsque l'audio est terminé, on répète si la boucle est activée
audioForward.addEventListener('ended', () => {
if (isLooping) { if (isLooping) {
audio.currentTime = 0; audioForward.currentTime = 0;
audio.play(); audioForward.play();
} else {
vinyl.style.animationPlayState = 'paused';
isPlaying = false;
}
});
audioReverse.addEventListener('ended', () => {
if (isLooping) {
audioReverse.currentTime = 0;
audioReverse.play();
} else { } else {
vinyl.style.animationPlayState = 'paused'; vinyl.style.animationPlayState = 'paused';
isPlaying = false; isPlaying = false;

Binary file not shown.

Binary file not shown.

View File

@ -43,7 +43,8 @@
<button id="forward">10s +</button> <button id="forward">10s +</button>
</div> </div>
<audio id="audio" src="stamina-v17.mp3"></audio> <audio id="audio-forward" src="stamina-v17.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>