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"
32 #include "ardour/amp.h"
33 #include "ardour/audio_track.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/internal_send.h"
36 #include "ardour/io.h"
37 #include "ardour/meter.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/pannable.h"
40 #include "ardour/panner.h"
41 #include "ardour/panner_shell.h"
42 #include "ardour/panner_manager.h"
43 #include "ardour/port.h"
44 #include "ardour/profile.h"
45 #include "ardour/route.h"
46 #include "ardour/route_group.h"
47 #include "ardour/send.h"
48 #include "ardour/session.h"
49 #include "ardour/types.h"
50 #include "ardour/user_bundle.h"
51 #include "ardour/vca.h"
52 #include "ardour/vca_manager.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/menu_elems.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/doi.h"
59 #include "widgets/tooltips.h"
61 #include "ardour_window.h"
62 #include "enums_convert.h"
63 #include "mixer_strip.h"
66 #include "public_editor.h"
68 #include "io_selector.h"
70 #include "gui_thread.h"
71 #include "route_group_menu.h"
72 #include "meter_patterns.h"
73 #include "ui_config.h"
77 using namespace ARDOUR;
78 using namespace ArdourWidgets;
81 using namespace Gtkmm2ext;
83 using namespace ArdourMeter;
85 MixerStrip* MixerStrip::_entered_mixer_strip;
86 PBD::Signal1<void,MixerStrip*> MixerStrip::CatchDeletion;
88 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, bool in_mixer)
89 : SessionHandlePtr (sess)
92 , _mixer_owned (in_mixer)
93 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
96 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
97 , rec_mon_table (2, 2)
98 , solo_iso_table (1, 2)
99 , mute_solo_table (1, 2)
100 , bottom_button_table (1, 3)
101 , monitor_section_button (0)
102 , midi_input_enable_button (0)
103 , _plugin_insert_cnt (0)
104 , _comment_button (_("Comments"))
105 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
106 , _visibility (X_("mixer-element-visibility"))
107 , control_slave_ui (sess)
112 /* the editor mixer strip: don't destroy it every time
113 the underlying route goes away.
116 self_destruct = false;
120 MixerStrip::MixerStrip (Mixer_UI& mx, Session* sess, boost::shared_ptr<Route> rt, bool in_mixer)
121 : SessionHandlePtr (sess)
124 , _mixer_owned (in_mixer)
125 , processor_box (sess, boost::bind (&MixerStrip::plugin_selector, this), mx.selection(), this, in_mixer)
128 , button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_HORIZONTAL))
129 , rec_mon_table (2, 2)
130 , solo_iso_table (1, 2)
131 , mute_solo_table (1, 2)
132 , bottom_button_table (1, 3)
133 , monitor_section_button (0)
134 , midi_input_enable_button (0)
135 , _plugin_insert_cnt (0)
136 , _comment_button (_("Comments"))
137 , trim_control (ArdourKnob::default_elements, ArdourKnob::Flags (ArdourKnob::Detent | ArdourKnob::ArcToZero))
138 , _visibility (X_("mixer-element-visibility"))
139 , control_slave_ui (sess)
148 _entered_mixer_strip= 0;
151 ignore_comment_edit = false;
152 ignore_toggle = false;
156 /* the length of this string determines the width of the mixer strip when it is set to `wide' */
157 longest_label = "longest label";
159 string t = _("Click to toggle the width of this mixer strip.");
161 t += string_compose (_("\n%1-%2-click to toggle the width of all strips."), Keyboard::primary_modifier_name(), Keyboard::tertiary_modifier_name ());
164 width_button.set_icon (ArdourIcon::StripWidth);
165 hide_button.set_tweaks (ArdourButton::Square);
166 set_tooltip (width_button, t);
168 hide_button.set_icon (ArdourIcon::CloseCross);
169 hide_button.set_tweaks (ArdourButton::Square);
170 set_tooltip (&hide_button, _("Hide this mixer strip"));
172 input_button_box.set_spacing(2);
174 input_button.set_text (_("Input"));
175 input_button.set_name ("mixer strip button");
176 input_button_box.pack_start (input_button, true, true);
178 output_button.set_text (_("Output"));
179 output_button.set_name ("mixer strip button");
181 bottom_button_table.attach (gpm.meter_point_button, 2, 3, 0, 1);
183 hide_button.set_events (hide_button.get_events() & ~(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK));
185 solo_isolated_led = manage (new ArdourButton (ArdourButton::led_default_elements));
186 solo_isolated_led->show ();
187 solo_isolated_led->set_no_show_all (true);
188 solo_isolated_led->set_name (X_("solo isolate"));
189 solo_isolated_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
190 solo_isolated_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_isolate_button_release), false);
191 UI::instance()->set_tip (solo_isolated_led, _("Isolate Solo"), "");
193 solo_safe_led = manage (new ArdourButton (ArdourButton::led_default_elements));
194 solo_safe_led->show ();
195 solo_safe_led->set_no_show_all (true);
196 solo_safe_led->set_name (X_("solo safe"));
197 solo_safe_led->add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
198 solo_safe_led->signal_button_release_event().connect (sigc::mem_fun (*this, &RouteUI::solo_safe_button_release), false);
199 UI::instance()->set_tip (solo_safe_led, _("Lock Solo Status"), "");
201 solo_safe_led->set_text (S_("SoloLock|Lock"));
202 solo_isolated_led->set_text (_("Iso"));
204 solo_iso_table.set_homogeneous (true);
205 solo_iso_table.set_spacings (2);
206 if (!ARDOUR::Profile->get_trx()) {
207 solo_iso_table.attach (*solo_isolated_led, 0, 1, 0, 1);
208 solo_iso_table.attach (*solo_safe_led, 1, 2, 0, 1);
210 solo_iso_table.show ();
212 rec_mon_table.set_homogeneous (true);
213 rec_mon_table.set_row_spacings (2);
214 rec_mon_table.set_col_spacings (2);
215 if (ARDOUR::Profile->get_mixbus()) {
216 rec_mon_table.resize (1, 3);
217 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
218 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
219 } else if (!ARDOUR::Profile->get_trx()) {
220 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
221 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
223 rec_mon_table.show ();
225 if (solo_isolated_led) {
226 button_size_group->add_widget (*solo_isolated_led);
229 button_size_group->add_widget (*solo_safe_led);
232 if (!ARDOUR::Profile->get_mixbus()) {
233 if (rec_enable_button) {
234 button_size_group->add_widget (*rec_enable_button);
236 if (monitor_disk_button) {
237 button_size_group->add_widget (*monitor_disk_button);
239 if (monitor_input_button) {
240 button_size_group->add_widget (*monitor_input_button);
244 mute_solo_table.set_homogeneous (true);
245 mute_solo_table.set_spacings (2);
247 bottom_button_table.set_spacings (2);
248 bottom_button_table.set_homogeneous (true);
249 bottom_button_table.attach (group_button, 1, 2, 0, 1);
250 bottom_button_table.attach (gpm.gain_automation_state_button, 0, 1, 0, 1);
252 name_button.set_name ("mixer strip button");
253 name_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
254 name_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::name_button_resized));
256 set_tooltip (&group_button, _("Mix group"));
257 group_button.set_name ("mixer strip button");
259 _comment_button.set_name (X_("mixer strip button"));
260 _comment_button.set_text_ellipsize (Pango::ELLIPSIZE_END);
261 _comment_button.signal_clicked.connect (sigc::mem_fun (*this, &RouteUI::toggle_comment_editor));
262 _comment_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::comment_button_resized));
264 // TODO implement ArdourKnob::on_size_request properly
265 #define PX_SCALE(px) std::max((float)px, rintf((float)px * UIConfiguration::instance().get_ui_scale()))
266 trim_control.set_size_request (PX_SCALE(19), PX_SCALE(19));
268 trim_control.set_tooltip_prefix (_("Trim: "));
269 trim_control.set_name ("trim knob");
270 trim_control.set_no_show_all (true);
271 trim_control.StartGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_start_touch));
272 trim_control.StopGesture.connect(sigc::mem_fun(*this, &MixerStrip::trim_end_touch));
273 input_button_box.pack_start (trim_control, false, false);
275 global_vpacker.set_border_width (1);
276 global_vpacker.set_spacing (0);
278 width_button.set_name ("mixer strip button");
279 hide_button.set_name ("mixer strip button");
281 width_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::width_button_pressed), false);
282 hide_button.signal_clicked.connect (sigc::mem_fun(*this, &MixerStrip::hide_clicked));
284 width_hide_box.set_spacing (2);
285 width_hide_box.pack_start (width_button, false, true);
286 width_hide_box.pack_start (number_label, true, true);
287 width_hide_box.pack_end (hide_button, false, true);
289 number_label.set_text ("-");
290 number_label.set_elements((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::Text|ArdourButton::Inactive));
291 number_label.set_no_show_all ();
292 number_label.set_name ("tracknumber label");
293 number_label.set_fixed_colors (0x80808080, 0x80808080);
294 number_label.set_alignment (.5, .5);
295 number_label.set_fallthrough_to_parent (true);
296 number_label.set_tweaks (ArdourButton::OccasionalText);
298 global_vpacker.set_spacing (2);
299 if (!ARDOUR::Profile->get_trx()) {
300 global_vpacker.pack_start (width_hide_box, Gtk::PACK_SHRINK);
301 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
302 global_vpacker.pack_start (input_button_box, Gtk::PACK_SHRINK);
303 global_vpacker.pack_start (_invert_button_box, Gtk::PACK_SHRINK);
304 global_vpacker.pack_start (processor_box, true, true);
306 global_vpacker.pack_start (panners, Gtk::PACK_SHRINK);
307 global_vpacker.pack_start (rec_mon_table, Gtk::PACK_SHRINK);
308 global_vpacker.pack_start (solo_iso_table, Gtk::PACK_SHRINK);
309 global_vpacker.pack_start (mute_solo_table, Gtk::PACK_SHRINK);
310 global_vpacker.pack_start (gpm, Gtk::PACK_SHRINK);
311 global_vpacker.pack_start (control_slave_ui, Gtk::PACK_SHRINK);
312 global_vpacker.pack_start (bottom_button_table, Gtk::PACK_SHRINK);
313 if (!ARDOUR::Profile->get_trx()) {
314 global_vpacker.pack_start (output_button, Gtk::PACK_SHRINK);
315 global_vpacker.pack_start (_comment_button, Gtk::PACK_SHRINK);
317 global_vpacker.pack_start (name_button, Gtk::PACK_SHRINK);
321 //add a spacer underneath the master bus;
322 //this fills the area that is taken up by the scrollbar on the tracks;
323 //and therefore keeps the faders "even" across the bottom
324 int scrollbar_height = 0;
326 Gtk::Window window (WINDOW_TOPLEVEL);
327 HScrollbar scrollbar;
328 window.add (scrollbar);
329 scrollbar.set_name ("MixerWindow");
330 scrollbar.ensure_style();
331 Gtk::Requisition requisition(scrollbar.size_request ());
332 scrollbar_height = requisition.height;
334 spacer.set_size_request (-1, scrollbar_height);
335 global_vpacker.pack_end (spacer, false, false);
338 global_frame.add (global_vpacker);
339 global_frame.set_shadow_type (Gtk::SHADOW_IN);
340 global_frame.set_name ("BaseFrame");
344 /* force setting of visible selected status */
347 set_selected (false);
352 _session->engine().Stopped.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_stopped, this), gui_context());
353 _session->engine().Running.connect (*this, invalidator (*this), boost::bind (&MixerStrip::engine_running, this), gui_context());
355 input_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::input_press), false);
356 input_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::input_release), false);
357 input_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::input_button_resized));
359 input_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
360 output_button.set_text_ellipsize (Pango::ELLIPSIZE_MIDDLE);
362 output_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::output_press), false);
363 output_button.signal_button_release_event().connect (sigc::mem_fun(*this, &MixerStrip::output_release), false);
364 output_button.signal_size_allocate().connect (sigc::mem_fun (*this, &MixerStrip::output_button_resized));
366 number_label.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::number_button_button_press), false);
368 name_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::name_button_button_press), false);
370 group_button.signal_button_press_event().connect (sigc::mem_fun(*this, &MixerStrip::select_route_group), false);
374 /* start off as a passthru strip. we'll correct this, if necessary,
375 in update_diskstream_display().
378 /* start off as a passthru strip. we'll correct this, if necessary,
379 in update_diskstream_display().
382 if (is_midi_track()) {
383 set_name ("MidiTrackStripBase");
385 set_name ("AudioTrackStripBase");
388 add_events (Gdk::BUTTON_RELEASE_MASK|
389 Gdk::ENTER_NOTIFY_MASK|
390 Gdk::LEAVE_NOTIFY_MASK|
392 Gdk::KEY_RELEASE_MASK);
394 set_flags (get_flags() | Gtk::CAN_FOCUS);
396 AudioEngine::instance()->PortConnectedOrDisconnected.connect (
397 *this, invalidator (*this), boost::bind (&MixerStrip::port_connected_or_disconnected, this, _1, _3), gui_context ()
400 /* Add the widgets under visibility control to the VisibilityGroup; the names used here
401 must be the same as those used in RCOptionEditor so that the configuration changes
402 are recognised when they occur.
404 _visibility.add (&input_button_box, X_("Input"), _("Input"), false);
405 _visibility.add (&_invert_button_box, X_("PhaseInvert"), _("Phase Invert"), false);
406 _visibility.add (&rec_mon_table, X_("RecMon"), _("Record & Monitor"), false);
407 _visibility.add (&solo_iso_table, X_("SoloIsoLock"), _("Solo Iso / Lock"), false);
408 _visibility.add (&output_button, X_("Output"), _("Output"), false);
409 _visibility.add (&_comment_button, X_("Comments"), _("Comments"), false);
410 _visibility.add (&control_slave_ui, X_("VCA"), _("VCA Assigns"), false);
412 parameter_changed (X_("mixer-element-visibility"));
413 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &MixerStrip::parameter_changed));
414 Config->ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
415 _session->config.ParameterChanged.connect (_config_connection, MISSING_INVALIDATOR, boost::bind (&MixerStrip::parameter_changed, this, _1), gui_context());
417 //watch for mouse enter/exit so we can do some stuff
418 signal_enter_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_enter_event ));
419 signal_leave_notify_event().connect (sigc::mem_fun(*this, &MixerStrip::mixer_strip_leave_event ));
421 gpm.LevelMeterButtonPress.connect_same_thread (_level_meter_connection, boost::bind (&MixerStrip::level_meter_button_press, this, _1));
424 MixerStrip::~MixerStrip ()
426 CatchDeletion (this);
428 if (this ==_entered_mixer_strip)
429 _entered_mixer_strip = NULL;
433 MixerStrip::vca_assign (boost::shared_ptr<ARDOUR::VCA> vca)
435 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
441 MixerStrip::vca_unassign (boost::shared_ptr<ARDOUR::VCA> vca)
443 boost::shared_ptr<Slavable> sl = boost::dynamic_pointer_cast<Slavable> ( route() );
449 MixerStrip::mixer_strip_enter_event (GdkEventCrossing* /*ev*/)
451 _entered_mixer_strip = this;
453 //although we are triggering on the "enter", to the user it will appear that it is happenin on the "leave"
454 //because the mixerstrip control is a parent that encompasses the strip
455 deselect_all_processors();
461 MixerStrip::mixer_strip_leave_event (GdkEventCrossing *ev)
463 //if we have moved outside our strip, but not into a child view, then deselect ourselves
464 if ( !(ev->detail == GDK_NOTIFY_INFERIOR) ) {
465 _entered_mixer_strip= 0;
467 //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
468 gpm.gain_display.set_sensitive(false);
470 gpm.gain_display.set_sensitive(true);
472 //if we leave this mixer strip we need to clear out any selections
473 //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
480 MixerStrip::name() const
483 return _route->name();
489 MixerStrip::update_trim_control ()
491 if (route()->trim() && route()->trim()->active() &&
492 route()->n_inputs().n_audio() > 0) {
493 trim_control.show ();
494 trim_control.set_controllable (route()->trim()->gain_control());
496 trim_control.hide ();
497 boost::shared_ptr<Controllable> none;
498 trim_control.set_controllable (none);
503 MixerStrip::trim_start_touch ()
505 assert (_route && _session);
506 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
507 route()->trim()->gain_control ()->start_touch (_session->transport_frame());
512 MixerStrip::trim_end_touch ()
514 assert (_route && _session);
515 if (route()->trim() && route()->trim()->active() && route()->n_inputs().n_audio() > 0) {
516 route()->trim()->gain_control ()->stop_touch (_session->transport_frame());
521 MixerStrip::set_route (boost::shared_ptr<Route> rt)
523 //the rec/monitor stuff only shows up for tracks.
524 //the show_sends only shows up for buses.
525 //remove them all here, and we may add them back later
526 if (show_sends_button->get_parent()) {
527 rec_mon_table.remove (*show_sends_button);
529 if (rec_enable_button->get_parent()) {
530 rec_mon_table.remove (*rec_enable_button);
532 if (monitor_input_button->get_parent()) {
533 rec_mon_table.remove (*monitor_input_button);
535 if (monitor_disk_button->get_parent()) {
536 rec_mon_table.remove (*monitor_disk_button);
538 if (group_button.get_parent()) {
539 bottom_button_table.remove (group_button);
542 RouteUI::set_route (rt);
544 control_slave_ui.set_stripable (boost::dynamic_pointer_cast<Stripable> (rt));
546 /* ProcessorBox needs access to _route so that it can read
549 processor_box.set_route (rt);
551 revert_to_default_display ();
553 /* unpack these from the parent and stuff them into our own
557 if (gpm.peak_display.get_parent()) {
558 gpm.peak_display.get_parent()->remove (gpm.peak_display);
560 if (gpm.gain_display.get_parent()) {
561 gpm.gain_display.get_parent()->remove (gpm.gain_display);
564 gpm.set_type (rt->meter_type());
566 mute_solo_table.attach (gpm.gain_display,0,1,1,2, EXPAND|FILL, EXPAND);
567 mute_solo_table.attach (gpm.peak_display,1,2,1,2, EXPAND|FILL, EXPAND);
569 if (solo_button->get_parent()) {
570 mute_solo_table.remove (*solo_button);
573 if (mute_button->get_parent()) {
574 mute_solo_table.remove (*mute_button);
577 if (route()->is_master()) {
578 solo_button->hide ();
579 mute_button->show ();
580 rec_mon_table.hide ();
581 solo_iso_table.set_sensitive(false);
582 control_slave_ui.set_sensitive(false);
583 if (monitor_section_button == 0) {
584 Glib::RefPtr<Action> act = ActionManager::get_action ("Common", "ToggleMonitorSection");
585 _session->MonitorChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::monitor_changed, this), gui_context());
587 monitor_section_button = manage (new ArdourButton);
589 monitor_section_button->set_related_action (act);
590 set_tooltip (monitor_section_button, _("Show/Hide Monitoring Section"));
591 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
592 monitor_section_button->show();
593 monitor_section_button->unset_flags (Gtk::CAN_FOCUS);
595 parameter_changed ("use-monitor-bus");
597 bottom_button_table.attach (group_button, 1, 2, 0, 1);
598 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
599 mute_solo_table.attach (*solo_button, 1, 2, 0, 1);
600 mute_button->show ();
601 solo_button->show ();
602 rec_mon_table.show ();
603 solo_iso_table.set_sensitive(true);
604 control_slave_ui.set_sensitive(true);
607 if (_mixer_owned && route()->is_master() ) {
614 monitor_input_button->show ();
615 monitor_disk_button->show ();
617 monitor_input_button->hide();
618 monitor_disk_button->hide ();
621 update_trim_control();
623 if (is_midi_track()) {
624 if (midi_input_enable_button == 0) {
625 midi_input_enable_button = manage (new ArdourButton);
626 midi_input_enable_button->set_name ("midi input button");
627 midi_input_enable_button->set_elements ((ArdourButton::Element)(ArdourButton::Edge|ArdourButton::Body|ArdourButton::VectorIcon));
628 midi_input_enable_button->set_icon (ArdourIcon::DinMidi);
629 midi_input_enable_button->signal_button_press_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_press), false);
630 midi_input_enable_button->signal_button_release_event().connect (sigc::mem_fun (*this, &MixerStrip::input_active_button_release), false);
631 set_tooltip (midi_input_enable_button, _("Enable/Disable MIDI input"));
633 input_button_box.remove (*midi_input_enable_button);
635 /* get current state */
636 midi_input_status_changed ();
637 input_button_box.pack_start (*midi_input_enable_button, false, false);
639 midi_track()->InputActiveChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::midi_input_status_changed, this), gui_context());
641 if (midi_input_enable_button) {
642 /* removal from the container will delete it */
643 input_button_box.remove (*midi_input_enable_button);
644 midi_input_enable_button = 0;
648 if (is_audio_track()) {
649 boost::shared_ptr<AudioTrack> at = audio_track();
650 at->FreezeChange.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::map_frozen, this), gui_context());
655 rec_mon_table.attach (*rec_enable_button, 0, 1, 0, ARDOUR::Profile->get_mixbus() ? 1 : 2);
656 rec_enable_button->show();
658 if (ARDOUR::Profile->get_mixbus()) {
659 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
660 rec_mon_table.attach (*monitor_disk_button, 2, 3, 0, 1);
661 } else if (ARDOUR::Profile->get_trx()) {
662 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 2);
664 rec_mon_table.attach (*monitor_input_button, 1, 2, 0, 1);
665 rec_mon_table.attach (*monitor_disk_button, 1, 2, 1, 2);
672 if (!_route->is_master()) {
673 rec_mon_table.attach (*show_sends_button, 0, 1, 0, 2);
674 show_sends_button->show();
678 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
680 delete route_ops_menu;
683 _route->meter_change.connect (route_connections, invalidator (*this), bind (&MixerStrip::meter_changed, this), gui_context());
684 _route->input()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_input_display, this), gui_context());
685 _route->output()->changed.connect (*this, invalidator (*this), boost::bind (&MixerStrip::update_output_display, this), gui_context());
686 _route->route_group_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::route_group_changed, this), gui_context());
688 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::io_changed_proxy, this), gui_context ());
690 if (_route->panner_shell()) {
691 update_panner_choices();
692 _route->panner_shell()->Changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::connect_to_pan, this), gui_context());
695 if (is_audio_track()) {
696 audio_track()->DiskstreamChanged.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::diskstream_changed, this), gui_context());
699 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
701 set_stuff_from_route ();
703 /* now force an update of all the various elements */
705 update_mute_display ();
706 update_solo_display ();
709 route_group_changed ();
710 update_track_number_visibility ();
713 panners.setup_pan ();
715 if (has_audio_outputs ()) {
721 update_diskstream_display ();
722 update_input_display ();
723 update_output_display ();
725 add_events (Gdk::BUTTON_RELEASE_MASK);
727 processor_box.show ();
729 if (!route()->is_master() && !route()->is_monitor()) {
730 /* we don't allow master or control routes to be hidden */
735 gpm.reset_peak_display ();
736 gpm.gain_display.show ();
737 gpm.peak_display.show ();
740 width_hide_box.show();
742 global_vpacker.show();
743 mute_solo_table.show();
744 bottom_button_table.show();
746 gpm.meter_point_button.show();
747 input_button_box.show_all();
748 output_button.show();
750 _comment_button.show();
752 gpm.gain_automation_state_button.show();
754 parameter_changed ("mixer-element-visibility");
761 MixerStrip::set_stuff_from_route ()
763 /* if width is not set, it will be set by the MixerUI or editor */
766 if (get_gui_property ("strip-width", width)) {
767 set_width_enum (width, this);
772 MixerStrip::set_width_enum (Width w, void* owner)
774 /* always set the gpm width again, things may be hidden */
777 panners.set_width (w);
779 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
781 _width_owner = owner;
785 if (_width_owner == this) {
786 set_gui_property ("strip-width", _width);
791 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
796 if (show_sends_button) {
797 show_sends_button->set_text (_("Aux"));
800 gpm.gain_automation_state_button.set_text (
801 gpm.astate_string(gain_automation->automation_state()));
803 if (_route->panner()) {
804 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
805 panners.astate_string(_route->panner()->automation_state()));
809 // panners expect an even number of horiz. pixels
810 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
812 set_size_request (width, -1);
818 if (show_sends_button) {
819 show_sends_button->set_text (_("Snd"));
822 gpm.gain_automation_state_button.set_text (
823 gpm.short_astate_string(gain_automation->automation_state()));
824 gain_meter().setup_meters (); // recalc meter width
826 if (_route->panner()) {
827 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
828 panners.short_astate_string(_route->panner()->automation_state()));
832 // panners expect an even number of horiz. pixels
833 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
835 set_size_request (width, -1);
840 processor_box.set_width (w);
842 update_input_display ();
843 update_output_display ();
844 setup_comment_button ();
845 route_group_changed ();
851 MixerStrip::set_packed (bool yn)
854 set_gui_property ("visible", _packed);
858 struct RouteCompareByName {
859 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
860 return a->name().compare (b->name()) < 0;
865 MixerStrip::output_release (GdkEventButton *ev)
867 switch (ev->button) {
869 edit_output_configuration ();
877 MixerStrip::output_press (GdkEventButton *ev)
879 using namespace Menu_Helpers;
880 if (!_session->engine().connected()) {
881 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
886 MenuList& citems = output_menu.items();
887 switch (ev->button) {
890 return false; //wait for the mouse-up to pop the dialog
894 output_menu.set_name ("ArdourContextMenu");
896 output_menu_bundles.clear ();
898 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
900 citems.push_back (SeparatorElem());
901 uint32_t const n_with_separator = citems.size ();
903 ARDOUR::BundleList current = _route->output()->bundles_connected ();
905 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
907 /* give user bundles first chance at being in the menu */
909 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
910 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
911 maybe_add_bundle_to_output_menu (*i, current);
915 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
916 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
917 maybe_add_bundle_to_output_menu (*i, current);
921 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
922 RouteList copy = *routes;
923 copy.sort (RouteCompareByName ());
924 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
925 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current);
928 if (citems.size() == n_with_separator) {
929 /* no routes added; remove the separator */
933 if (!ARDOUR::Profile->get_mixbus()) {
934 citems.push_back (SeparatorElem());
936 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
939 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
940 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
946 citems.push_back (SeparatorElem());
947 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
949 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
962 MixerStrip::input_release (GdkEventButton *ev)
964 switch (ev->button) {
967 edit_input_configuration ();
979 MixerStrip::input_press (GdkEventButton *ev)
981 using namespace Menu_Helpers;
983 MenuList& citems = input_menu.items();
984 input_menu.set_name ("ArdourContextMenu");
987 if (!_session->engine().connected()) {
988 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
993 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
996 switch (ev->button) {
999 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1003 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1005 citems.push_back (SeparatorElem());
1006 uint32_t const n_with_separator = citems.size ();
1008 input_menu_bundles.clear ();
1010 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1012 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1014 /* give user bundles first chance at being in the menu */
1016 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1017 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1018 maybe_add_bundle_to_input_menu (*i, current);
1022 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1023 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1024 maybe_add_bundle_to_input_menu (*i, current);
1028 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1029 RouteList copy = *routes;
1030 copy.sort (RouteCompareByName ());
1031 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1032 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1035 if (citems.size() == n_with_separator) {
1036 /* no routes added; remove the separator */
1040 citems.push_back (SeparatorElem());
1041 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1044 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1045 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1050 citems.push_back (SeparatorElem());
1051 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1053 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1065 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1067 if (ignore_toggle) {
1071 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1073 if (std::find (current.begin(), current.end(), c) == current.end()) {
1074 _route->input()->connect_ports_to_bundle (c, true, this);
1076 _route->input()->disconnect_ports_from_bundle (c, this);
1081 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1083 if (ignore_toggle) {
1087 ARDOUR::BundleList current = _route->output()->bundles_connected ();
1089 if (std::find (current.begin(), current.end(), c) == current.end()) {
1090 _route->output()->connect_ports_to_bundle (c, true, this);
1092 _route->output()->disconnect_ports_from_bundle (c, 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*/)
1123 using namespace Menu_Helpers;
1125 if (b->ports_are_inputs() == false || b->nchannels() != _route->n_outputs() || *b == *_route->input()->bundle()) {
1129 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1130 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1134 if (i != output_menu_bundles.end()) {
1138 output_menu_bundles.push_back (b);
1140 MenuList& citems = output_menu.items();
1141 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1145 MixerStrip::update_diskstream_display ()
1147 if (is_track() && input_selector) {
1148 input_selector->hide_all ();
1151 route_color_changed ();
1155 MixerStrip::connect_to_pan ()
1157 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1159 panstate_connection.disconnect ();
1160 panstyle_connection.disconnect ();
1162 if (!_route->panner()) {
1166 boost::shared_ptr<Pannable> p = _route->pannable ();
1168 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1170 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1171 * However, that only works a panner was previously set.
1173 * PannerUI must remain subscribed to _panshell->Changed() in case
1174 * we switch the panner eg. AUX-Send and back
1175 * _route->panner_shell()->Changed() vs _panshell->Changed
1177 if (panners._panner == 0) {
1178 panners.panshell_changed ();
1180 update_panner_choices();
1184 MixerStrip::update_panner_choices ()
1186 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1187 if (!_route->panner_shell()) { return; }
1189 uint32_t in = _route->output()->n_ports().n_audio();
1191 if (_route->panner()) {
1192 in = _route->panner()->in().n_audio();
1195 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1199 * Output port labelling
1200 * =====================
1202 * Case 1: Each output has one connection, all connections are to system:playback_%i
1203 * out 1 -> system:playback_1
1204 * out 2 -> system:playback_2
1205 * out 3 -> system:playback_3
1208 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1209 * out 1 -> ardour:track_x/in 1
1210 * out 2 -> ardour:track_x/in 2
1211 * Display as: track_x
1213 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1214 * out 1 -> program x:foo
1215 * out 2 -> program x:foo
1216 * Display as: program x
1218 * Case 4: No connections (Disconnected)
1221 * Default case (unusual routing):
1222 * Display as: *number of connections*
1226 * .-----------------------------------------------.
1228 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1229 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1230 * '-----------------------------------------------'
1231 * .-----------------------------------------------.
1234 * '-----------------------------------------------'
1238 MixerStrip::update_io_button (boost::shared_ptr<ARDOUR::Route> route, Width width, bool for_input)
1242 boost::shared_ptr<IO> io;
1243 boost::shared_ptr<Port> port;
1244 vector<string> port_connections;
1246 uint32_t total_connection_count = 0;
1247 uint32_t io_connection_count = 0;
1248 uint32_t ardour_connection_count = 0;
1249 uint32_t system_connection_count = 0;
1250 uint32_t other_connection_count = 0;
1251 uint32_t typed_connection_count = 0;
1253 ostringstream label;
1255 bool have_label = false;
1256 bool each_io_has_one_connection = true;
1258 string connection_name;
1259 string ardour_track_name;
1260 string other_connection_type;
1261 string system_ports;
1264 ostringstream tooltip;
1265 char * tooltip_cstr;
1267 /* To avoid confusion, the button caption only shows connections that match the expected datatype
1269 * First of all, if the user made only connections to a given type, we should use that one since
1270 * it is very probably what the user expects. If there are several connections types, then show
1271 * audio ones as primary, which matches expectations for both audio tracks with midi control and
1272 * synthesisers. This first heuristic can be expressed with these two rules:
1273 * A) If there are connected audio ports, consider audio as primary type.
1274 * B) Else, if there are connected midi ports, consider midi as primary type.
1276 * If there are no connected ports, then we choose the primary type based on the type of existing
1277 * but unconnected ports. Again:
1278 * C) If there are audio ports, consider audio as primary type.
1279 * D) Else, if there are midi ports, consider midi as primary type. */
1281 DataType dt = DataType::AUDIO;
1285 io = route->input();
1287 io = route->output();
1290 io_count = io->n_ports().n_total();
1291 for (io_index = 0; io_index < io_count; ++io_index) {
1292 port = io->nth (io_index);
1293 if (port->connected()) {
1295 if (port->type() == DataType::AUDIO) {
1296 /* Rule A) applies no matter the remaining ports */
1297 dt = DataType::AUDIO;
1300 if (port->type() == DataType::MIDI) {
1301 /* Rule B) is a good candidate... */
1302 dt = DataType::MIDI;
1303 /* ...but continue the loop to check remaining ports for rule A) */
1309 /* Neither rule A) nor rule B) matched */
1310 if ( io->n_ports().n_audio() > 0 ) {
1312 dt = DataType::AUDIO;
1313 } else if ( io->n_ports().n_midi() > 0 ) {
1315 dt = DataType::MIDI;
1319 if ( dt == DataType::MIDI ) {
1320 tooltip << _("MIDI ");
1324 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (route->name()));
1326 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (route->name()));
1329 for (io_index = 0; io_index < io_count; ++io_index) {
1330 port = io->nth (io_index);
1332 port_connections.clear ();
1333 port->get_connections(port_connections);
1335 //ignore any port connections that don't match our DataType
1336 if (port->type() != dt) {
1337 if (!port_connections.empty()) {
1338 ++typed_connection_count;
1343 io_connection_count = 0;
1345 if (!port_connections.empty()) {
1346 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1348 string& connection_name (*i);
1350 if (connection_name.find("system:") == 0) {
1351 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1354 if (io_connection_count == 0) {
1355 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1357 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1360 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1363 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1364 if (ardour_track_name.empty()) {
1365 // "ardour:Master/in 1" -> "ardour:Master/"
1366 string::size_type slash = connection_name.find("/");
1367 if (slash != string::npos) {
1368 ardour_track_name = connection_name.substr(0, slash + 1);
1372 if (connection_name.find(ardour_track_name) == 0) {
1373 ++ardour_connection_count;
1375 } else if (!pn.empty()) {
1376 if (system_ports.empty()) {
1379 system_ports += "/" + pn;
1381 if (connection_name.find("system:") == 0) {
1382 ++system_connection_count;
1384 } else if (connection_name.find("system:midi_") == 0) {
1386 // "system:midi_capture_123" -> "123"
1387 system_port = "M " + connection_name.substr(20);
1389 // "system:midi_playback_123" -> "123"
1390 system_port = "M " + connection_name.substr(21);
1393 if (system_ports.empty()) {
1394 system_ports += system_port;
1396 system_ports += "/" + system_port;
1399 ++system_connection_count;
1401 } else if (connection_name.find("system:") == 0) {
1403 // "system:capture_123" -> "123"
1404 system_port = connection_name.substr(15);
1406 // "system:playback_123" -> "123"
1407 system_port = connection_name.substr(16);
1410 if (system_ports.empty()) {
1411 system_ports += system_port;
1413 system_ports += "/" + system_port;
1416 ++system_connection_count;
1418 if (other_connection_type.empty()) {
1419 // "jamin:in 1" -> "jamin:"
1420 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1423 if (connection_name.find(other_connection_type) == 0) {
1424 ++other_connection_count;
1428 ++total_connection_count;
1429 ++io_connection_count;
1433 if (io_connection_count != 1) {
1434 each_io_has_one_connection = false;
1438 if (total_connection_count == 0) {
1439 tooltip << endl << _("Disconnected");
1442 tooltip_cstr = new char[tooltip.str().size() + 1];
1443 strcpy(tooltip_cstr, tooltip.str().c_str());
1446 set_tooltip (&input_button, tooltip_cstr);
1448 set_tooltip (&output_button, tooltip_cstr);
1451 delete [] tooltip_cstr;
1453 if (each_io_has_one_connection) {
1454 if (total_connection_count == ardour_connection_count) {
1455 // all connections are to the same track in ardour
1456 // "ardour:Master/" -> "Master"
1457 string::size_type slash = ardour_track_name.find("/");
1458 if (slash != string::npos) {
1459 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1460 label << ardour_track_name.substr (ppps, slash - ppps);
1464 else if (total_connection_count == system_connection_count) {
1465 // all connections are to system ports
1466 label << system_ports;
1469 else if (total_connection_count == other_connection_count) {
1470 // all connections are to the same external program eg jamin
1471 // "jamin:" -> "jamin"
1472 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1478 if (total_connection_count == 0) {
1482 // Odd configuration
1483 label << "*" << total_connection_count << "*";
1485 if (typed_connection_count > 0) {
1486 label << "\u2295"; // circled plus
1491 input_button.set_text (label.str());
1493 output_button.set_text (label.str());
1498 MixerStrip::update_input_display ()
1500 update_io_button (_route, _width, true);
1501 panners.setup_pan ();
1503 if (has_audio_outputs ()) {
1504 panners.show_all ();
1506 panners.hide_all ();
1512 MixerStrip::update_output_display ()
1514 update_io_button (_route, _width, false);
1515 gpm.setup_meters ();
1516 panners.setup_pan ();
1518 if (has_audio_outputs ()) {
1519 panners.show_all ();
1521 panners.hide_all ();
1526 MixerStrip::fast_update ()
1528 gpm.update_meters ();
1532 MixerStrip::diskstream_changed ()
1534 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1538 MixerStrip::io_changed_proxy ()
1540 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1541 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1545 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1547 boost::shared_ptr<Port> a = wa.lock ();
1548 boost::shared_ptr<Port> b = wb.lock ();
1550 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1551 update_input_display ();
1552 set_width_enum (_width, this);
1555 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1556 update_output_display ();
1557 set_width_enum (_width, this);
1562 MixerStrip::setup_comment_button ()
1564 std::string comment = _route->comment();
1566 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1568 if (comment.empty ()) {
1569 _comment_button.set_name ("generic button");
1570 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1574 _comment_button.set_name ("comment button");
1576 string::size_type pos = comment.find_first_of (" \t\n");
1577 if (pos != string::npos) {
1578 comment = comment.substr (0, pos);
1580 if (comment.empty()) {
1581 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1583 _comment_button.set_text (comment);
1588 MixerStrip::select_route_group (GdkEventButton *ev)
1590 using namespace Menu_Helpers;
1592 if (ev->button == 1) {
1594 if (group_menu == 0) {
1596 PropertyList* plist = new PropertyList();
1598 plist->add (Properties::group_gain, true);
1599 plist->add (Properties::group_mute, true);
1600 plist->add (Properties::group_solo, true);
1602 group_menu = new RouteGroupMenu (_session, plist);
1606 r.push_back (route ());
1607 group_menu->build (r);
1609 RouteGroup *rg = _route->route_group();
1611 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1612 rg ? rg->name() : _("No Group"),
1620 MixerStrip::route_group_changed ()
1622 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1624 RouteGroup *rg = _route->route_group();
1627 group_button.set_text (PBD::short_version (rg->name(), 5));
1631 group_button.set_text (_("Grp"));
1634 group_button.set_text (_("~G"));
1641 MixerStrip::route_color_changed ()
1643 using namespace ARDOUR_UI_UTILS;
1644 name_button.modify_bg (STATE_NORMAL, color());
1645 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1646 reset_strip_style ();
1650 MixerStrip::show_passthru_color ()
1652 reset_strip_style ();
1657 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1659 boost::shared_ptr<Processor> processor (p.lock ());
1660 if (!processor || !processor->display_to_user()) {
1663 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1665 if (pi && pi->is_channelstrip ()) {
1670 ++_plugin_insert_cnt;
1674 MixerStrip::build_route_ops_menu ()
1676 using namespace Menu_Helpers;
1677 route_ops_menu = new Menu;
1678 route_ops_menu->set_name ("ArdourContextMenu");
1680 MenuList& items = route_ops_menu->items();
1682 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1684 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1686 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1688 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1690 if (!Profile->get_mixbus()) {
1691 items.push_back (SeparatorElem());
1694 if (!_route->is_master()
1696 && !_route->mixbus()
1699 if (Profile->get_mixbus()) {
1700 items.push_back (SeparatorElem());
1702 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1705 if (!Profile->get_mixbus()) {
1706 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1707 /* do not allow rename if the track is record-enabled */
1708 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1711 items.push_back (SeparatorElem());
1712 items.push_back (CheckMenuElem (_("Active")));
1713 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1714 i->set_active (_route->active());
1715 i->set_sensitive(! _session->transport_rolling());
1716 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1718 if (!Profile->get_mixbus ()) {
1719 items.push_back (SeparatorElem());
1720 items.push_back (CheckMenuElem (_("Strict I/O")));
1721 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1722 i->set_active (_route->strict_io());
1723 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1726 _plugin_insert_cnt = 0;
1727 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1728 if (_plugin_insert_cnt > 0) {
1729 items.push_back (SeparatorElem());
1730 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1733 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1734 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1735 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1736 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1739 items.push_back (SeparatorElem());
1740 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1742 items.push_back (SeparatorElem());
1743 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1744 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1745 denormal_menu_item->set_active (_route->denormal_protection());
1748 /* note that this relies on selection being shared across editor and
1749 mixer (or global to the backend, in the future), which is the only
1750 sane thing for users anyway.
1753 RouteTimeAxisView* rtav = PublicEditor::instance().get_route_view_by_route_id (_route->id());
1755 Selection& selection (PublicEditor::instance().get_selection());
1756 if (!selection.selected (rtav)) {
1757 selection.set (rtav);
1760 if (!_route->is_master()) {
1761 items.push_back (SeparatorElem());
1762 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1765 items.push_back (SeparatorElem());
1766 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1772 MixerStrip::name_button_button_press (GdkEventButton* ev)
1774 if (ev->button == 1 || ev->button == 3) {
1775 list_route_operations ();
1777 if (ev->button == 1) {
1778 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1781 route_ops_menu->popup (3, ev->time);
1791 MixerStrip::number_button_button_press (GdkEventButton* ev)
1793 if ( ev->button == 3 ) {
1794 list_route_operations ();
1796 route_ops_menu->popup (1, ev->time);
1805 MixerStrip::list_route_operations ()
1807 delete route_ops_menu;
1808 build_route_ops_menu ();
1812 MixerStrip::set_selected (bool yn)
1814 AxisView::set_selected (yn);
1817 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1818 global_frame.set_name ("MixerStripSelectedFrame");
1820 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1821 global_frame.set_name ("MixerStripFrame");
1824 global_frame.queue_draw ();
1827 // processor_box.deselect_all_processors();
1831 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1833 if (what_changed.contains (ARDOUR::Properties::name)) {
1839 MixerStrip::name_changed ()
1843 name_button.set_text (_route->name());
1846 name_button.set_text (PBD::short_version (_route->name(), 5));
1850 set_tooltip (name_button, _route->name());
1852 if (_session->config.get_track_name_number()) {
1853 const int64_t track_number = _route->track_number ();
1854 if (track_number == 0) {
1855 number_label.set_text ("-");
1857 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1860 number_label.set_text ("");
1865 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1867 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1871 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1873 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1877 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1879 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1883 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1885 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1889 MixerStrip::width_button_pressed (GdkEventButton* ev)
1891 if (ev->button != 1) {
1895 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1898 _mixer.set_strip_width (Narrow, true);
1902 _mixer.set_strip_width (Wide, true);
1908 set_width_enum (Narrow, this);
1911 set_width_enum (Wide, this);
1920 MixerStrip::hide_clicked ()
1922 // LAME fix to reset the button status for when it is redisplayed (part 1)
1923 hide_button.set_sensitive(false);
1926 Hiding(); /* EMIT_SIGNAL */
1928 _mixer.hide_strip (this);
1932 hide_button.set_sensitive(true);
1936 MixerStrip::set_embedded (bool yn)
1942 MixerStrip::map_frozen ()
1944 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1946 boost::shared_ptr<AudioTrack> at = audio_track();
1949 switch (at->freeze_state()) {
1950 case AudioTrack::Frozen:
1951 processor_box.set_sensitive (false);
1952 hide_redirect_editors ();
1955 processor_box.set_sensitive (true);
1956 // XXX need some way, maybe, to retoggle redirect editors
1960 processor_box.set_sensitive (true);
1962 RouteUI::map_frozen ();
1966 MixerStrip::hide_redirect_editors ()
1968 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1972 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1974 boost::shared_ptr<Processor> processor (p.lock ());
1979 Gtk::Window* w = processor_box.get_processor_ui (processor);
1987 MixerStrip::reset_strip_style ()
1989 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1991 gpm.set_fader_name ("SendStripBase");
1995 if (is_midi_track()) {
1996 if (_route->active()) {
1997 set_name ("MidiTrackStripBase");
1999 set_name ("MidiTrackStripBaseInactive");
2001 gpm.set_fader_name ("MidiTrackFader");
2002 } else if (is_audio_track()) {
2003 if (_route->active()) {
2004 set_name ("AudioTrackStripBase");
2006 set_name ("AudioTrackStripBaseInactive");
2008 gpm.set_fader_name ("AudioTrackFader");
2010 if (_route->active()) {
2011 set_name ("AudioBusStripBase");
2013 set_name ("AudioBusStripBaseInactive");
2015 gpm.set_fader_name ("AudioBusFader");
2017 /* (no MIDI busses yet) */
2024 MixerStrip::engine_stopped ()
2029 MixerStrip::engine_running ()
2034 MixerStrip::meter_point_string (MeterPoint mp)
2047 case MeterPostFader:
2064 return S_("Meter|In");
2068 return S_("Meter|Pr");
2071 case MeterPostFader:
2072 return S_("Meter|Po");
2076 return S_("Meter|O");
2081 return S_("Meter|C");
2090 /** Called when the monitor-section state */
2092 MixerStrip::monitor_changed ()
2094 assert (monitor_section_button);
2095 if (_session->monitor_active()) {
2096 monitor_section_button->set_name ("master monitor section button active");
2098 monitor_section_button->set_name ("master monitor section button normal");
2102 /** Called when the metering point has changed */
2104 MixerStrip::meter_changed ()
2106 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2107 gpm.setup_meters ();
2108 // reset peak when meter point changes
2109 gpm.reset_peak_display();
2112 /** The bus that we are displaying sends to has changed, or been turned off.
2113 * @param send_to New bus that we are displaying sends to, or 0.
2116 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2118 RouteUI::bus_send_display_changed (send_to);
2121 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2126 revert_to_default_display ();
2129 revert_to_default_display ();
2134 MixerStrip::drop_send ()
2136 boost::shared_ptr<Send> current_send;
2138 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2139 current_send->set_metering (false);
2142 send_gone_connection.disconnect ();
2143 input_button.set_sensitive (true);
2144 output_button.set_sensitive (true);
2145 group_button.set_sensitive (true);
2146 set_invert_sensitive (true);
2147 gpm.meter_point_button.set_sensitive (true);
2148 mute_button->set_sensitive (true);
2149 solo_button->set_sensitive (true);
2150 solo_isolated_led->set_sensitive (true);
2151 solo_safe_led->set_sensitive (true);
2152 monitor_input_button->set_sensitive (true);
2153 monitor_disk_button->set_sensitive (true);
2154 _comment_button.set_sensitive (true);
2155 RouteUI::check_rec_enable_sensitivity ();
2156 set_button_names (); // update solo button visual state
2160 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2162 _current_delivery = d;
2163 DeliveryChanged (_current_delivery);
2167 MixerStrip::show_send (boost::shared_ptr<Send> send)
2173 set_current_delivery (send);
2175 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2176 send->set_metering (true);
2177 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2179 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2180 gain_meter().setup_meters ();
2182 uint32_t const in = _current_delivery->pans_required();
2183 uint32_t const out = _current_delivery->pan_outs();
2185 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2186 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2187 panner_ui().setup_pan ();
2188 panner_ui().set_send_drawing_mode (true);
2189 panner_ui().show_all ();
2191 input_button.set_sensitive (false);
2192 group_button.set_sensitive (false);
2193 set_invert_sensitive (false);
2194 gpm.meter_point_button.set_sensitive (false);
2195 mute_button->set_sensitive (false);
2196 solo_button->set_sensitive (false);
2197 rec_enable_button->set_sensitive (false);
2198 solo_isolated_led->set_sensitive (false);
2199 solo_safe_led->set_sensitive (false);
2200 monitor_input_button->set_sensitive (false);
2201 monitor_disk_button->set_sensitive (false);
2202 _comment_button.set_sensitive (false);
2204 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2205 output_button.set_sensitive (false);
2208 reset_strip_style ();
2212 MixerStrip::revert_to_default_display ()
2216 set_current_delivery (_route->main_outs ());
2218 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2219 gain_meter().setup_meters ();
2221 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2222 update_panner_choices();
2223 panner_ui().setup_pan ();
2224 panner_ui().set_send_drawing_mode (false);
2226 if (has_audio_outputs ()) {
2227 panners.show_all ();
2229 panners.hide_all ();
2232 reset_strip_style ();
2236 MixerStrip::set_button_names ()
2240 mute_button->set_text (_("Mute"));
2241 monitor_input_button->set_text (_("In"));
2242 monitor_disk_button->set_text (_("Disk"));
2243 if (monitor_section_button) {
2244 monitor_section_button->set_text (_("Mon"));
2247 if (_route && _route->solo_safe_control()->solo_safe()) {
2248 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2250 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2252 if (!Config->get_solo_control_is_listen_control()) {
2253 solo_button->set_text (_("Solo"));
2255 switch (Config->get_listen_position()) {
2256 case AfterFaderListen:
2257 solo_button->set_text (_("AFL"));
2259 case PreFaderListen:
2260 solo_button->set_text (_("PFL"));
2264 solo_isolated_led->set_text (_("Iso"));
2265 solo_safe_led->set_text (S_("SoloLock|Lock"));
2269 mute_button->set_text (S_("Mute|M"));
2270 monitor_input_button->set_text (S_("MonitorInput|I"));
2271 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2272 if (monitor_section_button) {
2273 monitor_section_button->set_text (S_("Mon|O"));
2276 if (_route && _route->solo_safe_control()->solo_safe()) {
2277 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2279 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2281 if (!Config->get_solo_control_is_listen_control()) {
2282 solo_button->set_text (S_("Solo|S"));
2284 switch (Config->get_listen_position()) {
2285 case AfterFaderListen:
2286 solo_button->set_text (S_("AfterFader|A"));
2288 case PreFaderListen:
2289 solo_button->set_text (S_("Prefader|P"));
2294 solo_isolated_led->set_text (S_("SoloIso|I"));
2295 solo_safe_led->set_text (S_("SoloLock|L"));
2300 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2302 gpm.meter_point_button.set_text ("");
2307 MixerStrip::plugin_selector()
2309 return _mixer.plugin_selector();
2313 MixerStrip::hide_things ()
2315 processor_box.hide_things ();
2319 MixerStrip::input_active_button_press (GdkEventButton*)
2321 /* nothing happens on press */
2326 MixerStrip::input_active_button_release (GdkEventButton* ev)
2328 boost::shared_ptr<MidiTrack> mt = midi_track ();
2334 boost::shared_ptr<RouteList> rl (new RouteList);
2336 rl->push_back (route());
2338 _session->set_exclusive_input_active (rl, !mt->input_active(),
2339 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2345 MixerStrip::midi_input_status_changed ()
2347 if (midi_input_enable_button) {
2348 boost::shared_ptr<MidiTrack> mt = midi_track ();
2350 midi_input_enable_button->set_active (mt->input_active ());
2355 MixerStrip::state_id () const
2357 return string_compose ("strip %1", _route->id().to_s());
2361 MixerStrip::parameter_changed (string p)
2363 if (p == _visibility.get_state_name()) {
2364 /* The user has made changes to the mixer strip visibility, so get
2365 our VisibilityGroup to reflect these changes in our widgets.
2367 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2368 } else if (p == "track-name-number") {
2370 } else if (p == "use-monitor-bus") {
2371 if (monitor_section_button) {
2372 if (mute_button->get_parent()) {
2373 mute_button->get_parent()->remove(*mute_button);
2375 if (monitor_section_button->get_parent()) {
2376 monitor_section_button->get_parent()->remove(*monitor_section_button);
2378 if (Config->get_use_monitor_bus ()) {
2379 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2380 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2381 mute_button->show();
2382 monitor_section_button->show();
2384 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2385 mute_button->show();
2388 } else if (p == "track-name-number") {
2389 update_track_number_visibility();
2393 /** Called to decide whether the solo isolate / solo lock button visibility should
2394 * be overridden from that configured by the user. We do this for the master bus.
2396 * @return optional value that is present if visibility state should be overridden.
2398 boost::optional<bool>
2399 MixerStrip::override_solo_visibility () const
2401 if (_route && _route->is_master ()) {
2402 return boost::optional<bool> (false);
2405 return boost::optional<bool> ();
2409 MixerStrip::add_input_port (DataType t)
2411 _route->input()->add_port ("", this, t);
2415 MixerStrip::add_output_port (DataType t)
2417 _route->output()->add_port ("", this, t);
2421 MixerStrip::route_active_changed ()
2423 reset_strip_style ();
2427 MixerStrip::copy_processors ()
2429 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2433 MixerStrip::cut_processors ()
2435 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2439 MixerStrip::paste_processors ()
2441 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2445 MixerStrip::select_all_processors ()
2447 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2451 MixerStrip::deselect_all_processors ()
2453 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2457 MixerStrip::delete_processors ()
2459 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2463 MixerStrip::toggle_processors ()
2465 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2469 MixerStrip::ab_plugins ()
2471 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2475 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2477 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2480 if (ev->button == 3) {
2481 popup_level_meter_menu (ev);
2489 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2491 using namespace Gtk::Menu_Helpers;
2493 Gtk::Menu* m = manage (new Menu);
2494 MenuList& items = m->items ();
2496 RadioMenuItem::Group group;
2498 _suspend_menu_callbacks = true;
2499 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2500 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2501 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2502 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2503 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2505 if (gpm.meter_channels().n_audio() == 0) {
2506 m->popup (ev->button, ev->time);
2507 _suspend_menu_callbacks = false;
2511 RadioMenuItem::Group tgroup;
2512 items.push_back (SeparatorElem());
2514 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2515 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2516 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2517 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2518 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2519 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2520 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2521 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2522 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2523 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2524 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2527 if (_route->is_master()) {
2530 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2531 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2532 /* non-master bus */
2535 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2542 MeterType cmt = _route->meter_type();
2543 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2545 items.push_back (SeparatorElem());
2546 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2547 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2548 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2549 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2550 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2551 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2553 m->popup (ev->button, ev->time);
2554 _suspend_menu_callbacks = false;
2558 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2559 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2561 using namespace Menu_Helpers;
2563 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2564 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2565 i->set_active (_route->meter_point() == point);
2569 MixerStrip::set_meter_point (MeterPoint p)
2571 if (_suspend_menu_callbacks) return;
2572 _route->set_meter_point (p);
2576 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2577 RadioMenuItem::Group& group, string const & name, MeterType type)
2579 using namespace Menu_Helpers;
2581 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2582 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2583 i->set_active (_route->meter_type() == type);
2587 MixerStrip::set_meter_type (MeterType t)
2589 if (_suspend_menu_callbacks) return;
2594 MixerStrip::update_track_number_visibility ()
2596 DisplaySuspender ds;
2597 bool show_label = _session->config.get_track_name_number();
2599 if (_route && _route->is_master()) {
2604 number_label.show ();
2605 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2606 // except the width of the number label is subtracted from the name-hbox, so we
2607 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2608 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2610 number_label.set_size_request(tnw, -1);
2611 number_label.show ();
2613 number_label.hide ();
2618 MixerStrip::color () const
2620 return route_color ();
2624 MixerStrip::marked_for_display () const
2626 return !_route->presentation_info().hidden();
2630 MixerStrip::set_marked_for_display (bool yn)
2632 return RouteUI::mark_hidden (!yn);