diff options
author | Robin Gareus <robin@gareus.org> | 2019-07-30 21:17:15 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2019-07-30 21:17:15 +0200 |
commit | 8dbbc195676e15c7d8ce6a17de3d370c90b8184e (patch) | |
tree | 8562a7ff5c67f565bf56dc32000eae22b666a452 /libs/evoral | |
parent | bf5da033dcbbe87cb18ae1d727cb4aae6c687db0 (diff) |
Update MIDI Event precedence
A patch-change that is concurrent with a note-on event should be sent
before the given Note-on event.
As follow up: CCs also need to be prioritize to send bank-select first.
see also https://discourse.ardour.org/t/midi-strangeness-patch-setting-and-first-notes/101415
Diffstat (limited to 'libs/evoral')
-rw-r--r-- | libs/evoral/src/Sequence.cpp | 35 |
1 files changed, 19 insertions, 16 deletions
diff --git a/libs/evoral/src/Sequence.cpp b/libs/evoral/src/Sequence.cpp index 99d5d1448c..6db79be6ae 100644 --- a/libs/evoral/src/Sequence.cpp +++ b/libs/evoral/src/Sequence.cpp @@ -238,30 +238,40 @@ Sequence<Time>::const_iterator::choose_next(Time earliest_t) { _type = NIL; - // Next earliest note on + // Next earliest note on, if any if (_note_iter != _seq->notes().end()) { _type = NOTE_ON; earliest_t = (*_note_iter)->time(); } - // Use the next note off iff it's earlier or the same time as the note on - if ((!_active_notes.empty())) { - if (_type == NIL || _active_notes.top()->end_time().to_double() <= earliest_t.to_double()) { - _type = NOTE_OFF; - earliest_t = _active_notes.top()->end_time(); + /* Use the next earliest patch change iff it is earlier or coincident with the note-on. + * A patch-change with the same time-stamp applies to the concurrent note-on */ + if (_patch_change_iter != _seq->patch_changes().end()) { + if (_type == NIL || (*_patch_change_iter)->time() <= earliest_t) { + _type = PATCH_CHANGE; + earliest_t = (*_patch_change_iter)->time(); } } - // Use the next earliest controller iff it's earlier than the note event + /* Use the next earliest controller iff it's earlier or coincident with the note-on + * or patch-change. Bank-select (CC0, CC32) needs to be sent before the PGM. */ if (_control_iter != _control_iters.end() && _control_iter->list && _control_iter->x != DBL_MAX) { - if (_type == NIL || _control_iter->x < earliest_t.to_double()) { + if (_type == NIL || _control_iter->x <= earliest_t.to_double()) { _type = CONTROL; earliest_t = Time(_control_iter->x); } } - // Use the next earliest SysEx iff it's earlier than the controller + /* .. but prefer to send any Note-off first */ + if ((!_active_notes.empty())) { + if (_type == NIL || _active_notes.top()->end_time().to_double() <= earliest_t.to_double()) { + _type = NOTE_OFF; + earliest_t = _active_notes.top()->end_time(); + } + } + + /* SysEx is last, always sent after any other concurrent 3 byte event */ if (_sysex_iter != _seq->sysexes().end()) { if (_type == NIL || (*_sysex_iter)->time() < earliest_t) { _type = SYSEX; @@ -269,13 +279,6 @@ Sequence<Time>::const_iterator::choose_next(Time earliest_t) } } - // Use the next earliest patch change iff it's earlier than the SysEx - if (_patch_change_iter != _seq->patch_changes().end()) { - if (_type == NIL || (*_patch_change_iter)->time() < earliest_t) { - _type = PATCH_CHANGE; - earliest_t = (*_patch_change_iter)->time(); - } - } return earliest_t; } |