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 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&MixerStrip::setup_comment_button, this), gui_context());
697 set_stuff_from_route ();
699 /* now force an update of all the various elements */
701 update_mute_display ();
702 update_solo_display ();
705 route_group_changed ();
706 update_track_number_visibility ();
709 panners.setup_pan ();
711 if (has_audio_outputs ()) {
717 update_diskstream_display ();
718 update_input_display ();
719 update_output_display ();
721 add_events (Gdk::BUTTON_RELEASE_MASK);
723 processor_box.show ();
725 if (!route()->is_master() && !route()->is_monitor()) {
726 /* we don't allow master or control routes to be hidden */
731 gpm.reset_peak_display ();
732 gpm.gain_display.show ();
733 gpm.peak_display.show ();
736 width_hide_box.show();
738 global_vpacker.show();
739 mute_solo_table.show();
740 bottom_button_table.show();
742 gpm.meter_point_button.show();
743 input_button_box.show_all();
744 output_button.show();
746 _comment_button.show();
748 gpm.gain_automation_state_button.show();
750 parameter_changed ("mixer-element-visibility");
757 MixerStrip::set_stuff_from_route ()
759 /* if width is not set, it will be set by the MixerUI or editor */
762 if (get_gui_property ("strip-width", width)) {
763 set_width_enum (width, this);
768 MixerStrip::set_width_enum (Width w, void* owner)
770 /* always set the gpm width again, things may be hidden */
773 panners.set_width (w);
775 boost::shared_ptr<AutomationList> gain_automation = _route->gain_control()->alist();
777 _width_owner = owner;
781 if (_width_owner == this) {
782 set_gui_property ("strip-width", _width);
787 const float scale = std::max(1.f, UIConfiguration::instance().get_ui_scale());
792 if (show_sends_button) {
793 show_sends_button->set_text (_("Aux"));
796 gpm.gain_automation_state_button.set_text (
797 gpm.astate_string(gain_automation->automation_state()));
799 if (_route->panner()) {
800 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
801 panners.astate_string(_route->panner()->automation_state()));
805 // panners expect an even number of horiz. pixels
806 int width = rintf (max (110.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
808 set_size_request (width, -1);
814 if (show_sends_button) {
815 show_sends_button->set_text (_("Snd"));
818 gpm.gain_automation_state_button.set_text (
819 gpm.short_astate_string(gain_automation->automation_state()));
820 gain_meter().setup_meters (); // recalc meter width
822 if (_route->panner()) {
823 ((Gtk::Label*)panners.pan_automation_state_button.get_child())->set_text (
824 panners.short_astate_string(_route->panner()->automation_state()));
828 // panners expect an even number of horiz. pixels
829 int width = rintf (max (60.f * scale, gpm.get_gm_width() + 10.f * scale)) + 1;
831 set_size_request (width, -1);
836 processor_box.set_width (w);
838 update_input_display ();
839 update_output_display ();
840 setup_comment_button ();
841 route_group_changed ();
847 MixerStrip::set_packed (bool yn)
850 set_gui_property ("visible", _packed);
854 struct RouteCompareByName {
855 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
856 return a->name().compare (b->name()) < 0;
861 MixerStrip::output_release (GdkEventButton *ev)
863 switch (ev->button) {
865 edit_output_configuration ();
873 MixerStrip::output_press (GdkEventButton *ev)
875 using namespace Menu_Helpers;
876 if (!_session->engine().connected()) {
877 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
882 MenuList& citems = output_menu.items();
883 switch (ev->button) {
886 return false; //wait for the mouse-up to pop the dialog
890 output_menu.set_name ("ArdourContextMenu");
892 output_menu_bundles.clear ();
894 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
896 citems.push_back (SeparatorElem());
897 uint32_t const n_with_separator = citems.size ();
899 ARDOUR::BundleList current = _route->output()->bundles_connected ();
901 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
903 /* guess the user-intended main type of the route output */
904 DataType intended_type = guess_main_type(false);
906 /* try adding the master bus first */
907 boost::shared_ptr<Route> master = _session->master_out();
909 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
912 /* then other routes inputs */
913 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
914 RouteList copy = *routes;
915 copy.sort (RouteCompareByName ());
916 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
917 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
920 /* then try adding user bundles, often labeled/grouped physical inputs */
921 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
922 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
923 maybe_add_bundle_to_output_menu (*i, current, intended_type);
927 /* then all other bundles, including physical outs or other sofware */
928 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
929 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
930 maybe_add_bundle_to_output_menu (*i, current, intended_type);
934 if (citems.size() == n_with_separator) {
935 /* no routes added; remove the separator */
939 if (!ARDOUR::Profile->get_mixbus()) {
940 citems.push_back (SeparatorElem());
942 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
945 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
946 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
952 citems.push_back (SeparatorElem());
953 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
955 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
968 MixerStrip::input_release (GdkEventButton *ev)
970 switch (ev->button) {
973 edit_input_configuration ();
985 MixerStrip::input_press (GdkEventButton *ev)
987 using namespace Menu_Helpers;
989 MenuList& citems = input_menu.items();
990 input_menu.set_name ("ArdourContextMenu");
993 if (!_session->engine().connected()) {
994 MessageDialog msg (_("Not connected to audio engine - no I/O changes are possible"));
999 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
1002 switch (ev->button) {
1005 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1009 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1011 citems.push_back (SeparatorElem());
1012 uint32_t const n_with_separator = citems.size ();
1014 input_menu_bundles.clear ();
1016 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1018 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1020 /* give user bundles first chance at being in the menu */
1022 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1023 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1024 maybe_add_bundle_to_input_menu (*i, current);
1028 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1029 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1030 maybe_add_bundle_to_input_menu (*i, current);
1034 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1035 RouteList copy = *routes;
1036 copy.sort (RouteCompareByName ());
1037 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1038 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1041 if (citems.size() == n_with_separator) {
1042 /* no routes added; remove the separator */
1046 citems.push_back (SeparatorElem());
1047 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1050 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1051 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1056 citems.push_back (SeparatorElem());
1057 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1059 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1071 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1073 if (ignore_toggle) {
1077 _route->input()->connect_ports_to_bundle (c, true, this);
1081 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1083 if (ignore_toggle) {
1087 _route->output()->connect_ports_to_bundle (c, true, true, this);
1091 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1093 using namespace Menu_Helpers;
1095 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1099 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1100 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1104 if (i != input_menu_bundles.end()) {
1108 input_menu_bundles.push_back (b);
1110 MenuList& citems = input_menu.items();
1111 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1115 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1118 using namespace Menu_Helpers;
1120 /* The bundle should be an input one, but not ours */
1121 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1125 /* Don't add the monitor input unless we are Master */
1126 boost::shared_ptr<Route> monitor = _session->monitor_out();
1127 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1130 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1131 * or have the same number of |type| channels than our outputs. */
1132 if (type == DataType::NIL) {
1133 if(b->nchannels() != _route->n_outputs())
1136 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1140 /* Avoid adding duplicates */
1141 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1142 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1145 if (i != output_menu_bundles.end()) {
1149 /* Now add the bundle to the menu */
1150 output_menu_bundles.push_back (b);
1152 MenuList& citems = output_menu.items();
1153 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1157 MixerStrip::update_diskstream_display ()
1159 if (is_track() && input_selector) {
1160 input_selector->hide_all ();
1163 route_color_changed ();
1167 MixerStrip::connect_to_pan ()
1169 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1171 panstate_connection.disconnect ();
1172 panstyle_connection.disconnect ();
1174 if (!_route->panner()) {
1178 boost::shared_ptr<Pannable> p = _route->pannable ();
1180 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1182 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1183 * However, that only works a panner was previously set.
1185 * PannerUI must remain subscribed to _panshell->Changed() in case
1186 * we switch the panner eg. AUX-Send and back
1187 * _route->panner_shell()->Changed() vs _panshell->Changed
1189 if (panners._panner == 0) {
1190 panners.panshell_changed ();
1192 update_panner_choices();
1196 MixerStrip::update_panner_choices ()
1198 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1199 if (!_route->panner_shell()) { return; }
1201 uint32_t in = _route->output()->n_ports().n_audio();
1203 if (_route->panner()) {
1204 in = _route->panner()->in().n_audio();
1207 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1211 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1213 /* The heuristic follows these principles:
1214 * A) If all ports that the user connected are of the same type, then he
1215 * very probably intends to use the IO with that type. A common subcase
1216 * is when the IO has only ports of the same type (connected or not).
1217 * B) If several types of ports are connected, then we should guess based
1218 * on the likeliness of the user wanting to use a given type.
1219 * We assume that the DataTypes are ordered from the most likely to the
1220 * least likely when iterating or comparing them with "<".
1221 * C) If no port is connected, the same logic can be applied with all ports
1222 * instead of connected ones. TODO: Try other ideas, for instance look at
1223 * the last plugin output when |for_input| is false (note: when StrictIO
1224 * the outs of the last plugin should be the same as the outs of the route
1225 * modulo the panner which forwards non-audio anyway).
1226 * All of these constraints are respected by the following algorithm that
1227 * just returns the most likely datatype found in connected ports if any, or
1228 * available ports if any (since if all ports are of the same type, the most
1229 * likely found will be that one obviously). */
1231 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1233 /* Find most likely type among connected ports */
1234 if (favor_connected) {
1235 DataType type = DataType::NIL; /* NIL is always last so least likely */
1236 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1237 if (p->connected() && p->type() < type)
1240 if (type != DataType::NIL) {
1241 /* There has been a connected port (necessarily non-NIL) */
1246 /* Find most likely type among available ports.
1247 * The iterator stops before NIL. */
1248 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1249 if (io->n_ports().n(*t) > 0)
1253 /* No port at all, return the most likely datatype by default */
1254 return DataType::front();
1258 * Output port labelling
1259 * =====================
1261 * Case 1: Each output has one connection, all connections are to system:playback_%i
1262 * out 1 -> system:playback_1
1263 * out 2 -> system:playback_2
1264 * out 3 -> system:playback_3
1267 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1268 * out 1 -> ardour:track_x/in 1
1269 * out 2 -> ardour:track_x/in 2
1270 * Display as: track_x
1272 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1273 * out 1 -> program x:foo
1274 * out 2 -> program x:foo
1275 * Display as: program x
1277 * Case 4: No connections (Disconnected)
1280 * Default case (unusual routing):
1281 * Display as: *number of connections*
1285 * .-----------------------------------------------.
1287 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1288 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1289 * '-----------------------------------------------'
1290 * .-----------------------------------------------.
1293 * '-----------------------------------------------'
1297 MixerStrip::update_io_button (bool for_input)
1299 ostringstream tooltip;
1300 ostringstream label;
1301 bool have_label = false;
1303 uint32_t total_connection_count = 0;
1304 uint32_t typed_connection_count = 0;
1305 bool each_typed_port_has_one_connection = true;
1307 DataType dt = guess_main_type(for_input);
1308 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1310 /* Fill in the tooltip. Also count:
1311 * - The total number of connections.
1312 * - The number of main-typed connections.
1313 * - Whether each main-typed port has exactly one connection. */
1315 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1316 Gtkmm2ext::markup_escape_text (_route->name()));
1318 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1319 Gtkmm2ext::markup_escape_text (_route->name()));
1322 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1323 vector<string> port_connections;
1324 for (PortSet::iterator port = io->ports().begin();
1325 port != io->ports().end();
1327 port_connections.clear();
1328 port->get_connections(port_connections);
1330 uint32_t port_connection_count = 0;
1332 for (vector<string>::iterator i = port_connections.begin();
1333 i != port_connections.end();
1335 ++port_connection_count;
1337 if (port_connection_count == 1) {
1338 tooltip << endl << Gtkmm2ext::markup_escape_text (
1339 port->name().substr(port->name().find("/") + 1));
1345 tooltip << Gtkmm2ext::markup_escape_text(*i);
1348 total_connection_count += port_connection_count;
1349 if (port->type() == dt) {
1350 typed_connection_count += port_connection_count;
1351 each_typed_port_has_one_connection &= (port_connection_count == 1);
1356 if (total_connection_count == 0) {
1357 tooltip << endl << _("Disconnected");
1360 if (typed_connection_count == 0) {
1365 /* Are all main-typed channels connected to the same route ? */
1367 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1368 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1369 route != routes->end();
1371 boost::shared_ptr<IO> dest_io =
1372 for_input ? (*route)->output() : (*route)->input();
1373 if (io->bundle()->connected_to(dest_io->bundle(),
1376 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1383 /* Are all main-typed channels connected to the same (user) bundle ? */
1385 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1386 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1387 bundle != bundles->end();
1389 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1391 if (io->bundle()->connected_to(*bundle, _session->engine(),
1393 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1400 /* Is each main-typed channel only connected to a physical output ? */
1401 if (!have_label && each_typed_port_has_one_connection) {
1402 ostringstream temp_label;
1403 vector<string> phys;
1404 string playorcapture;
1406 _session->engine().get_physical_inputs(dt, phys);
1407 playorcapture = "capture_";
1409 _session->engine().get_physical_outputs(dt, phys);
1410 playorcapture = "playback_";
1412 for (PortSet::iterator port = io->ports().begin(dt);
1413 port != io->ports().end(dt);
1416 for (vector<string>::iterator s = phys.begin();
1419 if (!port->connected_to(*s))
1421 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1423 string::size_type start = (*s).find(playorcapture);
1424 if (start != string::npos) {
1425 pn = (*s).substr(start + playorcapture.size());
1431 temp_label.str(""); /* erase the failed attempt */
1434 if (port != io->ports().begin(dt))
1439 if (!temp_label.str().empty()) {
1440 label << temp_label.str();
1445 /* Is each main-typed channel connected to a single and different port with
1446 * the same client name (e.g. another JACK client) ? */
1447 if (!have_label && each_typed_port_has_one_connection) {
1448 string maybe_client = "";
1449 vector<string> connections;
1450 for (PortSet::iterator port = io->ports().begin(dt);
1451 port != io->ports().end(dt);
1453 port_connections.clear();
1454 port->get_connections(port_connections);
1455 string connection = port_connections.front();
1457 vector<string>::iterator i = connections.begin();
1458 while (i != connections.end() && *i != connection) {
1461 if (i != connections.end())
1462 break; /* duplicate connection */
1463 connections.push_back(connection);
1465 connection = connection.substr(0, connection.find(":"));
1466 if (maybe_client.empty())
1467 maybe_client = connection;
1468 if (maybe_client != connection)
1471 if (connections.size() == io->n_ports().n(dt)) {
1472 label << maybe_client;
1477 /* Odd configuration */
1479 label << "*" << total_connection_count << "*";
1482 if (total_connection_count > typed_connection_count) {
1483 label << "\u2295"; /* circled plus */
1486 /* Actually set the properties of the button */
1487 char * cstr = new char[tooltip.str().size() + 1];
1488 strcpy(cstr, tooltip.str().c_str());
1491 input_button.set_text (label.str());
1492 set_tooltip (&input_button, cstr);
1494 output_button.set_text (label.str());
1495 set_tooltip (&output_button, cstr);
1502 MixerStrip::update_input_display ()
1504 update_io_button (true);
1505 panners.setup_pan ();
1507 if (has_audio_outputs ()) {
1508 panners.show_all ();
1510 panners.hide_all ();
1516 MixerStrip::update_output_display ()
1518 update_io_button (false);
1519 gpm.setup_meters ();
1520 panners.setup_pan ();
1522 if (has_audio_outputs ()) {
1523 panners.show_all ();
1525 panners.hide_all ();
1530 MixerStrip::fast_update ()
1532 gpm.update_meters ();
1536 MixerStrip::diskstream_changed ()
1538 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1542 MixerStrip::io_changed_proxy ()
1544 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1545 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1549 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1551 boost::shared_ptr<Port> a = wa.lock ();
1552 boost::shared_ptr<Port> b = wb.lock ();
1554 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1555 update_input_display ();
1556 set_width_enum (_width, this);
1559 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1560 update_output_display ();
1561 set_width_enum (_width, this);
1566 MixerStrip::setup_comment_button ()
1568 std::string comment = _route->comment();
1570 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1572 if (comment.empty ()) {
1573 _comment_button.set_name ("generic button");
1574 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1578 _comment_button.set_name ("comment button");
1580 string::size_type pos = comment.find_first_of (" \t\n");
1581 if (pos != string::npos) {
1582 comment = comment.substr (0, pos);
1584 if (comment.empty()) {
1585 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1587 _comment_button.set_text (comment);
1592 MixerStrip::select_route_group (GdkEventButton *ev)
1594 using namespace Menu_Helpers;
1596 if (ev->button == 1) {
1598 if (group_menu == 0) {
1600 PropertyList* plist = new PropertyList();
1602 plist->add (Properties::group_gain, true);
1603 plist->add (Properties::group_mute, true);
1604 plist->add (Properties::group_solo, true);
1606 group_menu = new RouteGroupMenu (_session, plist);
1610 r.push_back (route ());
1611 group_menu->build (r);
1613 RouteGroup *rg = _route->route_group();
1615 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1616 rg ? rg->name() : _("No Group"),
1624 MixerStrip::route_group_changed ()
1626 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1628 RouteGroup *rg = _route->route_group();
1631 group_button.set_text (PBD::short_version (rg->name(), 5));
1635 group_button.set_text (_("Grp"));
1638 group_button.set_text (_("~G"));
1645 MixerStrip::route_color_changed ()
1647 using namespace ARDOUR_UI_UTILS;
1648 name_button.modify_bg (STATE_NORMAL, color());
1649 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1650 reset_strip_style ();
1654 MixerStrip::show_passthru_color ()
1656 reset_strip_style ();
1661 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1663 boost::shared_ptr<Processor> processor (p.lock ());
1664 if (!processor || !processor->display_to_user()) {
1667 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1669 if (pi && pi->is_channelstrip ()) {
1674 ++_plugin_insert_cnt;
1678 MixerStrip::build_route_ops_menu ()
1680 using namespace Menu_Helpers;
1681 route_ops_menu = new Menu;
1682 route_ops_menu->set_name ("ArdourContextMenu");
1684 MenuList& items = route_ops_menu->items();
1686 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1688 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1690 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1692 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1694 if (!Profile->get_mixbus()) {
1695 items.push_back (SeparatorElem());
1698 if (!_route->is_master()
1700 && !_route->mixbus()
1703 if (Profile->get_mixbus()) {
1704 items.push_back (SeparatorElem());
1706 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1709 if (!Profile->get_mixbus()) {
1710 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1711 /* do not allow rename if the track is record-enabled */
1712 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1715 items.push_back (SeparatorElem());
1716 items.push_back (CheckMenuElem (_("Active")));
1717 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1718 i->set_active (_route->active());
1719 i->set_sensitive(! _session->transport_rolling());
1720 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1722 if (!Profile->get_mixbus ()) {
1723 items.push_back (SeparatorElem());
1724 items.push_back (CheckMenuElem (_("Strict I/O")));
1725 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1726 i->set_active (_route->strict_io());
1727 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1730 _plugin_insert_cnt = 0;
1731 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1732 if (_plugin_insert_cnt > 0) {
1733 items.push_back (SeparatorElem());
1734 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1737 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1738 items.push_back (MenuElem (_("Patch Selector..."),
1739 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1742 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1743 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1744 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1745 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1748 items.push_back (SeparatorElem());
1749 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1751 items.push_back (SeparatorElem());
1752 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1753 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1754 denormal_menu_item->set_active (_route->denormal_protection());
1757 /* note that this relies on selection being shared across editor and
1758 mixer (or global to the backend, in the future), which is the only
1759 sane thing for users anyway.
1762 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1764 Selection& selection (PublicEditor::instance().get_selection());
1765 if (!selection.selected (stav)) {
1766 selection.set (stav);
1769 if (!_route->is_master()) {
1770 items.push_back (SeparatorElem());
1771 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1774 items.push_back (SeparatorElem());
1775 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1781 MixerStrip::name_button_button_press (GdkEventButton* ev)
1783 if (ev->button == 1 || ev->button == 3) {
1784 list_route_operations ();
1786 if (ev->button == 1) {
1787 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1790 route_ops_menu->popup (3, ev->time);
1800 MixerStrip::number_button_button_press (GdkEventButton* ev)
1802 if ( ev->button == 3 ) {
1803 list_route_operations ();
1805 route_ops_menu->popup (1, ev->time);
1814 MixerStrip::list_route_operations ()
1816 delete route_ops_menu;
1817 build_route_ops_menu ();
1821 MixerStrip::set_selected (bool yn)
1823 AxisView::set_selected (yn);
1826 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1827 global_frame.set_name ("MixerStripSelectedFrame");
1829 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1830 global_frame.set_name ("MixerStripFrame");
1833 global_frame.queue_draw ();
1836 // processor_box.deselect_all_processors();
1840 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1842 if (what_changed.contains (ARDOUR::Properties::name)) {
1848 MixerStrip::name_changed ()
1852 name_button.set_text (_route->name());
1855 name_button.set_text (PBD::short_version (_route->name(), 5));
1859 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1861 if (_session->config.get_track_name_number()) {
1862 const int64_t track_number = _route->track_number ();
1863 if (track_number == 0) {
1864 number_label.set_text ("-");
1866 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1869 number_label.set_text ("");
1874 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1876 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1880 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1882 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1886 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1888 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1892 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1894 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1898 MixerStrip::width_button_pressed (GdkEventButton* ev)
1900 if (ev->button != 1) {
1904 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1907 _mixer.set_strip_width (Narrow, true);
1911 _mixer.set_strip_width (Wide, true);
1917 set_width_enum (Narrow, this);
1920 set_width_enum (Wide, this);
1929 MixerStrip::hide_clicked ()
1931 // LAME fix to reset the button status for when it is redisplayed (part 1)
1932 hide_button.set_sensitive(false);
1935 Hiding(); /* EMIT_SIGNAL */
1937 _mixer.hide_strip (this);
1941 hide_button.set_sensitive(true);
1945 MixerStrip::set_embedded (bool yn)
1951 MixerStrip::map_frozen ()
1953 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1955 boost::shared_ptr<AudioTrack> at = audio_track();
1958 switch (at->freeze_state()) {
1959 case AudioTrack::Frozen:
1960 processor_box.set_sensitive (false);
1961 hide_redirect_editors ();
1964 processor_box.set_sensitive (true);
1965 // XXX need some way, maybe, to retoggle redirect editors
1969 processor_box.set_sensitive (true);
1971 RouteUI::map_frozen ();
1975 MixerStrip::hide_redirect_editors ()
1977 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1981 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1983 boost::shared_ptr<Processor> processor (p.lock ());
1988 Gtk::Window* w = processor_box.get_processor_ui (processor);
1996 MixerStrip::reset_strip_style ()
1998 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2000 gpm.set_fader_name ("SendStripBase");
2004 if (is_midi_track()) {
2005 if (_route->active()) {
2006 set_name ("MidiTrackStripBase");
2008 set_name ("MidiTrackStripBaseInactive");
2010 gpm.set_fader_name ("MidiTrackFader");
2011 } else if (is_audio_track()) {
2012 if (_route->active()) {
2013 set_name ("AudioTrackStripBase");
2015 set_name ("AudioTrackStripBaseInactive");
2017 gpm.set_fader_name ("AudioTrackFader");
2019 if (_route->active()) {
2020 set_name ("AudioBusStripBase");
2022 set_name ("AudioBusStripBaseInactive");
2024 gpm.set_fader_name ("AudioBusFader");
2026 /* (no MIDI busses yet) */
2033 MixerStrip::engine_stopped ()
2038 MixerStrip::engine_running ()
2043 MixerStrip::meter_point_string (MeterPoint mp)
2056 case MeterPostFader:
2073 return S_("Meter|In");
2077 return S_("Meter|Pr");
2080 case MeterPostFader:
2081 return S_("Meter|Po");
2085 return S_("Meter|O");
2090 return S_("Meter|C");
2099 /** Called when the monitor-section state */
2101 MixerStrip::monitor_changed ()
2103 assert (monitor_section_button);
2104 if (_session->monitor_active()) {
2105 monitor_section_button->set_name ("master monitor section button active");
2107 monitor_section_button->set_name ("master monitor section button normal");
2111 /** Called when the metering point has changed */
2113 MixerStrip::meter_changed ()
2115 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2116 gpm.setup_meters ();
2117 // reset peak when meter point changes
2118 gpm.reset_peak_display();
2121 /** The bus that we are displaying sends to has changed, or been turned off.
2122 * @param send_to New bus that we are displaying sends to, or 0.
2125 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2127 RouteUI::bus_send_display_changed (send_to);
2130 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2135 revert_to_default_display ();
2138 revert_to_default_display ();
2143 MixerStrip::drop_send ()
2145 boost::shared_ptr<Send> current_send;
2147 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2148 current_send->set_metering (false);
2151 send_gone_connection.disconnect ();
2152 input_button.set_sensitive (true);
2153 output_button.set_sensitive (true);
2154 group_button.set_sensitive (true);
2155 set_invert_sensitive (true);
2156 gpm.meter_point_button.set_sensitive (true);
2157 mute_button->set_sensitive (true);
2158 solo_button->set_sensitive (true);
2159 solo_isolated_led->set_sensitive (true);
2160 solo_safe_led->set_sensitive (true);
2161 monitor_input_button->set_sensitive (true);
2162 monitor_disk_button->set_sensitive (true);
2163 _comment_button.set_sensitive (true);
2164 RouteUI::check_rec_enable_sensitivity ();
2165 set_button_names (); // update solo button visual state
2169 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2171 _current_delivery = d;
2172 DeliveryChanged (_current_delivery);
2176 MixerStrip::show_send (boost::shared_ptr<Send> send)
2182 set_current_delivery (send);
2184 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2185 send->set_metering (true);
2186 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2188 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2189 gain_meter().setup_meters ();
2191 uint32_t const in = _current_delivery->pans_required();
2192 uint32_t const out = _current_delivery->pan_outs();
2194 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2195 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2196 panner_ui().setup_pan ();
2197 panner_ui().set_send_drawing_mode (true);
2198 panner_ui().show_all ();
2200 input_button.set_sensitive (false);
2201 group_button.set_sensitive (false);
2202 set_invert_sensitive (false);
2203 gpm.meter_point_button.set_sensitive (false);
2204 mute_button->set_sensitive (false);
2205 solo_button->set_sensitive (false);
2206 rec_enable_button->set_sensitive (false);
2207 solo_isolated_led->set_sensitive (false);
2208 solo_safe_led->set_sensitive (false);
2209 monitor_input_button->set_sensitive (false);
2210 monitor_disk_button->set_sensitive (false);
2211 _comment_button.set_sensitive (false);
2213 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2214 output_button.set_sensitive (false);
2217 reset_strip_style ();
2221 MixerStrip::revert_to_default_display ()
2225 set_current_delivery (_route->main_outs ());
2227 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2228 gain_meter().setup_meters ();
2230 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2231 update_panner_choices();
2232 panner_ui().setup_pan ();
2233 panner_ui().set_send_drawing_mode (false);
2235 if (has_audio_outputs ()) {
2236 panners.show_all ();
2238 panners.hide_all ();
2241 reset_strip_style ();
2245 MixerStrip::set_button_names ()
2249 mute_button->set_text (_("Mute"));
2250 monitor_input_button->set_text (_("In"));
2251 monitor_disk_button->set_text (_("Disk"));
2252 if (monitor_section_button) {
2253 monitor_section_button->set_text (_("Mon"));
2256 if (_route && _route->solo_safe_control()->solo_safe()) {
2257 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2259 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2261 if (!Config->get_solo_control_is_listen_control()) {
2262 solo_button->set_text (_("Solo"));
2264 switch (Config->get_listen_position()) {
2265 case AfterFaderListen:
2266 solo_button->set_text (_("AFL"));
2268 case PreFaderListen:
2269 solo_button->set_text (_("PFL"));
2273 solo_isolated_led->set_text (_("Iso"));
2274 solo_safe_led->set_text (S_("SoloLock|Lock"));
2278 mute_button->set_text (S_("Mute|M"));
2279 monitor_input_button->set_text (S_("MonitorInput|I"));
2280 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2281 if (monitor_section_button) {
2282 monitor_section_button->set_text (S_("Mon|O"));
2285 if (_route && _route->solo_safe_control()->solo_safe()) {
2286 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2288 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2290 if (!Config->get_solo_control_is_listen_control()) {
2291 solo_button->set_text (S_("Solo|S"));
2293 switch (Config->get_listen_position()) {
2294 case AfterFaderListen:
2295 solo_button->set_text (S_("AfterFader|A"));
2297 case PreFaderListen:
2298 solo_button->set_text (S_("Prefader|P"));
2303 solo_isolated_led->set_text (S_("SoloIso|I"));
2304 solo_safe_led->set_text (S_("SoloLock|L"));
2309 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2311 gpm.meter_point_button.set_text ("");
2316 MixerStrip::plugin_selector()
2318 return _mixer.plugin_selector();
2322 MixerStrip::hide_things ()
2324 processor_box.hide_things ();
2328 MixerStrip::input_active_button_press (GdkEventButton*)
2330 /* nothing happens on press */
2335 MixerStrip::input_active_button_release (GdkEventButton* ev)
2337 boost::shared_ptr<MidiTrack> mt = midi_track ();
2343 boost::shared_ptr<RouteList> rl (new RouteList);
2345 rl->push_back (route());
2347 _session->set_exclusive_input_active (rl, !mt->input_active(),
2348 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2354 MixerStrip::midi_input_status_changed ()
2356 if (midi_input_enable_button) {
2357 boost::shared_ptr<MidiTrack> mt = midi_track ();
2359 midi_input_enable_button->set_active (mt->input_active ());
2364 MixerStrip::state_id () const
2366 return string_compose ("strip %1", _route->id().to_s());
2370 MixerStrip::parameter_changed (string p)
2372 if (p == _visibility.get_state_name()) {
2373 /* The user has made changes to the mixer strip visibility, so get
2374 our VisibilityGroup to reflect these changes in our widgets.
2376 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2377 } else if (p == "track-name-number") {
2379 } else if (p == "use-monitor-bus") {
2380 if (monitor_section_button) {
2381 if (mute_button->get_parent()) {
2382 mute_button->get_parent()->remove(*mute_button);
2384 if (monitor_section_button->get_parent()) {
2385 monitor_section_button->get_parent()->remove(*monitor_section_button);
2387 if (Config->get_use_monitor_bus ()) {
2388 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2389 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2390 mute_button->show();
2391 monitor_section_button->show();
2393 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2394 mute_button->show();
2397 } else if (p == "track-name-number") {
2398 update_track_number_visibility();
2402 /** Called to decide whether the solo isolate / solo lock button visibility should
2403 * be overridden from that configured by the user. We do this for the master bus.
2405 * @return optional value that is present if visibility state should be overridden.
2407 boost::optional<bool>
2408 MixerStrip::override_solo_visibility () const
2410 if (_route && _route->is_master ()) {
2411 return boost::optional<bool> (false);
2414 return boost::optional<bool> ();
2418 MixerStrip::add_input_port (DataType t)
2420 _route->input()->add_port ("", this, t);
2424 MixerStrip::add_output_port (DataType t)
2426 _route->output()->add_port ("", this, t);
2430 MixerStrip::route_active_changed ()
2432 reset_strip_style ();
2436 MixerStrip::copy_processors ()
2438 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2442 MixerStrip::cut_processors ()
2444 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2448 MixerStrip::paste_processors ()
2450 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2454 MixerStrip::select_all_processors ()
2456 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2460 MixerStrip::deselect_all_processors ()
2462 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2466 MixerStrip::delete_processors ()
2468 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2472 MixerStrip::toggle_processors ()
2474 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2478 MixerStrip::ab_plugins ()
2480 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2484 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2486 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2489 if (ev->button == 3) {
2490 popup_level_meter_menu (ev);
2498 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2500 using namespace Gtk::Menu_Helpers;
2502 Gtk::Menu* m = manage (new Menu);
2503 MenuList& items = m->items ();
2505 RadioMenuItem::Group group;
2507 _suspend_menu_callbacks = true;
2508 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2509 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2510 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2511 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2512 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2514 if (gpm.meter_channels().n_audio() == 0) {
2515 m->popup (ev->button, ev->time);
2516 _suspend_menu_callbacks = false;
2520 RadioMenuItem::Group tgroup;
2521 items.push_back (SeparatorElem());
2523 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2524 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2525 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2526 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2527 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2528 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2529 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2530 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2531 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2532 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2533 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2536 if (_route->is_master()) {
2539 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2540 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2541 /* non-master bus */
2544 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2551 MeterType cmt = _route->meter_type();
2552 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2554 items.push_back (SeparatorElem());
2555 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2556 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2557 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2558 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2559 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2560 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2562 m->popup (ev->button, ev->time);
2563 _suspend_menu_callbacks = false;
2567 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2568 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2570 using namespace Menu_Helpers;
2572 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2573 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2574 i->set_active (_route->meter_point() == point);
2578 MixerStrip::set_meter_point (MeterPoint p)
2580 if (_suspend_menu_callbacks) return;
2581 _route->set_meter_point (p);
2585 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2586 RadioMenuItem::Group& group, string const & name, MeterType type)
2588 using namespace Menu_Helpers;
2590 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2591 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2592 i->set_active (_route->meter_type() == type);
2596 MixerStrip::set_meter_type (MeterType t)
2598 if (_suspend_menu_callbacks) return;
2603 MixerStrip::update_track_number_visibility ()
2605 DisplaySuspender ds;
2606 bool show_label = _session->config.get_track_name_number();
2608 if (_route && _route->is_master()) {
2613 number_label.show ();
2614 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2615 // except the width of the number label is subtracted from the name-hbox, so we
2616 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2617 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2619 number_label.set_size_request(tnw, -1);
2620 number_label.show ();
2622 number_label.hide ();
2627 MixerStrip::color () const
2629 return route_color ();
2633 MixerStrip::marked_for_display () const
2635 return !_route->presentation_info().hidden();
2639 MixerStrip::set_marked_for_display (bool yn)
2641 return RouteUI::mark_hidden (!yn);