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"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/utils.h"
29 #include <gtkmm/menu.h>
30 #include <gtkmm/menuitem.h>
32 #include "widgets/tearoff.h"
33 #include "widgets/tooltips.h"
35 #include "ardour/amp.h"
36 #include "ardour/audioengine.h"
37 #include "ardour/monitor_processor.h"
38 #include "ardour/port.h"
39 #include "ardour/route.h"
40 #include "ardour/solo_isolate_control.h"
41 #include "ardour/user_bundle.h"
42 #include "ardour/plugin_manager.h"
44 #include "ardour_ui.h"
45 #include "gui_thread.h"
47 #include "monitor_section.h"
48 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ArdourWidgets;
57 using namespace ARDOUR_UI_UTILS;
59 using namespace Gtkmm2ext;
63 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
65 MonitorSection::MonitorSection ()
66 : RouteUI ((Session*) 0)
69 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
70 , *channel_table_scroller.get_vadjustment ())
73 , solo_boost_control (0)
74 , solo_cut_control (0)
77 , solo_boost_display (0)
78 , solo_cut_display (0)
79 , _output_selector (0)
80 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
81 , afl_button (_("AFL"), ArdourButton::led_default_elements)
82 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
83 , exclusive_solo_button (ArdourButton::led_default_elements)
84 , solo_mute_override_button (ArdourButton::led_default_elements)
85 , toggle_processorbox_button (ArdourButton::default_elements)
86 , _inhibit_solo_model_update (false)
88 , _ui_initialized (false)
90 /* note that although this a RouteUI, we never called ::set_route() so
91 * we do not need to worry about self-destructing when the Route (the
92 * monitor out) is destroyed.
95 using namespace Menu_Helpers;
97 Glib::RefPtr<Action> act;
101 set_data ("ardour-bindings", bindings);
103 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
105 _plugin_selector = new PluginSelector (PluginManager::instance());
106 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
107 insert_box->set_no_show_all ();
109 // TODO allow keyboard shortcuts in ProcessorBox
111 /* Rude Solo & Solo Isolated */
112 rude_solo_button.set_text (_("Soloing"));
113 rude_solo_button.set_name ("rude solo");
114 rude_solo_button.show ();
116 rude_iso_button.set_text (_("Isolated"));
117 rude_iso_button.set_name ("rude isolate");
118 rude_iso_button.show ();
120 rude_audition_button.set_text (_("Auditioning"));
121 rude_audition_button.set_name ("rude audition");
122 rude_audition_button.show ();
124 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
126 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
128 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
129 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
131 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
132 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
134 /* SIP, AFL, PFL radio */
136 solo_in_place_button.set_name ("monitor section solo model");
137 afl_button.set_name ("monitor section solo model");
138 pfl_button.set_name ("monitor section solo model");
140 solo_in_place_button.set_led_left (true);
141 afl_button.set_led_left (true);
142 pfl_button.set_led_left (true);
144 solo_in_place_button.show ();
148 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
149 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
151 solo_in_place_button.set_related_action (act);
154 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
155 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
157 afl_button.set_related_action (act);
160 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
161 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
163 pfl_button.set_related_action (act);
166 /* Solo option buttons */
167 exclusive_solo_button.set_text (_("Excl. Solo"));
168 exclusive_solo_button.set_name (X_("monitor section solo option"));
169 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
171 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
173 exclusive_solo_button.set_related_action (act);
176 solo_mute_override_button.set_text (_("Solo ยป Mute"));
177 solo_mute_override_button.set_name (X_("monitor section solo option"));
178 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
180 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
182 /* Processor Box hide/shos */
183 toggle_processorbox_button.set_text (_("Processors"));
184 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
185 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
187 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
188 toggle_processorbox_button.set_related_action (proctoggle);
191 Label* solo_boost_label;
192 Label* solo_cut_label;
195 /* Solo Boost Knob */
197 solo_boost_control = new ArdourKnob ();
198 solo_boost_control->set_name("monitor section knob");
199 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
200 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
202 solo_boost_display = new ArdourDisplay ();
203 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
204 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
205 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
206 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
207 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
209 solo_boost_label = manage (new Label (_("Solo Boost")));
213 solo_cut_control = new ArdourKnob ();
214 solo_cut_control->set_name ("monitor section knob");
215 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
216 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
218 solo_cut_display = new ArdourDisplay ();
219 solo_cut_display->set_name("monitor section dropdown"); // XXX
220 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
221 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
222 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
223 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
224 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
225 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
227 solo_cut_label = manage (new Label (_("SiP Cut")));
231 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
232 dim_control->set_name ("monitor section knob");
233 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
234 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
236 dim_display = new ArdourDisplay ();
237 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
238 dim_display->add_controllable_preset(_("0 dB"), 0.0);
239 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
240 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
241 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
242 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
244 dim_label = manage (new Label (_("Dim")));
247 cut_all_button.set_text (_("Mute"));
248 cut_all_button.set_name ("mute button");
249 cut_all_button.set_size_request (-1, PX_SCALE(30));
250 cut_all_button.show ();
252 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
254 cut_all_button.set_related_action (act);
258 dim_all_button.set_text (_("Dim"));
259 dim_all_button.set_name ("monitor section dim");
260 dim_all_button.set_size_request (-1, PX_SCALE(25));
261 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
263 dim_all_button.set_related_action (act);
267 mono_button.set_text (_("Mono"));
268 mono_button.set_name ("monitor section mono");
269 mono_button.set_size_request (-1, PX_SCALE(25));
270 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
272 mono_button.set_related_action (act);
277 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
278 gain_control->set_name("monitor section knob");
279 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
281 gain_display = new ArdourDisplay ();
282 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
283 gain_display->add_controllable_preset(_("0 dB"), 0.0);
284 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
285 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
286 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
287 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
288 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
290 Label* output_label = manage (new Label (_("Output")));
291 output_label->set_name (X_("MonitorSectionLabel"));
293 output_button = new ArdourButton ();
294 output_button->set_text (_("Output"));
295 output_button->set_name (X_("monitor section cut")); // XXX
296 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
297 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
299 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
300 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
301 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
302 channel_table_scroller.show ();
303 channel_table_scroller.add (channel_table_viewport);
305 channel_size_group->add_widget (channel_table_header);
306 channel_table_header.resize (1, 5);
308 Label* l1 = manage (new Label (X_(" ")));
309 l1->set_name (X_("MonitorSectionLabel"));
310 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
312 l1 = manage (new Label (_("Mute")));
313 l1->set_name (X_("MonitorSectionLabel"));
314 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
316 l1 = manage (new Label (_("Dim")));
317 l1->set_name (X_("MonitorSectionLabel"));
318 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
320 l1 = manage (new Label (_("Solo")));
321 l1->set_name (X_("MonitorSectionLabel"));
322 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
324 l1 = manage (new Label (_("Inv")));
325 l1->set_name (X_("MonitorSectionLabel"));
326 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
328 channel_table_header.show ();
331 /****************************************************************************
332 * LAYOUT top to bottom
335 // solo, iso information
336 HBox* rude_box = manage (new HBox);
337 rude_box->set_spacing (PX_SCALE(4));
338 rude_box->set_homogeneous (true);
339 rude_box->pack_start (rude_solo_button, true, true);
340 rude_box->pack_start (rude_iso_button, true, true);
342 // solo options (right align)
343 HBox* tbx1 = manage (new HBox);
344 tbx1->pack_end (exclusive_solo_button, false, false);
346 HBox* tbx2 = manage (new HBox);
347 tbx2->pack_end (solo_mute_override_button, false, false);
349 HBox* tbx3 = manage (new HBox);
350 tbx3->pack_end (toggle_processorbox_button, false, false);
352 HBox* tbx0 = manage (new HBox); // space
354 // combined solo mode (Sip, AFL, PFL) & solo options
355 Table *solo_tbl = manage (new Table);
356 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
357 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
358 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
359 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
360 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
361 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
362 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
364 // boost, cut, dim volume control
365 Table *level_tbl = manage (new Table);
366 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
367 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
368 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
370 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
371 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
372 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
374 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
375 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
379 HBox* mono_dim_box = manage (new HBox);
380 mono_dim_box->set_spacing (PX_SCALE(4));
381 mono_dim_box->set_homogeneous (true);
382 mono_dim_box->pack_start (mono_button, true, true);
383 mono_dim_box->pack_end (dim_all_button, true, true);
386 Label* spin_label = manage (new Label (_("Monitor")));
387 VBox* spin_packer = manage (new VBox);
388 spin_packer->set_spacing (PX_SCALE(2));
389 spin_packer->pack_start (*spin_label, false, false);
390 spin_packer->pack_start (*gain_control, false, false);
391 spin_packer->pack_start (*gain_display, false, false);
393 master_packer.pack_start (*spin_packer, true, false);
395 // combined gain section (channels, mute, dim)
396 VBox* lower_packer = manage (new VBox);
397 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
398 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
399 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
400 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
402 // calc height of mixer scrollbar
403 int scrollbar_height = 0;
405 Gtk::Window window (WINDOW_TOPLEVEL);
406 HScrollbar scrollbar;
407 window.add (scrollbar);
408 scrollbar.set_name ("MixerWindow");
409 scrollbar.ensure_style();
410 Gtk::Requisition requisition(scrollbar.size_request ());
411 scrollbar_height = requisition.height;
414 // output port select
415 VBox* out_packer = manage (new VBox);
416 out_packer->set_spacing (PX_SCALE(2));
417 out_packer->pack_start (*output_label, false, false);
418 out_packer->pack_start (*output_button, false, false);
420 /****************************************************************************
423 vpacker.set_border_width (PX_SCALE(3));
424 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
425 vpacker.pack_start (rude_audition_button, false, false, 0);
426 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
427 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
428 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
429 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
430 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
431 vpacker.pack_end (*out_packer, false, false,
433 scrollbar_height - 2 /* no outer sample */
435 scrollbar_height + 2 /* sample borders */
439 hpacker.set_spacing (0);
440 hpacker.pack_start (vpacker, true, true);
444 gain_control->show_all ();
445 gain_display->show_all ();
446 dim_control->show_all ();
447 dim_display->show_all();
448 solo_boost_control->show_all ();
449 solo_boost_display->show_all();
451 mono_dim_box->show ();
452 spin_packer->show ();
453 master_packer.show ();
456 solo_tbl->show_all();
458 lower_packer->show ();
465 assign_controllables ();
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 output_changed_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 = Glib::RefPtr<ToggleAction>::cast_dynamic (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);
589 /* These are not actually dependent on the Session, but they
590 * need to be set after construction, not during, and
591 * this is as good a place as any.
594 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
595 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
597 _route = _session->monitor_out ();
600 /* session with monitor section */
601 _monitor = _route->monitor_control ();
602 assign_controllables ();
603 _route->output()->changed.connect (output_changed_connections, invalidator (*this),
604 boost::bind (&MonitorSection::update_output_display, this),
606 insert_box->set_route (_route);
607 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
608 _route->output()->PortCountChanged.connect (output_changed_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
609 _route->DropReferences.connect (*this, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
611 if (_ui_initialized) {
612 update_processor_box ();
615 ActionManager::set_sensitive (monitor_actions, true);
616 ActionManager::set_sensitive (solo_actions, true);
619 /* session with no monitor section */
620 output_changed_connections.drop_connections();
623 delete _output_selector;
624 _output_selector = 0;
626 ActionManager::set_sensitive (monitor_actions, false);
627 /* this action needs to always be true in this * scenaro, so that we can turn it back on*/
628 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
629 ActionManager::set_sensitive (solo_actions, true);
632 /* make sure the state of this action reflects reality */
633 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_active (_route != 0);
643 assign_controllables ();
645 ActionManager::set_sensitive (monitor_actions, false);
646 ActionManager::set_sensitive (solo_actions, false);
651 MonitorSection::drop_route ()
653 output_changed_connections.drop_connections();
656 control_connections.drop_connections ();
657 rude_iso_button.unset_active_state ();
658 rude_solo_button.unset_active_state ();
659 delete _output_selector;
660 _output_selector = 0;
663 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
665 cut.set_name (X_("mute button"));
666 dim.set_name (X_("monitor section dim"));
667 solo.set_name (X_("solo button"));
668 invert.set_name (X_("invert button"));
670 cut.unset_flags (Gtk::CAN_FOCUS);
671 dim.unset_flags (Gtk::CAN_FOCUS);
672 solo.unset_flags (Gtk::CAN_FOCUS);
673 invert.unset_flags (Gtk::CAN_FOCUS);
677 MonitorSection::populate_buttons ()
684 channel_size_group->remove_widget (*channel_table);
685 delete channel_table;
688 channel_table = new Gtk::Table();
690 channel_table->set_col_spacings (6);
691 channel_table->set_row_spacings (6);
692 channel_table->set_homogeneous (true);
694 channel_size_group->add_widget (*channel_table);
695 channel_table->show ();
696 table_hpacker.pack_start (*channel_table, true, true);
698 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
701 _channel_buttons.clear ();
703 Glib::RefPtr<Action> act;
704 uint32_t nchans = _monitor->output_streams().n_audio();
706 channel_table->resize (nchans, 5);
708 const uint32_t row_offset = 0;
710 for (uint32_t i = 0; i < nchans; ++i) {
723 snprintf (buf, sizeof (buf), "%d", i+1);
727 Label* label = manage (new Label (l));
728 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
730 ChannelButtonSet* cbs = new ChannelButtonSet;
732 _channel_buttons.push_back (cbs);
734 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
735 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
736 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
737 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
739 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
740 act = ActionManager::get_action (X_("Monitor"), buf);
742 cbs->cut.set_related_action (act);
745 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
746 act = ActionManager::get_action (X_("Monitor"), buf);
748 cbs->dim.set_related_action (act);
751 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
752 act = ActionManager::get_action (X_("Monitor"), buf);
754 cbs->solo.set_related_action (act);
757 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
758 act = ActionManager::get_action (X_("Monitor"), buf);
760 cbs->invert.set_related_action (act);
764 channel_table->show_all ();
766 if (channel_table_scroller.get_parent()) {
767 /* scroller is packed, so remove it */
768 channel_table_packer.remove (channel_table_scroller);
771 if (table_hpacker.get_parent () == &channel_table_packer) {
772 /* this occurs when the table hpacker is directly
773 packed, so remove it.
775 channel_table_packer.remove (table_hpacker);
776 } else if (table_hpacker.get_parent()) {
777 channel_table_viewport.remove ();
781 /* put the table into a scrolled window, and then put
782 * that into the channel vpacker, after the table header
784 channel_table_viewport.add (table_hpacker);
785 channel_table_packer.pack_start (channel_table_scroller, true, true);
786 channel_table_viewport.show ();
787 channel_table_scroller.show ();
790 /* just put the channel table itself into the channel
791 * vpacker, after the table header
793 channel_table_packer.pack_start (table_hpacker, true, true);
794 channel_table_scroller.hide ();
796 table_hpacker.show ();
797 channel_table->show ();
801 MonitorSection::toggle_exclusive_solo ()
807 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
811 MonitorSection::toggle_mute_overrides_solo ()
817 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), "toggle-mute-overrides-solo");
819 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
820 Config->set_solo_mute_override (tact->get_active());
825 MonitorSection::dim_all ()
831 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
833 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
834 _monitor->set_dim_all (tact->get_active());
840 MonitorSection::cut_all ()
846 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
848 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
849 _monitor->set_cut_all (tact->get_active());
854 MonitorSection::mono ()
860 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
862 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
863 _monitor->set_mono (tact->get_active());
868 MonitorSection::cut_channel (uint32_t chn)
875 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
877 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
879 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
880 _monitor->set_cut (chn, tact->get_active());
885 MonitorSection::dim_channel (uint32_t chn)
892 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
894 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
896 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
897 _monitor->set_dim (chn, tact->get_active());
903 MonitorSection::solo_channel (uint32_t chn)
910 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
912 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
914 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
915 _monitor->set_solo (chn, tact->get_active());
921 MonitorSection::invert_channel (uint32_t chn)
928 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
930 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
932 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
933 _monitor->set_polarity (chn, tact->get_active());
938 MonitorSection::register_actions ()
942 Glib::RefPtr<Action> act;
944 /* ...will get sensitized if a mon-session is added */
946 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
947 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
949 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
950 ActionManager::register_toggle_action (monitor_actions, "monitor-mono", _("Monitor Section: Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
951 ActionManager::register_toggle_action (monitor_actions, "monitor-cut-all", _("Monitor Section: Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
952 ActionManager::register_toggle_action (monitor_actions, "monitor-dim-all", _("Monitor Section: Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
954 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
955 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
958 for (uint32_t chn = 0; chn < 16; ++chn) {
960 action_name = string_compose (X_("monitor-cut-%1"), chn);
961 action_descr = string_compose (_("Cut monitor channel %1"), chn);
962 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
963 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
965 action_name = string_compose (X_("monitor-dim-%1"), chn);
966 action_descr = string_compose (_("Dim monitor channel %1"), chn);
967 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
968 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
970 action_name = string_compose (X_("monitor-solo-%1"), chn);
971 action_descr = string_compose (_("Solo monitor channel %1"), chn);
972 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
973 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
975 action_name = string_compose (X_("monitor-invert-%1"), chn);
976 action_descr = string_compose (_("Invert monitor channel %1"), chn);
977 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
978 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
982 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
983 RadioAction::Group solo_group;
985 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
986 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
987 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
988 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
989 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
990 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
992 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
993 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
994 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
995 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
999 MonitorSection::solo_use_in_place ()
1001 /* this is driven by a toggle on a radio group, and so is invoked twice,
1002 once for the item that became inactive and once for the one that became
1006 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
1009 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1011 if (!ract->get_active ()) {
1012 /* We are turning SiP off, which means that AFL or PFL will be turned on
1013 shortly; don't update the solo model in the mean time, as if the currently
1014 configured listen position is not the one that is about to be turned on,
1015 things will go wrong.
1017 _inhibit_solo_model_update = true;
1019 Config->set_solo_control_is_listen_control (!ract->get_active());
1020 _inhibit_solo_model_update = false;
1026 MonitorSection::solo_use_afl ()
1028 /* this is driven by a toggle on a radio group, and so is invoked twice,
1029 once for the item that became inactive and once for the one that became
1033 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
1035 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1037 if (ract->get_active()) {
1038 Config->set_solo_control_is_listen_control (true);
1039 Config->set_listen_position (AfterFaderListen);
1046 MonitorSection::solo_use_pfl ()
1048 /* this is driven by a toggle on a radio group, and so is invoked twice,
1049 once for the item that became inactive and once for the one that became
1053 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1055 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1057 if (ract->get_active()) {
1058 Config->set_solo_control_is_listen_control (true);
1059 Config->set_listen_position (PreFaderListen);
1066 MonitorSection::update_solo_model ()
1068 if (_inhibit_solo_model_update) {
1072 const char* action_name = 0;
1073 Glib::RefPtr<Action> act;
1075 if (Config->get_solo_control_is_listen_control()) {
1076 switch (Config->get_listen_position()) {
1077 case AfterFaderListen:
1078 action_name = X_("solo-use-afl");
1080 case PreFaderListen:
1081 action_name = X_("solo-use-pfl");
1085 action_name = X_("solo-use-in-place");
1088 act = ActionManager::get_action (X_("Solo"), action_name);
1091 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1093 /* because these are radio buttons, one of them will be
1094 active no matter what. to trigger a change in the
1095 action so that the view picks it up, toggle it.
1097 if (ract->get_active()) {
1098 ract->set_active (false);
1100 ract->set_active (true);
1107 MonitorSection::map_state ()
1109 if (!_route || !_monitor) {
1113 update_solo_model ();
1115 Glib::RefPtr<Action> act;
1116 Glib::RefPtr<ToggleAction> tact;
1118 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1120 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1122 tact->set_active (_monitor->cut_all());
1126 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1128 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1130 tact->set_active (_monitor->dim_all());
1134 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1136 tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1138 tact->set_active (_monitor->mono());
1142 uint32_t nchans = _monitor->output_streams().n_audio();
1144 assert (nchans == _channel_buttons.size ());
1146 for (uint32_t n = 0; n < nchans; ++n) {
1148 char action_name[32];
1150 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1151 act = ActionManager::get_action (X_("Monitor"), action_name);
1153 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1155 tact->set_active (_monitor->cut (n));
1159 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1160 act = ActionManager::get_action (X_("Monitor"), action_name);
1162 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1164 tact->set_active (_monitor->dimmed (n));
1168 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1169 act = ActionManager::get_action (X_("Monitor"), action_name);
1171 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1173 tact->set_active (_monitor->soloed (n));
1177 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1178 act = ActionManager::get_action (X_("Monitor"), action_name);
1180 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1182 tact->set_active (_monitor->inverted (n));
1189 MonitorSection::do_blink (bool onoff)
1191 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1196 audition_blink (onoff);
1200 MonitorSection::audition_blink (bool onoff)
1202 if (_session == 0) {
1206 if (_session->is_auditioning()) {
1207 rude_audition_button.set_active (onoff);
1209 rude_audition_button.set_active (false);
1214 MonitorSection::solo_blink (bool onoff)
1216 if (_session == 0) {
1220 if (_session->soloing() || _session->listening()) {
1221 rude_solo_button.set_active (onoff);
1223 if (_session->soloing()) {
1224 if (_session->solo_isolated()) {
1225 rude_iso_button.set_active (onoff);
1227 rude_iso_button.set_active (false);
1232 rude_solo_button.set_active (false);
1233 rude_iso_button.set_active (false);
1238 MonitorSection::cancel_isolate (GdkEventButton*)
1241 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1242 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1249 MonitorSection::cancel_audition (GdkEventButton*)
1252 _session->cancel_audition();
1257 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1258 if (action && action->get_active() != value) { \
1259 action->set_active(value); \
1263 MonitorSection::parameter_changed (std::string name)
1265 if (name == "solo-control-is-listen-control") {
1266 update_solo_model ();
1267 } else if (name == "listen-position") {
1268 update_solo_model ();
1269 } else if (name == "solo-mute-override") {
1270 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1271 } else if (name == "exclusive-solo") {
1272 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1273 } else if (name == "use-monitor-bus") {
1274 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), Config->get_use_monitor_bus ());
1279 MonitorSection::assign_controllables ()
1281 boost::shared_ptr<Controllable> none;
1283 if (!gain_control) {
1284 /* too early - GUI controls not set up yet */
1289 solo_cut_control->set_controllable (_session->solo_cut_control());
1290 solo_cut_display->set_controllable (_session->solo_cut_control());
1292 solo_cut_control->set_controllable (none);
1293 solo_cut_display->set_controllable (none);
1297 gain_control->set_controllable (_route->gain_control());
1298 gain_display->set_controllable (_route->gain_control());
1300 gain_control->set_controllable (none);
1305 cut_all_button.set_controllable (_monitor->cut_control());
1306 cut_all_button.watch ();
1307 dim_all_button.set_controllable (_monitor->dim_control());
1308 dim_all_button.watch ();
1309 mono_button.set_controllable (_monitor->mono_control());
1310 mono_button.watch ();
1312 dim_control->set_controllable (_monitor->dim_level_control ());
1313 dim_display->set_controllable (_monitor->dim_level_control ());
1314 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1315 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1319 cut_all_button.set_controllable (none);
1320 dim_all_button.set_controllable (none);
1321 mono_button.set_controllable (none);
1323 dim_control->set_controllable (none);
1324 dim_display->set_controllable (none);
1325 solo_boost_control->set_controllable (none);
1326 solo_boost_display->set_controllable (none);
1331 MonitorSection::state_id() const
1333 return "monitor-section";
1337 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1339 using namespace Menu_Helpers;
1341 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1345 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1346 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1350 if (i != output_menu_bundles.end()) {
1354 output_menu_bundles.push_back (b);
1356 MenuList& citems = output_menu.items();
1358 std::string n = b->name ();
1359 replace_all (n, "_", " ");
1361 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1365 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1368 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1370 if (std::find (current.begin(), current.end(), c) == current.end()) {
1371 _route->output()->connect_ports_to_bundle (c, true, this);
1373 _route->output()->disconnect_ports_from_bundle (c, this);
1378 MonitorSection::output_release (GdkEventButton *ev)
1380 switch (ev->button) {
1382 edit_output_configuration ();
1389 struct RouteCompareByName {
1390 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1391 return a->name().compare (b->name()) < 0;
1396 MonitorSection::output_press (GdkEventButton *ev)
1398 using namespace Menu_Helpers;
1400 MessageDialog msg (_("No session - no I/O changes are possible"));
1405 MenuList& citems = output_menu.items();
1406 switch (ev->button) {
1409 return false; //wait for the mouse-up to pop the dialog
1413 output_menu.set_name ("ArdourContextMenu");
1415 output_menu_bundles.clear ();
1417 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1419 citems.push_back (SeparatorElem());
1420 uint32_t const n_with_separator = citems.size ();
1422 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1424 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1426 /* give user bundles first chance at being in the menu */
1428 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1429 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1430 maybe_add_bundle_to_output_menu (*i, current);
1434 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1435 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1436 maybe_add_bundle_to_output_menu (*i, current);
1440 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1441 RouteList copy = *routes;
1442 copy.sort (RouteCompareByName ());
1443 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1444 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1447 if (citems.size() == n_with_separator) {
1448 /* no routes added; remove the separator */
1452 citems.push_back (SeparatorElem());
1453 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1455 output_menu.popup (1, ev->time);
1466 MonitorSection::update_output_display ()
1468 if (!_route || !_monitor || _session->deletion_in_progress()) {
1474 boost::shared_ptr<Port> port;
1475 vector<string> port_connections;
1477 uint32_t total_connection_count = 0;
1478 uint32_t io_connection_count = 0;
1479 uint32_t ardour_connection_count = 0;
1480 uint32_t system_connection_count = 0;
1481 uint32_t other_connection_count = 0;
1483 ostringstream label;
1485 bool have_label = false;
1486 bool each_io_has_one_connection = true;
1488 string connection_name;
1489 string ardour_track_name;
1490 string other_connection_type;
1491 string system_ports;
1494 ostringstream tooltip;
1495 char * tooltip_cstr;
1497 io_count = _route->n_outputs().n_total();
1498 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1501 for (io_index = 0; io_index < io_count; ++io_index) {
1503 port = _route->output()->nth (io_index);
1505 //ignore any port connections that don't match our DataType
1506 if (port->type() != DataType::AUDIO) {
1510 port_connections.clear ();
1511 port->get_connections(port_connections);
1512 io_connection_count = 0;
1514 if (!port_connections.empty()) {
1515 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1517 string& connection_name (*i);
1519 if (connection_name.find("system:") == 0) {
1520 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1523 if (io_connection_count == 0) {
1524 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1526 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1529 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1532 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1533 if (ardour_track_name.empty()) {
1534 // "ardour:Master/in 1" -> "ardour:Master/"
1535 string::size_type slash = connection_name.find("/");
1536 if (slash != string::npos) {
1537 ardour_track_name = connection_name.substr(0, slash + 1);
1541 if (connection_name.find(ardour_track_name) == 0) {
1542 ++ardour_connection_count;
1544 } else if (!pn.empty()) {
1545 if (system_ports.empty()) {
1548 system_ports += "/" + pn;
1550 if (connection_name.find("system:") == 0) {
1551 ++system_connection_count;
1553 } else if (connection_name.find("system:") == 0) {
1554 // "system:playback_123" -> "123"
1555 system_port = connection_name.substr(16);
1556 if (system_ports.empty()) {
1557 system_ports += system_port;
1559 system_ports += "/" + system_port;
1562 ++system_connection_count;
1564 if (other_connection_type.empty()) {
1565 // "jamin:in 1" -> "jamin:"
1566 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1569 if (connection_name.find(other_connection_type) == 0) {
1570 ++other_connection_count;
1574 ++total_connection_count;
1575 ++io_connection_count;
1579 if (io_connection_count != 1) {
1580 each_io_has_one_connection = false;
1584 if (total_connection_count == 0) {
1585 tooltip << endl << _("Disconnected");
1588 tooltip_cstr = new char[tooltip.str().size() + 1];
1589 strcpy(tooltip_cstr, tooltip.str().c_str());
1591 set_tooltip (output_button, tooltip_cstr, "");
1593 if (each_io_has_one_connection) {
1594 if (total_connection_count == ardour_connection_count) {
1595 // all connections are to the same track in ardour
1596 // "ardour:Master/" -> "Master"
1597 string::size_type slash = ardour_track_name.find("/");
1598 if (slash != string::npos) {
1599 label << ardour_track_name.substr(7, slash - 7);
1602 } else if (total_connection_count == system_connection_count) {
1603 // all connections are to system ports
1604 label << system_ports;
1606 } else if (total_connection_count == other_connection_count) {
1607 // all connections are to the same external program eg jamin
1608 // "jamin:" -> "jamin"
1609 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1615 if (total_connection_count == 0) {
1619 // Odd configuration
1620 label << "*" << total_connection_count << "*";
1624 output_button->set_text (label.str());
1628 MonitorSection::disconnect_output ()
1631 _route->output()->disconnect(this);
1636 MonitorSection::edit_output_configuration ()
1638 if (_output_selector == 0) {
1639 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1641 _output_selector->present ();
1645 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1650 boost::shared_ptr<Port> a = wa.lock ();
1651 boost::shared_ptr<Port> b = wb.lock ();
1652 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1653 update_output_display ();
1658 MonitorSection::load_bindings ()
1660 bindings = Bindings::get_bindings (X_("Monitor Section"));
1664 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1666 boost::shared_ptr<Processor> processor (p.lock ());
1667 if (!processor || !processor->display_to_user()) {
1670 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1677 MonitorSection::count_processors ()
1679 uint32_t processor_count = 0;
1681 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1683 return processor_count;
1687 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1689 update_processor_box ();
1693 MonitorSection::use_others_actions ()
1695 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1699 MonitorSection::toggle_use_monitor_section ()
1705 Config->set_use_monitor_bus (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active());