Skip to content

Share section FFTs between clips and cache template spectra - #52

Merged
andrewchen5678 merged 7 commits into
mainfrom
correlation-optimizations
Oct 7, 2026
Merged

andrewchen5678 merged 7 commits into
mainfrom
correlation-optimizations

Conversation

@andrewchen5678

Copy link
Copy Markdown
Collaborator

Summary

  • Clips with the same sliding window share one loudness-normalized audio section per chunk; the section's forward FFT is reused and each clip's template spectrum is cached per FFT size.
  • Each correlation's FFT size depends only on the section and that clip, so detections never depend on which other clips are loaded.
  • Zero samples stay at zero when normalizing silence.
  • Detections with the same timestamp are reported to the callback in clip order.
  • Version bumped to 0.4.2.

Validation

  • cargo clippy --all-targets -- -D warnings (also with --features python) and cargo test pass.
  • Real recordings, each decoded to WAV once and run through both main and this branch: 48 RTHK hours (235 detections), 14 am1430 sidecars and 3 881903 sidecars are identical.

🤖 Generated with Claude Code

andrewchen5678 and others added 7 commits October 6, 2026 15:12
Speed up detection roughly 2x with six patterns (5.5s -> 2.45s for two
hours of 8 kHz audio) without pulling in dependencies:

- CorrelationWorkspace/CorrelationTemplate in dsp/correlate.rs transform
  the signal once per chunk, cache each clip's reversed template spectrum
  per FFT size and reuse all FFT buffers across chunks.
- The detector builds one loudness-normalized audio section per chunk
  (longest clip's lookback) shared by all clips; each clip searches for
  candidates from its own lookback offset so candidate semantics stay as
  close as possible to the per-clip sections.
- find_peaks applies the height threshold inside a block-wise local
  maxima scan that vectorizes, instead of collecting every maximum first.
- loudness_normalize works in place; abs and max passes are fused.

Detections are unchanged on every sample, regression clip and long test
file; verification metrics move by at most 3e-4 from the shared FFT size
and loudness window.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sharing one section across all clips let a longer clip's lookback change
the loudness gain and clipping applied to shorter clips, so a quiet match
could be lost just by loading an unrelated pattern. Group clips by
sliding window instead: clips in a group have identical sections and
share the normalization and forward FFT, while every clip's detections
depend only on its own section exactly as before. Adds a regression test
for the quiet-beep-after-loud-audio case.

Also size the correlation FFT to cover the whole signal when the template
is empty, which used to panic on the padded copy.

Detections, debug dumps and audio sections are now byte-identical to the
pre-optimization output on every sample and regression clip.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ections

Cover the branch's changes: template spectrum cache eviction and reuse,
workspaces sized for a group's longest template, the block-wise local
maxima scan against the reference scan for every data length, NaN and
plateau handling across block edges, in-scan height versus filtering
afterwards, section grouping by sliding window, the in-place loudness
normalization, and end-to-end runs where clips sharing a section (and
clips in different groups) match their solo detections exactly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Silence measures -inf LUFS, so the gain is infinite and 0 * inf gave NaN.
Skip zero samples in loudness_normalize so they stay finite, and drop the
NaN-to-zero pass the detector used to paper over it. Outputs for all
sample audio are byte-identical.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Grouping clips by sliding window made the callback order of detections
with identical timestamps follow group order. Break ties by clip index
so the order matches the clip order again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The shared FFT was sized for the longest clip in a sliding-window group,
so a clip's f32 rounding, and with it a peak at the height threshold,
depended on which other clips were loaded. The workspace now transforms
the section at the size each template needs on its own and reuses the
transform while consecutive clips need the same size.

Update the pattern-matching docs for per-group sections and the
workspace/template correlation flow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@andrewchen5678
andrewchen5678 merged commit ff070ac into main Oct 7, 2026
2 checks passed
@andrewchen5678
andrewchen5678 deleted the correlation-optimizations branch October 7, 2026 04:01
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.

1 participant