* MidiModel::const_iterator::operator++: added AUTOMATION type
[ardour.git] / libs / ardour / ardour / automation_event.h
1 /*
2     Copyright (C) 2002 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __ardour_automation_event_h__
21 #define __ardour_automation_event_h__
22
23 #include <stdint.h>
24 #include <list>
25 #include <cmath>
26
27 #include <sigc++/signal.h>
28 #include <glibmm/thread.h>
29
30 #include <boost/pool/pool.hpp>
31 #include <boost/pool/pool_alloc.hpp>
32
33 #include <pbd/undo.h>
34 #include <pbd/xml++.h>
35 #include <pbd/statefuldestructible.h> 
36
37 #include <ardour/ardour.h>
38 #include <ardour/parameter.h>
39
40 namespace ARDOUR {
41
42 class Curve;
43
44 struct ControlEvent {
45
46     ControlEvent (double w, double v)
47             : when (w), value (v), coeff (0) { 
48         }
49
50     ControlEvent (const ControlEvent& other) 
51             : when (other.when), value (other.value), coeff (0) {
52                 if (other.coeff) {
53                         create_coeffs();
54                         for (size_t i=0; i < 4; ++i)
55                                 coeff[i] = other.coeff[i];
56                 }
57         }
58
59         ~ControlEvent() { if (coeff) delete[] coeff; }
60
61         void create_coeffs() {
62                 if (!coeff)
63                         coeff = new double[4];
64             
65                 coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
66         }
67
68     double  when;
69     double  value;
70     double* coeff; ///< double[4] allocated by Curve as needed
71 };
72
73 /* automation lists use a pool allocator that does not use a lock and 
74    allocates 8k of new pointers at a time
75 */
76
77 typedef boost::fast_pool_allocator<ControlEvent*,
78         boost::default_user_allocator_new_delete,
79         boost::details::pool::null_mutex,
80         8192> ControlEventAllocator;
81
82 class AutomationList : public PBD::StatefulDestructible
83 {
84   public:
85         typedef std::list<ControlEvent*,ControlEventAllocator> EventList;
86         typedef EventList::iterator iterator;
87         typedef EventList::reverse_iterator reverse_iterator;
88         typedef EventList::const_iterator const_iterator;
89
90         AutomationList (Parameter id, double min_val, double max_val, double default_val);
91         AutomationList (const XMLNode&, Parameter id);
92         ~AutomationList();
93
94         AutomationList (const AutomationList&);
95         AutomationList (const AutomationList&, double start, double end);
96         AutomationList& operator= (const AutomationList&);
97         bool operator== (const AutomationList&);
98
99         const Parameter& parameter() const          { return _parameter; }
100         void             set_parameter(Parameter p) { _parameter = p; }
101
102         void freeze();
103         void thaw ();
104
105         EventList::size_type size() const { return _events.size(); }
106         bool empty() const { return _events.empty(); }
107
108         void reset_default (double val) {
109                 _default_value = val;
110         }
111
112         void clear ();
113         void x_scale (double factor);
114         bool extend_to (double);
115         void slide (iterator before, double distance);
116         
117         void reposition_for_rt_add (double when);
118         void rt_add (double when, double value);
119         void add (double when, double value);
120         /* this should be private but old-school automation loading needs it in IO/IOProcessor */
121         void fast_simple_add (double when, double value);
122
123         void reset_range (double start, double end);
124         void erase_range (double start, double end);
125         void erase (iterator);
126         void erase (iterator, iterator);
127         void move_range (iterator start, iterator end, double, double);
128         void modify (iterator, double, double);
129
130         AutomationList* cut (double, double);
131         AutomationList* copy (double, double);
132         void clear (double, double);
133
134         AutomationList* cut (iterator, iterator);
135         AutomationList* copy (iterator, iterator);
136         void clear (iterator, iterator);
137
138         bool paste (AutomationList&, double position, float times);
139
140         void set_automation_state (AutoState);
141         AutoState automation_state() const { return _state; }
142         sigc::signal<void> automation_style_changed;
143
144         void set_automation_style (AutoStyle m);
145         AutoStyle automation_style() const { return _style; }
146         sigc::signal<void> automation_state_changed;
147
148         bool automation_playback() const {
149                 return (_state & Play) || ((_state & Touch) && !_touching);
150         }
151         bool automation_write () const {
152                 return (_state & Write) || ((_state & Touch) && _touching);
153         }
154
155         void start_touch ();
156         void stop_touch ();
157         bool touching() const { return _touching; }
158
159         void set_yrange (double min, double max) {
160                 _min_yval = min;
161                 _max_yval = max;
162         }
163
164         double get_max_y() const { return _max_yval; }
165         double get_min_y() const { return _min_yval; }
166
167         void truncate_end (double length);
168         void truncate_start (double length);
169         
170         iterator begin() { return _events.begin(); }
171         iterator end() { return _events.end(); }
172
173         ControlEvent* back() { return _events.back(); }
174         ControlEvent* front() { return _events.front(); }
175
176         const_iterator const_begin() const { return _events.begin(); }
177         const_iterator const_end() const { return _events.end(); }
178
179         std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
180
181         template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
182                 Glib::Mutex::Lock lm (_lock);
183                 (obj.*method)(*this);
184         }
185         
186         sigc::signal<void> StateChanged;
187
188         XMLNode& get_state(void); 
189         int set_state (const XMLNode &s);
190         XMLNode& state (bool full);
191         XMLNode& serialize_events ();
192
193         void set_max_xval (double);
194         double get_max_xval() const { return _max_xval; }
195
196         double eval (double where) {
197                 Glib::Mutex::Lock lm (_lock);
198                 return unlocked_eval (where);
199         }
200
201         double rt_safe_eval (double where, bool& ok) {
202
203                 Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
204
205                 if ((ok = lm.locked())) {
206                         return unlocked_eval (where);
207                 } else {
208                         return 0.0;
209                 }
210         }
211
212         static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) { 
213                 return a->when < b->when;
214         }
215         
216         /** Lookup cache for eval functions, range contains equivalent values */
217         struct LookupCache {
218                 LookupCache() : left(-1) {}
219             double left;  /* leftmost x coordinate used when finding "range" */
220             std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
221         };
222         
223         /** Lookup cache for point finding, range contains points between left and right */
224         struct SearchCache {
225                 SearchCache() : left(-1), right(-1) {}
226             double left;  /* leftmost x coordinate used when finding "range" */
227                 double right; /* rightmost x coordinate used when finding "range" */
228             std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
229         };
230
231         static sigc::signal<void, AutomationList*> AutomationListCreated;
232
233         const EventList& events() const { return _events; }
234         double default_value() const { return _default_value; }
235
236         // teeny const violations for Curve
237         mutable sigc::signal<void> Dirty;
238         Glib::Mutex& lock() const { return _lock; }
239         LookupCache& lookup_cache() const { return _lookup_cache; }
240         SearchCache& search_cache() const { return _search_cache; }
241
242         /** Called by locked entry point and various private
243          * locations where we already hold the lock.
244          * 
245          * FIXME: Should this be private?  Curve needs it..
246          */
247         double unlocked_eval (double x) const;
248         
249         bool rt_safe_earliest_event (double start, double end, double& x, double& y, bool start_inclusive=false) const;
250         bool rt_safe_earliest_event_unlocked (double start, double end, double& x, double& y, bool start_inclusive=false) const;
251
252         Curve&       curve()       { return *_curve; }
253         const Curve& curve() const { return *_curve; }
254
255         enum InterpolationStyle {
256                 Discrete,
257                 Linear,
258                 Curved
259         };
260
261         InterpolationStyle interpolation() const { return _interpolation; }
262         void set_interpolation(InterpolationStyle style) { _interpolation = style; }
263
264   private:
265
266         /** Called by unlocked_eval() to handle cases of 3 or more control points.
267          */
268         double multipoint_eval (double x) const; 
269
270         void build_search_cache_if_necessary(double start, double end) const;
271         
272         bool rt_safe_earliest_event_discrete_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
273         bool rt_safe_earliest_event_linear_unlocked (double start, double end, double& x, double& y, bool inclusive) const;
274
275         AutomationList* cut_copy_clear (double, double, int op);
276
277         int deserialize_events (const XMLNode&);
278         
279         void maybe_signal_changed ();
280         void mark_dirty ();
281         void _x_scale (double factor);
282
283         mutable LookupCache _lookup_cache;
284         mutable SearchCache _search_cache;
285         
286         Parameter           _parameter;
287         InterpolationStyle  _interpolation;
288         EventList           _events;
289         mutable Glib::Mutex _lock;
290         int8_t              _frozen;
291         bool                _changed_when_thawed;
292         AutoState           _state;
293         AutoStyle           _style;
294         bool                _touching;
295         bool                _new_touch;
296         double              _max_xval;
297         double              _min_yval;
298         double              _max_yval;
299         double              _default_value;
300         bool                _sort_pending;
301         iterator            _rt_insertion_point;
302         double              _rt_pos;
303
304         Curve* _curve;
305 };
306
307 } // namespace
308
309 #endif /* __ardour_automation_event_h__ */