1 /*
2 * Copyright (C) 2010-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2011-2012 David Robillard <d@drobilla.net>
4 * Copyright (C) 2011 Carl Hetherington <carl@carlh.net>
5 * Copyright (C) 2014-2015 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
7 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24 #include <gdkmm/pixbuf.h>
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/replace_all.h"
29
30 #include "gtkmm2ext/actions.h"
31 #include "gtkmm2ext/utils.h"
32
33 #include <gtkmm/menu.h>
34 #include <gtkmm/menuitem.h>
35
36 #include "widgets/tearoff.h"
37 #include "widgets/tooltips.h"
38
39 #include "ardour/amp.h"
40 #include "ardour/audioengine.h"
41 #include "ardour/monitor_processor.h"
42 #include "ardour/port.h"
43 #include "ardour/route.h"
44 #include "ardour/solo_isolate_control.h"
45 #include "ardour/user_bundle.h"
46 #include "ardour/plugin_manager.h"
47
48 #include "ardour_ui.h"
49 #include "gui_thread.h"
50 #include "mixer_ui.h"
51 #include "monitor_section.h"
52 #include "public_editor.h"
53 #include "timers.h"
54 #include "ui_config.h"
55 #include "utils.h"
56
57 #include "pbd/i18n.h"
58
59 using namespace ARDOUR;
60 using namespace ArdourWidgets;
61 using namespace ARDOUR_UI_UTILS;
62 using namespace Gtk;
63 using namespace Gtkmm2ext;
64 using namespace PBD;
65 using namespace std;
66
67 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
68
69 #define SYNCHRONIZE_TOGGLE_ACTION(action, value) \
70 if (action && action->get_active() != value) { \
71 action->set_active(value); \
72 }
73
MonitorSection()74 MonitorSection::MonitorSection ()
75 : RouteUI ((Session*) 0)
76 , _tearoff (0)
77 , channel_table (0)
78 , channel_table_viewport (*channel_table_scroller.get_hadjustment()
79 , *channel_table_scroller.get_vadjustment ())
80 , gain_control (0)
81 , dim_control (0)
82 , solo_boost_control (0)
83 , solo_cut_control (0)
84 , gain_display (0)
85 , dim_display (0)
86 , solo_boost_display (0)
87 , solo_cut_display (0)
88 , _output_selector (0)
89 , solo_in_place_button (_("SiP"), ArdourButton::led_default_elements)
90 , afl_button (_("AFL"), ArdourButton::led_default_elements)
91 , pfl_button (_("PFL"), ArdourButton::led_default_elements)
92 , exclusive_solo_button (ArdourButton::led_default_elements)
93 , solo_mute_override_button (ArdourButton::led_default_elements)
94 , toggle_processorbox_button (ArdourButton::default_elements)
95 , _inhibit_solo_model_update (false)
96 , _rr_selection ()
97 , _ui_initialized (false)
98 {
99 /* note that although this a RouteUI, we never called ::set_route() so
100 * we do not need to worry about self-destructing when the Route (the
101 * monitor out) is destroyed.
102 */
103
104 using namespace Menu_Helpers;
105
106 Glib::RefPtr<Action> act;
107
108 load_bindings ();
109 register_actions ();
110 set_data ("ardour-bindings", bindings);
111
112 channel_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
113
114 insert_box = new ProcessorBox (0, boost::bind (&MonitorSection::plugin_selector, this), _rr_selection, 0);
115 insert_box->set_no_show_all ();
116 insert_box->show ();
117 // TODO allow keyboard shortcuts in ProcessorBox
118
119 /* Rude Solo & Solo Isolated */
120 rude_solo_button.set_text (_("Soloing"));
121 rude_solo_button.set_name ("rude solo");
122 rude_solo_button.show ();
123
124 rude_iso_button.set_text (_("Isolated"));
125 rude_iso_button.set_name ("rude isolate");
126 rude_iso_button.show ();
127
128 rude_audition_button.set_text (_("Auditioning"));
129 rude_audition_button.set_name ("rude audition");
130 rude_audition_button.show ();
131
132 Timers::blink_connect (sigc::mem_fun (*this, &MonitorSection::do_blink));
133
134 UI::instance()->set_tip (rude_solo_button, _("When active, something is soloed.\nClick to de-solo everything"));
135
136 rude_iso_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_isolate), false);
137 UI::instance()->set_tip (rude_iso_button, _("When active, something is solo-isolated.\nClick to de-isolate everything"));
138
139 rude_audition_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::cancel_audition), false);
140 UI::instance()->set_tip (rude_audition_button, _("When active, auditioning is active.\nClick to stop the audition"));
141
142 /* SIP, AFL, PFL radio */
143
144 solo_in_place_button.set_name ("monitor section solo model");
145 afl_button.set_name ("monitor section solo model");
146 pfl_button.set_name ("monitor section solo model");
147
148 solo_in_place_button.set_led_left (true);
149 afl_button.set_led_left (true);
150 pfl_button.set_led_left (true);
151
152 solo_in_place_button.show ();
153 afl_button.show ();
154 pfl_button.show ();
155
156 act = ActionManager::get_action (X_("Solo"), X_("solo-use-in-place"));
157 set_tooltip (solo_in_place_button, _("Solo controls affect solo-in-place"));
158 if (act) {
159 solo_in_place_button.set_related_action (act);
160 }
161
162 act = ActionManager::get_action (X_("Solo"), X_("solo-use-afl"));
163 set_tooltip (afl_button, _("Solo controls toggle after-fader-listen"));
164 if (act) {
165 afl_button.set_related_action (act);
166 }
167
168 act = ActionManager::get_action (X_("Solo"), X_("solo-use-pfl"));
169 set_tooltip (pfl_button, _("Solo controls toggle pre-fader-listen"));
170 if (act) {
171 pfl_button.set_related_action (act);
172 }
173
174 /* Solo option buttons */
175 exclusive_solo_button.set_text (_("Excl. Solo"));
176 exclusive_solo_button.set_name (X_("monitor section solo option"));
177 set_tooltip (&exclusive_solo_button, _("Exclusive solo means that only 1 solo is active at a time"));
178
179 act = ActionManager::get_action (X_("Solo"), X_("toggle-exclusive-solo"));
180 if (act) {
181 exclusive_solo_button.set_related_action (act);
182 }
183
184 solo_mute_override_button.set_text (_("Solo » Mute"));
185 solo_mute_override_button.set_name (X_("monitor section solo option"));
186 set_tooltip (&solo_mute_override_button, _("If enabled, solo will override mute\n(a soloed & muted track or bus will be audible)"));
187
188 solo_mute_override_button.set_related_action (ActionManager::get_action (X_("Solo"), X_("toggle-mute-overrides-solo")));
189
190 /* Processor Box hide/shos */
191 toggle_processorbox_button.set_text (_("Processors"));
192 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
193 set_tooltip (&toggle_processorbox_button, _("Allow one to add monitor effect processors"));
194
195 proctoggle = ActionManager::get_toggle_action (X_("Monitor"), X_("toggle-monitor-processor-box"));
196 toggle_processorbox_button.set_related_action (proctoggle);
197
198 /* Knobs */
199 Label* solo_boost_label;
200 Label* solo_cut_label;
201 Label* dim_label;
202
203 /* Solo Boost Knob */
204
205 solo_boost_control = new ArdourKnob ();
206 solo_boost_control->set_name("monitor section knob");
207 solo_boost_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
208 set_tooltip (*solo_boost_control, _("Gain increase for soloed signals (0dB is normal)"));
209
210 solo_boost_display = new ArdourDisplay ();
211 set_tooltip (*solo_boost_display, _("Gain increase for soloed signals (0dB is normal)"));
212 solo_boost_display->set_name("monitor section button");
213 solo_boost_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
214 solo_boost_display->add_controllable_preset(_("0 dB"), 0.0);
215 solo_boost_display->add_controllable_preset(_("3 dB"), 3.0);
216 solo_boost_display->add_controllable_preset(_("6 dB"), 6.0);
217 solo_boost_display->add_controllable_preset(_("10 dB"), 10.0);
218
219 solo_boost_label = manage (new Label (_("Solo Boost")));
220
221 /* Solo (SiP) cut */
222
223 solo_cut_control = new ArdourKnob ();
224 solo_cut_control->set_name ("monitor section knob");
225 solo_cut_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
226 set_tooltip (*solo_cut_control, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
227
228 solo_cut_display = new ArdourDisplay ();
229 set_tooltip (*solo_cut_display, _("Gain reduction non-soloed signals\nA value above -inf dB causes \"solo-in-front\""));
230 solo_cut_display->set_name("monitor section button");
231 solo_cut_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
232 solo_cut_display->add_controllable_preset(_("0 dB"), 0.0);
233 solo_cut_display->add_controllable_preset(_("-6 dB"), -6.0);
234 solo_cut_display->add_controllable_preset(_("-12 dB"), -12.0);
235 solo_cut_display->add_controllable_preset(_("-20 dB"), -20.0);
236 solo_cut_display->add_controllable_preset(_("OFF"), -1200.0);
237
238 solo_cut_label = manage (new Label (_("SiP Cut")));
239
240 /* Dim */
241
242 dim_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
243 dim_control->set_name ("monitor section knob");
244 dim_control->set_size_request (PX_SCALE(36), PX_SCALE(36));
245 set_tooltip (*dim_control, _("Gain reduction to use when dimming monitor outputs"));
246
247 dim_display = new ArdourDisplay ();
248 set_tooltip (*dim_display, _("Gain reduction to use when dimming monitor outputs"));
249 dim_display->set_name ("monitor section button");
250 dim_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
251 dim_display->add_controllable_preset(_("0 dB"), 0.0);
252 dim_display->add_controllable_preset(_("-3 dB"), -3.0);
253 dim_display->add_controllable_preset(_("-6 dB"), -6.0);
254 dim_display->add_controllable_preset(_("-12 dB"), -12.0);
255 dim_display->add_controllable_preset(_("-20 dB"), -20.0);
256
257 dim_label = manage (new Label (_("Dim")));
258
259 // mute button
260 cut_all_button.set_text (_("Mute"));
261 cut_all_button.set_name ("mute button");
262 cut_all_button.set_size_request (-1, PX_SCALE(30));
263 cut_all_button.show ();
264
265 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-cut-all"));
266 if (act) {
267 cut_all_button.set_related_action (act);
268 }
269
270 // dim button
271 dim_all_button.set_text (_("Dim"));
272 dim_all_button.set_name ("monitor section dim");
273 dim_all_button.set_size_request (-1, PX_SCALE(25));
274 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-dim-all"));
275 if (act) {
276 dim_all_button.set_related_action (act);
277 }
278
279 // mono button
280 mono_button.set_text (_("Mono"));
281 mono_button.set_name ("monitor section mono");
282 mono_button.set_size_request (-1, PX_SCALE(25));
283 act = ActionManager::get_action (X_("Monitor Section"), X_("monitor-mono"));
284 if (act) {
285 mono_button.set_related_action (act);
286 }
287
288 /* Gain */
289
290 gain_control = new ArdourKnob (ArdourKnob::default_elements, ArdourKnob::Detent);
291 gain_control->set_name("monitor section knob");
292 gain_control->set_size_request (PX_SCALE(60), PX_SCALE(60));
293
294 gain_display = new ArdourDisplay ();
295 gain_display->set_name("monitor section button");
296 gain_display->set_size_request (PX_SCALE(68), PX_SCALE(20));
297 gain_display->add_controllable_preset(_("0 dB"), 0.0);
298 gain_display->add_controllable_preset(_("-3 dB"), -3.0);
299 gain_display->add_controllable_preset(_("-6 dB"), -6.0);
300 gain_display->add_controllable_preset(_("-12 dB"), -12.0);
301 gain_display->add_controllable_preset(_("-20 dB"), -20.0);
302 gain_display->add_controllable_preset(_("-30 dB"), -30.0);
303
304 Label* output_label = manage (new Label (_("Output")));
305 output_label->set_name (X_("MonitorSectionLabel"));
306
307 output_button = new ArdourButton ();
308 output_button->set_text (_("Output"));
309 output_button->set_name (X_("monitor section button"));
310 output_button->set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
311 output_button->set_layout_ellipsize_width (PX_SCALE(128) * PANGO_SCALE);
312
313 channel_table_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
314 channel_table_scroller.set_size_request (-1, PX_SCALE(150));
315 channel_table_scroller.set_shadow_type (Gtk::SHADOW_NONE);
316 channel_table_scroller.show ();
317 channel_table_scroller.add (channel_table_viewport);
318
319 channel_size_group->add_widget (channel_table_header);
320 channel_table_header.resize (1, 5);
321
322 Label* l1 = manage (new Label (X_(" ")));
323 l1->set_name (X_("MonitorSectionLabel"));
324 channel_table_header.attach (*l1, 0, 1, 0, 1, EXPAND|FILL);
325
326 l1 = manage (new Label (_("Mute")));
327 l1->set_name (X_("MonitorSectionLabel"));
328 channel_table_header.attach (*l1, 1, 2, 0, 1, EXPAND|FILL);
329
330 l1 = manage (new Label (_("Dim")));
331 l1->set_name (X_("MonitorSectionLabel"));
332 channel_table_header.attach (*l1, 2, 3, 0, 1, EXPAND|FILL);
333
334 l1 = manage (new Label (_("Solo")));
335 l1->set_name (X_("MonitorSectionLabel"));
336 channel_table_header.attach (*l1, 3, 4, 0, 1, EXPAND|FILL);
337
338 l1 = manage (new Label (_("Inv")));
339 l1->set_name (X_("MonitorSectionLabel"));
340 channel_table_header.attach (*l1, 4, 5, 0, 1, EXPAND|FILL);
341
342 channel_table_header.show ();
343
344
345 /****************************************************************************
346 * LAYOUT top to bottom
347 */
348
349 Gtk::Label *top_spacer = manage (new Gtk::Label);
350
351 // solo, iso information
352 HBox* rude_box = manage (new HBox);
353 rude_box->set_spacing (PX_SCALE(4));
354 rude_box->set_homogeneous (true);
355 rude_box->pack_start (rude_solo_button, true, true);
356 rude_box->pack_start (rude_iso_button, true, true);
357
358 // solo options (right align)
359 HBox* tbx1 = manage (new HBox);
360 tbx1->pack_end (exclusive_solo_button, false, false);
361
362 HBox* tbx2 = manage (new HBox);
363 tbx2->pack_end (solo_mute_override_button, false, false);
364
365 HBox* tbx3 = manage (new HBox);
366 tbx3->pack_end (toggle_processorbox_button, false, false);
367
368 HBox* tbx0 = manage (new HBox); // space
369
370 // combined solo mode (Sip, AFL, PFL) & solo options
371 Table *solo_tbl = manage (new Table);
372 solo_tbl->attach (solo_in_place_button, 0, 1, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
373 solo_tbl->attach (pfl_button, 0, 1, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
374 solo_tbl->attach (afl_button, 0, 1, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
375 solo_tbl->attach (*tbx0, 1, 2, 0, 3, EXPAND|FILL, SHRINK, 2, 2);
376 solo_tbl->attach (*tbx1, 2, 3, 0, 1, EXPAND|FILL, SHRINK, 0, 2);
377 solo_tbl->attach (*tbx2, 2, 3, 1, 2, EXPAND|FILL, SHRINK, 0, 2);
378 solo_tbl->attach (*tbx3, 2, 3, 2, 3, EXPAND|FILL, SHRINK, 0, 2);
379
380 // boost, cut, dim volume control
381 Table *level_tbl = manage (new Table);
382 level_tbl->attach (*solo_boost_label, 0, 2, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
383 level_tbl->attach (*solo_boost_control, 0, 2, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
384 level_tbl->attach (*solo_boost_display, 0, 2, 2, 3, EXPAND , SHRINK, 1, 2);
385
386 level_tbl->attach (*solo_cut_label, 2, 4, 0, 1, EXPAND|FILL, SHRINK, 1, 2);
387 level_tbl->attach (*solo_cut_control, 2, 4, 1, 2, EXPAND|FILL, SHRINK, 1, 2);
388 level_tbl->attach (*solo_cut_display, 2, 4, 2, 3, EXPAND , SHRINK, 1, 2);
389
390 level_tbl->attach (*dim_label, 1, 3, 3, 4, EXPAND|FILL, SHRINK, 1, 2);
391 level_tbl->attach (*dim_control, 1, 3, 4, 5, EXPAND|FILL, SHRINK, 1, 2);
392 level_tbl->attach (*dim_display, 1, 3, 5, 6, EXPAND , SHRINK, 1, 2);
393
394 // mono, dim
395 HBox* mono_dim_box = manage (new HBox);
396 mono_dim_box->set_spacing (PX_SCALE(4));
397 mono_dim_box->set_homogeneous (true);
398 mono_dim_box->pack_start (mono_button, true, true);
399 mono_dim_box->pack_end (dim_all_button, true, true);
400
401 // master gain
402 Label* spin_label = manage (new Label (_("Monitor")));
403 VBox* spin_packer = manage (new VBox);
404 spin_packer->set_spacing (PX_SCALE(2));
405 spin_packer->pack_start (*spin_label, false, false);
406 spin_packer->pack_start (*gain_control, false, false);
407 spin_packer->pack_start (*gain_display, false, false);
408
409 master_packer.pack_start (*spin_packer, true, false);
410
411 // combined gain section (channels, mute, dim)
412 VBox* lower_packer = manage (new VBox);
413 lower_packer->pack_start (channel_table_header, false, false, PX_SCALE(0));
414 lower_packer->pack_start (channel_table_packer, false, false, PX_SCALE(8));
415 lower_packer->pack_start (*mono_dim_box, false, false, PX_SCALE(2));
416 lower_packer->pack_start (cut_all_button, false, false, PX_SCALE(2));
417
418 // calc height of mixer scrollbar
419 int scrollbar_height = 0;
420 {
421 Gtk::Window window (WINDOW_TOPLEVEL);
422 HScrollbar scrollbar;
423 window.add (scrollbar);
424 scrollbar.set_name ("MixerWindow");
425 scrollbar.ensure_style();
426 Gtk::Requisition requisition(scrollbar.size_request ());
427 scrollbar_height = requisition.height;
428 scrollbar_height += 3; // track_display_frame border/shadow
429 }
430
431 // output port select
432 VBox* out_packer = manage (new VBox);
433 out_packer->set_spacing (PX_SCALE(2));
434 out_packer->pack_start (*output_label, false, false);
435 out_packer->pack_start (*output_button, false, false);
436
437 /****************************************************************************
438 * TOP LEVEL LAYOUT
439 */
440 vpacker.set_border_width (PX_SCALE(3));
441 vpacker.pack_start (*top_spacer, false, false, PX_SCALE(3));
442 vpacker.pack_start (*rude_box, false, false, PX_SCALE(3));
443 vpacker.pack_start (rude_audition_button, false, false, 0);
444 vpacker.pack_start (*solo_tbl, false, false, PX_SCALE(8));
445 vpacker.pack_start (*insert_box, true, true, PX_SCALE(8));
446 vpacker.pack_start (*level_tbl, false, false, PX_SCALE(8));
447 vpacker.pack_start (*lower_packer, false, false, PX_SCALE(8));
448 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
449 vpacker.pack_end (*out_packer, false, false,
450 #ifdef MIXBUS
451 scrollbar_height /* no outer frame */
452 #else
453 scrollbar_height + 2 /* frame borders */
454 #endif
455 );
456
457 hpacker.set_spacing (0);
458 hpacker.pack_start (vpacker, true, true);
459
460 add (hpacker);
461
462 gain_control->show_all ();
463 gain_display->show_all ();
464 dim_control->show_all ();
465 dim_display->show_all();
466 solo_boost_control->show_all ();
467 solo_boost_display->show_all();
468
469 mono_dim_box->show ();
470 spin_packer->show ();
471 master_packer.show ();
472
473 rude_box->show();
474 solo_tbl->show_all();
475 level_tbl->show();
476 lower_packer->show ();
477 out_packer->show ();
478
479 vpacker.show ();
480 hpacker.show ();
481
482 map_state ();
483
484 output_button->signal_button_press_event().connect (sigc::mem_fun(*this, &MonitorSection::output_press), false);
485 output_button->signal_button_release_event().connect (sigc::mem_fun(*this, &MonitorSection::output_release), false);
486
487 signal_enter_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::enter_handler));
488 signal_leave_notify_event().connect (sigc::mem_fun (*this, &MonitorSection::leave_handler));
489 set_flags (CAN_FOCUS);
490
491 _tearoff = new TearOff (*this);
492
493 if (!UIConfiguration::instance().get_floating_monitor_section()) {
494 /* if torn off, make this a normal window
495 * (default is WINDOW_TYPE_HINT_UTILITY in libs/gtkmm2ext/tearoff.cc)
496 */
497 _tearoff->tearoff_window().set_type_hint (Gdk::WINDOW_TYPE_HINT_NORMAL);
498 }
499 _tearoff->tearoff_window().set_title (X_("Monitor"));
500 _tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), (Gtk::Window*) &_tearoff->tearoff_window()), false);
501
502 update_output_display ();
503 update_processor_box ();
504 _ui_initialized = true;
505
506 /* catch changes that affect us */
507 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
508 *this, invalidator (*this), boost::bind (&MonitorSection::port_connected_or_disconnected, this, _1, _3), gui_context ()
509 );
510 AudioEngine::instance()->PortPrettyNameChanged.connect (
511 *this, invalidator (*this), boost::bind (&MonitorSection::port_pretty_name_changed, this, _1), gui_context ()
512 );
513 Config->ParameterChanged.connect (config_connection, invalidator (*this), boost::bind (&MonitorSection::parameter_changed, this, _1), gui_context());
514 }
515
~MonitorSection()516 MonitorSection::~MonitorSection ()
517 {
518 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
519 delete *i;
520 }
521
522 _channel_buttons.clear ();
523 route_connections.drop_connections ();
524
525 delete insert_box; insert_box = 0;
526 delete output_button; output_button = 0;
527 delete gain_control; gain_control = 0;
528 delete gain_display; gain_display = 0;
529 delete dim_control; dim_control = 0;
530 delete dim_display; dim_display = 0;
531 delete solo_boost_control; solo_boost_control = 0;
532 delete solo_boost_display; solo_boost_display = 0;
533 delete solo_cut_control; solo_cut_control = 0;
534 delete solo_cut_display; solo_cut_display = 0;
535 delete _tearoff; _tearoff = 0;
536 delete _output_selector; _output_selector = 0;
537 delete channel_table; channel_table = 0;
538 }
539
540 bool
enter_handler(GdkEventCrossing * ev)541 MonitorSection::enter_handler (GdkEventCrossing* ev)
542 {
543 grab_focus ();
544 return false;
545 }
546
547 bool
leave_handler(GdkEventCrossing * ev)548 MonitorSection::leave_handler (GdkEventCrossing* ev)
549 {
550 switch (ev->detail) {
551 case GDK_NOTIFY_INFERIOR:
552 return false;
553 default:
554 break;
555 }
556
557 /* cancel focus if we're not torn off. With X11 WM's that do
558 * focus-follows-mouse, focus will be taken from us anyway.
559 */
560
561 Widget* top = get_toplevel();
562
563 if (top->is_toplevel() && top != &_tearoff->tearoff_window()) {
564 Window* win = dynamic_cast<Window*> (top);
565 gtk_window_set_focus (win->gobj(), 0);
566 }
567
568 return false;
569 }
570
571 void
update_processor_box()572 MonitorSection::update_processor_box ()
573 {
574 bool show_processor_box = proctoggle->get_active ();
575
576 if (count_processors () > 0 && !show_processor_box) {
577 toggle_processorbox_button.set_name (X_("monitor section processors present"));
578 } else {
579 toggle_processorbox_button.set_name (X_("monitor section processors toggle"));
580 }
581
582 if (insert_box->is_visible() == show_processor_box) {
583 return;
584 }
585
586 if (show_processor_box) {
587 if (master_packer.get_parent()) {
588 master_packer.get_parent()->remove (master_packer);
589 }
590 insert_box->show();
591 vpacker.pack_start (master_packer, false, false, PX_SCALE(10));
592 } else {
593 if (master_packer.get_parent()) {
594 master_packer.get_parent()->remove (master_packer);
595 }
596 insert_box->hide();
597 vpacker.pack_start (master_packer, true, false, PX_SCALE(10));
598 }
599 }
600
601 void
set_session(Session * s)602 MonitorSection::set_session (Session* s)
603 {
604 RouteUI::set_session (s);
605 insert_box->set_session (_session);
606
607 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
608
609 if (_session) {
610
611 /* These are not actually dependent on the Session, but they
612 * need to be set after construction, not during, and
613 * this is as good a place as any.
614 */
615
616 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-exclusive-solo"))->set_active (Config->get_exclusive_solo());
617 ActionManager::get_toggle_action (X_("Solo"), X_("toggle-mute-overrides-solo"))->set_active (Config->get_solo_mute_override());
618
619 _route = _session->monitor_out ();
620
621 if (_route) {
622 /* session with monitor section */
623 _monitor = _route->monitor_control ();
624 assign_controllables ();
625 _route->output()->changed.connect (route_connections, invalidator (*this),
626 boost::bind (&MonitorSection::update_output_display, this),
627 gui_context());
628 insert_box->set_route (_route);
629 _route->processors_changed.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::processors_changed, this, _1), gui_context());
630 _route->output()->PortCountChanged.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::populate_buttons, this), gui_context());
631 _route->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&MonitorSection::drop_route, this), gui_context());
632
633 if (_ui_initialized) {
634 update_processor_box ();
635 update_output_display ();
636 }
637
638 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), true);
639 ActionManager::set_sensitive (global_monitor_actions, true);
640 ActionManager::set_sensitive (monitor_actions, true);
641 ActionManager::set_sensitive (solo_actions, true);
642
643 } else {
644 /* session with no monitor section */
645 route_connections.drop_connections();
646 _monitor.reset ();
647 _route.reset ();
648 delete _output_selector;
649 _output_selector = 0;
650
651 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection"), false);
652 ActionManager::set_sensitive (global_monitor_actions, false);
653 ActionManager::set_sensitive (monitor_actions, false);
654 ActionManager::set_sensitive (solo_actions, true);
655 /* this action needs to always be true in this, so that we can turn it back on */
656 ActionManager::get_toggle_action (X_("Monitor"), X_("UseMonitorSection"))->set_sensitive (true);
657 }
658
659 populate_buttons ();
660 map_state ();
661
662 } else {
663
664 /* no session */
665
666 if (_route) {
667 drop_route ();
668 unassign_controllables ();
669 }
670
671 ActionManager::set_sensitive (monitor_actions, false);
672 ActionManager::set_sensitive (solo_actions, false);
673 ActionManager::set_sensitive (global_monitor_actions, false);
674 }
675 }
676
677 void
drop_route()678 MonitorSection::drop_route ()
679 {
680 route_connections.drop_connections();
681 _monitor.reset ();
682 _route.reset ();
683 unassign_controllables ();
684 rude_iso_button.unset_active_state ();
685 rude_solo_button.unset_active_state ();
686 delete _output_selector;
687 _output_selector = 0;
688 }
689
ChannelButtonSet()690 MonitorSection::ChannelButtonSet::ChannelButtonSet ()
691 {
692 cut.set_name (X_("mute button"));
693 dim.set_name (X_("monitor section dim"));
694 solo.set_name (X_("solo button"));
695 invert.set_name (X_("invert button"));
696
697 cut.unset_flags (Gtk::CAN_FOCUS);
698 dim.unset_flags (Gtk::CAN_FOCUS);
699 solo.unset_flags (Gtk::CAN_FOCUS);
700 invert.unset_flags (Gtk::CAN_FOCUS);
701 }
702
703 void
populate_buttons()704 MonitorSection::populate_buttons ()
705 {
706 if (!_monitor) {
707 return;
708 }
709
710 if (channel_table) {
711 channel_size_group->remove_widget (*channel_table);
712 delete channel_table;
713 }
714
715 channel_table = new Gtk::Table();
716
717 channel_table->set_col_spacings (6);
718 channel_table->set_row_spacings (6);
719 channel_table->set_homogeneous (true);
720
721 channel_size_group->add_widget (*channel_table);
722 channel_table->show ();
723 table_hpacker.pack_start (*channel_table, true, true);
724
725 for (ChannelButtons::iterator i = _channel_buttons.begin(); i != _channel_buttons.end(); ++i) {
726 delete *i;
727 }
728 _channel_buttons.clear ();
729
730 Glib::RefPtr<Action> act;
731 uint32_t nchans = _monitor->output_streams().n_audio();
732
733 channel_table->resize (nchans, 5);
734
735 const uint32_t row_offset = 0;
736
737 for (uint32_t i = 0; i < nchans; ++i) {
738
739 string l;
740 char buf[64];
741
742 if (nchans == 2) {
743 if (i == 0) {
744 l = "L";
745 } else {
746 l = "R";
747 }
748 } else {
749 char buf[32];
750 snprintf (buf, sizeof (buf), "%d", i+1);
751 l = buf;
752 }
753
754 Label* label = manage (new Label (l));
755 channel_table->attach (*label, 0, 1, i+row_offset, i+row_offset+1, EXPAND|FILL);
756
757 ChannelButtonSet* cbs = new ChannelButtonSet;
758
759 _channel_buttons.push_back (cbs);
760
761 channel_table->attach (cbs->cut, 1, 2, i+row_offset, i+row_offset+1, EXPAND|FILL);
762 channel_table->attach (cbs->dim, 2, 3, i+row_offset, i+row_offset+1, EXPAND|FILL);
763 channel_table->attach (cbs->solo, 3, 4, i+row_offset, i+row_offset+1, EXPAND|FILL);
764 channel_table->attach (cbs->invert, 4, 5, i+row_offset, i+row_offset+1, EXPAND|FILL);
765
766 snprintf (buf, sizeof (buf), "monitor-cut-%u", i);
767 act = ActionManager::get_action (X_("Monitor"), buf);
768 if (act) {
769 cbs->cut.set_related_action (act);
770 }
771
772 snprintf (buf, sizeof (buf), "monitor-dim-%u", i);
773 act = ActionManager::get_action (X_("Monitor"), buf);
774 if (act) {
775 cbs->dim.set_related_action (act);
776 }
777
778 snprintf (buf, sizeof (buf), "monitor-solo-%u", i);
779 act = ActionManager::get_action (X_("Monitor"), buf);
780 if (act) {
781 cbs->solo.set_related_action (act);
782 }
783
784 snprintf (buf, sizeof (buf), "monitor-invert-%u", i);
785 act = ActionManager::get_action (X_("Monitor"), buf);
786 if (act) {
787 cbs->invert.set_related_action (act);
788 }
789 }
790
791 channel_table->show_all ();
792
793 if (channel_table_scroller.get_parent()) {
794 /* scroller is packed, so remove it */
795 channel_table_packer.remove (channel_table_scroller);
796 }
797
798 if (table_hpacker.get_parent () == &channel_table_packer) {
799 /* this occurs when the table hpacker is directly
800 packed, so remove it.
801 */
802 channel_table_packer.remove (table_hpacker);
803 } else if (table_hpacker.get_parent()) {
804 channel_table_viewport.remove ();
805 }
806
807 if (nchans > 7) {
808 /* put the table into a scrolled window, and then put
809 * that into the channel vpacker, after the table header
810 */
811 channel_table_viewport.add (table_hpacker);
812 channel_table_packer.pack_start (channel_table_scroller, true, true);
813 channel_table_viewport.show ();
814 channel_table_scroller.show ();
815
816 } else {
817 /* just put the channel table itself into the channel
818 * vpacker, after the table header
819 */
820 channel_table_packer.pack_start (table_hpacker, true, true);
821 channel_table_scroller.hide ();
822 }
823 table_hpacker.show ();
824 channel_table->show ();
825 }
826
827 void
toggle_exclusive_solo()828 MonitorSection::toggle_exclusive_solo ()
829 {
830 if (!_monitor) {
831 return;
832 }
833
834 Config->set_exclusive_solo (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo")->get_active());
835 }
836
837 void
toggle_mute_overrides_solo()838 MonitorSection::toggle_mute_overrides_solo ()
839 {
840 if (!_monitor) {
841 return;
842 }
843
844 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo");
845 Config->set_solo_mute_override (tact->get_active());
846 }
847
848 void
dim_all()849 MonitorSection::dim_all ()
850 {
851 if (!_monitor) {
852 return;
853 }
854
855 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
856 _monitor->set_dim_all (tact->get_active());
857 }
858
859 void
cut_all()860 MonitorSection::cut_all ()
861 {
862 if (!_monitor) {
863 return;
864 }
865
866 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
867 _monitor->set_cut_all (tact->get_active());
868 }
869
870 void
mono()871 MonitorSection::mono ()
872 {
873 if (!_monitor) {
874 return;
875 }
876
877 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
878 _monitor->set_mono (tact->get_active());
879 }
880
881 void
cut_channel(uint32_t chn)882 MonitorSection::cut_channel (uint32_t chn)
883 {
884 if (!_monitor) {
885 return;
886 }
887
888 char buf[64];
889 snprintf (buf, sizeof (buf), "monitor-cut-%u", chn);
890
891 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
892 _monitor->set_cut (chn, tact->get_active());
893 }
894
895 void
dim_channel(uint32_t chn)896 MonitorSection::dim_channel (uint32_t chn)
897 {
898 if (!_monitor) {
899 return;
900 }
901
902 char buf[64];
903 snprintf (buf, sizeof (buf), "monitor-dim-%u", chn);
904
905 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
906 _monitor->set_dim (chn, tact->get_active());
907 }
908
909 void
solo_channel(uint32_t chn)910 MonitorSection::solo_channel (uint32_t chn)
911 {
912 if (!_monitor) {
913 return;
914 }
915
916 char buf[64];
917 snprintf (buf, sizeof (buf), "monitor-solo-%u", chn);
918
919 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
920 _monitor->set_solo (chn, tact->get_active());
921
922 }
923
924 void
invert_channel(uint32_t chn)925 MonitorSection::invert_channel (uint32_t chn)
926 {
927 if (!_monitor) {
928 return;
929 }
930
931 char buf[64];
932 snprintf (buf, sizeof (buf), "monitor-invert-%u", chn);
933
934 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Monitor"), buf);
935 _monitor->set_polarity (chn, tact->get_active());
936 }
937
938 void
register_actions()939 MonitorSection::register_actions ()
940 {
941 string action_name;
942 string action_descr;
943 Glib::RefPtr<Action> act;
944
945 /* ...will get sensitized if a mon-session is added */
946
947 monitor_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
948 solo_actions = ActionManager::create_action_group (bindings, X_("Monitor"));
949
950
951 ActionManager::register_toggle_action (monitor_actions, X_("UseMonitorSection"), _("Use Monitor Section"), sigc::mem_fun(*this, &MonitorSection::toggle_use_monitor_section));
952
953 /* these are global monitor actions that invoke MonitorSectioncode. Do
954 * not create local versions (i.e. as part of "monitor_actions")
955 * because then we can end up with two different bindings (one global,
956 * one local to the monitor section) for the same action.
957 */
958
959 Glib::RefPtr<ActionGroup> global_monitor_actions = ActionManager::get_action_group (X_("Monitor Section"));
960
961 ActionManager::register_toggle_action (global_monitor_actions, "monitor-mono", _("Mono"), sigc::mem_fun (*this, &MonitorSection::mono));
962 ActionManager::register_toggle_action (global_monitor_actions, "monitor-cut-all", _("Mute"), sigc::mem_fun (*this, &MonitorSection::cut_all));
963 ActionManager::register_toggle_action (global_monitor_actions, "monitor-dim-all", _("Dim"), sigc::mem_fun (*this, &MonitorSection::dim_all));
964
965 ActionManager::register_toggle_action (monitor_actions, "toggle-monitor-processor-box", _("Toggle Monitor Section Processor Box"),
966 sigc::mem_fun (*this, &MonitorSection::update_processor_box));
967
968
969 for (uint32_t chn = 0; chn < 16; ++chn) {
970
971 action_name = string_compose (X_("monitor-cut-%1"), chn);
972 action_descr = string_compose (_("Cut monitor channel %1"), chn);
973 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
974 sigc::bind (sigc::mem_fun (*this, &MonitorSection::cut_channel), chn));
975
976 action_name = string_compose (X_("monitor-dim-%1"), chn);
977 action_descr = string_compose (_("Dim monitor channel %1"), chn);
978 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
979 sigc::bind (sigc::mem_fun (*this, &MonitorSection::dim_channel), chn));
980
981 action_name = string_compose (X_("monitor-solo-%1"), chn);
982 action_descr = string_compose (_("Solo monitor channel %1"), chn);
983 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
984 sigc::bind (sigc::mem_fun (*this, &MonitorSection::solo_channel), chn));
985
986 action_name = string_compose (X_("monitor-invert-%1"), chn);
987 action_descr = string_compose (_("Invert monitor channel %1"), chn);
988 ActionManager::register_toggle_action (monitor_actions, action_name.c_str(), action_descr.c_str(),
989 sigc::bind (sigc::mem_fun (*this, &MonitorSection::invert_channel), chn));
990
991 }
992
993 solo_actions = ActionManager::create_action_group (bindings, X_("Solo"));
994 RadioAction::Group solo_group;
995
996 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-in-place", _("In-place solo"),
997 sigc::mem_fun (*this, &MonitorSection::solo_use_in_place));
998 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-afl", _("After Fade Listen (AFL) solo"),
999 sigc::mem_fun (*this, &MonitorSection::solo_use_afl));
1000 ActionManager::register_radio_action (solo_actions, solo_group, "solo-use-pfl", _("Pre Fade Listen (PFL) solo"),
1001 sigc::mem_fun (*this, &MonitorSection::solo_use_pfl));
1002
1003 ActionManager::register_toggle_action (solo_actions, "toggle-exclusive-solo", _("Toggle exclusive solo mode"),
1004 sigc::mem_fun (*this, &MonitorSection::toggle_exclusive_solo));
1005 ActionManager::register_toggle_action (solo_actions, "toggle-mute-overrides-solo", _("Toggle mute overrides solo mode"),
1006 sigc::mem_fun (*this, &MonitorSection::toggle_mute_overrides_solo));
1007 }
1008
1009 void
solo_use_in_place()1010 MonitorSection::solo_use_in_place ()
1011 {
1012 /* this is driven by a toggle on a radio group, and so is invoked twice,
1013 once for the item that became inactive and once for the one that became
1014 active.
1015 */
1016
1017 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-in-place"));
1018 if (!ract->get_active ()) {
1019 /* We are turning SiP off, which means that AFL or PFL will be turned on
1020 shortly; don't update the solo model in the mean time, as if the currently
1021 configured listen position is not the one that is about to be turned on,
1022 things will go wrong.
1023 */
1024 _inhibit_solo_model_update = true;
1025 }
1026 Config->set_solo_control_is_listen_control (!ract->get_active());
1027 _inhibit_solo_model_update = false;
1028 }
1029
1030 void
solo_use_afl()1031 MonitorSection::solo_use_afl ()
1032 {
1033 /* this is driven by a toggle on a radio group, and so is invoked twice,
1034 once for the item that became inactive and once for the one that became
1035 active.
1036 */
1037
1038 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-afl"));
1039 if (ract->get_active()) {
1040 Config->set_solo_control_is_listen_control (true);
1041 Config->set_listen_position (AfterFaderListen);
1042 }
1043 }
1044
1045 void
solo_use_pfl()1046 MonitorSection::solo_use_pfl ()
1047 {
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
1050 active.
1051 */
1052
1053 Glib::RefPtr<RadioAction> ract = ActionManager::get_radio_action (X_("Solo"), X_("solo-use-pfl"));
1054 if (ract->get_active()) {
1055 Config->set_solo_control_is_listen_control (true);
1056 Config->set_listen_position (PreFaderListen);
1057 }
1058 }
1059
1060 void
update_solo_model()1061 MonitorSection::update_solo_model ()
1062 {
1063 if (_inhibit_solo_model_update) {
1064 return;
1065 }
1066
1067 const char* action_name = 0;
1068 Glib::RefPtr<RadioAction> ract;
1069
1070 if (Config->get_solo_control_is_listen_control()) {
1071 switch (Config->get_listen_position()) {
1072 case AfterFaderListen:
1073 action_name = X_("solo-use-afl");
1074 break;
1075 case PreFaderListen:
1076 action_name = X_("solo-use-pfl");
1077 break;
1078 }
1079 } else {
1080 action_name = X_("solo-use-in-place");
1081 }
1082
1083 ract = ActionManager::get_radio_action (X_("Solo"), action_name);
1084
1085 /* because these are radio buttons, one of them will be
1086 active no matter what. to trigger a change in the
1087 action so that the view picks it up, toggle it.
1088 */
1089
1090 if (ract->get_active()) {
1091 ract->set_active (false);
1092 }
1093
1094 ract->set_active (true);
1095 }
1096
1097 void
map_state()1098 MonitorSection::map_state ()
1099 {
1100 if (!_route || !_monitor) {
1101 return;
1102 }
1103
1104 update_solo_model ();
1105
1106 Glib::RefPtr<Action> act;
1107 Glib::RefPtr<ToggleAction> tact;
1108
1109 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-cut-all");
1110 tact->set_active (_monitor->cut_all());
1111
1112 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-dim-all");
1113 tact->set_active (_monitor->dim_all());
1114
1115 tact = ActionManager::get_toggle_action (X_("Monitor Section"), "monitor-mono");
1116 tact->set_active (_monitor->mono());
1117
1118 uint32_t nchans = _monitor->output_streams().n_audio();
1119
1120 assert (nchans == _channel_buttons.size ());
1121
1122 for (uint32_t n = 0; n < nchans; ++n) {
1123
1124 char action_name[32];
1125
1126 snprintf (action_name, sizeof (action_name), "monitor-cut-%u", n);
1127 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1128 tact->set_active (_monitor->cut (n));
1129
1130 snprintf (action_name, sizeof (action_name), "monitor-dim-%u", n);
1131 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1132 tact->set_active (_monitor->dimmed (n));
1133
1134 snprintf (action_name, sizeof (action_name), "monitor-solo-%u", n);
1135 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1136 tact->set_active (_monitor->soloed (n));
1137
1138 snprintf (action_name, sizeof (action_name), "monitor-invert-%u", n);
1139 tact = ActionManager::get_toggle_action (X_("Monitor"), action_name);
1140 tact->set_active (_monitor->inverted (n));
1141 }
1142 }
1143
1144 void
do_blink(bool onoff)1145 MonitorSection::do_blink (bool onoff)
1146 {
1147 if (!UIConfiguration::instance().get_blink_alert_indicators ()) {
1148 onoff = true;
1149 }
1150
1151 solo_blink (onoff);
1152 audition_blink (onoff);
1153 }
1154
1155 void
audition_blink(bool onoff)1156 MonitorSection::audition_blink (bool onoff)
1157 {
1158 if (_session == 0) {
1159 return;
1160 }
1161
1162 if (_session->is_auditioning()) {
1163 rude_audition_button.set_active (onoff);
1164 } else {
1165 rude_audition_button.set_active (false);
1166 }
1167 }
1168
1169 void
solo_blink(bool onoff)1170 MonitorSection::solo_blink (bool onoff)
1171 {
1172 if (_session == 0) {
1173 return;
1174 }
1175
1176 if (_session->soloing() || _session->listening()) {
1177 rude_solo_button.set_active (onoff);
1178
1179 if (_session->soloing()) {
1180 if (_session->solo_isolated()) {
1181 rude_iso_button.set_active (onoff);
1182 } else {
1183 rude_iso_button.set_active (false);
1184 }
1185 }
1186
1187 } else {
1188 rude_solo_button.set_active (false);
1189 rude_iso_button.set_active (false);
1190 }
1191 }
1192
1193 bool
cancel_isolate(GdkEventButton *)1194 MonitorSection::cancel_isolate (GdkEventButton*)
1195 {
1196 if (_session) {
1197 boost::shared_ptr<RouteList> rl (_session->get_routes ());
1198 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1199 }
1200
1201 return true;
1202 }
1203
1204 bool
cancel_audition(GdkEventButton *)1205 MonitorSection::cancel_audition (GdkEventButton*)
1206 {
1207 if (_session) {
1208 _session->cancel_audition();
1209 }
1210 return true;
1211 }
1212
1213 void
parameter_changed(std::string name)1214 MonitorSection::parameter_changed (std::string name)
1215 {
1216 if (name == "solo-control-is-listen-control") {
1217 update_solo_model ();
1218 } else if (name == "listen-position") {
1219 update_solo_model ();
1220 } else if (name == "solo-mute-override") {
1221 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-mute-overrides-solo"), Config->get_solo_mute_override ());
1222 } else if (name == "exclusive-solo") {
1223 SYNCHRONIZE_TOGGLE_ACTION (ActionManager::get_toggle_action (X_("Solo"), "toggle-exclusive-solo"), Config->get_exclusive_solo ());
1224 }
1225 }
1226
1227 void
unassign_controllables()1228 MonitorSection::unassign_controllables ()
1229 {
1230 boost::shared_ptr<Controllable> none;
1231
1232 solo_cut_control->set_controllable (none);
1233 solo_cut_display->set_controllable (none);
1234 gain_control->set_controllable (none);
1235 gain_display->set_controllable (none);
1236 cut_all_button.set_controllable (none);
1237 dim_all_button.set_controllable (none);
1238 mono_button.set_controllable (none);
1239 dim_control->set_controllable (none);
1240 dim_display->set_controllable (none);
1241 solo_boost_control->set_controllable (none);
1242 solo_boost_display->set_controllable (none);
1243 }
1244
1245 void
assign_controllables()1246 MonitorSection::assign_controllables ()
1247 {
1248 assert (_session);
1249 assert (_route);
1250 assert (_monitor);
1251
1252 solo_cut_control->set_controllable (_session->solo_cut_control());
1253 solo_cut_display->set_controllable (_session->solo_cut_control());
1254
1255 gain_control->set_controllable (_route->gain_control());
1256 gain_display->set_controllable (_route->gain_control());
1257 cut_all_button.set_controllable (_monitor->cut_control());
1258 cut_all_button.watch ();
1259 dim_all_button.set_controllable (_monitor->dim_control());
1260 dim_all_button.watch ();
1261 mono_button.set_controllable (_monitor->mono_control());
1262 mono_button.watch ();
1263 dim_control->set_controllable (_monitor->dim_level_control ());
1264 dim_display->set_controllable (_monitor->dim_level_control ());
1265 solo_boost_control->set_controllable (_monitor->solo_boost_control ());
1266 solo_boost_display->set_controllable (_monitor->solo_boost_control ());
1267 }
1268
1269 string
state_id() const1270 MonitorSection::state_id() const
1271 {
1272 return "monitor-section";
1273 }
1274
1275 void
maybe_add_bundle_to_output_menu(boost::shared_ptr<Bundle> b,ARDOUR::BundleList const &)1276 MonitorSection::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1277 {
1278 using namespace Menu_Helpers;
1279
1280 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1281 return;
1282 }
1283
1284 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1285 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1286 ++i;
1287 }
1288
1289 if (i != output_menu_bundles.end()) {
1290 return;
1291 }
1292
1293 output_menu_bundles.push_back (b);
1294
1295 MenuList& citems = output_menu.items();
1296
1297 std::string n = b->name ();
1298 replace_all (n, "_", " ");
1299
1300 citems.push_back (MenuElem (n, sigc::bind (sigc::mem_fun(*this, &MonitorSection::bundle_output_chosen), b)));
1301 }
1302
1303 void
bundle_output_chosen(boost::shared_ptr<ARDOUR::Bundle> c)1304 MonitorSection::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1305 {
1306
1307 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1308
1309 if (std::find (current.begin(), current.end(), c) == current.end()) {
1310 _route->output()->connect_ports_to_bundle (c, true, this);
1311 } else {
1312 _route->output()->disconnect_ports_from_bundle (c, this);
1313 }
1314 }
1315
1316 gint
output_release(GdkEventButton * ev)1317 MonitorSection::output_release (GdkEventButton *ev)
1318 {
1319 switch (ev->button) {
1320 case 3:
1321 edit_output_configuration ();
1322 break;
1323 }
1324
1325 return false;
1326 }
1327
1328 struct RouteCompareByName {
operator ()RouteCompareByName1329 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1330 return a->name().compare (b->name()) < 0;
1331 }
1332 };
1333
1334 gint
output_press(GdkEventButton * ev)1335 MonitorSection::output_press (GdkEventButton *ev)
1336 {
1337 using namespace Menu_Helpers;
1338 if (!_session) {
1339 MessageDialog msg (_("No session - no I/O changes are possible"));
1340 msg.run ();
1341 return true;
1342 }
1343
1344 MenuList& citems = output_menu.items();
1345 switch (ev->button) {
1346
1347 case 3:
1348 return false; //wait for the mouse-up to pop the dialog
1349
1350 case 1:
1351 {
1352 output_menu.set_name ("ArdourContextMenu");
1353 citems.clear ();
1354 output_menu_bundles.clear ();
1355
1356 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(this), &MonitorSection::disconnect_output)));
1357
1358 citems.push_back (SeparatorElem());
1359 uint32_t const n_with_separator = citems.size ();
1360
1361 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1362
1363 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1364
1365 /* give user bundles first chance at being in the menu */
1366
1367 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1368 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1369 maybe_add_bundle_to_output_menu (*i, current);
1370 }
1371 }
1372
1373 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1374 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1375 maybe_add_bundle_to_output_menu (*i, current);
1376 }
1377 }
1378
1379 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1380 RouteList copy = *routes;
1381 copy.sort (RouteCompareByName ());
1382 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1383 maybe_add_bundle_to_output_menu ((*i)->output()->bundle(), current);
1384 }
1385
1386 if (citems.size() == n_with_separator) {
1387 /* no routes added; remove the separator */
1388 citems.pop_back ();
1389 }
1390
1391 citems.push_back (SeparatorElem());
1392 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(this), &MonitorSection::edit_output_configuration)));
1393
1394 output_menu.popup (1, ev->time);
1395 break;
1396 }
1397
1398 default:
1399 break;
1400 }
1401 return TRUE;
1402 }
1403
1404 void
update_output_display()1405 MonitorSection::update_output_display ()
1406 {
1407 if (!_route || !_monitor || _session->deletion_in_progress()) {
1408 return;
1409 }
1410
1411 uint32_t io_count;
1412 uint32_t io_index;
1413 boost::shared_ptr<Port> port;
1414 vector<string> port_connections;
1415
1416 uint32_t total_connection_count = 0;
1417 uint32_t io_connection_count = 0;
1418 uint32_t ardour_connection_count = 0;
1419 uint32_t system_connection_count = 0;
1420 uint32_t other_connection_count = 0;
1421
1422 ostringstream label;
1423
1424 bool have_label = false;
1425 bool each_io_has_one_connection = true;
1426
1427 string connection_name;
1428 string ardour_track_name;
1429 string other_connection_type;
1430 string system_ports;
1431 string system_port;
1432
1433 ostringstream tooltip;
1434 char * tooltip_cstr;
1435
1436 io_count = _route->n_outputs().n_total();
1437 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1438
1439
1440 for (io_index = 0; io_index < io_count; ++io_index) {
1441
1442 port = _route->output()->nth (io_index);
1443
1444 //ignore any port connections that don't match our DataType
1445 if (port->type() != DataType::AUDIO) {
1446 continue;
1447 }
1448
1449 port_connections.clear ();
1450 port->get_connections(port_connections);
1451 io_connection_count = 0;
1452
1453 if (!port_connections.empty()) {
1454 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1455 string pn = "";
1456 string& connection_name (*i);
1457
1458 if (connection_name.find("system:") == 0) {
1459 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1460 }
1461
1462 if (io_connection_count == 0) {
1463 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1464 << " -> "
1465 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1466 } else {
1467 tooltip << ", "
1468 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1469 }
1470
1471 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1472 if (ardour_track_name.empty()) {
1473 // "ardour:Master/in 1" -> "ardour:Master/"
1474 string::size_type slash = connection_name.find("/");
1475 if (slash != string::npos) {
1476 ardour_track_name = connection_name.substr(0, slash + 1);
1477 }
1478 }
1479
1480 if (connection_name.find(ardour_track_name) == 0) {
1481 ++ardour_connection_count;
1482 }
1483 } else if (!pn.empty()) {
1484 if (system_ports.empty()) {
1485 system_ports += pn;
1486 } else {
1487 system_ports += "/" + pn;
1488 }
1489 if (connection_name.find("system:") == 0) {
1490 ++system_connection_count;
1491 }
1492 } else if (connection_name.find("system:") == 0) {
1493 // "system:playback_123" -> "123"
1494 system_port = connection_name.substr(16);
1495 if (system_ports.empty()) {
1496 system_ports += system_port;
1497 } else {
1498 system_ports += "/" + system_port;
1499 }
1500
1501 ++system_connection_count;
1502 } else {
1503 if (other_connection_type.empty()) {
1504 // "jamin:in 1" -> "jamin:"
1505 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1506 }
1507
1508 if (connection_name.find(other_connection_type) == 0) {
1509 ++other_connection_count;
1510 }
1511 }
1512
1513 ++total_connection_count;
1514 ++io_connection_count;
1515 }
1516 }
1517
1518 if (io_connection_count != 1) {
1519 each_io_has_one_connection = false;
1520 }
1521 }
1522
1523 if (total_connection_count == 0) {
1524 tooltip << endl << _("Disconnected");
1525 }
1526
1527 tooltip_cstr = new char[tooltip.str().size() + 1];
1528 strcpy(tooltip_cstr, tooltip.str().c_str());
1529
1530 set_tooltip (output_button, tooltip_cstr, "");
1531
1532 if (each_io_has_one_connection) {
1533 if (total_connection_count == ardour_connection_count) {
1534 // all connections are to the same track in ardour
1535 // "ardour:Master/" -> "Master"
1536 string::size_type slash = ardour_track_name.find("/");
1537 if (slash != string::npos) {
1538 label << ardour_track_name.substr(7, slash - 7);
1539 have_label = true;
1540 }
1541 } else if (total_connection_count == system_connection_count) {
1542 // all connections are to system ports
1543 label << system_ports;
1544 have_label = true;
1545 } else if (total_connection_count == other_connection_count) {
1546 // all connections are to the same external program eg jamin
1547 // "jamin:" -> "jamin"
1548 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1549 have_label = true;
1550 }
1551 }
1552
1553 if (!have_label) {
1554 if (total_connection_count == 0) {
1555 // Disconnected
1556 label << "-";
1557 } else {
1558 // Odd configuration
1559 label << "*" << total_connection_count << "*";
1560 }
1561 }
1562
1563 output_button->set_text (label.str());
1564 }
1565
1566 void
disconnect_output()1567 MonitorSection::disconnect_output ()
1568 {
1569 if (_route) {
1570 _route->output()->disconnect(this);
1571 }
1572 }
1573
1574 void
edit_output_configuration()1575 MonitorSection::edit_output_configuration ()
1576 {
1577 if (_output_selector == 0) {
1578 _output_selector = new MonitorSelectorWindow (_session, _route->output());
1579 }
1580 _output_selector->present ();
1581 }
1582
1583 void
port_connected_or_disconnected(boost::weak_ptr<Port> wa,boost::weak_ptr<Port> wb)1584 MonitorSection::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1585 {
1586 if (!_route) {
1587 return;
1588 }
1589 boost::shared_ptr<Port> a = wa.lock ();
1590 boost::shared_ptr<Port> b = wb.lock ();
1591 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1592 update_output_display ();
1593 }
1594 }
1595
1596 void
port_pretty_name_changed(std::string pn)1597 MonitorSection::port_pretty_name_changed (std::string pn)
1598 {
1599 if (!_route) {
1600 return;
1601 }
1602 if (_route->output()->connected_to (pn)) {
1603 update_output_display ();
1604 }
1605 }
1606
1607
1608 void
load_bindings()1609 MonitorSection::load_bindings ()
1610 {
1611 bindings = Bindings::get_bindings (X_("Monitor Section"));
1612 }
1613
1614 void
help_count_processors(boost::weak_ptr<Processor> p,uint32_t * cnt) const1615 MonitorSection::help_count_processors (boost::weak_ptr<Processor> p, uint32_t* cnt) const
1616 {
1617 boost::shared_ptr<Processor> processor (p.lock ());
1618 if (!processor || !processor->display_to_user()) {
1619 return;
1620 }
1621 if (boost::dynamic_pointer_cast<Amp>(processor)) {
1622 return;
1623 }
1624 ++(*cnt);
1625 }
1626
1627 uint32_t
count_processors()1628 MonitorSection::count_processors ()
1629 {
1630 uint32_t processor_count = 0;
1631 if (_route) {
1632 _route->foreach_processor (sigc::bind (sigc::mem_fun (*this, &MonitorSection::help_count_processors), &processor_count));
1633 }
1634 return processor_count;
1635 }
1636
1637 void
processors_changed(ARDOUR::RouteProcessorChange)1638 MonitorSection::processors_changed (ARDOUR::RouteProcessorChange)
1639 {
1640 update_processor_box ();
1641 }
1642
1643 PluginSelector*
plugin_selector()1644 MonitorSection::plugin_selector ()
1645 {
1646 return Mixer_UI::instance()->plugin_selector ();
1647 }
1648
1649 void
use_others_actions()1650 MonitorSection::use_others_actions ()
1651 {
1652 rude_solo_button.set_related_action (ActionManager::get_action (X_("Main"), X_("cancel-solo")));
1653 }
1654
1655 void
toggle_use_monitor_section()1656 MonitorSection::toggle_use_monitor_section ()
1657 {
1658 if (!_session) {
1659 return;
1660 }
1661 bool want_ms = ActionManager::get_toggle_action (X_("Monitor"), "UseMonitorSection")->get_active();
1662 bool have_ms = Config->get_use_monitor_bus ();
1663
1664 if (want_ms == have_ms) {
1665 return;
1666 }
1667
1668 if (want_ms) {
1669 Config->set_use_monitor_bus (true);
1670 ActionManager::get_toggle_action (X_("Mixer"), X_("ToggleMonitorSection"))->set_active (true);
1671 } else {
1672 Config->set_use_monitor_bus (false);
1673 }
1674 }
1675