2 Copyright (C) 2000-2006 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sigc++/bind.h>
25 #include <gtkmm/messagedialog.h>
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29 #include "pbd/replace_all.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/unwind.h"
33 #include "ardour/amp.h"
34 #include "ardour/audio_track.h"
35 #include "ardour/audioengine.h"
36 #include "ardour/internal_send.h"
37 #include "ardour/io.h"
38 #include "ardour/meter.h"
39 #include "ardour/midi_track.h"
40 #include "ardour/pannable.h"
41 #include "ardour/panner.h"
42 #include "ardour/panner_shell.h"
43 #include "ardour/panner_manager.h"
44 #include "ardour/port.h"
45 #include "ardour/profile.h"
46 #include "ardour/route.h"
47 #include "ardour/route_group.h"
48 #include "ardour/send.h"
49 #include "ardour/session.h"
50 #include "ardour/types.h"
51 #include "ardour/user_bundle.h"
52 #include "ardour/vca.h"
53 #include "ardour/vca_manager.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/menu_elems.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/doi.h"
60 #include "widgets/tooltips.h"
62 #include "ardour_window.h"
63 #include "context_menu_helper.h"
64 #include "enums_convert.h"
65 #include "mixer_strip.h"
68 #include "public_editor.h"
70 #include "io_selector.h"
72 #include "gui_thread.h"
73 #include "route_group_menu.h"
74 #include "meter_patterns.h"
75 #include "ui_config.h"
79 using namespace ARDOUR;
80 using namespace ArdourWidgets;
83 using namespace Gtkmm2ext;
85 using namespace ArdourMeter;
87 MixerStrip* MixerStrip::_entered_mixer_strip;
88 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
90 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
91 : SessionHandlePtr (sess)
94 , _mixer_owned (in_mixer)
95 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
98 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
99 , rec_mon_table (2, 2)
100 , solo_iso_table (1, 2)
101 , mute_solo_table (1, 2)
102 , bottom_button_table (1, 3)
103 , monitor_section_button (0)
104 , midi_input_enable_button (0)
105 , _plugin_insert_cnt (0)
106 , _comment_button (_("Comments"))
107 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
108 , _visibility (X_("mixer-element-visibility"))
109 , _suspend_menu_callbacks (false)
110 , control_slave_ui (sess)
115 /* the editor mixer strip: don't destroy it every time
116 the underlying route goes away.
119 self_destruct = false;
123 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
124 : SessionHandlePtr (sess)
127 , _mixer_owned (in_mixer)
128 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
131 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
132 , rec_mon_table (2, 2)
133 , solo_iso_table (1, 2)
134 , mute_solo_table (1, 2)
135 , bottom_button_table (1, 3)
136 , monitor_section_button (0)
137 , midi_input_enable_button (0)
138 , _plugin_insert_cnt (0)
139 , _comment_button (_("Comments"))
140 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
141 , _visibility (X_("mixer-element-visibility"))
142 , _suspend_menu_callbacks (false)
143 , control_slave_ui (sess)
152 _entered_mixer_strip= 0;
155 ignore_comment_edit = false;
156 ignore_toggle = false;
160 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
161 longest_label = "longest label";
163 string t = _("Click to toggle the width of this mixer strip.");
165 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
168 width_button.set_icon (ArdourIcon::StripWidth);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (width_button, t);
172 hide_button.set_icon (ArdourIcon::CloseCross);
173 hide_button.set_tweaks (ArdourButton::Square);
174 set_tooltip (&hide_button, _("Hide this mixer strip"));
176 input_button_box.set_spacing(2);
178 input_button.set_text (_("Input"));
179 input_button.set_name ("mixer strip button");
180 input_button_box.pack_start (input_button, true, true);
182 output_button.set_text (_("Output"));
183 output_button.set_name ("mixer strip button");
185 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
187 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
189 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
190 solo_isolated_led->show ();
191 solo_isolated_led->set_no_show_all (true);
192 solo_isolated_led->set_name (X_("solo isolate"));
193 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
194 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
195 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
197 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
198 solo_safe_led->show ();
199 solo_safe_led->set_no_show_all (true);
200 solo_safe_led->set_name (X_("solo safe"));
201 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
202 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
203 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
205 solo_safe_led->set_text (S_("SoloLock|Lock"));
206 solo_isolated_led->set_text (_("Iso"));
208 solo_iso_table.set_homogeneous (true);
209 solo_iso_table.set_spacings (2);
210 if (!ARDOUR::Profile->get_trx()) {
211 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
212 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
214 solo_iso_table.show ();
216 rec_mon_table.set_homogeneous (true);
217 rec_mon_table.set_row_spacings (2);
218 rec_mon_table.set_col_spacings (2);
219 if (ARDOUR::Profile->get_mixbus()) {
220 rec_mon_table.resize (1, 3);
221 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
222 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
223 } else if (!ARDOUR::Profile->get_trx()) {
224 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
225 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
227 rec_mon_table.show ();
229 if (solo_isolated_led) {
230 button_size_group->add_widget (*solo_isolated_led);
233 button_size_group->add_widget (*solo_safe_led);
236 if (!ARDOUR::Profile->get_mixbus()) {
237 if (rec_enable_button) {
238 button_size_group->add_widget (*rec_enable_button);
240 if (monitor_disk_button) {
241 button_size_group->add_widget (*monitor_disk_button);
243 if (monitor_input_button) {
244 button_size_group->add_widget (*monitor_input_button);
248 mute_solo_table.set_homogeneous (true);
249 mute_solo_table.set_spacings (2);
251 bottom_button_table.set_spacings (2);
252 bottom_button_table.set_homogeneous (true);
253 bottom_button_table.attach (group_button, 1, 2, 0, 1);
254 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
256 name_button.set_name ("mixer strip button");
257 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
258 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
260 set_tooltip (&group_button, _("Mix group"));
261 group_button.set_name ("mixer strip button");
263 _comment_button.set_name (X_("mixer strip button"));
264 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
265 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
266 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
268 // TODO implement ArdourKnob::on_size_request properly
269 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
270 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
272 trim_control.set_tooltip_prefix (_("Trim: "));
273 trim_control.set_name ("trim knob");
274 trim_control.set_no_show_all (true);
275 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
276 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
277 input_button_box.pack_start (trim_control, false, false);
279 global_vpacker.set_border_width (1);
280 global_vpacker.set_spacing (0);
282 width_button.set_name ("mixer strip button");
283 hide_button.set_name ("mixer strip button");
285 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
286 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
288 width_hide_box.set_spacing (2);
289 width_hide_box.pack_start (width_button, false, true);
290 width_hide_box.pack_start (number_label, true, true);
291 width_hide_box.pack_end (hide_button, false, true);
293 number_label.set_text ("-");
294 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
295 number_label.set_no_show_all ();
296 number_label.set_name ("tracknumber label");
297 number_label.set_fixed_colors (0x80808080, 0x80808080);
298 number_label.set_alignment (.5, .5);
299 number_label.set_fallthrough_to_parent (true);
300 number_label.set_tweaks (ArdourButton::OccasionalText);
302 global_vpacker.set_spacing (2);
303 if (!ARDOUR::Profile->get_trx()) {
304 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
305 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
306 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (processor_box, true, true);
310 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
313 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
314 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
316 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
317 if (!ARDOUR::Profile->get_trx()) {
318 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
319 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
321 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
325 //add a spacer underneath the master bus;
326 //this fills the area that is taken up by the scrollbar on the tracks;
327 //and therefore keeps the faders "even" across the bottom
328 int scrollbar_height = 0;
330 Gtk::Window window (WINDOW_TOPLEVEL);
331 HScrollbar scrollbar;
332 window.add (scrollbar);
333 scrollbar.set_name ("MixerWindow");
334 scrollbar.ensure_style();
335 Gtk::Requisition requisition(scrollbar.size_request ());
336 scrollbar_height = requisition.height;
338 spacer.set_size_request (-1, scrollbar_height);
339 global_vpacker.pack_end (spacer, false, false);
342 global_frame.add (global_vpacker);
343 global_frame.set_shadow_type (Gtk::SHADOW_IN);
344 global_frame.set_name ("BaseFrame");
348 /* force setting of visible selected status */
351 set_selected (false);
356 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
357 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
359 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
360 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
361 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
363 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
364 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
366 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
367 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
368 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
370 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
372 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
374 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
378 /* start off as a passthru strip. we'll correct this, if necessary,
379 in update_diskstream_display().
382 /* start off as a passthru strip. we'll correct this, if necessary,
383 in update_diskstream_display().
386 if (is_midi_track()) {
387 set_name ("MidiTrackStripBase");
389 set_name ("AudioTrackStripBase");
392 add_events (Gdk::BUTTON_RELEASE_MASK|
393 Gdk::ENTER_NOTIFY_MASK|
394 Gdk::LEAVE_NOTIFY_MASK|
396 Gdk::KEY_RELEASE_MASK);
398 set_flags (get_flags() | Gtk::CAN_FOCUS);
400 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
401 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
404 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
405 must be the same as those used in RCOptionEditor so that the configuration changes
406 are recognised when they occur.
408 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
409 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
410 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
411 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
412 _visibility.add (&output_button, X_("Output"), _("Output"), false);
413 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
414 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
416 parameter_changed (X_("mixer-element-visibility"));
417 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
418 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
419 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
421 //watch for mouse enter/exit so we can do some stuff
422 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
423 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
425 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
428 MixerStrip::~MixerStrip ()
430 CatchDeletion (this);
432 if (this ==_entered_mixer_strip)
433 _entered_mixer_strip = NULL;
437 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
439 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
445 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
447 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
453 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
455 _entered_mixer_strip = this;
457 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
458 //because the mixerstrip control is a parent that encompasses the strip
459 deselect_all_processors();
465 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
467 //if we have moved outside our strip, but not into a child view, then deselect ourselves
468 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
469 _entered_mixer_strip= 0;
471 //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
472 gpm.gain_display.set_sensitive(false);
474 gpm.gain_display.set_sensitive(true);
476 //if we leave this mixer strip we need to clear out any selections
477 //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
484 MixerStrip::name() const
487 return _route->name();
493 MixerStrip::update_trim_control ()
495 if (route()->trim() && route()->trim()->active() &&
496 route()->n_inputs().n_audio() > 0) {
497 trim_control.show ();
498 trim_control.set_controllable (route()->trim()->gain_control());
500 trim_control.hide ();
501 boost::shared_ptr<Controllable> none;
502 trim_control.set_controllable (none);
507 MixerStrip::trim_start_touch ()
509 assert (_route && _session);
510 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
511 route()->trim()->gain_control ()->start_touch (_session->transport_sample());
516 MixerStrip::trim_end_touch ()
518 assert (_route && _session);
519 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
520 route()->trim()->gain_control ()->stop_touch (_session->transport_sample());
525 MixerStrip::set_route (boost::shared_ptr<Route> rt)
527 //the rec/monitor stuff only shows up for tracks.
528 //the show_sends only shows up for buses.
529 //remove them all here, and we may add them back later
530 if (show_sends_button->get_parent()) {
531 rec_mon_table.remove (*show_sends_button);
533 if (rec_enable_button->get_parent()) {
534 rec_mon_table.remove (*rec_enable_button);
536 if (monitor_input_button->get_parent()) {
537 rec_mon_table.remove (*monitor_input_button);
539 if (monitor_disk_button->get_parent()) {
540 rec_mon_table.remove (*monitor_disk_button);
542 if (group_button.get_parent()) {
543 bottom_button_table.remove (group_button);
546 RouteUI::set_route (rt);
548 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
550 /* ProcessorBox needs access to _route so that it can read
553 processor_box.set_route (rt);
555 revert_to_default_display ();
557 /* unpack these from the parent and stuff them into our own
561 if (gpm.peak_display.get_parent()) {
562 gpm.peak_display.get_parent()->remove (gpm.peak_display);
564 if (gpm.gain_display.get_parent()) {
565 gpm.gain_display.get_parent()->remove (gpm.gain_display);
568 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
569 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
571 if (solo_button->get_parent()) {
572 mute_solo_table.remove (*solo_button);
575 if (mute_button->get_parent()) {
576 mute_solo_table.remove (*mute_button);
579 if (route()->is_master()) {
580 solo_button->hide ();
581 mute_button->show ();
582 rec_mon_table.hide ();
583 solo_iso_table.set_sensitive(false);
584 control_slave_ui.set_sensitive(false);
585 if (monitor_section_button == 0) {
586 Glib::RefPtr<Action> act = ActionManager::get_action ("Mixer", "ToggleMonitorSection");
587 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
588 _session->MonitorBusAddedOrRemoved.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_section_added_or_removed, this), gui_context());
590 monitor_section_button = manage (new ArdourButton);
592 monitor_section_button->set_related_action (act);
593 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
594 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
595 monitor_section_button->show();
596 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
597 monitor_section_added_or_removed ();
600 bottom_button_table.attach (group_button, 1, 2, 0, 1);
601 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
602 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
603 mute_button->show ();
604 solo_button->show ();
605 rec_mon_table.show ();
606 solo_iso_table.set_sensitive(true);
607 control_slave_ui.set_sensitive(true);
610 hide_master_spacer (false);
613 monitor_input_button->show ();
614 monitor_disk_button->show ();
616 monitor_input_button->hide();
617 monitor_disk_button->hide ();
620 update_trim_control();
622 if (is_midi_track()) {
623 if (midi_input_enable_button == 0) {
624 midi_input_enable_button = manage (new ArdourButton);
625 midi_input_enable_button->set_name ("midi input button");
626 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
627 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
628 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
629 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
630 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
632 input_button_box.remove (*midi_input_enable_button);
634 /* get current state */
635 midi_input_status_changed ();
636 input_button_box.pack_start (*midi_input_enable_button, false, false);
638 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
640 if (midi_input_enable_button) {
641 /* removal from the container will delete it */
642 input_button_box.remove (*midi_input_enable_button);
643 midi_input_enable_button = 0;
647 if (is_audio_track()) {
648 boost::shared_ptr<AudioTrack> at = audio_track();
649 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
654 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
655 rec_enable_button->show();
657 if (ARDOUR::Profile->get_mixbus()) {
658 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
659 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
660 } else if (ARDOUR::Profile->get_trx()) {
661 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
663 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
664 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
671 if (!_route->is_master()) {
672 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
673 show_sends_button->show();
677 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
679 delete route_ops_menu;
682 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
683 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
684 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
685 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
687 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
689 if (_route->panner_shell()) {
690 update_panner_choices();
691 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
694 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
696 set_stuff_from_route ();
698 /* now force an update of all the various elements */
700 update_mute_display ();
701 update_solo_display ();
704 route_group_changed ();
705 update_track_number_visibility ();
708 panners.setup_pan ();
710 if (has_audio_outputs ()) {
716 update_diskstream_display ();
717 update_input_display ();
718 update_output_display ();
720 add_events (Gdk::BUTTON_RELEASE_MASK);
722 processor_box.show ();
724 if (!route()->is_master() && !route()->is_monitor()) {
725 /* we don't allow master or control routes to be hidden */
730 gpm.reset_peak_display ();
731 gpm.gain_display.show ();
732 gpm.peak_display.show ();
735 width_hide_box.show();
737 global_vpacker.show();
738 mute_solo_table.show();
739 bottom_button_table.show();
741 gpm.meter_point_button.show();
742 input_button_box.show_all();
743 output_button.show();
745 _comment_button.show();
747 gpm.gain_automation_state_button.show();
749 parameter_changed ("mixer-element-visibility");
756 MixerStrip::set_stuff_from_route ()
758 /* if width is not set, it will be set by the MixerUI or editor */
761 if (get_gui_property ("strip-width", width)) {
762 set_width_enum (width, this);
767 MixerStrip::set_width_enum (Width w, void* owner)
769 /* always set the gpm width again, things may be hidden */
772 panners.set_width (w);
774 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
776 _width_owner = owner;
780 if (_width_owner == this) {
781 set_gui_property ("strip-width", _width);
786 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
791 if (show_sends_button) {
792 show_sends_button->set_text (_("Aux"));
795 gpm.gain_automation_state_button.set_text (
796 gpm.astate_string(gain_automation->automation_state()));
798 if (_route->panner()) {
799 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
800 panners.astate_string(_route->panner()->automation_state()));
804 // panners expect an even number of horiz. pixels
805 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
807 set_size_request (width, -1);
813 if (show_sends_button) {
814 show_sends_button->set_text (_("Snd"));
817 gpm.gain_automation_state_button.set_text (
818 gpm.short_astate_string(gain_automation->automation_state()));
819 gain_meter().setup_meters (); // recalc meter width
821 if (_route->panner()) {
822 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
823 panners.short_astate_string(_route->panner()->automation_state()));
827 // panners expect an even number of horiz. pixels
828 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
830 set_size_request (width, -1);
835 processor_box.set_width (w);
837 update_input_display ();
838 update_output_display ();
839 setup_comment_button ();
840 route_group_changed ();
846 MixerStrip::set_packed (bool yn)
849 set_gui_property ("visible", _packed);
853 struct RouteCompareByName {
854 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
855 return a->name().compare (b->name()) < 0;
860 MixerStrip::output_release (GdkEventButton *ev)
862 switch (ev->button) {
864 edit_output_configuration ();
872 MixerStrip::output_press (GdkEventButton *ev)
874 using namespace Menu_Helpers;
875 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
879 MenuList& citems = output_menu.items();
880 switch (ev->button) {
883 return false; //wait for the mouse-up to pop the dialog
887 output_menu.set_name ("ArdourContextMenu");
889 output_menu_bundles.clear ();
891 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
893 citems.push_back (SeparatorElem());
894 uint32_t const n_with_separator = citems.size ();
896 ARDOUR::BundleList current = _route->output()->bundles_connected ();
898 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
900 /* guess the user-intended main type of the route output */
901 DataType intended_type = guess_main_type(false);
903 /* try adding the master bus first */
904 boost::shared_ptr<Route> master = _session->master_out();
906 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
909 /* then other routes inputs */
910 RouteList copy = _session->get_routelist ();
911 copy.sort (RouteCompareByName ());
912 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
913 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
916 /* then try adding user bundles, often labeled/grouped physical inputs */
917 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
918 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
919 maybe_add_bundle_to_output_menu (*i, current, intended_type);
923 /* then all other bundles, including physical outs or other sofware */
924 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
925 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
926 maybe_add_bundle_to_output_menu (*i, current, intended_type);
930 if (citems.size() == n_with_separator) {
931 /* no routes added; remove the separator */
935 citems.push_back (SeparatorElem());
937 if (!ARDOUR::Profile->get_mixbus()) {
938 bool need_separator = false;
939 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
940 if (!_route->output()->can_add_port (*i)) {
943 need_separator = true;
946 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
947 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
951 if (need_separator) {
952 citems.push_back (SeparatorElem());
956 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
958 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
971 MixerStrip::input_release (GdkEventButton *ev)
973 switch (ev->button) {
976 edit_input_configuration ();
988 MixerStrip::input_press (GdkEventButton *ev)
990 using namespace Menu_Helpers;
992 MenuList& citems = input_menu.items();
993 input_menu.set_name ("ArdourContextMenu");
996 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
1000 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1003 switch (ev->button) {
1006 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1010 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1012 citems.push_back (SeparatorElem());
1013 uint32_t const n_with_separator = citems.size ();
1015 input_menu_bundles.clear ();
1017 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1019 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1021 /* give user bundles first chance at being in the menu */
1023 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1024 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1025 maybe_add_bundle_to_input_menu (*i, current);
1029 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1030 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1031 maybe_add_bundle_to_input_menu (*i, current);
1035 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1036 RouteList copy = *routes;
1037 copy.sort (RouteCompareByName ());
1038 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1039 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1042 if (citems.size() == n_with_separator) {
1043 /* no routes added; remove the separator */
1047 citems.push_back (SeparatorElem());
1049 bool need_separator = false;
1050 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1051 if (!_route->input()->can_add_port (*i)) {
1054 need_separator = true;
1057 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1058 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1062 if (need_separator) {
1063 citems.push_back (SeparatorElem());
1066 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1068 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1080 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1082 if (ignore_toggle) {
1086 _route->input()->connect_ports_to_bundle (c, true, this);
1090 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1092 if (ignore_toggle) {
1096 _route->output()->connect_ports_to_bundle (c, true, true, this);
1100 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1102 using namespace Menu_Helpers;
1104 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1108 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1109 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1113 if (i != input_menu_bundles.end()) {
1117 input_menu_bundles.push_back (b);
1119 MenuList& citems = input_menu.items();
1120 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1124 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1127 using namespace Menu_Helpers;
1129 /* The bundle should be an input one, but not ours */
1130 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1134 /* Don't add the monitor input unless we are Master */
1135 boost::shared_ptr<Route> monitor = _session->monitor_out();
1136 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1139 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1140 * or have the same number of |type| channels than our outputs. */
1141 if (type == DataType::NIL) {
1142 if(b->nchannels() != _route->n_outputs())
1145 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1149 /* Avoid adding duplicates */
1150 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1151 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1154 if (i != output_menu_bundles.end()) {
1158 /* Now add the bundle to the menu */
1159 output_menu_bundles.push_back (b);
1161 MenuList& citems = output_menu.items();
1162 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1166 MixerStrip::update_diskstream_display ()
1168 if (is_track() && input_selector) {
1169 input_selector->hide_all ();
1172 route_color_changed ();
1176 MixerStrip::connect_to_pan ()
1178 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1180 panstate_connection.disconnect ();
1181 panstyle_connection.disconnect ();
1183 if (!_route->panner()) {
1187 boost::shared_ptr<Pannable> p = _route->pannable ();
1189 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1191 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1192 * However, that only works a panner was previously set.
1194 * PannerUI must remain subscribed to _panshell->Changed() in case
1195 * we switch the panner eg. AUX-Send and back
1196 * _route->panner_shell()->Changed() vs _panshell->Changed
1198 if (panners._panner == 0) {
1199 panners.panshell_changed ();
1201 update_panner_choices();
1205 MixerStrip::update_panner_choices ()
1207 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1208 if (!_route->panner_shell()) { return; }
1210 uint32_t in = _route->output()->n_ports().n_audio();
1212 if (_route->panner()) {
1213 in = _route->panner()->in().n_audio();
1216 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1220 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1222 /* The heuristic follows these principles:
1223 * A) If all ports that the user connected are of the same type, then he
1224 * very probably intends to use the IO with that type. A common subcase
1225 * is when the IO has only ports of the same type (connected or not).
1226 * B) If several types of ports are connected, then we should guess based
1227 * on the likeliness of the user wanting to use a given type.
1228 * We assume that the DataTypes are ordered from the most likely to the
1229 * least likely when iterating or comparing them with "<".
1230 * C) If no port is connected, the same logic can be applied with all ports
1231 * instead of connected ones. TODO: Try other ideas, for instance look at
1232 * the last plugin output when |for_input| is false (note: when StrictIO
1233 * the outs of the last plugin should be the same as the outs of the route
1234 * modulo the panner which forwards non-audio anyway).
1235 * All of these constraints are respected by the following algorithm that
1236 * just returns the most likely datatype found in connected ports if any, or
1237 * available ports if any (since if all ports are of the same type, the most
1238 * likely found will be that one obviously). */
1240 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1242 /* Find most likely type among connected ports */
1243 if (favor_connected) {
1244 DataType type = DataType::NIL; /* NIL is always last so least likely */
1245 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1246 if (p->connected() && p->type() < type)
1249 if (type != DataType::NIL) {
1250 /* There has been a connected port (necessarily non-NIL) */
1255 /* Find most likely type among available ports.
1256 * The iterator stops before NIL. */
1257 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1258 if (io->n_ports().n(*t) > 0)
1262 /* No port at all, return the most likely datatype by default */
1263 return DataType::front();
1267 * Output port labelling
1269 * Case 1: Each output has one connection, all connections are to system:playback_%i
1270 * out 1 -> system:playback_1
1271 * out 2 -> system:playback_2
1272 * out 3 -> system:playback_3
1275 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1276 * out 1 -> ardour:track_x/in 1
1277 * out 2 -> ardour:track_x/in 2
1278 * Display as: track_x
1280 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1281 * out 1 -> program x:foo
1282 * out 2 -> program x:foo
1283 * Display as: program x
1285 * Case 4: No connections (Disconnected)
1288 * Default case (unusual routing):
1289 * Display as: *number of connections*
1294 * .-----------------------------------------------.
1296 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1297 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1298 * '-----------------------------------------------'
1299 * .-----------------------------------------------.
1302 * '-----------------------------------------------'
1306 MixerStrip::update_io_button (bool for_input)
1308 ostringstream tooltip;
1309 ostringstream label;
1310 bool have_label = false;
1312 uint32_t total_connection_count = 0;
1313 uint32_t typed_connection_count = 0;
1314 bool each_typed_port_has_one_connection = true;
1316 DataType dt = guess_main_type(for_input);
1317 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1319 /* Fill in the tooltip. Also count:
1320 * - The total number of connections.
1321 * - The number of main-typed connections.
1322 * - Whether each main-typed port has exactly one connection. */
1324 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1325 Gtkmm2ext::markup_escape_text (_route->name()));
1327 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1328 Gtkmm2ext::markup_escape_text (_route->name()));
1331 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1332 vector<string> port_connections;
1333 for (PortSet::iterator port = io->ports().begin();
1334 port != io->ports().end();
1336 port_connections.clear();
1337 port->get_connections(port_connections);
1339 uint32_t port_connection_count = 0;
1341 for (vector<string>::iterator i = port_connections.begin();
1342 i != port_connections.end();
1344 ++port_connection_count;
1346 if (port_connection_count == 1) {
1347 tooltip << endl << Gtkmm2ext::markup_escape_text (
1348 port->name().substr(port->name().find("/") + 1));
1354 tooltip << Gtkmm2ext::markup_escape_text(*i);
1357 total_connection_count += port_connection_count;
1358 if (port->type() == dt) {
1359 typed_connection_count += port_connection_count;
1360 each_typed_port_has_one_connection &= (port_connection_count == 1);
1365 if (total_connection_count == 0) {
1366 tooltip << endl << _("Disconnected");
1369 if (typed_connection_count == 0) {
1374 /* Are all main-typed channels connected to the same route ? */
1376 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1377 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1378 route != routes->end();
1380 boost::shared_ptr<IO> dest_io =
1381 for_input ? (*route)->output() : (*route)->input();
1382 if (io->bundle()->connected_to(dest_io->bundle(),
1385 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1392 /* Are all main-typed channels connected to the same (user) bundle ? */
1394 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1395 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1396 bundle != bundles->end();
1398 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1400 if (io->bundle()->connected_to(*bundle, _session->engine(),
1402 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1409 /* Is each main-typed channel only connected to a physical output ? */
1410 if (!have_label && each_typed_port_has_one_connection) {
1411 ostringstream temp_label;
1412 vector<string> phys;
1413 string playorcapture;
1415 _session->engine().get_physical_inputs(dt, phys);
1416 playorcapture = "capture_";
1418 _session->engine().get_physical_outputs(dt, phys);
1419 playorcapture = "playback_";
1421 for (PortSet::iterator port = io->ports().begin(dt);
1422 port != io->ports().end(dt);
1425 for (vector<string>::iterator s = phys.begin();
1428 if (!port->connected_to(*s))
1430 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1432 string::size_type start = (*s).find(playorcapture);
1433 if (start != string::npos) {
1434 pn = (*s).substr(start + playorcapture.size());
1440 temp_label.str(""); /* erase the failed attempt */
1443 if (port != io->ports().begin(dt))
1448 if (!temp_label.str().empty()) {
1449 label << temp_label.str();
1454 /* Is each main-typed channel connected to a single and different port with
1455 * the same client name (e.g. another JACK client) ? */
1456 if (!have_label && each_typed_port_has_one_connection) {
1457 string maybe_client = "";
1458 vector<string> connections;
1459 for (PortSet::iterator port = io->ports().begin(dt);
1460 port != io->ports().end(dt);
1462 port_connections.clear();
1463 port->get_connections(port_connections);
1464 string connection = port_connections.front();
1466 vector<string>::iterator i = connections.begin();
1467 while (i != connections.end() && *i != connection) {
1470 if (i != connections.end())
1471 break; /* duplicate connection */
1472 connections.push_back(connection);
1474 connection = connection.substr(0, connection.find(":"));
1475 if (maybe_client.empty())
1476 maybe_client = connection;
1477 if (maybe_client != connection)
1480 if (connections.size() == io->n_ports().n(dt)) {
1481 label << maybe_client;
1486 /* Odd configuration */
1488 label << "*" << total_connection_count << "*";
1491 if (total_connection_count > typed_connection_count) {
1492 label << "\u2295"; /* circled plus */
1495 /* Actually set the properties of the button */
1496 char * cstr = new char[tooltip.str().size() + 1];
1497 strcpy(cstr, tooltip.str().c_str());
1500 input_button.set_text (label.str());
1501 set_tooltip (&input_button, cstr);
1503 output_button.set_text (label.str());
1504 set_tooltip (&output_button, cstr);
1511 MixerStrip::update_input_display ()
1513 update_io_button (true);
1514 panners.setup_pan ();
1516 if (has_audio_outputs ()) {
1517 panners.show_all ();
1519 panners.hide_all ();
1525 MixerStrip::update_output_display ()
1527 update_io_button (false);
1528 gpm.setup_meters ();
1529 panners.setup_pan ();
1531 if (has_audio_outputs ()) {
1532 panners.show_all ();
1534 panners.hide_all ();
1539 MixerStrip::fast_update ()
1541 gpm.update_meters ();
1545 MixerStrip::diskstream_changed ()
1547 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1551 MixerStrip::io_changed_proxy ()
1553 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1554 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1558 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1560 boost::shared_ptr<Port> a = wa.lock ();
1561 boost::shared_ptr<Port> b = wb.lock ();
1563 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1564 update_input_display ();
1565 set_width_enum (_width, this);
1568 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1569 update_output_display ();
1570 set_width_enum (_width, this);
1575 MixerStrip::setup_comment_button ()
1577 std::string comment = _route->comment();
1579 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1581 if (comment.empty ()) {
1582 _comment_button.set_name ("generic button");
1583 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1587 _comment_button.set_name ("comment button");
1589 string::size_type pos = comment.find_first_of (" \t\n");
1590 if (pos != string::npos) {
1591 comment = comment.substr (0, pos);
1593 if (comment.empty()) {
1594 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1596 _comment_button.set_text (comment);
1601 MixerStrip::select_route_group (GdkEventButton *ev)
1603 using namespace Menu_Helpers;
1605 if (ev->button == 1) {
1607 if (group_menu == 0) {
1609 PropertyList* plist = new PropertyList();
1611 plist->add (Properties::group_gain, true);
1612 plist->add (Properties::group_mute, true);
1613 plist->add (Properties::group_solo, true);
1615 group_menu = new RouteGroupMenu (_session, plist);
1619 r.push_back (route ());
1620 group_menu->build (r);
1622 RouteGroup *rg = _route->route_group();
1624 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1625 rg ? rg->name() : _("No Group"),
1633 MixerStrip::route_group_changed ()
1635 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1637 RouteGroup *rg = _route->route_group();
1640 group_button.set_text (PBD::short_version (rg->name(), 5));
1644 group_button.set_text (_("Grp"));
1647 group_button.set_text (_("~G"));
1654 MixerStrip::route_color_changed ()
1656 using namespace ARDOUR_UI_UTILS;
1657 name_button.modify_bg (STATE_NORMAL, color());
1658 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1659 reset_strip_style ();
1663 MixerStrip::show_passthru_color ()
1665 reset_strip_style ();
1670 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1672 boost::shared_ptr<Processor> processor (p.lock ());
1673 if (!processor || !processor->display_to_user()) {
1676 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1678 if (pi && pi->is_channelstrip ()) {
1683 ++_plugin_insert_cnt;
1687 MixerStrip::build_route_ops_menu ()
1689 using namespace Menu_Helpers;
1690 route_ops_menu = new Menu;
1691 route_ops_menu->set_name ("ArdourContextMenu");
1693 MenuList& items = route_ops_menu->items();
1695 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1697 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1699 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1701 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1703 if (!Profile->get_mixbus()) {
1704 items.push_back (SeparatorElem());
1707 if (!_route->is_master()
1709 && !_route->mixbus()
1712 if (Profile->get_mixbus()) {
1713 items.push_back (SeparatorElem());
1715 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1718 if (!Profile->get_mixbus()) {
1719 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1720 /* do not allow rename if the track is record-enabled */
1721 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1724 items.push_back (SeparatorElem());
1725 items.push_back (CheckMenuElem (_("Active")));
1726 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1727 i->set_active (_route->active());
1728 i->set_sensitive(! _session->transport_rolling());
1729 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1731 if (!Profile->get_mixbus ()) {
1732 items.push_back (SeparatorElem());
1733 items.push_back (CheckMenuElem (_("Strict I/O")));
1734 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1735 i->set_active (_route->strict_io());
1736 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1740 items.push_back (SeparatorElem());
1742 Gtk::Menu* dio_menu = new Menu;
1743 MenuList& dio_items = dio_menu->items();
1744 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1745 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1746 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1748 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1751 _plugin_insert_cnt = 0;
1752 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1753 if (_plugin_insert_cnt > 0) {
1754 items.push_back (SeparatorElem());
1755 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1758 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1759 items.push_back (MenuElem (_("Patch Selector..."),
1760 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1763 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1764 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1765 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1766 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1769 items.push_back (SeparatorElem());
1770 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1772 items.push_back (SeparatorElem());
1773 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1774 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1775 denormal_menu_item->set_active (_route->denormal_protection());
1778 /* note that this relies on selection being shared across editor and
1779 mixer (or global to the backend, in the future), which is the only
1780 sane thing for users anyway.
1783 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1785 Selection& selection (PublicEditor::instance().get_selection());
1786 if (!selection.selected (stav)) {
1787 selection.set (stav);
1790 if (!_route->is_master()) {
1791 items.push_back (SeparatorElem());
1792 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1795 items.push_back (SeparatorElem());
1796 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1802 MixerStrip::name_button_button_press (GdkEventButton* ev)
1804 if (ev->button == 1 || ev->button == 3) {
1805 list_route_operations ();
1807 if (ev->button == 1) {
1808 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1811 route_ops_menu->popup (3, ev->time);
1821 MixerStrip::number_button_button_press (GdkEventButton* ev)
1823 if ( ev->button == 3 ) {
1824 list_route_operations ();
1826 route_ops_menu->popup (1, ev->time);
1835 MixerStrip::list_route_operations ()
1837 delete route_ops_menu;
1838 build_route_ops_menu ();
1842 MixerStrip::set_selected (bool yn)
1844 AxisView::set_selected (yn);
1847 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1848 global_frame.set_name ("MixerStripSelectedFrame");
1850 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1851 global_frame.set_name ("MixerStripFrame");
1854 global_frame.queue_draw ();
1857 // processor_box.deselect_all_processors();
1861 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1863 if (what_changed.contains (ARDOUR::Properties::name)) {
1869 MixerStrip::name_changed ()
1873 name_button.set_text (_route->name());
1876 name_button.set_text (PBD::short_version (_route->name(), 5));
1880 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1882 if (_session->config.get_track_name_number()) {
1883 const int64_t track_number = _route->track_number ();
1884 if (track_number == 0) {
1885 number_label.set_text ("-");
1887 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1890 number_label.set_text ("");
1895 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1897 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1901 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1903 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1907 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1909 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1913 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1915 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1919 MixerStrip::width_button_pressed (GdkEventButton* ev)
1921 if (ev->button != 1) {
1925 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1928 _mixer.set_strip_width (Narrow, true);
1932 _mixer.set_strip_width (Wide, true);
1938 set_width_enum (Narrow, this);
1941 set_width_enum (Wide, this);
1950 MixerStrip::hide_clicked ()
1952 // LAME fix to reset the button status for when it is redisplayed (part 1)
1953 hide_button.set_sensitive(false);
1956 Hiding(); /* EMIT_SIGNAL */
1958 _mixer.hide_strip (this);
1962 hide_button.set_sensitive(true);
1966 MixerStrip::set_embedded (bool yn)
1972 MixerStrip::map_frozen ()
1974 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1976 boost::shared_ptr<AudioTrack> at = audio_track();
1979 switch (at->freeze_state()) {
1980 case AudioTrack::Frozen:
1981 processor_box.set_sensitive (false);
1982 hide_redirect_editors ();
1985 processor_box.set_sensitive (true);
1986 // XXX need some way, maybe, to retoggle redirect editors
1990 processor_box.set_sensitive (true);
1992 RouteUI::map_frozen ();
1996 MixerStrip::hide_redirect_editors ()
1998 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
2002 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
2004 boost::shared_ptr<Processor> processor (p.lock ());
2009 Gtk::Window* w = processor_box.get_processor_ui (processor);
2017 MixerStrip::reset_strip_style ()
2019 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2021 gpm.set_fader_name ("SendStripBase");
2025 if (is_midi_track()) {
2026 if (_route->active()) {
2027 set_name ("MidiTrackStripBase");
2029 set_name ("MidiTrackStripBaseInactive");
2031 gpm.set_fader_name ("MidiTrackFader");
2032 } else if (is_audio_track()) {
2033 if (_route->active()) {
2034 set_name ("AudioTrackStripBase");
2036 set_name ("AudioTrackStripBaseInactive");
2038 gpm.set_fader_name ("AudioTrackFader");
2040 if (_route->active()) {
2041 set_name ("AudioBusStripBase");
2043 set_name ("AudioBusStripBaseInactive");
2045 gpm.set_fader_name ("AudioBusFader");
2047 /* (no MIDI busses yet) */
2054 MixerStrip::engine_stopped ()
2059 MixerStrip::engine_running ()
2064 MixerStrip::meter_point_string (MeterPoint mp)
2077 case MeterPostFader:
2094 return S_("Meter|In");
2098 return S_("Meter|Pr");
2101 case MeterPostFader:
2102 return S_("Meter|Po");
2106 return S_("Meter|O");
2111 return S_("Meter|C");
2120 /** Called when the monitor-section state */
2122 MixerStrip::monitor_changed ()
2124 assert (monitor_section_button);
2125 if (_session->monitor_active()) {
2126 monitor_section_button->set_name ("master monitor section button active");
2128 monitor_section_button->set_name ("master monitor section button normal");
2133 MixerStrip::monitor_section_added_or_removed ()
2135 assert (monitor_section_button);
2136 if (mute_button->get_parent()) {
2137 mute_button->get_parent()->remove(*mute_button);
2139 if (monitor_section_button->get_parent()) {
2140 monitor_section_button->get_parent()->remove(*monitor_section_button);
2142 if (_session && _session->monitor_out ()) {
2143 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2144 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2145 mute_button->show();
2146 monitor_section_button->show();
2148 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2149 mute_button->show();
2153 /** Called when the metering point has changed */
2155 MixerStrip::meter_changed ()
2157 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2158 gpm.setup_meters ();
2159 // reset peak when meter point changes
2160 gpm.reset_peak_display();
2163 /** The bus that we are displaying sends to has changed, or been turned off.
2164 * @param send_to New bus that we are displaying sends to, or 0.
2167 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2169 RouteUI::bus_send_display_changed (send_to);
2172 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2177 revert_to_default_display ();
2180 revert_to_default_display ();
2185 MixerStrip::drop_send ()
2187 boost::shared_ptr<Send> current_send;
2189 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2190 current_send->set_metering (false);
2193 send_gone_connection.disconnect ();
2194 input_button.set_sensitive (true);
2195 output_button.set_sensitive (true);
2196 group_button.set_sensitive (true);
2197 set_invert_sensitive (true);
2198 gpm.meter_point_button.set_sensitive (true);
2199 mute_button->set_sensitive (true);
2200 solo_button->set_sensitive (true);
2201 solo_isolated_led->set_sensitive (true);
2202 solo_safe_led->set_sensitive (true);
2203 monitor_input_button->set_sensitive (true);
2204 monitor_disk_button->set_sensitive (true);
2205 _comment_button.set_sensitive (true);
2206 trim_control.set_sensitive (true);
2207 if (midi_input_enable_button) {
2208 midi_input_enable_button->set_sensitive (true);
2210 control_slave_ui.set_sensitive (true);
2211 RouteUI::check_rec_enable_sensitivity ();
2212 set_button_names (); // update solo button visual state
2216 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2218 _current_delivery = d;
2219 DeliveryChanged (_current_delivery);
2223 MixerStrip::show_send (boost::shared_ptr<Send> send)
2229 set_current_delivery (send);
2231 send->meter()->set_meter_type (_route->meter_type ());
2232 send->set_metering (true);
2233 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2235 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2236 gain_meter().setup_meters ();
2238 uint32_t const in = _current_delivery->pans_required();
2239 uint32_t const out = _current_delivery->pan_outs();
2241 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2242 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2243 panner_ui().setup_pan ();
2244 panner_ui().set_send_drawing_mode (true);
2245 panner_ui().show_all ();
2247 input_button.set_sensitive (false);
2248 group_button.set_sensitive (false);
2249 set_invert_sensitive (false);
2250 gpm.meter_point_button.set_sensitive (false);
2251 mute_button->set_sensitive (false);
2252 solo_button->set_sensitive (false);
2253 rec_enable_button->set_sensitive (false);
2254 solo_isolated_led->set_sensitive (false);
2255 solo_safe_led->set_sensitive (false);
2256 monitor_input_button->set_sensitive (false);
2257 monitor_disk_button->set_sensitive (false);
2258 _comment_button.set_sensitive (false);
2259 trim_control.set_sensitive (false);
2260 if (midi_input_enable_button) {
2261 midi_input_enable_button->set_sensitive (false);
2263 control_slave_ui.set_sensitive (false);
2265 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2266 output_button.set_sensitive (false);
2269 reset_strip_style ();
2273 MixerStrip::revert_to_default_display ()
2277 set_current_delivery (_route->main_outs ());
2279 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2280 gain_meter().setup_meters ();
2282 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2283 update_panner_choices();
2284 panner_ui().setup_pan ();
2285 panner_ui().set_send_drawing_mode (false);
2287 if (has_audio_outputs ()) {
2288 panners.show_all ();
2290 panners.hide_all ();
2293 reset_strip_style ();
2297 MixerStrip::set_button_names ()
2301 mute_button->set_text (_("Mute"));
2302 monitor_input_button->set_text (_("In"));
2303 monitor_disk_button->set_text (_("Disk"));
2304 if (monitor_section_button) {
2305 monitor_section_button->set_text (_("Mon"));
2308 if (_route && _route->solo_safe_control()->solo_safe()) {
2309 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2311 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2313 if (!Config->get_solo_control_is_listen_control()) {
2314 solo_button->set_text (_("Solo"));
2316 switch (Config->get_listen_position()) {
2317 case AfterFaderListen:
2318 solo_button->set_text (_("AFL"));
2320 case PreFaderListen:
2321 solo_button->set_text (_("PFL"));
2325 solo_isolated_led->set_text (_("Iso"));
2326 solo_safe_led->set_text (S_("SoloLock|Lock"));
2330 mute_button->set_text (S_("Mute|M"));
2331 monitor_input_button->set_text (S_("MonitorInput|I"));
2332 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2333 if (monitor_section_button) {
2334 monitor_section_button->set_text (S_("Mon|O"));
2337 if (_route && _route->solo_safe_control()->solo_safe()) {
2338 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2340 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2342 if (!Config->get_solo_control_is_listen_control()) {
2343 solo_button->set_text (S_("Solo|S"));
2345 switch (Config->get_listen_position()) {
2346 case AfterFaderListen:
2347 solo_button->set_text (S_("AfterFader|A"));
2349 case PreFaderListen:
2350 solo_button->set_text (S_("Prefader|P"));
2355 solo_isolated_led->set_text (S_("SoloIso|I"));
2356 solo_safe_led->set_text (S_("SoloLock|L"));
2361 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2363 gpm.meter_point_button.set_text ("");
2368 MixerStrip::plugin_selector()
2370 return _mixer.plugin_selector();
2374 MixerStrip::hide_things ()
2376 processor_box.hide_things ();
2380 MixerStrip::input_active_button_press (GdkEventButton*)
2382 /* nothing happens on press */
2387 MixerStrip::input_active_button_release (GdkEventButton* ev)
2389 boost::shared_ptr<MidiTrack> mt = midi_track ();
2395 boost::shared_ptr<RouteList> rl (new RouteList);
2397 rl->push_back (route());
2399 _session->set_exclusive_input_active (rl, !mt->input_active(),
2400 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2406 MixerStrip::midi_input_status_changed ()
2408 if (midi_input_enable_button) {
2409 boost::shared_ptr<MidiTrack> mt = midi_track ();
2411 midi_input_enable_button->set_active (mt->input_active ());
2416 MixerStrip::state_id () const
2418 return string_compose ("strip %1", _route->id().to_s());
2422 MixerStrip::parameter_changed (string p)
2424 if (p == _visibility.get_state_name()) {
2425 /* The user has made changes to the mixer strip visibility, so get
2426 our VisibilityGroup to reflect these changes in our widgets.
2428 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2429 } else if (p == "track-name-number") {
2431 update_track_number_visibility();
2435 /** Called to decide whether the solo isolate / solo lock button visibility should
2436 * be overridden from that configured by the user. We do this for the master bus.
2438 * @return optional value that is present if visibility state should be overridden.
2440 boost::optional<bool>
2441 MixerStrip::override_solo_visibility () const
2443 if (_route && _route->is_master ()) {
2444 return boost::optional<bool> (false);
2447 return boost::optional<bool> ();
2451 MixerStrip::add_input_port (DataType t)
2453 _route->input()->add_port ("", this, t);
2457 MixerStrip::add_output_port (DataType t)
2459 _route->output()->add_port ("", this, t);
2463 MixerStrip::route_active_changed ()
2465 reset_strip_style ();
2469 MixerStrip::copy_processors ()
2471 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2475 MixerStrip::cut_processors ()
2477 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2481 MixerStrip::paste_processors ()
2483 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2487 MixerStrip::select_all_processors ()
2489 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2493 MixerStrip::deselect_all_processors ()
2495 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2499 MixerStrip::delete_processors ()
2501 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2505 MixerStrip::toggle_processors ()
2507 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2511 MixerStrip::ab_plugins ()
2513 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2517 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2519 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2522 if (ev->button == 3) {
2523 popup_level_meter_menu (ev);
2531 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2533 using namespace Gtk::Menu_Helpers;
2535 Gtk::Menu* m = ARDOUR_UI_UTILS::shared_popup_menu ();
2536 MenuList& items = m->items ();
2538 RadioMenuItem::Group group;
2540 PBD::Unwinder<bool> uw (_suspend_menu_callbacks, true);
2541 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2542 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2543 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2544 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2545 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2547 if (gpm.meter_channels().n_audio() == 0) {
2548 m->popup (ev->button, ev->time);
2552 RadioMenuItem::Group tgroup;
2553 items.push_back (SeparatorElem());
2555 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2556 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2557 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2558 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2559 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2560 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2561 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2562 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2563 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2564 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2565 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2568 if (_route->is_master()) {
2571 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2572 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2573 /* non-master bus */
2576 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2583 MeterType cmt = _route->meter_type();
2584 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2586 items.push_back (SeparatorElem());
2587 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2588 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2589 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2590 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2591 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2592 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2594 m->popup (ev->button, ev->time);
2598 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2599 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2601 using namespace Menu_Helpers;
2603 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2604 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2605 i->set_active (_route->meter_point() == point);
2609 MixerStrip::set_meter_point (MeterPoint p)
2611 if (_suspend_menu_callbacks) return;
2612 _route->set_meter_point (p);
2616 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2617 RadioMenuItem::Group& group, string const & name, MeterType type)
2619 using namespace Menu_Helpers;
2621 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2622 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2623 i->set_active (_route->meter_type() == type);
2627 MixerStrip::set_meter_type (MeterType t)
2629 if (_suspend_menu_callbacks) return;
2630 _route->set_meter_type (t);
2634 MixerStrip::update_track_number_visibility ()
2636 DisplaySuspender ds;
2637 bool show_label = _session->config.get_track_name_number();
2639 if (_route && _route->is_master()) {
2644 number_label.show ();
2645 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2646 // except the width of the number label is subtracted from the name-hbox, so we
2647 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2648 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2650 number_label.set_size_request(tnw, -1);
2651 number_label.show ();
2653 number_label.hide ();
2658 MixerStrip::color () const
2660 return route_color ();
2664 MixerStrip::marked_for_display () const
2666 return !_route->presentation_info().hidden();
2670 MixerStrip::set_marked_for_display (bool yn)
2672 return RouteUI::mark_hidden (!yn);
2676 MixerStrip::hide_master_spacer (bool yn)
2678 if (_mixer_owned && route()->is_master() && !yn) {