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