gfx/mpe_keyboard.h
An on-screen keyboard for MPE: every sounding note drawn as a circle that slides sideways with its pitch bend, rises with its timbre and swells with its pressure -- and a mouse that plays it the same way.
#include <sonore/gfx/mpe_keyboard.h>- 1type
- Guides: The native editor
On this page
Design notes
Why a second keyboard
midi_keyboard.h answers "is it receiving notes". For an MPE instrument that is a quarter of the question. The sound of a note on a Seaboard or a LinnStrument is in what each finger does AFTER it lands -- a slide of a whole tone, a press that opens the filter -- and a lit key cannot show any of it. A user checking that their controller's slides are reaching the plugin, or that the bend range agrees on both sides (the most common MPE setup fault there is), needs to SEE the slide.
So this is MidiKeyboard's geometry and look, with the notes drawn over it:
x the note's pitch: its key plus its own bend plus its zone's
master bend, placed between key centres so a slide moves
smoothly across white and black keys alike
y its timbre (CC 74): bright at the top, dark at the bottom
radius its pressure
Driven by the SDK's own MPE decoding
processMidi() reads the same channel-per-note MIDI the DSP gets, through MpeDecoder -- so zones from the MPE Configuration Message, bend ranges from RPN 0, and a master channel's zone-wide bend are understood exactly as the DSP understands them, by the same code. A host speaking per-note expression natively (CLAP, VST3) hands over a NoteExpressionBuffer instead, through applyExpression().
Per channel it also keeps the LAST bend, pressure and timbre seen, because MPE sends a note's starting expression BEFORE its note-on: a note begins where its channel already is, and a decoder that only tracks sounding notes would draw every note starting from the centre.
The mouse
A mouse cannot slide and press at once the way a finger does, but it has two axes. Pressing plays a note on a free member channel of the zone; dragging sideways bends it, measured from where the button went down (a click off a key's centre must not start bent); the vertical position sets pressure -- or timbre, setVerticalGesture() -- with the bottom of the key strongest, the way MidiKeyboard's velocity already works. What comes out is real MPE on onMpeMessage: the bend, CC 74 and pressure first, then the note-on, as the MPE specification orders them, so a synth hears the note begin already shaped.
UI thread only, like every widget: the plugin forwards what its DSP received to it on the UI's own clock.
Types 1
class MPEKeyboardComponent : public MidiKeyboard
A keyboard that draws each sounding MPE note as a circle moved by its bend, timbre and pressure, and plays MPE from the mouse -- the reference's MPEKeyboardComponent. The file comment explains the drawing, the decoding and the mouse gesture.
Feed it what the DSP received with processMidi() (channel-per-note MIDI) or applyExpression() (a host's per-note expression), on the UI thread: the owner carries the audio thread's events across, as for MidiKeyboard. Mouse notes come out on onMpeMessage when it is set, and on MidiKeyboard's onNoteOn / onNoteOff otherwise. It holds at most kMaxNotes notes; past that the oldest is dropped.