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; }
|
.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 { 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 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 { flex: 1; min-width: 180px; }
|
||||||
.now .lbl { font-size: 10px; font-weight: 600; letter-spacing: 0.2em; text-transform: uppercase; color: #6B6B6B; }
|
.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; }
|
.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
|
// Audio toggle
|
||||||
var btnA = document.getElementById('btnAudio');
|
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
|
// Fullscreen
|
||||||
document.getElementById('btnFs').addEventListener('click', function(){
|
document.getElementById('btnFs').addEventListener('click', function(){
|
||||||
var f = document.getElementById('playerFrame');
|
var f = document.getElementById('playerFrame');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user