mirror of
https://github.com/Psychotoxical/psysonic.git
synced 2026-07-22 07:15:47 +00:00
fix(seekbar): split waveform style into truewave (analyzed) + pseudowave (deterministic)
The waveform-loudness-cache merge replaced the existing deterministic per-track-ID waveform with a bins-based one driven by the analysis cache. The bins-based variant is the better default but the old deterministic look is still valuable when no analysis is available (brand-new track, cache-miss, etc.) and several users prefer it. Split into two explicit options in the seekbar style picker: - 'truewave' (default, replaces old 'waveform') — bins from the analysis cache, with morph-on-arrival animation and flat-line fallback while empty. - 'pseudowave' — pseudo-random heights derived deterministically from the track ID. No analysis dependency, no morph, instant render. Existing persisted seekbarStyle: 'waveform' is migrated to 'truewave' in onRehydrateStorage so users keep the visual they have today. The useEffect that builds heightsRef now lists seekbarStyle in its deps so switching between the two is live. i18n labels added in all 8 locales. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -750,7 +750,8 @@ export function drawSeekbar(
|
||||
) {
|
||||
const anim = animState ?? makeAnimState();
|
||||
switch (style) {
|
||||
case 'waveform': drawWaveform(canvas, heights, progress, buffered); break;
|
||||
case 'truewave': drawWaveform(canvas, heights, progress, buffered); break;
|
||||
case 'pseudowave': drawWaveform(canvas, heights, progress, buffered); break;
|
||||
case 'linedot': drawLineDot(canvas, progress, buffered); break;
|
||||
case 'bar': drawBar(canvas, progress, buffered); break;
|
||||
case 'thick': drawThick(canvas, progress, buffered); break;
|
||||
@@ -782,7 +783,7 @@ export function SeekbarPreview({
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
let heights: Float32Array | null = null;
|
||||
if (style === 'waveform') {
|
||||
if (style === 'truewave' || style === 'pseudowave') {
|
||||
heights = makeHeights('seekbar-preview-demo');
|
||||
}
|
||||
const animState = makeAnimState();
|
||||
@@ -896,6 +897,17 @@ export default function WaveformSeek({ trackId }: Props) {
|
||||
heightsRef.current = null;
|
||||
return;
|
||||
}
|
||||
// Pseudowave is the deterministic per-track-ID variant — no analysis needed,
|
||||
// no morph animation, no flat-fallback. It just sits there looking like a
|
||||
// waveform.
|
||||
if (seekbarStyle === 'pseudowave') {
|
||||
heightsRef.current = makeHeights(trackId);
|
||||
const canvas = canvasRef.current;
|
||||
if (canvas && !ANIMATED_STYLES.has(seekbarStyle)) {
|
||||
drawSeekbar(canvas, seekbarStyle, heightsRef.current, progressRef.current, bufferedRef.current, animStateRef.current);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (waveformBins && waveformBins.length > 0) {
|
||||
const h = binsToHeights(waveformBins);
|
||||
const prev = heightsRef.current;
|
||||
@@ -959,7 +971,7 @@ export default function WaveformSeek({ trackId }: Props) {
|
||||
}
|
||||
// No analysis bins yet: render 500 flat bars immediately.
|
||||
heightsRef.current = makeFlatWaveHeights();
|
||||
}, [trackId, waveformBins]);
|
||||
}, [trackId, waveformBins, seekbarStyle]);
|
||||
|
||||
// Imperative subscription — no React re-renders from progress changes.
|
||||
// Static styles draw here; animated styles only update refs.
|
||||
|
||||
Reference in New Issue
Block a user