Calibrate OscA pitch depth, G1 pre-roll phases and control levels (v25) #12

Merged
peterswimm merged 2 commits from calibration-v25 into main 2026-10-22 02:25:19 +00:00
Owner

Scope

Calibration round v25 of the shared G1 → Faust model laws, fit from G1-Emu measurements. Both the Faust export and the Python renderer change together.

  • OscA/OscB Type II pitch inputs. Each pitch-mod knob now has a measured full-scale step count, using G1's 1/128-semitone grid; for example, knob 64 is 560.26 steps and knob 127 is 8191.5. The summed inputs are floored once. Pitch modulation takes effect at capture start; during the adapter pre-roll the oscillator free-runs at its static pitch.
  • Control levels. Unipolar 7-bit levels send v/128, and 127 sends exactly 1.0. This covers Constant, ADSR/Mod-Env sustain, Multi-Env and NoteVelScal. Bipolar Constant sends (v−64)/64.
  • G1 adapter pre-roll (0.31 s). The Faust runner now renders the pre-roll and throws it away, so free-running sources keep patch time. Capture-calibrated pieces (gate, LFOA) use capture_time.
    • ClkGen beat phase.
    • LFOB/LFOC start phase for each voice mode.
    • LFOC waveform order, and rates equal to LFOB's in ranges 1–2.
    • OscA sine/triangle start phases.
    • Digitizer clock phase, refit to 0.60 measured from patch start.
  • Regenerated docs/G1_PARITY_MATRIX.{json,md} from the v25 sweep.

Not addressed this round: PercOsc (95) pitch law, the OscA FMA input, Phaser (102) notches, the Expander (105) gate parameter, and the end level of Multi-Env segments, which sits 2 steps low. docs/G1_BASELINE_STATUS.json is unchanged because regenerating it needs a full four-shard baseline run.

Testing

  • python3 -m unittest discover -s tests passes all 129 tests. New tests cover the pitch-step floor, the depth table, the control fraction, ClkGen on patch time, LFOB/LFOC phases and waveform order, OscA start phase and the Digitizer clock.
  • Cut plan v25 (module-baseline-plan --control-observer-ready --physical-output-source-ready --lfoa-modulation-ready) and swept all 1,489 probes. No probe that passed in v24 fails in v25.
  • tools/export_public.py verifies a clean public tree.
Verdict v24 v25
pass 842 922
pitch 298 245
level 192 194
shape-or-phase 100 74
both-silent 36 36
silence-mismatch 14 14
peak-only 7 4
Stage v24 v25
sweep-clean 17 21
near 22 23
partial 23 22
divergent 44 40
not-swept 3 3

Impact Statement

The Faust export and the Python renderer move closer to G1 on oscillator pitch modulation and on the startup phase of free-running sources. Faust renders get 0.31 s longer, because the pre-roll is computed and then discarded. This PR adds no private data (plans, fixtures, captures or results stay under ~/.nardwahl). Sweep verdicts are for triage only, so no module is promoted to reference-compared.

## Scope Calibration round v25 of the shared G1 → Faust model laws, fit from G1-Emu measurements. Both the Faust export and the Python renderer change together. - **OscA/OscB Type II pitch inputs.** Each pitch-mod knob now has a measured full-scale step count, using G1's 1/128-semitone grid; for example, knob 64 is 560.26 steps and knob 127 is 8191.5. The summed inputs are floored once. Pitch modulation takes effect at capture start; during the adapter pre-roll the oscillator free-runs at its static pitch. - **Control levels.** Unipolar 7-bit levels send v/128, and 127 sends exactly 1.0. This covers Constant, ADSR/Mod-Env sustain, Multi-Env and NoteVelScal. Bipolar Constant sends (v−64)/64. - **G1 adapter pre-roll (0.31 s).** The Faust runner now renders the pre-roll and throws it away, so free-running sources keep patch time. Capture-calibrated pieces (gate, LFOA) use `capture_time`. - ClkGen beat phase. - LFOB/LFOC start phase for each voice mode. - LFOC waveform order, and rates equal to LFOB's in ranges 1–2. - OscA sine/triangle start phases. - Digitizer clock phase, refit to 0.60 measured from patch start. - Regenerated `docs/G1_PARITY_MATRIX.{json,md}` from the v25 sweep. Not addressed this round: PercOsc (95) pitch law, the OscA FMA input, Phaser (102) notches, the Expander (105) gate parameter, and the end level of Multi-Env segments, which sits 2 steps low. `docs/G1_BASELINE_STATUS.json` is unchanged because regenerating it needs a full four-shard baseline run. ## Testing - `python3 -m unittest discover -s tests` passes all 129 tests. New tests cover the pitch-step floor, the depth table, the control fraction, ClkGen on patch time, LFOB/LFOC phases and waveform order, OscA start phase and the Digitizer clock. - Cut plan v25 (`module-baseline-plan --control-observer-ready --physical-output-source-ready --lfoa-modulation-ready`) and swept all 1,489 probes. No probe that passed in v24 fails in v25. - `tools/export_public.py` verifies a clean public tree. | Verdict | v24 | v25 | |---|---:|---:| | pass | 842 | 922 | | pitch | 298 | 245 | | level | 192 | 194 | | shape-or-phase | 100 | 74 | | both-silent | 36 | 36 | | silence-mismatch | 14 | 14 | | peak-only | 7 | 4 | | Stage | v24 | v25 | |---|---:|---:| | sweep-clean | 17 | 21 | | near | 22 | 23 | | partial | 23 | 22 | | divergent | 44 | 40 | | not-swept | 3 | 3 | ## Impact Statement The Faust export and the Python renderer move closer to G1 on oscillator pitch modulation and on the startup phase of free-running sources. Faust renders get 0.31 s longer, because the pre-roll is computed and then discarded. This PR adds no private data (plans, fixtures, captures or results stay under `~/.nardwahl`). Sweep verdicts are for triage only, so no module is promoted to reference-compared.
The Faust runner now renders the G1 adapter pre-roll, so the free-running
Digitizer clock accumulates from patch start. Its phase is refit there
against the default-rate G1 probes (0.60), and the Python renderer starts
the clock where the pre-roll leaves it.
Regenerate the parity matrix from plan v25
All checks were successful
PR policy check / policy-gate (pull_request) Successful in 0s
2ef5aa0864
Probe sweep v25: 922 of 1,489 probes pass (842 in v24) with no v24 pass
regressing; sweep-clean 21, near 23, partial 22, divergent 40.
peterswimm deleted branch calibration-v25 2026-10-22 02:25:19 +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
peter-swimm/nardwahl!12
No description provided.