2 * Copyright (C) 2005-2006 Nick Mainsbridge <mainsbridge@gmail.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
5 * Copyright (C) 2005-2017 Paul Davis <paul@linuxaudiosystems.com>
6 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
9 * Copyright (C) 2009-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 * Copyright (C) 2015-2016 Tim Mayberry <mojofunk@gmail.com>
14 * Copyright (C) 2016-2017 Julien "_FrnchFrgg_" RIVAUD <frnchfrgg@free.fr>
15 * Copyright (C) 2018 Len Ovens <len@ovenwerks.net>
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 #include <sigc++/bind.h>
38 #include <gtkmm/messagedialog.h>
40 #include "pbd/convert.h"
41 #include "pbd/enumwriter.h"
42 #include "pbd/replace_all.h"
43 #include "pbd/stacktrace.h"
44 #include "pbd/unwind.h"
46 #include "ardour/amp.h"
47 #include "ardour/audio_track.h"
48 #include "ardour/audioengine.h"
49 #include "ardour/internal_send.h"
50 #include "ardour/io.h"
51 #include "ardour/meter.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/pannable.h"
54 #include "ardour/panner.h"
55 #include "ardour/panner_shell.h"
56 #include "ardour/panner_manager.h"
57 #include "ardour/port.h"
58 #include "ardour/profile.h"
59 #include "ardour/route.h"
60 #include "ardour/route_group.h"
61 #include "ardour/send.h"
62 #include "ardour/session.h"
63 #include "ardour/types.h"
64 #include "ardour/user_bundle.h"
65 #include "ardour/vca.h"
66 #include "ardour/vca_manager.h"
68 #include "gtkmm2ext/gtk_ui.h"
69 #include "gtkmm2ext/menu_elems.h"
70 #include "gtkmm2ext/utils.h"
71 #include "gtkmm2ext/doi.h"
73 #include "widgets/tooltips.h"
75 #include "ardour_window.h"
76 #include "context_menu_helper.h"
77 #include "enums_convert.h"
78 #include "mixer_strip.h"
81 #include "public_editor.h"
83 #include "io_selector.h"
85 #include "gui_thread.h"
86 #include "route_group_menu.h"
87 #include "meter_patterns.h"
88 #include "ui_config.h"
92 using namespace ARDOUR;
93 using namespace ArdourWidgets;
96 using namespace Gtkmm2ext;
98 using namespace ArdourMeter;
100 MixerStrip* MixerStrip::_entered_mixer_strip;
101 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
103 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
104 : SessionHandlePtr (sess)
107 , _mixer_owned (in_mixer)
108 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
111 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
112 , rec_mon_table (2, 2)
113 , solo_iso_table (1, 2)
114 , mute_solo_table (1, 2)
115 , bottom_button_table (1, 3)
116 , monitor_section_button (0)
117 , midi_input_enable_button (0)
118 , _plugin_insert_cnt (0)
119 , _comment_button (_("Comments"))
120 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
121 , _visibility (X_("mixer-element-visibility"))
122 , _suspend_menu_callbacks (false)
123 , control_slave_ui (sess)
128 /* the editor mixer strip: don't destroy it every time
129 the underlying route goes away.
132 self_destruct = false;
136 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
137 : SessionHandlePtr (sess)
140 , _mixer_owned (in_mixer)
141 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
144 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
145 , rec_mon_table (2, 2)
146 , solo_iso_table (1, 2)
147 , mute_solo_table (1, 2)
148 , bottom_button_table (1, 3)
149 , monitor_section_button (0)
150 , midi_input_enable_button (0)
151 , _plugin_insert_cnt (0)
152 , _comment_button (_("Comments"))
153 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
154 , _visibility (X_("mixer-element-visibility"))
155 , _suspend_menu_callbacks (false)
156 , control_slave_ui (sess)
165 _entered_mixer_strip= 0;
168 ignore_comment_edit = false;
169 ignore_toggle = false;
173 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
174 longest_label = "longest label";
176 string t = _("Click to toggle the width of this mixer strip.");
178 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
181 width_button.set_icon (ArdourIcon::StripWidth);
182 hide_button.set_tweaks (ArdourButton::Square);
183 set_tooltip (width_button, t);
185 hide_button.set_icon (ArdourIcon::HideEye);
186 hide_button.set_tweaks (ArdourButton::Square);
187 set_tooltip (&hide_button, _("Hide this mixer strip"));
189 input_button_box.set_spacing(2);
191 input_button.set_text (_("Input"));
192 input_button.set_name ("mixer strip button");
193 input_button_box.pack_start (input_button, true, true);
195 output_button.set_text (_("Output"));
196 output_button.set_name ("mixer strip button");
198 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
200 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
202 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
203 solo_isolated_led->show ();
204 solo_isolated_led->set_no_show_all (true);
205 solo_isolated_led->set_name (X_("solo isolate"));
206 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
207 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
208 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
210 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
211 solo_safe_led->show ();
212 solo_safe_led->set_no_show_all (true);
213 solo_safe_led->set_name (X_("solo safe"));
214 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
215 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
216 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
218 solo_safe_led->set_text (S_("SoloLock|Lock"));
219 solo_isolated_led->set_text (_("Iso"));
221 solo_iso_table.set_homogeneous (true);
222 solo_iso_table.set_spacings (2);
223 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
224 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
225 solo_iso_table.show ();
227 rec_mon_table.set_homogeneous (true);
228 rec_mon_table.set_row_spacings (2);
229 rec_mon_table.set_col_spacings (2);
230 if (ARDOUR::Profile->get_mixbus()) {
231 rec_mon_table.resize (1, 3);
232 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
233 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
235 rec_mon_table.show ();
237 if (solo_isolated_led) {
238 button_size_group->add_widget (*solo_isolated_led);
241 button_size_group->add_widget (*solo_safe_led);
244 if (!ARDOUR::Profile->get_mixbus()) {
245 if (rec_enable_button) {
246 button_size_group->add_widget (*rec_enable_button);
248 if (monitor_disk_button) {
249 button_size_group->add_widget (*monitor_disk_button);
251 if (monitor_input_button) {
252 button_size_group->add_widget (*monitor_input_button);
256 mute_solo_table.set_homogeneous (true);
257 mute_solo_table.set_spacings (2);
259 bottom_button_table.set_spacings (2);
260 bottom_button_table.set_homogeneous (true);
261 bottom_button_table.attach (group_button, 1, 2, 0, 1);
262 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
264 name_button.set_name ("mixer strip button");
265 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
266 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
268 set_tooltip (&group_button, _("Mix group"));
269 group_button.set_name ("mixer strip button");
271 _comment_button.set_name (X_("mixer strip button"));
272 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
273 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
274 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
276 // TODO implement ArdourKnob::on_size_request properly
277 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
278 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
280 trim_control.set_tooltip_prefix (_("Trim: "));
281 trim_control.set_name ("trim knob");
282 trim_control.set_no_show_all (true);
283 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
284 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
285 input_button_box.pack_start (trim_control, false, false);
287 global_vpacker.set_border_width (1);
288 global_vpacker.set_spacing (0);
290 width_button.set_name ("mixer strip button");
291 hide_button.set_name ("mixer strip button");
293 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
294 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
296 width_hide_box.set_spacing (2);
297 width_hide_box.pack_start (width_button, false, true);
298 width_hide_box.pack_start (number_label, true, true);
299 width_hide_box.pack_end (hide_button, false, true);
301 number_label.set_text ("-");
302 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
303 number_label.set_no_show_all ();
304 number_label.set_name ("tracknumber label");
305 number_label.set_fixed_colors (0x80808080, 0x80808080);
306 number_label.set_alignment (.5, .5);
307 number_label.set_fallthrough_to_parent (true);
308 number_label.set_tweaks (ArdourButton::OccasionalText);
310 global_vpacker.set_spacing (2);
311 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (processor_box, true, true);
316 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
318 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
320 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
321 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
322 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
323 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
324 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
327 //add a spacer underneath the master bus;
328 //this fills the area that is taken up by the scrollbar on the tracks;
329 //and therefore keeps the faders "even" across the bottom
330 int scrollbar_height = 0;
332 Gtk::Window window (WINDOW_TOPLEVEL);
333 HScrollbar scrollbar;
334 window.add (scrollbar);
335 scrollbar.set_name ("MixerWindow");
336 scrollbar.ensure_style();
337 Gtk::Requisition requisition(scrollbar.size_request ());
338 scrollbar_height = requisition.height;
340 spacer.set_size_request (-1, scrollbar_height);
341 global_vpacker.pack_end (spacer, false, false);
344 global_frame.add (global_vpacker);
345 global_frame.set_shadow_type (Gtk::SHADOW_IN);
346 global_frame.set_name ("BaseFrame");
350 /* force setting of visible selected status */
353 set_selected (false);
358 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
359 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
360 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
362 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
363 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
365 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
366 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
367 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
369 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
371 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
373 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
377 /* start off as a passthru strip. we'll correct this, if necessary,
378 in update_diskstream_display().
381 /* start off as a passthru strip. we'll correct this, if necessary,
382 in update_diskstream_display().
385 if (is_midi_track()) {
386 set_name ("MidiTrackStripBase");
388 set_name ("AudioTrackStripBase");
391 add_events (Gdk::BUTTON_RELEASE_MASK|
392 Gdk::ENTER_NOTIFY_MASK|
393 Gdk::LEAVE_NOTIFY_MASK|
395 Gdk::KEY_RELEASE_MASK);
397 set_flags (get_flags() | Gtk::CAN_FOCUS);
399 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
400 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
403 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
404 must be the same as those used in RCOptionEditor so that the configuration changes
405 are recognised when they occur.
407 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
408 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
409 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
410 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
411 _visibility.add (&output_button, X_("Output"), _("Output"), false);
412 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
413 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
415 parameter_changed (X_("mixer-element-visibility"));
416 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
417 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
418 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
420 //watch for mouse enter/exit so we can do some stuff
421 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
422 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
424 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
427 MixerStrip::~MixerStrip ()
429 CatchDeletion (this);
431 if (this ==_entered_mixer_strip)
432 _entered_mixer_strip = NULL;
436 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
438 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
444 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
446 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
452 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
454 _entered_mixer_strip = this;
456 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
457 //because the mixerstrip control is a parent that encompasses the strip
458 deselect_all_processors();
464 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
466 //if we have moved outside our strip, but not into a child view, then deselect ourselves
467 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
468 _entered_mixer_strip= 0;
470 //clear keyboard focus in the gain display. this is cheesy but fixes a longstanding "bug" where the user starts typing in the gain entry, and leaves it active, thereby prohibiting other keybindings from working
471 gpm.gain_display.set_sensitive(false);
473 gpm.gain_display.set_sensitive(true);
475 //if we leave this mixer strip we need to clear out any selections
476 //processor_box.processor_display.select_none(); //but this doesn't work, because it gets triggered when (for example) you open the menu or start a drag
483 MixerStrip::name() const
486 return _route->name();
492 MixerStrip::update_trim_control ()
494 if (route()->trim() && route()->trim()->active() &&
495 route()->n_inputs().n_audio() > 0) {
496 trim_control.show ();
497 trim_control.set_controllable (route()->trim()->gain_control());
499 trim_control.hide ();
500 boost::shared_ptr<Controllable> none;
501 trim_control.set_controllable (none);
506 MixerStrip::trim_start_touch ()
508 assert (_route && _session);
509 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
510 route()->trim()->gain_control ()->start_touch (_session->transport_sample());
515 MixerStrip::trim_end_touch ()
517 assert (_route && _session);
518 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
519 route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
524 MixerStrip::set_route (boost::shared_ptr<Route> rt)
526 //the rec/monitor stuff only shows up for tracks.
527 //the show_sends only shows up for buses.
528 //remove them all here, and we may add them back later
529 if (show_sends_button->get_parent()) {
530 rec_mon_table.remove (*show_sends_button);
532 if (rec_enable_button->get_parent()) {
533 rec_mon_table.remove (*rec_enable_button);
535 if (monitor_input_button->get_parent()) {
536 rec_mon_table.remove (*monitor_input_button);
538 if (monitor_disk_button->get_parent()) {
539 rec_mon_table.remove (*monitor_disk_button);
541 if (group_button.get_parent()) {
542 bottom_button_table.remove (group_button);
545 RouteUI::set_route (rt);
547 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
549 /* ProcessorBox needs access to _route so that it can read
552 processor_box.set_route (rt);
554 revert_to_default_display ();
556 /* unpack these from the parent and stuff them into our own
560 if (gpm.peak_display.get_parent()) {
561 gpm.peak_display.get_parent()->remove (gpm.peak_display);
563 if (gpm.gain_display.get_parent()) {
564 gpm.gain_display.get_parent()->remove (gpm.gain_display);
567 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
568 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
570 if (solo_button->get_parent()) {
571 mute_solo_table.remove (*solo_button);
574 if (mute_button->get_parent()) {
575 mute_solo_table.remove (*mute_button);
578 if (route()->is_master()) {
579 solo_button->hide ();
580 mute_button->show ();
581 rec_mon_table.hide ();
582 solo_iso_table.set_sensitive(false);
583 control_slave_ui.set_sensitive(false);
584 if (monitor_section_button == 0) {
585 Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
586 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
587 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
589 monitor_section_button = manage (new ArdourButton);
591 monitor_section_button->set_related_action (act);
592 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
593 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
594 monitor_section_button->show();
595 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
596 monitor_section_added_or_removed ();
599 bottom_button_table.attach (group_button, 1, 2, 0, 1);
600 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
601 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
602 mute_button->show ();
603 solo_button->show ();
604 rec_mon_table.show ();
605 solo_iso_table.set_sensitive(true);
606 control_slave_ui.set_sensitive(true);
609 hide_master_spacer (false);
612 monitor_input_button->show ();
613 monitor_disk_button->show ();
615 monitor_input_button->hide();
616 monitor_disk_button->hide ();
619 update_trim_control();
621 if (is_midi_track()) {
622 if (midi_input_enable_button == 0) {
623 midi_input_enable_button = manage (new ArdourButton);
624 midi_input_enable_button->set_name ("midi input button");
625 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
626 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
627 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
628 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
629 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
631 input_button_box.remove (*midi_input_enable_button);
633 /* get current state */
634 midi_input_status_changed ();
635 input_button_box.pack_start (*midi_input_enable_button, false, false);
637 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
639 if (midi_input_enable_button) {
640 /* removal from the container will delete it */
641 input_button_box.remove (*midi_input_enable_button);
642 midi_input_enable_button = 0;
646 if (is_audio_track()) {
647 boost::shared_ptr<AudioTrack> at = audio_track();
648 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
653 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
654 rec_enable_button->show();
656 if (ARDOUR::Profile->get_mixbus()) {
657 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
658 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
660 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
661 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
668 if (!_route->is_master()) {
669 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
670 show_sends_button->show();
674 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
676 delete route_ops_menu;
679 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
680 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
681 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
682 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
684 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
686 if (_route->panner_shell()) {
687 update_panner_choices();
688 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
691 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
693 set_stuff_from_route ();
695 /* now force an update of all the various elements */
697 update_mute_display ();
698 update_solo_display ();
701 route_group_changed ();
702 update_track_number_visibility ();
705 panners.setup_pan ();
707 if (has_audio_outputs ()) {
713 update_diskstream_display ();
714 update_input_display ();
715 update_output_display ();
717 add_events (Gdk::BUTTON_RELEASE_MASK);
719 processor_box.show ();
721 if (!route()->is_master() && !route()->is_monitor()) {
722 /* we don't allow master or control routes to be hidden */
727 gpm.reset_peak_display ();
728 gpm.gain_display.show ();
729 gpm.peak_display.show ();
732 width_hide_box.show();
734 global_vpacker.show();
735 mute_solo_table.show();
736 bottom_button_table.show();
738 gpm.meter_point_button.show();
739 input_button_box.show_all();
740 output_button.show();
742 _comment_button.show();
744 gpm.gain_automation_state_button.show();
746 parameter_changed ("mixer-element-visibility");
753 MixerStrip::set_stuff_from_route ()
755 /* if width is not set, it will be set by the MixerUI or editor */
758 if (get_gui_property ("strip-width", width)) {
759 set_width_enum (width, this);
764 MixerStrip::set_width_enum (Width w, void* owner)
766 /* always set the gpm width again, things may be hidden */
769 panners.set_width (w);
771 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
773 _width_owner = owner;
777 if (_width_owner == this) {
778 set_gui_property ("strip-width", _width);
783 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
788 if (show_sends_button) {
789 show_sends_button->set_text (_("Aux"));
792 gpm.gain_automation_state_button.set_text (
793 gpm.astate_string(gain_automation->automation_state()));
795 if (_route->panner()) {
796 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
797 panners.astate_string(_route->panner()->automation_state()));
801 // panners expect an even number of horiz. pixels
802 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
804 set_size_request (width, -1);
810 if (show_sends_button) {
811 show_sends_button->set_text (_("Snd"));
814 gpm.gain_automation_state_button.set_text (
815 gpm.short_astate_string(gain_automation->automation_state()));
816 gain_meter().setup_meters (); // recalc meter width
818 if (_route->panner()) {
819 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
820 panners.short_astate_string(_route->panner()->automation_state()));
824 // panners expect an even number of horiz. pixels
825 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
827 set_size_request (width, -1);
832 processor_box.set_width (w);
834 update_input_display ();
835 update_output_display ();
836 setup_comment_button ();
837 route_group_changed ();
843 MixerStrip::set_packed (bool yn)
846 set_gui_property ("visible", _packed);
850 struct RouteCompareByName {
851 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
852 return a->name().compare (b->name()) < 0;
857 MixerStrip::output_release (GdkEventButton *ev)
859 switch (ev->button) {
861 edit_output_configuration ();
869 MixerStrip::output_press (GdkEventButton *ev)
871 using namespace Menu_Helpers;
872 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
876 MenuList& citems = output_menu.items();
877 switch (ev->button) {
880 return false; //wait for the mouse-up to pop the dialog
884 output_menu.set_name ("ArdourContextMenu");
886 output_menu_bundles.clear ();
888 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
890 citems.push_back (SeparatorElem());
891 uint32_t const n_with_separator = citems.size ();
893 ARDOUR::BundleList current = _route->output()->bundles_connected ();
895 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
897 /* guess the user-intended main type of the route output */
898 DataType intended_type = guess_main_type(false);
900 /* try adding the master bus first */
901 boost::shared_ptr<Route> master = _session->master_out();
903 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
906 /* then other routes inputs */
907 RouteList copy = _session->get_routelist ();
908 copy.sort (RouteCompareByName ());
909 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
910 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
913 /* then try adding user bundles, often labeled/grouped physical inputs */
914 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
915 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
916 maybe_add_bundle_to_output_menu (*i, current, intended_type);
920 /* then all other bundles, including physical outs or other sofware */
921 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
923 maybe_add_bundle_to_output_menu (*i, current, intended_type);
927 if (citems.size() == n_with_separator) {
928 /* no routes added; remove the separator */
932 citems.push_back (SeparatorElem());
934 if (!ARDOUR::Profile->get_mixbus()) {
935 bool need_separator = false;
936 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
937 if (!_route->output()->can_add_port (*i)) {
940 need_separator = true;
943 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
944 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
948 if (need_separator) {
949 citems.push_back (SeparatorElem());
953 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
955 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
968 MixerStrip::input_release (GdkEventButton *ev)
970 switch (ev->button) {
973 edit_input_configuration ();
985 MixerStrip::input_press (GdkEventButton *ev)
987 using namespace Menu_Helpers;
989 MenuList& citems = input_menu.items();
990 input_menu.set_name ("ArdourContextMenu");
993 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
997 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1000 switch (ev->button) {
1003 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1007 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1009 citems.push_back (SeparatorElem());
1010 uint32_t const n_with_separator = citems.size ();
1012 input_menu_bundles.clear ();
1014 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1016 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1018 /* give user bundles first chance at being in the menu */
1020 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1021 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1022 maybe_add_bundle_to_input_menu (*i, current);
1026 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1027 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1028 maybe_add_bundle_to_input_menu (*i, current);
1032 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1033 RouteList copy = *routes;
1034 copy.sort (RouteCompareByName ());
1035 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1036 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1039 if (citems.size() == n_with_separator) {
1040 /* no routes added; remove the separator */
1044 citems.push_back (SeparatorElem());
1046 bool need_separator = false;
1047 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1048 if (!_route->input()->can_add_port (*i)) {
1051 need_separator = true;
1054 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1055 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1059 if (need_separator) {
1060 citems.push_back (SeparatorElem());
1063 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1065 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1077 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1079 if (ignore_toggle) {
1083 _route->input()->connect_ports_to_bundle (c, true, this);
1087 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1089 if (ignore_toggle) {
1093 _route->output()->connect_ports_to_bundle (c, true, true, this);
1097 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1099 using namespace Menu_Helpers;
1101 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1105 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1106 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1110 if (i != input_menu_bundles.end()) {
1114 input_menu_bundles.push_back (b);
1116 MenuList& citems = input_menu.items();
1117 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1121 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1124 using namespace Menu_Helpers;
1126 /* The bundle should be an input one, but not ours */
1127 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1131 /* Don't add the monitor input unless we are Master */
1132 boost::shared_ptr<Route> monitor = _session->monitor_out();
1133 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1136 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1137 * or have the same number of |type| channels than our outputs. */
1138 if (type == DataType::NIL) {
1139 if(b->nchannels() != _route->n_outputs())
1142 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1146 /* Avoid adding duplicates */
1147 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1148 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1151 if (i != output_menu_bundles.end()) {
1155 /* Now add the bundle to the menu */
1156 output_menu_bundles.push_back (b);
1158 MenuList& citems = output_menu.items();
1159 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1163 MixerStrip::update_diskstream_display ()
1165 if (is_track() && input_selector) {
1166 input_selector->hide_all ();
1169 route_color_changed ();
1173 MixerStrip::connect_to_pan ()
1175 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1177 panstate_connection.disconnect ();
1178 panstyle_connection.disconnect ();
1180 if (!_route->panner()) {
1184 boost::shared_ptr<Pannable> p = _route->pannable ();
1186 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1188 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1189 * However, that only works a panner was previously set.
1191 * PannerUI must remain subscribed to _panshell->Changed() in case
1192 * we switch the panner eg. AUX-Send and back
1193 * _route->panner_shell()->Changed() vs _panshell->Changed
1195 if (panners._panner == 0) {
1196 panners.panshell_changed ();
1198 update_panner_choices();
1202 MixerStrip::update_panner_choices ()
1204 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1205 if (!_route->panner_shell()) { return; }
1207 uint32_t in = _route->output()->n_ports().n_audio();
1209 if (_route->panner()) {
1210 in = _route->panner()->in().n_audio();
1213 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1217 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1219 /* The heuristic follows these principles:
1220 * A) If all ports that the user connected are of the same type, then he
1221 * very probably intends to use the IO with that type. A common subcase
1222 * is when the IO has only ports of the same type (connected or not).
1223 * B) If several types of ports are connected, then we should guess based
1224 * on the likeliness of the user wanting to use a given type.
1225 * We assume that the DataTypes are ordered from the most likely to the
1226 * least likely when iterating or comparing them with "<".
1227 * C) If no port is connected, the same logic can be applied with all ports
1228 * instead of connected ones. TODO: Try other ideas, for instance look at
1229 * the last plugin output when |for_input| is false (note: when StrictIO
1230 * the outs of the last plugin should be the same as the outs of the route
1231 * modulo the panner which forwards non-audio anyway).
1232 * All of these constraints are respected by the following algorithm that
1233 * just returns the most likely datatype found in connected ports if any, or
1234 * available ports if any (since if all ports are of the same type, the most
1235 * likely found will be that one obviously). */
1237 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1239 /* Find most likely type among connected ports */
1240 if (favor_connected) {
1241 DataType type = DataType::NIL; /* NIL is always last so least likely */
1242 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1243 if (p->connected() && p->type() < type)
1246 if (type != DataType::NIL) {
1247 /* There has been a connected port (necessarily non-NIL) */
1252 /* Find most likely type among available ports.
1253 * The iterator stops before NIL. */
1254 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1255 if (io->n_ports().n(*t) > 0)
1259 /* No port at all, return the most likely datatype by default */
1260 return DataType::front();
1264 * Output port labelling
1266 * Case 1: Each output has one connection, all connections are to system:playback_%i
1267 * out 1 -> system:playback_1
1268 * out 2 -> system:playback_2
1269 * out 3 -> system:playback_3
1272 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1273 * out 1 -> ardour:track_x/in 1
1274 * out 2 -> ardour:track_x/in 2
1275 * Display as: track_x
1277 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1278 * out 1 -> program x:foo
1279 * out 2 -> program x:foo
1280 * Display as: program x
1282 * Case 4: No connections (Disconnected)
1285 * Default case (unusual routing):
1286 * Display as: *number of connections*
1291 * .-----------------------------------------------.
1293 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1294 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1295 * '-----------------------------------------------'
1296 * .-----------------------------------------------.
1299 * '-----------------------------------------------'
1303 MixerStrip::update_io_button (bool for_input)
1305 ostringstream tooltip;
1306 ostringstream label;
1307 bool have_label = false;
1309 uint32_t total_connection_count = 0;
1310 uint32_t typed_connection_count = 0;
1311 bool each_typed_port_has_one_connection = true;
1313 DataType dt = guess_main_type(for_input);
1314 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1316 /* Fill in the tooltip. Also count:
1317 * - The total number of connections.
1318 * - The number of main-typed connections.
1319 * - Whether each main-typed port has exactly one connection. */
1321 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1322 Gtkmm2ext::markup_escape_text (_route->name()));
1324 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1325 Gtkmm2ext::markup_escape_text (_route->name()));
1328 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1329 vector<string> port_connections;
1330 for (PortSet::iterator port = io->ports().begin();
1331 port != io->ports().end();
1333 port_connections.clear();
1334 port->get_connections(port_connections);
1336 uint32_t port_connection_count = 0;
1338 for (vector<string>::iterator i = port_connections.begin();
1339 i != port_connections.end();
1341 ++port_connection_count;
1343 if (port_connection_count == 1) {
1344 tooltip << endl << Gtkmm2ext::markup_escape_text (
1345 port->name().substr(port->name().find("/") + 1));
1351 tooltip << Gtkmm2ext::markup_escape_text(*i);
1354 total_connection_count += port_connection_count;
1355 if (port->type() == dt) {
1356 typed_connection_count += port_connection_count;
1357 each_typed_port_has_one_connection &= (port_connection_count == 1);
1362 if (total_connection_count == 0) {
1363 tooltip << endl << _("Disconnected");
1366 if (typed_connection_count == 0) {
1371 /* Are all main-typed channels connected to the same route ? */
1373 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1374 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1375 route != routes->end();
1377 boost::shared_ptr<IO> dest_io =
1378 for_input ? (*route)->output() : (*route)->input();
1379 if (io->bundle()->connected_to(dest_io->bundle(),
1382 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1389 /* Are all main-typed channels connected to the same (user) bundle ? */
1391 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1392 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1393 bundle != bundles->end();
1395 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1397 if (io->bundle()->connected_to(*bundle, _session->engine(),
1399 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1406 /* Is each main-typed channel only connected to a physical output ? */
1407 if (!have_label && each_typed_port_has_one_connection) {
1408 ostringstream temp_label;
1409 vector<string> phys;
1410 string playorcapture;
1412 _session->engine().get_physical_inputs(dt, phys);
1413 playorcapture = "capture_";
1415 _session->engine().get_physical_outputs(dt, phys);
1416 playorcapture = "playback_";
1418 for (PortSet::iterator port = io->ports().begin(dt);
1419 port != io->ports().end(dt);
1422 for (vector<string>::iterator s = phys.begin();
1425 if (!port->connected_to(*s))
1427 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1429 string::size_type start = (*s).find(playorcapture);
1430 if (start != string::npos) {
1431 pn = (*s).substr(start + playorcapture.size());
1437 temp_label.str(""); /* erase the failed attempt */
1440 if (port != io->ports().begin(dt))
1445 if (!temp_label.str().empty()) {
1446 label << temp_label.str();
1451 /* Is each main-typed channel connected to a single and different port with
1452 * the same client name (e.g. another JACK client) ? */
1453 if (!have_label && each_typed_port_has_one_connection) {
1454 string maybe_client = "";
1455 vector<string> connections;
1456 for (PortSet::iterator port = io->ports().begin(dt);
1457 port != io->ports().end(dt);
1459 port_connections.clear();
1460 port->get_connections(port_connections);
1461 string connection = port_connections.front();
1463 vector<string>::iterator i = connections.begin();
1464 while (i != connections.end() && *i != connection) {
1467 if (i != connections.end())
1468 break; /* duplicate connection */
1469 connections.push_back(connection);
1471 connection = connection.substr(0, connection.find(":"));
1472 if (maybe_client.empty())
1473 maybe_client = connection;
1474 if (maybe_client != connection)
1477 if (connections.size() == io->n_ports().n(dt)) {
1478 label << maybe_client;
1483 /* Odd configuration */
1485 label << "*" << total_connection_count << "*";
1488 if (total_connection_count > typed_connection_count) {
1489 label << "\u2295"; /* circled plus */
1492 /* Actually set the properties of the button */
1493 char * cstr = new char[tooltip.str().size() + 1];
1494 strcpy(cstr, tooltip.str().c_str());
1497 input_button.set_text (label.str());
1498 set_tooltip (&input_button, cstr);
1500 output_button.set_text (label.str());
1501 set_tooltip (&output_button, cstr);
1508 MixerStrip::update_input_display ()
1510 update_io_button (true);
1511 panners.setup_pan ();
1513 if (has_audio_outputs ()) {
1514 panners.show_all ();
1516 panners.hide_all ();
1522 MixerStrip::update_output_display ()
1524 update_io_button (false);
1525 gpm.setup_meters ();
1526 panners.setup_pan ();
1528 if (has_audio_outputs ()) {
1529 panners.show_all ();
1531 panners.hide_all ();
1536 MixerStrip::fast_update ()
1538 gpm.update_meters ();
1542 MixerStrip::diskstream_changed ()
1544 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1548 MixerStrip::io_changed_proxy ()
1550 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1551 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1555 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1557 boost::shared_ptr<Port> a = wa.lock ();
1558 boost::shared_ptr<Port> b = wb.lock ();
1560 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1561 update_input_display ();
1562 set_width_enum (_width, this);
1565 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1566 update_output_display ();
1567 set_width_enum (_width, this);
1572 MixerStrip::setup_comment_button ()
1574 std::string comment = _route->comment();
1576 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1578 if (comment.empty ()) {
1579 _comment_button.set_name ("generic button");
1580 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1584 _comment_button.set_name ("comment button");
1586 string::size_type pos = comment.find_first_of (" \t\n");
1587 if (pos != string::npos) {
1588 comment = comment.substr (0, pos);
1590 if (comment.empty()) {
1591 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1593 _comment_button.set_text (comment);
1598 MixerStrip::select_route_group (GdkEventButton *ev)
1600 using namespace Menu_Helpers;
1602 if (ev->button == 1) {
1604 if (group_menu == 0) {
1606 PropertyList* plist = new PropertyList();
1608 plist->add (Properties::group_gain, true);
1609 plist->add (Properties::group_mute, true);
1610 plist->add (Properties::group_solo, true);
1612 group_menu = new RouteGroupMenu (_session, plist);
1616 r.push_back (route ());
1617 group_menu->build (r);
1619 RouteGroup *rg = _route->route_group();
1621 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1622 rg ? rg->name() : _("No Group"),
1630 MixerStrip::route_group_changed ()
1632 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1634 RouteGroup *rg = _route->route_group();
1637 group_button.set_text (PBD::short_version (rg->name(), 5));
1641 group_button.set_text (_("Grp"));
1644 group_button.set_text (_("~G"));
1651 MixerStrip::route_color_changed ()
1653 using namespace ARDOUR_UI_UTILS;
1654 name_button.modify_bg (STATE_NORMAL, color());
1655 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1656 reset_strip_style ();
1660 MixerStrip::show_passthru_color ()
1662 reset_strip_style ();
1667 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1669 boost::shared_ptr<Processor> processor (p.lock ());
1670 if (!processor || !processor->display_to_user()) {
1673 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1675 if (pi && pi->is_channelstrip ()) {
1680 ++_plugin_insert_cnt;
1684 MixerStrip::build_route_ops_menu ()
1686 using namespace Menu_Helpers;
1687 route_ops_menu = new Menu;
1688 route_ops_menu->set_name ("ArdourContextMenu");
1690 MenuList& items = route_ops_menu->items();
1692 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1694 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1696 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1698 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1700 if (!Profile->get_mixbus()) {
1701 items.push_back (SeparatorElem());
1704 if (!_route->is_master()
1706 && !_route->mixbus()
1709 if (Profile->get_mixbus()) {
1710 items.push_back (SeparatorElem());
1712 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1715 if (!Profile->get_mixbus()) {
1716 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1717 /* do not allow rename if the track is record-enabled */
1718 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1721 items.push_back (SeparatorElem());
1722 items.push_back (CheckMenuElem (_("Active")));
1723 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1724 i->set_active (_route->active());
1725 i->set_sensitive(! _session->transport_rolling());
1726 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1728 if (!Profile->get_mixbus ()) {
1729 items.push_back (SeparatorElem());
1730 items.push_back (CheckMenuElem (_("Strict I/O")));
1731 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1732 i->set_active (_route->strict_io());
1733 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1737 items.push_back (SeparatorElem());
1739 Gtk::Menu* dio_menu = new Menu;
1740 MenuList& dio_items = dio_menu->items();
1741 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1742 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1743 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1745 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1748 _plugin_insert_cnt = 0;
1749 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1750 if (_plugin_insert_cnt > 0) {
1751 items.push_back (SeparatorElem());
1752 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1755 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1756 items.push_back (MenuElem (_("Patch Selector..."),
1757 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1760 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1761 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1762 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1763 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1766 items.push_back (SeparatorElem());
1767 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1768 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1769 denormal_menu_item->set_active (_route->denormal_protection());
1772 /* note that this relies on selection being shared across editor and
1773 mixer (or global to the backend, in the future), which is the only
1774 sane thing for users anyway.
1777 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1779 Selection& selection (PublicEditor::instance().get_selection());
1780 if (!selection.selected (stav)) {
1781 selection.set (stav);
1784 if (!_route->is_master()) {
1785 items.push_back (SeparatorElem());
1786 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1789 items.push_back (SeparatorElem());
1790 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1796 MixerStrip::name_button_button_press (GdkEventButton* ev)
1798 if (ev->button == 1 || ev->button == 3) {
1799 list_route_operations ();
1801 if (ev->button == 1) {
1802 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1805 route_ops_menu->popup (3, ev->time);
1815 MixerStrip::number_button_button_press (GdkEventButton* ev)
1817 if ( ev->button == 3 ) {
1818 list_route_operations ();
1820 route_ops_menu->popup (1, ev->time);
1829 MixerStrip::list_route_operations ()
1831 delete route_ops_menu;
1832 build_route_ops_menu ();
1836 MixerStrip::set_selected (bool yn)
1838 AxisView::set_selected (yn);
1841 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1842 global_frame.set_name ("MixerStripSelectedFrame");
1844 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1845 global_frame.set_name ("MixerStripFrame");
1848 global_frame.queue_draw ();
1851 // processor_box.deselect_all_processors();
1855 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1857 if (what_changed.contains (ARDOUR::Properties::name)) {
1863 MixerStrip::name_changed ()
1867 name_button.set_text (_route->name());
1870 name_button.set_text (PBD::short_version (_route->name(), 5));
1874 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1876 if (_session->config.get_track_name_number()) {
1877 const int64_t track_number = _route->track_number ();
1878 if (track_number == 0) {
1879 number_label.set_text ("-");
1881 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1884 number_label.set_text ("");
1889 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1891 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1895 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1897 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1901 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1903 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1907 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1909 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1913 MixerStrip::width_button_pressed (GdkEventButton* ev)
1915 if (ev->button != 1) {
1919 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1922 _mixer.set_strip_width (Narrow, true);
1926 _mixer.set_strip_width (Wide, true);
1932 set_width_enum (Narrow, this);
1935 set_width_enum (Wide, this);
1944 MixerStrip::hide_clicked ()
1946 // LAME fix to reset the button status for when it is redisplayed (part 1)
1947 hide_button.set_sensitive(false);
1950 Hiding(); /* EMIT_SIGNAL */
1952 _mixer.hide_strip (this);
1956 hide_button.set_sensitive(true);
1960 MixerStrip::set_embedded (bool yn)
1966 MixerStrip::map_frozen ()
1968 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1970 boost::shared_ptr<AudioTrack> at = audio_track();
1973 switch (at->freeze_state()) {
1974 case AudioTrack::Frozen:
1975 processor_box.set_sensitive (false);
1976 hide_redirect_editors ();
1979 processor_box.set_sensitive (true);
1980 // XXX need some way, maybe, to retoggle redirect editors
1984 processor_box.set_sensitive (true);
1986 RouteUI::map_frozen ();
1990 MixerStrip::hide_redirect_editors ()
1992 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1996 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1998 boost::shared_ptr<Processor> processor (p.lock ());
2003 Gtk::Window* w = processor_box.get_processor_ui (processor);
2011 MixerStrip::reset_strip_style ()
2013 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2015 gpm.set_fader_name ("SendStripBase");
2019 if (is_midi_track()) {
2020 if (_route->active()) {
2021 set_name ("MidiTrackStripBase");
2023 set_name ("MidiTrackStripBaseInactive");
2025 gpm.set_fader_name ("MidiTrackFader");
2026 } else if (is_audio_track()) {
2027 if (_route->active()) {
2028 set_name ("AudioTrackStripBase");
2030 set_name ("AudioTrackStripBaseInactive");
2032 gpm.set_fader_name ("AudioTrackFader");
2034 if (_route->active()) {
2035 set_name ("AudioBusStripBase");
2037 set_name ("AudioBusStripBaseInactive");
2039 gpm.set_fader_name ("AudioBusFader");
2041 /* (no MIDI busses yet) */
2048 MixerStrip::meter_point_string (MeterPoint mp)
2061 case MeterPostFader:
2078 return S_("Meter|In");
2082 return S_("Meter|Pr");
2085 case MeterPostFader:
2086 return S_("Meter|Po");
2090 return S_("Meter|O");
2095 return S_("Meter|C");
2104 /** Called when the monitor-section state */
2106 MixerStrip::monitor_changed ()
2108 assert (monitor_section_button);
2109 if (_session->monitor_active()) {
2110 monitor_section_button->set_name ("master monitor section button active");
2112 monitor_section_button->set_name ("master monitor section button normal");
2117 MixerStrip::monitor_section_added_or_removed ()
2119 assert (monitor_section_button);
2120 if (mute_button->get_parent()) {
2121 mute_button->get_parent()->remove(*mute_button);
2123 if (monitor_section_button->get_parent()) {
2124 monitor_section_button->get_parent()->remove(*monitor_section_button);
2126 if (_session && _session->monitor_out ()) {
2127 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2128 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2129 mute_button->show();
2130 monitor_section_button->show();
2132 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2133 mute_button->show();
2137 /** Called when the metering point has changed */
2139 MixerStrip::meter_changed ()
2141 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2142 gpm.setup_meters ();
2143 // reset peak when meter point changes
2144 gpm.reset_peak_display();
2147 /** The bus that we are displaying sends to has changed, or been turned off.
2148 * @param send_to New bus that we are displaying sends to, or 0.
2151 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2153 RouteUI::bus_send_display_changed (send_to);
2156 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2161 revert_to_default_display ();
2164 revert_to_default_display ();
2169 MixerStrip::drop_send ()
2171 boost::shared_ptr<Send> current_send;
2173 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2174 current_send->set_metering (false);
2177 send_gone_connection.disconnect ();
2178 input_button.set_sensitive (true);
2179 output_button.set_sensitive (true);
2180 group_button.set_sensitive (true);
2181 set_invert_sensitive (true);
2182 gpm.meter_point_button.set_sensitive (true);
2183 mute_button->set_sensitive (true);
2184 solo_button->set_sensitive (true);
2185 solo_isolated_led->set_sensitive (true);
2186 solo_safe_led->set_sensitive (true);
2187 monitor_input_button->set_sensitive (true);
2188 monitor_disk_button->set_sensitive (true);
2189 _comment_button.set_sensitive (true);
2190 trim_control.set_sensitive (true);
2191 if (midi_input_enable_button) {
2192 midi_input_enable_button->set_sensitive (true);
2194 control_slave_ui.set_sensitive (true);
2195 RouteUI::check_rec_enable_sensitivity ();
2196 set_button_names (); // update solo button visual state
2200 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2202 _current_delivery = d;
2203 DeliveryChanged (_current_delivery);
2207 MixerStrip::show_send (boost::shared_ptr<Send> send)
2213 set_current_delivery (send);
2215 send->meter()->set_meter_type (_route->meter_type ());
2216 send->set_metering (true);
2217 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2219 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2220 gain_meter().setup_meters ();
2222 uint32_t const in = _current_delivery->pans_required();
2223 uint32_t const out = _current_delivery->pan_outs();
2225 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2226 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2227 panner_ui().setup_pan ();
2228 panner_ui().set_send_drawing_mode (true);
2229 panner_ui().show_all ();
2231 input_button.set_sensitive (false);
2232 group_button.set_sensitive (false);
2233 set_invert_sensitive (false);
2234 gpm.meter_point_button.set_sensitive (false);
2235 mute_button->set_sensitive (false);
2236 solo_button->set_sensitive (false);
2237 rec_enable_button->set_sensitive (false);
2238 solo_isolated_led->set_sensitive (false);
2239 solo_safe_led->set_sensitive (false);
2240 monitor_input_button->set_sensitive (false);
2241 monitor_disk_button->set_sensitive (false);
2242 _comment_button.set_sensitive (false);
2243 trim_control.set_sensitive (false);
2244 if (midi_input_enable_button) {
2245 midi_input_enable_button->set_sensitive (false);
2247 control_slave_ui.set_sensitive (false);
2249 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2250 output_button.set_sensitive (false);
2253 reset_strip_style ();
2257 MixerStrip::revert_to_default_display ()
2261 set_current_delivery (_route->main_outs ());
2263 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2264 gain_meter().setup_meters ();
2266 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2267 update_panner_choices();
2268 panner_ui().setup_pan ();
2269 panner_ui().set_send_drawing_mode (false);
2271 if (has_audio_outputs ()) {
2272 panners.show_all ();
2274 panners.hide_all ();
2277 reset_strip_style ();
2281 MixerStrip::set_button_names ()
2285 mute_button->set_text (_("Mute"));
2286 monitor_input_button->set_text (_("In"));
2287 monitor_disk_button->set_text (_("Disk"));
2288 if (monitor_section_button) {
2289 monitor_section_button->set_text (_("Mon"));
2292 if (_route && _route->solo_safe_control()->solo_safe()) {
2293 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2295 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2297 if (!Config->get_solo_control_is_listen_control()) {
2298 solo_button->set_text (_("Solo"));
2300 switch (Config->get_listen_position()) {
2301 case AfterFaderListen:
2302 solo_button->set_text (_("AFL"));
2304 case PreFaderListen:
2305 solo_button->set_text (_("PFL"));
2309 solo_isolated_led->set_text (_("Iso"));
2310 solo_safe_led->set_text (S_("SoloLock|Lock"));
2314 mute_button->set_text (S_("Mute|M"));
2315 monitor_input_button->set_text (S_("MonitorInput|I"));
2316 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2317 if (monitor_section_button) {
2318 monitor_section_button->set_text (S_("Mon|O"));
2321 if (_route && _route->solo_safe_control()->solo_safe()) {
2322 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2324 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2326 if (!Config->get_solo_control_is_listen_control()) {
2327 solo_button->set_text (S_("Solo|S"));
2329 switch (Config->get_listen_position()) {
2330 case AfterFaderListen:
2331 solo_button->set_text (S_("AfterFader|A"));
2333 case PreFaderListen:
2334 solo_button->set_text (S_("Prefader|P"));
2339 solo_isolated_led->set_text (S_("SoloIso|I"));
2340 solo_safe_led->set_text (S_("SoloLock|L"));
2345 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2347 gpm.meter_point_button.set_text ("");
2352 MixerStrip::plugin_selector()
2354 return _mixer.plugin_selector();
2358 MixerStrip::hide_things ()
2360 processor_box.hide_things ();
2364 MixerStrip::input_active_button_press (GdkEventButton*)
2366 /* nothing happens on press */
2371 MixerStrip::input_active_button_release (GdkEventButton* ev)
2373 boost::shared_ptr<MidiTrack> mt = midi_track ();
2379 boost::shared_ptr<RouteList> rl (new RouteList);
2381 rl->push_back (route());
2383 _session->set_exclusive_input_active (rl, !mt->input_active(),
2384 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2390 MixerStrip::midi_input_status_changed ()
2392 if (midi_input_enable_button) {
2393 boost::shared_ptr<MidiTrack> mt = midi_track ();
2395 midi_input_enable_button->set_active (mt->input_active ());
2400 MixerStrip::state_id () const
2402 return string_compose ("strip %1", _route->id().to_s());
2406 MixerStrip::parameter_changed (string p)
2408 if (p == _visibility.get_state_name()) {
2409 /* The user has made changes to the mixer strip visibility, so get
2410 our VisibilityGroup to reflect these changes in our widgets.
2412 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2413 } else if (p == "track-name-number") {
2415 update_track_number_visibility();
2419 /** Called to decide whether the solo isolate / solo lock button visibility should
2420 * be overridden from that configured by the user. We do this for the master bus.
2422 * @return optional value that is present if visibility state should be overridden.
2424 boost::optional<bool>
2425 MixerStrip::override_solo_visibility () const
2427 if (_route && _route->is_master ()) {
2428 return boost::optional<bool> (false);
2431 return boost::optional<bool> ();
2435 MixerStrip::add_input_port (DataType t)
2437 _route->input()->add_port ("", this, t);
2441 MixerStrip::add_output_port (DataType t)
2443 _route->output()->add_port ("", this, t);
2447 MixerStrip::route_active_changed ()
2449 reset_strip_style ();
2453 MixerStrip::copy_processors ()
2455 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2459 MixerStrip::cut_processors ()
2461 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2465 MixerStrip::paste_processors ()
2467 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2471 MixerStrip::select_all_processors ()
2473 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2477 MixerStrip::deselect_all_processors ()
2479 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2483 MixerStrip::delete_processors ()
2485 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2489 MixerStrip::toggle_processors ()
2491 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2495 MixerStrip::ab_plugins ()
2497 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2501 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2503 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2506 if (ev->button == 3) {
2507 popup_level_meter_menu (ev);
2515 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2517 using namespace Gtk::Menu_Helpers;
2519 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2520 MenuList& items = m->items ();
2522 RadioMenuItem::Group group;
2524 PBD::Unwinder<bool> uw (_suspend_menu_callbacks, true);
2525 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2526 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2527 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2528 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2529 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2531 if (gpm.meter_channels().n_audio() == 0) {
2532 m->popup (ev->button, ev->time);
2536 RadioMenuItem::Group tgroup;
2537 items.push_back (SeparatorElem());
2539 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2540 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2541 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2542 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2543 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2545 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2546 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2547 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2548 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2549 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2552 if (_route->is_master()) {
2555 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2556 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2557 /* non-master bus */
2560 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2567 MeterType cmt = _route->meter_type();
2568 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2570 items.push_back (SeparatorElem());
2571 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2572 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2573 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2574 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2575 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2576 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2578 m->popup (ev->button, ev->time);
2582 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2583 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2585 using namespace Menu_Helpers;
2587 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2588 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2589 i->set_active (_route->meter_point() == point);
2593 MixerStrip::set_meter_point (MeterPoint p)
2595 if (_suspend_menu_callbacks) return;
2596 _route->set_meter_point (p);
2600 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2601 RadioMenuItem::Group& group, string const & name, MeterType type)
2603 using namespace Menu_Helpers;
2605 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2606 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2607 i->set_active (_route->meter_type() == type);
2611 MixerStrip::set_meter_type (MeterType t)
2613 if (_suspend_menu_callbacks) return;
2614 _route->set_meter_type (t);
2618 MixerStrip::update_track_number_visibility ()
2620 DisplaySuspender ds;
2621 bool show_label = _session->config.get_track_name_number();
2623 if (_route && _route->is_master()) {
2628 number_label.show ();
2629 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2630 // except the width of the number label is subtracted from the name-hbox, so we
2631 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2632 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2634 number_label.set_size_request(tnw, -1);
2635 number_label.show ();
2637 number_label.hide ();
2642 MixerStrip::color () const
2644 return route_color ();
2648 MixerStrip::marked_for_display () const
2650 return !_route->presentation_info().hidden();
2654 MixerStrip::set_marked_for_display (bool yn)
2656 return RouteUI::mark_hidden (!yn);
2660 MixerStrip::hide_master_spacer (bool yn)
2662 if (_mixer_owned && route()->is_master() && !yn) {