Skip to content

feat(eg-bias): selectable boost mode restoring the Core 1.23.0 behaviour (M2DX #168) - #23

Merged
hakaru merged 2 commits into
mainfrom
feat/eg-bias-boost-mode
Oct 4, 2026
Merged

hakaru merged 2 commits into
mainfrom
feat/eg-bias-boost-mode

Conversation

@hakaru

@hakaru hakaru commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Summary

For hakaru/M2DX#168. 1.24.0 made EG bias follow the DX7 (#22). The reporter confirmed the DX7 match but prefers the old response for breath sounds: raising all six operators made breath add harmonics (VL70m-like), which the DX7 semantics cannot do.

  • EGBiasMode — .dx7 (default, unchanged 1.24.0 behaviour) / .boost (#97 behaviour).
  • setEGBiasMode(_:), slot field egBiasMode, controller NRPN index 40 (AUv3 address 940).
  • Preset load resets the mode to .dx7 with the other controller mappings.

Verification

  • Boost output bit-identical to Core 1.23.0: Modern and Mark I, breath EG-bias range 15 and 99, a breath swell up and down over a 6-operator patch with mixed AMS and feedback (149,504 samples compared).
  • New EGBiasBoostModeTests (exact OL delta, 127 ceiling, DX7 default, boost vs DX7 on an AMS 0 operator, scaling, switching back). Existing EGBiasTests unchanged and passing.
  • 361 tests / 64 suites, Debug and Release.

RT: one Int32 per slot and per voice, no allocation; DX7 mode passes egBiasOL = 0.

🤖 Generated with Claude Code

…our (M2DX #168)

1.24.0 made EG bias follow the DX7 (M2DX #163). A player who confirmed
the DX7 match still prefers the old response for breath sounds: raising
every operator, modulators included, made breath add harmonics, which the
DX7 semantics cannot do (EG bias never lifts above the programmed level).

EGBiasMode (.dx7 default, .boost) with setEGBiasMode(_:), slot field
egBiasMode and controller NRPN index 40. Boost restores the #97 path:
range × controller summed into OL points (cap 99), applied to all six
operators through scaleOutputLevel and the 127 ceiling. Preset load resets
the mode to .dx7 with the other controller mappings.

Boost output is bit-identical to Core 1.23.0 (Modern and Mark I, ranges
15 and 99, breath swell up and down). EGBiasBoostModeTests: exact OL delta,
127 ceiling, DX7 default, boost ignores AMS while DX7 leaves AMS 0 alone,
scales with breath and range, switching back restores DX7. 361 tests /
64 suites pass in Debug and Release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-04T06:55:08.552841Z 107a850 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

_RefactorEvalDump.swift is a local, uncommitted experiment harness that
the previous commit picked up. The file stays on disk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@hakaru
hakaru merged commit 919e862 into main Oct 4, 2026
1 check passed
@hakaru
hakaru deleted the feat/eg-bias-boost-mode branch October 4, 2026 06:53

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 107a850107

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +169 to +173
if egBiasOL > 0 {
let biasedOL = min(99, outputLevel + Int(egBiasOL))
let base = min(127, scaleOutputLevel(outputLevel) + klsOffset)
let boosted = min(127, scaleOutputLevel(biasedOL) + klsOffset)
levelIn = levelIn &+ (Int32((boosted - base) << 5) << 16)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Stop boosting operators after their envelopes become idle

When one operator finishes its release before the other operators in the voice, env.getsample() returns 0 for that inactive operator, but this unconditional addition gives it a nonzero gain again. Because the voice remains active while any other operator envelope is running, the completed carrier or modulator can continue sounding for the rest of the longest release; apply the boost only when wasActive is true.

Useful? React with 👍 / 👎.

Comment on lines +171 to +173
let base = min(127, scaleOutputLevel(outputLevel) + klsOffset)
let boosted = min(127, scaleOutputLevel(biasedOL) + klsOffset)
levelIn = levelIn &+ (Int32((boosted - base) << 5) << 16)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include the output floor when calculating the boost delta

For notes with sufficiently negative keyboard scaling or velocity attenuation, the real envelope output is clamped by max(0, ...), but base and boosted are calculated before that lower clamp and omit velocityOffset. For example, when both scaled levels remain below zero, the actual output-level delta should be zero while this code applies the full raw delta, making an otherwise floor-clamped operator audible. Compute both endpoints through the same complete output-level clamp used by combinedOutputLevel.

Useful? React with 👍 / 👎.

Comment on lines +50 to +51
@Test("Dump envelope baseline to /tmp/refactor-eval/dump.bin")
func dump() throws {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove the temporary dump test from the committed suite

This test is explicitly described as an uncommitted experiment, yet swift test now executes it and writes to the fixed path /tmp/refactor-eval/dump.bin without validating any behavior. That adds an unrelated filesystem side effect to every full test run and can fail in restricted or concurrently running test environments; keep this harness outside the test target or remove its @Test entry.

Useful? React with 👍 / 👎.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant