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*/,
1124 using namespace Menu_Helpers;
1126 /* The bundle should be an input one, but not ours */
1127 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1131 /* Don't add the monitor input unless we are Master */
1132 boost::shared_ptr<Route> monitor = _session->monitor_out();
1133 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1136 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1137 * or have the same number of |type| channels than our outputs. */
1138 if (type == DataType::NIL) {
1139 if(b->nchannels() != _route->n_outputs())
1142 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1146 /* Avoid adding duplicates */
1147 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1148 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1151 if (i != output_menu_bundles.end()) {
1155 /* Now add the bundle to the menu */
1156 output_menu_bundles.push_back (b);
1158 MenuList& citems = output_menu.items();
1159 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1163 MixerStrip::update_diskstream_display ()
1165 if (is_track() && input_selector) {
1166 input_selector->hide_all ();
1169 route_color_changed ();
1173 MixerStrip::connect_to_pan ()
1175 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1177 panstate_connection.disconnect ();
1178 panstyle_connection.disconnect ();
1180 if (!_route->panner()) {
1184 boost::shared_ptr<Pannable> p = _route->pannable ();
1186 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1188 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1189 * However, that only works a panner was previously set.
1191 * PannerUI must remain subscribed to _panshell->Changed() in case
1192 * we switch the panner eg. AUX-Send and back
1193 * _route->panner_shell()->Changed() vs _panshell->Changed
1195 if (panners._panner == 0) {
1196 panners.panshell_changed ();
1198 update_panner_choices();
1202 MixerStrip::update_panner_choices ()
1204 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1205 if (!_route->panner_shell()) { return; }
1207 uint32_t in = _route->output()->n_ports().n_audio();
1209 if (_route->panner()) {
1210 in = _route->panner()->in().n_audio();
1213 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1217 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1219 /* The heuristic follows these principles:
1220 * A) If all ports that the user connected are of the same type, then he
1221 * very probably intends to use the IO with that type. A common subcase
1222 * is when the IO has only ports of the same type (connected or not).
1223 * B) If several types of ports are connected, then we should guess based
1224 * on the likeliness of the user wanting to use a given type.
1225 * We assume that the DataTypes are ordered from the most likely to the
1226 * least likely when iterating or comparing them with "<".
1227 * C) If no port is connected, the same logic can be applied with all ports
1228 * instead of connected ones. TODO: Try other ideas, for instance look at
1229 * the last plugin output when |for_input| is false (note: when StrictIO
1230 * the outs of the last plugin should be the same as the outs of the route
1231 * modulo the panner which forwards non-audio anyway).
1232 * All of these constraints are respected by the following algorithm that
1233 * just returns the most likely datatype found in connected ports if any, or
1234 * available ports if any (since if all ports are of the same type, the most
1235 * likely found will be that one obviously). */
1237 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1239 /* Find most likely type among connected ports */
1240 if (favor_connected) {
1241 DataType type = DataType::NIL; /* NIL is always last so least likely */
1242 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1243 if (p->connected() && p->type() < type)
1246 if (type != DataType::NIL) {
1247 /* There has been a connected port (necessarily non-NIL) */
1252 /* Find most likely type among available ports.
1253 * The iterator stops before NIL. */
1254 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1255 if (io->n_ports().n(*t) > 0)
1259 /* No port at all, return the most likely datatype by default */
1260 return DataType::front();
1264 * Output port labelling
1265 * =====================
1267 * Case 1: Each output has one connection, all connections are to system:playback_%i
1268 * out 1 -> system:playback_1
1269 * out 2 -> system:playback_2
1270 * out 3 -> system:playback_3
1273 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1274 * out 1 -> ardour:track_x/in 1
1275 * out 2 -> ardour:track_x/in 2
1276 * Display as: track_x
1278 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1279 * out 1 -> program x:foo
1280 * out 2 -> program x:foo
1281 * Display as: program x
1283 * Case 4: No connections (Disconnected)
1286 * Default case (unusual routing):
1287 * Display as: *number of connections*
1291 * .-----------------------------------------------.
1293 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1294 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1295 * '-----------------------------------------------'
1296 * .-----------------------------------------------.
1299 * '-----------------------------------------------'
1303 MixerStrip::update_io_button (bool for_input)
1305 vector<string> port_connections;
1307 uint32_t total_connection_count = 0;
1308 uint32_t io_connection_count = 0;
1309 uint32_t ardour_connection_count = 0;
1310 uint32_t system_connection_count = 0;
1311 uint32_t other_connection_count = 0;
1312 uint32_t typed_connection_count = 0;
1314 ostringstream label;
1316 bool have_label = false;
1317 bool each_io_has_one_connection = true;
1319 string connection_name;
1320 string ardour_track_name;
1321 string other_connection_type;
1322 string system_ports;
1325 ostringstream tooltip;
1326 char * tooltip_cstr;
1328 DataType dt = guess_main_type(for_input);
1330 if ( dt == DataType::MIDI ) {
1331 tooltip << _("MIDI ");
1335 tooltip << string_compose (_("<b>INPUT</b> to %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1337 tooltip << string_compose (_("<b>OUTPUT</b> from %1"), Gtkmm2ext::markup_escape_text (_route->name()));
1340 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1341 for (PortSet::iterator port = io->ports().begin(); port != io->ports().end(); ++port) {
1342 port_connections.clear ();
1343 port->get_connections(port_connections);
1345 //ignore any port connections that don't match our DataType
1346 if (port->type() != dt) {
1347 if (!port_connections.empty()) {
1348 ++typed_connection_count;
1353 io_connection_count = 0;
1355 if (!port_connections.empty()) {
1356 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
1358 string& connection_name (*i);
1360 if (connection_name.find("system:") == 0) {
1361 pn = AudioEngine::instance()->get_pretty_name_by_name (connection_name);
1364 if (io_connection_count == 0) {
1365 tooltip << endl << Gtkmm2ext::markup_escape_text (port->name().substr(port->name().find("/") + 1))
1367 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1370 << Gtkmm2ext::markup_escape_text ( pn.empty() ? connection_name : pn );
1373 if (connection_name.find(RouteUI::program_port_prefix) == 0) {
1374 if (ardour_track_name.empty()) {
1375 // "ardour:Master/in 1" -> "ardour:Master/"
1376 string::size_type slash = connection_name.find("/");
1377 if (slash != string::npos) {
1378 ardour_track_name = connection_name.substr(0, slash + 1);
1382 if (connection_name.find(ardour_track_name) == 0) {
1383 ++ardour_connection_count;
1385 } else if (!pn.empty()) {
1386 if (system_ports.empty()) {
1389 system_ports += "/" + pn;
1391 if (connection_name.find("system:") == 0) {
1392 ++system_connection_count;
1394 } else if (connection_name.find("system:midi_") == 0) {
1396 // "system:midi_capture_123" -> "123"
1397 system_port = "M " + connection_name.substr(20);
1399 // "system:midi_playback_123" -> "123"
1400 system_port = "M " + connection_name.substr(21);
1403 if (system_ports.empty()) {
1404 system_ports += system_port;
1406 system_ports += "/" + system_port;
1409 ++system_connection_count;
1411 } else if (connection_name.find("system:") == 0) {
1413 // "system:capture_123" -> "123"
1414 system_port = connection_name.substr(15);
1416 // "system:playback_123" -> "123"
1417 system_port = connection_name.substr(16);
1420 if (system_ports.empty()) {
1421 system_ports += system_port;
1423 system_ports += "/" + system_port;
1426 ++system_connection_count;
1428 if (other_connection_type.empty()) {
1429 // "jamin:in 1" -> "jamin:"
1430 other_connection_type = connection_name.substr(0, connection_name.find(":") + 1);
1433 if (connection_name.find(other_connection_type) == 0) {
1434 ++other_connection_count;
1438 ++total_connection_count;
1439 ++io_connection_count;
1443 if (io_connection_count != 1) {
1444 each_io_has_one_connection = false;
1448 if (total_connection_count == 0) {
1449 tooltip << endl << _("Disconnected");
1452 tooltip_cstr = new char[tooltip.str().size() + 1];
1453 strcpy(tooltip_cstr, tooltip.str().c_str());
1456 set_tooltip (&input_button, tooltip_cstr);
1458 set_tooltip (&output_button, tooltip_cstr);
1461 delete [] tooltip_cstr;
1463 if (each_io_has_one_connection) {
1464 if (total_connection_count == ardour_connection_count) {
1465 // all connections are to the same track in ardour
1466 // "ardour:Master/" -> "Master"
1467 string::size_type slash = ardour_track_name.find("/");
1468 if (slash != string::npos) {
1469 const size_t ppps = RouteUI::program_port_prefix.size (); // "ardour:"
1470 label << ardour_track_name.substr (ppps, slash - ppps);
1474 else if (total_connection_count == system_connection_count) {
1475 // all connections are to system ports
1476 label << system_ports;
1479 else if (total_connection_count == other_connection_count) {
1480 // all connections are to the same external program eg jamin
1481 // "jamin:" -> "jamin"
1482 label << other_connection_type.substr(0, other_connection_type.size() - 1);
1488 if (total_connection_count == 0) {
1492 // Odd configuration
1493 label << "*" << total_connection_count << "*";
1495 if (typed_connection_count > 0) {
1496 label << "\u2295"; // circled plus
1501 input_button.set_text (label.str());
1503 output_button.set_text (label.str());
1508 MixerStrip::update_input_display ()
1510 update_io_button (true);
1511 panners.setup_pan ();
1513 if (has_audio_outputs ()) {
1514 panners.show_all ();
1516 panners.hide_all ();
1522 MixerStrip::update_output_display ()
1524 update_io_button (false);
1525 gpm.setup_meters ();
1526 panners.setup_pan ();
1528 if (has_audio_outputs ()) {
1529 panners.show_all ();
1531 panners.hide_all ();
1536 MixerStrip::fast_update ()
1538 gpm.update_meters ();
1542 MixerStrip::diskstream_changed ()
1544 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1548 MixerStrip::io_changed_proxy ()
1550 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1551 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1555 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1557 boost::shared_ptr<Port> a = wa.lock ();
1558 boost::shared_ptr<Port> b = wb.lock ();
1560 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1561 update_input_display ();
1562 set_width_enum (_width, this);
1565 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1566 update_output_display ();
1567 set_width_enum (_width, this);
1572 MixerStrip::setup_comment_button ()
1574 std::string comment = _route->comment();
1576 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1578 if (comment.empty ()) {
1579 _comment_button.set_name ("generic button");
1580 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1584 _comment_button.set_name ("comment button");
1586 string::size_type pos = comment.find_first_of (" \t\n");
1587 if (pos != string::npos) {
1588 comment = comment.substr (0, pos);
1590 if (comment.empty()) {
1591 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1593 _comment_button.set_text (comment);
1598 MixerStrip::select_route_group (GdkEventButton *ev)
1600 using namespace Menu_Helpers;
1602 if (ev->button == 1) {
1604 if (group_menu == 0) {
1606 PropertyList* plist = new PropertyList();
1608 plist->add (Properties::group_gain, true);
1609 plist->add (Properties::group_mute, true);
1610 plist->add (Properties::group_solo, true);
1612 group_menu = new RouteGroupMenu (_session, plist);
1616 r.push_back (route ());
1617 group_menu->build (r);
1619 RouteGroup *rg = _route->route_group();
1621 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1622 rg ? rg->name() : _("No Group"),
1630 MixerStrip::route_group_changed ()
1632 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1634 RouteGroup *rg = _route->route_group();
1637 group_button.set_text (PBD::short_version (rg->name(), 5));
1641 group_button.set_text (_("Grp"));
1644 group_button.set_text (_("~G"));
1651 MixerStrip::route_color_changed ()
1653 using namespace ARDOUR_UI_UTILS;
1654 name_button.modify_bg (STATE_NORMAL, color());
1655 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1656 reset_strip_style ();
1660 MixerStrip::show_passthru_color ()
1662 reset_strip_style ();
1667 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1669 boost::shared_ptr<Processor> processor (p.lock ());
1670 if (!processor || !processor->display_to_user()) {
1673 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1675 if (pi && pi->is_channelstrip ()) {
1680 ++_plugin_insert_cnt;
1684 MixerStrip::build_route_ops_menu ()
1686 using namespace Menu_Helpers;
1687 route_ops_menu = new Menu;
1688 route_ops_menu->set_name ("ArdourContextMenu");
1690 MenuList& items = route_ops_menu->items();
1692 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1694 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1696 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1698 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1700 if (!Profile->get_mixbus()) {
1701 items.push_back (SeparatorElem());
1704 if (!_route->is_master()
1706 && !_route->mixbus()
1709 if (Profile->get_mixbus()) {
1710 items.push_back (SeparatorElem());
1712 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1715 if (!Profile->get_mixbus()) {
1716 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1717 /* do not allow rename if the track is record-enabled */
1718 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1721 items.push_back (SeparatorElem());
1722 items.push_back (CheckMenuElem (_("Active")));
1723 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1724 i->set_active (_route->active());
1725 i->set_sensitive(! _session->transport_rolling());
1726 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1728 if (!Profile->get_mixbus ()) {
1729 items.push_back (SeparatorElem());
1730 items.push_back (CheckMenuElem (_("Strict I/O")));
1731 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1732 i->set_active (_route->strict_io());
1733 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1736 _plugin_insert_cnt = 0;
1737 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1738 if (_plugin_insert_cnt > 0) {
1739 items.push_back (SeparatorElem());
1740 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1743 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1744 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1745 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1746 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1749 items.push_back (SeparatorElem());
1750 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1752 items.push_back (SeparatorElem());
1753 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1754 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1755 denormal_menu_item->set_active (_route->denormal_protection());
1758 /* note that this relies on selection being shared across editor and
1759 mixer (or global to the backend, in the future), which is the only
1760 sane thing for users anyway.
1763 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1765 Selection& selection (PublicEditor::instance().get_selection());
1766 if (!selection.selected (stav)) {
1767 selection.set (stav);
1770 if (!_route->is_master()) {
1771 items.push_back (SeparatorElem());
1772 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1775 items.push_back (SeparatorElem());
1776 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1782 MixerStrip::name_button_button_press (GdkEventButton* ev)
1784 if (ev->button == 1 || ev->button == 3) {
1785 list_route_operations ();
1787 if (ev->button == 1) {
1788 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1791 route_ops_menu->popup (3, ev->time);
1801 MixerStrip::number_button_button_press (GdkEventButton* ev)
1803 if ( ev->button == 3 ) {
1804 list_route_operations ();
1806 route_ops_menu->popup (1, ev->time);
1815 MixerStrip::list_route_operations ()
1817 delete route_ops_menu;
1818 build_route_ops_menu ();
1822 MixerStrip::set_selected (bool yn)
1824 AxisView::set_selected (yn);
1827 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1828 global_frame.set_name ("MixerStripSelectedFrame");
1830 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1831 global_frame.set_name ("MixerStripFrame");
1834 global_frame.queue_draw ();
1837 // processor_box.deselect_all_processors();
1841 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1843 if (what_changed.contains (ARDOUR::Properties::name)) {
1849 MixerStrip::name_changed ()
1853 name_button.set_text (_route->name());
1856 name_button.set_text (PBD::short_version (_route->name(), 5));
1860 set_tooltip (name_button, _route->name());
1862 if (_session->config.get_track_name_number()) {
1863 const int64_t track_number = _route->track_number ();
1864 if (track_number == 0) {
1865 number_label.set_text ("-");
1867 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1870 number_label.set_text ("");
1875 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1877 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1881 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1883 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1887 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1889 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1893 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1895 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1899 MixerStrip::width_button_pressed (GdkEventButton* ev)
1901 if (ev->button != 1) {
1905 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1908 _mixer.set_strip_width (Narrow, true);
1912 _mixer.set_strip_width (Wide, true);
1918 set_width_enum (Narrow, this);
1921 set_width_enum (Wide, this);
1930 MixerStrip::hide_clicked ()
1932 // LAME fix to reset the button status for when it is redisplayed (part 1)
1933 hide_button.set_sensitive(false);
1936 Hiding(); /* EMIT_SIGNAL */
1938 _mixer.hide_strip (this);
1942 hide_button.set_sensitive(true);
1946 MixerStrip::set_embedded (bool yn)
1952 MixerStrip::map_frozen ()
1954 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1956 boost::shared_ptr<AudioTrack> at = audio_track();
1959 switch (at->freeze_state()) {
1960 case AudioTrack::Frozen:
1961 processor_box.set_sensitive (false);
1962 hide_redirect_editors ();
1965 processor_box.set_sensitive (true);
1966 // XXX need some way, maybe, to retoggle redirect editors
1970 processor_box.set_sensitive (true);
1972 RouteUI::map_frozen ();
1976 MixerStrip::hide_redirect_editors ()
1978 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1982 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1984 boost::shared_ptr<Processor> processor (p.lock ());
1989 Gtk::Window* w = processor_box.get_processor_ui (processor);
1997 MixerStrip::reset_strip_style ()
1999 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2001 gpm.set_fader_name ("SendStripBase");
2005 if (is_midi_track()) {
2006 if (_route->active()) {
2007 set_name ("MidiTrackStripBase");
2009 set_name ("MidiTrackStripBaseInactive");
2011 gpm.set_fader_name ("MidiTrackFader");
2012 } else if (is_audio_track()) {
2013 if (_route->active()) {
2014 set_name ("AudioTrackStripBase");
2016 set_name ("AudioTrackStripBaseInactive");
2018 gpm.set_fader_name ("AudioTrackFader");
2020 if (_route->active()) {
2021 set_name ("AudioBusStripBase");
2023 set_name ("AudioBusStripBaseInactive");
2025 gpm.set_fader_name ("AudioBusFader");
2027 /* (no MIDI busses yet) */
2034 MixerStrip::engine_stopped ()
2039 MixerStrip::engine_running ()
2044 MixerStrip::meter_point_string (MeterPoint mp)
2057 case MeterPostFader:
2074 return S_("Meter|In");
2078 return S_("Meter|Pr");
2081 case MeterPostFader:
2082 return S_("Meter|Po");
2086 return S_("Meter|O");
2091 return S_("Meter|C");
2100 /** Called when the monitor-section state */
2102 MixerStrip::monitor_changed ()
2104 assert (monitor_section_button);
2105 if (_session->monitor_active()) {
2106 monitor_section_button->set_name ("master monitor section button active");
2108 monitor_section_button->set_name ("master monitor section button normal");
2112 /** Called when the metering point has changed */
2114 MixerStrip::meter_changed ()
2116 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2117 gpm.setup_meters ();
2118 // reset peak when meter point changes
2119 gpm.reset_peak_display();
2122 /** The bus that we are displaying sends to has changed, or been turned off.
2123 * @param send_to New bus that we are displaying sends to, or 0.
2126 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2128 RouteUI::bus_send_display_changed (send_to);
2131 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2136 revert_to_default_display ();
2139 revert_to_default_display ();
2144 MixerStrip::drop_send ()
2146 boost::shared_ptr<Send> current_send;
2148 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2149 current_send->set_metering (false);
2152 send_gone_connection.disconnect ();
2153 input_button.set_sensitive (true);
2154 output_button.set_sensitive (true);
2155 group_button.set_sensitive (true);
2156 set_invert_sensitive (true);
2157 gpm.meter_point_button.set_sensitive (true);
2158 mute_button->set_sensitive (true);
2159 solo_button->set_sensitive (true);
2160 solo_isolated_led->set_sensitive (true);
2161 solo_safe_led->set_sensitive (true);
2162 monitor_input_button->set_sensitive (true);
2163 monitor_disk_button->set_sensitive (true);
2164 _comment_button.set_sensitive (true);
2165 RouteUI::check_rec_enable_sensitivity ();
2166 set_button_names (); // update solo button visual state
2170 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2172 _current_delivery = d;
2173 DeliveryChanged (_current_delivery);
2177 MixerStrip::show_send (boost::shared_ptr<Send> send)
2183 set_current_delivery (send);
2185 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2186 send->set_metering (true);
2187 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2189 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2190 gain_meter().setup_meters ();
2192 uint32_t const in = _current_delivery->pans_required();
2193 uint32_t const out = _current_delivery->pan_outs();
2195 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2196 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2197 panner_ui().setup_pan ();
2198 panner_ui().set_send_drawing_mode (true);
2199 panner_ui().show_all ();
2201 input_button.set_sensitive (false);
2202 group_button.set_sensitive (false);
2203 set_invert_sensitive (false);
2204 gpm.meter_point_button.set_sensitive (false);
2205 mute_button->set_sensitive (false);
2206 solo_button->set_sensitive (false);
2207 rec_enable_button->set_sensitive (false);
2208 solo_isolated_led->set_sensitive (false);
2209 solo_safe_led->set_sensitive (false);
2210 monitor_input_button->set_sensitive (false);
2211 monitor_disk_button->set_sensitive (false);
2212 _comment_button.set_sensitive (false);
2214 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2215 output_button.set_sensitive (false);
2218 reset_strip_style ();
2222 MixerStrip::revert_to_default_display ()
2226 set_current_delivery (_route->main_outs ());
2228 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2229 gain_meter().setup_meters ();
2231 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2232 update_panner_choices();
2233 panner_ui().setup_pan ();
2234 panner_ui().set_send_drawing_mode (false);
2236 if (has_audio_outputs ()) {
2237 panners.show_all ();
2239 panners.hide_all ();
2242 reset_strip_style ();
2246 MixerStrip::set_button_names ()
2250 mute_button->set_text (_("Mute"));
2251 monitor_input_button->set_text (_("In"));
2252 monitor_disk_button->set_text (_("Disk"));
2253 if (monitor_section_button) {
2254 monitor_section_button->set_text (_("Mon"));
2257 if (_route && _route->solo_safe_control()->solo_safe()) {
2258 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2260 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2262 if (!Config->get_solo_control_is_listen_control()) {
2263 solo_button->set_text (_("Solo"));
2265 switch (Config->get_listen_position()) {
2266 case AfterFaderListen:
2267 solo_button->set_text (_("AFL"));
2269 case PreFaderListen:
2270 solo_button->set_text (_("PFL"));
2274 solo_isolated_led->set_text (_("Iso"));
2275 solo_safe_led->set_text (S_("SoloLock|Lock"));
2279 mute_button->set_text (S_("Mute|M"));
2280 monitor_input_button->set_text (S_("MonitorInput|I"));
2281 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2282 if (monitor_section_button) {
2283 monitor_section_button->set_text (S_("Mon|O"));
2286 if (_route && _route->solo_safe_control()->solo_safe()) {
2287 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2289 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2291 if (!Config->get_solo_control_is_listen_control()) {
2292 solo_button->set_text (S_("Solo|S"));
2294 switch (Config->get_listen_position()) {
2295 case AfterFaderListen:
2296 solo_button->set_text (S_("AfterFader|A"));
2298 case PreFaderListen:
2299 solo_button->set_text (S_("Prefader|P"));
2304 solo_isolated_led->set_text (S_("SoloIso|I"));
2305 solo_safe_led->set_text (S_("SoloLock|L"));
2310 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2312 gpm.meter_point_button.set_text ("");
2317 MixerStrip::plugin_selector()
2319 return _mixer.plugin_selector();
2323 MixerStrip::hide_things ()
2325 processor_box.hide_things ();
2329 MixerStrip::input_active_button_press (GdkEventButton*)
2331 /* nothing happens on press */
2336 MixerStrip::input_active_button_release (GdkEventButton* ev)
2338 boost::shared_ptr<MidiTrack> mt = midi_track ();
2344 boost::shared_ptr<RouteList> rl (new RouteList);
2346 rl->push_back (route());
2348 _session->set_exclusive_input_active (rl, !mt->input_active(),
2349 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2355 MixerStrip::midi_input_status_changed ()
2357 if (midi_input_enable_button) {
2358 boost::shared_ptr<MidiTrack> mt = midi_track ();
2360 midi_input_enable_button->set_active (mt->input_active ());
2365 MixerStrip::state_id () const
2367 return string_compose ("strip %1", _route->id().to_s());
2371 MixerStrip::parameter_changed (string p)
2373 if (p == _visibility.get_state_name()) {
2374 /* The user has made changes to the mixer strip visibility, so get
2375 our VisibilityGroup to reflect these changes in our widgets.
2377 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2378 } else if (p == "track-name-number") {
2380 } else if (p == "use-monitor-bus") {
2381 if (monitor_section_button) {
2382 if (mute_button->get_parent()) {
2383 mute_button->get_parent()->remove(*mute_button);
2385 if (monitor_section_button->get_parent()) {
2386 monitor_section_button->get_parent()->remove(*monitor_section_button);
2388 if (Config->get_use_monitor_bus ()) {
2389 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2390 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2391 mute_button->show();
2392 monitor_section_button->show();
2394 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2395 mute_button->show();
2398 } else if (p == "track-name-number") {
2399 update_track_number_visibility();
2403 /** Called to decide whether the solo isolate / solo lock button visibility should
2404 * be overridden from that configured by the user. We do this for the master bus.
2406 * @return optional value that is present if visibility state should be overridden.
2408 boost::optional<bool>
2409 MixerStrip::override_solo_visibility () const
2411 if (_route && _route->is_master ()) {
2412 return boost::optional<bool> (false);
2415 return boost::optional<bool> ();
2419 MixerStrip::add_input_port (DataType t)
2421 _route->input()->add_port ("", this, t);
2425 MixerStrip::add_output_port (DataType t)
2427 _route->output()->add_port ("", this, t);
2431 MixerStrip::route_active_changed ()
2433 reset_strip_style ();
2437 MixerStrip::copy_processors ()
2439 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2443 MixerStrip::cut_processors ()
2445 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2449 MixerStrip::paste_processors ()
2451 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2455 MixerStrip::select_all_processors ()
2457 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2461 MixerStrip::deselect_all_processors ()
2463 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2467 MixerStrip::delete_processors ()
2469 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2473 MixerStrip::toggle_processors ()
2475 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2479 MixerStrip::ab_plugins ()
2481 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2485 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2487 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2490 if (ev->button == 3) {
2491 popup_level_meter_menu (ev);
2499 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2501 using namespace Gtk::Menu_Helpers;
2503 Gtk::Menu* m = manage (new Menu);
2504 MenuList& items = m->items ();
2506 RadioMenuItem::Group group;
2508 _suspend_menu_callbacks = true;
2509 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2510 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2511 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2512 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2513 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2515 if (gpm.meter_channels().n_audio() == 0) {
2516 m->popup (ev->button, ev->time);
2517 _suspend_menu_callbacks = false;
2521 RadioMenuItem::Group tgroup;
2522 items.push_back (SeparatorElem());
2524 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2525 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2526 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2527 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2528 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2529 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2530 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2531 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2532 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2533 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2534 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2537 if (_route->is_master()) {
2540 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2541 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2542 /* non-master bus */
2545 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2552 MeterType cmt = _route->meter_type();
2553 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2555 items.push_back (SeparatorElem());
2556 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2557 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2558 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2559 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2560 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2561 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2563 m->popup (ev->button, ev->time);
2564 _suspend_menu_callbacks = false;
2568 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2569 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2571 using namespace Menu_Helpers;
2573 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2574 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2575 i->set_active (_route->meter_point() == point);
2579 MixerStrip::set_meter_point (MeterPoint p)
2581 if (_suspend_menu_callbacks) return;
2582 _route->set_meter_point (p);
2586 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2587 RadioMenuItem::Group& group, string const & name, MeterType type)
2589 using namespace Menu_Helpers;
2591 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2592 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2593 i->set_active (_route->meter_type() == type);
2597 MixerStrip::set_meter_type (MeterType t)
2599 if (_suspend_menu_callbacks) return;
2604 MixerStrip::update_track_number_visibility ()
2606 DisplaySuspender ds;
2607 bool show_label = _session->config.get_track_name_number();
2609 if (_route && _route->is_master()) {
2614 number_label.show ();
2615 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2616 // except the width of the number label is subtracted from the name-hbox, so we
2617 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2618 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2620 number_label.set_size_request(tnw, -1);
2621 number_label.show ();
2623 number_label.hide ();
2628 MixerStrip::color () const
2630 return route_color ();
2634 MixerStrip::marked_for_display () const
2636 return !_route->presentation_info().hidden();
2640 MixerStrip::set_marked_for_display (bool yn)
2642 return RouteUI::mark_hidden (!yn);