aqua-feel: headless feel meter + gate; fix PRC SYNTH1 clipping and thruster low-rpm hiss #8

Merged
aqua merged 2 commits from aqua/aqua-feel into main 2026-11-05 15:44:33 +00:00
Member

What

tools/aqua-feel, a headless feel meter. node feel.mjs run renders 81 items offline (every playground patch, the thruster at rpm 300/600/1200/4800, every DingCatalog event on every instrument), measures them, writes report.json + a static gallery, and gates against thresholds.json (exit 1 on failure). Metrics: onset latency, attack (first-peak 10-90%) and slope, crest, sample/true peak and over-1.0 count, BS.1770 integrated loudness, spectral centroid and flux over time, noise-to-tone ratio (flat and A-weighted, tone = temporally smooth spectral lines), low-motion flag (the song-swarm collapse shape).

Nothing was heard. Metrics are evidence for a listener to check, not verdicts. The README and the gallery banner say so.

Reuses tools/aqua-trial/analyze.mjs (mean, spearman, permutationP) and logic.js in feel.mjs correlate, which asks the trial's own question of each metric once listener exports exist. Render path is the playground's faustwasm, not the daemon's native one (README says so).

Fixes made with it (numbers in docs/renders/aqua-feel-2026-11-05.md)

  • prc-synth1-calibrated: sample peak 2.10 -> 0.67, 18,633 overs -> 0, patch gain 1.4 -> 0.45 (pure gain; crest/centroid unchanged). The parity probe in Dx7ReferenceParityTests builds its own script at 1.4 and is untouched.
  • thruster.dsp low rpm: A-weighted noise-to-tone 20.7/23.0/20.1 dB -> 13.1/5.0/12.7 at rpm 300/600/1200 (rpm 4800 10.3 -> 9.7). Rattle idle floor 0.1 -> 0.015, rasp floor 0.3 -> 0.05 (same value at full load), rumble low-pass opens at low load. Centroid drops (rpm 300: 2388 -> 752 Hz): darker as well as less noisy; whether that reads as "more tone" or "muffled" is unheard. thruster-trial.dsp mirrored so its identity test holds; its sweep is now narrower (README note).

Also

  • AquaLower --dings lowers the four Ding instruments + events (tools/aqua-feel/lowered-dings/).
  • Waivers (each must cite a follow-up; stale ones fail): sfxr-classic-classic-sfxr-abstract-golf (+0.9 dBTP, -5.3 LUFS, held noise), sfxr-explosion (3 s without decay).

Tests

  • node tools/aqua-feel/test.mjs: 20 checks on synthetic signals with known answers (BS.1770 level, true peak, clipping, onset/attack, tone-vs-noise incl. a noise-excited resonance, low motion, gate/waiver bookkeeping, WAV header, gallery).
  • node tools/aqua-trial/test.mjs: 15 pass. node tools/aqua-playground/test.mjs: all pass.
  • dotnet test --filter "FullyQualifiedName!~PackageBoundaryTests": 229 pass, 2 skip, 2 fail (Zyn pinned-source and CultMesh leased workers), the known baseline.
  • node tools/aqua-feel/feel.mjs run: gate PASS (81 items, 4 waived, 1 warning).

Not done: browser view of the gallery (HTML is static and unviewed), no CI runner exists to call the gate, the native-path render was not diffed against the faustwasm one.

🤖 Generated with Claude Code

## What `tools/aqua-feel`, a headless feel meter. `node feel.mjs run` renders 81 items offline (every playground patch, the thruster at rpm 300/600/1200/4800, every `DingCatalog` event on every instrument), measures them, writes `report.json` + a static gallery, and gates against `thresholds.json` (exit 1 on failure). Metrics: onset latency, attack (first-peak 10-90%) and slope, crest, sample/true peak and over-1.0 count, BS.1770 integrated loudness, spectral centroid and flux over time, noise-to-tone ratio (flat and A-weighted, tone = temporally smooth spectral lines), low-motion flag (the song-swarm collapse shape). **Nothing was heard.** Metrics are evidence for a listener to check, not verdicts. The README and the gallery banner say so. Reuses `tools/aqua-trial/analyze.mjs` (`mean`, `spearman`, `permutationP`) and `logic.js` in `feel.mjs correlate`, which asks the trial's own question of each metric once listener exports exist. Render path is the playground's faustwasm, not the daemon's native one (README says so). ## Fixes made with it (numbers in `docs/renders/aqua-feel-2026-11-05.md`) - `prc-synth1-calibrated`: sample peak 2.10 -> 0.67, 18,633 overs -> 0, patch gain 1.4 -> 0.45 (pure gain; crest/centroid unchanged). The parity probe in `Dx7ReferenceParityTests` builds its own script at 1.4 and is untouched. - `thruster.dsp` low rpm: A-weighted noise-to-tone 20.7/23.0/20.1 dB -> 13.1/5.0/12.7 at rpm 300/600/1200 (rpm 4800 10.3 -> 9.7). Rattle idle floor 0.1 -> 0.015, rasp floor 0.3 -> 0.05 (same value at full load), rumble low-pass opens at low load. Centroid drops (rpm 300: 2388 -> 752 Hz): darker as well as less noisy; whether that reads as "more tone" or "muffled" is unheard. `thruster-trial.dsp` mirrored so its identity test holds; its sweep is now narrower (README note). ## Also - `AquaLower --dings` lowers the four Ding instruments + events (`tools/aqua-feel/lowered-dings/`). - Waivers (each must cite a follow-up; stale ones fail): `sfxr-classic-classic-sfxr-abstract-golf` (+0.9 dBTP, -5.3 LUFS, held noise), `sfxr-explosion` (3 s without decay). ## Tests - `node tools/aqua-feel/test.mjs`: 20 checks on synthetic signals with known answers (BS.1770 level, true peak, clipping, onset/attack, tone-vs-noise incl. a noise-excited resonance, low motion, gate/waiver bookkeeping, WAV header, gallery). - `node tools/aqua-trial/test.mjs`: 15 pass. `node tools/aqua-playground/test.mjs`: all pass. - `dotnet test --filter "FullyQualifiedName!~PackageBoundaryTests"`: 229 pass, 2 skip, 2 fail (Zyn pinned-source and CultMesh leased workers), the known baseline. - `node tools/aqua-feel/feel.mjs run`: gate PASS (81 items, 4 waived, 1 warning). Not done: browser view of the gallery (HTML is static and unviewed), no CI runner exists to call the gate, the native-path render was not diffed against the faustwasm one. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
tools/aqua-feel renders every playground patch (thruster at four rpm) and every Ding
event on every instrument offline through faustwasm, measures onset latency, attack,
crest, true peak and clipping, BS.1770 loudness, centroid/flux over time, noise-to-tone
ratio (flat and A-weighted) and a low-motion flag, writes report.json plus a static
gallery, and gates against thresholds.json (waivers must cite a follow-up and go stale).
Nothing is heard; metrics are evidence, not verdicts.

Uses it: PRC SYNTH1 calibrated peaked at 2.10 (18,633 overs); shipped patch gain 1.4 to
0.45, peak 0.67. Thruster low-rpm A-weighted noise-to-tone 20.7/23.0 dB at rpm 300/600
down to 13.1/5.0 by cutting the idle rasp and rattle floors and opening the rumble
low-pass at low load. Trial copy mirrored; its README notes the narrower sweep.

AquaLower gains --dings to lower DingCatalog instruments and events.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- attack: peak-hold envelope and a 150 ms window; a 261 Hz tone no longer reads its
  first half-cycle as the attack (warm-bell 0.67 ms -> 3.8 ms, declared 4 ms).
- gate: a rule whose id matches no item fails a full run; waivers carry a bound and
  cover only up to it; a missing metric fails its rule; silent items fail once;
  --only runs gate as partial; silent threshold is -70 dBFS.
- DingCatalogTests: lowered Dings fed to the meter must match the catalog.
- README states NTR window/Q dependence, short-buffer loudness padding and the assumed
  Ding command gain; faust-toolchain-boundary notes the v5 manifest predates the mix change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
aqua merged commit fa1bf3fdbc into main 2026-11-05 15:44:33 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
GameCult/AquaSynth!8
No description provided.