forked from Keelrleek/SoulStream
feat: crossfade preview suite, loudness normalization, debug overlay
Preview modal audio, five rounds: - True track-change crossfade: scheduleSettle no longer silences the outgoing clip at t=0; preview_load's equal-power fade owns both ramps, gated on the incoming voice's first Playing event (audible_marks), with failure/overstay fallbacks. CROSSFADE_MS = 340 — locked to the reel's card-slide so audio and visuals land together. - Two-neighbour lease prefetch + a 15-min on-disk clip byte-cache (recent_clips): steps in BOTH directions crossfade in ~15 ms; revisits never re-download. - Adaptive settle (isolated steps fire immediately, bursts coalesce) and anticipatory auto-advance (step at clip end minus 400 ms) so auto-play crossfades over the tail instead of gapping. - Session resume memory: revisited tracks continue where they left off (decoder-level start offset via play_local_from/resume_at); finished tracks restart from the top. - Open/close crossfades with the MAIN player: fade-pause with the desired-paused latch landing at ramp end, fade-resume from the paused position; MAIN_FADE_GEN guards; focus handshake relaxation documented in focusBridge. Volume normalization (Settings > Playback, default on): - Dependency-free BS.1770/EBU R128 meter in the player crate (K-weighting, 400 ms gated blocks, incremental) + analyzer that reads the same growing file playback streams from — first plays are measured at download speed. - Gain layered under user volume; audible start GATED on a preliminary measurement (10 s of audio or 800 ms budget) so the level is right from the first sample and never changes mid-track; prelim boosts capped 3 dB, peak-aware clipping guard, persistent loudness-cache.json. - Gapless boundaries get their own sample-accurate gain via SetNextNormGainDb, fed by preload analysis. Debug overlay (Ctrl+Shift+D): process-tree CPU / PDH GPU / working-set + private-commit RAM / network rates / FPS / current-track download progress read from the backend's own StreamProgress / live normalization state / preview session phase. Polls only while visible. 131 JS + player + app tests green; every path verified live over CDP.
This commit is contained in:
1 parent
5e877c0b0a
commit
793f78370e
27 files changed
+2834
-178
No files matched your search
+14
-10
@@ -6,6 +6,7 @@
|
||||
import ArtworkViewer from "./components/ArtworkViewer.svelte";
|
||||
import LoginModal from "./components/LoginModal.svelte";
|
||||
import PreviewOverlay from "./components/PreviewOverlay.svelte";
|
||||
import DebugOverlay from "./components/DebugOverlay.svelte";
|
||||
import { previewUi } from "./lib/preview/previewSession.svelte.js";
|
||||
import Home from "./views/Home.svelte";
|
||||
import Search from "./views/Search.svelte";
|
||||
@@ -52,21 +53,23 @@
|
||||
class:preview-open={previewUi.open}
|
||||
>
|
||||
<TitleBar />
|
||||
<!-- Previews take over the whole window (decision 2026-07-22): while the
|
||||
modal is open the page and the player bar are inert/not rendered —
|
||||
there is deliberately NO UI path to command main audio behind the
|
||||
focus coordinator's back. The titlebar stays live for window chrome. -->
|
||||
<!-- While the preview modal is open the page is inert and the flanking
|
||||
panels + player bar are pointer-inert under the scrim (user decision
|
||||
2026-07-23: the bar stays VISIBLE, dimmed, like Spotify — un-rendering
|
||||
it left a black hole in the grid's bottom row). There is still no UI
|
||||
path to command main audio behind the focus coordinator's back: the
|
||||
scrim intercepts pointer input and the dialog traps the keyboard.
|
||||
The titlebar stays live for window chrome. -->
|
||||
<Sidebar />
|
||||
<main class="content" use:floatScroll inert={previewUi.open || undefined}>
|
||||
<CurrentView />
|
||||
</main>
|
||||
<NowPlaying />
|
||||
{#if !previewUi.open}
|
||||
<PlayerBar />
|
||||
{/if}
|
||||
<PlayerBar />
|
||||
<PreviewOverlay />
|
||||
<ArtworkViewer />
|
||||
<LoginModal />
|
||||
<DebugOverlay />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -74,10 +77,11 @@
|
||||
no separate chrome color, the panels float beneath it. */
|
||||
/* While the preview modal is open: keyboard is contained by the dialog's
|
||||
focus trap and aria-modal, the content pane is `inert`, and the flanking
|
||||
panels stop taking pointer input here. (The player bar is simply not
|
||||
rendered — see the markup note above.) */
|
||||
panels + player bar stop taking pointer input here — the bar stays
|
||||
visible (dimmed under the scrim) but cannot command main audio. */
|
||||
.app.preview-open :global(.sidebar),
|
||||
.app.preview-open :global(.nowplaying) {
|
||||
.app.preview-open :global(.nowplaying),
|
||||
.app.preview-open :global(.player) {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user