Remove separate ControlList min/max/default, use ParameterDescriptor.
[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 <stdint.h>
25
26 #include <boost/pool/pool.hpp>
27 #include <boost/pool/pool_alloc.hpp>
28
29 #include <glibmm/threads.h>
30
31 #include "pbd/signals.h"
32
33 #include "evoral/visibility.h"
34 #include "evoral/Range.hpp"
35 #include "evoral/Parameter.hpp"
36 #include "evoral/ParameterDescriptor.hpp"
37
38 namespace Evoral {
39
40 class Curve;
41 class TypeMap;
42
43 /** A single event (time-stamped value) for a control
44  */
45 class LIBEVORAL_API ControlEvent {
46 public:
47         ControlEvent (double w, double v)
48                 : when (w), value (v), coeff (0)
49         {}
50
51         ControlEvent (const ControlEvent& other)
52                 : when (other.when), value (other.value), coeff (0)
53         {
54                 if (other.coeff) {
55                         create_coeffs();
56                         for (size_t i = 0; i < 4; ++i)
57                                 coeff[i] = other.coeff[i];
58                 }
59         }
60
61         ~ControlEvent() { if (coeff) delete[] coeff; }
62
63         void create_coeffs() {
64                 if (!coeff)
65                         coeff = new double[4];
66
67                 coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
68         }
69
70         double  when;
71         double  value;
72         double* coeff; ///< double[4] allocated by Curve as needed
73 };
74
75 /** A list (sequence) of time-stamped values for a control
76  */
77 class LIBEVORAL_API ControlList
78 {
79 public:
80         typedef std::list<ControlEvent*> EventList;
81         typedef EventList::iterator iterator;
82         typedef EventList::reverse_iterator reverse_iterator;
83         typedef EventList::const_iterator const_iterator;
84         typedef EventList::const_reverse_iterator const_reverse_iterator;
85
86         ControlList (const Parameter& id, const ParameterDescriptor& desc);
87         ControlList (const ControlList&);
88         ControlList (const ControlList&, double start, double end);
89         virtual ~ControlList();
90
91         virtual boost::shared_ptr<ControlList> create(const Parameter& id, const ParameterDescriptor& desc);
92
93         void dump (std::ostream&);
94
95         ControlList& operator= (const ControlList&);
96         bool operator== (const ControlList&);
97         void copy_events (const ControlList&);
98
99         virtual void freeze();
100         virtual void thaw ();
101         bool frozen() const { return _frozen; }
102
103         const Parameter& parameter() const                 { return _parameter; }
104         void             set_parameter(const Parameter& p) { _parameter = p; }
105
106         const ParameterDescriptor& descriptor() const                           { return _desc; }
107         void                       set_descriptor(const ParameterDescriptor& d) { _desc = d; }
108
109         EventList::size_type size() const { return _events.size(); }
110         double length() const {
111                 Glib::Threads::RWLock::ReaderLock lm (_lock);
112                 return _events.empty() ? 0.0 : _events.back()->when;
113         }
114         bool empty() const { return _events.empty(); }
115
116         void clear ();
117         void x_scale (double factor);
118         bool extend_to (double);
119         void slide (iterator before, double distance);
120         void shift (double before, double distance);
121
122         void y_transform (boost::function<double(double)> callback);
123         void list_merge (ControlList const& other, boost::function<double(double, double)> callback);
124
125         /** add automation events
126          * @param when absolute time in samples
127          * @param value parameter value
128          * @param with_guards if true, add guard-points
129          * @param with_initial if true, add an initial point if the list is empty
130          */
131         virtual void add (double when, double value, bool with_guards=true, bool with_initial=true);
132
133         virtual bool editor_add (double when, double value, bool with_guard);
134
135         /* to be used only for loading pre-sorted data from saved state */
136         void fast_simple_add (double when, double value);
137
138         void erase_range (double start, double end);
139         void erase (iterator);
140         void erase (iterator, iterator);
141         void erase (double, double);
142         bool move_ranges (std::list< RangeMove<double> > const &);
143         void modify (iterator, double, double);
144
145         /** Thin the number of events in this list.
146          *
147          * The thinning factor corresponds to the area of a triangle computed
148          * between three points in the list (time-difference * value-difference).
149          * If the area is large, it indicates significant non-linearity between
150          * the points.
151          *
152          * Time is measured in samples, value is usually normalized to 0..1.
153          *
154          * During automation recording we thin the recorded points using this
155          * value.  If a point is sufficiently co-linear with its neighbours (as
156          * defined by the area of the triangle formed by three of them), we will
157          * not include it in the list.  The larger the value, the more points are
158          * excluded, so this effectively measures the amount of thinning to be
159          * done.
160          *
161          * @param thinning_factor area-size (default: 20)
162          */
163         void thin (double thinning_factor);
164
165         boost::shared_ptr<ControlList> cut (double, double);
166         boost::shared_ptr<ControlList> copy (double, double);
167
168         /** remove all automation events between the given time range
169          * @param start start of range (inclusive) in audio samples
170          * @param end end of range (inclusive) in audio samples
171          */
172         void clear (double start, double end);
173
174         bool paste (const ControlList&, double position);
175
176         /** truncate the event list after the given time
177          * @param last_coordinate last event to include
178          */
179         void truncate_end (double last_coordinate);
180         /** truncate the event list to the given time
181          * @param overall_length overall length
182          */
183         void truncate_start (double overall_length);
184
185         iterator            begin()       { return _events.begin(); }
186         const_iterator      begin() const { return _events.begin(); }
187         iterator            end()         { return _events.end(); }
188         const_iterator      end()   const { return _events.end(); }
189         reverse_iterator            rbegin()       { return _events.rbegin(); }
190         const_reverse_iterator      rbegin() const { return _events.rbegin(); }
191         reverse_iterator            rend()         { return _events.rend(); }
192         const_reverse_iterator      rend()   const { return _events.rend(); }
193         ControlEvent*       back()        { return _events.back(); }
194         const ControlEvent* back()  const { return _events.back(); }
195         ControlEvent*       front()       { return _events.front(); }
196         const ControlEvent* front() const { return _events.front(); }
197
198         std::pair<ControlList::iterator,ControlList::iterator> control_points_adjacent (double when);
199
200         template<class T> void apply_to_points (T& obj, void (T::*method)(const ControlList&)) {
201                 Glib::Threads::RWLock::WriterLock lm (_lock);
202                 (obj.*method)(*this);
203         }
204
205         /** query value at given time (takes a read-lock, not safe while writing automation)
206          * @param where absolute time in samples
207          * @returns parameter value
208          */
209         double eval (double where) const {
210                 Glib::Threads::RWLock::ReaderLock lm (_lock);
211                 return unlocked_eval (where);
212         }
213
214         /** realtime safe version of eval, may fail if read-lock cannot be taken
215          * @param where absolute time in samples
216          * @param ok boolean reference if returned value is valid
217          * @returns parameter value
218          */
219         double rt_safe_eval (double where, bool& ok) const {
220
221                 Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
222
223                 if ((ok = lm.locked())) {
224                         return unlocked_eval (where);
225                 } else {
226                         return 0.0;
227                 }
228         }
229
230         static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) {
231                 return a->when < b->when;
232         }
233
234         /** Lookup cache for eval functions, range contains equivalent values */
235         struct LookupCache {
236                 LookupCache() : left(-1) {}
237                 double left;  /* leftmost x coordinate used when finding "range" */
238                 std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
239         };
240
241         /** Lookup cache for point finding, range contains points after left */
242         struct SearchCache {
243                 SearchCache () : left(-1) {}
244                 double left;  /* leftmost x coordinate used when finding "first" */
245                 ControlList::const_iterator first;
246         };
247
248         const EventList& events() const { return _events; }
249
250         // FIXME: const violations for Curve
251         Glib::Threads::RWLock& lock()       const { return _lock; }
252         LookupCache& lookup_cache() const { return _lookup_cache; }
253         SearchCache& search_cache() const { return _search_cache; }
254
255         /** Called by locked entry point and various private
256          * locations where we already hold the lock.
257          *
258          * FIXME: Should this be private?  Curve needs it..
259          */
260         double unlocked_eval (double x) const;
261
262         bool rt_safe_earliest_event (double start, double& x, double& y, bool start_inclusive=false) const;
263         bool rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool start_inclusive=false) const;
264         bool rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const;
265         bool rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const;
266
267         void create_curve();
268         void destroy_curve();
269
270         Curve&       curve()       { assert(_curve); return *_curve; }
271         const Curve& curve() const { assert(_curve); return *_curve; }
272
273         void mark_dirty () const;
274
275         enum InterpolationStyle {
276                 Discrete,
277                 Linear,
278                 Curved
279         };
280
281         /** query interpolation style of the automation data
282          * @returns Interpolation Style
283          */
284         InterpolationStyle interpolation() const { return _interpolation; }
285
286         /** set the interpolation style of the automation data
287          * @param is interpolation style
288          */
289         void set_interpolation (InterpolationStyle is);
290
291         virtual bool touching() const { return false; }
292         virtual bool writing() const { return false; }
293         virtual bool touch_enabled() const { return false; }
294         void start_write_pass (double when);
295         void write_pass_finished (double when, double thinning_factor=0.0);
296         void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
297         bool in_write_pass () const;
298         bool in_new_write_pass () { return new_write_pass; }
299
300         /** Emitted when mark_dirty() is called on this object */
301         mutable PBD::Signal0<void> Dirty;
302         /** Emitted when our interpolation style changes */
303         PBD::Signal1<void, InterpolationStyle> InterpolationChanged;
304
305         bool operator!= (ControlList const &) const;
306
307         void invalidate_insert_iterator ();
308
309 protected:
310
311         /** Called by unlocked_eval() to handle cases of 3 or more control points. */
312         double multipoint_eval (double x) const;
313
314         void build_search_cache_if_necessary (double start) const;
315
316         boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
317         bool erase_range_internal (double start, double end, EventList &);
318
319         void     maybe_add_insert_guard (double when);
320         iterator erase_from_iterator_to (iterator iter, double when);
321         bool     maybe_insert_straight_line (double when, double value);
322
323         virtual void maybe_signal_changed ();
324
325         void _x_scale (double factor);
326
327         mutable LookupCache   _lookup_cache;
328         mutable SearchCache   _search_cache;
329
330         mutable Glib::Threads::RWLock _lock;
331
332         Parameter             _parameter;
333         ParameterDescriptor   _desc;
334         InterpolationStyle    _interpolation;
335         EventList             _events;
336         int8_t                _frozen;
337         bool                  _changed_when_thawed;
338         bool                  _sort_pending;
339
340         Curve* _curve;
341
342   private:
343     iterator   most_recent_insert_iterator;
344     double     insert_position;
345     bool       new_write_pass;
346     bool       did_write_during_pass;
347     bool       _in_write_pass;
348     void unlocked_invalidate_insert_iterator ();
349     void add_guard_point (double when);
350 };
351
352 } // namespace Evoral
353
354 #endif // EVORAL_CONTROL_LIST_HPP
355