Insert/Redirect refactoring, towards better MIDI support in mixer strip, and
[ardour.git] / libs / ardour / automatable.cc
1 /*
2     Copyright (C) 2001,2007 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 #include <ardour/ardour.h>
21 #include <fstream>
22 #include <inttypes.h>
23 #include <cstdio>
24 #include <errno.h>
25 #include <pbd/error.h>
26 #include <pbd/enumwriter.h>
27 #include <ardour/session.h>
28 #include <ardour/automatable.h>
29
30 #include "i18n.h"
31
32 using namespace std;
33 using namespace ARDOUR;
34 using namespace PBD;
35
36
37 Automatable::Automatable(Session& _session, const string& name)
38         : SessionObject(_session, name)
39         , _last_automation_snapshot(0)
40 {}
41
42 int
43 Automatable::old_set_automation_state (const XMLNode& node)
44 {
45         const XMLProperty *prop;
46                         
47         if ((prop = node.property ("path")) != 0) {
48                 load_automation (prop->value());
49         } else {
50                 warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg;
51         }
52         
53         if ((prop = node.property ("visible")) != 0) {
54                 uint32_t what;
55                 stringstream sstr;
56                 
57                 _visible_parameter_automation.clear ();
58                 
59                 sstr << prop->value();
60                 while (1) {
61                         sstr >> what;
62                         if (sstr.fail()) {
63                                 break;
64                         }
65                         mark_automation_visible (what, true);
66                 }
67         }
68
69         return 0;
70 }
71
72 int
73 Automatable::load_automation (const string& path)
74 {
75         string fullpath;
76
77         if (path[0] == '/') { // legacy
78                 fullpath = path;
79         } else {
80                 fullpath = _session.automation_dir();
81                 fullpath += path;
82         }
83         ifstream in (fullpath.c_str());
84
85         if (!in) {
86                 warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg;
87                 return 1;
88         }
89
90         Glib::Mutex::Lock lm (_automation_lock);
91         set<uint32_t> tosave;
92         _parameter_automation.clear ();
93
94         while (in) {
95                 double when;
96                 double value;
97                 uint32_t port;
98
99                 in >> port;  if (!in) break;
100                 in >> when;  if (!in) goto bad;
101                 in >> value; if (!in) goto bad;
102                 
103                 AutomationList& al = automation_list (port);
104                 al.add (when, value);
105                 tosave.insert (port);
106         }
107         
108         return 0;
109
110   bad:
111         error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg;
112         _parameter_automation.clear ();
113         return -1;
114 }
115
116
117 void
118 Automatable::what_has_automation (set<uint32_t>& s) const
119 {
120         Glib::Mutex::Lock lm (_automation_lock);
121         map<uint32_t,AutomationList*>::const_iterator li;
122         
123         for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
124                 s.insert  ((*li).first);
125         }
126 }
127
128 void
129 Automatable::what_has_visible_automation (set<uint32_t>& s) const
130 {
131         Glib::Mutex::Lock lm (_automation_lock);
132         set<uint32_t>::const_iterator li;
133         
134         for (li = _visible_parameter_automation.begin(); li != _visible_parameter_automation.end(); ++li) {
135                 s.insert  (*li);
136         }
137 }
138 AutomationList&
139 Automatable::automation_list (uint32_t parameter)
140 {
141         AutomationList* al = _parameter_automation[parameter];
142
143         if (al == 0) {
144                 al = _parameter_automation[parameter] = new AutomationList (default_parameter_value (parameter));
145                 /* let derived classes do whatever they need with this */
146                 automation_list_creation_callback (parameter, *al);
147         }
148
149         return *al;
150 }
151
152 string
153 Automatable::describe_parameter (uint32_t which)
154 {
155         /* derived classes will override this */
156         return "";
157 }
158
159 void
160 Automatable::can_automate (uint32_t what)
161 {
162         _can_automate_list.insert (what);
163 }
164
165 void
166 Automatable::mark_automation_visible (uint32_t what, bool yn)
167 {
168         if (yn) {
169                 _visible_parameter_automation.insert (what);
170         } else {
171                 set<uint32_t>::iterator i;
172
173                 if ((i = _visible_parameter_automation.find (what)) != _visible_parameter_automation.end()) {
174                         _visible_parameter_automation.erase (i);
175                 }
176         }
177 }
178
179 bool
180 Automatable::find_next_event (nframes_t now, nframes_t end, ControlEvent& next_event) const
181 {
182         map<uint32_t,AutomationList*>::const_iterator li;       
183         AutomationList::TimeComparator cmp;
184
185         next_event.when = max_frames;
186         
187         for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
188                 
189                 AutomationList::const_iterator i;
190                 const AutomationList& alist (*((*li).second));
191                 ControlEvent cp (now, 0.0f);
192                 
193                 for (i = lower_bound (alist.const_begin(), alist.const_end(), &cp, cmp); i != alist.const_end() && (*i)->when < end; ++i) {
194                         if ((*i)->when > now) {
195                                 break; 
196                         }
197                 }
198                 
199                 if (i != alist.const_end() && (*i)->when < end) {
200                         
201                         if ((*i)->when < next_event.when) {
202                                 next_event.when = (*i)->when;
203                         }
204                 }
205         }
206
207         return next_event.when != max_frames;
208 }
209
210 int
211 Automatable::set_automation_state (const XMLNode& node)
212 {       
213         Glib::Mutex::Lock lm (_automation_lock);
214
215         _parameter_automation.clear ();
216
217         XMLNodeList nlist = node.children();
218         XMLNodeIterator niter;
219
220         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
221                 uint32_t param;
222
223                 if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
224                         error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
225                         continue;
226                 }
227
228                 AutomationList& al = automation_list (param);
229                 if (al.set_state (*(*niter)->children().front())) {
230                         goto bad;
231                 }
232         }
233
234         return 0;
235
236   bad:
237         error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg;
238         _parameter_automation.clear ();
239         return -1;
240 }
241
242 XMLNode&
243 Automatable::get_automation_state ()
244 {
245         Glib::Mutex::Lock lm (_automation_lock);
246         XMLNode* node = new XMLNode (X_("Automation"));
247         string fullpath;
248
249         if (_parameter_automation.empty()) {
250                 return *node;
251         }
252
253         map<uint32_t,AutomationList*>::iterator li;
254         
255         for (li = _parameter_automation.begin(); li != _parameter_automation.end(); ++li) {
256         
257                 XMLNode* child;
258                 
259                 char buf[64];
260                 stringstream str;
261                 snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first);
262                 child = new XMLNode (buf);
263                 child->add_child_nocopy (li->second->get_state ());
264         }
265
266         return *node;
267 }