Skip to content

perf(pipeline): single-pass streamed peaks + presence - #306

Merged
thcp merged 1 commit into
mainfrom
perf/streamed-peaks-presence
Jul 17, 2026
Merged

perf(pipeline): single-pass streamed peaks + presence#306
thcp merged 1 commit into
mainfrom
perf/streamed-peaks-presence

Conversation

@thcp

@thcp thcp commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

PR-3B of Phase 3 (Performance).

  • New app/pipeline/audio_stats.py::scan_stem() does one streamed pass over a stem WAV via sf.blocks(), producing both the waveform peaks ([min, max] per bucket) and RMS (for stem presence) from the same blocks. Constant memory — a block is a few MB even for a 20-minute stereo stem, vs. sf.read()'s full in-memory load (~420 MB for the same file, done for up to 8 stems back-to-back right after Demucs has already stressed memory — a plausible contributor to OOM failures on memory-constrained machines like the reported 8 GB Mac Mini).
  • collect.compute_stem_peaks now delegates to scan_stem and additionally returns each stem's RMS. peaks.json's format and bucketing are unchanged — floor-division chunking, matching the old implementation bucket-for-bucket (verified by a golden test comparing against the old sf.read()-then-chunk reference on a real multi-tone signal).
  • runner._run_common now derives stem_presence from that RMS map instead of a second, separate decode. analyze.compute_stem_presence (which spawned its own ffmpeg downmix per stem) is deleted.

Closes #286
Closes #287

Known, accepted delta

Presence RMS is now measured over the full stem at full sample rate, vs. the old ffmpeg-downmixed mono decode capped at the first 180s. Sanity-checked against a real 220s track from a local job folder: this shifted some quiet-stem presence values by up to ~6 points (piano 1→6, other 12→19) — larger than the original estimate of "≲1-2 points," but a strict accuracy improvement (whole track vs. a 3-minute window), not a regression. Loud stems (bass, drums, vocals) moved by 2-6 points too, same direction.

Test plan

  • New tests in tests/test_pipeline_collect.py: RMS matches a full-load np.sqrt(mean(x**2)) reference within tolerance; a stem missing from disk is excluded from the returned RMS map (same as peaks); golden test — streamed peaks match the old sf.read()-then-chunk implementation bucket-for-bucket on a multi-tone signal.
  • New tests in tests/test_pipeline_runner.py for _presence_from_rms: normalizes to the loudest stem, empty input, all-silent input.
  • Manually ran compute_stem_peaks against a real 8-stem job folder (220s track) — correct RMS values, peaks.json written, ~0.8s for all 8 stems.
  • Full suite: 194 passed, 12 skipped
  • ruff check / ruff format --check clean

app/pipeline/audio_stats.py: new scan_stem() does one streamed pass over
a stem WAV via sf.blocks() -- [min, max] per bucket (waveform peaks) and
RMS (stem presence), both from the same blocks. Constant memory: a
block is a few MB even for a 20-minute stereo stem, vs. sf.read()'s full
in-memory load (~420 MB for the same file, done for up to 8 files
back-to-back right after Demucs has already stressed memory -- a
plausible contributor to OOM failures on memory-constrained machines).

collect.compute_stem_peaks now delegates to scan_stem and returns each
stem's RMS from the same pass; peaks.json's format and bucketing are
unchanged (floor-division chunking, matching the old implementation
bucket-for-bucket -- verified by a golden test comparing against the old
sf.read()-then-chunk reference).

runner._run_common now derives stem_presence from that RMS map (moved
out of analyze.compute_stem_presence, which is deleted along with its
separate ffmpeg-downmix decode of every stem) instead of decoding each
stem twice.

Known, accepted delta: presence RMS is now measured over the full
stem at full sample rate, vs. the old ffmpeg-downmixed mono decode
capped at the first 180s. On a real 220s track this shifted some
quiet-stem presence values by up to ~6 points (piano 1->6, other
12->19) -- larger than initially estimated, but a strict accuracy
improvement (whole track, not a 3-minute window), not a regression.

Closes #286
Closes #287
@thcp
thcp merged commit 6eb1741 into main Jul 17, 2026
8 checks passed
@thcp
thcp deleted the perf/streamed-peaks-presence branch July 17, 2026 11:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stem presence re-decodes every stem via ffmpeg Peaks computation loads entire WAVs into RAM

1 participant