Skip to content

Hello from autosound-tuning-skill: a Helix bank format (PR ready), hardware-verified Helix notes, and a file-level bridge with REW / TCC #86

Description

@ayukhno

A note on how this was written: this text, and the branch it points to, were produced by an AI coding agent working under my direction and review — the same way, judging by your AGENTS.md, much of Resonalyze is written. So it is written to be read comfortably by whichever agent you point at it as much as by you: file and member names are exact, every claim names its evidence, and every "we can" is something I have actually authorised.

Contact, in case a conversation is easier than issues: ayukhno@gmail.com, or name a messenger and how to reach you there.

Hi — I run autosound-tuning-skill (MIT code, CC BY-SA docs): a REW-driven car-audio tuning method written for AI coding agents, with a Python rew_tool/ (joint-phase summation, an excess-phase EQ-boost gate, crossover realisation against acoustic targets, a versioned DSP-state ledger). Its desktop front-end, Autosound TCC (Apache-2.0, Qt, installs on macOS and Windows 11), is in development: it reads REW live over its API, shows the whole rig (crossovers, delays, gains, per-channel EQ) and puts the AI in a panel; it never writes to the processor. Same doctrine as yours — loopback-referenced sweeps on one time base for phase and timing, moving-mic RTA for magnitude — and the same target hardware (Helix DSP Ultra S is our reference processor).

I read dsp/ end to end (and built it on macOS arm64 — the 1089 tests pass there, which is a nice property of the split you kept). The AlignmentSelection tie-breaks, the sum-loss objective with the dip penalty, and above all the register of refuted ideas in TODO.md are the most useful field notes on multi-way alignment I have seen in the open. Thank you for writing the "why" down.

A few things we can offer, roughly in order of how ready they are:

1. PR ready: the Audiotec-Fischer "Full EQ (30 bands)" bank as an IEqProfileFormat

Branch: ayukhno/Resonalyze@feat/audiotec-fischer-format (one commit on top of main; I will open the PR if you want it). It writes and reads the tab-separated bank the HELIX / MATCH / BRAX PC-Tool imports per channel — the same block REW exports with its Audiotec Fischer equaliser — with PK bells and the LS_Q / HS_Q shelves, always 30 slots, REW's row shapes byte for byte. It is pinned against a real REW export of a 20-band channel. Two design points I would like your view on:

  • The bank has no place for a preamp (channel gain is a separate PC-Tool control), so I added IEqProfileFormat.CarriesPreamp (default true, the same shape as SupportsShelvingFilters) and made the shared round-trip test assert 0 for such a format instead of failing. The EQ Wizard does not yet warn about a non-zero preamp left behind the way it warns about a dropped shelf — recorded as a residual on the "device profile" item in TODO.md. I can do that follow-up, but it is app-side and I cannot run Resonalyze.App.Tests here (macOS), so I kept the first PR to dsp/.
  • More than 30 bands is refused on export (an ArgumentException, which the coordinator already surfaces) rather than truncated.

Verified: Resonalyze.Dsp.Tests 1104/1104 on macOS arm64; the whole solution compiles with -p:EnableWindowsTargeting=true. App/Audio tests will need your Windows CI.

2. Hardware-verified Helix facts for the Q crib / a device profile

From our own bench work on a Helix DSP Ultra S (single-variable A/B: sweep → change one thing → sweep):

  • AP2 is the textbook 2nd-order all-pass. A free fit of the complex ratio recovered the entered f0/Q (fitted 4386 Hz / Q 3.82 against entered 4414 / 4.0, 31° RMS residual). Your AllPassFilter model matches.
  • LS_Q / HS_Q at Q 0.7071 are the RBJ shelf with S = 1 — REW models them as its "LS Q" / "HS Q" types (plain REW "Low/High shelf" is a different definition). Your PeqBandType shelves therefore travel into the bank unchanged.
  • Delays on the virtual-channel layer and the output layer SUM (max 20.82 ms each) — worth a line on any Helix sheet: enter a delay in one layer only.
  • 30 bands per channel; the channel gain is a separate control (hence CarriesPreamp = false above).
  • One honest caveat: the bell Q convention we have only from REW's list and from REW's own export (its Bandwidth column is exactly Fc / Q, i.e. RBJ). We have not measured Helix bell bandwidth at ±12 dB ourselves. If you want that data point, it is a 10-minute measurement on our side — say so.

3. An excess-phase criterion for the boostability mask (method offer, before any PR)

Your EqBoostabilityMask refuses boosts in low-coherence bins and narrow deep nulls. Ours (rew_tool/eq_gate.py) refuses them where the dip is non-minimum-phase: a sliding RMS of the excess-group-delay z-score against a ±1-octave baseline, ANDed with local depth and with the candidate filter actually delivering gain there. The reason we went that way: cabin mids are phase-rough almost everywhere (30–50 % of the band shows anomalies), so phase alone over-blocks, and depth alone cannot tell a fillable shape deficit from an interference null. On the build history of one car it reproduced 7/7 real boost outcomes; on an analytic family of minimum- vs non-minimum-phase combs at matched magnitude — where any depth-only rule is at chance — it scores 90/90 at the operating point. You already have MinimumPhase / ExcessDelay, so the machinery is there. If this interests you I would bring it as a criterion the mask can consult, plus that synthetic test family (it fits your deterministic-DSP-tests style). If not, no PR.

4. Robustness of near-tie candidates (a field observation, for discussion)

One thing our loop learned the hard way: deep interference nulls are chaotic — same-session sweep ratios breathe 4–6 dB RMS (1/12 oct), and a razor-tuned all-pass optimum did not survive one hour between snapshots. We now score joint-phase candidates by the worst null under a small perturbation set (±20 µs delay, ±0.5 dB level, and combinations) rather than at the point. Your candidate list already exposes near-ties; a robustness figure could be a cheap extra tie-break there. Happy to share the perturbation set and the data behind it.

5. A file-level bridge: REW loopback IR → Resonalyze, and Resonalyze → skill / TCC

Today a REW user with a two-input interface and a loopback measures on the same absolute time base you require, but the only way in is your own IR JSON. REW exports IRs as text/WAV with its timing-reference fields (we have a documented list of the API/format quirks — startTime / delay, float32 encoding, loopback offsets — from a year of driving it). If you would accept a "REW impulse response (loopback-referenced)" import that keeps absolute time — as opposed to the recorded-sweep WAV path, which rightly refuses to sum — Virtual DSP and Auto delay would open to the whole REW-with-loopback world, and our skill / TCC could hand IRs and PEQ profiles both ways with no retyping. I can write the spec first and let you say whether it belongs.

6. A second cabin for your calibrations

Your TODO.md says the field data lives outside the repo and several thresholds are field-anchored on your own cabins. We can share ours: a VW Passat B8 sedan, LHD, three-way front (door woofers, A-pillar mids and tweeters) plus a sealed-box sub in the trunk, Helix DSP Ultra S at 96 kHz, measured with a Behringer ECM8000 (0° / 90° calibration files) on a Focusrite Scarlett 2i2 4th gen with a physical loopback — i.e. exactly the rig your README describes. What exists: per-driver loopback-referenced sweeps of all seven channels (sub, woofer L/R, mid L/R, tweeter L/R; measured with the protective high-passes the drivers need engaged (mid ~100 Hz LR4, tweeter ~1 kHz LR4; the exact DSP state of every set is in the audit trail) — which your new ProtectiveHighPassCompensation is for), the matching moving-mic RTA of each channel, several REW sessions across the tune, and the DSP state / audit trail that the ear finally accepted (delays, polarity, crossovers, EQ) so you can score against a real end point, not only against a metric. Tell me the form you would want — REW's IR export (text or WAV, loopback timing kept) per channel plus the measurement settings, or your IR JSON v7 if you would rather I write a converter — and I will prepare it.

One question

Your sub-precedence preference (AlignmentSelection — a slightly leading sub reads as "bass up front", a trailing one as detached) is a rule we do not have. Our L/R-image experience is that below ~150 Hz the image is level/proximity-driven and timing barely moves it — which is a different axis (left/right vs front/attack), so I do not think we disagree, but I would like to understand what evidence pinned it: listening, or a measured figure? It would go straight into our references with attribution.

How would you like to receive these — one issue per topic, PRs, or a thread here? I am fine either way; the format PR is the concrete first step and needs nothing from you but a review.

If a conversation would be easier than issues, e-mail me at ayukhno@gmail.com, or name a messenger and how to reach you there — happy either way.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions