93 return member_bend_semi_[1];
97 return member_bend_semi_[channel & 0x0F];
101 return manager_bend_semi_[0];
105 return manager_bend_semi_[upper_zone ? 1 : 0];
128 follow_config_messages_ = enabled;
131 return follow_config_messages_;
145 if (cc_index) assignable_timbre_index_ =
static_cast<uint8_t
>(*cc_index & 0x7F);
146 else assignable_timbre_index_.reset();
149 return assignable_timbre_index_;
209 const std::array<MpeNoteState, kMaxNotes>&
slots()
const {
return notes_; }
246 void add_note(uint8_t ch, uint8_t note, uint8_t velocity,
bool upper);
247 void remove_note(uint8_t ch, uint8_t note);
248 bool accept_note_lifecycle(const
MpeNoteState* note_off,
250 bool defer_note_off(const
MpeNoteState& note_off) noexcept;
252 void record_generation_refusal() noexcept;
254 void update_channel_pitch_bend(uint8_t ch,
float semitones,
bool upper);
255 void update_channel_pressure(uint8_t ch,
float pressure,
bool upper);
256 void update_channel_timbre(uint8_t ch,
float timbre,
bool upper);
258 void track_registered_parameter(const
MidiEvent& event);
259 void apply_registered_parameter(uint8_t ch, uint16_t param, uint8_t data_msb, uint8_t data_lsb);
260 void apply_configuration_message(uint8_t manager_channel, uint8_t member_count);
261 void release_notes_outside_zones();
263 void apply_manager_message(const
MidiEvent& event,
bool upper);
264 void apply_manager_ump(const
UmpPacket& p,
bool upper);
269 void apply_per_note_pitch_bend(uint8_t ch, uint8_t note,
float semitones);
270 void apply_per_note_timbre(uint8_t ch, uint8_t note,
float timbre);
274 void apply_per_note_management(uint8_t ch, uint8_t note, uint8_t flags);
276 static
float ump_bend_normalised(uint32_t v32);
277 static
std::array<
float, 16> make_member_ranges() {
278 std::array<float, 16> r{};
284 std::array<MpeNoteState, kMaxNotes> notes_{};
285 std::array<float, 16> channel_pitch_bend_{};
286 std::array<float, 16> channel_pressure_{};
287 std::array<float, 16> channel_timbre_{};
290 std::array<float, 16> member_bend_semi_ = make_member_ranges();
295 struct ParameterSelection {
299 uint8_t data_msb = 0;
300 uint8_t data_lsb = 0;
302 std::array<ParameterSelection, 16> selection_{};
303 bool follow_config_messages_ =
true;
305 std::uint64_t refused_note_on_count_ = 0;
306 std::array<MpeNoteState, kMaxNotes> pending_note_offs_{};
307 std::size_t pending_note_off_head_ = 0;
308 std::size_t pending_note_off_count_ = 0;
309 std::optional<uint8_t> assignable_timbre_index_;
std::uint64_t refused_note_on_count() const noexcept
Number of note-ons refused because the generation space was exhausted.
Definition mpe_voice_tracker.hpp:189
const MpeNoteState * find(uint8_t channel, uint8_t note) const
Find the newest active note for channel/note, or nullptr.
bool flush_pending_note_offs()
Retry deferred note-offs in FIFO order.
std::function< void(const MpeNoteState &)> on_pressure
Definition mpe_voice_tracker.hpp:238
static constexpr std::size_t kMaxNotes
Maximum concurrently active notes the tracker can hold.
Definition mpe_voice_tracker.hpp:70
std::optional< uint8_t > assignable_timbre_index() const
Definition mpe_voice_tracker.hpp:148
void set_follow_configuration_messages(bool enabled)
When enabled (the default), process(MidiEvent) follows two Registered Parameter Number messages as th...
Definition mpe_voice_tracker.hpp:127
std::function< void(const MpeNoteState &)> on_pitch_bend
Definition mpe_voice_tracker.hpp:237
bool follows_configuration_messages() const
Definition mpe_voice_tracker.hpp:130
const MpeConfig & config() const
Definition mpe_voice_tracker.hpp:83
std::size_t pending_note_off_count() const noexcept
Number of accepted physical note-offs waiting for a bounded lifecycle sink to make room.
Definition mpe_voice_tracker.hpp:200
void set_manager_bend_range(float semitones)
Set the manager-channel pitch-bend range in semitones (zone-wide bend) for both zones.
const ZoneState & upper_zone_state() const
Definition mpe_voice_tracker.hpp:219
std::function< void(const MpeNoteState &)> on_note_on
Definition mpe_voice_tracker.hpp:235
std::function< void(const MpeNoteState &)> on_note_off
Definition mpe_voice_tracker.hpp:236
std::function< void(const MpeConfig &)> on_config_change
Invoked after an incoming MPE Configuration Message changed config().
Definition mpe_voice_tracker.hpp:135
float manager_bend_range() const
Manager range of the lower zone.
Definition mpe_voice_tracker.hpp:100
std::size_t active_count() const
void set_member_bend_range(float semitones)
Set the member-channel pitch-bend range in semitones (per-note bend) for every channel.
MpeVoiceTracker(MpeConfig config=MpeConfig::standard_lower())
Definition mpe_voice_tracker.hpp:77
bool process(const MidiEvent &event)
Process a single MIDI 1.0 event.
const std::array< MpeNoteState, kMaxNotes > & slots() const
Direct access to the underlying slots (active flag identifies live notes).
Definition mpe_voice_tracker.hpp:209
void set_config(const MpeConfig &cfg)
void set_assignable_timbre_index(std::optional< uint8_t > cc_index)
Bind a MIDI 2.0 Assignable Per-Note Controller index (status 0x10) to per-note timbre.
Definition mpe_voice_tracker.hpp:144
const ZoneState & lower_zone_state() const
Definition mpe_voice_tracker.hpp:218
std::function< void(const MpeNoteState &)> on_timbre
Definition mpe_voice_tracker.hpp:239
float member_bend_range() const
Member-channel range for channel 1 (the first lower-zone member).
Definition mpe_voice_tracker.hpp:92
std::size_t snapshot(MpeNoteState *out, std::size_t max) const
Iterate all active notes.
float member_bend_range(uint8_t channel) const
Member-channel range for one specific channel (0-15).
Definition mpe_voice_tracker.hpp:96
bool process(const UmpPacket &p)
Process a MIDI 2.0 UMP Channel Voice packet.
static constexpr float kDefaultManagerBendSemitones
Default manager-channel pitch-bend range (MPE spec).
Definition mpe_voice_tracker.hpp:75
static constexpr float kDefaultMemberBendSemitones
Default member-channel pitch-bend range (MPE spec).
Definition mpe_voice_tracker.hpp:73
float manager_bend_range(bool upper_zone) const
Manager range of one zone.
Definition mpe_voice_tracker.hpp:104
bool note_generation_exhausted() const noexcept
True once every representable nonzero note generation has been issued.
Definition mpe_voice_tracker.hpp:185
bool advance_note_generation(MpeNoteGeneration next) noexcept
Advance the next generation without issuing it.
std::function< bool(const MpeNoteState *note_off, const MpeNoteState *note_on)> on_note_lifecycle
Transactional note-lifecycle sink.
Definition mpe_voice_tracker.hpp:233
Definition custom_node_events.hpp:26
std::uint64_t MpeNoteGeneration
Stable identity assigned to one accepted MPE note-on generation.
Definition mpe_voice_tracker.hpp:36
Timestamped MIDI event combining a choc::midi::ShortMessage with timing info.
Definition message.hpp:32
static MpeConfig standard_lower(uint8_t members=15)
Definition ump.hpp:379
Per-note state maintained by MpeVoiceTracker.
Definition mpe_voice_tracker.hpp:44
bool detached
True after a UMP Per-Note Management message with the "detachcontrollers" flag landed on this note: s...
Definition mpe_voice_tracker.hpp:60
float timbre
CC 74 (0..1); same value as slide.
Definition mpe_voice_tracker.hpp:51
float pitch_bend_semitones
Current per-note pitch bend in semitones.
Definition mpe_voice_tracker.hpp:49
float pressure
Channel pressure (0..1).
Definition mpe_voice_tracker.hpp:50
uint8_t channel
MPE member channel the note lives on.
Definition mpe_voice_tracker.hpp:46
MpeNoteGeneration note_id
Monotonic generation assigned on note-on (never 0).
Definition mpe_voice_tracker.hpp:52
bool active
Definition mpe_voice_tracker.hpp:45
uint8_t note
MIDI note number (0-127).
Definition mpe_voice_tracker.hpp:47
uint8_t velocity
Note-on velocity (0-127).
Definition mpe_voice_tracker.hpp:48
bool is_upper_zone
true if this note lives in the upper zone
Definition mpe_voice_tracker.hpp:53
Definition mpe_voice_tracker.hpp:213
float timbre
Zone-wide timbre (CC 74).
Definition mpe_voice_tracker.hpp:216
float pitch_bend_semitones
Zone-wide pitch bend.
Definition mpe_voice_tracker.hpp:214
float pressure
Zone-wide pressure.
Definition mpe_voice_tracker.hpp:215