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_sample());
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_sample());
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 ("Mixer", "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 (!ARDOUR_UI_UTILS::engine_is_running ()) {
880 MenuList& citems = output_menu.items();
881 switch (ev->button) {
884 return false; //wait for the mouse-up to pop the dialog
888 output_menu.set_name ("ArdourContextMenu");
890 output_menu_bundles.clear ();
892 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_output)));
894 citems.push_back (SeparatorElem());
895 uint32_t const n_with_separator = citems.size ();
897 ARDOUR::BundleList current = _route->output()->bundles_connected ();
899 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
901 /* guess the user-intended main type of the route output */
902 DataType intended_type = guess_main_type(false);
904 /* try adding the master bus first */
905 boost::shared_ptr<Route> master = _session->master_out();
907 maybe_add_bundle_to_output_menu (master->input()->bundle(), current, intended_type);
910 /* then other routes inputs */
911 RouteList copy = _session->get_routelist ();
912 copy.sort (RouteCompareByName ());
913 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
914 maybe_add_bundle_to_output_menu ((*i)->input()->bundle(), current, intended_type);
917 /* then try adding user bundles, often labeled/grouped physical inputs */
918 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
919 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
920 maybe_add_bundle_to_output_menu (*i, current, intended_type);
924 /* then all other bundles, including physical outs or other sofware */
925 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
926 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
927 maybe_add_bundle_to_output_menu (*i, current, intended_type);
931 if (citems.size() == n_with_separator) {
932 /* no routes added; remove the separator */
936 if (!ARDOUR::Profile->get_mixbus()) {
937 citems.push_back (SeparatorElem());
939 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
942 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
943 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_output_port), *i)
949 citems.push_back (SeparatorElem());
950 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_output_configuration)));
952 Gtkmm2ext::anchored_menu_popup(&output_menu, &output_button, "",
965 MixerStrip::input_release (GdkEventButton *ev)
967 switch (ev->button) {
970 edit_input_configuration ();
982 MixerStrip::input_press (GdkEventButton *ev)
984 using namespace Menu_Helpers;
986 MenuList& citems = input_menu.items();
987 input_menu.set_name ("ArdourContextMenu");
990 if (!ARDOUR_UI_UTILS::engine_is_running ()) {
994 if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
997 switch (ev->button) {
1000 return false; //don't handle the mouse-down here. wait for mouse-up to pop the menu
1004 citems.push_back (MenuElem (_("Disconnect"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::disconnect_input)));
1006 citems.push_back (SeparatorElem());
1007 uint32_t const n_with_separator = citems.size ();
1009 input_menu_bundles.clear ();
1011 ARDOUR::BundleList current = _route->input()->bundles_connected ();
1013 boost::shared_ptr<ARDOUR::BundleList> b = _session->bundles ();
1015 /* give user bundles first chance at being in the menu */
1017 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1018 if (boost::dynamic_pointer_cast<UserBundle> (*i)) {
1019 maybe_add_bundle_to_input_menu (*i, current);
1023 for (ARDOUR::BundleList::iterator i = b->begin(); i != b->end(); ++i) {
1024 if (boost::dynamic_pointer_cast<UserBundle> (*i) == 0) {
1025 maybe_add_bundle_to_input_menu (*i, current);
1029 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1030 RouteList copy = *routes;
1031 copy.sort (RouteCompareByName ());
1032 for (ARDOUR::RouteList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
1033 maybe_add_bundle_to_input_menu ((*i)->output()->bundle(), current);
1036 if (citems.size() == n_with_separator) {
1037 /* no routes added; remove the separator */
1041 citems.push_back (SeparatorElem());
1042 for (DataType::iterator i = DataType::begin(); i != DataType::end(); ++i) {
1045 string_compose (_("Add %1 port"), (*i).to_i18n_string()),
1046 sigc::bind (sigc::mem_fun (*this, &MixerStrip::add_input_port), *i)
1051 citems.push_back (SeparatorElem());
1052 citems.push_back (MenuElem (_("Routing Grid"), sigc::mem_fun (*(static_cast<RouteUI*>(this)), &RouteUI::edit_input_configuration)));
1054 Gtkmm2ext::anchored_menu_popup(&input_menu, &input_button, "",
1066 MixerStrip::bundle_input_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1068 if (ignore_toggle) {
1072 _route->input()->connect_ports_to_bundle (c, true, this);
1076 MixerStrip::bundle_output_chosen (boost::shared_ptr<ARDOUR::Bundle> c)
1078 if (ignore_toggle) {
1082 _route->output()->connect_ports_to_bundle (c, true, true, this);
1086 MixerStrip::maybe_add_bundle_to_input_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/)
1088 using namespace Menu_Helpers;
1090 if (b->ports_are_outputs() == false || b->nchannels() != _route->n_inputs() || *b == *_route->output()->bundle()) {
1094 list<boost::shared_ptr<Bundle> >::iterator i = input_menu_bundles.begin ();
1095 while (i != input_menu_bundles.end() && b->has_same_ports (*i) == false) {
1099 if (i != input_menu_bundles.end()) {
1103 input_menu_bundles.push_back (b);
1105 MenuList& citems = input_menu.items();
1106 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_input_chosen), b)));
1110 MixerStrip::maybe_add_bundle_to_output_menu (boost::shared_ptr<Bundle> b, ARDOUR::BundleList const& /*current*/,
1113 using namespace Menu_Helpers;
1115 /* The bundle should be an input one, but not ours */
1116 if (b->ports_are_inputs() == false || *b == *_route->input()->bundle()) {
1120 /* Don't add the monitor input unless we are Master */
1121 boost::shared_ptr<Route> monitor = _session->monitor_out();
1122 if ((!_route->is_master()) && monitor && b->has_same_ports (monitor->input()->bundle()))
1125 /* It should either match exactly our outputs (if |type| is DataType::NIL)
1126 * or have the same number of |type| channels than our outputs. */
1127 if (type == DataType::NIL) {
1128 if(b->nchannels() != _route->n_outputs())
1131 if (b->nchannels().n(type) != _route->n_outputs().n(type))
1135 /* Avoid adding duplicates */
1136 list<boost::shared_ptr<Bundle> >::iterator i = output_menu_bundles.begin ();
1137 while (i != output_menu_bundles.end() && b->has_same_ports (*i) == false) {
1140 if (i != output_menu_bundles.end()) {
1144 /* Now add the bundle to the menu */
1145 output_menu_bundles.push_back (b);
1147 MenuList& citems = output_menu.items();
1148 citems.push_back (MenuElemNoMnemonic (b->name (), sigc::bind (sigc::mem_fun(*this, &MixerStrip::bundle_output_chosen), b)));
1152 MixerStrip::update_diskstream_display ()
1154 if (is_track() && input_selector) {
1155 input_selector->hide_all ();
1158 route_color_changed ();
1162 MixerStrip::connect_to_pan ()
1164 ENSURE_GUI_THREAD (*this, &MixerStrip::connect_to_pan)
1166 panstate_connection.disconnect ();
1167 panstyle_connection.disconnect ();
1169 if (!_route->panner()) {
1173 boost::shared_ptr<Pannable> p = _route->pannable ();
1175 p->automation_state_changed.connect (panstate_connection, invalidator (*this), boost::bind (&PannerUI::pan_automation_state_changed, &panners), gui_context());
1177 /* This call reduncant, PannerUI::set_panner() connects to _panshell->Changed itself
1178 * However, that only works a panner was previously set.
1180 * PannerUI must remain subscribed to _panshell->Changed() in case
1181 * we switch the panner eg. AUX-Send and back
1182 * _route->panner_shell()->Changed() vs _panshell->Changed
1184 if (panners._panner == 0) {
1185 panners.panshell_changed ();
1187 update_panner_choices();
1191 MixerStrip::update_panner_choices ()
1193 ENSURE_GUI_THREAD (*this, &MixerStrip::update_panner_choices)
1194 if (!_route->panner_shell()) { return; }
1196 uint32_t in = _route->output()->n_ports().n_audio();
1198 if (_route->panner()) {
1199 in = _route->panner()->in().n_audio();
1202 panners.set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
1206 MixerStrip::guess_main_type(bool for_input, bool favor_connected) const
1208 /* The heuristic follows these principles:
1209 * A) If all ports that the user connected are of the same type, then he
1210 * very probably intends to use the IO with that type. A common subcase
1211 * is when the IO has only ports of the same type (connected or not).
1212 * B) If several types of ports are connected, then we should guess based
1213 * on the likeliness of the user wanting to use a given type.
1214 * We assume that the DataTypes are ordered from the most likely to the
1215 * least likely when iterating or comparing them with "<".
1216 * C) If no port is connected, the same logic can be applied with all ports
1217 * instead of connected ones. TODO: Try other ideas, for instance look at
1218 * the last plugin output when |for_input| is false (note: when StrictIO
1219 * the outs of the last plugin should be the same as the outs of the route
1220 * modulo the panner which forwards non-audio anyway).
1221 * All of these constraints are respected by the following algorithm that
1222 * just returns the most likely datatype found in connected ports if any, or
1223 * available ports if any (since if all ports are of the same type, the most
1224 * likely found will be that one obviously). */
1226 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1228 /* Find most likely type among connected ports */
1229 if (favor_connected) {
1230 DataType type = DataType::NIL; /* NIL is always last so least likely */
1231 for (PortSet::iterator p = io->ports().begin(); p != io->ports().end(); ++p) {
1232 if (p->connected() && p->type() < type)
1235 if (type != DataType::NIL) {
1236 /* There has been a connected port (necessarily non-NIL) */
1241 /* Find most likely type among available ports.
1242 * The iterator stops before NIL. */
1243 for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
1244 if (io->n_ports().n(*t) > 0)
1248 /* No port at all, return the most likely datatype by default */
1249 return DataType::front();
1253 * Output port labelling
1255 * Case 1: Each output has one connection, all connections are to system:playback_%i
1256 * out 1 -> system:playback_1
1257 * out 2 -> system:playback_2
1258 * out 3 -> system:playback_3
1261 * Case 2: Each output has one connection, all connections are to ardour:track_x/in 1
1262 * out 1 -> ardour:track_x/in 1
1263 * out 2 -> ardour:track_x/in 2
1264 * Display as: track_x
1266 * Case 3: Each output has one connection, all connections are to Jack client "program x"
1267 * out 1 -> program x:foo
1268 * out 2 -> program x:foo
1269 * Display as: program x
1271 * Case 4: No connections (Disconnected)
1274 * Default case (unusual routing):
1275 * Display as: *number of connections*
1280 * .-----------------------------------------------.
1282 * | out 1 -> ardour:master/in 1, jamin:input/in 1 |
1283 * | out 2 -> ardour:master/in 2, jamin:input/in 2 |
1284 * '-----------------------------------------------'
1285 * .-----------------------------------------------.
1288 * '-----------------------------------------------'
1292 MixerStrip::update_io_button (bool for_input)
1294 ostringstream tooltip;
1295 ostringstream label;
1296 bool have_label = false;
1298 uint32_t total_connection_count = 0;
1299 uint32_t typed_connection_count = 0;
1300 bool each_typed_port_has_one_connection = true;
1302 DataType dt = guess_main_type(for_input);
1303 boost::shared_ptr<IO> io = for_input ? _route->input() : _route->output();
1305 /* Fill in the tooltip. Also count:
1306 * - The total number of connections.
1307 * - The number of main-typed connections.
1308 * - Whether each main-typed port has exactly one connection. */
1310 tooltip << string_compose (_("<b>INPUT</b> to %1"),
1311 Gtkmm2ext::markup_escape_text (_route->name()));
1313 tooltip << string_compose (_("<b>OUTPUT</b> from %1"),
1314 Gtkmm2ext::markup_escape_text (_route->name()));
1317 string arrow = Gtkmm2ext::markup_escape_text(for_input ? " <- " : " -> ");
1318 vector<string> port_connections;
1319 for (PortSet::iterator port = io->ports().begin();
1320 port != io->ports().end();
1322 port_connections.clear();
1323 port->get_connections(port_connections);
1325 uint32_t port_connection_count = 0;
1327 for (vector<string>::iterator i = port_connections.begin();
1328 i != port_connections.end();
1330 ++port_connection_count;
1332 if (port_connection_count == 1) {
1333 tooltip << endl << Gtkmm2ext::markup_escape_text (
1334 port->name().substr(port->name().find("/") + 1));
1340 tooltip << Gtkmm2ext::markup_escape_text(*i);
1343 total_connection_count += port_connection_count;
1344 if (port->type() == dt) {
1345 typed_connection_count += port_connection_count;
1346 each_typed_port_has_one_connection &= (port_connection_count == 1);
1351 if (total_connection_count == 0) {
1352 tooltip << endl << _("Disconnected");
1355 if (typed_connection_count == 0) {
1360 /* Are all main-typed channels connected to the same route ? */
1362 boost::shared_ptr<ARDOUR::RouteList> routes = _session->get_routes ();
1363 for (ARDOUR::RouteList::const_iterator route = routes->begin();
1364 route != routes->end();
1366 boost::shared_ptr<IO> dest_io =
1367 for_input ? (*route)->output() : (*route)->input();
1368 if (io->bundle()->connected_to(dest_io->bundle(),
1371 label << Gtkmm2ext::markup_escape_text ((*route)->name());
1378 /* Are all main-typed channels connected to the same (user) bundle ? */
1380 boost::shared_ptr<ARDOUR::BundleList> bundles = _session->bundles ();
1381 for (ARDOUR::BundleList::iterator bundle = bundles->begin();
1382 bundle != bundles->end();
1384 if (boost::dynamic_pointer_cast<UserBundle> (*bundle) == 0)
1386 if (io->bundle()->connected_to(*bundle, _session->engine(),
1388 label << Gtkmm2ext::markup_escape_text ((*bundle)->name());
1395 /* Is each main-typed channel only connected to a physical output ? */
1396 if (!have_label && each_typed_port_has_one_connection) {
1397 ostringstream temp_label;
1398 vector<string> phys;
1399 string playorcapture;
1401 _session->engine().get_physical_inputs(dt, phys);
1402 playorcapture = "capture_";
1404 _session->engine().get_physical_outputs(dt, phys);
1405 playorcapture = "playback_";
1407 for (PortSet::iterator port = io->ports().begin(dt);
1408 port != io->ports().end(dt);
1411 for (vector<string>::iterator s = phys.begin();
1414 if (!port->connected_to(*s))
1416 pn = AudioEngine::instance()->get_pretty_name_by_name(*s);
1418 string::size_type start = (*s).find(playorcapture);
1419 if (start != string::npos) {
1420 pn = (*s).substr(start + playorcapture.size());
1426 temp_label.str(""); /* erase the failed attempt */
1429 if (port != io->ports().begin(dt))
1434 if (!temp_label.str().empty()) {
1435 label << temp_label.str();
1440 /* Is each main-typed channel connected to a single and different port with
1441 * the same client name (e.g. another JACK client) ? */
1442 if (!have_label && each_typed_port_has_one_connection) {
1443 string maybe_client = "";
1444 vector<string> connections;
1445 for (PortSet::iterator port = io->ports().begin(dt);
1446 port != io->ports().end(dt);
1448 port_connections.clear();
1449 port->get_connections(port_connections);
1450 string connection = port_connections.front();
1452 vector<string>::iterator i = connections.begin();
1453 while (i != connections.end() && *i != connection) {
1456 if (i != connections.end())
1457 break; /* duplicate connection */
1458 connections.push_back(connection);
1460 connection = connection.substr(0, connection.find(":"));
1461 if (maybe_client.empty())
1462 maybe_client = connection;
1463 if (maybe_client != connection)
1466 if (connections.size() == io->n_ports().n(dt)) {
1467 label << maybe_client;
1472 /* Odd configuration */
1474 label << "*" << total_connection_count << "*";
1477 if (total_connection_count > typed_connection_count) {
1478 label << "\u2295"; /* circled plus */
1481 /* Actually set the properties of the button */
1482 char * cstr = new char[tooltip.str().size() + 1];
1483 strcpy(cstr, tooltip.str().c_str());
1486 input_button.set_text (label.str());
1487 set_tooltip (&input_button, cstr);
1489 output_button.set_text (label.str());
1490 set_tooltip (&output_button, cstr);
1497 MixerStrip::update_input_display ()
1499 update_io_button (true);
1500 panners.setup_pan ();
1502 if (has_audio_outputs ()) {
1503 panners.show_all ();
1505 panners.hide_all ();
1511 MixerStrip::update_output_display ()
1513 update_io_button (false);
1514 gpm.setup_meters ();
1515 panners.setup_pan ();
1517 if (has_audio_outputs ()) {
1518 panners.show_all ();
1520 panners.hide_all ();
1525 MixerStrip::fast_update ()
1527 gpm.update_meters ();
1531 MixerStrip::diskstream_changed ()
1533 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&MixerStrip::update_diskstream_display, this));
1537 MixerStrip::io_changed_proxy ()
1539 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_panner_choices));
1540 Glib::signal_idle().connect_once (sigc::mem_fun (*this, &MixerStrip::update_trim_control));
1544 MixerStrip::port_connected_or_disconnected (boost::weak_ptr<Port> wa, boost::weak_ptr<Port> wb)
1546 boost::shared_ptr<Port> a = wa.lock ();
1547 boost::shared_ptr<Port> b = wb.lock ();
1549 if ((a && _route->input()->has_port (a)) || (b && _route->input()->has_port (b))) {
1550 update_input_display ();
1551 set_width_enum (_width, this);
1554 if ((a && _route->output()->has_port (a)) || (b && _route->output()->has_port (b))) {
1555 update_output_display ();
1556 set_width_enum (_width, this);
1561 MixerStrip::setup_comment_button ()
1563 std::string comment = _route->comment();
1565 set_tooltip (_comment_button, comment.empty() ? _("Click to add/edit comments") : _route->comment());
1567 if (comment.empty ()) {
1568 _comment_button.set_name ("generic button");
1569 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1573 _comment_button.set_name ("comment button");
1575 string::size_type pos = comment.find_first_of (" \t\n");
1576 if (pos != string::npos) {
1577 comment = comment.substr (0, pos);
1579 if (comment.empty()) {
1580 _comment_button.set_text (_width == Wide ? _("Comments") : _("Cmt"));
1582 _comment_button.set_text (comment);
1587 MixerStrip::select_route_group (GdkEventButton *ev)
1589 using namespace Menu_Helpers;
1591 if (ev->button == 1) {
1593 if (group_menu == 0) {
1595 PropertyList* plist = new PropertyList();
1597 plist->add (Properties::group_gain, true);
1598 plist->add (Properties::group_mute, true);
1599 plist->add (Properties::group_solo, true);
1601 group_menu = new RouteGroupMenu (_session, plist);
1605 r.push_back (route ());
1606 group_menu->build (r);
1608 RouteGroup *rg = _route->route_group();
1610 Gtkmm2ext::anchored_menu_popup(group_menu->menu(), &group_button,
1611 rg ? rg->name() : _("No Group"),
1619 MixerStrip::route_group_changed ()
1621 ENSURE_GUI_THREAD (*this, &MixerStrip::route_group_changed)
1623 RouteGroup *rg = _route->route_group();
1626 group_button.set_text (PBD::short_version (rg->name(), 5));
1630 group_button.set_text (_("Grp"));
1633 group_button.set_text (_("~G"));
1640 MixerStrip::route_color_changed ()
1642 using namespace ARDOUR_UI_UTILS;
1643 name_button.modify_bg (STATE_NORMAL, color());
1644 number_label.set_fixed_colors (gdk_color_to_rgba (color()), gdk_color_to_rgba (color()));
1645 reset_strip_style ();
1649 MixerStrip::show_passthru_color ()
1651 reset_strip_style ();
1656 MixerStrip::help_count_plugins (boost::weak_ptr<Processor> p)
1658 boost::shared_ptr<Processor> processor (p.lock ());
1659 if (!processor || !processor->display_to_user()) {
1662 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (processor);
1664 if (pi && pi->is_channelstrip ()) {
1669 ++_plugin_insert_cnt;
1673 MixerStrip::build_route_ops_menu ()
1675 using namespace Menu_Helpers;
1676 route_ops_menu = new Menu;
1677 route_ops_menu->set_name ("ArdourContextMenu");
1679 MenuList& items = route_ops_menu->items();
1681 items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
1683 items.push_back (MenuElem (_("Comments..."), sigc::mem_fun (*this, &RouteUI::open_comment_editor)));
1685 items.push_back (MenuElem (_("Inputs..."), sigc::mem_fun (*this, &RouteUI::edit_input_configuration)));
1687 items.push_back (MenuElem (_("Outputs..."), sigc::mem_fun (*this, &RouteUI::edit_output_configuration)));
1689 if (!Profile->get_mixbus()) {
1690 items.push_back (SeparatorElem());
1693 if (!_route->is_master()
1695 && !_route->mixbus()
1698 if (Profile->get_mixbus()) {
1699 items.push_back (SeparatorElem());
1701 items.push_back (MenuElem (_("Save As Template..."), sigc::mem_fun(*this, &RouteUI::save_as_template)));
1704 if (!Profile->get_mixbus()) {
1705 items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteUI::route_rename)));
1706 /* do not allow rename if the track is record-enabled */
1707 items.back().set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
1710 items.push_back (SeparatorElem());
1711 items.push_back (CheckMenuElem (_("Active")));
1712 Gtk::CheckMenuItem* i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1713 i->set_active (_route->active());
1714 i->set_sensitive(! _session->transport_rolling());
1715 i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), !_route->active(), false));
1717 if (!Profile->get_mixbus ()) {
1718 items.push_back (SeparatorElem());
1719 items.push_back (CheckMenuElem (_("Strict I/O")));
1720 i = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1721 i->set_active (_route->strict_io());
1722 i->signal_activate().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*_route, &Route::set_strict_io), !_route->strict_io())));
1726 items.push_back (SeparatorElem());
1728 Gtk::Menu* dio_menu = new Menu;
1729 MenuList& dio_items = dio_menu->items();
1730 dio_items.push_back (MenuElem (_("Record Pre-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPreFader)));
1731 dio_items.push_back (MenuElem (_("Record Post-Fader"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOPostFader)));
1732 dio_items.push_back (MenuElem (_("Custom Record+Playback Positions"), sigc::bind (sigc::mem_fun (*this, &RouteUI::set_disk_io_point), DiskIOCustom)));
1734 items.push_back (MenuElem (_("Disk I/O..."), *dio_menu));
1737 _plugin_insert_cnt = 0;
1738 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::help_count_plugins));
1739 if (_plugin_insert_cnt > 0) {
1740 items.push_back (SeparatorElem());
1741 items.push_back (MenuElem (_("Pin Connections..."), sigc::mem_fun (*this, &RouteUI::manage_pins)));
1744 if (boost::dynamic_pointer_cast<MidiTrack>(_route) || _route->the_instrument ()) {
1745 items.push_back (MenuElem (_("Patch Selector..."),
1746 sigc::mem_fun(*this, &RouteUI::select_midi_patch)));
1749 if (_route->the_instrument () && _route->the_instrument ()->output_streams().n_audio() > 2) {
1750 // TODO ..->n_audio() > 1 && separate_output_groups) hard to check here every time.
1751 items.push_back (MenuElem (_("Fan out to Busses"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), true, true)));
1752 items.push_back (MenuElem (_("Fan out to Tracks"), sigc::bind (sigc::mem_fun (*this, &RouteUI::fan_out), false, true)));
1755 items.push_back (SeparatorElem());
1756 items.push_back (MenuElem (_("Adjust Latency..."), sigc::mem_fun (*this, &RouteUI::adjust_latency)));
1758 items.push_back (SeparatorElem());
1759 items.push_back (CheckMenuElem (_("Protect Against Denormals"), sigc::mem_fun (*this, &RouteUI::toggle_denormal_protection)));
1760 denormal_menu_item = dynamic_cast<Gtk::CheckMenuItem *> (&items.back());
1761 denormal_menu_item->set_active (_route->denormal_protection());
1764 /* note that this relies on selection being shared across editor and
1765 mixer (or global to the backend, in the future), which is the only
1766 sane thing for users anyway.
1769 StripableTimeAxisView* stav = PublicEditor::instance().get_stripable_time_axis_by_id (_route->id());
1771 Selection& selection (PublicEditor::instance().get_selection());
1772 if (!selection.selected (stav)) {
1773 selection.set (stav);
1776 if (!_route->is_master()) {
1777 items.push_back (SeparatorElem());
1778 items.push_back (MenuElem (_("Duplicate..."), sigc::mem_fun (*this, &RouteUI::duplicate_selected_routes)));
1781 items.push_back (SeparatorElem());
1782 items.push_back (MenuElem (_("Remove"), sigc::mem_fun(PublicEditor::instance(), &PublicEditor::remove_tracks)));
1788 MixerStrip::name_button_button_press (GdkEventButton* ev)
1790 if (ev->button == 1 || ev->button == 3) {
1791 list_route_operations ();
1793 if (ev->button == 1) {
1794 Gtkmm2ext::anchored_menu_popup(route_ops_menu, &name_button, "",
1797 route_ops_menu->popup (3, ev->time);
1807 MixerStrip::number_button_button_press (GdkEventButton* ev)
1809 if ( ev->button == 3 ) {
1810 list_route_operations ();
1812 route_ops_menu->popup (1, ev->time);
1821 MixerStrip::list_route_operations ()
1823 delete route_ops_menu;
1824 build_route_ops_menu ();
1828 MixerStrip::set_selected (bool yn)
1830 AxisView::set_selected (yn);
1833 global_frame.set_shadow_type (Gtk::SHADOW_ETCHED_OUT);
1834 global_frame.set_name ("MixerStripSelectedFrame");
1836 global_frame.set_shadow_type (Gtk::SHADOW_IN);
1837 global_frame.set_name ("MixerStripFrame");
1840 global_frame.queue_draw ();
1843 // processor_box.deselect_all_processors();
1847 MixerStrip::route_property_changed (const PropertyChange& what_changed)
1849 if (what_changed.contains (ARDOUR::Properties::name)) {
1855 MixerStrip::name_changed ()
1859 name_button.set_text (_route->name());
1862 name_button.set_text (PBD::short_version (_route->name(), 5));
1866 set_tooltip (name_button, Gtkmm2ext::markup_escape_text(_route->name()));
1868 if (_session->config.get_track_name_number()) {
1869 const int64_t track_number = _route->track_number ();
1870 if (track_number == 0) {
1871 number_label.set_text ("-");
1873 number_label.set_text (PBD::to_string (abs(_route->track_number ())));
1876 number_label.set_text ("");
1881 MixerStrip::input_button_resized (Gtk::Allocation& alloc)
1883 input_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1887 MixerStrip::output_button_resized (Gtk::Allocation& alloc)
1889 output_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1893 MixerStrip::name_button_resized (Gtk::Allocation& alloc)
1895 name_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1899 MixerStrip::comment_button_resized (Gtk::Allocation& alloc)
1901 _comment_button.set_layout_ellipsize_width (alloc.get_width() * PANGO_SCALE);
1905 MixerStrip::width_button_pressed (GdkEventButton* ev)
1907 if (ev->button != 1) {
1911 if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier | Keyboard::TertiaryModifier)) && _mixer_owned) {
1914 _mixer.set_strip_width (Narrow, true);
1918 _mixer.set_strip_width (Wide, true);
1924 set_width_enum (Narrow, this);
1927 set_width_enum (Wide, this);
1936 MixerStrip::hide_clicked ()
1938 // LAME fix to reset the button status for when it is redisplayed (part 1)
1939 hide_button.set_sensitive(false);
1942 Hiding(); /* EMIT_SIGNAL */
1944 _mixer.hide_strip (this);
1948 hide_button.set_sensitive(true);
1952 MixerStrip::set_embedded (bool yn)
1958 MixerStrip::map_frozen ()
1960 ENSURE_GUI_THREAD (*this, &MixerStrip::map_frozen)
1962 boost::shared_ptr<AudioTrack> at = audio_track();
1965 switch (at->freeze_state()) {
1966 case AudioTrack::Frozen:
1967 processor_box.set_sensitive (false);
1968 hide_redirect_editors ();
1971 processor_box.set_sensitive (true);
1972 // XXX need some way, maybe, to retoggle redirect editors
1976 processor_box.set_sensitive (true);
1978 RouteUI::map_frozen ();
1982 MixerStrip::hide_redirect_editors ()
1984 _route->foreach_processor (sigc::mem_fun (*this, &MixerStrip::hide_processor_editor));
1988 MixerStrip::hide_processor_editor (boost::weak_ptr<Processor> p)
1990 boost::shared_ptr<Processor> processor (p.lock ());
1995 Gtk::Window* w = processor_box.get_processor_ui (processor);
2003 MixerStrip::reset_strip_style ()
2005 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2007 gpm.set_fader_name ("SendStripBase");
2011 if (is_midi_track()) {
2012 if (_route->active()) {
2013 set_name ("MidiTrackStripBase");
2015 set_name ("MidiTrackStripBaseInactive");
2017 gpm.set_fader_name ("MidiTrackFader");
2018 } else if (is_audio_track()) {
2019 if (_route->active()) {
2020 set_name ("AudioTrackStripBase");
2022 set_name ("AudioTrackStripBaseInactive");
2024 gpm.set_fader_name ("AudioTrackFader");
2026 if (_route->active()) {
2027 set_name ("AudioBusStripBase");
2029 set_name ("AudioBusStripBaseInactive");
2031 gpm.set_fader_name ("AudioBusFader");
2033 /* (no MIDI busses yet) */
2040 MixerStrip::engine_stopped ()
2045 MixerStrip::engine_running ()
2050 MixerStrip::meter_point_string (MeterPoint mp)
2063 case MeterPostFader:
2080 return S_("Meter|In");
2084 return S_("Meter|Pr");
2087 case MeterPostFader:
2088 return S_("Meter|Po");
2092 return S_("Meter|O");
2097 return S_("Meter|C");
2106 /** Called when the monitor-section state */
2108 MixerStrip::monitor_changed ()
2110 assert (monitor_section_button);
2111 if (_session->monitor_active()) {
2112 monitor_section_button->set_name ("master monitor section button active");
2114 monitor_section_button->set_name ("master monitor section button normal");
2118 /** Called when the metering point has changed */
2120 MixerStrip::meter_changed ()
2122 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2123 gpm.setup_meters ();
2124 // reset peak when meter point changes
2125 gpm.reset_peak_display();
2128 /** The bus that we are displaying sends to has changed, or been turned off.
2129 * @param send_to New bus that we are displaying sends to, or 0.
2132 MixerStrip::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2134 RouteUI::bus_send_display_changed (send_to);
2137 boost::shared_ptr<Send> send = _route->internal_send_for (send_to);
2142 revert_to_default_display ();
2145 revert_to_default_display ();
2150 MixerStrip::drop_send ()
2152 boost::shared_ptr<Send> current_send;
2154 if (_current_delivery && ((current_send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0)) {
2155 current_send->set_metering (false);
2158 send_gone_connection.disconnect ();
2159 input_button.set_sensitive (true);
2160 output_button.set_sensitive (true);
2161 group_button.set_sensitive (true);
2162 set_invert_sensitive (true);
2163 gpm.meter_point_button.set_sensitive (true);
2164 mute_button->set_sensitive (true);
2165 solo_button->set_sensitive (true);
2166 solo_isolated_led->set_sensitive (true);
2167 solo_safe_led->set_sensitive (true);
2168 monitor_input_button->set_sensitive (true);
2169 monitor_disk_button->set_sensitive (true);
2170 _comment_button.set_sensitive (true);
2171 trim_control.set_sensitive (true);
2172 if (midi_input_enable_button) {
2173 midi_input_enable_button->set_sensitive (true);
2175 control_slave_ui.set_sensitive (true);
2176 RouteUI::check_rec_enable_sensitivity ();
2177 set_button_names (); // update solo button visual state
2181 MixerStrip::set_current_delivery (boost::shared_ptr<Delivery> d)
2183 _current_delivery = d;
2184 DeliveryChanged (_current_delivery);
2188 MixerStrip::show_send (boost::shared_ptr<Send> send)
2194 set_current_delivery (send);
2196 send->meter()->set_type(_route->shared_peak_meter()->get_type());
2197 send->set_metering (true);
2198 _current_delivery->DropReferences.connect (send_gone_connection, invalidator (*this), boost::bind (&MixerStrip::revert_to_default_display, this), gui_context());
2200 gain_meter().set_controls (_route, send->meter(), send->amp(), send->gain_control());
2201 gain_meter().setup_meters ();
2203 uint32_t const in = _current_delivery->pans_required();
2204 uint32_t const out = _current_delivery->pan_outs();
2206 panner_ui().set_panner (_current_delivery->panner_shell(), _current_delivery->panner());
2207 panner_ui().set_available_panners(PannerManager::instance().PannerManager::get_available_panners(in, out));
2208 panner_ui().setup_pan ();
2209 panner_ui().set_send_drawing_mode (true);
2210 panner_ui().show_all ();
2212 input_button.set_sensitive (false);
2213 group_button.set_sensitive (false);
2214 set_invert_sensitive (false);
2215 gpm.meter_point_button.set_sensitive (false);
2216 mute_button->set_sensitive (false);
2217 solo_button->set_sensitive (false);
2218 rec_enable_button->set_sensitive (false);
2219 solo_isolated_led->set_sensitive (false);
2220 solo_safe_led->set_sensitive (false);
2221 monitor_input_button->set_sensitive (false);
2222 monitor_disk_button->set_sensitive (false);
2223 _comment_button.set_sensitive (false);
2224 trim_control.set_sensitive (false);
2225 if (midi_input_enable_button) {
2226 midi_input_enable_button->set_sensitive (false);
2228 control_slave_ui.set_sensitive (false);
2230 if (boost::dynamic_pointer_cast<InternalSend>(send)) {
2231 output_button.set_sensitive (false);
2234 reset_strip_style ();
2238 MixerStrip::revert_to_default_display ()
2242 set_current_delivery (_route->main_outs ());
2244 gain_meter().set_controls (_route, _route->shared_peak_meter(), _route->amp(), _route->gain_control());
2245 gain_meter().setup_meters ();
2247 panner_ui().set_panner (_route->main_outs()->panner_shell(), _route->main_outs()->panner());
2248 update_panner_choices();
2249 panner_ui().setup_pan ();
2250 panner_ui().set_send_drawing_mode (false);
2252 if (has_audio_outputs ()) {
2253 panners.show_all ();
2255 panners.hide_all ();
2258 reset_strip_style ();
2262 MixerStrip::set_button_names ()
2266 mute_button->set_text (_("Mute"));
2267 monitor_input_button->set_text (_("In"));
2268 monitor_disk_button->set_text (_("Disk"));
2269 if (monitor_section_button) {
2270 monitor_section_button->set_text (_("Mon"));
2273 if (_route && _route->solo_safe_control()->solo_safe()) {
2274 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2276 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2278 if (!Config->get_solo_control_is_listen_control()) {
2279 solo_button->set_text (_("Solo"));
2281 switch (Config->get_listen_position()) {
2282 case AfterFaderListen:
2283 solo_button->set_text (_("AFL"));
2285 case PreFaderListen:
2286 solo_button->set_text (_("PFL"));
2290 solo_isolated_led->set_text (_("Iso"));
2291 solo_safe_led->set_text (S_("SoloLock|Lock"));
2295 mute_button->set_text (S_("Mute|M"));
2296 monitor_input_button->set_text (S_("MonitorInput|I"));
2297 monitor_disk_button->set_text (S_("MonitorDisk|D"));
2298 if (monitor_section_button) {
2299 monitor_section_button->set_text (S_("Mon|O"));
2302 if (_route && _route->solo_safe_control()->solo_safe()) {
2303 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
2305 solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
2307 if (!Config->get_solo_control_is_listen_control()) {
2308 solo_button->set_text (S_("Solo|S"));
2310 switch (Config->get_listen_position()) {
2311 case AfterFaderListen:
2312 solo_button->set_text (S_("AfterFader|A"));
2314 case PreFaderListen:
2315 solo_button->set_text (S_("Prefader|P"));
2320 solo_isolated_led->set_text (S_("SoloIso|I"));
2321 solo_safe_led->set_text (S_("SoloLock|L"));
2326 gpm.meter_point_button.set_text (meter_point_string (_route->meter_point()));
2328 gpm.meter_point_button.set_text ("");
2333 MixerStrip::plugin_selector()
2335 return _mixer.plugin_selector();
2339 MixerStrip::hide_things ()
2341 processor_box.hide_things ();
2345 MixerStrip::input_active_button_press (GdkEventButton*)
2347 /* nothing happens on press */
2352 MixerStrip::input_active_button_release (GdkEventButton* ev)
2354 boost::shared_ptr<MidiTrack> mt = midi_track ();
2360 boost::shared_ptr<RouteList> rl (new RouteList);
2362 rl->push_back (route());
2364 _session->set_exclusive_input_active (rl, !mt->input_active(),
2365 Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)));
2371 MixerStrip::midi_input_status_changed ()
2373 if (midi_input_enable_button) {
2374 boost::shared_ptr<MidiTrack> mt = midi_track ();
2376 midi_input_enable_button->set_active (mt->input_active ());
2381 MixerStrip::state_id () const
2383 return string_compose ("strip %1", _route->id().to_s());
2387 MixerStrip::parameter_changed (string p)
2389 if (p == _visibility.get_state_name()) {
2390 /* The user has made changes to the mixer strip visibility, so get
2391 our VisibilityGroup to reflect these changes in our widgets.
2393 _visibility.set_state (UIConfiguration::instance().get_mixer_strip_visibility ());
2394 } else if (p == "track-name-number") {
2396 update_track_number_visibility();
2397 } else if (p == "use-monitor-bus") {
2398 if (monitor_section_button) {
2399 if (mute_button->get_parent()) {
2400 mute_button->get_parent()->remove(*mute_button);
2402 if (monitor_section_button->get_parent()) {
2403 monitor_section_button->get_parent()->remove(*monitor_section_button);
2405 if (Config->get_use_monitor_bus ()) {
2406 mute_solo_table.attach (*mute_button, 0, 1, 0, 1);
2407 mute_solo_table.attach (*monitor_section_button, 1, 2, 0, 1);
2408 mute_button->show();
2409 monitor_section_button->show();
2411 mute_solo_table.attach (*mute_button, 0, 2, 0, 1);
2412 mute_button->show();
2418 /** Called to decide whether the solo isolate / solo lock button visibility should
2419 * be overridden from that configured by the user. We do this for the master bus.
2421 * @return optional value that is present if visibility state should be overridden.
2423 boost::optional<bool>
2424 MixerStrip::override_solo_visibility () const
2426 if (_route && _route->is_master ()) {
2427 return boost::optional<bool> (false);
2430 return boost::optional<bool> ();
2434 MixerStrip::add_input_port (DataType t)
2436 _route->input()->add_port ("", this, t);
2440 MixerStrip::add_output_port (DataType t)
2442 _route->output()->add_port ("", this, t);
2446 MixerStrip::route_active_changed ()
2448 reset_strip_style ();
2452 MixerStrip::copy_processors ()
2454 processor_box.processor_operation (ProcessorBox::ProcessorsCopy);
2458 MixerStrip::cut_processors ()
2460 processor_box.processor_operation (ProcessorBox::ProcessorsCut);
2464 MixerStrip::paste_processors ()
2466 processor_box.processor_operation (ProcessorBox::ProcessorsPaste);
2470 MixerStrip::select_all_processors ()
2472 processor_box.processor_operation (ProcessorBox::ProcessorsSelectAll);
2476 MixerStrip::deselect_all_processors ()
2478 processor_box.processor_operation (ProcessorBox::ProcessorsSelectNone);
2482 MixerStrip::delete_processors ()
2484 return processor_box.processor_operation (ProcessorBox::ProcessorsDelete);
2488 MixerStrip::toggle_processors ()
2490 processor_box.processor_operation (ProcessorBox::ProcessorsToggleActive);
2494 MixerStrip::ab_plugins ()
2496 processor_box.processor_operation (ProcessorBox::ProcessorsAB);
2500 MixerStrip::level_meter_button_press (GdkEventButton* ev)
2502 if (_current_delivery && boost::dynamic_pointer_cast<Send>(_current_delivery)) {
2505 if (ev->button == 3) {
2506 popup_level_meter_menu (ev);
2514 MixerStrip::popup_level_meter_menu (GdkEventButton* ev)
2516 using namespace Gtk::Menu_Helpers;
2518 Gtk::Menu* m = manage (new Menu);
2519 MenuList& items = m->items ();
2521 RadioMenuItem::Group group;
2523 _suspend_menu_callbacks = true;
2524 add_level_meter_item_point (items, group, _("Input"), MeterInput);
2525 add_level_meter_item_point (items, group, _("Pre Fader"), MeterPreFader);
2526 add_level_meter_item_point (items, group, _("Post Fader"), MeterPostFader);
2527 add_level_meter_item_point (items, group, _("Output"), MeterOutput);
2528 add_level_meter_item_point (items, group, _("Custom"), MeterCustom);
2530 if (gpm.meter_channels().n_audio() == 0) {
2531 m->popup (ev->button, ev->time);
2532 _suspend_menu_callbacks = false;
2536 RadioMenuItem::Group tgroup;
2537 items.push_back (SeparatorElem());
2539 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak), MeterPeak);
2540 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterPeak0dB), MeterPeak0dB);
2541 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterKrms), MeterKrms);
2542 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1DIN), MeterIEC1DIN);
2543 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC1NOR), MeterIEC1NOR);
2544 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2BBC), MeterIEC2BBC);
2545 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterIEC2EBU), MeterIEC2EBU);
2546 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK20), MeterK20);
2547 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK14), MeterK14);
2548 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterK12), MeterK12);
2549 add_level_meter_item_type (items, tgroup, ArdourMeter::meter_type_string(MeterVU), MeterVU);
2552 if (_route->is_master()) {
2555 else if (boost::dynamic_pointer_cast<AudioTrack>(_route) == 0
2556 && boost::dynamic_pointer_cast<MidiTrack>(_route) == 0) {
2557 /* non-master bus */
2560 else if (boost::dynamic_pointer_cast<MidiTrack>(_route)) {
2567 MeterType cmt = _route->meter_type();
2568 const std::string cmn = ArdourMeter::meter_type_string(cmt);
2570 items.push_back (SeparatorElem());
2571 items.push_back (MenuElem (string_compose(_("Change all in Group to %1"), cmn),
2572 sigc::bind (SetMeterTypeMulti, -1, _route->route_group(), cmt)));
2573 items.push_back (MenuElem (string_compose(_("Change all to %1"), cmn),
2574 sigc::bind (SetMeterTypeMulti, 0, _route->route_group(), cmt)));
2575 items.push_back (MenuElem (string_compose(_("Change same track-type to %1"), cmn),
2576 sigc::bind (SetMeterTypeMulti, _strip_type, _route->route_group(), cmt)));
2578 m->popup (ev->button, ev->time);
2579 _suspend_menu_callbacks = false;
2583 MixerStrip::add_level_meter_item_point (Menu_Helpers::MenuList& items,
2584 RadioMenuItem::Group& group, string const & name, MeterPoint point)
2586 using namespace Menu_Helpers;
2588 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_point), point)));
2589 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2590 i->set_active (_route->meter_point() == point);
2594 MixerStrip::set_meter_point (MeterPoint p)
2596 if (_suspend_menu_callbacks) return;
2597 _route->set_meter_point (p);
2601 MixerStrip::add_level_meter_item_type (Menu_Helpers::MenuList& items,
2602 RadioMenuItem::Group& group, string const & name, MeterType type)
2604 using namespace Menu_Helpers;
2606 items.push_back (RadioMenuElem (group, name, sigc::bind (sigc::mem_fun (*this, &MixerStrip::set_meter_type), type)));
2607 RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
2608 i->set_active (_route->meter_type() == type);
2612 MixerStrip::set_meter_type (MeterType t)
2614 if (_suspend_menu_callbacks) return;
2619 MixerStrip::update_track_number_visibility ()
2621 DisplaySuspender ds;
2622 bool show_label = _session->config.get_track_name_number();
2624 if (_route && _route->is_master()) {
2629 number_label.show ();
2630 // see ArdourButton::on_size_request(), we should probably use a global size-group here instead.
2631 // except the width of the number label is subtracted from the name-hbox, so we
2632 // need to explictly calculate it anyway until the name-label & entry become ArdourWidgets.
2633 int tnw = (2 + std::max(2u, _session->track_number_decimals())) * number_label.char_pixel_width();
2635 number_label.set_size_request(tnw, -1);
2636 number_label.show ();
2638 number_label.hide ();
2643 MixerStrip::color () const
2645 return route_color ();
2649 MixerStrip::marked_for_display () const
2651 return !_route->presentation_info().hidden();
2655 MixerStrip::set_marked_for_display (bool yn)
2657 return RouteUI::mark_hidden (!yn);