Per-region MIDI CC "automation".
[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 <pbd/undo.h>
31 #include <pbd/xml++.h>
32 #include <pbd/statefuldestructible.h> 
33
34 #include <ardour/ardour.h>
35 #include <ardour/parameter.h>
36
37 namespace ARDOUR {
38
39 class Curve;
40
41 struct ControlEvent {
42
43     ControlEvent (double w, double v)
44             : when (w), value (v), coeff (0) { 
45         }
46
47     ControlEvent (const ControlEvent& other) 
48             : when (other.when), value (other.value), coeff (0) {
49                 if (other.coeff) {
50                         create_coeffs();
51                         for (size_t i=0; i < 4; ++i)
52                                 coeff[i] = other.coeff[i];
53                 }
54         }
55
56         ~ControlEvent() { if (coeff) delete[] coeff; }
57
58         void create_coeffs() {
59                 if (!coeff)
60                         coeff = new double[4];
61             
62                 coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0.0;
63         }
64
65     double  when;
66     double  value;
67     double* coeff; ///< double[4] allocated by Curve as needed
68 };
69
70
71 class AutomationList : public PBD::StatefulDestructible
72 {
73   public:
74         typedef std::list<ControlEvent*> EventList;
75         typedef EventList::iterator iterator;
76         typedef EventList::const_iterator const_iterator;
77
78         AutomationList (Parameter id, double min_val, double max_val, double default_val);
79         AutomationList (const XMLNode&, Parameter id);
80         ~AutomationList();
81
82         AutomationList (const AutomationList&);
83         AutomationList (const AutomationList&, double start, double end);
84         AutomationList& operator= (const AutomationList&);
85         bool operator== (const AutomationList&);
86
87         Parameter parameter() const          { return _parameter; }
88         void      set_parameter(Parameter p) { _parameter = p; }
89
90         void freeze();
91         void thaw ();
92
93         EventList::size_type size() const { return _events.size(); }
94         bool empty() const { return _events.empty(); }
95
96         void reset_default (double val) {
97                 _default_value = val;
98         }
99
100         void clear ();
101         void x_scale (double factor);
102         bool extend_to (double);
103         void slide (iterator before, double distance);
104         
105         void reposition_for_rt_add (double when);
106         void rt_add (double when, double value);
107         void add (double when, double value);
108         /* this should be private but old-school automation loading needs it in IO/IOProcessor */
109         void fast_simple_add (double when, double value);
110
111         void reset_range (double start, double end);
112         void erase_range (double start, double end);
113         void erase (iterator);
114         void erase (iterator, iterator);
115         void move_range (iterator start, iterator end, double, double);
116         void modify (iterator, double, double);
117
118         AutomationList* cut (double, double);
119         AutomationList* copy (double, double);
120         void clear (double, double);
121
122         AutomationList* cut (iterator, iterator);
123         AutomationList* copy (iterator, iterator);
124         void clear (iterator, iterator);
125
126         bool paste (AutomationList&, double position, float times);
127
128         void set_automation_state (AutoState);
129         AutoState automation_state() const { return _state; }
130         sigc::signal<void> automation_style_changed;
131
132         void set_automation_style (AutoStyle m);
133         AutoStyle automation_style() const { return _style; }
134         sigc::signal<void> automation_state_changed;
135
136         bool automation_playback() const {
137                 return (_state & Play) || ((_state & Touch) && !_touching);
138         }
139         bool automation_write () const {
140                 return (_state & Write) || ((_state & Touch) && _touching);
141         }
142
143         void start_touch ();
144         void stop_touch ();
145         bool touching() const { return _touching; }
146
147         void set_yrange (double min, double max) {
148                 _min_yval = min;
149                 _max_yval = max;
150         }
151
152         double get_max_y() const { return _max_yval; }
153         double get_min_y() const { return _min_yval; }
154
155         void truncate_end (double length);
156         void truncate_start (double length);
157         
158         iterator begin() { return _events.begin(); }
159         iterator end() { return _events.end(); }
160
161         ControlEvent* back() { return _events.back(); }
162         ControlEvent* front() { return _events.front(); }
163
164         const_iterator const_begin() const { return _events.begin(); }
165         const_iterator const_end() const { return _events.end(); }
166
167         std::pair<AutomationList::iterator,AutomationList::iterator> control_points_adjacent (double when);
168
169         template<class T> void apply_to_points (T& obj, void (T::*method)(const AutomationList&)) {
170                 Glib::Mutex::Lock lm (_lock);
171                 (obj.*method)(*this);
172         }
173         
174         sigc::signal<void> StateChanged;
175
176         XMLNode& get_state(void); 
177         int set_state (const XMLNode &s);
178         XMLNode& state (bool full);
179         XMLNode& serialize_events ();
180
181         void set_max_xval (double);
182         double get_max_xval() const { return _max_xval; }
183
184         double eval (double where) {
185                 Glib::Mutex::Lock lm (_lock);
186                 return unlocked_eval (where);
187         }
188
189         double rt_safe_eval (double where, bool& ok) {
190
191                 Glib::Mutex::Lock lm (_lock, Glib::TRY_LOCK);
192
193                 if ((ok = lm.locked())) {
194                         return unlocked_eval (where);
195                 } else {
196                         return 0.0;
197                 }
198         }
199
200         static inline bool time_comparator (const ControlEvent* a, const ControlEvent* b) { 
201                 return a->when < b->when;
202         }
203         
204         /** Lookup cache for eval functions, range contains equivalent values */
205         struct LookupCache {
206                 LookupCache() : left(-1) {}
207             double left;  /* leftmost x coordinate used when finding "range" */
208             std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
209         };
210         
211         /** Lookup cache for point finding, range contains points between left and right */
212         struct SearchCache {
213                 SearchCache() : left(-1), right(-1) {}
214             double left;  /* leftmost x coordinate used when finding "range" */
215                 double right; /* rightmost x coordinate used when finding "range" */
216             std::pair<AutomationList::const_iterator,AutomationList::const_iterator> range;
217         };
218
219         static sigc::signal<void, AutomationList*> AutomationListCreated;
220
221         const EventList& events() const { return _events; }
222         double default_value() const { return _default_value; }
223
224         // teeny const violations for Curve
225         mutable sigc::signal<void> Dirty;
226         Glib::Mutex& lock() const { return _lock; }
227         LookupCache& lookup_cache() const { return _lookup_cache; }
228         SearchCache& search_cache() const { return _search_cache; }
229         
230         /** Called by locked entry point and various private
231          * locations where we already hold the lock.
232          * 
233          * FIXME: Should this be private?  Curve needs it..
234          */
235         double unlocked_eval (double x) const;
236         
237         bool rt_safe_earliest_event (double start, double end, double& x, double& y) const;
238
239         Curve&       curve()       { return *_curve; }
240         const Curve& curve() const { return *_curve; }
241
242         enum InterpolationStyle {
243                 Discrete,
244                 Linear,
245                 Curved
246         };
247
248         InterpolationStyle interpolation() const { return _interpolation; }
249         void set_interpolation(InterpolationStyle style) { _interpolation = style; }
250
251   private:
252
253         /** Called by unlocked_eval() to handle cases of 3 or more control points.
254          */
255         double multipoint_eval (double x) const; 
256
257         void build_search_cache_if_necessary(double start, double end) const;
258         
259         bool rt_safe_earliest_event_discrete (double start, double end, double& x, double& y) const;
260         bool rt_safe_earliest_event_linear (double start, double end, double& x, double& y) const;
261
262         AutomationList* cut_copy_clear (double, double, int op);
263
264         int deserialize_events (const XMLNode&);
265         
266         void maybe_signal_changed ();
267         void mark_dirty ();
268         void _x_scale (double factor);
269
270         mutable LookupCache _lookup_cache;
271         mutable SearchCache _search_cache;
272         
273         Parameter           _parameter;
274         InterpolationStyle  _interpolation;
275         EventList           _events;
276         mutable Glib::Mutex _lock;
277         int8_t              _frozen;
278         bool                _changed_when_thawed;
279         AutoState           _state;
280         AutoStyle           _style;
281         bool                _touching;
282         bool                _new_touch;
283         double              _max_xval;
284         double              _min_yval;
285         double              _max_yval;
286         double              _default_value;
287         bool                _sort_pending;
288         iterator            _rt_insertion_point;
289         double              _rt_pos;
290
291         Curve* _curve;
292 };
293
294 } // namespace
295
296 #endif /* __ardour_automation_event_h__ */