ui(vu): narrower 44deg swing, peak-based level, faster response; mini progress bar fix
- VU needle swings -22..+22deg instead of -45..+45 for a more realistic VU look - Switch from RMS to peak frequency reading so the needle catches musical hits - Faster attack (0.7) and release (0.25) so it swings rather than pinning - Replace explicit grid lines with subtle repeating-conic-gradient ticks - Scope mini progress bar styles to .mini-player; taller (3px), clickable
This commit is contained in:
@@ -763,10 +763,10 @@ export function updateUI(status) {
|
||||
dom.volumeDisplay.textContent = `${status.volume}%`;
|
||||
dom.miniVolumeSlider.value = status.volume;
|
||||
dom.miniVolumeDisplay.textContent = `${status.volume}%`;
|
||||
// VU needle: map 0-100 volume to -45deg..+45deg rotation.
|
||||
// VU needle: map 0-100 volume to -22deg..+22deg rotation.
|
||||
const needle = document.getElementById('vuNeedle');
|
||||
if (needle) {
|
||||
const deg = -45 + (status.volume / 100) * 90;
|
||||
const deg = -22 + (status.volume / 100) * 44;
|
||||
needle.style.transform = `rotate(${deg}deg)`;
|
||||
}
|
||||
// Editorial VU readout: VOL XX% / OUT (SYS or MUTED)
|
||||
@@ -802,22 +802,19 @@ export function updateUI(status) {
|
||||
// slider position so the needle still looks alive.
|
||||
let vuWobbleHandle = null;
|
||||
let vuWobbleStart = 0;
|
||||
let vuLevelSmoothed = 0; // Smoothed RMS of recent frequency frames
|
||||
const VU_LEVEL_ATTACK = 0.55; // How fast needle climbs to a peak
|
||||
const VU_LEVEL_RELEASE = 0.12; // How fast it falls back
|
||||
let vuLevelSmoothed = 0;
|
||||
const VU_LEVEL_ATTACK = 0.7; // Fast climb so the needle catches musical hits
|
||||
const VU_LEVEL_RELEASE = 0.25; // Faster fall so it swings between hits, not pins
|
||||
|
||||
function readAudioLevel() {
|
||||
// frequencyData is the WS-driven FFT payload from player.js scope.
|
||||
if (!frequencyData || !frequencyData.frequencies) return null;
|
||||
const bins = frequencyData.frequencies;
|
||||
if (!bins.length) return null;
|
||||
let sumSq = 0;
|
||||
// Skip the very lowest bin (DC + sub-rumble) for cleaner level.
|
||||
for (let i = 1; i < bins.length; i++) sumSq += bins[i] * bins[i];
|
||||
const rms = Math.sqrt(sumSq / (bins.length - 1));
|
||||
// The values are in 0..1 from the backend; gain a touch so quieter
|
||||
// tracks still swing the needle.
|
||||
return Math.min(1, rms * 1.6);
|
||||
let peak = 0;
|
||||
for (let i = 1; i < bins.length; i++) {
|
||||
if (bins[i] > peak) peak = bins[i];
|
||||
}
|
||||
return Math.min(1, peak * 1.4);
|
||||
}
|
||||
|
||||
function startVuWobble() {
|
||||
@@ -839,11 +836,9 @@ function startVuWobble() {
|
||||
const wanted = audioLevel * (vol / 100);
|
||||
const k = wanted > vuLevelSmoothed ? VU_LEVEL_ATTACK : VU_LEVEL_RELEASE;
|
||||
vuLevelSmoothed = vuLevelSmoothed * (1 - k) + wanted * k;
|
||||
// Map 0..1 to -45deg..+45deg.
|
||||
target = -45 + vuLevelSmoothed * 90;
|
||||
target = -22 + vuLevelSmoothed * 44;
|
||||
} else {
|
||||
// Synthetic fallback: volume-mapped + sine wobble.
|
||||
const base = -45 + (vol / 100) * 90;
|
||||
const base = -22 + (vol / 100) * 44;
|
||||
const mag = Math.max(2, Math.min(14, vol * 0.16));
|
||||
const t = (performance.now() - vuWobbleStart) / 1000;
|
||||
target = base
|
||||
@@ -864,9 +859,8 @@ function stopVuWobble() {
|
||||
vuWobbleHandle = null;
|
||||
}
|
||||
vuLevelSmoothed = 0;
|
||||
// Settle needle back to the bottom of the swing.
|
||||
const needle = document.getElementById('vuNeedle');
|
||||
if (needle) needle.style.transform = 'rotate(-45deg)';
|
||||
if (needle) needle.style.transform = 'rotate(-22deg)';
|
||||
}
|
||||
|
||||
export function updatePlaybackState(state) {
|
||||
|
||||
Reference in New Issue
Block a user