summaryrefslogtreecommitdiff
path: root/libs/evoral
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2019-07-30 21:17:15 +0200
committerRobin Gareus <robin@gareus.org>2019-07-30 21:17:15 +0200
commit8dbbc195676e15c7d8ce6a17de3d370c90b8184e (patch)
tree8562a7ff5c67f565bf56dc32000eae22b666a452 /libs/evoral
parentbf5da033dcbbe87cb18ae1d727cb4aae6c687db0 (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.cpp35
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;
}