Fix out of order event errors on save with overlapping notes.
authorDavid Robillard <d@drobilla.net>
Sat, 15 Nov 2014 02:19:09 +0000 (21:19 -0500)
committerDavid Robillard <d@drobilla.net>
Sat, 15 Nov 2014 02:19:09 +0000 (21:19 -0500)
Another consequence of fuzzy Sequence timing, but if the difference is less
than a tick this should handle things correctly.  If the difference is more
than a tick, something's wrong, and it might be okay to just bump forward
anyway, but I can't reproduce this and it could lead to corruption so I'm
leaving that case noisy.

libs/ardour/smf_source.cc

index c7cd7160f3e64b56fbf2640130a039dd0dabb025..8a865c39578abe4915f1999b5013436f77723df7 100644 (file)
@@ -389,10 +389,22 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
                name().c_str(), ev.id(), ev.time(), ev.size());
               for (size_t i = 0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
 
-       if (ev.time() < _last_ev_time_beats) {
-               warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
-                       << endmsg;
-               return;
+       double time = ev.time();
+       if (time < _last_ev_time_beats) {
+               const double difference = _last_ev_time_beats - time;
+               if (difference / (double)ppqn() < 1.0) {
+                       /* Close enough.  This problem occurs because Sequence is not
+                          actually ordered due to fuzzy time comparison.  I'm pretty sure
+                          this is inherently a bad idea which causes problems all over the
+                          place, but tolerate it here for now anyway. */
+                       time = _last_ev_time_beats;
+               } else {
+                       /* Out of order by more than a tick. */
+                       warning << string_compose(_("Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
+                                                 ev.time(), _last_ev_time_beats, difference, difference / (double)ppqn())
+                               << endmsg;
+                       return;
+               }
        }
 
        Evoral::event_id_t event_id;
@@ -407,13 +419,13 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
                _model->append (ev, event_id);
        }
 
-       _length_beats = max(_length_beats, ev.time());
+       _length_beats = max(_length_beats, time);
 
-       const double delta_time_beats   = ev.time() - _last_ev_time_beats;
+       const double delta_time_beats   = time - _last_ev_time_beats;
        const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
 
        Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
-       _last_ev_time_beats = ev.time();
+       _last_ev_time_beats = time;
        _flags = Source::Flag (_flags & ~Empty);
 }
 
@@ -430,7 +442,8 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, fr
        // for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");
 
        if (ev.time() < _last_ev_time_frames) {
-               warning << string_compose(_("Skipping event with unordered time %1"), ev.time())
+               warning << string_compose(_("Skipping event with unordered frame time %1 < %2"),
+                                         ev.time(), _last_ev_time_frames)
                        << endmsg;
                return;
        }