Fixing LV2_SUPPORT #ifdefs
[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 <cstdio>
21 #include <errno.h>
22
23 #include "pbd/gstdio_compat.h"
24 #include <glibmm/miscutils.h>
25
26 #include "pbd/error.h"
27
28 #include "ardour/amp.h"
29 #include "ardour/automatable.h"
30 #include "ardour/event_type_map.h"
31 #include "ardour/gain_control.h"
32 #include "ardour/monitor_control.h"
33 #include "ardour/midi_track.h"
34 #include "ardour/pan_controllable.h"
35 #include "ardour/pannable.h"
36 #include "ardour/plugin.h"
37 #include "ardour/plugin_insert.h"
38 #include "ardour/record_enable_control.h"
39 #include "ardour/session.h"
40 #ifdef LV2_SUPPORT
41 #include "ardour/uri_map.h"
42 #endif
43 #include "ardour/value_as_string.h"
44
45 #include "pbd/i18n.h"
46
47 using namespace std;
48 using namespace ARDOUR;
49 using namespace PBD;
50
51 const string Automatable::xml_node_name = X_("Automation");
52
53 Automatable::Automatable(Session& session)
54         : _a_session(session)
55 {
56 }
57
58 Automatable::Automatable (const Automatable& other)
59         : ControlSet (other)
60         , _a_session (other._a_session)
61 {
62         Glib::Threads::Mutex::Lock lm (other._control_lock);
63
64         for (Controls::const_iterator i = other._controls.begin(); i != other._controls.end(); ++i) {
65                 boost::shared_ptr<Evoral::Control> ac (control_factory (i->first));
66                 add_control (ac);
67         }
68 }
69
70 Automatable::~Automatable ()
71 {
72         {
73                 Glib::Threads::Mutex::Lock lm (_control_lock);
74
75                 for (Controls::const_iterator li = _controls.begin(); li != _controls.end(); ++li) {
76                         boost::dynamic_pointer_cast<AutomationControl>(li->second)->drop_references ();
77                 }
78         }
79 }
80
81 int
82 Automatable::old_set_automation_state (const XMLNode& node)
83 {
84         XMLProperty const * prop;
85
86         if ((prop = node.property ("path")) != 0) {
87                 load_automation (prop->value());
88         } else {
89                 warning << _("Automation node has no path property") << endmsg;
90         }
91
92         return 0;
93 }
94
95 int
96 Automatable::load_automation (const string& path)
97 {
98         string fullpath;
99
100         if (Glib::path_is_absolute (path)) { // legacy
101                 fullpath = path;
102         } else {
103                 fullpath = _a_session.automation_dir();
104                 fullpath += path;
105         }
106
107         FILE * in = g_fopen (fullpath.c_str (), "rb");
108
109         if (!in) {
110                 warning << string_compose(_("cannot open %2 to load automation data (%3)")
111                                 , fullpath, strerror (errno)) << endmsg;
112                 return 1;
113         }
114
115         Glib::Threads::Mutex::Lock lm (control_lock());
116         set<Evoral::Parameter> tosave;
117         controls().clear ();
118
119         while (!feof(in)) {
120                 double when;
121                 double value;
122                 uint32_t port;
123
124                 if (3 != fscanf (in, "%d %lf %lf", &port, &when, &value)) {
125                         if (feof(in)) {
126                                 break;
127                         }
128                         goto bad;
129                 }
130
131                 Evoral::Parameter param(PluginAutomation, 0, port);
132                 /* FIXME: this is legacy and only used for plugin inserts?  I think? */
133                 boost::shared_ptr<Evoral::Control> c = control (param, true);
134                 c->list()->add (when, value);
135                 tosave.insert (param);
136         }
137         ::fclose (in);
138
139         return 0;
140
141   bad:
142         error << string_compose(_("cannot load automation data from %2"), fullpath) << endmsg;
143         controls().clear ();
144         ::fclose (in);
145         return -1;
146 }
147
148 void
149 Automatable::add_control(boost::shared_ptr<Evoral::Control> ac)
150 {
151         Evoral::Parameter param = ac->parameter();
152
153         boost::shared_ptr<AutomationList> al = boost::dynamic_pointer_cast<AutomationList> (ac->list ());
154
155         boost::shared_ptr<AutomationControl> actl (boost::dynamic_pointer_cast<AutomationControl> (ac));
156
157         if ((!actl || !(actl->flags() & Controllable::NotAutomatable)) && al) {
158                 al->automation_state_changed.connect_same_thread (
159                         _list_connections,
160                         boost::bind (&Automatable::automation_list_automation_state_changed,
161                                      this, ac->parameter(), _1));
162         }
163
164         ControlSet::add_control (ac);
165
166         if ((!actl || !(actl->flags() & Controllable::NotAutomatable)) && al) {
167                 _can_automate_list.insert (param);
168                 automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up
169         }
170 }
171
172 string
173 Automatable::describe_parameter (Evoral::Parameter param)
174 {
175         /* derived classes like PluginInsert should override this */
176
177         if (param == Evoral::Parameter(GainAutomation)) {
178                 return _("Fader");
179         } else if (param.type() == TrimAutomation) {
180                 return _("Trim");
181         } else if (param.type() == MuteAutomation) {
182                 return _("Mute");
183         } else if (param.type() == MidiCCAutomation) {
184                 return string_compose("Controller %1 [%2]", param.id(), int(param.channel()) + 1);
185         } else if (param.type() == MidiPgmChangeAutomation) {
186                 return string_compose("Program [%1]", int(param.channel()) + 1);
187         } else if (param.type() == MidiPitchBenderAutomation) {
188                 return string_compose("Bender [%1]", int(param.channel()) + 1);
189         } else if (param.type() == MidiChannelPressureAutomation) {
190                 return string_compose("Pressure [%1]", int(param.channel()) + 1);
191         } else if (param.type() == MidiNotePressureAutomation) {
192                 return string_compose("PolyPressure [%1]", int(param.channel()) + 1);
193 #ifdef LV2_SUPPORT
194         } else if (param.type() == PluginPropertyAutomation) {
195                 return string_compose("Property %1", URIMap::instance().id_to_uri(param.id()));
196 #endif
197         } else {
198                 return EventTypeMap::instance().to_symbol(param);
199         }
200 }
201
202 void
203 Automatable::can_automate (Evoral::Parameter what)
204 {
205         _can_automate_list.insert (what);
206 }
207
208 /** \a legacy_param is used for loading legacy sessions where an object (IO, Panner)
209  * had a single automation parameter, with it's type implicit.  Derived objects should
210  * pass that type and it will be used for the untyped AutomationList found.
211  */
212 int
213 Automatable::set_automation_xml_state (const XMLNode& node, Evoral::Parameter legacy_param)
214 {
215         Glib::Threads::Mutex::Lock lm (control_lock());
216
217         /* Don't clear controls, since some may be special derived Controllable classes */
218
219         XMLNodeList nlist = node.children();
220         XMLNodeIterator niter;
221
222         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
223
224                 /*if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, &param) != 1) {
225                   error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg;
226                   continue;
227                   }*/
228
229                 if ((*niter)->name() == "AutomationList") {
230
231                         XMLProperty const * id_prop = (*niter)->property("automation-id");
232
233                         Evoral::Parameter param = (id_prop
234                                         ? EventTypeMap::instance().from_symbol(id_prop->value())
235                                         : legacy_param);
236
237                         if (param.type() == NullAutomation) {
238                                 warning << "Automation has null type" << endl;
239                                 continue;
240                         }
241
242                         if (_can_automate_list.find (param) == _can_automate_list.end ()) {
243                                 warning << "Ignored automation data for non-automatable parameter" << endl;
244                                 continue;
245                         }
246
247                         if (!id_prop) {
248                                 warning << "AutomationList node without automation-id property, "
249                                         << "using default: " << EventTypeMap::instance().to_symbol(legacy_param) << endmsg;
250                         }
251
252                         boost::shared_ptr<AutomationControl> existing = automation_control (param);
253
254                         if (existing) {
255                                 existing->alist()->set_state (**niter, 3000);
256                         } else {
257                                 boost::shared_ptr<Evoral::Control> newcontrol = control_factory(param);
258                                 add_control (newcontrol);
259                                 boost::shared_ptr<AutomationList> al (new AutomationList(**niter, param));
260                                 newcontrol->set_list(al);
261                         }
262
263                 } else {
264                         error << "Expected AutomationList node, got '" << (*niter)->name() << "'" << endmsg;
265                 }
266         }
267
268         return 0;
269 }
270
271 XMLNode&
272 Automatable::get_automation_xml_state ()
273 {
274         Glib::Threads::Mutex::Lock lm (control_lock());
275         XMLNode* node = new XMLNode (Automatable::xml_node_name);
276
277         if (controls().empty()) {
278                 return *node;
279         }
280
281         for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
282                 boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(li->second->list());
283                 if (l && !l->empty()) {
284                         node->add_child_nocopy (l->get_state ());
285                 }
286         }
287
288         return *node;
289 }
290
291 void
292 Automatable::set_parameter_automation_state (Evoral::Parameter param, AutoState s)
293 {
294         Glib::Threads::Mutex::Lock lm (control_lock());
295
296         boost::shared_ptr<AutomationControl> c = automation_control (param, true);
297
298         if (c && (s != c->automation_state())) {
299                 c->set_automation_state (s);
300                 _a_session.set_dirty ();
301                 AutomationStateChanged(); /* Emit signal */
302         }
303 }
304
305 AutoState
306 Automatable::get_parameter_automation_state (Evoral::Parameter param)
307 {
308         AutoState result = Off;
309
310         boost::shared_ptr<AutomationControl> c = automation_control(param);
311
312         if (c) {
313                 result = c->automation_state();
314         }
315
316         return result;
317 }
318
319 void
320 Automatable::set_parameter_automation_style (Evoral::Parameter param, AutoStyle s)
321 {
322         Glib::Threads::Mutex::Lock lm (control_lock());
323
324         boost::shared_ptr<AutomationControl> c = automation_control(param, true);
325
326         if (c && (s != c->automation_style())) {
327                 c->set_automation_style (s);
328                 _a_session.set_dirty ();
329         }
330 }
331
332 AutoStyle
333 Automatable::get_parameter_automation_style (Evoral::Parameter param)
334 {
335         Glib::Threads::Mutex::Lock lm (control_lock());
336
337         boost::shared_ptr<Evoral::Control> c = control(param);
338         boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
339
340         if (c) {
341                 return l->automation_style();
342         } else {
343                 return Absolute; // whatever
344         }
345 }
346
347 void
348 Automatable::protect_automation ()
349 {
350         typedef set<Evoral::Parameter> ParameterSet;
351         const ParameterSet& automated_params = what_can_be_automated ();
352
353         for (ParameterSet::const_iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
354
355                 boost::shared_ptr<Evoral::Control> c = control(*i);
356                 boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
357
358                 switch (l->automation_state()) {
359                 case Write:
360                         l->set_automation_state (Off);
361                         break;
362                 case Touch:
363                         l->set_automation_state (Play);
364                         break;
365                 default:
366                         break;
367                 }
368         }
369 }
370
371 void
372 Automatable::transport_located (framepos_t now)
373 {
374         for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
375
376                 boost::shared_ptr<AutomationControl> c
377                                 = boost::dynamic_pointer_cast<AutomationControl>(li->second);
378                 if (c) {
379                         boost::shared_ptr<AutomationList> l
380                                 = boost::dynamic_pointer_cast<AutomationList>(c->list());
381
382                         if (l) {
383                                 l->start_write_pass (now);
384                         }
385                 }
386         }
387 }
388
389 void
390 Automatable::transport_stopped (framepos_t now)
391 {
392         for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
393                 boost::shared_ptr<AutomationControl> c =
394                         boost::dynamic_pointer_cast<AutomationControl>(li->second);
395                 if (!c) {
396                         continue;
397                 }
398
399                 boost::shared_ptr<AutomationList> l =
400                         boost::dynamic_pointer_cast<AutomationList>(c->list());
401                 if (!l) {
402                         continue;
403                 }
404
405                 /* Stop any active touch gesture just before we mark the write pass
406                    as finished.  If we don't do this, the transport can end up stopped with
407                    an AutomationList thinking that a touch is still in progress and,
408                    when the transport is re-started, a touch will magically
409                    be happening without it ever have being started in the usual way.
410                 */
411                 const bool list_did_write = !l->in_new_write_pass ();
412
413                 l->stop_touch (true, now);
414
415                 c->commit_transaction (list_did_write);
416
417                 l->write_pass_finished (now, Config->get_automation_thinning_factor ());
418
419                 if (l->automation_state () == Write) {
420                         l->set_automation_state (Touch);
421                 }
422
423                 if (l->automation_playback ()) {
424                         c->set_value_unchecked (c->list ()->eval (now));
425                 }
426         }
427 }
428
429 boost::shared_ptr<Evoral::Control>
430 Automatable::control_factory(const Evoral::Parameter& param)
431 {
432         Evoral::Control*                  control   = NULL;
433         bool                              make_list = true;
434         ParameterDescriptor               desc(param);
435         boost::shared_ptr<AutomationList> list;
436
437         if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
438                 MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
439                 if (mt) {
440                         control = new MidiTrack::MidiControl(mt, param);
441                         make_list = false;  // No list, this is region "automation"
442                 }
443         } else if (param.type() == PluginAutomation) {
444                 PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
445                 if (pi) {
446                         pi->plugin(0)->get_parameter_descriptor(param.id(), desc);
447                         control = new PluginInsert::PluginControl(pi, param, desc);
448                 } else {
449                         warning << "PluginAutomation for non-Plugin" << endl;
450                 }
451         } else if (param.type() == PluginPropertyAutomation) {
452                 PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
453                 if (pi) {
454                         desc = pi->plugin(0)->get_property_descriptor(param.id());
455                         if (desc.datatype != Variant::NOTHING) {
456                                 if (!Variant::type_is_numeric(desc.datatype)) {
457                                         make_list = false;  // Can't automate non-numeric data yet
458                                 } else {
459                                         list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
460                                 }
461                                 control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
462                         }
463                 } else {
464                         warning << "PluginPropertyAutomation for non-Plugin" << endl;
465                 }
466         } else if (param.type() == GainAutomation) {
467                 control = new GainControl(_a_session, param);
468         } else if (param.type() == TrimAutomation) {
469                 control = new GainControl(_a_session, param);
470         } else if (param.type() == PanAzimuthAutomation || param.type() == PanWidthAutomation || param.type() == PanElevationAutomation) {
471                 Pannable* pannable = dynamic_cast<Pannable*>(this);
472                 if (pannable) {
473                         control = new PanControllable (_a_session, pannable->describe_parameter (param), pannable, param);
474                 } else {
475                         warning << "PanAutomation for non-Pannable" << endl;
476                 }
477         } else if (param.type() == RecEnableAutomation) {
478                 Recordable* re = dynamic_cast<Recordable*> (this);
479                 if (re) {
480                         control = new RecordEnableControl (_a_session, X_("recenable"), *re);
481                 }
482         } else if (param.type() == MonitoringAutomation) {
483                 Monitorable* m = dynamic_cast<Monitorable*>(this);
484                 if (m) {
485                         control = new MonitorControl (_a_session, X_("monitor"), *m);
486                 }
487         } else if (param.type() == SoloAutomation) {
488                 Soloable* s = dynamic_cast<Soloable*>(this);
489                 Muteable* m = dynamic_cast<Muteable*>(this);
490                 if (s && m) {
491                         control = new SoloControl (_a_session, X_("solo"), *s, *m);
492                 }
493         } else if (param.type() == MuteAutomation) {
494                 Muteable* m = dynamic_cast<Muteable*>(this);
495                 if (m) {
496                         control = new MuteControl (_a_session, X_("mute"), *m);
497                 }
498         }
499
500         if (make_list && !list) {
501                 list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
502         }
503
504         if (!control) {
505                 control = new AutomationControl(_a_session, param, desc, list);
506         }
507
508         return boost::shared_ptr<Evoral::Control>(control);
509 }
510
511 boost::shared_ptr<AutomationControl>
512 Automatable::automation_control (const Evoral::Parameter& id, bool create)
513 {
514         return boost::dynamic_pointer_cast<AutomationControl>(Evoral::ControlSet::control(id, create));
515 }
516
517 boost::shared_ptr<const AutomationControl>
518 Automatable::automation_control (const Evoral::Parameter& id) const
519 {
520         return boost::dynamic_pointer_cast<const AutomationControl>(Evoral::ControlSet::control(id));
521 }
522
523 void
524 Automatable::clear_controls ()
525 {
526         _control_connections.drop_connections ();
527         ControlSet::clear_controls ();
528 }
529
530 string
531 Automatable::value_as_string (boost::shared_ptr<const AutomationControl> ac) const
532 {
533         return ARDOUR::value_as_string(ac->desc(), ac->get_value());
534 }
535
536 bool
537 Automatable::find_next_event (double now, double end, Evoral::ControlEvent& next_event, bool only_active) const
538 {
539         Controls::const_iterator li;
540
541         next_event.when = std::numeric_limits<double>::max();
542
543         for (li = _controls.begin(); li != _controls.end(); ++li) {
544                 boost::shared_ptr<AutomationControl> c
545                         = boost::dynamic_pointer_cast<AutomationControl>(li->second);
546
547                 if (only_active && (!c || !c->automation_playback())) {
548                         continue;
549                 }
550
551                 Evoral::ControlList::const_iterator i;
552                 boost::shared_ptr<const Evoral::ControlList> alist (li->second->list());
553                 Evoral::ControlEvent cp (now, 0.0f);
554                 if (!alist) {
555                         continue;
556                 }
557
558                 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
559                      i != alist->end() && (*i)->when < end; ++i) {
560                         if ((*i)->when > now) {
561                                 break;
562                         }
563                 }
564
565                 if (i != alist->end() && (*i)->when < end) {
566                         if ((*i)->when < next_event.when) {
567                                 next_event.when = (*i)->when;
568                         }
569                 }
570         }
571
572         return next_event.when != std::numeric_limits<double>::max();
573 }