Vowel gestures calibrated by measurement; exporter sample rate from callers #18

Merged
aqua merged 10 commits from aqua/tract-voice into main 2026-11-10 18:13:29 +00:00
Member

Stacked on #17 (harmonic source + Kelly-Lochbaum ladder). Recalibrates the authored vowel gestures by measurement, keeps the lip radiating aperture open for vowels, fixes the radiation highpass at 200 Hz, passes the exporter sample rate from callers, and feeds tools/WordRender from Weksa's phones line. Nothing here has been heard by anyone.

Weksa phones in (WeksaPhones.cs): WeksaPhonesReader.Parse reads the {language, source, phones:[{ipa, stress none|primary|secondary}]} line of Weksa PR 16 (weksa lower --phones, commit a7bc2478). It refuses malformed JSON, missing/extra/null/mistyped keys, unknown stress and empty phones. WeksaWordPlan.From checks every phone against the DSL's own IPA table (PatchScript.TryIpaDescriptor, the table phoneme_gesture already used) and, if any phone is outside it, lists them and plans nothing: WordRender exits 4 and renders nothing (exit 3 for a refused file). Durations (vowel 180 ms, other 95 ms) and flat 140 Hz pitch stay AquaSynth's; stress only sets gesture intensity (primary 1.2, secondary 1.1, none 1.0). Fixture copied from Weksa PR 16 with provenance in tests/AquaSynth.Dsl.Tests/Fixtures/Weksa. 25 tests pass; 8 hand mutants (extra keys allowed, unknown stress to none, empty phones allowed, unsupported approximated, stress lengthens duration, stress ignored, stress on every phone, null ipa allowed) each fail at least one test.

Measured (WordRender from the Weksa fixture, 140 Hz, LPC order 12, median of 30 ms frames, vowels held 0.2-0.6 s):

vowel isolated F1/F2/F3 Hz rms
i 277 / 2356 / 2388 0.0292
u 392 / 869 / 2629 0.0199
a 681 / 1066 / 2767 0.0470

Inside /ˈnibu/: i 277/2352/2390, u 393/869/2629 (same as isolated).

/ˈnibu/ segment ms rms dB re i
n 0-95 0.0068 -12.1
i 95-275 0.0273 0
b 275-370 0.0129 -6.5
u 370-550 0.0200 -2.7
tail 550-672 0.0214 -2.1

Vowels differ in measured F1/F2. Script, WAVs and table: /opt/commons/handoff/aqua-nibu-first-render-20261108-weksa/render. Listening kit (new, the earlier kit is untouched): /opt/commons/handoff/aqua-nibu-first-render-20261108-weksa/kit/listen.html.

Weak spots

  • Measured only by LPC and levels; how any of it sounds is unknown.
  • The i F2 and F3 sit 32 Hz apart (2356/2388), probably one merged peak that LPC splits; F3 is not independently supported.
  • Stress is a level raise only, and it does not show: the stressed i inside the word (rms 0.0290) matches the unstressed isolated i (0.0292). No stress contour in duration or pitch exists.
  • The b peak (0.143) is above every vowel peak (0.073-0.077), a burst; the tail after the last gesture holds the u shape at 0.0214 rms, louder than the u segment, with no release.
  • Only n, i, u, a, b and the other phones in the DSL table are renderable. The Weksa-ruled /ɪ/ and /ʊ/ are not, and are reported, not approximated. GestureDescriptor still falls back to an alveolar approximant for hand-written scripts that name an unknown phone.
  • o is 454/962 from the earlier grid search (not re-measured in this pass); only i, u, a, ae, e, o, schwa shapes exist, and others pick the nearest anchor.
  • The u lip pinches to 0.05 cm and its tongue shape is not anatomical.
  • ProbeTimelineReport carries no formants and its delay_samples still hardcodes 48000; FaustExportOptions still defaults to 48000 (FaustRenderedSpeechLossSurface, AquaLower and the wasm compile path pass no rate).
  • VocalTractFormantTests and the four daemon/store tests that failed in this sandbox before were not re-run in this pass.

🤖 Generated with Claude Code

Stacked on #17 (harmonic source + Kelly-Lochbaum ladder). Recalibrates the authored vowel gestures by measurement, keeps the lip radiating aperture open for vowels, fixes the radiation highpass at 200 Hz, passes the exporter sample rate from callers, and feeds `tools/WordRender` from Weksa's phones line. Nothing here has been heard by anyone. **Weksa phones in** (`WeksaPhones.cs`): `WeksaPhonesReader.Parse` reads the `{language, source, phones:[{ipa, stress none|primary|secondary}]}` line of Weksa PR 16 (`weksa lower --phones`, commit a7bc2478). It refuses malformed JSON, missing/extra/null/mistyped keys, unknown stress and empty phones. `WeksaWordPlan.From` checks every phone against the DSL's own IPA table (`PatchScript.TryIpaDescriptor`, the table `phoneme_gesture` already used) and, if any phone is outside it, lists them and plans nothing: `WordRender` exits 4 and renders nothing (exit 3 for a refused file). Durations (vowel 180 ms, other 95 ms) and flat 140 Hz pitch stay AquaSynth's; stress only sets gesture intensity (primary 1.2, secondary 1.1, none 1.0). Fixture copied from Weksa PR 16 with provenance in `tests/AquaSynth.Dsl.Tests/Fixtures/Weksa`. 25 tests pass; 8 hand mutants (extra keys allowed, unknown stress to none, empty phones allowed, unsupported approximated, stress lengthens duration, stress ignored, stress on every phone, null ipa allowed) each fail at least one test. **Measured** (WordRender from the Weksa fixture, 140 Hz, LPC order 12, median of 30 ms frames, vowels held 0.2-0.6 s): | vowel | isolated F1/F2/F3 Hz | rms | |---|---|---| | i | 277 / 2356 / 2388 | 0.0292 | | u | 392 / 869 / 2629 | 0.0199 | | a | 681 / 1066 / 2767 | 0.0470 | Inside /ˈnibu/: i 277/2352/2390, u 393/869/2629 (same as isolated). | /ˈnibu/ segment | ms | rms | dB re i | |---|---|---|---| | n | 0-95 | 0.0068 | -12.1 | | i | 95-275 | 0.0273 | 0 | | b | 275-370 | 0.0129 | -6.5 | | u | 370-550 | 0.0200 | -2.7 | | tail | 550-672 | 0.0214 | -2.1 | Vowels differ in measured F1/F2. Script, WAVs and table: /opt/commons/handoff/aqua-nibu-first-render-20261108-weksa/render. Listening kit (new, the earlier kit is untouched): /opt/commons/handoff/aqua-nibu-first-render-20261108-weksa/kit/listen.html. **Weak spots** - Measured only by LPC and levels; how any of it sounds is unknown. - The i F2 and F3 sit 32 Hz apart (2356/2388), probably one merged peak that LPC splits; F3 is not independently supported. - Stress is a level raise only, and it does not show: the stressed i inside the word (rms 0.0290) matches the unstressed isolated i (0.0292). No stress contour in duration or pitch exists. - The b peak (0.143) is above every vowel peak (0.073-0.077), a burst; the tail after the last gesture holds the u shape at 0.0214 rms, louder than the u segment, with no release. - Only n, i, u, a, b and the other phones in the DSL table are renderable. The Weksa-ruled /ɪ/ and /ʊ/ are not, and are reported, not approximated. `GestureDescriptor` still falls back to an alveolar approximant for hand-written scripts that name an unknown phone. - o is 454/962 from the earlier grid search (not re-measured in this pass); only i, u, a, ae, e, o, schwa shapes exist, and others pick the nearest anchor. - The u lip pinches to 0.05 cm and its tongue shape is not anatomical. - `ProbeTimelineReport` carries no formants and its `delay_samples` still hardcodes 48000; `FaustExportOptions` still defaults to 48000 (FaustRenderedSpeechLossSurface, AquaLower and the wasm compile path pass no rate). - `VocalTractFormantTests` and the four daemon/store tests that failed in this sandbox before were not re-run in this pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ControlSplineTimeline.SurfaceSplines is the one owner of which spline decides a surface (>=2 enabled splines merge into one bezier curve over the union of points; one spline unchanged). FaustExport and ProbeTimelineReport no longer sum per-spline offsets; WordRender drops its no-spline emit and timeline-driven sliders.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replaces the sine os.osc in the primitive vocal source. Tilt (default .5, DSL tilt=, surface /vocal/sources/i/tilt): 0 brightest, 1 steepest rolloff; cutoff 200*2^((1-tilt)*5) Hz. Opening and tension amplitude factors kept. ProbeTimelineReport models only the source's flow level (no oscillator), so tilt does not enter it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Three native-compiling classes running at once crashed the test host (reproduced at 271 passed, every run, once a third
native class existed). They now share one xUnit collection.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Each waveguide path is a one-sample-per-cell ladder (N = round(L*SampleRate/c)) written as a Faust letrec; the glottal source
feeds cell 0 and the lip wave is the radiated signal. A branch port joining two paths of the network is a three-port velum
junction (Pink Trombone's), opening*coupling*0.4 cm wide. Lip reflection is the radiation load's live reflection.
The Gaussian area deformation of TerminalAreaExpression and SegmentAreaExpression is one helper, DeformedAreaExpression,
which the ladder cells also use. PrimitiveAreaExpression and PrimitiveDelayExpression are deleted. FaustExportOptions.SampleRate
(default 48000) is passed by the native runtime. Scaffold: contact opening 1, nostril radiation load.
Tests: F1/F2 of i, schwa, a, vowel ordering, stability with velum open, nasal exit with the mouth shut; the aliasing test
now measures the whole non-harmonic grid since the tract reshapes the harmonics.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The vocal ladder has one cell per sample, so exporting at the 48 kHz default and rendering at 44.1 kHz (daemon, IPA trial, song worker, graph renderer) shifted every formant down 8%. Speech-loss surface and AquaLower still take the default; the wasm compile path has no rate.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
EmitVowelGesture now holds tongue index, tongue and lip diameters (cm) from anchors measured by impulse response toward textbook F1/F2 (i 271/2313, u 292/876, a 703/1084, plus ae, e, o, schwa), with the constriction opened. The old targets put a at 310/2130 and i at 620/1620 through the same ladder. Tests render the authored gestures end to end and read LPC envelope peaks.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The gesture also scaled the aperture (an output gain and highpass corner) by lip cm / 2.2, so /u/ (lip .05 cm) rendered 29 dB under /i/. A vowel now holds aperture at 1; consonant closures still use it. Test: /u/ rms within -10..+3 dB of /i/, F2 under 1000 Hz.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The corner sat at 540 Hz for a vowel, above /u/'s F1, and the envelope read that F1 at 450 Hz. The ladder's lip cell already carries the lip area; aperture stays the gain consonant closures use. Tests: u F1 250-350 and F2 near 876; i F1 band widened to 20% (the harmonic-line reading of i moves 230-260 Hz with the corner).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The DSL's IPA table becomes PatchScript.TryIpaDescriptor so the reader asks the one table instead of keeping its own.
Fixture is Weksa PR 16 at a7bc2478, byte for byte.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
aqua changed target branch from aqua/nibu-first-render to main 2026-11-10 18:12:43 +00:00
Author
Member

Maintainer pass (2026-11-10). Stacked on #17 (merged); retargeted to main. Full suite at this tip: only the 3 failures main has (Zyn pinned source absent, FaustLoader platform-name, CultMesh leased workers) plus the four native daemon tests, fixed on main by #25. Merged as the base of #19, which supersedes its Gaussian-tongue area model with Story 2008 measured areas but keeps the Kelly-Lochbaum ladder, the calibrated gestures and the exporter sample rate. Unheard. Merging as provenance, not approval; nothing deployed.

Maintainer pass (2026-11-10). Stacked on #17 (merged); retargeted to main. Full suite at this tip: only the 3 failures main has (Zyn pinned source absent, FaustLoader platform-name, CultMesh leased workers) plus the four native daemon tests, fixed on main by #25. Merged as the base of #19, which supersedes its Gaussian-tongue area model with Story 2008 measured areas but keeps the Kelly-Lochbaum ladder, the calibrated gestures and the exporter sample rate. Unheard. Merging as provenance, not approval; nothing deployed.
aqua merged commit 6906ae590e into main 2026-11-10 18:13:29 +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!18
No description provided.