Conversation
Pickup mode has a second acceptance path, next to the tolerance test, for the case where a fast fader move makes consecutive MIDI values skip over the software value. Two separate defects meant it never ran. While waiting for pickup, midiPickupTryApply returned early without recording the value, so the history deque stayed empty and the size() >= 2 guard in midiPickupShouldApply was never satisfied. And prevMidi read back(), which is the value just appended, so the bracket test reduced to midiValue == currentValue, already covered by the tolerance test above it. Either defect alone disables the path; both are fixed here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
From review on jamulussoftware#3835: pickupBuffer is this function's parameter name, so a reader looking for where it is defined finds nothing but the signature. The objects behind it are the per-channel MidiPickupState::recentFader and ::recentPan deques, bound at the two call sites in SetFaderLevel and SetPanValue. Comment only; no behaviour change. CHANGELOG: SKIP Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MEXBpjaa8oA5PPgQcZg5Sq
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: QUIET Plan: Advanced Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review. 📝 WalkthroughWalkthroughThe MIDI pickup logic now preserves pending MIDI values and uses the second-to-last history entry for crossing detection. ChangesMIDI pickup behavior
Priority: ⬇️ Low Estimated code review effort: 1 (Trivial) | ~5 minutes Change: Bug fix Merge Risk: ⚪ Minimal · up to The pickup crossing fix is ready to merge; normal build and runtime checks remain sufficient. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Note
📡 STAND BY FOR AN LLM-AUTHORED MESSAGE.
MIDI pickup mode has a second acceptance path beside the tolerance test, for when a fast fader move makes consecutive MIDI values skip straight over the software value:
It has never run. There are two independent defects, and either one alone is enough to disable it.
1. The history is never recorded while waiting.
midiPickupTryApplybuilds a temporary copy, tests it, and on failure returns early — jumping over the// Update the pickup bufferblock at the end of the function. So whilewaitingForPickupis true, which is exactly the state the history exists to serve,pickupBufferstays empty. The largest deque ever passed tomidiPickupShouldApplyis 1, sosize() >= 2is never satisfied.2.
prevMidiis not the previous value.recentMidiValues.back()is the elementmidiValuewas justpush_back'd as, soprevMidi == midiValueand the bracket test reduces tomidiValue == currentValue— already covered by the tolerance test three lines above. Sweeping(prev, current, new)over 0..100 outside tolerance, the current code detects 0 of 323400 genuine crossings.The
size() >= 2guard is itself the evidence of intent: you only need two elements if you mean to look past the last one.What it costs a user
CSoundBase::ParseMIDIMessagemaps CC 0..127 onto fader 0..AUD_MIX_FADER_MAX(100), so one CC step is 0.79 fader units against aMIDI_PICKUP_TOLERANCEof 2. Slow moves are picked up by the tolerance test and the bug stays invisible. Fast moves are where it shows: sweeping a hardware fader past a software fader sitting at 50, the fader stays dead at several speeds until the user slows down and lands within ±2 units.The two middle columns are the reason this PR changes two things rather than one: fixing either defect on its own changes nothing measurable.
Checks
Harness compiles the two patched functions verbatim out of
audiomixerboard.cpprather than a re-typed copy, so what is measured is what is shipped.clang-format14.0.6 reports no change; compiles clean under-Wall -Wextra.Runtime, through the shipped client. A JACK MIDI source — not physical hardware, but real MIDI arriving on the port
CSound::CreateMIDIPortopens — feeds a GUI client with one channel fader parked at 50 and Pick-up Mode on, and the observable is theCHANNEL_GAINmessage the client puts on the wire. Two control-change messages 298.12 ms apart carrying CC 51 and CC 76 — fader 40 and 59, bracketing the parked 50, both outside tolerance — produce no gain message and no fader movement onmainat72e856af. The same two messages on that tree with this PR's two edits applied pick up and send the gain for 59. Sweeping that same span one CC step at a time onmaininstead picks up at 48, the tolerance edge, and tracks from there: 12 gain messages. Reproducers, including one that needs no MIDI hardware at all: this gist.What I did not do
One related thing I noticed and deliberately left alone:
g_midiPickupWaitingForPickupis a single flag per channel shared by the fader and the pan, while the history deques and timestamps beside it inMidiPickupStateare correctly per-control (recentFader/recentPan,lastMidiTimeFader/lastMidiTimePan). That means picking up the pan also clears the fader's waiting state, and either control's inactivity timeout re-arms both. It needs two flags rather than one, which is a different change from this one, so I have not folded it in. I can open it separately if you would like.CHANGELOG: Bugfix: MIDI pickup mode now correctly detects a fader crossing the software value during fast moves.