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/bindable_button.h"
27 #include "gtkmm2ext/tearoff.h"
28 #include "gtkmm2ext/actions.h"
29 #include "gtkmm2ext/utils.h"
31 #include <gtkmm/menu.h>
32 #include <gtkmm/menuitem.h>
34 #include "ardour/amp.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/monitor_processor.h"
37 #include "ardour/port.h"
38 #include "ardour/route.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/user_bundle.h"
41 #include "ardour/plugin_manager.h"
43 #include "ardour_ui.h"
44 #include "gui_thread.h"
46 #include "monitor_section.h"
47 #include "public_editor.h"
50 #include "ui_config.h"
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
58 using namespace Gtkmm2ext;
62 Glib::RefPtr<ActionGroup> MonitorSection::monitor_actions;
63 Gtkmm2ext::ActionMap MonitorSection::myactions (X_("monitor section"));
64 Gtkmm2ext::Bindings* MonitorSection::bindings = 0;
66 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68 MonitorSection::MonitorSection (Session* s)
69 : SessionHandlePtr (s)
72 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
73 , *channel_table_scroller.get_vadjustment ())
76 , solo_boost_control (0)
77 , solo_cut_control (0)
80 , solo_boost_display (0)
81 , solo_cut_display (0)
82 , _output_selector (0)
83 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
84 , afl_button (_("AFL"), ArdourButton::led_default_elements)
85 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
86 , exclusive_solo_button (ArdourButton::led_default_elements)
87 , solo_mute_override_button (ArdourButton::led_default_elements)
88 , toggle_processorbox_button (ArdourButton::default_elements)
89 , _inhibit_solo_model_update (false)
90 , _ui_initialized (false)
93 using namespace Menu_Helpers;
95 Glib::RefPtr<Action> act;
97 if (!monitor_actions) {
102 set_data ("ardour-bindings", bindings);
104 _plugin_selector = new PluginSelector (PluginManager::instance());
105 insert_box = new ProcessorBox (_session, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
106 insert_box->set_no_show_all ();
108 // 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 act = ActionManager::get_action (X_("Main"), X_("cancel-solo"));
128 rude_solo_button.set_related_action (act);
129 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
131 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
132 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
134 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
135 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
137 /* SIP, AFL, PFL radio */
139 solo_in_place_button.set_name ("monitor section solo model");
140 afl_button.set_name ("monitor section solo model");
141 pfl_button.set_name ("monitor section solo model");
143 solo_in_place_button.set_led_left (true);
144 afl_button.set_led_left (true);
145 pfl_button.set_led_left (true);
147 solo_in_place_button.show ();
151 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
152 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
154 solo_in_place_button.set_related_action (act);
157 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
158 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
160 afl_button.set_related_action (act);
163 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
164 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
166 pfl_button.set_related_action (act);
169 /* Solo option buttons */
170 exclusive_solo_button.set_text (_("Excl. Solo"));
171 exclusive_solo_button.set_name (X_("monitor section solo option"));
172 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
174 act = ActionManager::get_action (X_("Monitor"), X_("toggle-exclusive-solo"));
176 exclusive_solo_button.set_related_action (act);
179 solo_mute_override_button.set_text (_("Solo ยป Mute"));
180 solo_mute_override_button.set_name (X_("monitor section solo option"));
181 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
183 act = ActionManager::get_action (X_("Monitor"), X_("toggle-mute-overrides-solo"));
185 solo_mute_override_button.set_related_action (act);
188 /* Processor Box hide/shos */
189 toggle_processorbox_button.set_text (_("Processors"));
190 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
191 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
193 proctoggle = ActionManager::get_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
194 toggle_processorbox_button.set_related_action (proctoggle);
197 Label* solo_boost_label;
198 Label* solo_cut_label;
201 /* Solo Boost Knob */
203 solo_boost_control = new ArdourKnob ();
204 solo_boost_control->set_name("monitor section knob");
205 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
206 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
208 solo_boost_display = new ArdourDisplay ();
209 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
210 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
211 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
212 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
213 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
215 solo_boost_label = manage (new Label (_("Solo Boost")));
219 solo_cut_control = new ArdourKnob ();
220 solo_cut_control->set_name ("monitor section knob");
221 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
222 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
224 solo_cut_display = new ArdourDisplay ();
225 solo_cut_display->set_name("monitor section dropdown"); // XXX
226 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
227 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
228 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
229 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
230 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
231 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
233 solo_cut_label = manage (new Label (_("SiP Cut")));
237 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
238 dim_control->set_name ("monitor section knob");
239 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
240 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
242 dim_display = new ArdourDisplay ();
243 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
244 dim_display->add_controllable_preset(_("0 dB"), 0.0);
245 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
246 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
247 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
248 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
250 dim_label = manage (new Label (_("Dim")));
253 cut_all_button.set_text (_("Mute"));
254 cut_all_button.set_name ("mute button");
255 cut_all_button.set_size_request (-1, PX_SCALE(30));
256 cut_all_button.show ();
258 act = ActionManager::get_action (X_("Monitor"), X_("monitor-cut-all"));
260 cut_all_button.set_related_action (act);
264 dim_all_button.set_text (_("Dim"));
265 dim_all_button.set_name ("monitor section dim");
266 dim_all_button.set_size_request (-1, PX_SCALE(25));
267 act = ActionManager::get_action (X_("Monitor"), X_("monitor-dim-all"));
269 dim_all_button.set_related_action (act);
273 mono_button.set_text (_("Mono"));
274 mono_button.set_name ("monitor section mono");
275 mono_button.set_size_request (-1, PX_SCALE(25));
276 act = ActionManager::get_action (X_("Monitor"), X_("monitor-mono"));
278 mono_button.set_related_action (act);
283 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
284 gain_control->set_name("monitor section knob");
285 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
287 gain_display = new ArdourDisplay ();
288 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
289 gain_display->add_controllable_preset(_("0 dB"), 0.0);
290 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
291 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
292 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
293 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
294 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
296 Label* output_label = manage (new Label (_("Output")));
297 output_label->set_name (X_("MonitorSectionLabel"));
299 output_button = new ArdourButton ();
300 output_button->set_text (_("Output"));
301 output_button->set_name (X_("monitor section cut")); // XXX
302 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
303 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
305 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
306 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
307 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
308 channel_table_scroller.show ();
309 channel_table_scroller.add (channel_table_viewport);
311 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
312 channel_size_group->add_widget (channel_table_header);
313 channel_size_group->add_widget (channel_table);
315 channel_table_header.resize (1, 5);
317 Label* l1 = manage (new Label (X_(" ")));
318 l1->set_name (X_("MonitorSectionLabel"));
319 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
321 l1 = manage (new Label (_("Mute")));
322 l1->set_name (X_("MonitorSectionLabel"));
323 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
325 l1 = manage (new Label (_("Dim")));
326 l1->set_name (X_("MonitorSectionLabel"));
327 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
329 l1 = manage (new Label (_("Solo")));
330 l1->set_name (X_("MonitorSectionLabel"));
331 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
333 l1 = manage (new Label (_("Inv")));
334 l1->set_name (X_("MonitorSectionLabel"));
335 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
337 channel_table_header.show ();
340 /****************************************************************************
341 * LAYOUT top to bottom
344 // solo, iso information
345 HBox* rude_box = manage (new HBox);
346 rude_box->set_spacing (PX_SCALE(4));
347 rude_box->set_homogeneous (true);
348 rude_box->pack_start (rude_solo_button, true, true);
349 rude_box->pack_start (rude_iso_button, true, true);
351 // solo options (right align)
352 HBox* tbx1 = manage (new HBox);
353 tbx1->pack_end (exclusive_solo_button, false, false);
355 HBox* tbx2 = manage (new HBox);
356 tbx2->pack_end (solo_mute_override_button, false, false);
358 HBox* tbx3 = manage (new HBox);
359 tbx3->pack_end (toggle_processorbox_button, false, false);
361 HBox* tbx0 = manage (new HBox); // space
363 // combined solo mode (Sip, AFL, PFL) & solo options
364 Table *solo_tbl = manage (new Table);
365 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
366 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
367 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
368 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
369 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
370 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
371 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
373 // boost, cut, dim volume control
374 Table *level_tbl = manage (new Table);
375 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
376 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
377 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
379 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
380 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
381 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
383 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
385 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
387 /* note that we don't pack the table_hpacker till later
388 * -> top level channel_table_packer */
389 table_hpacker.pack_start (channel_table, true, true);
392 HBox* mono_dim_box = manage (new HBox);
393 mono_dim_box->set_spacing (PX_SCALE(4));
394 mono_dim_box->set_homogeneous (true);
395 mono_dim_box->pack_start (mono_button, true, true);
396 mono_dim_box->pack_end (dim_all_button, true, true);
399 Label* spin_label = manage (new Label (_("Monitor")));
400 VBox* spin_packer = manage (new VBox);
401 spin_packer->set_spacing (PX_SCALE(2));
402 spin_packer->pack_start (*spin_label, false, false);
403 spin_packer->pack_start (*gain_control, false, false);
404 spin_packer->pack_start (*gain_display, false, false);
406 master_packer.pack_start (*spin_packer, true, false);
408 // combined gain section (channels, mute, dim)
409 VBox* lower_packer = manage (new VBox);
410 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
411 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
412 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
413 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
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, PX_SCALE(3));
434 hpacker.set_spacing (0);
435 hpacker.pack_start (vpacker, true, true);
439 gain_control->show_all ();
440 gain_display->show_all ();
441 dim_control->show_all ();
442 dim_display->show_all();
443 solo_boost_control->show_all ();
444 solo_boost_display->show_all();
446 mono_dim_box->show ();
447 spin_packer->show ();
448 master_packer.show ();
449 channel_table.show ();
452 solo_tbl->show_all();
454 lower_packer->show ();
462 assign_controllables ();
464 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
465 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
467 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
468 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
469 set_flags (CAN_FOCUS);
471 _tearoff = new TearOff (*this);
473 if (!UIConfiguration::instance().get_floating_monitor_section()) {
474 /* if torn off, make this a normal window
475 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
477 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
479 _tearoff->tearoff_window().set_title (X_("Monitor"));
480 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
482 update_output_display ();
483 update_processor_box ();
484 _ui_initialized = true;
486 /* catch changes that affect us */
487 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
488 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
490 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
493 MonitorSection::~MonitorSection ()
495 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
499 _channel_buttons.clear ();
500 _output_changed_connection.disconnect ();
502 delete insert_box; insert_box = 0;
503 delete output_button; output_button = 0;
504 delete gain_control; gain_control = 0;
505 delete gain_display; gain_display = 0;
506 delete dim_control; dim_control = 0;
507 delete dim_display; dim_display = 0;
508 delete solo_boost_control; solo_boost_control = 0;
509 delete solo_boost_display; solo_boost_display = 0;
510 delete solo_cut_control; solo_cut_control = 0;
511 delete solo_cut_display; solo_cut_display = 0;
512 delete _tearoff; _tearoff = 0;
513 delete _output_selector; _output_selector = 0;
517 MonitorSection::enter_handler (GdkEventCrossing* ev)
524 MonitorSection::leave_handler (GdkEventCrossing* ev)
526 switch (ev->detail) {
527 case GDK_NOTIFY_INFERIOR:
533 /* cancel focus if we're not torn off. With X11 WM's that do
534 * focus-follows-mouse, focus will be taken from us anyway.
537 Widget* top = get_toplevel();
539 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
540 Window* win = dynamic_cast<Window*> (top);
541 gtk_window_set_focus (win->gobj(), 0);
548 MonitorSection::update_processor_box ()
550 bool show_processor_box = Glib::RefPtr<ToggleAction>::cast_dynamic (proctoggle)->get_active ();
552 if (count_processors () > 0 && !show_processor_box) {
553 toggle_processorbox_button.set_name (X_("monitor section processors present"));
555 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
558 if (insert_box->is_visible() == show_processor_box) {
562 if (show_processor_box) {
563 if (master_packer.get_parent()) {
564 master_packer.get_parent()->remove (master_packer);
567 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
569 if (master_packer.get_parent()) {
570 master_packer.get_parent()->remove (master_packer);
573 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
578 MonitorSection::set_session (Session* s)
580 RouteUI::set_session (s);
581 _plugin_selector->set_session (_session);
585 _route = _session->monitor_out ();
588 /* session with monitor section */
589 _monitor = _route->monitor_control ();
590 assign_controllables ();
591 _route->output()->changed.connect (_output_changed_connection, invalidator (*this),
592 boost::bind (&MonitorSection::update_output_display, this),
594 insert_box->set_route (_route);
595 _route->processors_changed.connect (*this, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
596 if (_ui_initialized) {
597 update_processor_box ();
600 /* session with no monitor section */
601 _output_changed_connection.disconnect();
604 delete _output_selector;
605 _output_selector = 0;
608 if (channel_table_scroller.get_parent()) {
609 /* scroller is packed, so remove it */
610 channel_table_packer.remove (channel_table_scroller);
613 if (table_hpacker.get_parent () == &channel_table_packer) {
614 /* this occurs when the table hpacker is directly
615 packed, so remove it.
617 channel_table_packer.remove (table_hpacker);
618 } else if (table_hpacker.get_parent()) {
619 channel_table_viewport.remove ();
622 if (_monitor->output_streams().n_audio() > 7) {
623 /* put the table into a scrolled window, and then put
624 * that into the channel vpacker, after the table header
626 channel_table_viewport.add (table_hpacker);
627 channel_table_packer.pack_start (channel_table_scroller, true, true);
628 channel_table_viewport.show ();
629 channel_table_scroller.show ();
632 /* just put the channel table itself into the channel
633 * vpacker, after the table header
636 channel_table_packer.pack_start (table_hpacker, true, true);
637 channel_table_scroller.hide ();
640 table_hpacker.show ();
641 channel_table.show ();
646 _output_changed_connection.disconnect();
649 control_connections.drop_connections ();
650 rude_iso_button.unset_active_state ();
651 rude_solo_button.unset_active_state ();
652 delete _output_selector;
653 _output_selector = 0;
655 assign_controllables ();
659 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
661 cut.set_name (X_("mute button"));
662 dim.set_name (X_("monitor section dim"));
663 solo.set_name (X_("solo button"));
664 invert.set_name (X_("invert button"));
666 cut.unset_flags (Gtk::CAN_FOCUS);
667 dim.unset_flags (Gtk::CAN_FOCUS);
668 solo.unset_flags (Gtk::CAN_FOCUS);
669 invert.unset_flags (Gtk::CAN_FOCUS);
673 MonitorSection::populate_buttons ()
679 Glib::RefPtr<Action> act;
680 uint32_t nchans = _monitor->output_streams().n_audio();
682 channel_table.resize (nchans, 5);
683 channel_table.set_col_spacings (6);
684 channel_table.set_row_spacings (6);
685 channel_table.set_homogeneous (true);
687 const uint32_t row_offset = 0;
689 for (uint32_t i = 0; i < nchans; ++i) {
702 snprintf (buf, sizeof (buf), "%d", i+1);
706 Label* label = manage (new Label (l));
707 channel_table.attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
709 ChannelButtonSet* cbs = new ChannelButtonSet;
711 _channel_buttons.push_back (cbs);
713 channel_table.attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
714 channel_table.attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
715 channel_table.attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
716 channel_table.attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
718 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
719 act = ActionManager::get_action (X_("Monitor"), buf);
721 cbs->cut.set_related_action (act);
724 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
725 act = ActionManager::get_action (X_("Monitor"), buf);
727 cbs->dim.set_related_action (act);
730 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
731 act = ActionManager::get_action (X_("Monitor"), buf);
733 cbs->solo.set_related_action (act);
736 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
737 act = ActionManager::get_action (X_("Monitor"), buf);
739 cbs->invert.set_related_action (act);
743 channel_table.show_all ();
747 MonitorSection::toggle_exclusive_solo ()
753 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo");
755 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
756 Config->set_exclusive_solo (tact->get_active());
762 MonitorSection::toggle_mute_overrides_solo ()
768 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo");
770 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
771 Config->set_solo_mute_override (tact->get_active());
776 MonitorSection::dim_all ()
782 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
784 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
785 _monitor->set_dim_all (tact->get_active());
791 MonitorSection::cut_all ()
797 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
799 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
800 _monitor->set_cut_all (tact->get_active());
805 MonitorSection::mono ()
811 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
813 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
814 _monitor->set_mono (tact->get_active());
819 MonitorSection::cut_channel (uint32_t chn)
826 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
828 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
830 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
831 _monitor->set_cut (chn, tact->get_active());
836 MonitorSection::dim_channel (uint32_t chn)
843 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
845 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
847 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
848 _monitor->set_dim (chn, tact->get_active());
854 MonitorSection::solo_channel (uint32_t chn)
861 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
863 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
865 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
866 _monitor->set_solo (chn, tact->get_active());
872 MonitorSection::invert_channel (uint32_t chn)
879 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
881 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Monitor"), buf);
883 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
884 _monitor->set_polarity (chn, tact->get_active());
889 MonitorSection::register_actions ()
893 Glib::RefPtr<Action> act;
895 monitor_actions = myactions.create_action_group (X_("Monitor"));
897 myactions.register_toggle_action (monitor_actions, "monitor-mono", _("Switch monitor to mono"),
898 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorMono));
900 myactions.register_toggle_action (monitor_actions, "monitor-cut-all", _("Cut monitor"),
901 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorCutAll));
903 myactions.register_toggle_action (monitor_actions, "monitor-dim-all", _("Dim monitor"),
904 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), MonitorDimAll));
906 act = myactions.register_toggle_action (monitor_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
907 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleExclusiveSolo));
909 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
910 tact->set_active (Config->get_exclusive_solo());
912 act = myactions.register_toggle_action (monitor_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
913 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMuteOverridesSolo));
915 tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
916 tact->set_active (Config->get_solo_mute_override());
918 for (uint32_t chn = 0; chn < 16; ++chn) {
920 action_name = string_compose (X_("monitor-cut-%1"), chn);
921 action_descr = string_compose (_("Cut monitor channel %1"), chn);
922 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
923 sigc::bind (sigc::ptr_fun (action_proxy1), CutChannel, chn));
925 action_name = string_compose (X_("monitor-dim-%1"), chn);
926 action_descr = string_compose (_("Dim monitor channel %1"), chn);
927 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
928 sigc::bind (sigc::ptr_fun (action_proxy1), DimChannel, chn));
930 action_name = string_compose (X_("monitor-solo-%1"), chn);
931 action_descr = string_compose (_("Solo monitor channel %1"), chn);
932 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
933 sigc::bind (sigc::ptr_fun (action_proxy1), SoloChannel, chn));
935 action_name = string_compose (X_("monitor-invert-%1"), chn);
936 action_descr = string_compose (_("Invert monitor channel %1"), chn);
937 myactions.register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
938 sigc::bind (sigc::ptr_fun (action_proxy1), InvertChannel, chn));
943 Glib::RefPtr<ActionGroup> solo_actions = myactions.create_action_group (X_("Solo"));
944 RadioAction::Group solo_group;
946 myactions.register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
947 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseInPlace));
948 myactions.register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
949 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUseAFL));
950 myactions.register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
951 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), SoloUsePFL));
953 myactions.register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
954 sigc::bind (sigc::ptr_fun (MonitorSection::action_proxy0), ToggleMonitorProcessorBox));
959 MonitorSection::solo_use_in_place ()
961 /* this is driven by a toggle on a radio group, and so is invoked twice,
962 once for the item that became inactive and once for the one that became
966 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
969 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
971 if (!ract->get_active ()) {
972 /* We are turning SiP off, which means that AFL or PFL will be turned on
973 shortly; don't update the solo model in the mean time, as if the currently
974 configured listen position is not the one that is about to be turned on,
975 things will go wrong.
977 _inhibit_solo_model_update = true;
979 Config->set_solo_control_is_listen_control (!ract->get_active());
980 _inhibit_solo_model_update = false;
986 MonitorSection::solo_use_afl ()
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<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
995 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
997 if (ract->get_active()) {
998 Config->set_solo_control_is_listen_control (true);
999 Config->set_listen_position (AfterFaderListen);
1006 MonitorSection::solo_use_pfl ()
1008 /* this is driven by a toggle on a radio group, and so is invoked twice,
1009 once for the item that became inactive and once for the one that became
1013 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
1015 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1017 if (ract->get_active()) {
1018 Config->set_solo_control_is_listen_control (true);
1019 Config->set_listen_position (PreFaderListen);
1026 MonitorSection::update_solo_model ()
1028 if (_inhibit_solo_model_update) {
1032 const char* action_name = 0;
1033 Glib::RefPtr<Action> act;
1035 if (Config->get_solo_control_is_listen_control()) {
1036 switch (Config->get_listen_position()) {
1037 case AfterFaderListen:
1038 action_name = X_("solo-use-afl");
1040 case PreFaderListen:
1041 action_name = X_("solo-use-pfl");
1045 action_name = X_("solo-use-in-place");
1048 act = ActionManager::get_action (X_("Solo"), action_name);
1051 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (act);
1053 /* because these are radio buttons, one of them will be
1054 active no matter what. to trigger a change in the
1055 action so that the view picks it up, toggle it.
1057 if (ract->get_active()) {
1058 ract->set_active (false);
1060 ract->set_active (true);
1067 MonitorSection::map_state ()
1069 if (!_route || !_monitor) {
1073 Glib::RefPtr<Action> act;
1075 update_solo_model ();
1077 act = ActionManager::get_action (X_("Monitor"), "monitor-cut-all");
1079 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1081 tact->set_active (_monitor->cut_all());
1085 act = ActionManager::get_action (X_("Monitor"), "monitor-dim-all");
1087 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1089 tact->set_active (_monitor->dim_all());
1093 act = ActionManager::get_action (X_("Monitor"), "monitor-mono");
1095 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1097 tact->set_active (_monitor->mono());
1101 uint32_t nchans = _monitor->output_streams().n_audio();
1103 assert (nchans == _channel_buttons.size ());
1105 for (uint32_t n = 0; n < nchans; ++n) {
1107 char action_name[32];
1109 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1110 act = ActionManager::get_action (X_("Monitor"), action_name);
1112 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1114 tact->set_active (_monitor->cut (n));
1118 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1119 act = ActionManager::get_action (X_("Monitor"), action_name);
1121 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1123 tact->set_active (_monitor->dimmed (n));
1127 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1128 act = ActionManager::get_action (X_("Monitor"), action_name);
1130 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1132 tact->set_active (_monitor->soloed (n));
1136 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1137 act = ActionManager::get_action (X_("Monitor"), action_name);
1139 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
1141 tact->set_active (_monitor->inverted (n));
1148 MonitorSection::do_blink (bool onoff)
1151 audition_blink (onoff);
1155 MonitorSection::audition_blink (bool onoff)
1157 if (_session == 0) {
1161 if (_session->is_auditioning()) {
1162 rude_audition_button.set_active (onoff);
1164 rude_audition_button.set_active (false);
1169 MonitorSection::solo_blink (bool onoff)
1171 if (_session == 0) {
1175 if (_session->soloing() || _session->listening()) {
1176 rude_solo_button.set_active (onoff);
1178 if (_session->soloing()) {
1179 if (_session->solo_isolated()) {
1180 rude_iso_button.set_active (onoff);
1182 rude_iso_button.set_active (false);
1187 rude_solo_button.set_active (false);
1188 rude_iso_button.set_active (false);
1193 MonitorSection::cancel_isolate (GdkEventButton*)
1196 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1197 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1204 MonitorSection::cancel_audition (GdkEventButton*)
1207 _session->cancel_audition();
1212 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
1214 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action); \
1215 if (tact && tact->get_active() != value) { \
1216 tact->set_active(value); \
1221 MonitorSection::parameter_changed (std::string name)
1223 if (name == "solo-control-is-listen-control") {
1224 update_solo_model ();
1225 } else if (name == "listen-position") {
1226 update_solo_model ();
1227 } else if (name == "solo-mute-override") {
1228 SYNCHRONIZE_TOGGLE_ACTION(
1229 ActionManager::get_action (X_("Monitor"), "toggle-mute-overrides-solo"),
1230 Config->get_solo_mute_override ())
1231 } else if (name == "exclusive-solo") {
1232 SYNCHRONIZE_TOGGLE_ACTION(
1233 ActionManager::get_action (X_("Monitor"), "toggle-exclusive-solo"),
1234 Config->get_exclusive_solo ())
1239 MonitorSection::assign_controllables ()
1241 boost::shared_ptr<Controllable> none;
1243 if (!gain_control) {
1244 /* too early - GUI controls not set up yet */
1249 solo_cut_control->set_controllable (_session->solo_cut_control());
1250 solo_cut_display->set_controllable (_session->solo_cut_control());
1252 solo_cut_control->set_controllable (none);
1253 solo_cut_display->set_controllable (none);
1257 gain_control->set_controllable (_route->gain_control());
1258 gain_display->set_controllable (_route->gain_control());
1260 gain_control->set_controllable (none);
1265 cut_all_button.set_controllable (_monitor->cut_control());
1266 cut_all_button.watch ();
1267 dim_all_button.set_controllable (_monitor->dim_control());
1268 dim_all_button.watch ();
1269 mono_button.set_controllable (_monitor->mono_control());
1270 mono_button.watch ();
1272 dim_control->set_controllable (_monitor->dim_level_control ());
1273 dim_display->set_controllable (_monitor->dim_level_control ());
1274 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1275 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1279 cut_all_button.set_controllable (none);
1280 dim_all_button.set_controllable (none);
1281 mono_button.set_controllable (none);
1283 dim_control->set_controllable (none);
1284 dim_display->set_controllable (none);
1285 solo_boost_control->set_controllable (none);
1286 solo_boost_display->set_controllable (none);
1291 MonitorSection::state_id() const
1293 return "monitor-section";
1297 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1299 using namespace Menu_Helpers;
1301 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1305 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1306 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1310 if (i != output_menu_bundles.end()) {
1314 output_menu_bundles.push_back (b);
1316 MenuList& citems = output_menu.items();
1318 std::string n = b->name ();
1319 replace_all (n, "_", " ");
1321 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1325 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1328 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1330 if (std::find (current.begin(), current.end(), c) == current.end()) {
1331 _route->output()->connect_ports_to_bundle (c, true, this);
1333 _route->output()->disconnect_ports_from_bundle (c, this);
1338 MonitorSection::output_release (GdkEventButton *ev)
1340 switch (ev->button) {
1342 edit_output_configuration ();
1349 struct RouteCompareByName {
1350 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1351 return a->name().compare (b->name()) < 0;
1356 MonitorSection::output_press (GdkEventButton *ev)
1358 using namespace Menu_Helpers;
1360 MessageDialog msg (_("No session - no I/O changes are possible"));
1365 MenuList& citems = output_menu.items();
1366 switch (ev->button) {
1369 return false; //wait for the mouse-up to pop the dialog
1373 output_menu.set_name ("ArdourContextMenu");
1375 output_menu_bundles.clear ();
1377 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1379 citems.push_back (SeparatorElem());
1380 uint32_t const n_with_separator = citems.size ();
1382 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1384 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1386 /* give user bundles first chance at being in the menu */
1388 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1389 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1390 maybe_add_bundle_to_output_menu (*i, current);
1394 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1395 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1396 maybe_add_bundle_to_output_menu (*i, current);
1400 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1401 RouteList copy = *routes;
1402 copy.sort (RouteCompareByName ());
1403 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1404 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1407 if (citems.size() == n_with_separator) {
1408 /* no routes added; remove the separator */
1412 citems.push_back (SeparatorElem());
1413 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1415 output_menu.popup (1, ev->time);
1426 MonitorSection::update_output_display ()
1428 if (!_route || !_monitor || _session->deletion_in_progress()) {
1434 boost::shared_ptr<Port> port;
1435 vector<string> port_connections;
1437 uint32_t total_connection_count = 0;
1438 uint32_t io_connection_count = 0;
1439 uint32_t ardour_connection_count = 0;
1440 uint32_t system_connection_count = 0;
1441 uint32_t other_connection_count = 0;
1443 ostringstream label;
1445 bool have_label = false;
1446 bool each_io_has_one_connection = true;
1448 string connection_name;
1449 string ardour_track_name;
1450 string other_connection_type;
1451 string system_ports;
1454 ostringstream tooltip;
1455 char * tooltip_cstr;
1457 io_count = _route->n_outputs().n_total();
1458 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1461 for (io_index = 0; io_index < io_count; ++io_index) {
1463 port = _route->output()->nth (io_index);
1465 //ignore any port connections that don't match our DataType
1466 if (port->type() != DataType::AUDIO) {
1470 port_connections.clear ();
1471 port->get_connections(port_connections);
1472 io_connection_count = 0;
1474 if (!port_connections.empty()) {
1475 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1477 string& connection_name (*i);
1479 if (connection_name.find("system:") == 0) {
1480 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1483 if (io_connection_count == 0) {
1484 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1486 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1489 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1492 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1493 if (ardour_track_name.empty()) {
1494 // "ardour:Master/in 1" -> "ardour:Master/"
1495 string::size_type slash = connection_name.find("/");
1496 if (slash != string::npos) {
1497 ardour_track_name = connection_name.substr(0, slash + 1);
1501 if (connection_name.find(ardour_track_name) == 0) {
1502 ++ardour_connection_count;
1504 } else if (!pn.empty()) {
1505 if (system_ports.empty()) {
1508 system_ports += "/" + pn;
1510 if (connection_name.find("system:") == 0) {
1511 ++system_connection_count;
1513 } else if (connection_name.find("system:") == 0) {
1514 // "system:playback_123" -> "123"
1515 system_port = connection_name.substr(16);
1516 if (system_ports.empty()) {
1517 system_ports += system_port;
1519 system_ports += "/" + system_port;
1522 ++system_connection_count;
1524 if (other_connection_type.empty()) {
1525 // "jamin:in 1" -> "jamin:"
1526 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1529 if (connection_name.find(other_connection_type) == 0) {
1530 ++other_connection_count;
1534 ++total_connection_count;
1535 ++io_connection_count;
1539 if (io_connection_count != 1) {
1540 each_io_has_one_connection = false;
1544 if (total_connection_count == 0) {
1545 tooltip << endl << _("Disconnected");
1548 tooltip_cstr = new char[tooltip.str().size() + 1];
1549 strcpy(tooltip_cstr, tooltip.str().c_str());
1551 set_tooltip (output_button, tooltip_cstr, "");
1553 if (each_io_has_one_connection) {
1554 if (total_connection_count == ardour_connection_count) {
1555 // all connections are to the same track in ardour
1556 // "ardour:Master/" -> "Master"
1557 string::size_type slash = ardour_track_name.find("/");
1558 if (slash != string::npos) {
1559 label << ardour_track_name.substr(7, slash - 7);
1562 } else if (total_connection_count == system_connection_count) {
1563 // all connections are to system ports
1564 label << system_ports;
1566 } else if (total_connection_count == other_connection_count) {
1567 // all connections are to the same external program eg jamin
1568 // "jamin:" -> "jamin"
1569 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1575 if (total_connection_count == 0) {
1579 // Odd configuration
1580 label << "*" << total_connection_count << "*";
1584 output_button->set_text (label.str());
1588 MonitorSection::disconnect_output ()
1591 _route->output()->disconnect(this);
1596 MonitorSection::edit_output_configuration ()
1598 if (_output_selector == 0) {
1599 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1601 _output_selector->present ();
1605 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1610 boost::shared_ptr<Port> a = wa.lock ();
1611 boost::shared_ptr<Port> b = wb.lock ();
1612 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1613 update_output_display ();
1618 MonitorSection::load_bindings ()
1620 bindings = Bindings::get_bindings (X_("Monitor Section"), myactions);
1624 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1626 boost::shared_ptr<Processor> processor (p.lock ());
1627 if (!processor || !processor->display_to_user()) {
1630 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1637 MonitorSection::count_processors ()
1639 uint32_t processor_count = 0;
1641 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1643 return processor_count;
1647 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1649 update_processor_box ();
1653 MonitorSection::action_proxy0 (enum MonitorActions action)
1655 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1669 case ToggleExclusiveSolo:
1670 ms->toggle_exclusive_solo ();
1672 case ToggleMuteOverridesSolo:
1673 ms->toggle_mute_overrides_solo ();
1675 case SoloUseInPlace:
1676 ms->solo_use_in_place ();
1679 ms->solo_use_afl ();
1682 ms->solo_use_pfl ();
1684 case ToggleMonitorProcessorBox:
1685 ms->update_processor_box ();
1691 MonitorSection::action_proxy1 (enum ChannelActions action, uint32_t chn)
1693 MonitorSection* ms = Mixer_UI::instance()->monitor_section ();
1699 ms->cut_channel (chn);
1702 ms->dim_channel (chn);
1705 ms->solo_channel (chn);
1708 ms->invert_channel (chn);