Add infrastructure to merge ControlLists
authorRobin Gareus <robin@gareus.org>
Wed, 14 Jun 2017 00:38:32 +0000 (02:38 +0200)
committerRobin Gareus <robin@gareus.org>
Wed, 14 Jun 2017 00:40:09 +0000 (02:40 +0200)
libs/evoral/evoral/ControlList.hpp
libs/evoral/src/ControlList.cpp

index 515067de04a2698e57dd5113d83e083ee2230823..109124162b314ee3bf29b1c786cb15df9c92f0c9 100644 (file)
@@ -124,6 +124,7 @@ public:
        void shift (double before, double distance);
 
        void y_transform (boost::function<double(double)> callback);
+       void list_merge (ControlList const& other, boost::function<double(double, double)> callback);
 
        /** add automation events
         * @param when absolute time in samples
@@ -217,7 +218,7 @@ public:
         * @param where absolute time in samples
         * @returns parameter value
         */
-       double eval (double where) {
+       double eval (double where) const {
                Glib::Threads::RWLock::ReaderLock lm (_lock);
                return unlocked_eval (where);
        }
index 92234a6ea7a84fdcd8f12e8c6cda80038fa62c1d..0ec9cad8149b7b0165f91bd35dc7afc4439336a9 100644 (file)
@@ -263,6 +263,52 @@ ControlList::y_transform (boost::function<double(double)> callback)
        maybe_signal_changed ();
 }
 
+void
+ControlList::list_merge (ControlList const& other, boost::function<double(double, double)> callback)
+{
+       {
+               Glib::Threads::RWLock::WriterLock lm (_lock);
+               EventList nel;
+               /* First scale existing events, copy into a new list.
+                * The original list is needed later to interpolate
+                * for new events only present in the master list.
+                */
+               for (iterator i = _events.begin(); i != _events.end(); ++i) {
+                       float val = callback ((*i)->value, other.eval ((*i)->when));
+                       nel.push_back (new ControlEvent ((*i)->when , val));
+               }
+               /* Now add events which are only present in the master-list. */
+               const EventList& evl (other.events());
+               for (const_iterator i = evl.begin(); i != evl.end(); ++i) {
+                       bool found = false;
+                       // TODO: optimize, remember last matching iterator (lists are sorted)
+                       for (iterator j = _events.begin(); j != _events.end(); ++j) {
+                               if ((*i)->when == (*j)->when) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       /* skip events that have already been merge in the first pass */
+                       if (found) {
+                               continue;
+                       }
+                       float val = callback (unlocked_eval ((*i)->when), (*i)->value);
+                       nel.push_back (new ControlEvent ((*i)->when, val));
+               }
+               nel.sort (event_time_less_than);
+
+               for (EventList::iterator x = _events.begin(); x != _events.end(); ++x) {
+                       delete (*x);
+               }
+               _events.clear ();
+               _events = nel;
+
+               unlocked_invalidate_insert_iterator ();
+               mark_dirty ();
+       }
+       maybe_signal_changed ();
+}
+
 void
 ControlList::_x_scale (double factor)
 {