diff --git a/docs/renders/aqua-feel-native-diff-2026-11-10.json b/docs/renders/aqua-feel-native-diff-2026-11-10.json new file mode 100644 index 0000000..35b0987 --- /dev/null +++ b/docs/renders/aqua-feel-native-diff-2026-11-10.json @@ -0,0 +1,278 @@ +{ + "libfaustWasm": "2.90.19", + "sampleRate": 48000, + "items": "core", + "smoother": "library", + "rows": [ + { + "id": "thruster@rpm300", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.026072267442941666, + "maxErrAt": 142707, + "rmsErr": 0.002385837227503057, + "relRmsErrDb": -28.770505442344437, + "wasm": { + "samplePeak": 0.14264661073684692, + "truePeakDb": -16.90120405295226, + "loudnessLufs": -30.226833288468896, + "centroidMedianHz": 751.9185607592701, + "overSamples": 0, + "rmsDb": -23.676437109698263, + "crestDb": 6.761666256511239, + "noiseToToneDb": -6.937988717513285, + "noiseToToneADb": 13.092512355240387, + "lowMotion": false + }, + "native": { + "samplePeak": 0.14242461323738098, + "truePeakDb": -16.915261179402926, + "loudnessLufs": -30.216031113774466, + "centroidMedianHz": 751.528437557621, + "overSamples": 0, + "rmsDb": -23.670746205832152, + "crestDb": 6.74244718138185, + "noiseToToneDb": -6.888378522251635, + "noiseToToneADb": 13.056342933565631, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "thruster@rpm600", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.049423644319176674, + "maxErrAt": 142945, + "rmsErr": 0.004812282166272209, + "relRmsErrDb": -23.51217894411906, + "wasm": { + "samplePeak": 0.15958738327026367, + "truePeakDb": -15.926835268189564, + "loudnessLufs": -28.69474712970973, + "centroidMedianHz": 1227.9568144573402, + "overSamples": 0, + "rmsDb": -22.840558133782523, + "crestDb": 6.900529208325618, + "noiseToToneDb": -0.7035305515542589, + "noiseToToneADb": 5.044756311984671, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1601162701845169, + "truePeakDb": -15.90057398970821, + "loudnessLufs": -28.709339901369557, + "centroidMedianHz": 1224.4350816353904, + "overSamples": 0, + "rmsDb": -22.846021449137904, + "crestDb": 6.934730747403392, + "noiseToToneDb": -0.6166079485198495, + "noiseToToneADb": 6.053873560512358, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "thruster@rpm1200", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.08972565084695816, + "maxErrAt": 143228, + "rmsErr": 0.012448641233006897, + "relRmsErrDb": -16.610480431926955, + "wasm": { + "samplePeak": 0.19161102175712585, + "truePeakDb": -14.343339234769212, + "loudnessLufs": -26.051033400616078, + "centroidMedianHz": 2114.222071076734, + "overSamples": 0, + "rmsDb": -21.48680915202533, + "crestDb": 7.1352188868162605, + "noiseToToneDb": -4.949059402813134, + "noiseToToneADb": 12.652391835948997, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1893547624349594, + "truePeakDb": -14.423961460001248, + "loudnessLufs": -26.05070520432609, + "centroidMedianHz": 2115.6363534197994, + "overSamples": 0, + "rmsDb": -21.484457233344667, + "crestDb": 7.029981882815694, + "noiseToToneDb": -4.965083035181173, + "noiseToToneADb": 12.716143920958068, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "thruster@rpm4800", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.2870774045586586, + "maxErrAt": 142979, + "rmsErr": 0.054912511748541046, + "relRmsErrDb": -8.246006212467824, + "wasm": { + "samplePeak": 0.36383503675460815, + "truePeakDb": -8.715719927350808, + "loudnessLufs": -17.418922989049733, + "centroidMedianHz": 4914.23686401765, + "overSamples": 0, + "rmsDb": -16.959964506391177, + "crestDb": 8.17805487903365, + "noiseToToneDb": -2.834032055202698, + "noiseToToneADb": 9.67560044209106, + "lowMotion": false + }, + "native": { + "samplePeak": 0.3622153401374817, + "truePeakDb": -8.742560302886037, + "loudnessLufs": -17.424886445264, + "centroidMedianHz": 4908.148280531137, + "overSamples": 0, + "rmsDb": -16.961323502311725, + "crestDb": 8.140660284709858, + "noiseToToneDb": -2.9540607279645457, + "noiseToToneADb": 9.40924191267517, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "sfxr-classic-classic-sfxr-abstract-golf", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000002171844244003296, + "maxErrAt": 117685, + "rmsErr": 9.912912629276112e-8, + "relRmsErrDb": -134.45251378934543, + "wasm": { + "samplePeak": 0.9895820021629333, + "truePeakDb": 0.9076630707842905, + "loudnessLufs": -5.327743141800993, + "centroidMedianHz": 8147.614236982103, + "overSamples": 0, + "rmsDb": -5.623460642702886, + "crestDb": 5.532496403571967, + "noiseToToneDb": -0.9960950126656059, + "noiseToToneADb": 7.586387572827178, + "lowMotion": true + }, + "native": { + "samplePeak": 0.9895820021629333, + "truePeakDb": 0.9076628030277624, + "loudnessLufs": -5.327743184793801, + "centroidMedianHz": 8147.614175634302, + "overSamples": 0, + "rmsDb": -5.623460696287697, + "crestDb": 5.5324964571567765, + "noiseToToneDb": -0.9960947920917818, + "noiseToToneADb": 7.5863877077205615, + "lowMotion": true + }, + "flagsWasm": [ + "waived truePeakDb", + "waived lowMotion", + "waived loudnessLufs", + "warn truePeakDb" + ], + "flagsNative": [ + "waived truePeakDb", + "waived lowMotion", + "waived loudnessLufs", + "warn truePeakDb" + ], + "violations": [] + }, + { + "id": "sfxr-explosion", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000002158805727958679, + "maxErrAt": 129292, + "rmsErr": 1.1522412234189382e-7, + "relRmsErrDb": -127.13848106038596, + "wasm": { + "samplePeak": 0.6732206344604492, + "truePeakDb": -3.0561513953602306, + "loudnessLufs": -8.634121016036506, + "centroidMedianHz": 9795.322296183533, + "overSamples": 0, + "rmsDb": -11.630620604104497, + "crestDb": 8.193768979977403, + "noiseToToneDb": 60, + "noiseToToneADb": 60, + "lowMotion": true + }, + "native": { + "samplePeak": 0.6732206344604492, + "truePeakDb": -3.0561512376276347, + "loudnessLufs": -8.634121064908708, + "centroidMedianHz": 9795.322310734966, + "overSamples": 0, + "rmsDb": -11.630620652864625, + "crestDb": 8.193769028737531, + "noiseToToneDb": 60, + "noiseToToneADb": 60, + "lowMotion": true + }, + "flagsWasm": [ + "waived lowMotion" + ], + "flagsNative": [ + "waived lowMotion" + ], + "violations": [] + }, + { + "id": "tract/vowel-a", + "lenWasm": 34560, + "lenNative": 34560, + "maxErr": 0.0001921914517879486, + "maxErrAt": 28187, + "rmsErr": 0.000046111049670587934, + "relRmsErrDb": -52.60441410619507, + "wasm": { + "samplePeak": 0.08378415554761887, + "truePeakDb": -21.518327105526673, + "loudnessLufs": -34.251568232392565, + "centroidMedianHz": 1937.1220888731689, + "overSamples": 0, + "rmsDb": -33.80275018649363, + "crestDb": 12.265988122620389, + "noiseToToneDb": -10.436050344670264, + "noiseToToneADb": -12.885220061403881, + "lowMotion": false + }, + "native": { + "samplePeak": 0.08390921354293823, + "truePeakDb": -21.50539262673788, + "loudnessLufs": -34.23471535099468, + "centroidMedianHz": 1937.2296872141594, + "overSamples": 0, + "rmsDb": -33.78684837329708, + "crestDb": 12.263041385142849, + "noiseToToneDb": -10.447393994101596, + "noiseToToneADb": -12.89873810612136, + "lowMotion": false + }, + "flagsWasm": [ + "FAIL onsetMs" + ], + "flagsNative": [ + "FAIL onsetMs" + ], + "violations": [] + } + ] +} \ No newline at end of file diff --git a/docs/renders/aqua-feel-native-diff-2026-11-10.md b/docs/renders/aqua-feel-native-diff-2026-11-10.md new file mode 100644 index 0000000..b3c6040 --- /dev/null +++ b/docs/renders/aqua-feel-native-diff-2026-11-10.md @@ -0,0 +1,118 @@ +# aqua-feel: faustwasm vs the daemon's native libfaust path + +**Nothing here was heard.** Numbers from offline buffers, same Faust source, 48 kHz, mono, 512-frame blocks, same params. + +- wasm side: `tools/aqua-feel/render.js` (faustwasm 0.20.0, libfaust 2.90.19 and the stdlib bundled with it, `-ftz 2`). +- native side: `tools/FaustNativeRender` over `AquaSynthPatchCompiler` (`NativeFaustRuntime.cs:530`: `-single -ftz 2 -vec -lv 1`), libfaust 2.90.20 + LLVM built in the Linux sandbox 2026-10-31, with the stdlib `faustlibraries-20261031` (master 3d8c6ef) from `AQUASYNTH_FAUST_HOME`. **The two sides compile against different standard-library text**, and that decides the thruster result below; "native" here means this sandbox's library, which the repo does not pin (`docs/faust-toolchain-boundary.md`: the host's `share/faust`). +- driver: `node tools/aqua-feel/native-diff.mjs --tract `; raw numbers in `aqua-feel-native-diff-2026-11-10.json`. +- tract voice: `vowel-a` Faust source from the 2026-11-08 render kit (0.72 s, default controls). Not in the repo (`--tract` takes a path), not an aqua-feel catalog item, so its `FAIL onsetMs` is the patch-group rule applied by this script, not a repo gate result. +- the script exits 1 on a render error, a length mismatch, or a violation of its `LIMITS` (see "Tolerance in `native-diff.mjs`" below); the verdicts here are the reader's. +- Nothing here was heard. + +Columns are wasm / native. + +| item | max abs err (at sample) | err vs signal RMS | sample peak | centroid Hz | LUFS | true peak dBTP | gate flags | +|---|---|---|---|---|---|---|---| +| thruster rpm300 | 2.6e-2 (142707) | -28.8 dB | .1426/.1424 | 751.9/751.5 | -30.227/-30.216 | -16.90/-16.92 | none / none | +| thruster rpm600 | 4.9e-2 | -23.5 dB | .1596/.1601 | 1228.0/1224.4 | -28.695/-28.709 | -15.93/-15.90 | none / none | +| thruster rpm1200 | 9.0e-2 | -16.6 dB | .1916/.1894 | 2114.2/2115.6 | -26.051/-26.051 | -14.34/-14.42 | none / none | +| thruster rpm4800 | 2.9e-1 | -8.2 dB | .3638/.3622 | 4914.2/4908.1 | -17.419/-17.425 | -8.72/-8.74 | none / none | +| sfxr classic abstract-golf | 2.2e-6 | -134.5 dB | .9896/.9896 | 8147.6/8147.6 | -5.328/-5.328 | +0.908/+0.908 | waived truePeakDb, lowMotion, loudnessLufs; warn truePeakDb / identical | +| sfxr explosion | 2.2e-6 | -127.1 dB | .6732/.6732 | 9795.3/9795.3 | -8.634/-8.634 | -3.06/-3.06 | waived lowMotion / identical | +| tract vowel-a | 1.9e-4 | -52.6 dB | .08378/.08391 | 1937.1/1937.2 | -34.252/-34.235 | -21.52/-21.51 | FAIL onsetMs / identical | + +Hiss caps (noiseToToneADb, wasm / native; cap): rpm300 13.09/13.06 (16), rpm600 5.04/6.05 (8), rpm1200 12.65/12.72 (15). rpm4800 9.68/9.41 (no cap). + +## Verdict + +**sfxr (two items): the paths agree** to float rounding (2e-6). These two patches use no library smoother (`smooth01` and a local `seg_smooth`), so the agreement says nothing about the library difference below. The gate flags are the script's `gate()` applied to each side's metrics for these two items only; they match. + +**Tract voice: agrees to -52.6 dB** (max 1.9e-4 on a 0.084 peak); metrics within 0.02 dB and 0.01 % centroid. The residual is the same library difference: the source calls `si.smoo` 101 times; with the old smoother form pinned on both sides the error is -61.2 dB, with the new form pinned on both it is 3.1e-7 (-109.3 dB). + +**Thruster: waveforms diverge, level and spectrum metrics stay close.** Relative RMS error -28.8 dB at rpm300 to -8.2 dB at rpm4800. At rpm4800 it grows over time: windowed -53, -33, -22, -15, -10 and -4 dB for 0-0.25, 0.25-0.5, 0.5-1, 1-1.5, 1.5-2 and 2-3 s. Differences in the metrics: LUFS 0.015 dB, true peak 0.081 dB, sample peak 1.2 %, centroid 0.3 %, crest 0.11 dB, hiss within 0.27 dB except rpm600 A-weighted, 1.0 dB higher native. + +### Cause (isolated by a separate Soul pass, 2026-11-10) + +The thruster smooths `rpm` with `si.smooth(ba.tau2pole(0.2))`, and every oscillator integrates that into phase. The two library texts define `si.smooth` differently: + +- the wasm bundle (libfaust 2.90.19, `/usr/share/faust`): `smooth(s) = *(1.0 - s) : + ~ *(s)`. In float32 it stalls: the rpm freezes at **4796.632** from sample ~72063 (1.5 s) for a target of 4800. A float32 simulation without fused multiply-add reproduces 4796.6318359375. +- the native overlay (faustlibraries master 3d8c6ef, `signals.lib:391`): `smooth = imp(3)`, an error-form recursion whose comment says it cannot stall. It reaches 4800.0001. + +Evidence that the library text, not `-vec`, `-lv`, `-double` or contraction, decides it: the `faust` CLI emits the same update expression for the same `si.smooth` source under scalar, `-vec -lv 0/1` and `-double`. With the old explicit form pinned in the DSP on both sides, native ends at 4797.6573 (LLVM does contract to FMA, which moves the stall point from 4796.632 to 4797.657, matching the FMA simulation) and wasm at 4796.6319. With the explicit `imp(3)` form pinned on both sides, thruster error falls from 2.61e-2 to 5.7e-7 (rpm300, -120.3 dB) and from 2.87e-1 to 1.13e-4 (rpm4800, -80.5 dB). The stall point is also hypersensitive: one ulp on the pole constant gives 4799.38 or 4798.57. + +The earlier version of this report said the cause was the float32 rounding of the smoother on a native path that "does not stall for an unisolated reason" and suggested `-vec`; that was wrong. The `wander` term is not the cause (removing it leaves rpm300 2.62e-2, rpm4800 2.89e-1). + +The isolation probes are scratch scripts in `/var/lib/mind-aqua-self/soul-nd-1` (not committed); the numbers above are not in the `.json`, which holds the seven main rows plus the tract. + +### What this does and does not invalidate + +- Level, true-peak, centroid, crest and hiss claims for the thruster hold on both libraries within the numbers above. The rpm600 hiss cap (8 dB) has 1.95 dB of headroom with the native library, not the 2.96 dB the threshold note assumes; still passes. +- Sample- or phase-level comparisons of the thruster (null tests, exact waveform diffs, sub-ms timing of the rotor tone) are specific to the library that rendered them. +- Which library a given daemon uses depends on its `share/faust`. A daemon shipping a release stdlib with the old `si.smooth` would stall like wasm; this sandbox's would not. The only Windows Faust install found (Starfire, 2.85.5) has the old form; see the section on the production stdlib below. +- **Not tested:** the other aqua-feel items that do not call `si.smooth`/`si.smoo` (the 81 items are 45 patch renders and 36 Ding event mixes; this report covers 12 sources plus the tract), the Ding event mixes (only one note per instrument is rendered below), block sizes other than 512, and any live (non-offline) host. + +## Toolchain + +dotnet 10.0.403 builds `FaustNativeRender` with `/var/lib/mind-aqua-self/env-review.sh`. Re-running the script reproduces the JSON byte for byte. + +## Which stdlib the production daemon compiles against (2026-11-10) + +The repo neither vendors nor pins faustlibraries (`.gitmodules` holds only zynaddsubfx and pink-trombone-mod). `NativeFaustRuntime.cs:530` passes `-I /share/faust`, and `AquaSynthFaustToolchain.Find` (`NativeFaustRuntime.cs:651`) takes `home` from `AQUASYNTH_FAUST_HOME`, then `AQUARIUM_FAUST_HOME`, then `Tools/Faust` beside the app, then `C:\Program Files\Faust` (Windows) or `/usr/local`, `/usr`. So the daemon compiles against whatever Faust install the host has. + +| host | Faust | `si.smooth` in its `signals.lib` | stalls (float32)? | +|---|---|---|---| +| Starfire `C:\Program Files\Faust` (read over ssh; faust.exe 2.85.5, `signals.lib` 2026-03-20, `smooth = smooth_imp(0)`, line 382) | 2.85.5 | `(1.0 - s) * x + s * y`, the same recursion as wasm's | yes, by the same mechanism | +| aqua-feel's wasm bundle (faustwasm 0.20.0, libfaust 2.90.19; embedded `signals.lib`) | 2.90.19 | `smooth(s) = *(1.0 - s) : + ~ *(s)` | yes: 4796.632 | +| this sandbox (`faustlibraries-20261031`, master 3d8c6ef, a one-commit shallow clone) | 2.90.20 | `smooth = imp(3)` with a comment on the stall | no | + +I read only that Starfire file's `smooth` definition; I did not render on Starfire. On the evidence, the Windows daemon uses the old form, so **aqua-feel's wasm numbers are the closer model of that host than this sandbox's native render is**; the sandbox's imp(3) library is not what any shipped host has. Whether the daemon runs on Starfire in production is not established here; it is the only Windows Faust install found. + +## The twelve sources that call `si.smooth` / `si.smoo` + +The earlier "eleven" was seven patches, three Ding instruments and the larynx graph; the catalog has seven patches besides the thruster **including** the larynx graph, and **four** Ding instruments (`muted-pluck` was missed). Rendered: the thruster at rpm 1200, those seven patches, and one note per instrument (261.6256 Hz, 1.5 s, not the mixed event). Three conditions, each the same Faust text on both sides: as shipped (each side's own stdlib), the old smoother pinned (`nd_smooth(s) = *(1.0 - s) : + ~ *(s)`), and imp(3) pinned. Pinning rewrites `si.smooth` and `si.smoo` in the source text; a smoother called inside another library function is not rewritten, which may account for the `dx7-algorithm-32` residual below. The tract voice rides along as a thirteenth row. Columns are native minus wasm. Raw rows: `aqua-feel-native-diff-smoother-{library,old,imp3}-2026-11-10.json`. + +| source | stdlib as shipped (wasm bundle vs sandbox): max err / rel RMS dB | old smoother pinned | imp3 pinned | ΔLUFS lib / old / imp3 | Δ true peak dB lib / old / imp3 | Δ centroid % lib / old / imp3 | +|---|---|---|---|---|---|---| +| thruster@rpm1200 | 9.0e-2 / -16.6 | 4.5e-2 / -21.2 | 7.1e-6 / -99.9 | 0.000 / 0.001 / -0.000 | -0.081 / -0.152 / 0.000 | 0.07 / -0.08 / 0.00 | +| advanced-alien-multivalve-graph | 2.9e-5 / -68.4 | 1.0e-5 / -72.5 | 7.9e-7 / -97.9 | -0.000 / -0.000 / -0.000 | -0.001 / -0.000 / -0.000 | -0.00 / 0.00 / 0.00 | +| advanced-bird-syrinx | 2.8e-3 / -27.3 | 1.6e-3 / -31.7 | 3.2e-6 / -88.3 | -0.001 / -0.001 / -0.000 | -0.000 / -0.000 / -0.000 | -0.00 / -0.00 / 0.00 | +| advanced-bird-syrinx-graph | 9.4e-4 / -38.4 | 2.7e-4 / -47.1 | 1.5e-5 / -75.4 | 0.000 / -0.000 / 0.000 | 0.000 / 0.000 / -0.000 | -0.01 / 0.00 / -0.00 | +| advanced-syrinx-voice | 1.3e-3 / -23.9 | 3.6e-4 / -34.6 | 2.3e-6 / -86.3 | 0.001 / 0.000 / 0.000 | 0.003 / 0.003 / -0.000 | -0.00 / -0.00 / 0.00 | +| advanced-human-larynx-graph | 9.6e-5 / -38.1 | 3.3e-5 / -46.6 | 7.6e-7 / -94.2 | 0.002 / 0.001 / -0.000 | 0.002 / 0.001 / -0.000 | 0.05 / 0.05 / 0.04 | +| dx7-algorithm-32-additive-organ | 1.7e-4 / -79.3 | 1.6e-4 / -79.5 | 1.6e-4 / -79.5 | 0.000 / -0.000 / 0.000 | -0.000 / -0.000 / -0.000 | -0.00 / -0.00 / -0.00 | +| dx7-algorithm-8-bright-pair | 4.1e-6 / -94.5 | 4.2e-6 / -94.2 | 3.9e-6 / -94.7 | 0.000 / 0.000 / 0.000 | -0.000 / -0.000 / -0.000 | 0.00 / 0.00 / -0.00 | +| ding-instrument/glass-chime | 3.8e-2 / -18.4 | 2.5e-2 / -21.9 | 3.3e-7 / -130.0 | 0.000 / 0.000 / 0.000 | -0.000 / 0.000 / -0.000 | 0.02 / 0.01 / -0.00 | +| ding-instrument/muted-pluck | 6.6e-4 / -49.8 | 6.1e-4 / -50.2 | 3.0e-8 / -141.7 | -0.000 / -0.000 / -0.000 | -0.000 / -0.000 / -0.000 | 0.00 / -0.01 / -0.00 | +| ding-instrument/soft-triangle | 4.3e-3 / -30.3 | 2.4e-3 / -35.2 | 4.5e-8 / -142.0 | 0.000 / -0.000 / -0.000 | -0.000 / -0.000 / 0.000 | 0.16 / 0.12 / -0.00 | +| ding-instrument/warm-bell | 5.4e-2 / -18.3 | 3.2e-2 / -22.9 | 2.3e-7 / -134.2 | 0.000 / 0.000 / -0.000 | -0.000 / 0.000 / -0.000 | 0.01 / 0.00 / -0.00 | +| tract/vowel-a | 1.9e-4 / -52.6 | 6.7e-5 / -61.2 | 3.1e-7 / -109.3 | 0.017 / 0.006 / -0.000 | 0.013 / 0.004 / -0.000 | 0.01 / 0.01 / -0.00 | + +Largest metric deltas over all sources and the three conditions: |LUFS| 0.017 dB (tract), |true peak| 0.152 dB (thruster, old pinned), |centroid| 0.16 % (soft-triangle; the earlier core run has 0.3 % at thruster rpm600). **No gate flag differs on any source in any condition**; the tract's patch-group `FAIL onsetMs` is on both sides (see above). + +What the data says: + +- With imp(3) pinned on both sides all 13 rows agree to -75 dB or better (Ding instruments -130 to -142 dB, thruster -99.9 dB, tract -109 dB; worst: `advanced-bird-syrinx-graph` -75.4 dB). `dx7-algorithm-32-additive-organ` sits at -79.3 (library), -79.5 (old) and -79.5 dB (imp3), so its residual is not the pinned smoother (a smoother inside a library function, or float rounding; not isolated). +- With the old smoother pinned the thruster still differs (-21.2 dB): native's LLVM contracts the recursion to FMA and stalls at 4797.657 instead of wasm's 4796.632. The old form's stall point depends on the arithmetic; the imp(3) form does not. +- As shipped, nine of the 13 rows differ at waveform level by -16 to -50 dB (thruster, the three syrinx patches, the larynx graph, all four Ding instruments); `advanced-alien-multivalve-graph` (-68 dB), the tract (-52.6 dB) and the two dx7 patches are closer. + +## Tolerance in `native-diff.mjs` + +Added, because the data shows a gap. Across all 13 sources and the 3 conditions the metric deltas stay under |LUFS| 0.017 dB, |true peak| 0.152 dB, centroid 0.3 %. A deliberate +1 dB gain on the native buffer moves LUFS and true peak by 1.0 dB. The limits sit between: 0.1 dB, 0.5 dB, 1 %. Sample-level error has no limit with the library smoother (the waveforms legitimately diverge), but with `--smoother imp3` it has one at -60 dB (the worst row is -75.4 dB; a one-sample shift reads about -4 dB). + +Mutation check on the tool, `--items smoother --smoother imp3`: unmutated, 12 of 12 clean, exit 0; +1 dB native gain, 12 of 12 flagged (`loudnessLufs`, `truePeakDb`, `relRmsErrDb`), exit 1; one-sample native shift, 12 of 12 flagged (`relRmsErrDb`), exit 1. A one-sample shift is not detectable with the library smoother; `loudnessLufs`, `truePeakDb` and centroid also cannot see it. The limits are tripwires fit to these 13 sources, not taste. + +## What changes in aqua-feel's conclusions + +- Nothing in the gate changes: no flag differs on any tested source, and every metric delta is far below any threshold in `thresholds.json` that I looked at except the rpm600 thruster hiss cap noted above (1.0 dB, still under the cap). +- aqua-feel's WAVs are a fair rendering of what a host with the old `si.smooth` produces (the only Windows install found). They are **not** sample-identical to this sandbox's native render, and no sample-level claim about the thruster, the syrinx patches or the Ding instruments should be carried across them. +- The listening trial heard wasm renders; for a Windows daemon that is the closer path. For a daemon built on the sandbox's library, the same sources have the same level and spectrum and a different phase trajectory. +- Nothing was heard. + +## Proposed faustlibraries pin (not made) + +The cause is that `si.smooth` is whatever the host's `share/faust` says. Options, in order of my preference (confidence moderate; none of this is Soul-checked): +1. Vendor a pinned faustlibraries tree under the daemon's `Tools/Faust/share/faust` at build, record its commit in the compile manifest next to `faustLibrary`, and have `AquaSynthNativeOptions` prefer it over the system install. This makes the wasm bundle, Starfire and the sandbox agree only if aqua-feel's wasm path pins the same text too (faustwasm takes a library via its virtual FS), so pin both. +2. Decide the smoother once, in AquaSynth's emitted source: lowering emits a local smoother definition instead of calling `si.smooth`, so no host's stdlib decides it. Smaller, but changes every lowered patch and does not cover library functions that smooth internally. +3. Leave unpinned and record the host library identity in each compile manifest, accepting skew. + +Which smoother is the right one is a sound decision, not a measurement: imp(3) cannot stall (the library's own comment), the old form lands 0.07 % short of an rpm target at 4800. That is the owner's call. diff --git a/docs/renders/aqua-feel-native-diff-smoother-imp3-2026-11-10.json b/docs/renders/aqua-feel-native-diff-smoother-imp3-2026-11-10.json new file mode 100644 index 0000000..70ade89 --- /dev/null +++ b/docs/renders/aqua-feel-native-diff-smoother-imp3-2026-11-10.json @@ -0,0 +1,480 @@ +{ + "libfaustWasm": "2.90.19", + "sampleRate": 48000, + "items": "smoother", + "smoother": "imp3", + "rows": [ + { + "id": "thruster@rpm1200", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000007145106792449951, + "maxErrAt": 129748, + "rmsErr": 8.55413991926508e-7, + "relRmsErrDb": -99.87174472945775, + "wasm": { + "samplePeak": 0.18935100734233856, + "truePeakDb": -14.4241663695795, + "loudnessLufs": -26.05070420011194, + "centroidMedianHz": 2115.6325442720204, + "overSamples": 0, + "rmsDb": -21.48445687766135, + "crestDb": 7.029809275623743, + "noiseToToneDb": -4.965082233659885, + "noiseToToneADb": 12.71614612278843, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1893547624349594, + "truePeakDb": -14.423961460001248, + "loudnessLufs": -26.05070520432609, + "centroidMedianHz": 2115.6363534197994, + "overSamples": 0, + "rmsDb": -21.484457233344667, + "crestDb": 7.029981882815694, + "noiseToToneDb": -4.965083035181173, + "noiseToToneADb": 12.716143920958068, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-alien-multivalve-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 7.934868335723877e-7, + "maxErrAt": 35537, + "rmsErr": 8.335841454269617e-8, + "relRmsErrDb": -97.93819913427402, + "wasm": { + "samplePeak": 0.03596395254135132, + "truePeakDb": -28.873901668042834, + "loudnessLufs": -44.01583944248863, + "centroidMedianHz": 1719.746341068706, + "overSamples": 0, + "rmsDb": -38.86915824557575, + "crestDb": 9.986506563399741, + "noiseToToneDb": 2.2949371593837427, + "noiseToToneADb": -35.26674665881937, + "lowMotion": false + }, + "native": { + "samplePeak": 0.03596379607915878, + "truePeakDb": -28.87393371231402, + "loudnessLufs": -44.01584006251751, + "centroidMedianHz": 1719.7470242831325, + "overSamples": 0, + "rmsDb": -38.86915865101764, + "crestDb": 9.986469180550948, + "noiseToToneDb": 2.2949373787323424, + "noiseToToneADb": -35.266660047022036, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0000031944364309310913, + "maxErrAt": 45510, + "rmsErr": 3.8508989002632593e-7, + "relRmsErrDb": -88.25157230135844, + "wasm": { + "samplePeak": 0.07248446345329285, + "truePeakDb": -22.789810284125757, + "loudnessLufs": -39.38587031070514, + "centroidMedianHz": 3246.9416863147353, + "overSamples": 0, + "rmsDb": -35.86910042371045, + "crestDb": 13.073998993865658, + "noiseToToneDb": 3.398154713653433, + "noiseToToneADb": -0.2652457381911617, + "lowMotion": false + }, + "native": { + "samplePeak": 0.07248446345329285, + "truePeakDb": -22.789811642249525, + "loudnessLufs": -39.38587068917686, + "centroidMedianHz": 3246.965668802187, + "overSamples": 0, + "rmsDb": -35.86909904000429, + "crestDb": 13.0739976101595, + "noiseToToneDb": 3.3981546091622192, + "noiseToToneADb": -0.2652490593489034, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000015079975128173828, + "maxErrAt": 32899, + "rmsErr": 0.000001467630377556357, + "relRmsErrDb": -75.44121356490483, + "wasm": { + "samplePeak": 0.06643311679363251, + "truePeakDb": -23.549215787508704, + "loudnessLufs": -41.27251453792896, + "centroidMedianHz": 3608.1313492575864, + "overSamples": 0, + "rmsDb": -35.83554258887882, + "crestDb": 12.283235156759115, + "noiseToToneDb": 3.2057938097979033, + "noiseToToneADb": -14.047787523198789, + "lowMotion": false + }, + "native": { + "samplePeak": 0.06643310934305191, + "truePeakDb": -23.549216695315987, + "loudnessLufs": -41.27251147778152, + "centroidMedianHz": 3608.0824292245743, + "overSamples": 0, + "rmsDb": -35.83554221039036, + "crestDb": 12.28323380413414, + "noiseToToneDb": 3.205791878004028, + "noiseToToneADb": -14.047777587591895, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-syrinx-voice", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000002266373485326767, + "maxErrAt": 34649, + "rmsErr": 1.2956788367741612e-7, + "relRmsErrDb": -86.30175634080427, + "wasm": { + "samplePeak": 0.01358692068606615, + "truePeakDb": -37.32686366831106, + "loudnessLufs": -43.745499382417364, + "centroidMedianHz": 3723.182853016622, + "overSamples": 0, + "rmsDb": -46.7956174011546, + "crestDb": 9.458038205292446, + "noiseToToneDb": 1.791072654520292, + "noiseToToneADb": 1.7998750278369968, + "lowMotion": false + }, + "native": { + "samplePeak": 0.013587156310677528, + "truePeakDb": -37.32703848354456, + "loudnessLufs": -43.74549926644062, + "centroidMedianHz": 3723.2127010397694, + "overSamples": 0, + "rmsDb": -46.7956172502661, + "crestDb": 9.45818868394479, + "noiseToToneDb": 1.7910715795642531, + "noiseToToneADb": 1.7998739270327846, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-human-larynx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 7.587950676679611e-7, + "maxErrAt": 23972, + "rmsErr": 3.7846162388541006e-8, + "relRmsErrDb": -94.24621859478574, + "wasm": { + "samplePeak": 0.007788178510963917, + "truePeakDb": -42.17101862717542, + "loudnessLufs": -50.40721974974582, + "centroidMedianHz": 310.7891589769418, + "overSamples": 0, + "rmsDb": -50.08572494872536, + "crestDb": 7.914442895151346, + "noiseToToneDb": -30.816131815537496, + "noiseToToneADb": -27.766650651768487, + "lowMotion": false + }, + "native": { + "samplePeak": 0.0077881766483187675, + "truePeakDb": -42.17102078454992, + "loudnessLufs": -50.40722107125285, + "centroidMedianHz": 310.8999754545593, + "overSamples": 0, + "rmsDb": -50.08572618353941, + "crestDb": 7.914442052620592, + "noiseToToneDb": -30.816127938801678, + "noiseToToneADb": -27.766649805181505, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-32-additive-organ", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000164765864610672, + "maxErrAt": 23021, + "rmsErr": 0.000020540035138682098, + "relRmsErrDb": -79.45828076486667, + "wasm": { + "samplePeak": 0.6862082481384277, + "truePeakDb": -3.2699164206425015, + "loudnessLufs": -9.759124233116152, + "centroidMedianHz": 656.4226191119797, + "overSamples": 0, + "rmsDb": -8.539759068566523, + "crestDb": 5.268877746918222, + "noiseToToneDb": -37.01983113652173, + "noiseToToneADb": -37.788337502316935, + "lowMotion": false + }, + "native": { + "samplePeak": 0.6861962676048279, + "truePeakDb": -3.2700776073676936, + "loudnessLufs": -9.75912403739766, + "centroidMedianHz": 656.4212037746422, + "overSamples": 0, + "rmsDb": -8.53975888452333, + "crestDb": 5.268725914302816, + "noiseToToneDb": -37.0197944928564, + "noiseToToneADb": -37.78830410408929, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-8-bright-pair", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000003874767571687698, + "maxErrAt": 4727, + "rmsErr": 3.855039254064681e-7, + "relRmsErrDb": -94.6889441823849, + "wasm": { + "samplePeak": 0.150354266166687, + "truePeakDb": -16.445140264060527, + "loudnessLufs": -27.707281021900723, + "centroidMedianHz": 570.7301006928219, + "overSamples": 0, + "rmsDb": -25.228220791943087, + "crestDb": 8.770535898454384, + "noiseToToneDb": -33.00376708572004, + "noiseToToneADb": -31.168271339188635, + "lowMotion": false + }, + "native": { + "samplePeak": 0.15035313367843628, + "truePeakDb": -16.44521182640461, + "loudnessLufs": -27.707279746651498, + "centroidMedianHz": 570.7300173443439, + "overSamples": 0, + "rmsDb": -25.228219801277547, + "crestDb": 8.770469484271047, + "noiseToToneDb": -33.00374306131664, + "noiseToToneADb": -31.168260425434468, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/glass-chime", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 3.3155083656311035e-7, + "maxErrAt": 1305, + "rmsErr": 1.7352308119215504e-8, + "relRmsErrDb": -130.0126824087709, + "wasm": { + "samplePeak": 0.17621399462223053, + "truePeakDb": -15.062043767848326, + "loudnessLufs": -21.567272532108692, + "centroidMedianHz": 1602.876747515682, + "overSamples": 0, + "rmsDb": -22.84411377344017, + "crestDb": 7.764921701255961, + "noiseToToneDb": -3.1568108379227766, + "noiseToToneADb": -2.864104015545095, + "lowMotion": false + }, + "native": { + "samplePeak": 0.17621399462223053, + "truePeakDb": -15.062043917300066, + "loudnessLufs": -21.567272049422396, + "centroidMedianHz": 1602.87659074774, + "overSamples": 0, + "rmsDb": -22.844113441684826, + "crestDb": 7.764921369500614, + "noiseToToneDb": -3.156811070401325, + "noiseToToneADb": -2.8641043762574725, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/muted-pluck", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 2.9802322387695312e-8, + "maxErrAt": 39, + "rmsErr": 2.9894375811414372e-9, + "relRmsErrDb": -141.73373986178612, + "wasm": { + "samplePeak": 0.184849813580513, + "truePeakDb": -14.6610699229291, + "loudnessLufs": -27.093755336399102, + "centroidMedianHz": 337.57025931776576, + "overSamples": 0, + "rmsDb": -22.505770402082735, + "crestDb": 7.842150740622795, + "noiseToToneDb": -1.8131372817002074, + "noiseToToneADb": -3.773645767164254, + "lowMotion": false + }, + "native": { + "samplePeak": 0.184849813580513, + "truePeakDb": -14.66107041311351, + "loudnessLufs": -27.093755376725216, + "centroidMedianHz": 337.5700092248225, + "overSamples": 0, + "rmsDb": -22.505770501962672, + "crestDb": 7.842150840502738, + "noiseToToneDb": -1.813137412998607, + "noiseToToneADb": -3.773645881399787, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/soft-triangle", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 4.470348358154297e-8, + "maxErrAt": 8043, + "rmsErr": 4.533743604935639e-9, + "relRmsErrDb": -141.9875633660136, + "wasm": { + "samplePeak": 0.19771063327789307, + "truePeakDb": -14.073779284051348, + "loudnessLufs": -24.40759733605614, + "centroidMedianHz": 432.727373830872, + "overSamples": 0, + "rmsDb": -22.83707655432693, + "crestDb": 8.757677097882045, + "noiseToToneDb": -7.168489439744874, + "noiseToToneADb": -9.027978911866263, + "lowMotion": false + }, + "native": { + "samplePeak": 0.19771063327789307, + "truePeakDb": -14.073779075736933, + "loudnessLufs": -24.407597412236093, + "centroidMedianHz": 432.72721346965216, + "overSamples": 0, + "rmsDb": -22.83707661841455, + "crestDb": 8.757677161969662, + "noiseToToneDb": -7.168489371555516, + "noiseToToneADb": -9.027978838572636, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/warm-bell", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 2.3096799850463867e-7, + "maxErrAt": 4434, + "rmsErr": 1.76394996238211e-8, + "relRmsErrDb": -134.18055622815194, + "wasm": { + "samplePeak": 0.2345581352710724, + "truePeakDb": -12.586384128665326, + "loudnessLufs": -19.507703963974553, + "centroidMedianHz": 930.5955363634018, + "overSamples": 0, + "rmsDb": -19.84892961990138, + "crestDb": 7.25393962687934, + "noiseToToneDb": -4.493021207525722, + "noiseToToneADb": -3.568407049551638, + "lowMotion": false + }, + "native": { + "samplePeak": 0.2345581352710724, + "truePeakDb": -12.586384726471685, + "loudnessLufs": -19.50770471111663, + "centroidMedianHz": 930.5954188145085, + "overSamples": 0, + "rmsDb": -19.84893033283087, + "crestDb": 7.253940339808832, + "noiseToToneDb": -4.49302081177872, + "noiseToToneADb": -3.568406831675894, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "tract/vowel-a", + "lenWasm": 34560, + "lenNative": 34560, + "maxErr": 3.129243850708008e-7, + "maxErrAt": 32270, + "rmsErr": 6.777997120190261e-8, + "relRmsErrDb": -109.27441638992673, + "wasm": { + "samplePeak": 0.08390945941209793, + "truePeakDb": -21.50535980428806, + "loudnessLufs": -34.23468728787301, + "centroidMedianHz": 1937.2312975664222, + "overSamples": 0, + "rmsDb": -33.786820379265095, + "crestDb": 12.26303884229992, + "noiseToToneDb": -10.447396268131833, + "noiseToToneADb": -12.898741047906523, + "lowMotion": false + }, + "native": { + "samplePeak": 0.08390921354293823, + "truePeakDb": -21.50539262673788, + "loudnessLufs": -34.23471535099468, + "centroidMedianHz": 1937.2296872141594, + "overSamples": 0, + "rmsDb": -33.78684837329708, + "crestDb": 12.263041385142849, + "noiseToToneDb": -10.447393994101596, + "noiseToToneADb": -12.89873810612136, + "lowMotion": false + }, + "flagsWasm": [ + "FAIL onsetMs" + ], + "flagsNative": [ + "FAIL onsetMs" + ], + "violations": [] + } + ] +} \ No newline at end of file diff --git a/docs/renders/aqua-feel-native-diff-smoother-library-2026-11-10.json b/docs/renders/aqua-feel-native-diff-smoother-library-2026-11-10.json new file mode 100644 index 0000000..4ec5042 --- /dev/null +++ b/docs/renders/aqua-feel-native-diff-smoother-library-2026-11-10.json @@ -0,0 +1,480 @@ +{ + "libfaustWasm": "2.90.19", + "sampleRate": 48000, + "items": "smoother", + "smoother": "library", + "rows": [ + { + "id": "thruster@rpm1200", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.08972565084695816, + "maxErrAt": 143228, + "rmsErr": 0.012448641233006897, + "relRmsErrDb": -16.610480431926955, + "wasm": { + "samplePeak": 0.19161102175712585, + "truePeakDb": -14.343339234769212, + "loudnessLufs": -26.051033400616078, + "centroidMedianHz": 2114.222071076734, + "overSamples": 0, + "rmsDb": -21.48680915202533, + "crestDb": 7.1352188868162605, + "noiseToToneDb": -4.949059402813134, + "noiseToToneADb": 12.652391835948997, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1893547624349594, + "truePeakDb": -14.423961460001248, + "loudnessLufs": -26.05070520432609, + "centroidMedianHz": 2115.6363534197994, + "overSamples": 0, + "rmsDb": -21.484457233344667, + "crestDb": 7.029981882815694, + "noiseToToneDb": -4.965083035181173, + "noiseToToneADb": 12.716143920958068, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-alien-multivalve-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000028988346457481384, + "maxErrAt": 35885, + "rmsErr": 0.0000024852740234353792, + "relRmsErrDb": -68.44968710695318, + "wasm": { + "samplePeak": 0.03596847131848335, + "truePeakDb": -28.872530673301476, + "loudnessLufs": -44.01558191383624, + "centroidMedianHz": 1719.821403397199, + "overSamples": 0, + "rmsDb": -38.86917357972277, + "crestDb": 9.98761318843934, + "noiseToToneDb": 2.2946722668875523, + "noiseToToneADb": -35.26574829949449, + "lowMotion": false + }, + "native": { + "samplePeak": 0.03596379607915878, + "truePeakDb": -28.87393371231402, + "loudnessLufs": -44.01584006251751, + "centroidMedianHz": 1719.7470242831325, + "overSamples": 0, + "rmsDb": -38.86915865101764, + "crestDb": 9.986469180550948, + "noiseToToneDb": 2.2949373787323424, + "noiseToToneADb": -35.266660047022036, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0027769599109888077, + "maxErrAt": 45282, + "rmsErr": 0.0004283705044505341, + "relRmsErrDb": -27.32626534167103, + "wasm": { + "samplePeak": 0.0724848210811615, + "truePeakDb": -22.789532845508607, + "loudnessLufs": -39.384826220237244, + "centroidMedianHz": 3246.9736644772215, + "overSamples": 0, + "rmsDb": -35.86925853361916, + "crestDb": 13.074199958593006, + "noiseToToneDb": 3.395163753535492, + "noiseToToneADb": -0.26769809662280863, + "lowMotion": false + }, + "native": { + "samplePeak": 0.07248446345329285, + "truePeakDb": -22.789811642249525, + "loudnessLufs": -39.38587068917686, + "centroidMedianHz": 3246.965668802187, + "overSamples": 0, + "rmsDb": -35.86909904000429, + "crestDb": 13.0739976101595, + "noiseToToneDb": 3.3981546091622192, + "noiseToToneADb": -0.2652490593489034, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0009388141334056854, + "maxErrAt": 33098, + "rmsErr": 0.00010481991412365385, + "relRmsErrDb": -38.36457659477791, + "wasm": { + "samplePeak": 0.06643299758434296, + "truePeakDb": -23.549220126103343, + "loudnessLufs": -41.272964930830874, + "centroidMedianHz": 3608.3773722521782, + "overSamples": 0, + "rmsDb": -35.835637421519465, + "crestDb": 12.28331440320251, + "noiseToToneDb": 3.205981107524842, + "noiseToToneADb": -14.050756471755903, + "lowMotion": false + }, + "native": { + "samplePeak": 0.06643310934305191, + "truePeakDb": -23.549216695315987, + "loudnessLufs": -41.27251147778152, + "centroidMedianHz": 3608.0824292245743, + "overSamples": 0, + "rmsDb": -35.83554221039036, + "crestDb": 12.28323380413414, + "noiseToToneDb": 3.205791878004028, + "noiseToToneADb": -14.047777587591895, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-syrinx-voice", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0012954180128872395, + "maxErrAt": 33655, + "rmsErr": 0.00017071330356165833, + "relRmsErrDb": -23.90529822473789, + "wasm": { + "samplePeak": 0.013509727083146572, + "truePeakDb": -37.32985445982076, + "loudnessLufs": -43.74666608622773, + "centroidMedianHz": 3723.272760511277, + "overSamples": 0, + "rmsDb": -46.796675488586175, + "crestDb": 9.409607002734177, + "noiseToToneDb": 1.790967089244596, + "noiseToToneADb": 1.7997448212983471, + "lowMotion": false + }, + "native": { + "samplePeak": 0.013587156310677528, + "truePeakDb": -37.32703848354456, + "loudnessLufs": -43.74549926644062, + "centroidMedianHz": 3723.2127010397694, + "overSamples": 0, + "rmsDb": -46.7956172502661, + "crestDb": 9.45818868394479, + "noiseToToneDb": 1.7910715795642531, + "noiseToToneADb": 1.7998739270327846, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-human-larynx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.00009577462333254516, + "maxErrAt": 34584, + "rmsErr": 0.00002426493085728514, + "relRmsErrDb": -38.10546679970197, + "wasm": { + "samplePeak": 0.007785667199641466, + "truePeakDb": -42.173192592326515, + "loudnessLufs": -50.40895750738575, + "centroidMedianHz": 310.7359227777714, + "overSamples": 0, + "rmsDb": -50.08733256154268, + "crestDb": 7.913249276521016, + "noiseToToneDb": -30.80971405508631, + "noiseToToneADb": -27.762876726971946, + "lowMotion": false + }, + "native": { + "samplePeak": 0.0077881766483187675, + "truePeakDb": -42.17102078454992, + "loudnessLufs": -50.40722107125285, + "centroidMedianHz": 310.8999754545593, + "overSamples": 0, + "rmsDb": -50.08572618353941, + "crestDb": 7.914442052620592, + "noiseToToneDb": -30.816127938801678, + "noiseToToneADb": -27.766649805181505, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-32-additive-organ", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.00016526132822036743, + "maxErrAt": 23020, + "rmsErr": 0.000020994103574012447, + "relRmsErrDb": -79.26822857998425, + "wasm": { + "samplePeak": 0.6861975789070129, + "truePeakDb": -3.270050577733717, + "loudnessLufs": -9.759294906714691, + "centroidMedianHz": 656.4219631461098, + "overSamples": 0, + "rmsDb": -8.539888188883904, + "crestDb": 5.268871817143614, + "noiseToToneDb": -37.019826930432856, + "noiseToToneADb": -37.7883341551492, + "lowMotion": false + }, + "native": { + "samplePeak": 0.6861962676048279, + "truePeakDb": -3.2700776073676936, + "loudnessLufs": -9.75912403739766, + "centroidMedianHz": 656.4212037746422, + "overSamples": 0, + "rmsDb": -8.53975888452333, + "crestDb": 5.268725914302816, + "noiseToToneDb": -37.0197944928564, + "noiseToToneADb": -37.78830410408929, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-8-bright-pair", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000004090368747711182, + "maxErrAt": 4395, + "rmsErr": 3.9566542791342453e-7, + "relRmsErrDb": -94.46295503093202, + "wasm": { + "samplePeak": 0.1503547728061676, + "truePeakDb": -16.445110330444138, + "loudnessLufs": -27.707288476356375, + "centroidMedianHz": 570.7272310041899, + "overSamples": 0, + "rmsDb": -25.22822394507269, + "crestDb": 8.7705683198403, + "noiseToToneDb": -33.00382123099267, + "noiseToToneADb": -31.168321209089953, + "lowMotion": false + }, + "native": { + "samplePeak": 0.15035313367843628, + "truePeakDb": -16.44521182640461, + "loudnessLufs": -27.707279746651498, + "centroidMedianHz": 570.7300173443439, + "overSamples": 0, + "rmsDb": -25.228219801277547, + "crestDb": 8.770469484271047, + "noiseToToneDb": -33.00374306131664, + "noiseToToneADb": -31.168260425434468, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/glass-chime", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.03821572195738554, + "maxErrAt": 19431, + "rmsErr": 0.006593494603898945, + "relRmsErrDb": -18.417512948342896, + "wasm": { + "samplePeak": 0.17621681094169617, + "truePeakDb": -15.062032445423984, + "loudnessLufs": -21.56737037885148, + "centroidMedianHz": 1602.6138671100102, + "overSamples": 0, + "rmsDb": -22.844945161193554, + "crestDb": 7.765891909110638, + "noiseToToneDb": -3.1846833757850774, + "noiseToToneADb": -2.8894771746074213, + "lowMotion": false + }, + "native": { + "samplePeak": 0.17621399462223053, + "truePeakDb": -15.062043917300066, + "loudnessLufs": -21.567272049422396, + "centroidMedianHz": 1602.87659074774, + "overSamples": 0, + "rmsDb": -22.844113441684826, + "crestDb": 7.764921369500614, + "noiseToToneDb": -3.156811070401325, + "noiseToToneADb": -2.8641043762574725, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/muted-pluck", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.000662742939312011, + "maxErrAt": 13239, + "rmsErr": 0.00011858435565109058, + "relRmsErrDb": -49.764983408100534, + "wasm": { + "samplePeak": 0.18485014140605927, + "truePeakDb": -14.661061484678669, + "loudnessLufs": -27.09375077529527, + "centroidMedianHz": 337.55371147245654, + "overSamples": 0, + "rmsDb": -22.505768680170274, + "crestDb": 7.8421644228588985, + "noiseToToneDb": -1.8131427242661857, + "noiseToToneADb": -3.7732237451762884, + "lowMotion": false + }, + "native": { + "samplePeak": 0.184849813580513, + "truePeakDb": -14.66107041311351, + "loudnessLufs": -27.093755376725216, + "centroidMedianHz": 337.5700092248225, + "overSamples": 0, + "rmsDb": -22.505770501962672, + "crestDb": 7.842150840502738, + "noiseToToneDb": -1.813137412998607, + "noiseToToneADb": -3.773645881399787, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/soft-triangle", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.004339124541729689, + "maxErrAt": 27366, + "rmsErr": 0.0017425528838580662, + "relRmsErrDb": -30.292986249468473, + "wasm": { + "samplePeak": 0.19771148264408112, + "truePeakDb": -14.073758822230804, + "loudnessLufs": -24.407607566689737, + "centroidMedianHz": 432.02737524513924, + "overSamples": 0, + "rmsDb": -22.837073455193796, + "crestDb": 8.757711313308086, + "noiseToToneDb": -7.16850817229934, + "noiseToToneADb": -9.027202849078392, + "lowMotion": false + }, + "native": { + "samplePeak": 0.19771063327789307, + "truePeakDb": -14.073779075736933, + "loudnessLufs": -24.407597412236093, + "centroidMedianHz": 432.72721346965216, + "overSamples": 0, + "rmsDb": -22.83707661841455, + "crestDb": 8.757677161969662, + "noiseToToneDb": -7.168489371555516, + "noiseToToneADb": -9.027978838572636, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/warm-bell", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.05384007841348648, + "maxErrAt": 22907, + "rmsErr": 0.010932589918993823, + "relRmsErrDb": -18.335820982841014, + "wasm": { + "samplePeak": 0.23455719649791718, + "truePeakDb": -12.586378660039248, + "loudnessLufs": -19.50785299525781, + "centroidMedianHz": 930.5251827853554, + "overSamples": 0, + "rmsDb": -19.848928933876216, + "crestDb": 7.2539041772066515, + "noiseToToneDb": -4.487748875412059, + "noiseToToneADb": -3.561906168663185, + "lowMotion": false + }, + "native": { + "samplePeak": 0.2345581352710724, + "truePeakDb": -12.586384726471685, + "loudnessLufs": -19.50770471111663, + "centroidMedianHz": 930.5954188145085, + "overSamples": 0, + "rmsDb": -19.84893033283087, + "crestDb": 7.253940339808832, + "noiseToToneDb": -4.49302081177872, + "noiseToToneADb": -3.568406831675894, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "tract/vowel-a", + "lenWasm": 34560, + "lenNative": 34560, + "maxErr": 0.0001921914517879486, + "maxErrAt": 28187, + "rmsErr": 0.000046111049670587934, + "relRmsErrDb": -52.60441410619507, + "wasm": { + "samplePeak": 0.08378415554761887, + "truePeakDb": -21.518327105526673, + "loudnessLufs": -34.251568232392565, + "centroidMedianHz": 1937.1220888731689, + "overSamples": 0, + "rmsDb": -33.80275018649363, + "crestDb": 12.265988122620389, + "noiseToToneDb": -10.436050344670264, + "noiseToToneADb": -12.885220061403881, + "lowMotion": false + }, + "native": { + "samplePeak": 0.08390921354293823, + "truePeakDb": -21.50539262673788, + "loudnessLufs": -34.23471535099468, + "centroidMedianHz": 1937.2296872141594, + "overSamples": 0, + "rmsDb": -33.78684837329708, + "crestDb": 12.263041385142849, + "noiseToToneDb": -10.447393994101596, + "noiseToToneADb": -12.89873810612136, + "lowMotion": false + }, + "flagsWasm": [ + "FAIL onsetMs" + ], + "flagsNative": [ + "FAIL onsetMs" + ], + "violations": [] + } + ] +} \ No newline at end of file diff --git a/docs/renders/aqua-feel-native-diff-smoother-old-2026-11-10.json b/docs/renders/aqua-feel-native-diff-smoother-old-2026-11-10.json new file mode 100644 index 0000000..486b785 --- /dev/null +++ b/docs/renders/aqua-feel-native-diff-smoother-old-2026-11-10.json @@ -0,0 +1,480 @@ +{ + "libfaustWasm": "2.90.19", + "sampleRate": 48000, + "items": "smoother", + "smoother": "old", + "rows": [ + { + "id": "thruster@rpm1200", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.04497168958187103, + "maxErrAt": 141577, + "rmsErr": 0.007318071121139892, + "relRmsErrDb": -21.224986931184873, + "wasm": { + "samplePeak": 0.19161102175712585, + "truePeakDb": -14.343339234769212, + "loudnessLufs": -26.051033400616078, + "centroidMedianHz": 2114.222071076734, + "overSamples": 0, + "rmsDb": -21.48680915202533, + "crestDb": 7.1352188868162605, + "noiseToToneDb": -4.949059402813134, + "noiseToToneADb": 12.652391835948997, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1881352812051773, + "truePeakDb": -14.4953016770333, + "loudnessLufs": -26.05000842555788, + "centroidMedianHz": 2112.509030190081, + "overSamples": 0, + "rmsDb": -21.48554731845163, + "crestDb": 6.974952256138389, + "noiseToToneDb": -4.986880144493831, + "noiseToToneADb": 12.399428225827492, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-alien-multivalve-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000010244548320770264, + "maxErrAt": 35688, + "rmsErr": 0.0000015676294788398326, + "relRmsErrDb": -72.45230428385759, + "wasm": { + "samplePeak": 0.03596847131848335, + "truePeakDb": -28.872530673301476, + "loudnessLufs": -44.01558191383624, + "centroidMedianHz": 1719.821403397199, + "overSamples": 0, + "rmsDb": -38.86917357972277, + "crestDb": 9.98761318843934, + "noiseToToneDb": 2.2946722668875523, + "noiseToToneADb": -35.26574829949449, + "lowMotion": false + }, + "native": { + "samplePeak": 0.03596773371100426, + "truePeakDb": -28.872900426797354, + "loudnessLufs": -44.015640274857304, + "centroidMedianHz": 1719.8495576360149, + "overSamples": 0, + "rmsDb": -38.86920427795782, + "crestDb": 9.987465762817079, + "noiseToToneDb": 2.294718621072647, + "noiseToToneADb": -35.265694920035834, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0016491450369358063, + "maxErrAt": 45282, + "rmsErr": 0.00025934850824015885, + "relRmsErrDb": -31.68498145060413, + "wasm": { + "samplePeak": 0.0724848210811615, + "truePeakDb": -22.789532845508607, + "loudnessLufs": -39.384826220237244, + "centroidMedianHz": 3246.9736644772215, + "overSamples": 0, + "rmsDb": -35.86925853361916, + "crestDb": 13.074199958593006, + "noiseToToneDb": 3.395163753535492, + "noiseToToneADb": -0.26769809662280863, + "lowMotion": false + }, + "native": { + "samplePeak": 0.07248431444168091, + "truePeakDb": -22.78984322120366, + "loudnessLufs": -39.38565490955099, + "centroidMedianHz": 3246.899582775747, + "overSamples": 0, + "rmsDb": -35.86920348626081, + "crestDb": 13.074084200179179, + "noiseToToneDb": 3.396666156772234, + "noiseToToneADb": -0.2667876831196381, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-bird-syrinx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.0002693869173526764, + "maxErrAt": 32700, + "rmsErr": 0.00003826655739568763, + "relRmsErrDb": -47.117064721842894, + "wasm": { + "samplePeak": 0.06643299758434296, + "truePeakDb": -23.549220126103343, + "loudnessLufs": -41.272964930830874, + "centroidMedianHz": 3608.3773722521782, + "overSamples": 0, + "rmsDb": -35.835637421519465, + "crestDb": 12.28331440320251, + "noiseToToneDb": 3.205981107524842, + "noiseToToneADb": -14.050756471755903, + "lowMotion": false + }, + "native": { + "samplePeak": 0.06643303483724594, + "truePeakDb": -23.549216558140902, + "loudnessLufs": -41.27307677467835, + "centroidMedianHz": 3608.449964447863, + "overSamples": 0, + "rmsDb": -35.835623258716865, + "crestDb": 12.283305111089557, + "noiseToToneDb": 3.20619543415809, + "noiseToToneADb": -14.048989011382716, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-syrinx-voice", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.00035776360891759396, + "maxErrAt": 33071, + "rmsErr": 0.00004987960856320729, + "relRmsErrDb": -34.59218482563713, + "wasm": { + "samplePeak": 0.013509727083146572, + "truePeakDb": -37.32985445982076, + "loudnessLufs": -43.74666608622773, + "centroidMedianHz": 3723.272760511277, + "overSamples": 0, + "rmsDb": -46.796675488586175, + "crestDb": 9.409607002734177, + "noiseToToneDb": 1.790967089244596, + "noiseToToneADb": 1.7997448212983471, + "lowMotion": false + }, + "native": { + "samplePeak": 0.013522684574127197, + "truePeakDb": -37.32721733719029, + "loudnessLufs": -43.74636063400179, + "centroidMedianHz": 3723.1202654076387, + "overSamples": 0, + "rmsDb": -46.79638101226304, + "crestDb": 9.41763937099232, + "noiseToToneDb": 1.7908757840446228, + "noiseToToneADb": 1.7996603730072778, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "advanced-human-larynx-graph", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.00003339786780998111, + "maxErrAt": 29445, + "rmsErr": 0.0000091717665877173, + "relRmsErrDb": -46.55598808562419, + "wasm": { + "samplePeak": 0.007785667199641466, + "truePeakDb": -42.173192592326515, + "loudnessLufs": -50.40895750738575, + "centroidMedianHz": 310.7359227777714, + "overSamples": 0, + "rmsDb": -50.08733256154268, + "crestDb": 7.913249276521016, + "noiseToToneDb": -30.80971405508631, + "noiseToToneADb": -27.762876726971946, + "lowMotion": false + }, + "native": { + "samplePeak": 0.00778665067628026, + "truePeakDb": -42.172393196766, + "loudnessLufs": -50.40839338870849, + "centroidMedianHz": 310.88482517283643, + "overSamples": 0, + "rmsDb": -50.086764610534054, + "crestDb": 7.913778447935089, + "noiseToToneDb": -30.8115791514923, + "noiseToToneADb": -27.76354669965494, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-32-additive-organ", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.00016482919454574585, + "maxErrAt": 23021, + "rmsErr": 0.000020542966407864508, + "relRmsErrDb": -79.45691216935256, + "wasm": { + "samplePeak": 0.6861975789070129, + "truePeakDb": -3.270050577733717, + "loudnessLufs": -9.759294906714691, + "centroidMedianHz": 656.4219631461098, + "overSamples": 0, + "rmsDb": -8.539888188883904, + "crestDb": 5.268871817143614, + "noiseToToneDb": -37.019826930432856, + "noiseToToneADb": -37.7883341551492, + "lowMotion": false + }, + "native": { + "samplePeak": 0.6861848831176758, + "truePeakDb": -3.2702216053436386, + "loudnessLufs": -9.759310761718336, + "centroidMedianHz": 656.4199149750565, + "overSamples": 0, + "rmsDb": -8.539903940430642, + "crestDb": 5.268726863889608, + "noiseToToneDb": -37.01979015752506, + "noiseToToneADb": -37.78830074856767, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "dx7-algorithm-8-bright-pair", + "lenWasm": 144000, + "lenNative": 144000, + "maxErr": 0.000004217028617858887, + "maxErrAt": 4395, + "rmsErr": 4.0587175382789543e-7, + "relRmsErrDb": -94.24174055880029, + "wasm": { + "samplePeak": 0.1503547728061676, + "truePeakDb": -16.445110330444138, + "loudnessLufs": -27.707288476356375, + "centroidMedianHz": 570.7272310041899, + "overSamples": 0, + "rmsDb": -25.22822394507269, + "crestDb": 8.7705683198403, + "noiseToToneDb": -33.00382123099267, + "noiseToToneADb": -31.168321209089953, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1503528207540512, + "truePeakDb": -16.44522744967477, + "loudnessLufs": -27.707277125976997, + "centroidMedianHz": 570.7333021952353, + "overSamples": 0, + "rmsDb": -25.228219761996577, + "crestDb": 8.770451367352216, + "noiseToToneDb": -33.00373339984028, + "noiseToToneADb": -31.168249293529612, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/glass-chime", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.0249517853371799, + "maxErrAt": 16135, + "rmsErr": 0.004421638829626474, + "relRmsErrDb": -21.888160741392436, + "wasm": { + "samplePeak": 0.17621681094169617, + "truePeakDb": -15.062032445423984, + "loudnessLufs": -21.56737037885148, + "centroidMedianHz": 1602.6138671100102, + "overSamples": 0, + "rmsDb": -22.844945161193554, + "crestDb": 7.765891909110638, + "noiseToToneDb": -3.1846833757850774, + "noiseToToneADb": -2.8894771746074213, + "lowMotion": false + }, + "native": { + "samplePeak": 0.1762169897556305, + "truePeakDb": -15.06203177829347, + "loudnessLufs": -21.567324293584342, + "centroidMedianHz": 1602.7309843808985, + "overSamples": 0, + "rmsDb": -22.8449443529706, + "crestDb": 7.765899914787472, + "noiseToToneDb": -3.15615732806026, + "noiseToToneADb": -2.8631443461744297, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/muted-pluck", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.0006083704647608101, + "maxErrAt": 11771, + "rmsErr": 0.00011333511339155152, + "relRmsErrDb": -50.15824170095642, + "wasm": { + "samplePeak": 0.18485014140605927, + "truePeakDb": -14.661061484678669, + "loudnessLufs": -27.09375077529527, + "centroidMedianHz": 337.55371147245654, + "overSamples": 0, + "rmsDb": -22.505768680170274, + "crestDb": 7.8421644228588985, + "noiseToToneDb": -1.8131427242661857, + "noiseToToneADb": -3.7732237451762884, + "lowMotion": false + }, + "native": { + "samplePeak": 0.18485012650489807, + "truePeakDb": -14.661062836676077, + "loudnessLufs": -27.093759010723893, + "centroidMedianHz": 337.5238499031714, + "overSamples": 0, + "rmsDb": -22.505770398210146, + "crestDb": 7.842165440710797, + "noiseToToneDb": -1.8131374325665277, + "noiseToToneADb": -3.773589944716136, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/soft-triangle", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.0023703736951574683, + "maxErrAt": 25715, + "rmsErr": 0.0009930534248776234, + "relRmsErrDb": -35.17725332142618, + "wasm": { + "samplePeak": 0.19771148264408112, + "truePeakDb": -14.073758822230804, + "loudnessLufs": -24.407607566689737, + "centroidMedianHz": 432.02737524513924, + "overSamples": 0, + "rmsDb": -22.837073455193796, + "crestDb": 8.757711313308086, + "noiseToToneDb": -7.16850817229934, + "noiseToToneADb": -9.027202849078392, + "lowMotion": false + }, + "native": { + "samplePeak": 0.19771143794059753, + "truePeakDb": -14.07376035946359, + "loudnessLufs": -24.407608271539363, + "centroidMedianHz": 432.56670373115156, + "overSamples": 0, + "rmsDb": -22.837076588859357, + "crestDb": 8.757712483053472, + "noiseToToneDb": -7.168496214436587, + "noiseToToneADb": -9.027680538222803, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "ding-instrument/warm-bell", + "lenWasm": 72000, + "lenNative": 72000, + "maxErr": 0.031899021938443184, + "maxErrAt": 20346, + "rmsErr": 0.0064883595529472505, + "relRmsErrDb": -22.867583977030858, + "wasm": { + "samplePeak": 0.23455719649791718, + "truePeakDb": -12.586378660039248, + "loudnessLufs": -19.50785299525781, + "centroidMedianHz": 930.5251827853554, + "overSamples": 0, + "rmsDb": -19.848928933876216, + "crestDb": 7.2539041772066515, + "noiseToToneDb": -4.487748875412059, + "noiseToToneADb": -3.561906168663185, + "lowMotion": false + }, + "native": { + "samplePeak": 0.23455692827701569, + "truePeakDb": -12.58637491873251, + "loudnessLufs": -19.50777054747485, + "centroidMedianHz": 930.5575374762606, + "overSamples": 0, + "rmsDb": -19.84893016359035, + "crestDb": 7.253895474424504, + "noiseToToneDb": -4.485889851528931, + "noiseToToneADb": -3.56069167084123, + "lowMotion": false + }, + "flagsWasm": [], + "flagsNative": [], + "violations": [] + }, + { + "id": "tract/vowel-a", + "lenWasm": 34560, + "lenNative": 34560, + "maxErr": 0.00006673485040664673, + "maxErrAt": 28187, + "rmsErr": 0.000017135153866313287, + "relRmsErrDb": -61.202754106950046, + "wasm": { + "samplePeak": 0.08378415554761887, + "truePeakDb": -21.518327105526673, + "loudnessLufs": -34.251568232392565, + "centroidMedianHz": 1937.1220888731689, + "overSamples": 0, + "rmsDb": -33.80275018649363, + "crestDb": 12.265988122620389, + "noiseToToneDb": -10.436050344670264, + "noiseToToneADb": -12.885220061403881, + "lowMotion": false + }, + "native": { + "samplePeak": 0.08382102102041245, + "truePeakDb": -21.514509846938733, + "loudnessLufs": -34.245380439304775, + "centroidMedianHz": 1937.234382427543, + "overSamples": 0, + "rmsDb": -33.796727413065646, + "crestDb": 12.263786346131285, + "noiseToToneDb": -10.440493522060173, + "noiseToToneADb": -12.890432956436477, + "lowMotion": false + }, + "flagsWasm": [ + "FAIL onsetMs" + ], + "flagsNative": [ + "FAIL onsetMs" + ], + "violations": [] + } + ] +} \ No newline at end of file diff --git a/tools/FaustNativeRender/FaustNativeRender.csproj b/tools/FaustNativeRender/FaustNativeRender.csproj new file mode 100644 index 0000000..9dd3508 --- /dev/null +++ b/tools/FaustNativeRender/FaustNativeRender.csproj @@ -0,0 +1,12 @@ + + + Exe + net10.0 + enable + enable + true + + + + + diff --git a/tools/FaustNativeRender/Program.cs b/tools/FaustNativeRender/Program.cs new file mode 100644 index 0000000..c533296 --- /dev/null +++ b/tools/FaustNativeRender/Program.cs @@ -0,0 +1,55 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using AquaSynth.Faust; + +// Offline render of one Faust source through the daemon's native libfaust path (AquaSynthPatchCompiler, -vec -lv 1) +// to a mono float32 WAV, for diffing against aqua-feel's faustwasm render. 48 kHz, 512-frame blocks, like render.js. +// usage: FaustNativeRender [control=value ...] +const int Rate = 48000, Frames = 512; +if (args.Length < 3) { Console.Error.WriteLine("usage: FaustNativeRender [control=value ...]"); return 2; } +var dspPath = Path.GetFullPath(args[0]); +var outPath = Path.GetFullPath(args[1]); +var total = (int)Math.Round(double.Parse(args[2]) * Rate); +var source = File.ReadAllText(dspPath); +Directory.CreateDirectory(Path.GetDirectoryName(outPath)!); + +using var compiler = new AquaSynthPatchCompiler(new AquaSynthNativeOptions(SampleRate: Rate)); +var name = Path.GetFileNameWithoutExtension(dspPath); +if (!compiler.TryCompileSource(new AquaSynthCompileIdentity(name, name, ""), source, (float)total / Rate, out var patch0, out var cerr)) +{ + Console.Error.WriteLine("COMPILE FAILED: " + cerr); + return 1; +} +using var patch = patch0!; +if (patch.Manifest.OutputCount != 1) { Console.Error.WriteLine($"expected 1 output, patch has {patch.Manifest.OutputCount}"); return 1; } +var ctl = new Dictionary(); +foreach (var spec in args.Skip(3)) +{ + var eq = spec.IndexOf('='); + var key = spec[..eq]; + var hits = patch.ControlPaths.Where(p => p.TrimStart('/') == key.TrimStart('/') || p.EndsWith("/" + key.TrimStart('/'))).ToList(); + if (hits.Count != 1) { Console.Error.WriteLine($"control \"{key}\" matches {hits.Count} of: {string.Join(", ", patch.ControlPaths)}"); return 1; } + var path = hits[0]; + ctl[path] = float.Parse(spec[(eq + 1)..], System.Globalization.CultureInfo.InvariantCulture); +} + +using var stream = patch.CreateStreamingPatch(); +var buf = GC.AllocateArray(Frames, pinned: true); +var ptrs = GC.AllocateArray(1, pinned: true); +unsafe { ptrs[0] = (IntPtr)Unsafe.AsPointer(ref buf[0]); } +var outP = Marshal.UnsafeAddrOfPinnedArrayElement(ptrs, 0); +var pcm = new float[total]; +for (var at = 0; at < total; at += Frames) +{ + stream.ProcessBlock(Frames, IntPtr.Zero, outP, ctl); + Array.Copy(buf, 0, pcm, at, Math.Min(Frames, total - at)); +} +using (var w = new BinaryWriter(File.Create(outPath))) +{ + var db = total * 4; + w.Write("RIFF"u8); w.Write(36 + db); w.Write("WAVEfmt "u8); w.Write(16); w.Write((short)3); w.Write((short)1); + w.Write(Rate); w.Write(Rate * 4); w.Write((short)4); w.Write((short)32); w.Write("data"u8); w.Write(db); + foreach (var s in pcm) w.Write(s); +} +Console.WriteLine($"{outPath} frames={total} controls={ctl.Count}"); +return 0; diff --git a/tools/aqua-feel/README.md b/tools/aqua-feel/README.md index 87aa094..dfe80db 100644 --- a/tools/aqua-feel/README.md +++ b/tools/aqua-feel/README.md @@ -33,8 +33,7 @@ non-zero on any unwaived failure or stale waiver. No CI runner exists in this re The command gain 0.6 is an assumption (`DingsPlaybackHost` takes it from the caller as 0..1), so the Ding loudness window depends on it. Render path: the same faustwasm offline processor the playground and the listening trial use (libfaust 2.90.x, `-ftz 2`), -mono channel 0. It is **not** the daemon's native libfaust path (`-vec`); the same Faust source should render alike, but -nobody has diffed the two. +mono channel 0. It is **not** the daemon's native libfaust path (`-vec`); on a thruster the two diverge in waveform because the wasm bundle's `si.smooth` and the sandbox's native stdlib are different library text (not the host, not `-vec`); level and spectrum metrics stay close: `docs/renders/aqua-feel-native-diff-2026-11-10.md`, `node native-diff.mjs`. ## What it measures (per item, `report.json` `items[].metrics`) diff --git a/tools/aqua-feel/native-diff.mjs b/tools/aqua-feel/native-diff.mjs new file mode 100644 index 0000000..3ae628a --- /dev/null +++ b/tools/aqua-feel/native-diff.mjs @@ -0,0 +1,81 @@ +// Diff aqua-feel's faustwasm render against the daemon's native libfaust render (tools/FaustNativeRender) of the same +// Faust source, at the same params, 48 kHz and length. Nothing here was heard. +// Both sides compile against their own stdlib (faustwasm bundles libfaust's; native reads AQUASYNTH_FAUST_HOME's share/faust), so a +// difference here can be library text, not the host: the report records the identities. The script exits 1 +// on a render error, a length mismatch, or a LIMITS violation. LIMITS sit between the largest deltas seen across 13 sources and +// three conditions (|LUFS| 0.017, |true peak| 0.152 dB, centroid 0.3 %) and a deliberate +1 dB gain (LUFS and true peak 1.0 dB); +// the sample-level bound applies only with --smoother imp3, where the largest error seen is -75.4 dB (dx7-32, unexplained, is -79.5) and a one-sample +// shift reads about -4 dB. With the library smoother the waveforms legitimately diverge (thruster -8 to -29 dB), so no sample bound. +// usage: node native-diff.mjs [--tract PATH.dsp] [--out DIR] [--items core|smoother] [--smoother library|old|imp3] +// --items smoother: the 12 catalog sources that call si.smooth/si.smoo (thruster at rpm 1200, 7 patches, 4 Ding instruments, one note at 261.6256 Hz for 1.5 s) +// --smoother old|imp3: rewrite si.smooth/si.smoo in the source text to a local definition (old = `*(1-s) : + ~ *(s)`, imp3 = the error-form +// recursion), the same text on both sides, so the standard library's own si.smooth no longer decides. Smoothers called inside other +// library functions are not rewritten. +import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import { join, dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { tmpdir } from "node:os"; +import { SR, measure } from "./metrics.js"; +import { gate } from "./gate.js"; +import { loadRuntime, compile, renderOnce, writeWav, readText, playground } from "./render.js"; + +const LIMITS = { lufsDb: 0.1, truePeakDb: 0.5, centroidPct: 1, relRmsErrDbImp3: -60 }; +const here = dirname(fileURLToPath(import.meta.url)), args = process.argv.slice(2); +const opt = (k) => { const i = args.indexOf(k); return i < 0 ? null : args[i + 1]; }; +const bin = resolve(args[0]), out = resolve(opt("--out") ?? join(tmpdir(), "aqua-feel-native-diff")); +const low = (n) => readText(join(playground, "lowered", n)); +const mode = opt("--smoother") ?? "library", set = opt("--items") ?? "core"; +const DEFS = { + old: "nd_smooth(s) = *(1.0 - s) : + ~ *(s);", + imp3: "nd_smooth(s) = \\(x).(x + (fb ~ _ with { fb(e) = s * (e + (x' - x : min(3.4e38))); }));", +}; +const pin = (src) => mode === "library" ? src : src.replace(/\bsi\.smoo\b/g, "nd_smoo").replace(/\bsi\.smooth\b/g, "nd_smooth").replace(/import\("stdfaust\.lib"\);/, (m) => `${m}\n${DEFS[mode]}\nnd_smoo = nd_smooth(1 - 44.1/ma.SR);`); +if (!["library", "old", "imp3"].includes(mode) || !["core", "smoother"].includes(set)) { console.error("bad --smoother or --items"); process.exit(2); } +const SMOOTHER_PATCHES = ["thruster", "advanced-alien-multivalve-graph", "advanced-bird-syrinx", "advanced-bird-syrinx-graph", "advanced-syrinx-voice", "advanced-human-larynx-graph", "dx7-algorithm-32-additive-organ", "dx7-algorithm-8-bright-pair"]; +function smootherItems() { + const dir = join(here, "lowered-dings"), d = JSON.parse(readText(join(dir, "dings.json"))); + return [ + ...SMOOTHER_PATCHES.map((n) => ({ id: n === "thruster" ? "thruster@rpm1200" : n, group: "patch", file: `${n}.dsp`, source: low(`${n}.dsp`), params: n === "thruster" ? { rpm: 1200 } : {}, seconds: 3 })), + ...d.instruments.map((i) => ({ id: `ding-instrument/${i.id}`, group: "ding", file: `ding-${i.id}.dsp`, source: readText(join(dir, i.dsp)), params: { [i.controlPath]: i.rootFrequency }, seconds: d.noteSeconds })), + ]; +} +const items = set === "smoother" ? smootherItems() : [ + ...[300, 600, 1200, 4800].map((rpm) => ({ id: `thruster@rpm${rpm}`, group: "patch", file: "thruster.dsp", source: low("thruster.dsp"), params: { rpm }, seconds: 3 })), + ...["sfxr-classic-classic-sfxr-abstract-golf", "sfxr-explosion"].map((n) => ({ id: n, group: "patch", file: `${n}.dsp`, source: low(`${n}.dsp`), params: {}, seconds: 3 })), +]; +if (opt("--tract")) items.push({ id: "tract/vowel-a", group: "patch", file: "tract-vowel-a.dsp", source: readText(opt("--tract")), params: {}, seconds: 0.72 }); +for (const it of items) it.source = pin(it.source); +mkdirSync(join(out, "dsp"), { recursive: true }); + +const readF32Wav = (p) => { const b = readFileSync(p), n = b.readUInt32LE(40) / 4, x = new Float32Array(n); for (let i = 0; i < n; i++) x[i] = b.readFloatLE(44 + i * 4); return x; }; +const thresholds = JSON.parse(readText(join(here, "thresholds.json"))); +const flagsOf = (id, group, m) => { const g = gate({ items: [{ id, group, metrics: m }] }, thresholds, { partial: true }); return [...g.failures.map((f) => `FAIL ${f.metric}`), ...g.waived.map((f) => `waived ${f.metric}`), ...g.warnings.map((f) => `warn ${f.metric}`)]; }; + +const rt = await loadRuntime(), rows = []; +for (const it of items) { + const w = (await renderOnce(await compile(rt, it.id, it.source), it.params, it.seconds)).samples; + const dsp = join(out, "dsp", it.file); writeFileSync(dsp, it.source); + const wav = join(out, `${it.id.replace(/[^A-Za-z0-9._@-]+/g, "_")}.native.wav`); + const r = spawnSync("dotnet", [bin.endsWith(".dll") ? bin : join(bin, "FaustNativeRender.dll"), dsp, wav, String(it.seconds), ...Object.entries(it.params).map(([k, v]) => `${k}=${v}`)], { encoding: "utf8" }); + if (r.status !== 0) { rows.push({ id: it.id, error: (r.stderr || r.stdout).slice(0, 400) }); continue; } + const n = readF32Wav(wav); writeWav(join(out, `${it.id.replace(/[^A-Za-z0-9._@-]+/g, "_")}.wasm.wav`), w); + if (w.length !== n.length) { rows.push({ id: it.id, error: `length mismatch: wasm ${w.length}, native ${n.length}` }); continue; } + const len = w.length; let maxErr = 0, at = 0, sq = 0, sqRef = 0; + for (let i = 0; i < len; i++) { const d = Math.abs(w[i] - n[i]); if (d > maxErr) { maxErr = d; at = i; } sq += d * d; sqRef += w[i] * w[i]; } + const mw = measure(w), mn = measure(n); + rows.push({ id: it.id, lenWasm: w.length, lenNative: n.length, maxErr, maxErrAt: at, rmsErr: Math.sqrt(sq / len), relRmsErrDb: 10 * Math.log10(sq / Math.max(sqRef, 1e-30)), + wasm: pick(mw), native: pick(mn), flagsWasm: flagsOf(it.id, it.group, mw), flagsNative: flagsOf(it.id, it.group, mn) }); +} +function pick(m) { return { samplePeak: m.samplePeak, truePeakDb: m.truePeakDb, loudnessLufs: m.loudnessLufs, centroidMedianHz: m.centroidMedianHz, overSamples: m.overSamples, rmsDb: m.rmsDb, crestDb: m.crestDb, noiseToToneDb: m.noiseToToneDb, noiseToToneADb: m.noiseToToneADb, lowMotion: m.lowMotion }; } +for (const r of rows) { + if (r.error) continue; + r.violations = []; + if (Math.abs(r.native.loudnessLufs - r.wasm.loudnessLufs) > LIMITS.lufsDb) r.violations.push("loudnessLufs"); + if (Math.abs(r.native.truePeakDb - r.wasm.truePeakDb) > LIMITS.truePeakDb) r.violations.push("truePeakDb"); + if (100 * Math.abs(r.native.centroidMedianHz - r.wasm.centroidMedianHz) / r.wasm.centroidMedianHz > LIMITS.centroidPct) r.violations.push("centroidMedianHz"); + if (mode === "imp3" && r.relRmsErrDb > LIMITS.relRmsErrDbImp3) r.violations.push("relRmsErrDb"); +} +writeFileSync(join(out, "native-diff.json"), JSON.stringify({ libfaustWasm: rt.version, sampleRate: SR, items: set, smoother: mode, rows }, null, 1)); +if (rows.some((r) => r.error || r.violations.length)) process.exitCode = 1; +console.log(JSON.stringify({ libfaustWasm: rt.version, items: set, smoother: mode, rows }, null, 1)); diff --git a/tools/aqua-feel/render.js b/tools/aqua-feel/render.js index 91cdb11..61a6a38 100644 --- a/tools/aqua-feel/render.js +++ b/tools/aqua-feel/render.js @@ -1,5 +1,5 @@ // Offline render through the same faustwasm runtime the playground and the listening trial load (not the daemon's -// native libfaust path: same Faust source, same compiler version family, but a different host; see README). +// native libfaust path: same Faust source text but a different compiler build and standard library, so not the same arithmetic; see docs/renders/aqua-feel-native-diff-2026-11-10.md). import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url";