Compare commits
50
Commits
82f4868f78
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0352efbc34 | ||
|
|
911049a2fe | ||
|
|
60bb918f54 | ||
|
|
0f16a93a7e | ||
|
|
8cde0ef01e | ||
|
|
62cac7c459 | ||
|
|
be551e8844 | ||
|
|
d56266d1f3 | ||
|
|
c74daf7337 | ||
|
|
a9808ba9d4 | ||
|
|
303c76cbd6 | ||
|
|
8c1e56c3f9 | ||
|
|
82ce27c10d | ||
|
|
10e8782798 | ||
|
|
fe24e5aa23 | ||
|
|
702e428ee5 | ||
|
|
f236665829 | ||
|
|
21f18d1b2a | ||
|
|
daa0505504 | ||
|
|
69b45e386f | ||
|
|
8accaf4ab2 | ||
|
|
cf8c4b0e47 | ||
|
|
710cd0506d | ||
|
|
7a7c04dbe4 | ||
|
|
1e04b86236 | ||
|
|
6a8463fab5 | ||
|
|
9cf7c74f9c | ||
|
|
825acfe48b | ||
|
|
cadb42d693 | ||
|
|
024338d4dc | ||
|
|
a33466d6d9 | ||
|
|
ebc97c8930 | ||
|
|
0e8efa0902 | ||
|
|
4eadf7dc7e | ||
|
|
9033c8ad20 | ||
|
|
ac89ce77e6 | ||
|
|
2b54c71eae | ||
|
|
e957de4d86 | ||
|
|
61f68ca41f | ||
|
|
bdd82be393 | ||
|
|
a9c1f21fe3 | ||
|
|
98f3a4a02f | ||
|
|
80002351ad | ||
|
|
533cd1052e | ||
|
|
3b7b46f25b | ||
|
|
0252347f65 | ||
|
|
c3bf6811ea | ||
|
|
b2f9e5abb5 | ||
|
|
1088699977 | ||
|
|
44ec586c1e |
@@ -43,9 +43,12 @@
|
|||||||
<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"
|
||||||
|
src="song_to_song_v4.mp3"
|
||||||
|
data-reverse-src="song_to_song_v4_reverse.mp3"></audio>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script src="socket.io.min.js"></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -43,9 +43,12 @@
|
|||||||
<button id="forward">10s +</button>
|
<button id="forward">10s +</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<audio id="audio" src="paradisev2.mp3"></audio>
|
<audio id="audio"
|
||||||
|
src="paradisev2.mp3"
|
||||||
|
data-reverse-src="paradisev2_reverse.mp3"></audio>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script src="socket.io.min.js"></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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,9 +43,14 @@
|
|||||||
<button id="forward">10s +</button>
|
<button id="forward">10s +</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<audio id="audio" src="muddy_files.mp3"></audio>
|
<audio id="audio"
|
||||||
|
src="muddy_files.mp3"
|
||||||
|
data-reverse-src="muddy_files_reverse.mp3"></audio>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="socket.io.min.js"></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
|||||||
// 1. Sélection des éléments du DOM
|
// 1. Sélection des éléments DOM
|
||||||
const vinyl = document.getElementById('vinyl');
|
const vinyl = document.getElementById('vinyl');
|
||||||
const audio = document.getElementById('audio');
|
const audio = document.getElementById('audio');
|
||||||
const progress = document.getElementById('progress');
|
const progress = document.getElementById('progress');
|
||||||
@@ -11,42 +11,89 @@ 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 = null;
|
||||||
|
let lastTime = null;
|
||||||
|
|
||||||
// sokcet.io & arduino serial info
|
const rotationsPerTrack = 3; // tours complets du vinyle sur toute la durée
|
||||||
|
let currentRotation = 0; // rotation en degrés actuelle du vinyle
|
||||||
|
|
||||||
|
// 3. Connexion Socket.io
|
||||||
const socket = io();
|
const socket = io();
|
||||||
|
|
||||||
socket.on('position', (position) => {
|
socket.on('position', (position) => {
|
||||||
console.log('recieved position', position);
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (lastPosition !== null && lastTime !== null) {
|
||||||
|
const deltaPos = position - lastPosition;
|
||||||
|
const deltaTime = (now - lastTime) / 1000;
|
||||||
|
|
||||||
|
const speed = deltaPos / deltaTime; // vitesse de rotation
|
||||||
|
|
||||||
|
clearTimeout(idleTimeout);
|
||||||
|
|
||||||
|
// Seuil de mouvement pour arrêt
|
||||||
|
if (Math.abs(speed) < 1) {
|
||||||
|
stopPlayback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speed < 0) {
|
||||||
|
// Rotation inverse : on recule la timeline
|
||||||
|
audio.pause();
|
||||||
|
isPlaying = false;
|
||||||
|
// recule proportionnellement à la vitesse (sensibilité ajustable)
|
||||||
|
audio.currentTime = Math.max(0, audio.currentTime + speed * 0.0025);
|
||||||
|
} else {
|
||||||
|
// Rotation avant : jouer la piste et ajuster vitesse
|
||||||
|
if (!isPlaying) {
|
||||||
|
audio.play();
|
||||||
|
isPlaying = true;
|
||||||
|
}
|
||||||
|
// SENSIBILITÉ : le facteur diviseur est plus grand → plus doux
|
||||||
|
let playbackSpeed = 0.5 + speed / 600;
|
||||||
|
playbackSpeed = Math.min(Math.max(playbackSpeed, 0.5), 1.1); // plage limitée à x1 max
|
||||||
|
audio.playbackRate = playbackSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPosition = position;
|
||||||
|
lastTime = now;
|
||||||
|
|
||||||
|
// Détection d'inactivité
|
||||||
|
idleTimeout = setTimeout(() => {
|
||||||
|
stopPlayback();
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 3. Fonctions
|
// 4. Fonctions
|
||||||
|
|
||||||
// Fonction pour basculer la lecture
|
|
||||||
function togglePlay() {
|
function togglePlay() {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
audio.pause();
|
audio.pause();
|
||||||
vinyl.style.animationPlayState = 'paused';
|
|
||||||
} else {
|
} else {
|
||||||
audio.play();
|
audio.play();
|
||||||
vinyl.style.animationPlayState = 'running';
|
|
||||||
}
|
}
|
||||||
isPlaying = !isPlaying;
|
isPlaying = !isPlaying;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mise à jour de la barre de progression
|
|
||||||
function updateProgress() {
|
function updateProgress() {
|
||||||
const progressPercent = (audio.currentTime / audio.duration) * 100;
|
if (!isNaN(audio.duration)) {
|
||||||
progress.value = progressPercent;
|
const progressPercent = (audio.currentTime / audio.duration) * 100;
|
||||||
currentTimeEl.textContent = formatTime(audio.currentTime);
|
progress.value = progressPercent;
|
||||||
|
currentTimeEl.textContent = formatTime(audio.currentTime);
|
||||||
|
durationEl.textContent = formatTime(audio.duration);
|
||||||
|
|
||||||
|
updateVinylRotation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fonction pour changer la position de lecture en cliquant sur la barre
|
|
||||||
function setProgress(e) {
|
function setProgress(e) {
|
||||||
const width = progress.clientWidth;
|
const width = progress.clientWidth;
|
||||||
const clickX = e.offsetX;
|
const clickX = e.offsetX;
|
||||||
@@ -54,85 +101,51 @@ function setProgress(e) {
|
|||||||
audio.currentTime = (clickX / width) * duration;
|
audio.currentTime = (clickX / width) * duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fonction pour regler la vitesse de lecture en fonction de la balle
|
function stopPlayback() {
|
||||||
function controlPlayback(speed) {
|
audio.pause();
|
||||||
if (speed > 0) {
|
isPlaying = false;
|
||||||
if (!isPlaying) {
|
audio.playbackRate = 1;
|
||||||
audio.play();
|
}
|
||||||
vinyl.style.animationPlayState = 'running';
|
|
||||||
isPlaying = true;
|
// La rotation est synchronisée avec la timeline audio
|
||||||
}
|
function updateVinylRotation() {
|
||||||
// Ajuste la vitesse de lecture audio (entre 0.5 et 2 par exemple)
|
if (audio.duration && audio.currentTime >= 0) {
|
||||||
audio.playbackRate = Math.min(2, Math.max(0.5, speed));
|
// Rotation proportionnelle au temps courant
|
||||||
} else {
|
currentRotation = (audio.currentTime / audio.duration) * 360 * rotationsPerTrack;
|
||||||
if (isPlaying) {
|
vinyl.style.transform = `rotate(${currentRotation}deg)`;
|
||||||
audio.pause();
|
console.log('Rotation:', currentRotation); // Debug
|
||||||
vinyl.style.animationPlayState = 'paused';
|
|
||||||
isPlaying = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Événements
|
// 5. Événements
|
||||||
|
|
||||||
// Clique sur le vinyle pour basculer lecture
|
|
||||||
vinyl.addEventListener('click', togglePlay);
|
vinyl.addEventListener('click', togglePlay);
|
||||||
|
|
||||||
// Mise à jour de la barre de progression à chaque changement de temps
|
|
||||||
audio.addEventListener('timeupdate', updateProgress);
|
audio.addEventListener('timeupdate', updateProgress);
|
||||||
|
|
||||||
// Mise à jour de la durée du titre dès que l'audio est chargé
|
|
||||||
audio.addEventListener('loadedmetadata', () => {
|
audio.addEventListener('loadedmetadata', () => {
|
||||||
durationEl.textContent = formatTime(audio.duration);
|
durationEl.textContent = formatTime(audio.duration);
|
||||||
|
console.log('Audio duration:', audio.duration);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Permet de cliquer sur la barre de progression
|
|
||||||
progress.addEventListener('click', setProgress);
|
progress.addEventListener('click', setProgress);
|
||||||
|
|
||||||
// Bouton reculer de 10s
|
|
||||||
backwardBtn.addEventListener('click', () => {
|
backwardBtn.addEventListener('click', () => {
|
||||||
audio.currentTime = Math.max(0, audio.currentTime - 10);
|
audio.currentTime = Math.max(0, audio.currentTime - 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bouton avancer de 10s
|
|
||||||
forwardBtn.addEventListener('click', () => {
|
forwardBtn.addEventListener('click', () => {
|
||||||
audio.currentTime = Math.min(audio.duration, audio.currentTime + 10);
|
audio.currentTime = Math.min(audio.duration, audio.currentTime + 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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';
|
||||||
});
|
});
|
||||||
|
|
||||||
// Lorsque l'audio est terminé, on répète si la boucle est activée
|
|
||||||
audio.addEventListener('ended', () => {
|
audio.addEventListener('ended', () => {
|
||||||
if (isLooping) {
|
if (isLooping) {
|
||||||
audio.currentTime = 0;
|
audio.currentTime = 0;
|
||||||
audio.play();
|
audio.play();
|
||||||
} else {
|
} else {
|
||||||
vinyl.style.animationPlayState = 'paused';
|
|
||||||
isPlaying = false;
|
isPlaying = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// server WebSocket
|
|
||||||
const WebSocket = require('ws');
|
|
||||||
const wss = new WebSocket.Server({ port: 3000 });
|
|
||||||
|
|
||||||
wss.on('connection', function connection(ws) {
|
|
||||||
console.log('🟢 Un client WebSocket est connecté');
|
|
||||||
|
|
||||||
ws.on('message', function incoming(message) {
|
|
||||||
console.log('📨 Message reçu:', message);
|
|
||||||
});
|
|
||||||
|
|
||||||
ws.send('🔗 Connexion WebSocket établie avec le Raspberry Pi');
|
|
||||||
});
|
|
||||||
|
|
||||||
const socket = new WebSocket('ws://[IP_DU_PI]:8080');
|
|
||||||
|
|
||||||
socket.onopen = () => console.log("✅ Connecté");
|
|
||||||
socket.onmessage = e => console.log("📩 Message :", e.data);
|
|
||||||
socket.onerror = e => console.log("❌ Erreur :", e);
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -43,9 +43,12 @@
|
|||||||
<button id="forward">10s +</button>
|
<button id="forward">10s +</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<audio id="audio" src="stamina-v17.mp3"></audio>
|
<audio id="audio"
|
||||||
|
src="stamina-v17.mp3"
|
||||||
|
data-reverse-src="stamina-v17_reverse.mp3"></audio>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
|
<script src="socket.io.min.js"></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ body {
|
|||||||
height: 600px;
|
height: 600px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
||||||
animation: spin 5s linear infinite paused;
|
/*animation: spin 5s linear infinite paused;*/
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -86,6 +86,10 @@ body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vinyl.reverse {
|
||||||
|
animation: spin-reverse 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.vinyl img {
|
.vinyl img {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
|
|||||||
@@ -78,14 +78,21 @@ body {
|
|||||||
height: 600px;
|
height: 600px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
||||||
animation: spin 5s linear infinite paused;
|
/*animation: spin 4s linear infinite;
|
||||||
|
animation-play-state: paused;*/
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transition: transform 0.3s linear;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.vinyl.reverse {
|
||||||
|
animation: spin-reverse 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.vinyl img {
|
.vinyl img {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
@@ -166,12 +173,13 @@ body {
|
|||||||
|
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
from {
|
from { transform: rotate(0deg); }
|
||||||
transform: rotate(0deg);
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
@keyframes spin-reverse {
|
||||||
}
|
from { transform: rotate(0deg); }
|
||||||
|
to { transform: rotate(-360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ body {
|
|||||||
height: 600px;
|
height: 600px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
||||||
animation: spin 5s linear infinite paused;
|
/*animation: spin 5s linear infinite paused;*/
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -87,6 +87,10 @@ body {
|
|||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vinyl.reverse {
|
||||||
|
animation: spin-reverse 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.vinyl img {
|
.vinyl img {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ body {
|
|||||||
height: 600px;
|
height: 600px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
background: radial-gradient(circle at center, #444 0%, #111 60%, #000 100%);
|
||||||
animation: spin 5s linear infinite paused;
|
/*animation: spin 5s linear infinite paused;*/
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -86,6 +86,10 @@ body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vinyl.reverse {
|
||||||
|
animation: spin-reverse 4s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
.vinyl img {
|
.vinyl img {
|
||||||
width: 40%;
|
width: 40%;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user