// note_entry.h — PURE parse + clamp for the S12 direct numeric entry of a zone's // low/high/root MIDI note. NO VST3, NO REAPER, NO SWELL/LICE types at the boundary. The // mirror of the other pure editor helpers: the fiddly text->note parse lives here, unit- // tested outside the DAW, while the editor shell hosts the text field (a SWELL edit control // or a LICE text-entry idiom) and feeds the committed string here on Enter. // // WHY IT EXISTS (S12). Low/high/root are draggable on the keyboard strip, but a drag can't // hit a precise note reliably. This adds a typed field: the user clicks the field, types a // value, and presses Enter; the shell hands the raw string here to parse into a clamped MIDI // note [0,127] and commits via the same off-thread reload as every other edit. // // ACCEPTED FORMS (both, so a musician OR a MIDI-number user is served): // * a plain decimal integer ("60", " 127 ", "+5") — the raw MIDI note number; and // * a note name ("C4", "f#3", "Bb-1") — parsed to its MIDI number under the DAW's C4==60 // convention (MIDI 0 == C-1, matching REAPER + the editor's noteLabel). // A value out of [0,127] CLAMPS to the range (a typed 200 becomes 127) rather than // rejecting — the least-surprising behavior for a nudge field. Unparseable input returns // nullopt (the shell keeps the old value + may flash the field). #pragma once #include #include namespace reasampler::vst { // Parse a typed low/high/root field into a clamped MIDI note [0,127]. Accepts a decimal // integer OR a note name (see the header notes). Leading/trailing ASCII whitespace is // ignored. An in-range parse returns the note; an out-of-range numeric or note value clamps // into [0,127]; empty or unparseable input returns nullopt (no change). Pure — no host types. std::optional parseNoteEntry(const std::string& text); } // namespace reasampler::vst