add new sigc++2 directory
[ardour.git] / libs / ardour / ardour / automation_event.h
index 007bad7259052240f5d8019962c5de64859bd776..18190aa9b6e08f4f6e4034c835eeb17419031a0b 100644 (file)
 #include <sigc++/signal.h>
 #include <glibmm/thread.h>
 
+#include <boost/pool/pool.hpp>
+#include <boost/pool/pool_alloc.hpp>
+
 #include <pbd/undo.h>
 #include <pbd/xml++.h>
 #include <pbd/statefuldestructible.h> 
 
 #include <ardour/ardour.h>
+#include <ardour/parameter.h>
 
 namespace ARDOUR {
-       
+
+class Curve;
+
 struct ControlEvent {
-    double when;
-    double value;
-    
+
     ControlEvent (double w, double v)
-           : when (w), value (v) { }
+           : when (w), value (v), coeff (0) { 
+       }
+
     ControlEvent (const ControlEvent& other) 
-           : when (other.when), value (other.value) {}
+           : when (other.when), value (other.value), coeff (0) {
+               if (other.coeff) {
+                       create_coeffs();
+                       for (size_t i=0; i < 4; ++i)
+                               coeff[i] = other.coeff[i];
+               }
+       }
 
-    virtual ~ControlEvent() {}
-    
-//    bool operator==(const ControlEvent& other) {
-//         return value == other.value && when == other.when;
-//    }
+       ~ControlEvent() { if (coeff) delete[] coeff; }
+
+       void create_coeffs() {
+               if (!coeff)
+                       coeff = new double[4];
+           
+               coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
+       }
 
+    double  when;
+    double  value;
+    double* coeff; ///< double[4] allocated by Curve as needed
 };
 
+/* automation lists use a pool allocator that does not use a lock and 
+   allocates 8k of new pointers at a time
+*/
+
+typedef boost::fast_pool_allocator<ControlEvent*,
+       boost::default_user_allocator_new_delete,
+       boost::details::pool::null_mutex,
+       8192> ControlEventAllocator;
+
 class AutomationList : public PBD::StatefulDestructible
 {
   public:
-       typedef std::list<ControlEvent*> AutomationEventList;
-       typedef AutomationEventList::iterator iterator;
-       typedef AutomationEventList::const_iterator const_iterator;
+       typedef std::list<ControlEvent*,ControlEventAllocator> EventList;
+       typedef EventList::iterator iterator;
+       typedef EventList::reverse_iterator reverse_iterator;
+       typedef EventList::const_iterator const_iterator;
 
-       AutomationList (double default_value);
-       AutomationList (const XMLNode&);
+       AutomationList (Parameter id, double min_val, double max_val, double default_val);
+       AutomationList (const XMLNode&, Parameter id);
        ~AutomationList();
 
        AutomationList (const AutomationList&);
@@ -68,14 +96,17 @@ class AutomationList : public PBD::StatefulDestructible
        AutomationList& operator= (const AutomationList&);
        bool operator== (const AutomationList&);
 
+       const Parameter& parameter() const          { return _parameter; }
+       void             set_parameter(Parameter p) { _parameter = p; }
+
        void freeze();
        void thaw ();
 
-       AutomationEventList::size_type size() const { return events.size(); }
-       bool empty() const { return events.empty(); }
+       EventList::size_type size() const { return _events.size(); }
+       bool empty() const { return _events.empty(); }
 
        void reset_default (double val) {
-               default_value = val;
+               _default_value = val;
        }
 
        void clear ();
@@ -86,7 +117,7 @@ class AutomationList : public PBD::StatefulDestructible
        void reposition_for_rt_add (double when);
        void rt_add (double when, double value);
        void add (double when, double value);
-       /* this should be private but old-school automation loading needs it in IO/Redirect */
+       /* this should be private but old-school automation loading needs it in IO/IOProcessor */
        void fast_simple_add (double when, double value);
 
        void reset_range (double start, double end);
@@ -111,13 +142,13 @@ class AutomationList : public PBD::StatefulDestructible
        sigc::signal<void> automation_style_changed;
 
        void set_automation_style (AutoStyle m);
-        AutoStyle automation_style() const { return _style; }
+       AutoStyle automation_style() const { return _style; }
        sigc::signal<void> automation_state_changed;
 
-       bool automation_playback() {
+       bool automation_playback() const {
                return (_state & Play) || ((_state & Touch) && !_touching);
        }
-       bool automation_write () {
+       bool automation_write () const {
                return (_state & Write) || ((_state & Touch) && _touching);
        }
 
@@ -126,32 +157,32 @@ class AutomationList : public PBD::StatefulDestructible
        bool touching() const { return _touching; }
 
        void set_yrange (double min, double max) {
-               min_yval = min;
-               max_yval = max;
+               _min_yval = min;
+               _max_yval = max;
        }
 
-       double get_max_y() const { return max_yval; }
-       double get_min_y() const { return min_yval; }
+       double get_max_y() const { return _max_yval; }
+       double get_min_y() const { return _min_yval; }
 
        void truncate_end (double length);
        void truncate_start (double length);
        
-       iterator begin() { return events.begin(); }
-       iterator end() { return events.end(); }
+       iterator begin() { return _events.begin(); }
+       iterator end() { return _events.end(); }
 
-       ControlEvent* back() { return events.back(); }
-       ControlEvent* front() { return events.front(); }
+       ControlEvent* back() { return _events.back(); }
+       ControlEvent* front() { return _events.front(); }
 
-       const_iterator const_begin() const { return events.begin(); }
-       const_iterator const_end() const { return events.end(); }
+       const_iterator const_begin() const { return _events.begin(); }
+       const_iterator const_end() const { return _events.end(); }
 
        std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
 
        template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
-               Glib::Mutex::Lock lm (lock);
+               Glib::Mutex::Lock lm (_lock);
                (obj.*method)(*this);
        }
-
+       
        sigc::signal<void> StateChanged;
 
        XMLNode& get_state(void); 
@@ -160,16 +191,16 @@ class AutomationList : public PBD::StatefulDestructible
        XMLNode& serialize_events ();
 
        void set_max_xval (double);
-       double get_max_xval() const { return max_xval; }
+       double get_max_xval() const { return _max_xval; }
 
        double eval (double where) {
-               Glib::Mutex::Lock lm (lock);
+               Glib::Mutex::Lock lm (_lock);
                return unlocked_eval (where);
        }
 
        double rt_safe_eval (double where, bool& ok) {
 
-               Glib::Mutex::Lock lm (lock, Glib::TRY_LOCK);
+               Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
 
                if ((ok = lm.locked())) {
                        return unlocked_eval (where);
@@ -178,70 +209,99 @@ class AutomationList : public PBD::StatefulDestructible
                }
        }
 
-       struct TimeComparator {
-               bool operator() (const ControlEvent* a, const ControlEvent* b) { 
-                       return a->when < b->when;
-               }
-       };
-
-        static sigc::signal<void, AutomationList*> AutomationListCreated;
-
-  protected:
-
-       AutomationEventList events;
-       mutable Glib::Mutex lock;
-       int8_t  _frozen;
-       bool    changed_when_thawed;
-       bool   _dirty;
-
+       static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) { 
+               return a->when < b->when;
+       }
+       
+       /** Lookup cache for eval functions, range contains equivalent values */
        struct LookupCache {
+               LookupCache() : left(-1) {}
            double left;  /* leftmost x coordinate used when finding "range" */
-           std::pair<AutomationList::iterator,AutomationList::iterator> range;
+           std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
+       };
+       
+       /** Lookup cache for point finding, range contains points between left and right */
+       struct SearchCache {
+               SearchCache() : left(-1), right(-1) {}
+           double left;  /* leftmost x coordinate used when finding "range" */
+               double right; /* rightmost x coordinate used when finding "range" */
+           std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
        };
 
-       LookupCache lookup_cache;
-
-       AutoState  _state;
-       AutoStyle  _style;
-       bool  _touching;
-       bool  _new_touch;
-       double max_xval;
-       double min_yval;
-       double max_yval;
-       double default_value;
-       bool   sort_pending;
+       static sigc::signal<void, AutomationList*> AutomationListCreated;
 
-       iterator rt_insertion_point;
-       double   rt_pos;
+       const EventList& events() const { return _events; }
+       double default_value() const { return _default_value; }
 
-       void maybe_signal_changed ();
-       void mark_dirty ();
-       void _x_scale (double factor);
+       // teeny const violations for Curve
+       mutable sigc::signal<void> Dirty;
+       Glib::Mutex& lock() const { return _lock; }
+       LookupCache& lookup_cache() const { return _lookup_cache; }
+       SearchCache& search_cache() const { return _search_cache; }
 
-       /* called by type-specific unlocked_eval() to handle
-          common case of 0, 1 or 2 control points.
-       */
+       /** Called by locked entry point and various private
+        * locations where we already hold the lock.
+        * 
+        * FIXME: Should this be private?  Curve needs it..
+        */
+       double unlocked_eval (double x) const;
+       
+       bool rt_safe_earliest_event (double start, double end, double& x, double& y, bool start_inclusive=false) const;
+       bool rt_safe_earliest_event_unlocked (double start, double end, double& x, double& y, bool start_inclusive=false) const;
 
-       double shared_eval (double x);
+       Curve&       curve()       { return *_curve; }
+       const Curve& curve() const { return *_curve; }
 
-       /* called by shared_eval() to handle any case of
-          3 or more control points.
-       */
+       enum InterpolationStyle {
+               Discrete,
+               Linear,
+               Curved
+       };
 
-       virtual double multipoint_eval (double x); 
+       InterpolationStyle interpolation() const { return _interpolation; }
+       void set_interpolation(InterpolationStyle style) { _interpolation = style; }
 
-       /* called by locked entry point and various private
-          locations where we already hold the lock.
-       */
+  private:
 
-       virtual double unlocked_eval (double where);
+       /** Called by unlocked_eval() to handle cases of 3 or more control points.
+        */
+       double multipoint_eval (double x) const; 
 
-       virtual ControlEvent* point_factory (double,double) const;
-       virtual ControlEvent* point_factory (const ControlEvent&) const;
+       void build_search_cache_if_necessary(double start, double end) const;
+       
+       bool rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
+       bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
 
        AutomationList* cut_copy_clear (double, double, int op);
 
        int deserialize_events (const XMLNode&);
+       
+       void maybe_signal_changed ();
+       void mark_dirty ();
+       void _x_scale (double factor);
+
+       mutable LookupCache _lookup_cache;
+       mutable SearchCache _search_cache;
+       
+       Parameter           _parameter;
+       InterpolationStyle  _interpolation;
+       EventList           _events;
+       mutable Glib::Mutex _lock;
+       int8_t              _frozen;
+       bool                _changed_when_thawed;
+       AutoState           _state;
+       AutoStyle           _style;
+       bool                _touching;
+       bool                _new_touch;
+       double              _max_xval;
+       double              _min_yval;
+       double              _max_yval;
+       double              _default_value;
+       bool                _sort_pending;
+       iterator            _rt_insertion_point;
+       double              _rt_pos;
+
+       Curve* _curve;
 };
 
 } // namespace