Add automatable click-free bypass/enable feature to a-eq
[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 #include "ardour/uri_map.h"
41 #include "ardour/value_as_string.h"
42
43 #include "pbd/i18n.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48
49 const string Automatable::xml_node_name = X_("Automation");
50
51 Automatable::Automatable(Session& session)
52         : _a_session(session)
53 {
54 }
55
56 Automatable::Automatable (const Automatable& other)
57         : ControlSet (other)
58         , _a_session (other._a_session)
59 {
60         Glib::Threads::Mutex::Lock lm (other._control_lock);
61
62         for (Controls::const_iterator i = other._controls.begin(); i != other._controls.end(); ++i) {
63                 boost::shared_ptr<Evoral::Control> ac (control_factory (i->first));
64                 add_control (ac);
65         }
66 }
67
68 Automatable::~Automatable ()
69 {
70         {
71                 Glib::Threads::Mutex::Lock lm (_control_lock);
72
73                 for (Controls::const_iterator li = _controls.begin(); li != _controls.end(); ++li) {
74                         boost::dynamic_pointer_cast<AutomationControl>(li->second)->drop_references ();
75                 }
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 && !l->empty()) {
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::set_parameter_automation_style (Evoral::Parameter param, AutoStyle s)
319 {
320         Glib::Threads::Mutex::Lock lm (control_lock());
321
322         boost::shared_ptr<AutomationControl> c = automation_control(param, true);
323
324         if (c && (s != c->automation_style())) {
325                 c->set_automation_style (s);
326                 _a_session.set_dirty ();
327         }
328 }
329
330 AutoStyle
331 Automatable::get_parameter_automation_style (Evoral::Parameter param)
332 {
333         Glib::Threads::Mutex::Lock lm (control_lock());
334
335         boost::shared_ptr<Evoral::Control> c = control(param);
336         boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
337
338         if (c) {
339                 return l->automation_style();
340         } else {
341                 return Absolute; // whatever
342         }
343 }
344
345 void
346 Automatable::protect_automation ()
347 {
348         typedef set<Evoral::Parameter> ParameterSet;
349         const ParameterSet& automated_params = what_can_be_automated ();
350
351         for (ParameterSet::const_iterator i = automated_params.begin(); i != automated_params.end(); ++i) {
352
353                 boost::shared_ptr<Evoral::Control> c = control(*i);
354                 boost::shared_ptr<AutomationList> l = boost::dynamic_pointer_cast<AutomationList>(c->list());
355
356                 switch (l->automation_state()) {
357                 case Write:
358                         l->set_automation_state (Off);
359                         break;
360                 case Touch:
361                         l->set_automation_state (Play);
362                         break;
363                 default:
364                         break;
365                 }
366         }
367 }
368
369 void
370 Automatable::transport_located (framepos_t now)
371 {
372         for (Controls::iterator li = controls().begin(); li != controls().end(); ++li) {
373
374                 boost::shared_ptr<AutomationControl> c
375                                 = boost::dynamic_pointer_cast<AutomationControl>(li->second);
376                 if (c) {
377                         boost::shared_ptr<AutomationList> l
378                                 = boost::dynamic_pointer_cast<AutomationList>(c->list());
379
380                         if (l) {
381                                 l->start_write_pass (now);
382                         }
383                 }
384         }
385 }
386
387 void
388 Automatable::transport_stopped (framepos_t now)
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 (true, 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 boost::shared_ptr<Evoral::Control>
428 Automatable::control_factory(const Evoral::Parameter& param)
429 {
430         Evoral::Control*                  control   = NULL;
431         bool                              make_list = true;
432         ParameterDescriptor               desc(param);
433         boost::shared_ptr<AutomationList> list;
434
435         if (param.type() >= MidiCCAutomation && param.type() <= MidiChannelPressureAutomation) {
436                 MidiTrack* mt = dynamic_cast<MidiTrack*>(this);
437                 if (mt) {
438                         control = new MidiTrack::MidiControl(mt, param);
439                         make_list = false;  // No list, this is region "automation"
440                 }
441         } else if (param.type() == PluginAutomation) {
442                 PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
443                 if (pi) {
444                         pi->plugin(0)->get_parameter_descriptor(param.id(), desc);
445                         control = new PluginInsert::PluginControl(pi, param, desc);
446                 } else {
447                         warning << "PluginAutomation for non-Plugin" << endl;
448                 }
449         } else if (param.type() == PluginPropertyAutomation) {
450                 PluginInsert* pi = dynamic_cast<PluginInsert*>(this);
451                 if (pi) {
452                         desc = pi->plugin(0)->get_property_descriptor(param.id());
453                         if (desc.datatype != Variant::NOTHING) {
454                                 if (!Variant::type_is_numeric(desc.datatype)) {
455                                         make_list = false;  // Can't automate non-numeric data yet
456                                 } else {
457                                         list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
458                                 }
459                                 control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
460                         }
461                 } else {
462                         warning << "PluginPropertyAutomation for non-Plugin" << endl;
463                 }
464         } else if (param.type() == GainAutomation) {
465                 control = new GainControl(_a_session, param);
466         } else if (param.type() == TrimAutomation) {
467                 control = new GainControl(_a_session, param);
468         } else if (param.type() == PanAzimuthAutomation || param.type() == PanWidthAutomation || param.type() == PanElevationAutomation) {
469                 Pannable* pannable = dynamic_cast<Pannable*>(this);
470                 if (pannable) {
471                         control = new PanControllable (_a_session, pannable->describe_parameter (param), pannable, param);
472                 } else {
473                         warning << "PanAutomation for non-Pannable" << endl;
474                 }
475         } else if (param.type() == RecEnableAutomation) {
476                 Recordable* re = dynamic_cast<Recordable*> (this);
477                 if (re) {
478                         control = new RecordEnableControl (_a_session, X_("recenable"), *re);
479                 }
480         } else if (param.type() == MonitoringAutomation) {
481                 Monitorable* m = dynamic_cast<Monitorable*>(this);
482                 if (m) {
483                         control = new MonitorControl (_a_session, X_("monitor"), *m);
484                 }
485         } else if (param.type() == SoloAutomation) {
486                 Soloable* s = dynamic_cast<Soloable*>(this);
487                 Muteable* m = dynamic_cast<Muteable*>(this);
488                 if (s && m) {
489                         control = new SoloControl (_a_session, X_("solo"), *s, *m);
490                 }
491         } else if (param.type() == MuteAutomation) {
492                 Muteable* m = dynamic_cast<Muteable*>(this);
493                 if (m) {
494                         control = new MuteControl (_a_session, X_("mute"), *m);
495                 }
496         }
497
498         if (make_list && !list) {
499                 list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
500         }
501
502         if (!control) {
503                 control = new AutomationControl(_a_session, param, desc, list);
504         }
505
506         return boost::shared_ptr<Evoral::Control>(control);
507 }
508
509 boost::shared_ptr<AutomationControl>
510 Automatable::automation_control (const Evoral::Parameter& id, bool create)
511 {
512         return boost::dynamic_pointer_cast<AutomationControl>(Evoral::ControlSet::control(id, create));
513 }
514
515 boost::shared_ptr<const AutomationControl>
516 Automatable::automation_control (const Evoral::Parameter& id) const
517 {
518         return boost::dynamic_pointer_cast<const AutomationControl>(Evoral::ControlSet::control(id));
519 }
520
521 void
522 Automatable::clear_controls ()
523 {
524         _control_connections.drop_connections ();
525         ControlSet::clear_controls ();
526 }
527
528 string
529 Automatable::value_as_string (boost::shared_ptr<const AutomationControl> ac) const
530 {
531         return ARDOUR::value_as_string(ac->desc(), ac->get_value());
532 }
533
534 bool
535 Automatable::find_next_event (double now, double end, Evoral::ControlEvent& next_event, bool only_active) const
536 {
537         Controls::const_iterator li;
538
539         next_event.when = std::numeric_limits<double>::max();
540
541         for (li = _controls.begin(); li != _controls.end(); ++li) {
542                 boost::shared_ptr<AutomationControl> c
543                         = boost::dynamic_pointer_cast<AutomationControl>(li->second);
544
545                 if (only_active && (!c || !c->automation_playback())) {
546                         continue;
547                 }
548
549                 Evoral::ControlList::const_iterator i;
550                 boost::shared_ptr<const Evoral::ControlList> alist (li->second->list());
551                 Evoral::ControlEvent cp (now, 0.0f);
552                 if (!alist) {
553                         continue;
554                 }
555
556                 for (i = lower_bound (alist->begin(), alist->end(), &cp, Evoral::ControlList::time_comparator);
557                      i != alist->end() && (*i)->when < end; ++i) {
558                         if ((*i)->when > now) {
559                                 break;
560                         }
561                 }
562
563                 if (i != alist->end() && (*i)->when < end) {
564                         if ((*i)->when < next_event.when) {
565                                 next_event.when = (*i)->when;
566                         }
567                 }
568         }
569
570         return next_event.when != std::numeric_limits<double>::max();
571 }