Add dsp::room — image-source ER + SH-domain FDN, verified against the R1–R10 harness#13
Merged
Merged
Conversation
…selected design) Implements the architecture the R1-R10 harness selected (notebooks/ room_model.py, seed 11): Allen-Berkley image sources < 30 ms as nearest-sample taps on a shared delay ring, SH-encoded via evaluate_sh with amplitude prod(beta)/r; 16-line FDN with the verified delay set 431-3989, signed-Hadamard feedback and output matrices, per-line 255-tap linear-phase absorption FIRs fitted to 10^(-3(L+D)/(fs*T60(f))) with loop group delay counted (faithful firwin2 replica over Ooura), ~53 ms octave-shaped injection-aligned input FIRs, SN3D per-order output gains, tail level calibrated to the prototype's energy target. The rejected velvet decorrelator variant is not implemented. Determinism: numpy's PCG64 stream is not reasonably reproducible in C++, so the raw seed-11 draws are baked as generated room_data.h (~780 KB, hrtf_data.h style; scripts/generate_room_data.py regenerates); everything derived is computed at runtime from parameters. Injection alignment is non-causal by up to 2549 samples at 48 kHz -> fixed documented latency_samples() on every path. Rebuilds ride async_rebuilder (decoder idiom) with 256-sample crossfades on adoption; injection convolution is a shared-spectrum partitioned overlap-save whose history lives in the object so parameter swaps stay click-free. FDN state is float32 (documented: loop gain <= ~0.92 per traversal, orthogonal feedback — rounding enters at ~-150 dB and decays at T60; design math is double on the worker). Acceptance: tools/room_render renders the seed-11 config and the notebook's own gate functions evaluate it — every enforced gate matches the prototype (R1 0.437 smp, R4 worst T20 +6.0% band-identical, R7 0.16 dB, R8 0.053, R9 worst dev 0.079 / broadband-re-reference 0.020, R10 byte-identical across processes); ER/tail deviations vs the float64 prototype are <= 3.6e-8. Tests: R1-R3 exact mirrors vs independent image enumeration, per-band T20/EDT (Schroeder estimator in C++), calibration energy, determinism, toggle composition, block-size invariance, mid-stream rebuild continuity, RT-safety allocation guard. 141/141 green under gcc and clang-18, both with AMBITAP_WERROR=ON; clang-format clean (room_data.h excluded alongside the other generated tables). docs/PERCEPTUAL-VERIFICATION.md: R9 broadband regated relative to the diffuse-field reference per the first measurement run (the ideal order-3 reference itself measures 0.429); seed-11 results row added to the log. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
MSVC treats fopen as deprecated (C4996) and the WERROR leg fails on it; binaural_render.cpp's std::ofstream is the repo precedent. Byte-identical output; short writes now detected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The real-time C++ phase of
room~(ROADMAP Wave 3 item 4), implementing exactly the architecture the harness selected in #12: Allen–Berkley image-source early reflections (< 30 ms, SH-encoded point sources) plus the 16-line SH-domain FDN — verified delay set, signed-Hadamard feedback/output, group-delay-corrected per-line absorption FIRs, injection-aligned octave-shaped input FIRs, SN3D per-order gains, energy-calibrated tail.Acceptance is the harness itself:
tools/room_renderrenders the C++ SH IR for the exact seed-11 configuration and the notebook's own gate functions evaluate it. Every enforced gate matches the prototype — R1 arrivals 0.437 samples, R4 worst T20 +6.0% (per-band identical), R7 order balance 0.16 dB, R8 |rE| 0.053, R9 worst per-band IACC deviation 0.079 / broadband-re-reference 0.020, R10 byte-identical across separate processes. ER/tail sample deviations vs the float64 prototype ≤ 3.6e-8.Engineering notes:
room_data.h(regenerated byscripts/generate_room_data.py) since numpy's PCG64 stream isn't reasonably reproducible in C++; everything derived is computed at runtime from parameters.async_rebuilderwith 256-sample adoption crossfades; the partitioned injection convolution keeps its history in the object so parameter swaps are click-free; FDN state is float32 with the reasoning documented in-header (orthogonal feedback, loop gain ≤ ~0.92 — unlike NFC's near-unit-circle poles). Fixed documented latency (latency_samples(), ~53 ms at 48 kHz) from the injection alignment inherent to the verified design.Downstream
ambitap.room~(mono → HOA bus external) is ready on the AmbiTap-Max branch; needs this merged + submodule bump. That completes the ROADMAP object line (16 externals).Test plan
AMBITAP_WERROR=ONroom_data.hexcluded alongside the other generated tables)🤖 Generated with Claude Code
https://claude.ai/code/session_012VeadvCRUHJdneFNwRbFAM
Generated by Claude Code