reduce waveform mem consumption
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
* and a dotted placeholder when idle.
|
* and a dotted placeholder when idle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { createEffect, on } from "solid-js";
|
import { createEffect, createMemo, on, Show } from "solid-js";
|
||||||
import { useTerminalDimensions } from "@opentui/solid";
|
import { useTerminalDimensions } from "@opentui/solid";
|
||||||
import { useVisualizer } from "@/stores/visualizer";
|
import { useVisualizer } from "@/stores/visualizer";
|
||||||
import { useTheme } from "@/context/ThemeContext";
|
import { useTheme } from "@/context/ThemeContext";
|
||||||
@@ -45,46 +45,40 @@ export function RealtimeWaveform() {
|
|||||||
createEffect(on(numBars, (n) => viz.setBarCount(n)));
|
createEffect(on(numBars, (n) => viz.setBarCount(n)));
|
||||||
|
|
||||||
// ── Rendering ──────────────────────────────────────────────────────
|
// ── Rendering ──────────────────────────────────────────────────────
|
||||||
|
//
|
||||||
const renderLine = () => {
|
// The two bar rows are CONTENT of fixed text nodes — the element tree is
|
||||||
|
// created once and only the strings change. Rebuilding the box/texts per
|
||||||
|
// bar update (30/s) tears down a renderable per frame, and the renderer
|
||||||
|
// leaks ~44KB of native memory per teardown: gigabytes over one long
|
||||||
|
// playback session.
|
||||||
|
const lines = createMemo(() => {
|
||||||
const bars = viz.barData();
|
const bars = viz.barData();
|
||||||
const count = numBars();
|
|
||||||
|
|
||||||
// Loading state: the braille spinner shows while the pipeline is
|
|
||||||
// warming up — cold start (first play / after an unload), resume
|
|
||||||
// into undecoded audio, or a stalled position clock (mpv
|
|
||||||
// re-buffering after a long pause on a network stream). The store
|
|
||||||
// clears it the moment the first fresh frame renders, so stale
|
|
||||||
// bars never masquerade as live data while the pipeline re-arms.
|
|
||||||
if (viz.isLoading() || viz.isStalled()) {
|
|
||||||
return <LoadingIndicator />;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bars.length === 0) {
|
if (bars.length === 0) {
|
||||||
const placeholder = ".".repeat(count);
|
const placeholder = ".".repeat(numBars());
|
||||||
return (
|
return { top: placeholder, bottom: placeholder };
|
||||||
<box flexDirection="column" gap={0}>
|
|
||||||
<text fg={theme.primary}>{placeholder}</text>
|
|
||||||
<text fg={theme.primary}>{placeholder}</text>
|
|
||||||
</box>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pairs = bars.map((v) => barChars(Math.floor(v * BAR_LEVELS)));
|
const pairs = bars.map((v) => barChars(Math.floor(v * BAR_LEVELS)));
|
||||||
const top = pairs.map((pair) => pair.top).join("");
|
return {
|
||||||
const bottom = pairs.map((pair) => pair.bottom).join("");
|
top: pairs.map((pair) => pair.top).join(""),
|
||||||
|
bottom: pairs.map((pair) => pair.bottom).join(""),
|
||||||
return (
|
|
||||||
<box flexDirection="column" gap={0}>
|
|
||||||
<text fg={theme.primary}>{top}</text>
|
|
||||||
<text fg={theme.primary}>{bottom}</text>
|
|
||||||
</box>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box border borderColor={theme.border} padding={1}>
|
<box border borderColor={theme.border} padding={1}>
|
||||||
{renderLine()}
|
{/* Loading: braille spinner while the pipeline warms up — cold
|
||||||
|
start, resume into undecoded audio, or a stalled position
|
||||||
|
clock. The store clears it the moment the first fresh frame
|
||||||
|
renders, so stale bars never masquerade as live data. */}
|
||||||
|
<Show
|
||||||
|
when={!viz.isLoading() && !viz.isStalled()}
|
||||||
|
fallback={<LoadingIndicator />}
|
||||||
|
>
|
||||||
|
<box flexDirection="column" gap={0}>
|
||||||
|
<text fg={theme.primary}>{lines().top}</text>
|
||||||
|
<text fg={theme.primary}>{lines().bottom}</text>
|
||||||
|
</box>
|
||||||
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user