2 Copyright (C) 2012 Paul Davis
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.
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.
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.
20 #include <gdkmm/pixbuf.h>
22 #include "pbd/compose.h"
23 #include "pbd/error.h"
24 #include "pbd/replace_all.h"
25 #include "pbd/stacktrace.h"
27 #include "gtkmm2ext/actions.h"
28 #include "gtkmm2ext/utils.h"
30 #include <gtkmm/menu.h>
31 #include <gtkmm/menuitem.h>
33 #include "widgets/tearoff.h"
34 #include "widgets/tooltips.h"
36 #include "ardour/amp.h"
37 #include "ardour/audioengine.h"
38 #include "ardour/monitor_processor.h"
39 #include "ardour/port.h"
40 #include "ardour/route.h"
41 #include "ardour/solo_isolate_control.h"
42 #include "ardour/user_bundle.h"
43 #include "ardour/plugin_manager.h"
45 #include "ardour_ui.h"
46 #include "gui_thread.h"
48 #include "monitor_section.h"
49 #include "public_editor.h"
51 #include "ui_config.h"
56 using namespace ARDOUR;
57 using namespace ArdourWidgets;
58 using namespace ARDOUR_UI_UTILS;
60 using namespace Gtkmm2ext;
64 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
66 MonitorSection::MonitorSection ()
67 : RouteUI ((Session*) 0)
70 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
71 , *channel_table_scroller.get_vadjustment ())
74 , solo_boost_control (0)
75 , solo_cut_control (0)
78 , solo_boost_display (0)
79 , solo_cut_display (0)
80 , _output_selector (0)
81 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
82 , afl_button (_("AFL"), ArdourButton::led_default_elements)
83 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
84 , exclusive_solo_button (ArdourButton::led_default_elements)
85 , solo_mute_override_button (ArdourButton::led_default_elements)
86 , toggle_processorbox_button (ArdourButton::default_elements)
87 , _inhibit_solo_model_update (false)
89 , _ui_initialized (false)
91 /* note that although this a RouteUI, we never called ::set_route() so
92 * we do not need to worry about self-destructing when the Route (the
93 * monitor out) is destroyed.
96 using namespace Menu_Helpers;
98 Glib::RefPtr<Action> act;
102 set_data ("ardour-bindings", bindings);
104 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
106 _plugin_selector = new PluginSelector (PluginManager::instance());
107 insert_box = new ProcessorBox (0, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
108 insert_box->set_no_show_all ();
110 // TODO allow keyboard shortcuts in ProcessorBox
112 /* Rude Solo & Solo Isolated */
113 rude_solo_button.set_text (_("Soloing"));
114 rude_solo_button.set_name ("rude solo");
115 rude_solo_button.show ();
117 rude_iso_button.set_text (_("Isolated"));
118 rude_iso_button.set_name ("rude isolate");
119 rude_iso_button.show ();
121 rude_audition_button.set_text (_("Auditioning"));
122 rude_audition_button.set_name ("rude audition");
123 rude_audition_button.show ();
125 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
127 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
129 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
130 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
132 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
133 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
135 /* SIP, AFL, PFL radio */
137 solo_in_place_button.set_name ("monitor section solo model");
138 afl_button.set_name ("monitor section solo model");
139 pfl_button.set_name ("monitor section solo model");
141 solo_in_place_button.set_led_left (true);
142 afl_button.set_led_left (true);
143 pfl_button.set_led_left (true);
145 solo_in_place_button.show ();
149 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
150 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
152 solo_in_place_button.set_related_action (act);
155 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
156 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
158 afl_button.set_related_action (act);
161 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
162 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
164 pfl_button.set_related_action (act);
167 /* Solo option buttons */
168 exclusive_solo_button.set_text (_("Excl. Solo"));
169 exclusive_solo_button.set_name (X_("monitor section solo option"));
170 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
172 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
174 exclusive_solo_button.set_related_action (act);
177 solo_mute_override_button.set_text (_("Solo ยป Mute"));
178 solo_mute_override_button.set_name (X_("monitor section solo option"));
179 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
181 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
183 /* Processor Box hide/shos */
184 toggle_processorbox_button.set_text (_("Processors"));
185 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
186 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
188 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
189 toggle_processorbox_button.set_related_action (proctoggle);
192 Label* solo_boost_label;
193 Label* solo_cut_label;
196 /* Solo Boost Knob */
198 solo_boost_control = new ArdourKnob ();
199 solo_boost_control->set_name("monitor section knob");
200 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
201 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
203 solo_boost_display = new ArdourDisplay ();
204 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
205 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
206 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
207 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
208 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
210 solo_boost_label = manage (new Label (_("Solo Boost")));
214 solo_cut_control = new ArdourKnob ();
215 solo_cut_control->set_name ("monitor section knob");
216 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
217 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
219 solo_cut_display = new ArdourDisplay ();
220 solo_cut_display->set_name("monitor section dropdown"); // XXX
221 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
222 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
223 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
224 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
225 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
226 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
228 solo_cut_label = manage (new Label (_("SiP Cut")));
232 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
233 dim_control->set_name ("monitor section knob");
234 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
235 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
237 dim_display = new ArdourDisplay ();
238 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
239 dim_display->add_controllable_preset(_("0 dB"), 0.0);
240 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
241 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
242 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
243 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
245 dim_label = manage (new Label (_("Dim")));
248 cut_all_button.set_text (_("Mute"));
249 cut_all_button.set_name ("mute button");
250 cut_all_button.set_size_request (-1, PX_SCALE(30));
251 cut_all_button.show ();
253 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
255 cut_all_button.set_related_action (act);
259 dim_all_button.set_text (_("Dim"));
260 dim_all_button.set_name ("monitor section dim");
261 dim_all_button.set_size_request (-1, PX_SCALE(25));
262 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
264 dim_all_button.set_related_action (act);
268 mono_button.set_text (_("Mono"));
269 mono_button.set_name ("monitor section mono");
270 mono_button.set_size_request (-1, PX_SCALE(25));
271 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
273 mono_button.set_related_action (act);
278 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
279 gain_control->set_name("monitor section knob");
280 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
282 gain_display = new ArdourDisplay ();
283 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
284 gain_display->add_controllable_preset(_("0 dB"), 0.0);
285 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
286 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
287 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
288 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
289 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
291 Label* output_label = manage (new Label (_("Output")));
292 output_label->set_name (X_("MonitorSectionLabel"));
294 output_button = new ArdourButton ();
295 output_button->set_text (_("Output"));
296 output_button->set_name (X_("monitor section cut")); // XXX
297 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
298 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
300 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
301 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
302 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
303 channel_table_scroller.show ();
304 channel_table_scroller.add (channel_table_viewport);
306 channel_size_group->add_widget (channel_table_header);
307 channel_table_header.resize (1, 5);
309 Label* l1 = manage (new Label (X_(" ")));
310 l1->set_name (X_("MonitorSectionLabel"));
311 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
313 l1 = manage (new Label (_("Mute")));
314 l1->set_name (X_("MonitorSectionLabel"));
315 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
317 l1 = manage (new Label (_("Dim")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Solo")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Inv")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
329 channel_table_header.show ();
332 /****************************************************************************
333 * LAYOUT top to bottom
336 // solo, iso information
337 HBox* rude_box = manage (new HBox);
338 rude_box->set_spacing (PX_SCALE(4));
339 rude_box->set_homogeneous (true);
340 rude_box->pack_start (rude_solo_button, true, true);
341 rude_box->pack_start (rude_iso_button, true, true);
343 // solo options (right align)
344 HBox* tbx1 = manage (new HBox);
345 tbx1->pack_end (exclusive_solo_button, false, false);
347 HBox* tbx2 = manage (new HBox);
348 tbx2->pack_end (solo_mute_override_button, false, false);
350 HBox* tbx3 = manage (new HBox);
351 tbx3->pack_end (toggle_processorbox_button, false, false);
353 HBox* tbx0 = manage (new HBox); // space
355 // combined solo mode (Sip, AFL, PFL) & solo options
356 Table *solo_tbl = manage (new Table);
357 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
358 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
359 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
360 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
361 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
363 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
365 // boost, cut, dim volume control
366 Table *level_tbl = manage (new Table);
367 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
368 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
369 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
371 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
373 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
375 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
380 HBox* mono_dim_box = manage (new HBox);
381 mono_dim_box->set_spacing (PX_SCALE(4));
382 mono_dim_box->set_homogeneous (true);
383 mono_dim_box->pack_start (mono_button, true, true);
384 mono_dim_box->pack_end (dim_all_button, true, true);
387 Label* spin_label = manage (new Label (_("Monitor")));
388 VBox* spin_packer = manage (new VBox);
389 spin_packer->set_spacing (PX_SCALE(2));
390 spin_packer->pack_start (*spin_label, false, false);
391 spin_packer->pack_start (*gain_control, false, false);
392 spin_packer->pack_start (*gain_display, false, false);
394 master_packer.pack_start (*spin_packer, true, false);
396 // combined gain section (channels, mute, dim)
397 VBox* lower_packer = manage (new VBox);
398 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
399 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
400 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
401 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
403 // calc height of mixer scrollbar
404 int scrollbar_height = 0;
406 Gtk::Window window (WINDOW_TOPLEVEL);
407 HScrollbar scrollbar;
408 window.add (scrollbar);
409 scrollbar.set_name ("MixerWindow");
410 scrollbar.ensure_style();
411 Gtk::Requisition requisition(scrollbar.size_request ());
412 scrollbar_height = requisition.height;
415 // output port select
416 VBox* out_packer = manage (new VBox);
417 out_packer->set_spacing (PX_SCALE(2));
418 out_packer->pack_start (*output_label, false, false);
419 out_packer->pack_start (*output_button, false, false);
421 /****************************************************************************
424 vpacker.set_border_width (PX_SCALE(3));
425 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
426 vpacker.pack_start (rude_audition_button, false, false, 0);
427 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
428 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
429 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
430 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
431 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
432 vpacker.pack_end (*out_packer, false, false,
434 scrollbar_height - 2 /* no outer sample */
436 scrollbar_height + 2 /* sample borders */
440 hpacker.set_spacing (0);
441 hpacker.pack_start (vpacker, true, true);
445 gain_control->show_all ();
446 gain_display->show_all ();
447 dim_control->show_all ();
448 dim_display->show_all();
449 solo_boost_control->show_all ();
450 solo_boost_display->show_all();
452 mono_dim_box->show ();
453 spin_packer->show ();
454 master_packer.show ();
457 solo_tbl->show_all();
459 lower_packer->show ();
467 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
468 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
470 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
471 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
472 set_flags (CAN_FOCUS);
474 _tearoff = new TearOff (*this);
476 if (!UIConfiguration::instance().get_floating_monitor_section()) {
477 /* if torn off, make this a normal window
478 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
480 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
482 _tearoff->tearoff_window().set_title (X_("Monitor"));
483 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
485 update_output_display ();
486 update_processor_box ();
487 _ui_initialized = true;
489 /* catch changes that affect us */
490 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
491 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
493 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
496 MonitorSection::~MonitorSection ()
498 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
502 _channel_buttons.clear ();
503 route_connections.drop_connections ();
505 delete insert_box; insert_box = 0;
506 delete output_button; output_button = 0;
507 delete gain_control; gain_control = 0;
508 delete gain_display; gain_display = 0;
509 delete dim_control; dim_control = 0;
510 delete dim_display; dim_display = 0;
511 delete solo_boost_control; solo_boost_control = 0;
512 delete solo_boost_display; solo_boost_display = 0;
513 delete solo_cut_control; solo_cut_control = 0;
514 delete solo_cut_display; solo_cut_display = 0;
515 delete _tearoff; _tearoff = 0;
516 delete _output_selector; _output_selector = 0;
517 delete channel_table; channel_table = 0;
521 MonitorSection::enter_handler (GdkEventCrossing* ev)
528 MonitorSection::leave_handler (GdkEventCrossing* ev)
530 switch (ev->detail) {
531 case GDK_NOTIFY_INFERIOR:
537 /* cancel focus if we're not torn off. With X11 WM's that do
538 * focus-follows-mouse, focus will be taken from us anyway.
541 Widget* top = get_toplevel();
543 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
544 Window* win = dynamic_cast<Window*> (top);
545 gtk_window_set_focus (win->gobj(), 0);
552 MonitorSection::update_processor_box ()
554 bool show_processor_box = proctoggle->get_active ();
556 if (count_processors () > 0 && !show_processor_box) {
557 toggle_processorbox_button.set_name (X_("monitor section processors present"));
559 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
562 if (insert_box->is_visible() == show_processor_box) {
566 if (show_processor_box) {
567 if (master_packer.get_parent()) {
568 master_packer.get_parent()->remove (master_packer);
571 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
573 if (master_packer.get_parent()) {
574 master_packer.get_parent()->remove (master_packer);
577 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
582 MonitorSection::set_session (Session* s)
584 RouteUI::set_session (s);
585 _plugin_selector->set_session (_session);
586 insert_box->set_session (_session);
590 /* These are not actually dependent on the Session, but they
591 * need to be set after construction, not during, and
592 * this is as good a place as any.
595 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
596 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
598 _route = _session->monitor_out ();
601 /* session with monitor section */
602 _monitor = _route->monitor_control ();
603 assign_controllables ();
604 _route->output()->changed.connect (route_connections, invalidator (*this),
605 boost::bind (&MonitorSection::update_output_display, this),
607 insert_box->set_route (_route);
608 _route->processors_changed.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
609 _route->output()->PortCountChanged.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
610 _route->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
612 if (_ui_initialized) {
613 update_processor_box ();
616 ActionManager::set_sensitive (monitor_actions, true);
617 ActionManager::set_sensitive (solo_actions, true);
620 /* session with no monitor section */
621 route_connections.drop_connections();
624 delete _output_selector;
625 _output_selector = 0;
627 ActionManager::set_sensitive (monitor_actions, false);
628 /* this action needs to always be true in this * scenaro, so that we can turn it back on*/
629 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
630 ActionManager::set_sensitive (solo_actions, true);
633 /* make sure the state of this action reflects reality */
634 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_active (_route != 0);
645 unassign_controllables ();
648 ActionManager::set_sensitive (monitor_actions, false);
649 ActionManager::set_sensitive (solo_actions, false);
654 MonitorSection::drop_route ()
656 route_connections.drop_connections();
659 unassign_controllables ();
660 rude_iso_button.unset_active_state ();
661 rude_solo_button.unset_active_state ();
662 delete _output_selector;
663 _output_selector = 0;
666 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
668 cut.set_name (X_("mute button"));
669 dim.set_name (X_("monitor section dim"));
670 solo.set_name (X_("solo button"));
671 invert.set_name (X_("invert button"));
673 cut.unset_flags (Gtk::CAN_FOCUS);
674 dim.unset_flags (Gtk::CAN_FOCUS);
675 solo.unset_flags (Gtk::CAN_FOCUS);
676 invert.unset_flags (Gtk::CAN_FOCUS);
680 MonitorSection::populate_buttons ()
687 channel_size_group->remove_widget (*channel_table);
688 delete channel_table;
691 channel_table = new Gtk::Table();
693 channel_table->set_col_spacings (6);
694 channel_table->set_row_spacings (6);
695 channel_table->set_homogeneous (true);
697 channel_size_group->add_widget (*channel_table);
698 channel_table->show ();
699 table_hpacker.pack_start (*channel_table, true, true);
701 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
704 _channel_buttons.clear ();
706 Glib::RefPtr<Action> act;
707 uint32_t nchans = _monitor->output_streams().n_audio();
709 channel_table->resize (nchans, 5);
711 const uint32_t row_offset = 0;
713 for (uint32_t i = 0; i < nchans; ++i) {
726 snprintf (buf, sizeof (buf), "%d", i+1);
730 Label* label = manage (new Label (l));
731 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
733 ChannelButtonSet* cbs = new ChannelButtonSet;
735 _channel_buttons.push_back (cbs);
737 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
738 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
739 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
740 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
742 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
743 act = ActionManager::get_action (X_("Monitor"), buf);
745 cbs->cut.set_related_action (act);
748 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
749 act = ActionManager::get_action (X_("Monitor"), buf);
751 cbs->dim.set_related_action (act);
754 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
755 act = ActionManager::get_action (X_("Monitor"), buf);
757 cbs->solo.set_related_action (act);
760 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
761 act = ActionManager::get_action (X_("Monitor"), buf);
763 cbs->invert.set_related_action (act);
767 channel_table->show_all ();
769 if (channel_table_scroller.get_parent()) {
770 /* scroller is packed, so remove it */
771 channel_table_packer.remove (channel_table_scroller);
774 if (table_hpacker.get_parent () == &channel_table_packer) {
775 /* this occurs when the table hpacker is directly
776 packed, so remove it.
778 channel_table_packer.remove (table_hpacker);
779 } else if (table_hpacker.get_parent()) {
780 channel_table_viewport.remove ();
784 /* put the table into a scrolled window, and then put
785 * that into the channel vpacker, after the table header
787 channel_table_viewport.add (table_hpacker);
788 channel_table_packer.pack_start (channel_table_scroller, true, true);
789 channel_table_viewport.show ();
790 channel_table_scroller.show ();
793 /* just put the channel table itself into the channel
794 * vpacker, after the table header
796 channel_table_packer.pack_start (table_hpacker, true, true);
797 channel_table_scroller.hide ();
799 table_hpacker.show ();
800 channel_table->show ();
804 MonitorSection::toggle_exclusive_solo ()
810 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
814 MonitorSection::toggle_mute_overrides_solo ()
820 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
821 Config->set_solo_mute_override (tact->get_active());
825 MonitorSection::dim_all ()
831 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
832 _monitor->set_dim_all (tact->get_active());
836 MonitorSection::cut_all ()
842 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
843 _monitor->set_cut_all (tact->get_active());
847 MonitorSection::mono ()
853 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
854 _monitor->set_mono (tact->get_active());
858 MonitorSection::cut_channel (uint32_t chn)
865 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
867 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
868 _monitor->set_cut (chn, tact->get_active());
872 MonitorSection::dim_channel (uint32_t chn)
879 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
881 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
882 _monitor->set_dim (chn, tact->get_active());
886 MonitorSection::solo_channel (uint32_t chn)
893 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
895 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
896 _monitor->set_solo (chn, tact->get_active());
901 MonitorSection::invert_channel (uint32_t chn)
908 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
910 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
911 _monitor->set_polarity (chn, tact->get_active());
915 MonitorSection::register_actions ()
919 Glib::RefPtr<Action> act;
921 /* ...will get sensitized if a mon-session is added */
923 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
924 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
927 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
929 /* these are global monitor actions that invoke MonitorSectioncode. Do
930 * not create local versions (i.e. as part of "monitor_actions")
931 * because then we can end up with two different bindings (one global,
932 * one local to the monitor section) for the same action.
935 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
937 ActionManager::register_toggle_action (global_monitor_actions, "monitor-mono", _("Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
938 ActionManager::register_toggle_action (global_monitor_actions, "monitor-cut-all", _("Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
939 ActionManager::register_toggle_action (global_monitor_actions, "monitor-dim-all", _("Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
941 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
942 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
945 for (uint32_t chn = 0; chn < 16; ++chn) {
947 action_name = string_compose (X_("monitor-cut-%1"), chn);
948 action_descr = string_compose (_("Cut monitor channel %1"), chn);
949 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
950 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
952 action_name = string_compose (X_("monitor-dim-%1"), chn);
953 action_descr = string_compose (_("Dim monitor channel %1"), chn);
954 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
955 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
957 action_name = string_compose (X_("monitor-solo-%1"), chn);
958 action_descr = string_compose (_("Solo monitor channel %1"), chn);
959 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
960 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
962 action_name = string_compose (X_("monitor-invert-%1"), chn);
963 action_descr = string_compose (_("Invert monitor channel %1"), chn);
964 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
965 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
969 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
970 RadioAction::Group solo_group;
972 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
973 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
974 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
975 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
976 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
977 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
979 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
980 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
981 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
982 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
986 MonitorSection::solo_use_in_place ()
988 /* this is driven by a toggle on a radio group, and so is invoked twice,
989 once for the item that became inactive and once for the one that became
993 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
994 if (!ract->get_active ()) {
995 /* We are turning SiP off, which means that AFL or PFL will be turned on
996 shortly; don't update the solo model in the mean time, as if the currently
997 configured listen position is not the one that is about to be turned on,
998 things will go wrong.
1000 _inhibit_solo_model_update = true;
1002 Config->set_solo_control_is_listen_control (!ract->get_active());
1003 _inhibit_solo_model_update = false;
1007 MonitorSection::solo_use_afl ()
1009 /* this is driven by a toggle on a radio group, and so is invoked twice,
1010 once for the item that became inactive and once for the one that became
1014 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1015 if (ract->get_active()) {
1016 Config->set_solo_control_is_listen_control (true);
1017 Config->set_listen_position (AfterFaderListen);
1022 MonitorSection::solo_use_pfl ()
1024 /* this is driven by a toggle on a radio group, and so is invoked twice,
1025 once for the item that became inactive and once for the one that became
1029 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1030 if (ract->get_active()) {
1031 Config->set_solo_control_is_listen_control (true);
1032 Config->set_listen_position (PreFaderListen);
1037 MonitorSection::update_solo_model ()
1039 if (_inhibit_solo_model_update) {
1043 const char* action_name = 0;
1044 Glib::RefPtr<RadioAction> ract;
1046 if (Config->get_solo_control_is_listen_control()) {
1047 switch (Config->get_listen_position()) {
1048 case AfterFaderListen:
1049 action_name = X_("solo-use-afl");
1051 case PreFaderListen:
1052 action_name = X_("solo-use-pfl");
1056 action_name = X_("solo-use-in-place");
1059 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1061 /* because these are radio buttons, one of them will be
1062 active no matter what. to trigger a change in the
1063 action so that the view picks it up, toggle it.
1066 if (ract->get_active()) {
1067 ract->set_active (false);
1070 ract->set_active (true);
1074 MonitorSection::map_state ()
1076 if (!_route || !_monitor) {
1080 update_solo_model ();
1082 Glib::RefPtr<Action> act;
1083 Glib::RefPtr<ToggleAction> tact;
1085 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-cut-all");
1086 tact->set_active (_monitor->cut_all());
1088 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-dim-all");
1089 tact->set_active (_monitor->dim_all());
1091 tact = ActionManager::get_toggle_action (X_("Monitor"), "monitor-mono");
1092 tact->set_active (_monitor->mono());
1094 uint32_t nchans = _monitor->output_streams().n_audio();
1096 assert (nchans == _channel_buttons.size ());
1098 for (uint32_t n = 0; n < nchans; ++n) {
1100 char action_name[32];
1102 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1103 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1104 tact->set_active (_monitor->cut (n));
1106 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1107 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1108 tact->set_active (_monitor->dimmed (n));
1110 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1111 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1112 tact->set_active (_monitor->soloed (n));
1114 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1115 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1116 tact->set_active (_monitor->inverted (n));
1121 MonitorSection::do_blink (bool onoff)
1123 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1128 audition_blink (onoff);
1132 MonitorSection::audition_blink (bool onoff)
1134 if (_session == 0) {
1138 if (_session->is_auditioning()) {
1139 rude_audition_button.set_active (onoff);
1141 rude_audition_button.set_active (false);
1146 MonitorSection::solo_blink (bool onoff)
1148 if (_session == 0) {
1152 if (_session->soloing() || _session->listening()) {
1153 rude_solo_button.set_active (onoff);
1155 if (_session->soloing()) {
1156 if (_session->solo_isolated()) {
1157 rude_iso_button.set_active (onoff);
1159 rude_iso_button.set_active (false);
1164 rude_solo_button.set_active (false);
1165 rude_iso_button.set_active (false);
1170 MonitorSection::cancel_isolate (GdkEventButton*)
1173 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1174 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1181 MonitorSection::cancel_audition (GdkEventButton*)
1184 _session->cancel_audition();
1189 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1190 if (action && action->get_active() != value) { \
1191 action->set_active(value); \
1195 MonitorSection::parameter_changed (std::string name)
1197 if (name == "solo-control-is-listen-control") {
1198 update_solo_model ();
1199 } else if (name == "listen-position") {
1200 update_solo_model ();
1201 } else if (name == "solo-mute-override") {
1202 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1203 } else if (name == "exclusive-solo") {
1204 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1205 } else if (name == "use-monitor-bus") {
1206 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), Config->get_use_monitor_bus ());
1211 MonitorSection::unassign_controllables ()
1213 boost::shared_ptr<Controllable> none;
1215 solo_cut_control->set_controllable (none);
1216 solo_cut_display->set_controllable (none);
1217 gain_control->set_controllable (none);
1218 gain_display->set_controllable (none);
1219 cut_all_button.set_controllable (none);
1220 dim_all_button.set_controllable (none);
1221 mono_button.set_controllable (none);
1222 dim_control->set_controllable (none);
1223 dim_display->set_controllable (none);
1224 solo_boost_control->set_controllable (none);
1225 solo_boost_display->set_controllable (none);
1229 MonitorSection::assign_controllables ()
1235 solo_cut_control->set_controllable (_session->solo_cut_control());
1236 solo_cut_display->set_controllable (_session->solo_cut_control());
1238 gain_control->set_controllable (_route->gain_control());
1239 gain_display->set_controllable (_route->gain_control());
1240 cut_all_button.set_controllable (_monitor->cut_control());
1241 cut_all_button.watch ();
1242 dim_all_button.set_controllable (_monitor->dim_control());
1243 dim_all_button.watch ();
1244 mono_button.set_controllable (_monitor->mono_control());
1245 mono_button.watch ();
1246 dim_control->set_controllable (_monitor->dim_level_control ());
1247 dim_display->set_controllable (_monitor->dim_level_control ());
1248 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1249 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1253 MonitorSection::state_id() const
1255 return "monitor-section";
1259 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1261 using namespace Menu_Helpers;
1263 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1267 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1268 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1272 if (i != output_menu_bundles.end()) {
1276 output_menu_bundles.push_back (b);
1278 MenuList& citems = output_menu.items();
1280 std::string n = b->name ();
1281 replace_all (n, "_", " ");
1283 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1287 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1290 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1292 if (std::find (current.begin(), current.end(), c) == current.end()) {
1293 _route->output()->connect_ports_to_bundle (c, true, this);
1295 _route->output()->disconnect_ports_from_bundle (c, this);
1300 MonitorSection::output_release (GdkEventButton *ev)
1302 switch (ev->button) {
1304 edit_output_configuration ();
1311 struct RouteCompareByName {
1312 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1313 return a->name().compare (b->name()) < 0;
1318 MonitorSection::output_press (GdkEventButton *ev)
1320 using namespace Menu_Helpers;
1322 MessageDialog msg (_("No session - no I/O changes are possible"));
1327 MenuList& citems = output_menu.items();
1328 switch (ev->button) {
1331 return false; //wait for the mouse-up to pop the dialog
1335 output_menu.set_name ("ArdourContextMenu");
1337 output_menu_bundles.clear ();
1339 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1341 citems.push_back (SeparatorElem());
1342 uint32_t const n_with_separator = citems.size ();
1344 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1346 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1348 /* give user bundles first chance at being in the menu */
1350 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1351 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1352 maybe_add_bundle_to_output_menu (*i, current);
1356 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1357 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1358 maybe_add_bundle_to_output_menu (*i, current);
1362 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1363 RouteList copy = *routes;
1364 copy.sort (RouteCompareByName ());
1365 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1366 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1369 if (citems.size() == n_with_separator) {
1370 /* no routes added; remove the separator */
1374 citems.push_back (SeparatorElem());
1375 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1377 output_menu.popup (1, ev->time);
1388 MonitorSection::update_output_display ()
1390 if (!_route || !_monitor || _session->deletion_in_progress()) {
1396 boost::shared_ptr<Port> port;
1397 vector<string> port_connections;
1399 uint32_t total_connection_count = 0;
1400 uint32_t io_connection_count = 0;
1401 uint32_t ardour_connection_count = 0;
1402 uint32_t system_connection_count = 0;
1403 uint32_t other_connection_count = 0;
1405 ostringstream label;
1407 bool have_label = false;
1408 bool each_io_has_one_connection = true;
1410 string connection_name;
1411 string ardour_track_name;
1412 string other_connection_type;
1413 string system_ports;
1416 ostringstream tooltip;
1417 char * tooltip_cstr;
1419 io_count = _route->n_outputs().n_total();
1420 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1423 for (io_index = 0; io_index < io_count; ++io_index) {
1425 port = _route->output()->nth (io_index);
1427 //ignore any port connections that don't match our DataType
1428 if (port->type() != DataType::AUDIO) {
1432 port_connections.clear ();
1433 port->get_connections(port_connections);
1434 io_connection_count = 0;
1436 if (!port_connections.empty()) {
1437 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1439 string& connection_name (*i);
1441 if (connection_name.find("system:") == 0) {
1442 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1445 if (io_connection_count == 0) {
1446 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1448 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1451 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1454 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1455 if (ardour_track_name.empty()) {
1456 // "ardour:Master/in 1" -> "ardour:Master/"
1457 string::size_type slash = connection_name.find("/");
1458 if (slash != string::npos) {
1459 ardour_track_name = connection_name.substr(0, slash + 1);
1463 if (connection_name.find(ardour_track_name) == 0) {
1464 ++ardour_connection_count;
1466 } else if (!pn.empty()) {
1467 if (system_ports.empty()) {
1470 system_ports += "/" + pn;
1472 if (connection_name.find("system:") == 0) {
1473 ++system_connection_count;
1475 } else if (connection_name.find("system:") == 0) {
1476 // "system:playback_123" -> "123"
1477 system_port = connection_name.substr(16);
1478 if (system_ports.empty()) {
1479 system_ports += system_port;
1481 system_ports += "/" + system_port;
1484 ++system_connection_count;
1486 if (other_connection_type.empty()) {
1487 // "jamin:in 1" -> "jamin:"
1488 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1491 if (connection_name.find(other_connection_type) == 0) {
1492 ++other_connection_count;
1496 ++total_connection_count;
1497 ++io_connection_count;
1501 if (io_connection_count != 1) {
1502 each_io_has_one_connection = false;
1506 if (total_connection_count == 0) {
1507 tooltip << endl << _("Disconnected");
1510 tooltip_cstr = new char[tooltip.str().size() + 1];
1511 strcpy(tooltip_cstr, tooltip.str().c_str());
1513 set_tooltip (output_button, tooltip_cstr, "");
1515 if (each_io_has_one_connection) {
1516 if (total_connection_count == ardour_connection_count) {
1517 // all connections are to the same track in ardour
1518 // "ardour:Master/" -> "Master"
1519 string::size_type slash = ardour_track_name.find("/");
1520 if (slash != string::npos) {
1521 label << ardour_track_name.substr(7, slash - 7);
1524 } else if (total_connection_count == system_connection_count) {
1525 // all connections are to system ports
1526 label << system_ports;
1528 } else if (total_connection_count == other_connection_count) {
1529 // all connections are to the same external program eg jamin
1530 // "jamin:" -> "jamin"
1531 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1537 if (total_connection_count == 0) {
1541 // Odd configuration
1542 label << "*" << total_connection_count << "*";
1546 output_button->set_text (label.str());
1550 MonitorSection::disconnect_output ()
1553 _route->output()->disconnect(this);
1558 MonitorSection::edit_output_configuration ()
1560 if (_output_selector == 0) {
1561 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1563 _output_selector->present ();
1567 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1572 boost::shared_ptr<Port> a = wa.lock ();
1573 boost::shared_ptr<Port> b = wb.lock ();
1574 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1575 update_output_display ();
1580 MonitorSection::load_bindings ()
1582 bindings = Bindings::get_bindings (X_("Monitor Section"));
1586 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1588 boost::shared_ptr<Processor> processor (p.lock ());
1589 if (!processor || !processor->display_to_user()) {
1592 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1599 MonitorSection::count_processors ()
1601 uint32_t processor_count = 0;
1603 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1605 return processor_count;
1609 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1611 update_processor_box ();
1615 MonitorSection::use_others_actions ()
1617 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1621 MonitorSection::toggle_use_monitor_section ()
1627 Config->set_use_monitor_bus (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active());