ardour
monitor_section.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 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 <gdkmm/pixbuf.h>
21 
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25 
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
30 
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
33 
34 #include "ardour/audioengine.h"
36 #include "ardour/port.h"
37 #include "ardour/route.h"
38 
39 #include "ardour_ui.h"
40 #include "gui_thread.h"
41 #include "monitor_section.h"
42 #include "public_editor.h"
43 #include "timers.h"
44 #include "volume_controller.h"
45 #include "utils.h"
46 
47 #include "i18n.h"
48 
49 using namespace ARDOUR;
50 using namespace ARDOUR_UI_UTILS;
51 using namespace Gtk;
52 using namespace Gtkmm2ext;
53 using namespace PBD;
54 using namespace std;
55 
56 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
57 
58 #define PX_SCALE(px) std::max((float)px, rintf((float)px * ARDOUR_UI::ui_scale))
59 
61  : AxisView (s)
62  , RouteUI (s)
63  , _tearoff (0)
64  , channel_table_viewport (*channel_table_scroller.get_hadjustment()
65  , *channel_table_scroller.get_vadjustment ())
66  , gain_control (0)
67  , dim_control (0)
68  , solo_boost_control (0)
69  , solo_cut_control (0)
70  , gain_display (0)
71  , dim_display (0)
72  , solo_boost_display (0)
73  , solo_cut_display (0)
74  , _output_selector (0)
75  , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
76  , afl_button (_("AFL"), ArdourButton::led_default_elements)
77  , pfl_button (_("PFL"), ArdourButton::led_default_elements)
78  , exclusive_solo_button (ArdourButton::led_default_elements)
79  , solo_mute_override_button (ArdourButton::led_default_elements)
80  , _inhibit_solo_model_update (false)
81 {
82 
83  using namespace Menu_Helpers;
84 
85  Glib::RefPtr<Action> act;
86 
87  if (!monitor_actions) {
88 
89  /* do some static stuff */
90 
92 
93  }
94 
95  set_session (s);
96 
97  VBox* spin_packer;
98  Label* spin_label;
99 
100  /* Rude Solo */
101 
102  rude_solo_button.set_text (_("Soloing"));
103  rude_solo_button.set_name ("rude solo");
104  rude_solo_button.show ();
105 
106  rude_iso_button.set_text (_("Isolated"));
107  rude_iso_button.set_name ("rude isolate");
108  rude_iso_button.show ();
109 
110  rude_audition_button.set_text (_("Auditioning"));
111  rude_audition_button.set_name ("rude audition");
112  rude_audition_button.show ();
113 
114  Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
115 
116  rude_solo_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_solo), false);
117  UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
118 
119  rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
120  UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
121 
122  rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
123  UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
124 
125  solo_in_place_button.set_name ("monitor section solo model");
126  afl_button.set_name ("monitor section solo model");
127  pfl_button.set_name ("monitor section solo model");
128 
129  solo_model_box.set_spacing (6);
130  solo_model_box.pack_start (solo_in_place_button, true, false);
131  solo_model_box.pack_start (afl_button, true, false);
132  solo_model_box.pack_start (pfl_button, true, false);
133 
134  solo_in_place_button.show ();
135  afl_button.show ();
136  pfl_button.show ();
137  solo_model_box.show ();
138 
139  act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
140  ARDOUR_UI::instance()->tooltips().set_tip (solo_in_place_button, _("Solo controls affect solo-in-place"));
141  if (act) {
143  }
144 
145  act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
146  ARDOUR_UI::instance()->tooltips().set_tip (afl_button, _("Solo controls toggle after-fader-listen"));
147  if (act) {
149  }
150 
151  act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
152  ARDOUR_UI::instance()->tooltips().set_tip (pfl_button, _("Solo controls toggle pre-fader-listen"));
153  if (act) {
155  }
156 
157  /* Solo Boost */
158 
160  solo_boost_control->set_name("monitor knob");
161  solo_boost_control->set_size_request (PX_SCALE(40), PX_SCALE(40));
162  ARDOUR_UI::instance()->tooltips().set_tip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
163 
165  solo_boost_display->set_name("monitor section cut");
166  solo_boost_display->set_size_request (PX_SCALE(80), PX_SCALE(20));
171 
172  HBox* solo_packer = manage (new HBox);
173  solo_packer->set_spacing (6);
174  solo_packer->show ();
175 
176  spin_label = manage (new Label (_("Solo Boost")));
177  spin_packer = manage (new VBox);
178  spin_packer->show ();
179  spin_packer->set_spacing (3);
180  spin_packer->pack_start (*spin_label, false, false);
181  spin_packer->pack_start (*solo_boost_control, false, false);
182  spin_packer->pack_start (*solo_boost_display, false, false);
183 
184  solo_packer->pack_start (*spin_packer, true, false);
185 
186  /* Solo (SiP) cut */
187 
188  solo_cut_control = new ArdourKnob ();
189  solo_cut_control->set_name ("monitor knob");
190  solo_cut_control->set_size_request (PX_SCALE(40), PX_SCALE(40));
191  ARDOUR_UI::instance()->tooltips().set_tip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
192 
194  solo_cut_display->set_name("monitor section cut");
195  solo_cut_display->set_size_request (PX_SCALE(80), PX_SCALE(20));
197  solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
198  solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
199  solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
200  solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
201 
202  spin_label = manage (new Label (_("SiP Cut")));
203  spin_packer = manage (new VBox);
204  spin_packer->show ();
205  spin_packer->set_spacing (3);
206  spin_packer->pack_start (*spin_label, false, false);
207  spin_packer->pack_start (*solo_cut_control, false, false);
208  spin_packer->pack_start (*solo_cut_display, false, false);
209 
210  solo_packer->pack_start (*spin_packer, true, false);
211 
212  /* Dim */
213 
215  dim_control->set_name ("monitor knob");
216  dim_control->set_size_request (PX_SCALE(40), PX_SCALE(40));
217  ARDOUR_UI::instance()->tooltips().set_tip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
218 
219  dim_display = new ArdourDisplay ();
220  dim_display->set_name("monitor section cut");
221  dim_display->set_size_request (PX_SCALE(80), PX_SCALE(20));
222  dim_display->add_controllable_preset(_("0 dB"), 0.0);
223  dim_display->add_controllable_preset(_("-3 dB"), -3.0);
224  dim_display->add_controllable_preset(_("-6 dB"), -6.0);
225  dim_display->add_controllable_preset(_("-12 dB"), -12.0);
226  dim_display->add_controllable_preset(_("-20 dB"), -20.0);
227 
228  HBox* dim_packer = manage (new HBox);
229  dim_packer->show ();
230 
231  spin_label = manage (new Label (_("Dim")));
232  spin_packer = manage (new VBox);
233  spin_packer->show ();
234  spin_packer->set_spacing (3);
235  spin_packer->pack_start (*spin_label, false, false);
236  spin_packer->pack_start (*dim_control, false, false);
237  spin_packer->pack_start (*dim_display, false, false);
238 
239  dim_packer->pack_start (*spin_packer, true, false);
240 
241  exclusive_solo_button.set_text (_("Excl. Solo"));
242  exclusive_solo_button.set_name (X_("monitor solo exclusive"));
243  ARDOUR_UI::instance()->set_tip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
244 
245  act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
246  if (act) {
248  }
249 
250  solo_mute_override_button.set_text (_("Solo ยป Mute"));
251  solo_mute_override_button.set_name (X_("monitor solo override"));
252  ARDOUR_UI::instance()->set_tip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
253 
254  act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
255  if (act) {
257  }
258 
259  HBox* solo_opt_box = manage (new HBox);
260  solo_opt_box->set_spacing (12);
261  solo_opt_box->set_homogeneous (true);
262  solo_opt_box->pack_start (exclusive_solo_button);
263  solo_opt_box->pack_start (solo_mute_override_button);
264  solo_opt_box->show ();
265 
266  upper_packer.set_spacing (6);
267 
268  Gtk::HBox* rude_box = manage (new HBox);
269  rude_box->pack_start (rude_solo_button, true, true);
270  rude_box->pack_start (rude_iso_button, true, true);
271 
272  upper_packer.pack_start (*rude_box, false, false);
273  upper_packer.pack_start (rude_audition_button, false, false);
274  upper_packer.pack_start (solo_model_box, false, false, 12);
275  upper_packer.pack_start (*solo_opt_box, false, false);
276  upper_packer.pack_start (*solo_packer, false, false, 12);
277 
278  cut_all_button.set_text (_("Mute"));
279  cut_all_button.set_name ("monitor section cut");
280  cut_all_button.set_name (X_("monitor section cut"));
281  cut_all_button.set_size_request (-1, PX_SCALE(50));
282  cut_all_button.show ();
283 
284  act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
285  if (act) {
287  }
288 
289  dim_all_button.set_text (_("Dim"));
290  dim_all_button.set_name ("monitor section dim");
291  act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
292  if (act) {
294  }
295 
296  mono_button.set_text (_("Mono"));
297  mono_button.set_name ("monitor section mono");
298  act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
299  if (act) {
301  }
302 
303  HBox* bbox = manage (new HBox);
304 
305  bbox->set_spacing (12);
306  bbox->pack_start (mono_button, true, true);
307  bbox->pack_start (dim_all_button, true, true);
308 
309  lower_packer.set_spacing (12);
310  lower_packer.pack_start (*bbox, false, false);
311  lower_packer.pack_start (cut_all_button, false, false);
312 
313  /* Gain */
314 
316  gain_control->set_name("monitor knob");
317  gain_control->set_size_request (PX_SCALE(80), PX_SCALE(80));
318 
319  gain_display = new ArdourDisplay ();
320  gain_display->set_name("monitor section cut");
321  gain_display->set_size_request (PX_SCALE(40), PX_SCALE(20));
322  gain_display->add_controllable_preset(_("0 dB"), 0.0);
323  gain_display->add_controllable_preset(_("-3 dB"), -3.0);
324  gain_display->add_controllable_preset(_("-6 dB"), -6.0);
325  gain_display->add_controllable_preset(_("-12 dB"), -12.0);
326  gain_display->add_controllable_preset(_("-20 dB"), -20.0);
327  gain_display->add_controllable_preset(_("-30 dB"), -30.0);
328 
329  Label* output_label = manage (new Label (_("Output")));
330  output_label->set_name (X_("MonitorSectionLabel"));
331 
332  output_button = new ArdourButton ();
333  output_button->set_text (_("Output"));
334  output_button->set_name (X_("monitor section cut"));
335  output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
336  VBox* out_packer = manage (new VBox);
337  out_packer->set_spacing (6);
338  out_packer->pack_start (*output_label, false, false);
339  out_packer->pack_start (*output_button, false, false);
340 
341  spin_label = manage (new Label (_("Monitor")));
342  spin_packer = manage (new VBox);
343  spin_packer->show ();
344  spin_packer->set_spacing (3);
345  spin_packer->pack_start (*spin_label, false, false);
346  spin_packer->pack_start (*gain_control, false, false);
347  spin_packer->pack_start (*gain_display, false, false);
348  spin_packer->pack_start (*out_packer, false, false, 24);
349 
350  lower_packer.pack_start (*spin_packer, true, true);
351 
352  channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
353  channel_table_scroller.set_size_request (-1, PX_SCALE(150));
354  channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
355  channel_table_scroller.show ();
357 
358  channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
360  channel_size_group->add_widget (channel_table);
361 
362  channel_table_header.resize (1, 5);
363 
364  Label* l1 = manage (new Label (X_(" ")));
365  l1->set_name (X_("MonitorSectionLabel"));
366  channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
367 
368  l1 = manage (new Label (_("Mute")));
369  l1->set_name (X_("MonitorSectionLabel"));
370  channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
371 
372  l1 = manage (new Label (_("Dim")));
373  l1->set_name (X_("MonitorSectionLabel"));
374  channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
375 
376  l1 = manage (new Label (_("Solo")));
377  l1->set_name (X_("MonitorSectionLabel"));
378  channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
379 
380  l1 = manage (new Label (_("Inv")));
381  l1->set_name (X_("MonitorSectionLabel"));
382  channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
383 
384  channel_table_header.show ();
385 
386  table_hpacker.pack_start (channel_table, true, true);
387 
388  /* note that we don't pack the table_hpacker till later
389  */
390 
391  vpacker.set_border_width (6);
392  vpacker.set_spacing (12);
393  vpacker.pack_start (upper_packer, false, false);
394  vpacker.pack_start (*dim_packer, false, false);
395  vpacker.pack_start (channel_table_header, false, false);
396  vpacker.pack_start (channel_table_packer, false, false);
397  vpacker.pack_start (lower_packer, false, false);
398 
399  hpacker.pack_start (vpacker, true, true);
400 
401  gain_control->show_all ();
402  gain_display->show_all ();
403  dim_control->show_all ();
404  dim_display->show_all();
405  solo_boost_control->show_all ();
406  solo_boost_display->show_all();
407 
408  channel_table.show ();
409  hpacker.show ();
410  upper_packer.show ();
411  lower_packer.show ();
412  vpacker.show ();
413 
414  populate_buttons ();
415  map_state ();
417 
418  output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
419  output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
420  output_button->signal_size_allocate().connect (sigc::mem_fun (*this, &MonitorSection::output_button_resized));
421 
422  _tearoff = new TearOff (hpacker);
423 
424  /* if torn off, make this a normal window */
425  _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
426  _tearoff->tearoff_window().set_title (X_("Monitor"));
427  _tearoff->tearoff_window().signal_key_press_event().connect (sigc::ptr_fun (forward_key_press), false);
428 
430 
431  /* catch changes that affect us */
432  AudioEngine::instance()->PortConnectedOrDisconnected.connect (
433  *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
434  );
436 }
437 
439 {
440  for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
441  delete *i;
442  }
443 
444  _channel_buttons.clear ();
446 
447  delete output_button;
448  delete gain_control;
449  delete gain_display;
450  delete dim_control;
451  delete dim_display;
452  delete solo_boost_control;
453  delete solo_boost_display;
454  delete solo_cut_control;
455  delete solo_cut_display;
456  delete _tearoff;
457  delete _output_selector;
458  _output_selector = 0;
459 }
460 
461 void
463 {
465 
466  if (_session) {
467 
469 
470  if (_route) {
471  /* session with monitor section */
474  _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
475  boost::bind (&MonitorSection::update_output_display, this),
476  gui_context());
477  } else {
478  /* session with no monitor section */
480  _monitor.reset ();
481  _route.reset ();
482  delete _output_selector;
483  _output_selector = 0;
484  }
485 
486  if (channel_table_scroller.get_parent()) {
487  /* scroller is packed, so remove it */
489  }
490 
491  if (table_hpacker.get_parent () == &channel_table_packer) {
492  /* this occurs when the table hpacker is directly
493  packed, so remove it.
494  */
496  } else if (table_hpacker.get_parent()) {
497  channel_table_viewport.remove ();
498  }
499 
500  if (_monitor->output_streams().n_audio() > 7) {
501  /* put the table into a scrolled window, and then put
502  * that into the channel vpacker, after the table header
503  */
505  channel_table_packer.pack_start (channel_table_scroller, true, true);
506  channel_table_viewport.show ();
507  channel_table_scroller.show ();
508 
509  } else {
510  /* just put the channel table itself into the channel
511  * vpacker, after the table header
512  */
513 
514  channel_table_packer.pack_start (table_hpacker, true, true);
515  channel_table_scroller.hide ();
516  }
517 
518  table_hpacker.show ();
519  channel_table.show ();
520 
521  } else {
522  /* no session */
523 
525  _monitor.reset ();
526  _route.reset ();
530  delete _output_selector;
531  _output_selector = 0;
532 
534  }
535 }
536 
538 {
539  cut.set_name (X_("monitor section cut"));
540  dim.set_name (X_("monitor section dim"));
541  solo.set_name (X_("monitor section solo"));
542  invert.set_name (X_("monitor section invert"));
543 
544  cut.unset_flags (Gtk::CAN_FOCUS);
545  dim.unset_flags (Gtk::CAN_FOCUS);
546  solo.unset_flags (Gtk::CAN_FOCUS);
547  invert.unset_flags (Gtk::CAN_FOCUS);
548 }
549 
550  void
552 {
553  if (!_monitor) {
554  return;
555  }
556 
557  Glib::RefPtr<Action> act;
558  uint32_t nchans = _monitor->output_streams().n_audio();
559 
560  channel_table.resize (nchans, 5);
561  channel_table.set_col_spacings (6);
562  channel_table.set_row_spacings (6);
563  channel_table.set_homogeneous (true);
564 
565  const uint32_t row_offset = 0;
566 
567  for (uint32_t i = 0; i < nchans; ++i) {
568 
569  string l;
570  char buf[64];
571 
572  if (nchans == 2) {
573  if (i == 0) {
574  l = "L";
575  } else {
576  l = "R";
577  }
578  } else {
579  char buf[32];
580  snprintf (buf, sizeof (buf), "%d", i+1);
581  l = buf;
582  }
583 
584  Label* label = manage (new Label (l));
585  channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
586 
588 
589  _channel_buttons.push_back (cbs);
590 
591  channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
592  channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
593  channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
594  channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
595 
596  snprintf (buf, sizeof (buf), "monitor-cut-%u", i+1);
597  act = ActionManager::get_action (X_("Monitor"), buf);
598  if (act) {
599  cbs->cut.set_related_action (act);
600  }
601 
602  snprintf (buf, sizeof (buf), "monitor-dim-%u", i+1);
603  act = ActionManager::get_action (X_("Monitor"), buf);
604  if (act) {
605  cbs->dim.set_related_action (act);
606  }
607 
608  snprintf (buf, sizeof (buf), "monitor-solo-%u", i+1);
609  act = ActionManager::get_action (X_("Monitor"), buf);
610  if (act) {
611  cbs->solo.set_related_action (act);
612  }
613 
614  snprintf (buf, sizeof (buf), "monitor-invert-%u", i+1);
615  act = ActionManager::get_action (X_("Monitor"), buf);
616  if (act) {
617  cbs->invert.set_related_action (act);
618  }
619  }
620 
621  channel_table.show_all ();
622 }
623 
624 void
626 {
627  if (!_monitor) {
628  return;
629  }
630 
631  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
632  if (act) {
633  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
634  Config->set_exclusive_solo (tact->get_active());
635  }
636 
637 }
638 
639 void
641 {
642  if (!_monitor) {
643  return;
644  }
645 
646  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
647  if (act) {
648  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
649  Config->set_solo_mute_override (tact->get_active());
650  }
651 }
652 
653 void
655 {
656  if (!_monitor) {
657  return;
658  }
659 
660  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
661  if (act) {
662  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
663  _monitor->set_dim_all (tact->get_active());
664  }
665 
666 }
667 
668 void
670 {
671  if (!_monitor) {
672  return;
673  }
674 
675  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
676  if (act) {
677  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
678  _monitor->set_cut_all (tact->get_active());
679  }
680 }
681 
682 void
684 {
685  if (!_monitor) {
686  return;
687  }
688 
689  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
690  if (act) {
691  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
692  _monitor->set_mono (tact->get_active());
693  }
694 }
695 
696 void
698 {
699  if (!_monitor) {
700  return;
701  }
702 
703  char buf[64];
704  snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
705 
706  --chn; // 0-based in backend
707 
708  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
709  if (act) {
710  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
711  _monitor->set_cut (chn, tact->get_active());
712  }
713 }
714 
715 void
717 {
718  if (!_monitor) {
719  return;
720  }
721 
722  char buf[64];
723  snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
724 
725  --chn; // 0-based in backend
726 
727  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
728  if (act) {
729  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
730  _monitor->set_dim (chn, tact->get_active());
731  }
732 
733 }
734 
735 void
737 {
738  if (!_monitor) {
739  return;
740  }
741 
742  char buf[64];
743  snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
744 
745  --chn; // 0-based in backend
746 
747  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
748  if (act) {
749  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
750  _monitor->set_solo (chn, tact->get_active());
751  }
752 
753 }
754 
755 void
757 {
758  if (!_monitor) {
759  return;
760  }
761 
762  char buf[64];
763  snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
764 
765  --chn; // 0-based in backend
766 
767  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
768  if (act) {
769  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
770  _monitor->set_polarity (chn, tact->get_active());
771  }
772 }
773 
774 void
776 {
777  string action_name;
778  string action_descr;
779  Glib::RefPtr<Action> act;
780 
781  monitor_actions = ActionGroup::create (X_("Monitor"));
783 
784  ActionManager::register_toggle_action (monitor_actions, "monitor-mono", "", _("Switch monitor to mono"),
785  sigc::mem_fun (*this, &MonitorSection::mono));
786 
787  ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", "", _("Cut monitor"),
788  sigc::mem_fun (*this, &MonitorSection::cut_all));
789 
790  ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", "", _("Dim monitor"),
791  sigc::mem_fun (*this, &MonitorSection::dim_all));
792 
793  act = ActionManager::register_toggle_action (monitor_actions, "toggle-exclusive-solo", "", _("Toggle exclusive solo mode"),
794  sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
795 
796  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
797  tact->set_active (Config->get_exclusive_solo());
798 
799  act = ActionManager::register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", "", _("Toggle mute overrides solo mode"),
800  sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
801 
802  tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
803  tact->set_active (Config->get_solo_mute_override());
804 
805 
806  /* note the 1-based counting (for naming - backend uses 0-based) */
807 
808  for (uint32_t chn = 1; chn <= 16; ++chn) {
809 
810  action_name = string_compose (X_("monitor-cut-%1"), chn);
811  action_descr = string_compose (_("Cut monitor channel %1"), chn);
812  ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
813  sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
814 
815  action_name = string_compose (X_("monitor-dim-%1"), chn);
816  action_descr = string_compose (_("Dim monitor channel %1"), chn);
817  ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
818  sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
819 
820  action_name = string_compose (X_("monitor-solo-%1"), chn);
821  action_descr = string_compose (_("Solo monitor channel %1"), chn);
822  ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
823  sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
824 
825  action_name = string_compose (X_("monitor-invert-%1"), chn);
826  action_descr = string_compose (_("Invert monitor channel %1"), chn);
827  ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), "", action_descr.c_str(),
828  sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
829 
830  }
831 
832 
833  Glib::RefPtr<ActionGroup> solo_actions = ActionGroup::create (X_("Solo"));
834  RadioAction::Group solo_group;
835 
836  ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", "", _("In-place solo"),
837  sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
838  ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", "", _("After Fade Listen (AFL) solo"),
839  sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
840  ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", "", _("Pre Fade Listen (PFL) solo"),
841  sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
842 
843  ActionManager::add_action_group (solo_actions);
844 }
845 
846 void
848 {
849  /* this is driven by a toggle on a radio group, and so is invoked twice,
850  once for the item that became inactive and once for the one that became
851  active.
852  */
853 
854  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
855 
856  if (act) {
857  Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
858  if (ract) {
859  if (!ract->get_active ()) {
860  /* We are turning SiP off, which means that AFL or PFL will be turned on
861  shortly; don't update the solo model in the mean time, as if the currently
862  configured listen position is not the one that is about to be turned on,
863  things will go wrong.
864  */
866  }
867  Config->set_solo_control_is_listen_control (!ract->get_active());
869  }
870  }
871 }
872 
873 void
875 {
876  /* this is driven by a toggle on a radio group, and so is invoked twice,
877  once for the item that became inactive and once for the one that became
878  active.
879  */
880 
881  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
882  if (act) {
883  Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
884  if (ract) {
885  if (ract->get_active()) {
886  Config->set_solo_control_is_listen_control (true);
887  Config->set_listen_position (AfterFaderListen);
888  }
889  }
890  }
891 }
892 
893 void
895 {
896  /* this is driven by a toggle on a radio group, and so is invoked twice,
897  once for the item that became inactive and once for the one that became
898  active.
899  */
900 
901  Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
902  if (act) {
903  Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
904  if (ract) {
905  if (ract->get_active()) {
906  Config->set_solo_control_is_listen_control (true);
907  Config->set_listen_position (PreFaderListen);
908  }
909  }
910  }
911 }
912 
913 void
915 {
917  return;
918  }
919 
920  const char* action_name = 0;
921  Glib::RefPtr<Action> act;
922 
923  if (Config->get_solo_control_is_listen_control()) {
924  switch (Config->get_listen_position()) {
925  case AfterFaderListen:
926  action_name = X_("solo-use-afl");
927  break;
928  case PreFaderListen:
929  action_name = X_("solo-use-pfl");
930  break;
931  }
932  } else {
933  action_name = X_("solo-use-in-place");
934  }
935 
936  act = ActionManager::get_action (X_("Solo"), action_name);
937  if (act) {
938 
939  Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
940  if (ract) {
941  /* because these are radio buttons, one of them will be
942  active no matter what. to trigger a change in the
943  action so that the view picks it up, toggle it.
944  */
945  if (ract->get_active()) {
946  ract->set_active (false);
947  }
948  ract->set_active (true);
949  }
950 
951  }
952 }
953 
954 void
956 {
957  if (!_route || !_monitor) {
958  return;
959  }
960 
961  Glib::RefPtr<Action> act;
962 
964 
965  act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
966  if (act) {
967  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
968  if (tact) {
969  tact->set_active (_monitor->cut_all());
970  }
971  }
972 
973  act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
974  if (act) {
975  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
976  if (tact) {
977  tact->set_active (_monitor->dim_all());
978  }
979  }
980 
981  act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
982  if (act) {
983  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
984  if (tact) {
985  tact->set_active (_monitor->mono());
986  }
987  }
988 
989  uint32_t nchans = _monitor->output_streams().n_audio();
990 
991  assert (nchans == _channel_buttons.size ());
992 
993  for (uint32_t n = 0; n < nchans; ++n) {
994 
995  char action_name[32];
996 
997  snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
998  act = ActionManager::get_action (X_("Monitor"), action_name);
999  if (act) {
1000  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1001  if (tact) {
1002  tact->set_active (_monitor->cut (n));
1003  }
1004  }
1005 
1006  snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1007  act = ActionManager::get_action (X_("Monitor"), action_name);
1008  if (act) {
1009  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1010  if (tact) {
1011  tact->set_active (_monitor->dimmed (n));
1012  }
1013  }
1014 
1015  snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1016  act = ActionManager::get_action (X_("Monitor"), action_name);
1017  if (act) {
1018  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1019  if (tact) {
1020  tact->set_active (_monitor->soloed (n));
1021  }
1022  }
1023 
1024  snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1025  act = ActionManager::get_action (X_("Monitor"), action_name);
1026  if (act) {
1027  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1028  if (tact) {
1029  tact->set_active (_monitor->inverted (n));
1030  }
1031  }
1032  }
1033 }
1034 
1035 void
1037 {
1038  solo_blink (onoff);
1039  audition_blink (onoff);
1040 }
1041 
1042 void
1044 {
1045  if (_session == 0) {
1046  return;
1047  }
1048 
1049  if (_session->is_auditioning()) {
1051  } else {
1053  }
1054 }
1055 
1056 void
1058 {
1059  if (_session == 0) {
1060  return;
1061  }
1062 
1063  if (_session->soloing() || _session->listening()) {
1064  rude_solo_button.set_active (onoff);
1065 
1066  if (_session->soloing()) {
1067  if (_session->solo_isolated()) {
1068  rude_iso_button.set_active (onoff);
1069  } else {
1070  rude_iso_button.set_active (false);
1071  }
1072  }
1073 
1074  } else {
1075  rude_solo_button.set_active (false);
1076  rude_iso_button.set_active (false);
1077  }
1078 }
1079 
1080 bool
1082 {
1083  if (_session) {
1084  if (_session->soloing()) {
1085  _session->set_solo (_session->get_routes(), false);
1086  } else if (_session->listening()) {
1087  _session->set_listen (_session->get_routes(), false);
1088  }
1089  }
1090 
1091  return true;
1092 }
1093 
1094 bool
1096 {
1097  if (_session) {
1099  _session->set_solo_isolated (rl, false, Session::rt_cleanup, true);
1100  }
1101 
1102  return true;
1103 }
1104 
1105 bool
1107 {
1108  if (_session) {
1110  }
1111  return true;
1112 }
1113 
1114 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1115  if (action) { \
1116  Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1117  if (tact && tact->get_active() != value) { \
1118  tact->set_active(value); \
1119  } \
1120  }
1121 
1122 void
1124 {
1125  if (name == "solo-control-is-listen-control") {
1126  update_solo_model ();
1127  } else if (name == "listen-position") {
1128  update_solo_model ();
1129  } else if (name == "solo-mute-override") {
1131  ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1132  Config->get_solo_mute_override ())
1133  } else if (name == "exclusive-solo") {
1135  ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1136  Config->get_exclusive_solo ())
1137  }
1138 }
1139 
1140 void
1142 {
1144 
1145  if (!gain_control) {
1146  /* too early - GUI controls not set up yet */
1147  return;
1148  }
1149 
1150  if (_session) {
1153  } else {
1156  }
1157 
1158  if (_route) {
1161  } else {
1163  }
1164 
1165  if (_monitor) {
1166 
1168  cut_all_button.watch ();
1170  dim_all_button.watch ();
1172  mono_button.watch ();
1173 
1178 
1179  } else {
1180 
1184 
1185  dim_control->set_controllable (none);
1186  dim_display->set_controllable (none);
1189  }
1190 }
1191 
1192 string
1194 {
1195  return "monitor-section";
1196 }
1197 
1198 void
1200 {
1201  using namespace Menu_Helpers;
1202 
1203  if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1204  return;
1205  }
1206 
1207  list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1208  while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1209  ++i;
1210  }
1211 
1212  if (i != output_menu_bundles.end()) {
1213  return;
1214  }
1215 
1216  output_menu_bundles.push_back (b);
1217 
1218  MenuList& citems = output_menu.items();
1219 
1220  std::string n = b->name ();
1221  replace_all (n, "_", " ");
1222 
1223  citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1224 }
1225 
1226 void
1228 {
1229 
1230  ARDOUR::BundleList current = _route->output()->bundles_connected ();
1231 
1232  if (std::find (current.begin(), current.end(), c) == current.end()) {
1233  _route->output()->connect_ports_to_bundle (c, true, this);
1234  } else {
1235  _route->output()->disconnect_ports_from_bundle (c, this);
1236  }
1237 }
1238 
1239 gint
1241 {
1242  switch (ev->button) {
1243  case 3:
1245  break;
1246  }
1247 
1248  return false;
1249 }
1250 
1251 struct RouteCompareByName {
1253  return a->name().compare (b->name()) < 0;
1254  }
1255 };
1256 
1257 gint
1258 MonitorSection::output_press (GdkEventButton *ev)
1259 {
1260  using namespace Menu_Helpers;
1261  if (!_session) {
1262  MessageDialog msg (_("No session - no I/O changes are possible"));
1263  msg.run ();
1264  return true;
1265  }
1266 
1267  MenuList& citems = output_menu.items();
1268  switch (ev->button) {
1269 
1270  case 3:
1271  return false; //wait for the mouse-up to pop the dialog
1272 
1273  case 1:
1274  {
1275  output_menu.set_name ("ArdourContextMenu");
1276  citems.clear ();
1277  output_menu_bundles.clear ();
1278 
1279  citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1280 
1281  citems.push_back (SeparatorElem());
1282  uint32_t const n_with_separator = citems.size ();
1283 
1284  ARDOUR::BundleList current = _route->output()->bundles_connected ();
1285 
1287 
1288  /* give user bundles first chance at being in the menu */
1289 
1290  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1291  if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1292  maybe_add_bundle_to_output_menu (*i, current);
1293  }
1294  }
1295 
1296  for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1297  if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1298  maybe_add_bundle_to_output_menu (*i, current);
1299  }
1300  }
1301 
1303  RouteList copy = *routes;
1304  copy.sort (RouteCompareByName ());
1305  for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1306  maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1307  }
1308 
1309  if (citems.size() == n_with_separator) {
1310  /* no routes added; remove the separator */
1311  citems.pop_back ();
1312  }
1313 
1314  citems.push_back (SeparatorElem());
1315  citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1316 
1317  output_menu.popup (1, ev->time);
1318  break;
1319  }
1320 
1321  default:
1322  break;
1323  }
1324  return TRUE;
1325 }
1326 
1327 void
1329 {
1330  output_button->set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1331 }
1332 
1333 void
1335 {
1336  if (!_route || !_monitor || _session->deletion_in_progress()) {
1337  return;
1338  }
1339 
1340  uint32_t io_count;
1341  uint32_t io_index;
1343  vector<string> port_connections;
1344 
1345  uint32_t total_connection_count = 0;
1346  uint32_t io_connection_count = 0;
1347  uint32_t ardour_connection_count = 0;
1348  uint32_t system_connection_count = 0;
1349  uint32_t other_connection_count = 0;
1350 
1351  ostringstream label;
1352 
1353  bool have_label = false;
1354  bool each_io_has_one_connection = true;
1355 
1356  string connection_name;
1357  string ardour_track_name;
1358  string other_connection_type;
1359  string system_ports;
1360  string system_port;
1361 
1362  ostringstream tooltip;
1363  char * tooltip_cstr;
1364 
1365  io_count = _route->n_outputs().n_total();
1366  tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Glib::Markup::escape_text(_route->name()));
1367 
1368 
1369  for (io_index = 0; io_index < io_count; ++io_index) {
1370 
1371  port = _route->output()->nth (io_index);
1372 
1373  //ignore any port connections that don't match our DataType
1374  if (port->type() != DataType::AUDIO) {
1375  continue;
1376  }
1377 
1378  port_connections.clear ();
1379  port->get_connections(port_connections);
1380  io_connection_count = 0;
1381 
1382  if (!port_connections.empty()) {
1383  for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1384  string pn = "";
1385  string& connection_name (*i);
1386 
1387  if (connection_name.find("system:") == 0) {
1388  pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1389  }
1390 
1391  if (io_connection_count == 0) {
1392  tooltip << endl << Glib::Markup::escape_text(port->name().substr(port->name().find("/") + 1))
1393  << " -> "
1394  << Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
1395  } else {
1396  tooltip << ", "
1397  << Glib::Markup::escape_text( pn.empty() ? connection_name : pn );
1398  }
1399 
1400  if (connection_name.find("ardour:") == 0) {
1401  if (ardour_track_name.empty()) {
1402  // "ardour:Master/in 1" -> "ardour:Master/"
1403  string::size_type slash = connection_name.find("/");
1404  if (slash != string::npos) {
1405  ardour_track_name = connection_name.substr(0, slash + 1);
1406  }
1407  }
1408 
1409  if (connection_name.find(ardour_track_name) == 0) {
1410  ++ardour_connection_count;
1411  }
1412  } else if (!pn.empty()) {
1413  if (system_ports.empty()) {
1414  system_ports += pn;
1415  } else {
1416  system_ports += "/" + pn;
1417  }
1418  if (connection_name.find("system:") == 0) {
1419  ++system_connection_count;
1420  }
1421  } else if (connection_name.find("system:") == 0) {
1422  // "system:playback_123" -> "123"
1423  system_port = connection_name.substr(16);
1424  if (system_ports.empty()) {
1425  system_ports += system_port;
1426  } else {
1427  system_ports += "/" + system_port;
1428  }
1429 
1430  ++system_connection_count;
1431  } else {
1432  if (other_connection_type.empty()) {
1433  // "jamin:in 1" -> "jamin:"
1434  other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1435  }
1436 
1437  if (connection_name.find(other_connection_type) == 0) {
1438  ++other_connection_count;
1439  }
1440  }
1441 
1442  ++total_connection_count;
1443  ++io_connection_count;
1444  }
1445  }
1446 
1447  if (io_connection_count != 1) {
1448  each_io_has_one_connection = false;
1449  }
1450  }
1451 
1452  if (total_connection_count == 0) {
1453  tooltip << endl << _("Disconnected");
1454  }
1455 
1456  tooltip_cstr = new char[tooltip.str().size() + 1];
1457  strcpy(tooltip_cstr, tooltip.str().c_str());
1458 
1459  ARDOUR_UI::instance()->set_tip (output_button, tooltip_cstr, "");
1460 
1461  if (each_io_has_one_connection) {
1462  if (total_connection_count == ardour_connection_count) {
1463  // all connections are to the same track in ardour
1464  // "ardour:Master/" -> "Master"
1465  string::size_type slash = ardour_track_name.find("/");
1466  if (slash != string::npos) {
1467  label << ardour_track_name.substr(7, slash - 7);
1468  have_label = true;
1469  }
1470  } else if (total_connection_count == system_connection_count) {
1471  // all connections are to system ports
1472  label << system_ports;
1473  have_label = true;
1474  } else if (total_connection_count == other_connection_count) {
1475  // all connections are to the same external program eg jamin
1476  // "jamin:" -> "jamin"
1477  label << other_connection_type.substr(0, other_connection_type.size() - 1);
1478  have_label = true;
1479  }
1480  }
1481 
1482  if (!have_label) {
1483  if (total_connection_count == 0) {
1484  // Disconnected
1485  label << "-";
1486  } else {
1487  // Odd configuration
1488  label << "*" << total_connection_count << "*";
1489  }
1490  }
1491 
1492  output_button->set_text (label.str());
1493 }
1494 
1495 void
1497 {
1498  if (_route) {
1499  _route->output()->disconnect(this);
1500  }
1501 }
1502 
1503 void
1505 {
1506  if (_output_selector == 0) {
1508  }
1509  _output_selector->present ();
1510 }
1511 
1512 void
1514 {
1515  if (!_route) {
1516  return;
1517  }
1518  boost::shared_ptr<Port> a = wa.lock ();
1519  boost::shared_ptr<Port> b = wb.lock ();
1520  if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1522  }
1523 }
virtual DataType type() const =0
Gtk::HBox channel_table_packer
boost::shared_ptr< PBD::Controllable > dim_control() const
void toggle_exclusive_solo()
boost::shared_ptr< PBD::Controllable > solo_cut_control() const
bool inverted(uint32_t chn) const
#define SYNCHRONIZE_TOGGLE_ACTION(action, value)
ArdourButton exclusive_solo_button
void set_listen(boost::shared_ptr< RouteList >, bool, SessionEvent::RTeventCallback after=rt_cleanup, bool group_override=false)
bool soloing() const
Definition: session.h:691
Gtk::HBox table_hpacker
bool solo_isolated() const
Definition: session.h:693
ArdourKnob * dim_control
ArdourButton rude_solo_button
Gtk::HBox hpacker
void set_solo(boost::shared_ptr< RouteList >, bool, SessionEvent::RTeventCallback after=rt_cleanup, bool group_override=false)
void update_output_display()
boost::shared_ptr< ARDOUR::Route > _route
void dim_channel(uint32_t)
void set_cut(uint32_t, bool cut)
void toggle_mute_overrides_solo()
void cut_channel(uint32_t)
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
ArdourKnob * solo_cut_control
bool forward_key_press(GdkEventKey *ev)
Definition: utils.cc:317
ArdourButton solo_mute_override_button
void set_related_action(Glib::RefPtr< Gtk::Action >)
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > get_action(const char *group, const char *name)
Definition: actions.cc:406
Gtk::Viewport channel_table_viewport
boost::shared_ptr< AutomationControl > gain_control() const
Definition: route.cc:4042
uint32_t n_audio() const
Definition: chan_count.h:63
bool is_auditioning() const
Definition: session.cc:4184
Definition: Beats.hpp:239
Gtk::VBox lower_packer
Gtk::Table channel_table
bool cut(uint32_t chn) const
boost::shared_ptr< MonitorProcessor > monitor_control() const
Definition: route.h:239
std::string name() const
Definition: port.h:54
ArdourButton cut_all_button
boost::shared_ptr< PBD::Controllable > dim_level_control() const
Gtk::Table channel_table_header
LIBPBD_API int replace_all(std::string &str, const std::string &target, const std::string &replacement)
Definition: strreplace.cc:24
static Element default_elements
Definition: ardour_knob.h:75
void unset_active_state()
Definition: cairo_widget.h:50
#define invalidator(x)
Definition: gui_thread.h:40
void cancel_audition()
Definition: session.cc:4160
Gtk::HBox solo_model_box
boost::shared_ptr< PBD::Controllable > solo_boost_control() const
void add_controllable_preset(const char *, float)
Gtkmm2ext::TearOff * _tearoff
uint32_t n_total() const
Definition: chan_count.h:69
boost::shared_ptr< PBD::Controllable > cut_control() const
ArdourKnob * gain_control
#define _(Text)
Definition: i18n.h:11
ChannelButtons _channel_buttons
bool soloed(uint32_t chn) const
bool cancel_isolate(GdkEventButton *)
void edit_output_configuration()
MonitorSelectorWindow * _output_selector
#define X_(Text)
Definition: i18n.h:13
LIBARDOUR_API RCConfiguration * Config
Definition: globals.cc:119
ArdourKnob * solo_boost_control
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > register_radio_action(Glib::RefPtr< Gtk::ActionGroup > group, Gtk::RadioAction::Group &, const char *name, const char *label, sigc::slot< void > sl, guint key, Gdk::ModifierType mods)
std::vector< boost::shared_ptr< Bundle > > BundleList
Definition: types.h:535
ArdourButton dim_all_button
std::string state_id() const
Glib::RefPtr< Gtk::SizeGroup > channel_size_group
boost::shared_ptr< PBD::Controllable > mono_control() const
void set_controllable(boost::shared_ptr< PBD::Controllable > c)
Definition: ardour_knob.cc:455
void set_controllable(boost::shared_ptr< PBD::Controllable > c)
ArdourButton mono_button
void output_button_resized(Gtk::Allocation &)
void solo_blink(bool)
Definition: amp.h:29
bool ports_are_inputs() const
Definition: bundle.h:114
bool dimmed(uint32_t chn) const
void set_controllable(boost::shared_ptr< PBD::Controllable > c)
bool cancel_solo(GdkEventButton *)
Gtk::VBox vpacker
boost::shared_ptr< BundleList > bundles()
Definition: session.h:241
ChanCount n_outputs() const
Definition: route.h:93
#define gui_context()
Definition: gui_thread.h:36
ChanCount nchannels() const
Definition: bundle.cc:68
boost::shared_ptr< ARDOUR::MonitorProcessor > _monitor
bool deletion_in_progress() const
Definition: session.h:179
void set_solo(uint32_t, bool)
ArdourDisplay * gain_display
gint output_release(GdkEventButton *)
boost::shared_ptr< RouteList > get_routes() const
Definition: session.h:229
std::list< boost::shared_ptr< ARDOUR::Bundle > > output_menu_bundles
std::string name() const
Definition: route_ui.cc:1774
void set_dim(uint32_t, bool dim)
ArdourButton afl_button
std::string name() const
Definition: bundle.h:110
Gtk::Tooltips & tooltips()
Definition: ardour_ui.h:199
ArdourButton rude_iso_button
void set_layout_ellipsize_width(int w)
void solo_channel(uint32_t)
Gtk::Window & tearoff_window()
Definition: tearoff.h:50
gint output_press(GdkEventButton *)
static Glib::RefPtr< Gtk::ActionGroup > monitor_actions
PBD::Signal1< void, std::string > ParameterChanged
Definition: configuration.h:44
void parameter_changed(std::string)
sigc::connection blink_connect(const sigc::slot< void, bool > &slot)
Definition: timers.cc:171
void set_tip(Gtk::Widget &w, const gchar *tip)
ArdourDisplay * dim_display
ArdourDisplay * solo_boost_display
Gtk::VBox upper_packer
bool cancel_audition(GdkEventButton *)
ArdourButton rude_audition_button
void set_text_ellipsize(Pango::EllipsizeMode)
PBD::ScopedConnectionList control_connections
LIBARDOUR_API PBD::PropertyDescriptor< bool > solo
Definition: route_group.cc:46
void port_connected_or_disconnected(boost::weak_ptr< ARDOUR::Port >, boost::weak_ptr< ARDOUR::Port >)
int get_connections(std::vector< std::string > &) const
Definition: port.cc:161
void set_active(bool)
ArdourButton * output_button
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > register_toggle_action(Glib::RefPtr< Gtk::ActionGroup > group, const char *name, const char *label, sigc::slot< void > sl, guint key, Gdk::ModifierType mods)
std::string name() const
void maybe_add_bundle_to_output_menu(boost::shared_ptr< ARDOUR::Bundle >, ARDOUR::BundleList const &)
void set_polarity(uint32_t, bool invert)
void set_text(const std::string &)
ArdourButton solo_in_place_button
bool listening() const
Definition: session.h:692
Definition: debug.h:30
boost::shared_ptr< IO > input() const
Definition: route.h:89
void set_session(ARDOUR::Session *)
virtual void set_session(ARDOUR::Session *)
boost::shared_ptr< IO > output() const
Definition: route.h:90
ArdourDisplay * solo_cut_display
void invert_channel(uint32_t)
Gtk::ScrolledWindow channel_table_scroller
MonitorSection(ARDOUR::Session *)
Gtk::Menu output_menu
void audition_blink(bool)
PBD::ScopedConnection config_connection
PBD::ScopedConnection _output_changed_connection
void set_solo_isolated(boost::shared_ptr< RouteList >, bool, SessionEvent::RTeventCallback after=rt_cleanup, bool group_override=false)
LIBGTKMM2EXT_API void add_action_group(Glib::RefPtr< Gtk::ActionGroup >)
std::list< boost::shared_ptr< Route > > RouteList
Definition: types.h:532
boost::shared_ptr< Route > monitor_out() const
Definition: session.h:717
#define PX_SCALE(px)
bool _inhibit_solo_model_update
ARDOUR::Session * _session
bool has_same_ports(boost::shared_ptr< Bundle >) const
Definition: bundle.cc:501
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
void bundle_output_chosen(boost::shared_ptr< ARDOUR::Bundle >)
ArdourButton pfl_button
virtual ChanCount output_streams() const
Definition: processor.h:89