VU wave: pravi audio spekter prek Web Audio analizatorja ob vklopu zvoka (fallback CSS pri mute)
This commit is contained in:
parent
b7918e41c7
commit
a0c935af7a
@ -45,6 +45,7 @@
|
||||
.ctrl { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; background: #0A0A0A; border: 1px solid rgba(255,255,255,0.14); border-top: 0; padding: 12px 16px; margin-top: -1px; }
|
||||
.vu { display: flex; gap: 3px; align-items: flex-end; height: 30px; flex: none; }
|
||||
.vu span { width: 3px; height: 100%; background: var(--akzent); transform-origin: bottom; animation: fx-vu 0.7s infinite ease-in-out alternate; }
|
||||
.vu.live span { animation: none; transform: scaleY(.15); transition: transform 60ms linear; }
|
||||
.now { flex: 1; min-width: 180px; }
|
||||
.now .lbl { font-size: 10px; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase; color: #6B6B6B; }
|
||||
.now .t { font-weight: 700; font-size: 15px; text-transform: uppercase; letter-spacing: -0.005em; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
@ -147,7 +148,50 @@
|
||||
|
||||
// Audio toggle
|
||||
var btnA = document.getElementById('btnAudio');
|
||||
btnA.addEventListener('click', function(){ video.muted = !video.muted; if(!video.muted && video.volume===0) video.volume=0.8; btnA.textContent = video.muted ? '🔇' : '🔊'; });
|
||||
btnA.addEventListener('click', function(){ video.muted = !video.muted; if(!video.muted && video.volume===0) video.volume=0.8; btnA.textContent = video.muted ? '🔇' : '🔊'; syncVu(); });
|
||||
|
||||
// --- pravi VU: Web Audio analizator na dejanskem zvoku streama ---
|
||||
var vuEl = document.getElementById('vu');
|
||||
var vuBars = vuEl ? vuEl.querySelectorAll('span') : [];
|
||||
var audioCtx = null, analyser = null, vuRaf = null, freqData = null;
|
||||
function initAnalyser(){
|
||||
if (audioCtx || !window.AudioContext && !window.webkitAudioContext) return;
|
||||
try {
|
||||
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
||||
var src = audioCtx.createMediaElementSource(video);
|
||||
analyser = audioCtx.createAnalyser();
|
||||
analyser.fftSize = 64;
|
||||
analyser.smoothingTimeConstant = 0.75;
|
||||
src.connect(analyser);
|
||||
analyser.connect(audioCtx.destination);
|
||||
freqData = new Uint8Array(analyser.frequencyBinCount);
|
||||
} catch(e) { audioCtx = null; analyser = null; }
|
||||
}
|
||||
function vuLoop(){
|
||||
if (!analyser) return;
|
||||
analyser.getByteFrequencyData(freqData);
|
||||
var n = vuBars.length; // 7 stolpcev, razporejenih cez spekter (bas -> visine)
|
||||
for (var i = 0; i < n; i++) {
|
||||
var a = Math.floor(i * freqData.length / (n + 4));
|
||||
var b = Math.floor((i + 1) * freqData.length / (n + 4));
|
||||
var sum = 0; for (var j = a; j < b; j++) sum += freqData[j];
|
||||
var v = (sum / Math.max(1, b - a)) / 255;
|
||||
var sc = Math.max(0.12, Math.min(1, Math.pow(v, 0.8) * 1.25));
|
||||
vuBars[i].style.transform = 'scaleY(' + sc.toFixed(3) + ')';
|
||||
}
|
||||
vuRaf = requestAnimationFrame(vuLoop);
|
||||
}
|
||||
function syncVu(){
|
||||
if (!video.muted) {
|
||||
initAnalyser();
|
||||
if (audioCtx && audioCtx.state === 'suspended') audioCtx.resume();
|
||||
if (analyser) { vuEl.classList.add('live'); if (!vuRaf) vuRaf = requestAnimationFrame(vuLoop); return; }
|
||||
}
|
||||
// mutirano ali analizator ni na voljo -> nazaj na organsko animacijo
|
||||
vuEl.classList.remove('live');
|
||||
if (vuRaf) { cancelAnimationFrame(vuRaf); vuRaf = null; }
|
||||
for (var i = 0; i < vuBars.length; i++) vuBars[i].style.transform = '';
|
||||
}
|
||||
// Fullscreen
|
||||
document.getElementById('btnFs').addEventListener('click', function(){
|
||||
var f = document.getElementById('playerFrame');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user