enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / libs / ardour / route_group.cc
1 /*
2     Copyright (C) 2000-2016 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 <inttypes.h>
21
22 #include <algorithm>
23
24 #include "pbd/error.h"
25 #include "pbd/enumwriter.h"
26 #include "pbd/strsplit.h"
27 #include "pbd/debug.h"
28
29 #include "ardour/amp.h"
30 #include "ardour/audio_track.h"
31 #include "ardour/debug.h"
32 #include "ardour/monitor_control.h"
33 #include "ardour/route.h"
34 #include "ardour/route_group.h"
35 #include "ardour/session.h"
36 #include "ardour/vca.h"
37 #include "ardour/vca_manager.h"
38
39 #include "pbd/i18n.h"
40
41 using namespace ARDOUR;
42 using namespace PBD;
43 using namespace std;
44
45 namespace ARDOUR {
46         namespace Properties {
47                 PropertyDescriptor<bool> active;
48                 PropertyDescriptor<bool> group_relative;
49                 PropertyDescriptor<bool> group_gain;
50                 PropertyDescriptor<bool> group_mute;
51                 PropertyDescriptor<bool> group_solo;
52                 PropertyDescriptor<bool> group_recenable;
53                 PropertyDescriptor<bool> group_select;
54                 PropertyDescriptor<bool> group_route_active;
55                 PropertyDescriptor<bool> group_color;
56                 PropertyDescriptor<bool> group_monitoring;
57                 PropertyDescriptor<int32_t> group_master_number;
58         }
59 }
60
61 void
62 RouteGroup::make_property_quarks ()
63 {
64         Properties::active.property_id = g_quark_from_static_string (X_("active"));
65         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n",      Properties::active.property_id));
66
67         Properties::group_relative.property_id = g_quark_from_static_string (X_("relative"));
68         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n",    Properties::group_relative.property_id));
69         Properties::group_gain.property_id = g_quark_from_static_string (X_("gain"));
70         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n",        Properties::group_gain.property_id));
71         Properties::group_mute.property_id = g_quark_from_static_string (X_("mute"));
72         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n",        Properties::group_mute.property_id));
73         Properties::group_solo.property_id = g_quark_from_static_string (X_("solo"));
74         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n",        Properties::group_solo.property_id));
75         Properties::group_recenable.property_id = g_quark_from_static_string (X_("recenable"));
76         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n",   Properties::group_recenable.property_id));
77         Properties::group_select.property_id = g_quark_from_static_string (X_("select"));
78         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n",      Properties::group_select.property_id));
79         Properties::group_route_active.property_id = g_quark_from_static_string (X_("route-active"));
80         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for route-active = %1\n", Properties::group_route_active.property_id));
81         Properties::group_color.property_id = g_quark_from_static_string (X_("color"));
82         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for color = %1\n", Properties::group_color.property_id));
83         Properties::group_monitoring.property_id = g_quark_from_static_string (X_("monitoring"));
84         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for monitoring = %1\n", Properties::group_monitoring.property_id));
85         Properties::group_master_number.property_id = g_quark_from_static_string (X_("group-master-number"));
86         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for group-master-number = %1\n", Properties::group_master_number.property_id));
87 }
88
89 #define ROUTE_GROUP_DEFAULT_PROPERTIES  _relative (Properties::group_relative, true) \
90         , _active (Properties::active, true) \
91         , _hidden (Properties::hidden, false) \
92         , _gain (Properties::group_gain, true) \
93         , _mute (Properties::group_mute, true) \
94         , _solo (Properties::group_solo, true) \
95         , _recenable (Properties::group_recenable, true) \
96         , _select (Properties::group_select, true) \
97         , _route_active (Properties::group_route_active, true) \
98         , _color (Properties::group_color, true) \
99         , _monitoring (Properties::group_monitoring, true) \
100         , _group_master_number (Properties::group_master_number, -1)
101
102 RouteGroup::RouteGroup (Session& s, const string &n)
103         : SessionObject (s, n)
104         , routes (new RouteList)
105         , ROUTE_GROUP_DEFAULT_PROPERTIES
106         , _solo_group (new ControlGroup (SoloAutomation))
107         , _mute_group (new ControlGroup (MuteAutomation))
108         , _rec_enable_group (new ControlGroup (RecEnableAutomation))
109         , _gain_group (new GainControlGroup ())
110         , _monitoring_group (new ControlGroup (MonitoringAutomation))
111 {
112         _xml_node_name = X_("RouteGroup");
113
114         add_property (_relative);
115         add_property (_active);
116         add_property (_hidden);
117         add_property (_gain);
118         add_property (_mute);
119         add_property (_solo);
120         add_property (_recenable);
121         add_property (_select);
122         add_property (_route_active);
123         add_property (_color);
124         add_property (_monitoring);
125         add_property (_group_master_number);
126 }
127
128 RouteGroup::~RouteGroup ()
129 {
130         _solo_group->clear ();
131         _mute_group->clear ();
132         _gain_group->clear ();
133         _rec_enable_group->clear ();
134         _monitoring_group->clear ();
135
136         boost::shared_ptr<VCA> vca (group_master.lock());
137
138         for (RouteList::iterator i = routes->begin(); i != routes->end();) {
139                 RouteList::iterator tmp = i;
140                 ++tmp;
141
142                 (*i)->set_route_group (0);
143
144                 if (vca) {
145                         (*i)->unassign (vca);
146                 }
147
148                 i = tmp;
149         }
150 }
151
152 /** Add a route to a group.  Adding a route which is already in the group is allowed; nothing will happen.
153  *  @param r Route to add.
154  */
155 int
156 RouteGroup::add (boost::shared_ptr<Route> r)
157 {
158         if (find (routes->begin(), routes->end(), r) != routes->end()) {
159                 return 0;
160         }
161
162         if (r->route_group()) {
163                 r->route_group()->remove (r);
164         }
165
166         routes->push_back (r);
167
168         _solo_group->add_control (r->solo_control());
169         _mute_group->add_control (r->mute_control());
170         _gain_group->add_control (r->gain_control());
171         boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
172         if (trk) {
173                 _rec_enable_group->add_control (trk->rec_enable_control());
174                 _monitoring_group->add_control (trk->monitoring_control());
175         }
176
177         r->set_route_group (this);
178         r->DropReferences.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
179
180         boost::shared_ptr<VCA> vca (group_master.lock());
181
182         if (vca) {
183                 r->assign  (vca);
184         }
185
186         _session.set_dirty ();
187         RouteAdded (this, boost::weak_ptr<Route> (r)); /* EMIT SIGNAL */
188         return 0;
189 }
190
191 void
192 RouteGroup::remove_when_going_away (boost::weak_ptr<Route> wr)
193 {
194         boost::shared_ptr<Route> r (wr.lock());
195
196         if (r) {
197                 remove (r);
198         }
199 }
200
201 int
202 RouteGroup::remove (boost::shared_ptr<Route> r)
203 {
204         RouteList::iterator i;
205
206         if ((i = find (routes->begin(), routes->end(), r)) != routes->end()) {
207                 r->set_route_group (0);
208
209                 boost::shared_ptr<VCA> vca = group_master.lock();
210
211                 if (vca) {
212                         r->unassign (vca);
213                 }
214
215                 _solo_group->remove_control (r->solo_control());
216                 _mute_group->remove_control (r->mute_control());
217                 _gain_group->remove_control (r->gain_control());
218                 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
219                 if (trk) {
220                         _rec_enable_group->remove_control (trk->rec_enable_control());
221                         _monitoring_group->remove_control (trk->monitoring_control());
222                 }
223                 routes->erase (i);
224                 _session.set_dirty ();
225                 RouteRemoved (this, boost::weak_ptr<Route> (r)); /* EMIT SIGNAL */
226                 return 0;
227         }
228
229         return -1;
230 }
231
232
233 XMLNode&
234 RouteGroup::get_state ()
235 {
236         XMLNode *node = new XMLNode ("RouteGroup");
237
238         char buf[64];
239         id().print (buf, sizeof (buf));
240         node->add_property ("id", buf);
241
242         add_properties (*node);
243
244         if (!routes->empty()) {
245                 stringstream str;
246
247                 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
248                         str << (*i)->id () << ' ';
249                 }
250
251                 node->add_property ("routes", str.str());
252         }
253
254         return *node;
255 }
256
257 int
258 RouteGroup::set_state (const XMLNode& node, int version)
259 {
260         if (version < 3000) {
261                 return set_state_2X (node, version);
262         }
263
264         XMLProperty const * prop;
265
266         set_id (node);
267         set_values (node);
268
269         if ((prop = node.property ("routes")) != 0) {
270                 stringstream str (prop->value());
271                 vector<string> ids;
272                 split (str.str(), ids, ' ');
273
274                 for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) {
275                         PBD::ID id (*i);
276                         boost::shared_ptr<Route> r = _session.route_by_id (id);
277
278                         if (r) {
279                                 add (r);
280                         }
281                 }
282         }
283
284         if (_group_master_number.val() > 0) {
285                 boost::shared_ptr<VCA> vca = _session.vca_manager().vca_by_number (_group_master_number.val());
286                 if (vca) {
287                         /* no need to do the assignment because slaves will
288                            handle that themselves. But we can set group_master
289                            to use with future assignments of newly added routes.
290                         */
291                         group_master = vca;
292                 }
293         }
294
295         push_to_groups ();
296
297         return 0;
298 }
299
300 int
301 RouteGroup::set_state_2X (const XMLNode& node, int /*version*/)
302 {
303         set_values (node);
304
305         if (node.name() == "MixGroup") {
306                 _gain = true;
307                 _mute = true;
308                 _solo = true;
309                 _recenable = true;
310                 _route_active = true;
311                 _color = false;
312         } else if (node.name() == "EditGroup") {
313                 _gain = false;
314                 _mute = false;
315                 _solo = false;
316                 _recenable = false;
317                 _route_active = false;
318                 _color = false;
319         }
320
321         push_to_groups ();
322
323         return 0;
324 }
325
326 void
327 RouteGroup::set_gain (bool yn)
328 {
329         if (is_gain() == yn) {
330                 return;
331         }
332         if (has_control_master()) {
333                 return;
334         }
335
336         _gain = yn;
337         _gain_group->set_active (yn);
338
339         send_change (PropertyChange (Properties::group_gain));
340 }
341
342 void
343 RouteGroup::set_mute (bool yn)
344 {
345         if (is_mute() == yn) {
346                 return;
347         }
348         _mute = yn;
349         _mute_group->set_active (yn);
350
351         send_change (PropertyChange (Properties::group_mute));
352 }
353
354 void
355 RouteGroup::set_solo (bool yn)
356 {
357         if (is_solo() == yn) {
358                 return;
359         }
360         _solo = yn;
361         _solo_group->set_active (yn);
362
363         send_change (PropertyChange (Properties::group_solo));
364 }
365
366 void
367 RouteGroup::set_recenable (bool yn)
368 {
369         if (is_recenable() == yn) {
370                 return;
371         }
372         _recenable = yn;
373         _rec_enable_group->set_active (yn);
374         send_change (PropertyChange (Properties::group_recenable));
375 }
376
377 void
378 RouteGroup::set_select (bool yn)
379 {
380         if (is_select() == yn) {
381                 return;
382         }
383         _select = yn;
384         send_change (PropertyChange (Properties::group_select));
385 }
386
387 void
388 RouteGroup::set_route_active (bool yn)
389 {
390         if (is_route_active() == yn) {
391                 return;
392         }
393         _route_active = yn;
394         send_change (PropertyChange (Properties::group_route_active));
395 }
396
397 void
398 RouteGroup::set_color (bool yn)
399 {
400         if (is_color() == yn) {
401                 return;
402         }
403         _color = yn;
404
405         send_change (PropertyChange (Properties::group_color));
406
407         /* This is a bit of a hack, but this might change
408            our route's effective color, so emit gui_changed
409            for our routes.
410         */
411
412         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
413                 (*i)->gui_changed (X_("color"), this);
414         }
415 }
416
417 void
418 RouteGroup::set_monitoring (bool yn)
419 {
420         if (is_monitoring() == yn) {
421                 return;
422         }
423
424         _monitoring = yn;
425         _monitoring_group->set_active (yn);
426
427         send_change (PropertyChange (Properties::group_monitoring));
428
429         _session.set_dirty ();
430 }
431
432 void
433 RouteGroup::set_active (bool yn, void* /*src*/)
434 {
435         if (is_active() == yn) {
436                 return;
437         }
438
439         _active = yn;
440
441         push_to_groups ();
442
443         send_change (PropertyChange (Properties::active));
444         _session.set_dirty ();
445 }
446
447 void
448 RouteGroup::set_relative (bool yn, void* /*src*/)
449 {
450         if (is_relative() == yn) {
451                 return;
452         }
453
454         _relative = yn;
455
456         push_to_groups ();
457
458         send_change (PropertyChange (Properties::group_relative));
459         _session.set_dirty ();
460 }
461
462 void
463 RouteGroup::set_hidden (bool yn, void* /*src*/)
464 {
465         if (is_hidden() == yn) {
466                 return;
467         }
468
469         if (yn) {
470                 _hidden = true;
471                 if (Config->get_hiding_groups_deactivates_groups()) {
472                         _active = false;
473                 }
474         } else {
475                 _hidden = false;
476                 if (Config->get_hiding_groups_deactivates_groups()) {
477                         _active = true;
478                 }
479         }
480
481         send_change (Properties::hidden);
482
483         _session.set_dirty ();
484 }
485
486 void
487 RouteGroup::audio_track_group (set<boost::shared_ptr<AudioTrack> >& ats)
488 {
489         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
490                 boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(*i);
491                 if (at) {
492                         ats.insert (at);
493                 }
494         }
495 }
496
497 void
498 RouteGroup::make_subgroup (bool aux, Placement placement)
499 {
500         RouteList rl;
501         uint32_t nin = 0;
502
503         /* since we don't do MIDI Busses yet, check quickly ... */
504
505         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
506                 if ((*i)->output()->n_ports().n_midi() != 0) {
507                         PBD::warning << _("You cannot subgroup MIDI tracks at this time") << endmsg;
508                         return;
509                 }
510         }
511
512         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
513                 if (!aux && nin != 0 && nin != (*i)->output()->n_ports().n_audio()) {
514                         PBD::warning << _("You cannot subgroup tracks with different number of outputs at this time.") << endmsg;
515                         return;
516                 }
517                 nin = max (nin, (*i)->output()->n_ports().n_audio());
518         }
519
520         try {
521                 /* use master bus etc. to determine default nouts.
522                  *
523                  * (since tracks can't have fewer outs than ins,
524                  * "nin" currently defines the number of outpus if nin > 2)
525                  */
526                 rl = _session.new_audio_route (nin, 2, 0, 1, string(), PresentationInfo::AudioBus, PresentationInfo::max_order);
527         } catch (...) {
528                 return;
529         }
530
531         subgroup_bus = rl.front();
532         subgroup_bus->set_name (_name);
533
534         if (aux) {
535
536                 _session.add_internal_sends (subgroup_bus, placement, routes);
537
538         } else {
539
540                 boost::shared_ptr<Bundle> bundle = subgroup_bus->input()->bundle ();
541
542                 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
543                         (*i)->output()->disconnect (this);
544                         (*i)->output()->connect_ports_to_bundle (bundle, false, this);
545                 }
546         }
547 }
548
549 void
550 RouteGroup::destroy_subgroup ()
551 {
552         if (!subgroup_bus) {
553                 return;
554         }
555
556         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
557                 (*i)->output()->disconnect (this);
558                 /* XXX find a new bundle to connect to */
559         }
560
561         _session.remove_route (subgroup_bus);
562         subgroup_bus.reset ();
563 }
564
565 bool
566 RouteGroup::has_subgroup() const
567 {
568         return subgroup_bus != 0;
569 }
570
571 bool
572 RouteGroup::enabled_property (PBD::PropertyID prop)
573 {
574         OwnedPropertyList::iterator i = _properties->find (prop);
575         if (i == _properties->end()) {
576                 return false;
577         }
578
579         return dynamic_cast<const PropertyTemplate<bool>* > (i->second)->val ();
580 }
581
582 void
583 RouteGroup::post_set (PBD::PropertyChange const &)
584 {
585         push_to_groups ();
586 }
587
588 void
589 RouteGroup::push_to_groups ()
590 {
591         if (is_relative()) {
592                 _gain_group->set_mode (ControlGroup::Mode (_gain_group->mode()|ControlGroup::Relative));
593         } else {
594                 _gain_group->set_mode (ControlGroup::Mode (_gain_group->mode()&~ControlGroup::Relative));
595         }
596
597         if (_active) {
598                 _gain_group->set_active (is_gain());
599                 _solo_group->set_active (is_solo());
600                 _mute_group->set_active (is_mute());
601                 _rec_enable_group->set_active (is_recenable());
602                 _monitoring_group->set_active (is_monitoring());
603         } else {
604                 _gain_group->set_active (false);
605                 _solo_group->set_active (false);
606                 _mute_group->set_active (false);
607                 _rec_enable_group->set_active (false);
608                 _monitoring_group->set_active (false);
609         }
610 }
611
612 void
613 RouteGroup::assign_master (boost::shared_ptr<VCA> master)
614 {
615         if (!routes || routes->empty()) {
616                 return;
617         }
618
619         boost::shared_ptr<Route> front = routes->front ();
620
621         if (front->slaved_to (master)) {
622                 return;
623         }
624
625         for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
626                 (*r)->assign (master);
627         }
628
629         group_master = master;
630         _group_master_number = master->number();
631 }
632
633 void
634 RouteGroup::unassign_master (boost::shared_ptr<VCA> master)
635 {
636         if (!routes || routes->empty()) {
637                 return;
638         }
639
640         boost::shared_ptr<Route> front = routes->front ();
641
642         if (!front->slaved_to (master)) {
643                 return;
644         }
645
646         for (RouteList::iterator r = routes->begin(); r != routes->end(); ++r) {
647                 (*r)->unassign (master);
648         }
649
650         group_master.reset ();
651         _group_master_number = -1;
652 }
653
654 bool
655 RouteGroup::slaved () const
656 {
657         if (!routes || routes->empty()) {
658                 return false;
659         }
660
661         return routes->front()->slaved ();
662 }
663
664 bool
665 RouteGroup::has_control_master() const
666 {
667         return group_master.lock() != 0;
668 }