Skip to content

Reuse NumPy buffers and eliminate steady-state HPF/AEC DSP allocations - #3

Merged
egorsmkv merged 1 commit into
mainfrom
perf/reusable-audio-buffers
Oct 8, 2026
Merged

egorsmkv merged 1 commit into
mainfrom
perf/reusable-audio-buffers

Conversation

@egorsmkv

@egorsmkv egorsmkv commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

The default mono/stereo HPF+AEC path now bypasses graph packet allocation and reuses planar buffers. process_into() writes to a caller-owned float32 NumPy array; process_frames_into() amortizes safe NumPy borrowing over a batch. The existing process() API and optional NS/AGC/post-filter graph behavior are preserved, with backend="graph" available for comparison.

Vendor only the aec3 0.4.0 library sources, minimal manifest and LICENSE/PATENT (no upstream workflows, editor instructions, demos, CLI tools, integration tests, release docs or nested lockfile), with four targeted DSP patches: stack FFT scratch, recycled render queue tensors, disabled diagnostic formatting when diagnostics are off, and bounded diagnostic history. Preserve LICENSE/PATENT and document provenance. Include vendored sources in the sdist.

Validation: 124 normal-build tests pass (12 allocation tests intentionally skipped); tracking builds exercise all 136 tests. 24 baseline signal configurations produce bit-identical audio and metrics. Native allocation probe covers 24 rate/channel/HPF configurations, queue overflow, delay/gain changes and 700 seconds of diagnostic history. On Linux, mono processing falls from 105/139/240 µs to 57/76/119 µs at 16/32/48 kHz. The measured medians and limitations are in docs/performance.md; raw JSON outputs are generated locally and are not committed.

Scope of the allocation guarantee: zero native DSP heap allocations after warmup with stable mono/stereo HPF+AEC configuration. Safe NumPy borrow checks still request three allocations (540 bytes) per Python call, independent of batch size; CPython allocations are not measured. DSP format conversion remains necessary, so this is not an end-to-end zero-copy claim. Content-driven core reconfiguration and graph-only optional stages can allocate.

CI covers Linux/macOS/Windows, Python 3.10–3.14, Rust 1.88, lint and allocation probes on all three operating systems.

Batch arrays require C-contiguous row-major layout; Fortran layouts are rejected before DSP state changes.

Python quality: pinned Ruff lint/format and Pyright checks cover tests, benchmarks and examples on Python 3.10, using a packaged float32 NumPy API stub. Fix typed Path handling, potentially uninitialized results, import ordering and strict zip lengths. The quality dependency group is locked in uv.lock. No JSON files remain in the PR tree.

@egorsmkv
egorsmkv force-pushed the perf/reusable-audio-buffers branch from 9ded05f to 714dee2 Compare October 8, 2026 09:16
@egorsmkv
egorsmkv force-pushed the perf/reusable-audio-buffers branch from 714dee2 to 619649e Compare October 8, 2026 09:29
@egorsmkv
egorsmkv merged commit fd90eac into main Oct 8, 2026
21 checks passed
@egorsmkv
egorsmkv deleted the perf/reusable-audio-buffers branch October 8, 2026 09:46
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