Skip to content

Bridge comparison: 44.1 ↔ 48 against libsamplerate, soxr, r8brain and SpeexDSP at matched spec and frontier - #76

Merged
tap merged 5 commits into
mainfrom
claude/sample-rate-solutions-comparison-mqc190
Oct 10, 2026
Merged

tap merged 5 commits into
mainfrom
claude/sample-rate-solutions-comparison-mqc190

Conversation

@tap

@tap tap commented Oct 9, 2026

Copy link
Copy Markdown
Owner

What this changes

PR 2 of the comparison plan (after #73 and #75; rational follows). The bridge engine 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 (renamed tap_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. async references it through TAP_SR_COMPARE_TOOLS; the old tap_sr_async_* shim and target names are retired words.
  • bridge/bench/compare (host, Google Benchmark) and bridge/bench/icount/cmp_main.cpp (M33/M55/Hexagon, 2 s and 4 s, both directions, 40 binaries per target). compare.yml measures both engines' binaries from one list (scripts/compare_binaries.sh) and harvests one record per engine (harvest_compare.py --prefix); update_compare_docs.py derives 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.md and the family index docs/COMPARISON.md at the root; README and plan links.

Why

The async comparison asked what clock recovery costs. bridge exists for one ratio pair, so its question is different and cleaner: at that pair, what does each library need to reach economy (70 dB, 18 kHz) and transparent (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

  • Matched settings (notebook, asserted): economy — libsamplerate MEDIUM (its FASTEST droops 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, asserted None).
  • Quality (notebook, 24-bit interface, asserted for bridge's rows): 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.
  • Embedded counts: CI-measured (run 37985746994, the first with the bridge binaries). The record reproduces the local derivation in every steady-state cell; two Hexagon construction cells round 0.1 M lower from a constant 1,620-instruction start-up offset on the runner. The async record re-measured on the same run is identical to the committed one in every count. Headline: bridge economy Q15 is the cheapest row on every target (209 / 419 / 235 instructions per stereo frame on M55 / M33 / Hexagon going down), 3× under r8brain's matched setting on the M55 and 13–34× on the soft-double targets.
  • Host table: one session, median of 5, all 34 subjects. soxr and r8brain's FFT engines win raw throughput at 1.5–17× bridge's matched tier (paid in latency); bridge is 3–5× faster than the other polyphase engines (libsamplerate, SpeexDSP).
  • Gates: the family battery, 305/305 with every engine's WERROR and 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.py idempotent on both records; the async notebook re-executed against the renamed shims with every number identical.
  • Not run: the compare-smoke CI 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

  • The finding the doc states plainly: in float, r8brain's FFT block convolution undercuts bridge's direct-form polyphase at both tiers on every target (0.8–1.0× economy's per-frame cost, 0.3–0.6× transparent's), at 4–15× the latency. bridge wins in Q15, which r8brain lacks. PLAN.md section 7 defers the multistage and FFT levers "until a consumer pulls them"; this table is the measurement that says by how much.
  • Negative construction cells (libsamplerate BEST on 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.
  • Notebooks re-executed: bridge_comparison.ipynb is new; asrc_comparison.ipynb re-executed because its cell 1 names the shim targets. Both committed executed.
  • Async's cmake/ and tools/ directories are gone; everything they held is under tools/compare/. PLAN.md section 4's layout tree gains the line; its migration record keeps the old paths as history.
  • One new third-party fetch path, no new third party: the soxr shim links the system package the host bench already required.

🤖 Generated with Claude Code

https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK


Generated by Claude Code

claude added 5 commits October 9, 2026 19:56
…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
tap merged commit ab00eb8 into main Oct 10, 2026
30 checks passed
@tap
tap deleted the claude/sample-rate-solutions-comparison-mqc190 branch October 10, 2026 00:33
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
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.

2 participants