Add a post-effects master volume knob with MIDI Learn #14

Merged
erdoar merged 2 commits from claude/master-volume-midi into main 2026-10-10 16:57:53 +00:00
erdoar commented 2026-10-10 04:18:01 +00:00 (Migrated from github.com)

Summary

  • Master volume: after the whole effect chain, as a master stage feeding the main mixer. It's an AVAudioUnitEQ with no bands, used for its global gain, so it can cut and boost. Silence mutes the main mixer.
  • Taper: like a desk fader. 0 dB sits at 80% of the travel, a cubic curve below that falls to silence (≈ -18 dB at half of 0 dB's travel), and above it the level rises evenly to +10 dB. AudioEngine.masterGain is linear and clamps to 0...+10 dB. Boosted audio that goes over full scale clips at the output.
  • Knob: a large bakelite knob on the pine board next to STOP. Drag it up or down to turn it. Its level shows in dB on a tuning scale, with "MASTER" burnt into the wood. It works with VoiceOver's adjust actions.
  • Bent tack: a brass drawing pin bent over in the wood beside the rim marks 0 dB. Clicking it snaps the knob back to 0 dB.
  • MIDI: MIDIInput (CoreMIDI, receive-only) listens to every MIDI source, including devices that appear later. UMP in PlugCore reads the control changes out of CoreMIDI's Universal MIDI Packets, stepping over longer messages correctly.
  • MIDI Learn: a brass plate under the knob. Click it, move a control on your controller, and it binds to that channel and CC; the plate shows e.g. "CC 7 · CH 1". Right-click to forget. Values 0–127 cover the whole knob, silence to +10 dB.
  • The level (saved as masterPosition, defaulting to 0 dB) and the binding are saved. During MIDI moves, saves wait until the control settles.
  • The window's minimum width grows to 900.

Tested

  • Linux, Swift 6.0.3: 31 tests pass, covering the taper (silence, unity at 80%, +10 dB at the top, steady rise, labels), UMP parsing, binding matching, and settings round trip plus defaults.
  • New macOS tests: the master gain cuts, boosts and clamps to +10 dB matching the knob, and the MIDI input starts. Not run yet.
  • The macOS files pass a syntax-only parse. Not compiled or tried with a controller yet.

To test on the Mac

  1. Quit Plug, then run swift test.
  2. Run scripts/bundle.sh --open and play something at a low system volume. The knob should start at 0 dB, pointing at the tack. Turning it down should cut, and turning it past the tack should boost up to +10 dB. Click the tack to return to 0 dB.
  3. Click MIDI LEARN and move a control on your controller. It should then drive the knob.
  4. Quit and reopen Plug. The level and the binding should be kept.

🤖 Generated with Claude Code

https://claude.ai/code/session_011C96TJ2L7nzVMFTH7raNu5

## Summary - **Master volume:** after the whole effect chain, as a master stage feeding the main mixer. It's an `AVAudioUnitEQ` with no bands, used for its global gain, so it can cut and boost. Silence mutes the main mixer. - **Taper:** like a desk fader. **0 dB sits at 80% of the travel**, a cubic curve below that falls to silence (≈ -18 dB at half of 0 dB's travel), and above it the level rises evenly to **+10 dB**. `AudioEngine.masterGain` is linear and clamps to 0...+10 dB. Boosted audio that goes over full scale clips at the output. - **Knob:** a large bakelite knob on the pine board next to STOP. Drag it up or down to turn it. Its level shows in dB on a tuning scale, with "MASTER" burnt into the wood. It works with VoiceOver's adjust actions. - **Bent tack:** a brass drawing pin bent over in the wood beside the rim marks 0 dB. Clicking it snaps the knob back to 0 dB. - **MIDI:** `MIDIInput` (CoreMIDI, receive-only) listens to every MIDI source, including devices that appear later. `UMP` in PlugCore reads the control changes out of CoreMIDI's Universal MIDI Packets, stepping over longer messages correctly. - **MIDI Learn:** a brass plate under the knob. Click it, move a control on your controller, and it binds to that channel and CC; the plate shows e.g. "CC 7 · CH 1". Right-click to forget. Values 0–127 cover the whole knob, silence to +10 dB. - The level (saved as `masterPosition`, defaulting to 0 dB) and the binding are saved. During MIDI moves, saves wait until the control settles. - The window's minimum width grows to 900. ## Tested - Linux, Swift 6.0.3: 31 tests pass, covering the taper (silence, unity at 80%, +10 dB at the top, steady rise, labels), UMP parsing, binding matching, and settings round trip plus defaults. - New macOS tests: the master gain cuts, boosts and clamps to +10 dB matching the knob, and the MIDI input starts. **Not run yet.** - The macOS files pass a syntax-only parse. **Not compiled or tried with a controller yet.** ## To test on the Mac 1. Quit Plug, then run `swift test`. 2. Run `scripts/bundle.sh --open` and play something **at a low system volume**. The knob should start at 0 dB, pointing at the tack. Turning it down should cut, and turning it past the tack should boost up to +10 dB. Click the tack to return to 0 dB. 3. Click **MIDI LEARN** and move a control on your controller. It should then drive the knob. 4. Quit and reopen Plug. The level and the binding should be kept. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_011C96TJ2L7nzVMFTH7raNu5
Sign in to join this conversation.
No description provided.