Repository navigation
Bridge comparison: 44.1 ↔ 48 against libsamplerate, soxr, r8brain and SpeexDSP at matched spec and frontier - #76
Merged
Conversation
…k, docs PR 2 of the comparison plan, in progress: the bridge engine measured against libsamplerate, soxr, r8brain and SpeexDSP at exactly 44.1 <-> 48, both directions, at matched spec and at each library's frontier. - The competitor tooling moves from async/ to the family's tools/compare (fetch recipes, the notebook shims with a new soxr shim for its custom quality spec, the bare-metal mutex stub, a warnings policy), so bridge measures through it without depending on async; the old tap_sr_async_* names are retired words. - bridge/bench/compare (host) and bridge/bench/icount/cmp_main.cpp (M33/M55/Hexagon, 2 s and 4 s, both directions); compare.yml measures both engines' binaries and harvests one record per engine (harvest_compare.py --prefix); update_compare_docs.py derives both docs. - notebooks/bridge_comparison.ipynb, executed: the matched settings are measured by rule (stopband at least the tier's, passband within 0.1 dB at its edge, both directions) and asserted against the benches' constants; THD+N and DR at the 24-bit interface, latency. - bridge/docs/COMPARISON.md with the quality and latency tables; the family index at docs/COMPARISON.md; README and plan links. Still to land: the host table, the harvested record and its derived block. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
Numbers identical to the committed run; only the shim names it prints and the execution timestamps change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
…ost line From the local M55/M33/Hexagon derivation; the committed record follows from the compare.yml dispatch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
One session on this host, median of 5, every subject in both directions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
The first run with the bridge binaries, on this branch's head: bridge's record and its derived block (both directions, three targets), and the async record re-measured on the same run — every async count identical to the committed record, so only its provenance line moves. The bridge block reproduces the local M55/M33/Hexagon derivation in every steady-state cell; two Hexagon construction cells round 0.1 M lower from a constant 1,620-instruction difference in the runner's process start-up. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
tap
pushed a commit
that referenced
this pull request
Oct 10, 2026
The comparison plan (#73, #75, #76, #77) and its follow-up (#78) closed; this is the plan for what the family's plans and ledgers still carry open, sequenced into twelve weeks in three blocks, with "production-ready" defined as a thirteen-row checklist per engine so the verdict can be checked rather than believed. Drafted and then audited by two independent adversarial reviews (one against the trees' facts and settled decisions, one against engineering judgement). The audit changed the draft materially: the book's bridge chapters are done (#68), so they are off the list; rational has no cross-engine validation by design (scipy and decimate.h are its legs); TSan runs async only; four host compilers and three QEMU targets, not the draft's counts; the +1.9 % M55 ratio23_q15_eco drift is ab8fea3's stated move, not a DspTap bump, and the chain rows sit +926/+1,102; the hardware block never ran bridge or rational on silicon; nothing builds with -fno-exceptions; TSan has never seen the converter with two threads; no footprint, stack or worst-single-call figure exists; Setup 1's "< 1 ppm" criterion tests the counting, not the servo, and cheap USB dongles may not own a crystal; the timestamp servo is a four-to-five-week extension, not an overload, and must not be frozen in the release that adds it; "C ABIs frozen" needs a reconciled NULL model, an extension rule, SOVERSION and a compat test. Section 7 holds the six decisions the maintainer takes before week 1, each with a recommendation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
tap
pushed a commit
that referenced
this pull request
Oct 10, 2026
The comparison plan (#73, #75, #76, #77) and its follow-up (#78) closed; this is the plan for what the family's plans and ledgers still carry open, sequenced into twelve weeks in three blocks, with "production-ready" defined as a thirteen-row checklist per engine so the verdict can be checked rather than believed. Drafted and then audited by two independent adversarial reviews (one against the trees' facts and settled decisions, one against engineering judgement). The audit changed the draft materially: the book's bridge chapters are done (#68), so they are off the list; rational has no cross-engine validation by design (scipy and decimate.h are its legs); TSan runs async only; four host compilers and three QEMU targets, not the draft's counts; the +1.9 % M55 ratio23_q15_eco drift is ab8fea3's stated move, not a DspTap bump, and the chain rows sit +926/+1,102; the hardware block never ran bridge or rational on silicon; nothing builds with -fno-exceptions; TSan has never seen the converter with two threads; no footprint, stack or worst-single-call figure exists; Setup 1's "< 1 ppm" criterion tests the counting, not the servo, and cheap USB dongles may not own a crystal; the timestamp servo is a four-to-five-week extension, not an overload, and must not be frozen in the release that adds it; "C ABIs frozen" needs a reconciled NULL model, an extension rule, SOVERSION and a compat test. Section 7 holds the six decisions the maintainer takes before week 1, each with a recommendation. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
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.
What this changes
PR 2 of the comparison plan (after #73 and #75; rational follows). The
bridgeengine measured against the four resampler libraries at exactly 44.1 ↔ 48 kHz, both directions, in quality, latency, host throughput and embedded instruction counts — and the competitor tooling hoisted to the family level so it could be.tools/compare/now holds what every engine's comparison measures the competitors with: the fetch recipes (r8brain, SpeexDSP, and the libsamplerate tarball recipe that was inline in async's icount CMake), the notebook shims (renamedtap_sr_cmp_*, plus a new soxr shim because python-soxr exposes only the named recipes, not the custom quality spec the matched rows need), the bare-metal mutex stub and a warnings policy.asyncreferences it throughTAP_SR_COMPARE_TOOLS; the oldtap_sr_async_*shim and target names are retired words.bridge/bench/compare(host, Google Benchmark) andbridge/bench/icount/cmp_main.cpp(M33/M55/Hexagon, 2 s and 4 s, both directions, 40 binaries per target).compare.ymlmeasures both engines' binaries from one list (scripts/compare_binaries.sh) and harvests one record per engine (harvest_compare.py --prefix);update_compare_docs.pyderives both docs' blocks, async's byte for byte as before.bridge/notebooks/bridge_comparison.ipynb, executed: the AES17-style instrument calibrated at both output rates, the matched-setting sweep, THD+N and DR at the 24-bit interface, latency.bridge/docs/COMPARISON.mdand the family indexdocs/COMPARISON.mdat the root; README and plan links.Why
The async comparison asked what clock recovery costs.
bridgeexists for one ratio pair, so its question is different and cleaner: at that pair, what does each library need to reacheconomy(70 dB, 18 kHz) andtransparent(120 dB, 20 kHz), and what does it pay for it? The matching rule is stated once and applied by measurement: a competitor's matched setting is its cheapest whose measured stopband is at least the tier's and whose passband droops no more than 0.1 dB at the tier's edge, in both directions; its frontier is its best. The notebook asserts the picks against the constants the benches compile in, so the benches cannot drift from the measurement.Verification
MEDIUM(itsFASTESTdroops 4 dB at 18 kHz), soxr 16-bit at a 0.816 passband (its lowest precision), r8brain 70 dB at a 12 % band, SpeexDSP quality 3; transparent —BEST,HQ, r8brain 120 dB at 6 %, SpeexDSP quality 9 (its fixed-point build cannot reach 120 dB, assertedNone).economy−91.4 / −86.2 dB THD+N by direction, its 70 dB imaging floor;transparent−141.7 / −142.9 dB, at the ceiling with every frontier setting. r8brain's economy-matched setting is the one true 70 dB competitor (−88 dB, 71–72 dB worst product); the others overshoot by 15–50 dB because they offer nothing closer. The 16-bit rows (bridge economy Q15, SpeexDSP fixed-point) share the ~98 dB A-weighted floor.WERRORand the C ABIs on, zero warnings; clang-format and clang-tidy clean on the shims and the bridge comparison units (house naming, mandatory braces); retired-words clean; both workflows parse;update_compare_docs.pyidempotent on both records; the async notebook re-executed against the renamed shims with every number identical.compare-smokeCI job's new bridge targets on the hosted compilers (built locally with GCC; this PR's CI is its first run).Notes for the reviewer
BESTon the M33, −1.3 / −3.1 M) are the 2 s / 4 s split's resolution, not a measurement; footnote ⁴ says so rather than clamping the derived number.bridge_comparison.ipynbis new;asrc_comparison.ipynbre-executed because its cell 1 names the shim targets. Both committed executed.cmake/andtools/directories are gone; everything they held is undertools/compare/.PLAN.mdsection 4's layout tree gains the line; its migration record keeps the old paths as history.🤖 Generated with Claude Code
https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
Generated by Claude Code