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