attempt to handle poly-pressure (polyphonic aftertouch) similarly to other MIDI messages
[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 reset_default (double val) {
117                 _default_value = val;
118         }
119
120         void clear ();
121         void x_scale (double factor);
122         bool extend_to (double);
123         void slide (iterator before, double distance);
124         void shift (double before, double distance);
125
126         /** add automation events
127          * @param when absolute time in samples
128          * @param value parameter value
129          * @param with_guards if true, add guard-points
130          * @param with_initial if true, add an initial point if the list is empty
131          */
132         virtual void add (double when, double value, bool with_guards=true, bool with_initial=true);
133
134         virtual bool editor_add (double when, double value, bool with_guard);
135
136         /* to be used only for loading pre-sorted data from saved state */
137         void fast_simple_add (double when, double value);
138
139         void erase_range (double start, double end);
140         void erase (iterator);
141         void erase (iterator, iterator);
142         void erase (double, double);
143         bool move_ranges (std::list< RangeMove<double> > const &);
144         void modify (iterator, double, double);
145
146         /** Thin the number of events in this list.
147          *
148          * The thinning factor corresponds to the area of a triangle computed
149          * between three points in the list (time-difference * value-difference).
150          * If the area is large, it indicates significant non-linearity between
151          * the points.
152          *
153          * Time is measured in samples, value is usually normalized to 0..1.
154          *
155          * During automation recording we thin the recorded points using this
156          * value.  If a point is sufficiently co-linear with its neighbours (as
157          * defined by the area of the triangle formed by three of them), we will
158          * not include it in the list.  The larger the value, the more points are
159          * excluded, so this effectively measures the amount of thinning to be
160          * done.
161          *
162          * @param thinning_factor area-size (default: 20)
163          */
164         void thin (double thinning_factor);
165
166         boost::shared_ptr<ControlList> cut (double, double);
167         boost::shared_ptr<ControlList> copy (double, double);
168
169         /** remove all automation events between the given time range
170          * @param start start of range (inclusive) in audio samples
171          * @param end end of range (inclusive) in audio samples
172          */
173         void clear (double start, double end);
174
175         bool paste (const ControlList&, double position, float times);
176
177         void set_yrange (double min, double max) {
178                 _min_yval = min;
179                 _max_yval = max;
180         }
181
182         double get_max_y() const { return _max_yval; }
183         double get_min_y() const { return _min_yval; }
184
185         /** truncate the event list after the given time
186          * @param last_coordinate last event to include
187          */
188         void truncate_end (double last_coordinate);
189         /** truncate the event list to the given time
190          * @param overall_length overall length
191          */
192         void truncate_start (double overall_length);
193
194         iterator            begin()       { return _events.begin(); }
195         const_iterator      begin() const { return _events.begin(); }
196         iterator            end()         { return _events.end(); }
197         const_iterator      end()   const { return _events.end(); }
198         reverse_iterator            rbegin()       { return _events.rbegin(); }
199         const_reverse_iterator      rbegin() const { return _events.rbegin(); }
200         reverse_iterator            rend()         { return _events.rend(); }
201         const_reverse_iterator      rend()   const { return _events.rend(); }
202         ControlEvent*       back()        { return _events.back(); }
203         const ControlEvent* back()  const { return _events.back(); }
204         ControlEvent*       front()       { return _events.front(); }
205         const ControlEvent* front() const { return _events.front(); }
206
207         std::pair<ControlList::iterator,ControlList::iterator> control_points_adjacent (double when);
208
209         template<class T> void apply_to_points (T& obj, void (T::*method)(const ControlList&)) {
210                 Glib::Threads::RWLock::WriterLock lm (_lock);
211                 (obj.*method)(*this);
212         }
213
214         /** query value at given time (takes a read-lock, not safe while writing automation)
215          * @param where absolute time in samples
216          * @returns parameter value
217          */
218         double eval (double where) {
219                 Glib::Threads::RWLock::ReaderLock lm (_lock);
220                 return unlocked_eval (where);
221         }
222
223         /** realtime safe version of eval, may fail if read-lock cannot be taken
224          * @param where absolute time in samples
225          * @param ok boolean reference if returned value is valid
226          * @returns parameter value
227          */
228         double rt_safe_eval (double where, bool& ok) {
229
230                 Glib::Threads::RWLock::ReaderLock lm (_lock, Glib::Threads::TRY_LOCK);
231
232                 if ((ok = lm.locked())) {
233                         return unlocked_eval (where);
234                 } else {
235                         return 0.0;
236                 }
237         }
238
239         static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) {
240                 return a->when < b->when;
241         }
242
243         /** Lookup cache for eval functions, range contains equivalent values */
244         struct LookupCache {
245                 LookupCache() : left(-1) {}
246                 double left;  /* leftmost x coordinate used when finding "range" */
247                 std::pair<ControlList::const_iterator,ControlList::const_iterator> range;
248         };
249
250         /** Lookup cache for point finding, range contains points after left */
251         struct SearchCache {
252                 SearchCache () : left(-1) {}
253                 double left;  /* leftmost x coordinate used when finding "first" */
254                 ControlList::const_iterator first;
255         };
256
257         const EventList& events() const { return _events; }
258         double default_value() const { return _default_value; }
259
260         // FIXME: const violations for Curve
261         Glib::Threads::RWLock& lock()       const { return _lock; }
262         LookupCache& lookup_cache() const { return _lookup_cache; }
263         SearchCache& search_cache() const { return _search_cache; }
264
265         /** Called by locked entry point and various private
266          * locations where we already hold the lock.
267          *
268          * FIXME: Should this be private?  Curve needs it..
269          */
270         double unlocked_eval (double x) const;
271
272         bool rt_safe_earliest_event (double start, double& x, double& y, bool start_inclusive=false) const;
273         bool rt_safe_earliest_event_unlocked (double start, double& x, double& y, bool start_inclusive=false) const;
274         bool rt_safe_earliest_event_linear_unlocked (double start, double& x, double& y, bool inclusive) const;
275         bool rt_safe_earliest_event_discrete_unlocked (double start, double& x, double& y, bool inclusive) const;
276
277         void create_curve();
278         void destroy_curve();
279
280         Curve&       curve()       { assert(_curve); return *_curve; }
281         const Curve& curve() const { assert(_curve); return *_curve; }
282
283         void mark_dirty () const;
284
285         enum InterpolationStyle {
286                 Discrete,
287                 Linear,
288                 Curved
289         };
290
291         /** query interpolation style of the automation data
292          * @returns Interpolation Style
293          */
294         InterpolationStyle interpolation() const { return _interpolation; }
295
296         /** set the interpolation style of the automation data
297          * @param is interpolation style
298          */
299         void set_interpolation (InterpolationStyle is);
300
301         virtual bool touching() const { return false; }
302         virtual bool writing() const { return false; }
303         virtual bool touch_enabled() const { return false; }
304         void start_write_pass (double when);
305         void write_pass_finished (double when, double thinning_factor=0.0);
306         void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
307         bool in_write_pass () const;
308         bool in_new_write_pass () { return new_write_pass; }
309
310         /** Emitted when mark_dirty() is called on this object */
311         mutable PBD::Signal0<void> Dirty;
312         /** Emitted when our interpolation style changes */
313         PBD::Signal1<void, InterpolationStyle> InterpolationChanged;
314
315         bool operator!= (ControlList const &) const;
316
317         void invalidate_insert_iterator ();
318
319 protected:
320
321         /** Called by unlocked_eval() to handle cases of 3 or more control points. */
322         double multipoint_eval (double x) const;
323
324         void build_search_cache_if_necessary (double start) const;
325
326         boost::shared_ptr<ControlList> cut_copy_clear (double, double, int op);
327         bool erase_range_internal (double start, double end, EventList &);
328
329         void     maybe_add_insert_guard (double when);
330         iterator erase_from_iterator_to (iterator iter, double when);
331         bool     maybe_insert_straight_line (double when, double value);
332
333         virtual void maybe_signal_changed ();
334
335         void _x_scale (double factor);
336
337         mutable LookupCache   _lookup_cache;
338         mutable SearchCache   _search_cache;
339
340         mutable Glib::Threads::RWLock _lock;
341
342         Parameter             _parameter;
343         ParameterDescriptor   _desc;
344         InterpolationStyle    _interpolation;
345         EventList             _events;
346         int8_t                _frozen;
347         bool                  _changed_when_thawed;
348         double                _min_yval;
349         double                _max_yval;
350         double                _default_value;
351         bool                  _sort_pending;
352
353         Curve* _curve;
354
355   private:
356     iterator   most_recent_insert_iterator;
357     double     insert_position;
358     bool       new_write_pass;
359     bool       did_write_during_pass;
360     bool       _in_write_pass;
361     void unlocked_invalidate_insert_iterator ();
362     void add_guard_point (double when);
363 };
364
365 } // namespace Evoral
366
367 #endif // EVORAL_CONTROL_LIST_HPP
368