fix (?) behaviour when punching into automation write mode while the transport is...
[ardour.git] / libs / evoral / evoral / ControlList.hpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 David Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  *
5  * Evoral is free software; you can redistribute it and/or modify it under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2 of the License, or (at your option) any later
8  * version.
9  *
10  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #ifndef EVORAL_CONTROL_LIST_HPP
20 #define EVORAL_CONTROL_LIST_HPP
21
22 #include <cassert>
23 #include <list>
24 #include <boost/pool/pool.hpp>
25 #include <boost/pool/pool_alloc.hpp>
26 #include <glibmm/threads.h>
27 #include "pbd/signals.h"
28 #include "evoral/types.hpp"
29 #include "evoral/Range.hpp"
30 #include "evoral/Parameter.hpp"
31
32 namespace Evoral {
33
34 class Curve;
35
36 /** A single event (time-stamped value) for a control
37  */
38 class ControlEvent {
39 public:
40         ControlEvent (double w, double v)
41                 : when (w), value (v), coeff (0)
42         {}
43
44         ControlEvent (const ControlEvent& other)
45                 : when (other.when), value (other.value), coeff (0)
46         {
47                 if (other.coeff) {
48                         create_coeffs();
49                         for (size_t i = 0; i < 4; ++i)
50                                 coeff[i] = other.coeff[i];
51                 }
52         }
53
54         ~ControlEvent() { if (coeff) delete[] coeff; }
55
56         void create_coeffs() {
57                 if (!coeff)
58                         coeff = new double[4];
59
60                 coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
61         }
62
63         double  when;
64         double  value;
65         double* coeff; ///< double[4] allocated by Curve as needed
66 };
67
68 /** A list (sequence) of time-stamped values for a control
69  */
70 class ControlList
71 {
72 public:
73         typedef std::list<ControlEvent*> EventList;
74         typedef EventList::iterator iterator;
75         typedef EventList::reverse_iterator reverse_iterator;
76         typedef EventList::const_iterator const_iterator;
77         typedef EventList::const_reverse_iterator const_reverse_iterator;
78
79         ControlList (const Parameter& id);
80         ControlList (const ControlList&);
81         ControlList (const ControlList&, double start, double end);
82         virtual ~ControlList();
83
84         virtual boost::shared_ptr<ControlList> create(Parameter id);
85
86         void dump (std::ostream&);
87
88         ControlList& operator= (const ControlList&);
89         bool operator== (const ControlList&);
90         void copy_events (const ControlList&);
91
92         virtual void freeze();
93         virtual void thaw ();
94         bool frozen() const { return _frozen; }
95
96         const Parameter& parameter() const                 { return _parameter; }
97         void             set_parameter(const Parameter& p) { _parameter = p; }
98
99         EventList::size_type size() const { return _events.size(); }
100         double length() const {                 
101                 Glib::Threads::Mutex::Lock lm (_lock);
102                 return _events.empty() ? 0.0 : _events.back()->when;
103         }
104         bool empty() const { return _events.empty(); }
105
106         void reset_default (double val) {
107                 _default_value = val;
108         }
109
110         void clear ();
111         void x_scale (double factor);
112         bool extend_to (double);
113         void slide (iterator before, double distance);
114         void shift (double before, double distance);
115
116         virtual bool clamp_value (double& /*when*/, double& /*value*/) const { return true; }
117
118         virtual void add (double when, double value);
119         void fast_simple_add (double when, double value);
120
121         void erase_range (double start, double end);
122         void erase (iterator);
123         void erase (iterator, iterator);
124         void erase (double, double);
125         bool move_ranges (std::list< RangeMove<double> > const &);
126         void modify (iterator, double, double);
127
128         void thin ();
129
130         boost::shared_ptr<ControlList> cut (double, double);
131         boost::shared_ptr<ControlList> copy (double, double);
132         void clear (double, double);
133
134         bool paste (ControlList&, double position, float times);
135
136         void set_yrange (double min, double max) {
137                 _min_yval = min;
138                 _max_yval = max;
139         }
140
141         double get_max_y() const { return _max_yval; }
142         double get_min_y() const { return _min_yval; }
143
144         void truncate_end (double length);
145         void truncate_start (double length);
146
147         iterator            begin()       { return _events.begin(); }
148         const_iterator      begin() const { return _events.begin(); }
149         iterator            end()         { return _events.end(); }
150         const_iterator      end()   const { return _events.end(); }
151         reverse_iterator            rbegin()       { return _events.rbegin(); }
152         const_reverse_iterator      rbegin() const { return _events.rbegin(); }
153         reverse_iterator            rend()         { return _events.rend(); }
154         const_reverse_iterator      rend()   const { return _events.rend(); }
155         ControlEvent*       back()        { return _events.back(); }
156         const ControlEvent* back()  const { return _events.back(); }
157         ControlEvent*       front()       { return _events.front(); }
158         const ControlEvent* front() const { return _events.front(); }
159
160         std::pair<ControlList::iterator,ControlList::iterator> control_points_adjacent (double when);
161
162         template<class T> void apply_to_points (T& obj, void (T::*method)(const ControlList&)) {
163                 Glib::Threads::Mutex::Lock lm (_lock);
164                 (obj.*method)(*this);
165         }
166
167         double eval (double where) {
168                 Glib::Threads::Mutex::Lock lm (_lock);
169                 return unlocked_eval (where);
170         }
171
172         double rt_safe_eval (double where, bool& ok) {
173
174                 Glib::Threads::Mutex::Lock lm (_lock, Glib::Threads::TRY_LOCK);
175
176                 if ((ok = lm.locked())) {
177                         return unlocked_eval (where);
178                 } else {
179                         return 0.0;
180                 }
181         }
182
183         static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) {
184                 return a->when < b->when;
185         }
186
187         /** Lookup cache for eval functions, range contains equivalent values */
188         struct LookupCache {
189                 LookupCache() : left(-1) {}
190                 double left;  /* leftmost x coordinate used when finding "range" */
191                 std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
192         };
193
194         /** Lookup cache for point finding, range contains points after left */
195         struct SearchCache {
196                 SearchCache () : left(-1) {}
197                 double left;  /* leftmost x coordinate used when finding "first" */
198                 ControlList::const_iterator first;
199         };
200
201         const EventList& events() const { return _events; }
202         double default_value() const { return _parameter.normal(); }
203
204         // FIXME: const violations for Curve
205         Glib::Threads::Mutex& lock()         const { return _lock; }
206         LookupCache& lookup_cache() const { return _lookup_cache; }
207         SearchCache& search_cache() const { return _search_cache; }
208
209         /** Called by locked entry point and various private
210          * locations where we already hold the lock.
211          *
212          * FIXME: Should this be private?  Curve needs it..
213          */
214         double unlocked_eval (double x) const;
215
216         bool rt_safe_earliest_event (double start, double& x, double& y, bool start_inclusive=false) const;
217         bool rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool start_inclusive=false) const;
218         bool rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const;
219         bool rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const;
220
221         void create_curve();
222         void destroy_curve();
223
224         Curve&       curve()       { assert(_curve); return *_curve; }
225         const Curve& curve() const { assert(_curve); return *_curve; }
226
227         void mark_dirty () const;
228
229         enum InterpolationStyle {
230                 Discrete,
231                 Linear,
232                 Curved
233         };
234
235         InterpolationStyle interpolation() const { return _interpolation; }
236         void set_interpolation (InterpolationStyle);
237
238         virtual bool touching() const { return false; }
239         virtual bool writing() const { return false; }
240         virtual bool touch_enabled() const { return false; }
241         void start_write_pass (double time);
242         void write_pass_finished (double when);
243         void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
244         bool in_write_pass () const;
245
246         /** Emitted when mark_dirty() is called on this object */
247         mutable PBD::Signal0<void> Dirty;
248         /** Emitted when our interpolation style changes */
249         PBD::Signal1<void, InterpolationStyle> InterpolationChanged;
250
251         static void set_thinning_factor (double d);
252         static double thinning_factor() { return _thinning_factor; }
253
254         bool operator!= (ControlList const &) const;
255
256         void invalidate_insert_iterator ();
257
258 protected:
259
260         /** Called by unlocked_eval() to handle cases of 3 or more control points. */
261         double multipoint_eval (double x) const;
262
263         void build_search_cache_if_necessary (double start) const;
264
265         boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
266         bool erase_range_internal (double start, double end, EventList &);
267
268         virtual void maybe_signal_changed ();
269
270         void _x_scale (double factor);
271
272         mutable LookupCache   _lookup_cache;
273         mutable SearchCache   _search_cache;
274
275         Parameter             _parameter;
276         InterpolationStyle    _interpolation;
277         EventList             _events;
278         mutable Glib::Threads::Mutex   _lock;
279         int8_t                _frozen;
280         bool                  _changed_when_thawed;
281         double                _min_yval;
282         double                _max_yval;
283         double                _default_value;
284         bool                  _sort_pending;
285
286         Curve* _curve;
287
288         static double _thinning_factor;
289
290   private:
291     iterator   most_recent_insert_iterator;
292     double     insert_position;
293     bool       new_write_pass;
294     bool       did_write_during_pass;
295     bool       _in_write_pass;
296     void unlocked_invalidate_insert_iterator ();
297     void add_guard_point (double when);
298 };
299
300 } // namespace Evoral
301
302 #endif // EVORAL_CONTROL_LIST_HPP
303