2 Copyright (C) 2002-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.
21 #include <boost/algorithm/string.hpp>
23 #include <gtkmm2ext/gtk_ui.h>
24 #include <gtkmm2ext/choice.h>
25 #include <gtkmm2ext/doi.h>
26 #include <gtkmm2ext/bindable_button.h>
27 #include <gtkmm2ext/barcontroller.h>
28 #include <gtkmm2ext/gtk_ui.h>
29 #include <gtkmm2ext/utils.h>
31 #include "pbd/memento_command.h"
32 #include "pbd/stacktrace.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour/dB.h"
37 #include "ardour/route_group.h"
38 #include "ardour/solo_isolate_control.h"
39 #include "ardour/vca.h"
40 #include "ardour/vca_manager.h"
41 #include "ardour/audio_track.h"
42 #include "ardour/audio_port.h"
43 #include "ardour/audioengine.h"
44 #include "ardour/filename_extensions.h"
45 #include "ardour/midi_track.h"
46 #include "ardour/monitor_control.h"
47 #include "ardour/internal_send.h"
48 #include "ardour/panner_shell.h"
49 #include "ardour/profile.h"
50 #include "ardour/phase_control.h"
51 #include "ardour/send.h"
52 #include "ardour/route.h"
53 #include "ardour/session.h"
54 #include "ardour/template_utils.h"
56 #include "ardour_button.h"
57 #include "ardour_dialog.h"
58 #include "ardour_ui.h"
59 #include "automation_time_axis.h"
61 #include "group_tabs.h"
62 #include "gui_object.h"
63 #include "gui_thread.h"
65 #include "latency_gui.h"
66 #include "mixer_strip.h"
67 #include "plugin_pin_dialog.h"
69 #include "rgb_macros.h"
70 #include "route_time_axis.h"
73 #include "ui_config.h"
79 using namespace Gtkmm2ext;
80 using namespace ARDOUR;
81 using namespace ARDOUR_UI_UTILS;
85 uint32_t RouteUI::_max_invert_buttons = 3;
86 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
87 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
88 std::string RouteUI::program_port_prefix;
90 RouteUI::RouteUI (ARDOUR::Session* sess)
91 : monitor_input_button (0)
92 , monitor_disk_button (0)
100 , output_selector (0)
103 if (program_port_prefix.empty()) {
104 // compare to gtk2_ardour/port_group.cc
105 string lpn (PROGRAM_NAME);
106 boost::to_lower (lpn);
107 program_port_prefix = lpn + ":"; // e.g. "ardour:"
118 ARDOUR_UI::instance()->gui_object_state->remove_node (route_state_id());
121 _route.reset (); /* drop reference to route, so that it can be cleaned up */
122 route_connections.drop_connections ();
128 delete comment_window;
129 delete input_selector;
130 delete output_selector;
131 delete monitor_input_button;
132 delete monitor_disk_button;
135 send_blink_connection.disconnect ();
136 rec_blink_connection.disconnect ();
142 self_destruct = true;
148 pre_fader_mute_check = 0;
149 post_fader_mute_check = 0;
150 listen_mute_check = 0;
153 solo_isolated_check = 0;
154 solo_isolated_led = 0;
158 denormal_menu_item = 0;
161 multiple_mute_change = false;
162 multiple_solo_change = false;
163 _i_am_the_modifier = 0;
168 setup_invert_buttons ();
170 mute_button = manage (new ArdourButton);
171 mute_button->set_name ("mute button");
172 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
174 solo_button = manage (new ArdourButton);
175 solo_button->set_name ("solo button");
176 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
177 solo_button->set_no_show_all (true);
179 rec_enable_button = manage (new ArdourButton);
180 rec_enable_button->set_name ("record enable button");
181 rec_enable_button->set_icon (ArdourIcon::RecButton);
182 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
184 if (UIConfiguration::instance().get_blink_rec_arm()) {
185 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
188 show_sends_button = manage (new ArdourButton);
189 show_sends_button->set_name ("send alert button");
190 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
192 monitor_input_button = new ArdourButton (ArdourButton::default_elements);
193 monitor_input_button->set_name ("monitor button");
194 monitor_input_button->set_text (_("In"));
195 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
196 monitor_input_button->set_no_show_all (true);
198 monitor_disk_button = new ArdourButton (ArdourButton::default_elements);
199 monitor_disk_button->set_name ("monitor button");
200 monitor_disk_button->set_text (_("Disk"));
201 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
202 monitor_disk_button->set_no_show_all (true);
204 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
205 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
206 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
208 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
209 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
210 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (this, &RouteUI::parameter_changed));
212 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
213 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
215 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
216 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
218 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
219 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
220 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
221 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
223 monitor_input_button->set_distinct_led_click (false);
224 monitor_disk_button->set_distinct_led_click (false);
226 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
227 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
229 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
230 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
232 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
238 route_connections.drop_connections ();
246 denormal_menu_item = 0;
250 RouteUI::self_delete ()
256 RouteUI::set_route (boost::shared_ptr<Route> rp)
262 if (set_color_from_route()) {
263 set_color (gdk_color_to_rgba (AxisView::unique_random_color ()));
267 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
270 delete input_selector;
273 delete output_selector;
276 mute_button->set_controllable (_route->mute_control());
277 solo_button->set_controllable (_route->solo_control());
279 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
281 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
283 _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
284 _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
285 _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
286 _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
287 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
290 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
291 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
292 track_mode_changed();
296 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_property_changed, this, _1), gui_context());
297 _route->presentation_info().PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
299 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
301 if (_session->writable() && is_track()) {
302 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
304 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
305 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
307 rec_enable_button->show();
308 rec_enable_button->set_controllable (t->rec_enable_control());
310 if (is_midi_track()) {
311 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
312 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
317 /* this will work for busses and tracks, and needs to be called to
318 set up the name entry/name label display.
322 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
323 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
325 update_monitoring_display ();
328 mute_button->unset_flags (Gtk::CAN_FOCUS);
329 solo_button->unset_flags (Gtk::CAN_FOCUS);
333 if (_route->is_monitor() || _route->is_master()) {
334 solo_button->hide ();
341 setup_invert_buttons ();
342 set_invert_button_state ();
344 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
345 bus_send_display_changed (s);
347 update_mute_display ();
348 update_solo_display ();
350 if (!UIConfiguration::instance().get_blink_rec_arm()) {
351 blink_rec_display(true); // set initial rec-en button state
354 check_rec_enable_sensitivity ();
355 maybe_add_route_print_mgr ();
356 route_color_changed();
357 route_gui_changed (PropertyChange (Properties::selected));
361 RouteUI::polarity_changed ()
367 set_invert_button_state ();
371 RouteUI::mute_press (GdkEventButton* ev)
373 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
377 //if this is a binding action, let the ArdourButton handle it
378 if ( BindingProxy::is_bind_action(ev) )
381 multiple_mute_change = false;
383 if (Keyboard::is_context_menu_event (ev)) {
389 mute_menu->popup(0,ev->time);
395 if (Keyboard::is_button2_event (ev)) {
396 // button2-click is "momentary"
398 _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
401 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
403 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
405 /* toggle mute on everything (but
406 * exclude the master and monitor)
408 * because we are going to erase
409 * elements of the list we need to work
413 boost::shared_ptr<RouteList> copy (new RouteList);
415 *copy = *_session->get_routes ();
417 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
418 if ((*i)->is_master() || (*i)->is_monitor()) {
426 _mute_release->routes = copy;
430 _session->set_controls (route_list_to_control_list (copy, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
432 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
434 /* Primary-button1 inverts the implication of
435 the group being active. If the group is
436 active (for mute), then this modifier means
437 "do not apply to mute". If the group is
438 inactive (for mute), then this modifier
439 means "apply to route". This is all
440 accomplished by passing just the actual
441 route, along with the InverseGroup group
444 NOTE: Primary-button2 is MIDI learn.
447 boost::shared_ptr<RouteList> rl;
449 if (ev->button == 1) {
451 rl.reset (new RouteList);
452 rl->push_back (_route);
455 _mute_release->routes = rl;
459 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
464 /* plain click applies change to this route */
466 boost::shared_ptr<RouteList> rl (new RouteList);
467 rl->push_back (_route);
470 _mute_release->routes = rl;
473 _route->mute_control()->set_value (!_route->muted_by_self(), Controllable::UseGroup);
482 RouteUI::mute_release (GdkEventButton* /*ev*/)
486 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Stripable::mute_control), _mute_release->active, Controllable::UseGroup);
487 delete _mute_release;
495 RouteUI::edit_output_configuration ()
497 if (output_selector == 0) {
499 boost::shared_ptr<Send> send;
500 boost::shared_ptr<IO> output;
502 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
503 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
504 output = send->output();
506 output = _route->output ();
509 output = _route->output ();
512 output_selector = new IOSelectorWindow (_session, output);
515 if (output_selector->is_visible()) {
516 output_selector->get_toplevel()->get_window()->raise();
518 output_selector->present ();
521 //output_selector->set_keep_above (true);
525 RouteUI::edit_input_configuration ()
527 if (input_selector == 0) {
528 input_selector = new IOSelectorWindow (_session, _route->input());
531 if (input_selector->is_visible()) {
532 input_selector->get_toplevel()->get_window()->raise();
534 input_selector->present ();
537 //input_selector->set_keep_above (true);
541 RouteUI::solo_press(GdkEventButton* ev)
543 /* ignore double/triple clicks */
545 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
549 //if this is a binding action, let the ArdourButton handle it
550 if ( BindingProxy::is_bind_action(ev) )
553 multiple_solo_change = false;
555 if (Keyboard::is_context_menu_event (ev)) {
557 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
558 ! (solo_safe_led && solo_safe_led->is_visible())) {
560 if (solo_menu == 0) {
564 solo_menu->popup (1, ev->time);
569 if (Keyboard::is_button2_event (ev)) {
571 // button2-click is "momentary"
572 _solo_release = new SoloMuteRelease (_route->self_soloed());
575 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
577 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
579 /* Primary-Tertiary-click applies change to all routes */
582 _solo_release->routes = _session->get_routes ();
586 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
588 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
590 // Primary-Secondary-click: exclusively solo this track
593 _solo_release->exclusive = true;
595 boost::shared_ptr<RouteList> routes = _session->get_routes();
597 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
598 if ((*i)->soloed ()) {
599 _solo_release->routes_on->push_back (*i);
601 _solo_release->routes_off->push_back (*i);
606 if (Config->get_solo_control_is_listen_control()) {
607 /* ??? we need a just_one_listen() method */
610 _route->solo_control()->set_value (1.0, Controllable::NoGroup);
613 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
615 // shift-click: toggle solo isolated status
617 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
618 delete _solo_release;
621 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
623 /* Primary-button1: solo mix group.
624 NOTE: Primary-button2 is MIDI learn.
627 /* Primary-button1 applies change to the mix group even if it is not active
628 NOTE: Primary-button2 is MIDI learn.
631 boost::shared_ptr<RouteList> rl;
633 if (ev->button == 1) {
635 /* Primary-button1 inverts the implication of
636 the group being active. If the group is
637 active (for solo), then this modifier means
638 "do not apply to solo". If the group is
639 inactive (for mute), then this modifier
640 means "apply to route". This is all
641 accomplished by passing just the actual
642 route, along with the InverseGroup group
645 NOTE: Primary-button2 is MIDI learn.
648 rl.reset (new RouteList);
649 rl->push_back (_route);
652 _solo_release->routes = rl;
657 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
660 delete _solo_release;
665 /* click: solo this route */
667 boost::shared_ptr<RouteList> rl (new RouteList);
668 rl->push_back (route());
671 _solo_release->routes = rl;
675 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), !_route->self_soloed(), Controllable::UseGroup);
684 RouteUI::solo_release (GdkEventButton* /*ev*/)
688 if (_solo_release->exclusive) {
692 _session->set_controls (route_list_to_control_list (_solo_release->routes, &Stripable::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
695 delete _solo_release;
703 RouteUI::rec_enable_press(GdkEventButton* ev)
705 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
709 //if this is a binding action, let the ArdourButton handle it
710 if ( BindingProxy::is_bind_action(ev) )
713 if (!_session->engine().connected()) {
714 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
719 if (is_midi_track()) {
721 /* rec-enable button exits from step editing */
723 if (midi_track()->step_editing()) {
724 midi_track()->set_step_editing (false);
729 if (is_track() && rec_enable_button) {
731 if (Keyboard::is_button2_event (ev)) {
733 //rec arm does not have a momentary mode
736 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
739 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
741 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
743 /* Primary-button1 applies change to the route group (even if it is not active)
744 NOTE: Primary-button2 is MIDI learn.
747 if (ev->button == 1) {
749 boost::shared_ptr<RouteList> rl;
751 rl.reset (new RouteList);
752 rl->push_back (_route);
755 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
758 } else if (Keyboard::is_context_menu_event (ev)) {
760 /* do this on release */
764 boost::shared_ptr<Track> trk = track();
765 trk->rec_enable_control()->set_value (!trk->rec_enable_control()->get_value(), Controllable::UseGroup);
773 RouteUI::update_monitoring_display ()
779 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
785 MonitorState ms = t->monitoring_state();
787 if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
788 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
790 if (ms & MonitoringInput) {
791 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
793 monitor_input_button->unset_active_state ();
797 if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
798 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
800 if (ms & MonitoringDisk) {
801 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
803 monitor_disk_button->unset_active_state ();
809 RouteUI::monitor_input_press(GdkEventButton*)
815 RouteUI::monitor_input_release(GdkEventButton* ev)
817 return monitor_release (ev, MonitorInput);
821 RouteUI::monitor_disk_press (GdkEventButton*)
827 RouteUI::monitor_disk_release (GdkEventButton* ev)
829 return monitor_release (ev, MonitorDisk);
833 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
835 if (ev->button != 1) {
839 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
846 boost::shared_ptr<RouteList> rl;
848 /* XXX for now, monitoring choices are orthogonal. cue monitoring
849 will follow in 3.X but requires mixing the input and playback (disk)
850 signal together, which requires yet more buffers.
853 if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
854 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
856 /* this line will change when the options are non-orthogonal */
857 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
861 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
862 rl = _session->get_routes ();
864 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
865 if (_route->route_group() && _route->route_group()->is_monitoring()) {
866 rl = _route->route_group()->route_list();
868 rl.reset (new RouteList);
869 rl->push_back (route());
872 rl.reset (new RouteList);
873 rl->push_back (route());
877 _session->set_controls (route_list_to_control_list (rl, &Stripable::monitoring_control), (double) mc, Controllable::UseGroup);
883 RouteUI::build_record_menu ()
886 record_menu = new Menu;
887 record_menu->set_name ("ArdourContextMenu");
888 using namespace Menu_Helpers;
889 MenuList& items = record_menu->items();
891 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
892 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
894 if (is_midi_track()) {
895 items.push_back (SeparatorElem());
896 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
897 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
901 if (step_edit_item) {
902 if (track()->rec_enable_control()->get_value()) {
903 step_edit_item->set_sensitive (false);
905 step_edit_item->set_active (midi_track()->step_editing());
908 rec_safe_item->set_sensitive (!_route->rec_enable_control()->get_value());
909 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
914 RouteUI::toggle_step_edit ()
916 if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
920 midi_track()->set_step_editing (step_edit_item->get_active());
924 RouteUI::toggle_rec_safe ()
926 boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
932 /* This check is made inside the control too, but dong it here can't
936 if (_route->rec_enable_control()->get_value()) {
940 rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
944 RouteUI::step_edit_changed (bool yn)
947 if (rec_enable_button) {
948 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
951 start_step_editing ();
953 if (step_edit_item) {
954 step_edit_item->set_active (true);
959 if (rec_enable_button) {
960 rec_enable_button->unset_active_state ();
963 stop_step_editing ();
965 if (step_edit_item) {
966 step_edit_item->set_active (false);
972 RouteUI::rec_enable_release (GdkEventButton* ev)
974 if (Keyboard::is_context_menu_event (ev)) {
975 build_record_menu ();
977 record_menu->popup (1, ev->time);
986 RouteUI::build_sends_menu ()
988 using namespace Menu_Helpers;
990 sends_menu = new Menu;
991 sends_menu->set_name ("ArdourContextMenu");
992 MenuList& items = sends_menu->items();
995 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
999 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1003 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1007 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1011 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1015 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1018 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1022 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1025 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1026 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1027 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1032 RouteUI::create_sends (Placement p, bool include_buses)
1034 _session->globally_add_internal_sends (_route, p, include_buses);
1038 RouteUI::create_selected_sends (Placement p, bool include_buses)
1040 boost::shared_ptr<RouteList> rlist (new RouteList);
1041 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1043 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1044 RouteTimeAxisView* rtv;
1046 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1047 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1048 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1049 rlist->push_back (rui->route());
1055 _session->add_internal_sends (_route, p, rlist);
1059 RouteUI::set_sends_gain_from_track ()
1061 _session->globally_set_send_gains_from_track (_route);
1065 RouteUI::set_sends_gain_to_zero ()
1067 _session->globally_set_send_gains_to_zero (_route);
1071 RouteUI::set_sends_gain_to_unity ()
1073 _session->globally_set_send_gains_to_unity (_route);
1077 RouteUI::show_sends_press(GdkEventButton* ev)
1079 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1083 if (!is_track() && show_sends_button) {
1085 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1087 // do nothing on midi sigc::bind event
1090 } else if (Keyboard::is_context_menu_event (ev)) {
1092 if (sends_menu == 0) {
1093 build_sends_menu ();
1096 sends_menu->popup (0, ev->time);
1100 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1103 set_showing_sends_to (boost::shared_ptr<Route> ());
1105 set_showing_sends_to (_route);
1114 RouteUI::show_sends_release (GdkEventButton*)
1120 RouteUI::send_blink (bool onoff)
1122 if (!show_sends_button) {
1127 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1129 show_sends_button->unset_active_state ();
1133 Gtkmm2ext::ActiveState
1134 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1136 boost::shared_ptr<SoloControl> sc = s->solo_control();
1139 return Gtkmm2ext::Off;
1142 if (!sc->can_solo()) {
1143 return Gtkmm2ext::Off;
1147 if (sc->self_soloed()) {
1148 return Gtkmm2ext::ExplicitActive;
1149 } else if (sc->soloed_by_others()) {
1150 return Gtkmm2ext::ImplicitActive;
1152 return Gtkmm2ext::Off;
1156 Gtkmm2ext::ActiveState
1157 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1159 boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1162 return Gtkmm2ext::Off;
1165 if (s->is_master() || s->is_monitor()) {
1166 return Gtkmm2ext::Off;
1169 if (sc->solo_isolated()) {
1170 return Gtkmm2ext::ExplicitActive;
1172 return Gtkmm2ext::Off;
1176 Gtkmm2ext::ActiveState
1177 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1179 boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1182 return Gtkmm2ext::Off;
1185 if (s->is_master() || s->is_monitor()) {
1186 return Gtkmm2ext::Off;
1189 if (sc->solo_safe()) {
1190 return Gtkmm2ext::ExplicitActive;
1192 return Gtkmm2ext::Off;
1197 RouteUI::update_solo_display ()
1199 bool yn = _route->solo_safe_control()->solo_safe ();
1201 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1202 solo_safe_check->set_active (yn);
1205 yn = _route->solo_isolate_control()->solo_isolated ();
1207 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1208 solo_isolated_check->set_active (yn);
1211 set_button_names ();
1213 if (solo_isolated_led) {
1214 if (_route->solo_isolate_control()->solo_isolated()) {
1215 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1217 solo_isolated_led->unset_active_state ();
1221 if (solo_safe_led) {
1222 if (_route->solo_safe_control()->solo_safe()) {
1223 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1225 solo_safe_led->unset_active_state ();
1229 solo_button->set_active_state (solo_active_state (_route));
1231 /* some changes to solo status can affect mute display, so catch up
1234 update_mute_display ();
1238 RouteUI::solo_changed_so_update_mute ()
1240 update_mute_display ();
1244 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1246 boost::shared_ptr<MuteControl> mc = s->mute_control();
1248 if (s->is_monitor()) {
1249 return Gtkmm2ext::Off;
1253 return Gtkmm2ext::Off;
1256 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1258 if (mc->muted_by_self ()) {
1260 return Gtkmm2ext::ExplicitActive;
1261 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1262 /* this will reflect both solo mutes AND master mutes */
1263 return Gtkmm2ext::ImplicitActive;
1265 /* no mute at all */
1266 return Gtkmm2ext::Off;
1271 if (mc->muted_by_self()) {
1273 return Gtkmm2ext::ExplicitActive;
1274 } else if (mc->muted_by_masters ()) {
1275 /* this shows only master mutes, not mute-by-others-soloing */
1276 return Gtkmm2ext::ImplicitActive;
1278 /* no mute at all */
1279 return Gtkmm2ext::Off;
1283 return ActiveState(0);
1287 RouteUI::update_mute_display ()
1293 mute_button->set_active_state (mute_active_state (_session, _route));
1298 RouteUI::route_rec_enable_changed ()
1300 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1304 RouteUI::session_rec_enable_changed ()
1306 blink_rec_display (true); //this lets the button change "immediately" rather than wait for the next blink
1310 RouteUI::blink_rec_display (bool blinkOn)
1312 if (!rec_enable_button || !_route) {
1316 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1324 if (track()->rec_enable_control()->get_value()) {
1325 switch (_session->record_status ()) {
1326 case Session::Recording:
1327 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1330 case Session::Disabled:
1331 case Session::Enabled:
1332 if (UIConfiguration::instance().get_blink_rec_arm()) {
1333 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1335 rec_enable_button->set_active_state ( ImplicitActive );
1340 if (step_edit_item) {
1341 step_edit_item->set_sensitive (false);
1345 rec_enable_button->unset_active_state ();
1347 if (step_edit_item) {
1348 step_edit_item->set_sensitive (true);
1352 check_rec_enable_sensitivity ();
1356 RouteUI::build_solo_menu (void)
1358 using namespace Menu_Helpers;
1360 solo_menu = new Menu;
1361 solo_menu->set_name ("ArdourContextMenu");
1362 MenuList& items = solo_menu->items();
1363 Gtk::CheckMenuItem* check;
1365 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1366 check->set_active (_route->solo_isolate_control()->solo_isolated());
1367 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1368 items.push_back (CheckMenuElem(*check));
1369 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1372 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1373 check->set_active (_route->solo_safe_control()->solo_safe());
1374 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1375 items.push_back (CheckMenuElem(*check));
1376 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1379 //items.push_back (SeparatorElem());
1380 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1385 RouteUI::build_mute_menu(void)
1387 using namespace Menu_Helpers;
1389 mute_menu = new Menu;
1390 mute_menu->set_name ("ArdourContextMenu");
1392 MenuList& items = mute_menu->items();
1394 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1395 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1396 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1397 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1398 pre_fader_mute_check->show_all();
1400 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1401 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1402 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1403 items.push_back (CheckMenuElem(*post_fader_mute_check));
1404 post_fader_mute_check->show_all();
1406 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1407 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1408 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1409 items.push_back (CheckMenuElem(*listen_mute_check));
1410 listen_mute_check->show_all();
1412 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1413 init_mute_menu(MuteMaster::Main, main_mute_check);
1414 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1415 items.push_back (CheckMenuElem(*main_mute_check));
1416 main_mute_check->show_all();
1418 //items.push_back (SeparatorElem());
1419 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1421 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1425 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1427 check->set_active (_route->mute_control()->mute_points() & mp);
1431 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1433 if (check->get_active()) {
1434 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1436 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1441 RouteUI::muting_change ()
1443 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1446 MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1448 yn = (current & MuteMaster::PreFader);
1450 if (pre_fader_mute_check->get_active() != yn) {
1451 pre_fader_mute_check->set_active (yn);
1454 yn = (current & MuteMaster::PostFader);
1456 if (post_fader_mute_check->get_active() != yn) {
1457 post_fader_mute_check->set_active (yn);
1460 yn = (current & MuteMaster::Listen);
1462 if (listen_mute_check->get_active() != yn) {
1463 listen_mute_check->set_active (yn);
1466 yn = (current & MuteMaster::Main);
1468 if (main_mute_check->get_active() != yn) {
1469 main_mute_check->set_active (yn);
1474 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1476 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1480 bool view = solo_isolated_led->active_state();
1481 bool model = _route->solo_isolate_control()->solo_isolated();
1483 /* called BEFORE the view has changed */
1485 if (ev->button == 1) {
1486 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1489 /* disable isolate for all routes */
1490 DisplaySuspender ds;
1491 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1493 /* enable isolate for all routes */
1494 DisplaySuspender ds;
1495 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1500 if (model == view) {
1502 /* flip just this route */
1504 boost::shared_ptr<RouteList> rl (new RouteList);
1505 rl->push_back (_route);
1506 DisplaySuspender ds;
1507 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1516 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1518 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1522 bool view = solo_safe_led->active_state();
1523 bool model = _route->solo_safe_control()->solo_safe();
1525 if (ev->button == 1) {
1526 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1527 boost::shared_ptr<RouteList> rl (_session->get_routes());
1529 /* disable solo safe for all routes */
1530 DisplaySuspender ds;
1531 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1532 (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1535 /* enable solo safe for all routes */
1536 DisplaySuspender ds;
1537 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1538 (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1543 if (model == view) {
1544 /* flip just this route */
1545 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1554 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1556 bool view = check->get_active();
1557 bool model = _route->solo_isolate_control()->solo_isolated();
1559 /* called AFTER the view has changed */
1561 if (model != view) {
1562 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1567 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1569 _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1572 /** Ask the user to choose a colour, and then apply that color to my route
1575 RouteUI::choose_color ()
1578 Gdk::Color c (gdk_color_from_rgb (_route->presentation_info().color()));
1579 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &c);
1582 set_color (gdk_color_to_rgba (color));
1586 /** Set the route's own color. This may not be used for display if
1587 * the route is in a group which shares its color with its routes.
1590 RouteUI::set_color (uint32_t c)
1592 _route->presentation_info().set_color (c);
1595 /** @return GUI state ID for things that are common to the route in all its representations */
1597 RouteUI::route_state_id () const
1599 return string_compose (X_("route %1"), _route->id().to_s());
1603 RouteUI::set_color_from_route ()
1605 if (_route->presentation_info().color_set()) {
1606 return 0; /* nothing to do */
1609 return 1; /* pick a color */
1612 /** @return true if this name should be used for the route, otherwise false */
1614 RouteUI::verify_new_route_name (const std::string& name)
1616 if (name.find (':') == string::npos) {
1620 MessageDialog colon_msg (
1621 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1622 false, MESSAGE_QUESTION, BUTTONS_NONE
1625 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1626 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1628 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1632 RouteUI::route_rename ()
1634 ArdourPrompter name_prompter (true);
1639 name_prompter.set_title (_("Rename Track"));
1641 name_prompter.set_title (_("Rename Bus"));
1643 name_prompter.set_prompt (_("New name:"));
1644 name_prompter.set_initial_text (_route->name());
1645 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1646 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1647 name_prompter.show_all ();
1650 switch (name_prompter.run ()) {
1651 case Gtk::RESPONSE_ACCEPT:
1652 name_prompter.get_result (result);
1653 name_prompter.hide ();
1654 if (result.length()) {
1655 if (verify_new_route_name (result)) {
1656 _route->set_name (result);
1659 /* back to name prompter */
1663 /* nothing entered, just get out of here */
1678 RouteUI::toggle_comment_editor ()
1680 // if (ignore_toggle) {
1684 if (comment_window && comment_window->is_visible ()) {
1685 comment_window->hide ();
1687 open_comment_editor ();
1693 RouteUI::open_comment_editor ()
1695 if (comment_window == 0) {
1696 setup_comment_editor ();
1700 title = _route->name();
1701 title += _(": comment editor");
1703 comment_window->set_title (title);
1704 comment_window->present();
1708 RouteUI::setup_comment_editor ()
1710 comment_window = new ArdourWindow (""); // title will be reset to show route
1711 comment_window->set_skip_taskbar_hint (true);
1712 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1713 comment_window->set_default_size (400, 200);
1715 comment_area = manage (new TextView());
1716 comment_area->set_name ("MixerTrackCommentArea");
1717 comment_area->set_wrap_mode (WRAP_WORD);
1718 comment_area->set_editable (true);
1719 comment_area->get_buffer()->set_text (_route->comment());
1720 comment_area->show ();
1722 comment_window->add (*comment_area);
1726 RouteUI::comment_changed ()
1728 ignore_comment_edit = true;
1730 comment_area->get_buffer()->set_text (_route->comment());
1732 ignore_comment_edit = false;
1736 RouteUI::comment_editor_done_editing ()
1738 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1740 string const str = comment_area->get_buffer()->get_text();
1741 if (str == _route->comment ()) {
1745 _route->set_comment (str, this);
1749 RouteUI::set_route_active (bool a, bool apply_to_selection)
1751 if (apply_to_selection) {
1752 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1754 _route->set_active (a, this);
1759 RouteUI::duplicate_selected_routes ()
1761 ARDOUR_UI::instance()->start_duplicate_routes();
1765 RouteUI::toggle_denormal_protection ()
1767 if (denormal_menu_item) {
1771 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1773 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1774 _route->set_denormal_protection (x);
1780 RouteUI::denormal_protection_changed ()
1782 if (denormal_menu_item) {
1783 denormal_menu_item->set_active (_route->denormal_protection());
1788 RouteUI::disconnect_input ()
1790 _route->input()->disconnect (this);
1794 RouteUI::disconnect_output ()
1796 _route->output()->disconnect (this);
1800 RouteUI::is_track () const
1802 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1805 boost::shared_ptr<Track>
1806 RouteUI::track() const
1808 return boost::dynamic_pointer_cast<Track>(_route);
1812 RouteUI::is_audio_track () const
1814 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1817 boost::shared_ptr<AudioTrack>
1818 RouteUI::audio_track() const
1820 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1824 RouteUI::is_midi_track () const
1826 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1829 boost::shared_ptr<MidiTrack>
1830 RouteUI::midi_track() const
1832 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1836 RouteUI::has_audio_outputs () const
1838 return (_route->n_outputs().n_audio() > 0);
1842 RouteUI::map_frozen ()
1844 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1846 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1849 check_rec_enable_sensitivity ();
1854 RouteUI::adjust_latency ()
1856 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1860 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1863 std::string safe_name;
1866 prompter.get_result (name, true);
1868 safe_name = legalize_for_path (name);
1869 safe_name += template_suffix;
1871 path = Glib::build_filename (dir, safe_name);
1873 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1874 bool overwrite = overwrite_file_dialog (prompter,
1875 _("Confirm Template Overwrite"),
1876 _("A template already exists with that name. Do you want to overwrite it?"));
1883 _route->save_as_template (path, name);
1889 RouteUI::save_as_template ()
1893 dir = ARDOUR::user_route_template_directory ();
1895 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1896 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1900 ArdourPrompter prompter (true); // modal
1902 prompter.set_title (_("Save As Template"));
1903 prompter.set_prompt (_("Template name:"));
1904 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1906 bool finished = false;
1908 switch (prompter.run()) {
1909 case RESPONSE_ACCEPT:
1910 finished = process_save_template_prompter (prompter, dir);
1920 RouteUI::check_rec_enable_sensitivity ()
1922 if (!rec_enable_button) {
1923 assert (0); // This should not happen
1926 if (!_session->writable()) {
1927 rec_enable_button->set_sensitive (false);
1931 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1932 rec_enable_button->set_sensitive (false);
1933 } else if (is_audio_track () && track()->freeze_state() == AudioTrack::Frozen) {
1934 rec_enable_button->set_sensitive (false);
1936 rec_enable_button->set_sensitive (true);
1938 if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1939 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1941 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1943 update_monitoring_display ();
1947 RouteUI::parameter_changed (string const & p)
1949 /* this handles RC and per-session parameter changes */
1951 if (p == "disable-disarm-during-roll") {
1952 check_rec_enable_sensitivity ();
1953 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1954 set_button_names ();
1955 } else if (p == "auto-input") {
1956 update_monitoring_display ();
1957 } else if (p == "blink-rec-arm") {
1958 if (UIConfiguration::instance().get_blink_rec_arm()) {
1959 rec_blink_connection.disconnect ();
1960 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1962 rec_blink_connection.disconnect ();
1963 RouteUI::blink_rec_display(false);
1969 RouteUI::step_gain_up ()
1971 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1975 RouteUI::page_gain_up ()
1977 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1981 RouteUI::step_gain_down ()
1983 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1987 RouteUI::page_gain_down ()
1989 _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1993 RouteUI::setup_invert_buttons ()
1995 /* remove old invert buttons */
1996 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1997 _invert_button_box.remove (**i);
2000 _invert_buttons.clear ();
2002 if (!_route || !_route->input()) {
2006 uint32_t const N = _route->input()->n_ports().n_audio ();
2008 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2010 for (uint32_t i = 0; i < to_add; ++i) {
2011 ArdourButton* b = manage (new ArdourButton);
2012 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2013 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2015 b->set_name (X_("invert button"));
2018 b->set_text (string_compose (X_("Ø (%1)"), N));
2020 b->set_text (X_("Ø"));
2023 b->set_text (string_compose (X_("Ø%1"), i + 1));
2026 if (N <= _max_invert_buttons) {
2027 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert polarity of channel %1 of this track. Right-click to show menu."), i + 1));
2029 UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2032 _invert_buttons.push_back (b);
2033 _invert_button_box.pack_start (*b);
2036 _invert_button_box.set_spacing (1);
2037 _invert_button_box.show_all ();
2041 RouteUI::set_invert_button_state ()
2043 uint32_t const N = _route->input()->n_ports().n_audio();
2044 if (N > _max_invert_buttons) {
2046 /* One button for many channels; explicit active if all channels are inverted,
2047 implicit active if some are, off if none are.
2050 ArdourButton* b = _invert_buttons.front ();
2052 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2053 b->set_active_state (Gtkmm2ext::ExplicitActive);
2054 } else if (_route->phase_control()->any()) {
2055 b->set_active_state (Gtkmm2ext::ImplicitActive);
2057 b->set_active_state (Gtkmm2ext::Off);
2062 /* One button per channel; just set active */
2065 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2066 (*i)->set_active (_route->phase_control()->inverted (j));
2073 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2075 if (ev->button == 1 && i < _invert_buttons.size()) {
2076 uint32_t const N = _route->input()->n_ports().n_audio ();
2077 if (N <= _max_invert_buttons) {
2078 /* left-click inverts phase so long as we have a button per channel */
2079 _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2088 RouteUI::invert_press (GdkEventButton* ev)
2090 using namespace Menu_Helpers;
2092 uint32_t const N = _route->input()->n_ports().n_audio();
2093 if (N <= _max_invert_buttons && ev->button != 3) {
2094 /* If we have an invert button per channel, we only pop
2095 up a menu on right-click; left click is handled
2101 delete _invert_menu;
2102 _invert_menu = new Menu;
2103 _invert_menu->set_name ("ArdourContextMenu");
2104 MenuList& items = _invert_menu->items ();
2106 for (uint32_t i = 0; i < N; ++i) {
2107 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2108 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2109 ++_i_am_the_modifier;
2110 e->set_active (_route->phase_control()->inverted (i));
2111 --_i_am_the_modifier;
2114 _invert_menu->popup (0, ev->time);
2120 RouteUI::invert_menu_toggled (uint32_t c)
2122 if (_i_am_the_modifier) {
2127 _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2131 RouteUI::set_invert_sensitive (bool yn)
2133 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2134 (*b)->set_sensitive (yn);
2139 RouteUI::request_redraw ()
2142 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2146 /** The Route's gui_changed signal has been emitted */
2148 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2150 if (what_changed.contains (Properties::color)) {
2151 if (set_color_from_route () == 0) {
2152 route_color_changed ();
2158 RouteUI::track_mode_changed (void)
2161 switch (track()->mode()) {
2162 case ARDOUR::NonLayered:
2163 case ARDOUR::Normal:
2164 rec_enable_button->set_icon (ArdourIcon::RecButton);
2166 case ARDOUR::Destructive:
2167 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2170 rec_enable_button->queue_draw();
2173 /** @return the color that this route should use; it maybe its own,
2174 or it maybe that of its route group.
2178 RouteUI::route_color () const
2181 RouteGroup* g = _route->route_group ();
2184 if (g && g->is_color()) {
2185 set_color_from_rgba (c, GroupTabs::group_color (g));
2188 /* deal with older 4.x color, which was stored in the GUI object state */
2190 string p = ARDOUR_UI::instance()->gui_object_state->get_string (route_state_id(), X_("color"));
2194 /* old v4.x or earlier session. Use this information */
2196 int red, green, blue;
2199 stringstream ss (p);
2201 /* old color format version was:
2203 16bit value for red:16 bit value for green:16 bit value for blue
2218 _route->presentation_info().set_color (RGBA_TO_UINT (red, green, blue, 255));
2221 set_color_from_rgba (c, _route->presentation_info().color());
2228 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2230 _showing_sends_to = send_to;
2231 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2235 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2237 if (_route == send_to) {
2238 show_sends_button->set_active (true);
2239 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2241 show_sends_button->set_active (false);
2242 send_blink_connection.disconnect ();
2247 RouteUI::route_group() const
2249 return _route->route_group();
2253 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2254 : WM::ProxyBase (name, string())
2255 , _route (boost::weak_ptr<Route> (route))
2257 route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2260 RoutePinWindowProxy::~RoutePinWindowProxy()
2265 ARDOUR::SessionHandlePtr*
2266 RoutePinWindowProxy::session_handle ()
2268 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2269 if (aw) { return aw; }
2274 RoutePinWindowProxy::get (bool create)
2276 boost::shared_ptr<Route> r = _route.lock ();
2285 _window = new PluginPinDialog (r);
2286 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2288 aw->set_session (_session);
2290 _window->show_all ();
2296 RoutePinWindowProxy::route_going_away ()
2300 WM::Manager::instance().remove (this);
2301 going_away_connection.disconnect();
2305 RouteUI::maybe_add_route_print_mgr ()
2307 if (_route->pinmgr_proxy ()) {
2310 RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2311 string_compose ("RPM-%1", _route->id()), _route);
2312 wp->set_session (_session);
2314 const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2316 wp->set_state (*ui_xml, 0);
2320 void* existing_ui = _route->pinmgr_proxy ();
2322 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2325 _route->set_pingmgr_proxy (wp);
2327 WM::Manager::instance().register_window (wp);
2331 RouteUI::manage_pins ()
2333 RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2341 RouteUI::fan_out (bool to_busses, bool group)
2343 DisplaySuspender ds;
2344 boost::shared_ptr<ARDOUR::Route> route = _route;
2345 boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2348 const uint32_t n_outputs = pi->output_streams ().n_audio ();
2349 if (route->n_outputs ().n_audio () != n_outputs) {
2350 MessageDialog msg (string_compose (
2351 _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2352 n_outputs, route->n_outputs ().n_audio ()));
2357 #define BUSNAME pd.group_name + "(" + route->name () + ")"
2359 /* count busses and channels/bus */
2360 boost::shared_ptr<Plugin> plugin = pi->plugin ();
2361 std::map<std::string, uint32_t> busnames;
2362 for (uint32_t p = 0; p < n_outputs; ++p) {
2363 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2364 std::string bn = BUSNAME;
2368 if (busnames.size () < 2) {
2369 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2374 uint32_t outputs = 2;
2375 if (_session->master_out ()) {
2376 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2379 route->output ()->disconnect (this);
2380 route->panner_shell ()->set_bypassed (true);
2383 for (uint32_t p = 0; p < n_outputs; ++p) {
2384 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2385 std::string bn = BUSNAME;
2386 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2389 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2393 list<boost::shared_ptr<AudioTrack> > tl =
2394 _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2398 boost::shared_ptr<ControlList> cl (new ControlList);
2399 cl->push_back (r->monitoring_control ());
2400 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2402 r->input ()->disconnect (this);
2404 to_group.push_back (r);
2405 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2410 RouteGroup* rg = NULL;
2411 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2412 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2413 if ((*i)->name () == pi->name ()) {
2419 rg = new RouteGroup (*_session, pi->name ());
2420 _session->add_route_group (rg);
2421 rg->set_gain (false);
2424 GroupTabs::set_group_color (rg, route->presentation_info().color());
2425 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2432 RouteUI::mark_hidden (bool yn)
2434 if (yn != _route->presentation_info().hidden()) {
2435 _route->presentation_info().set_hidden (yn);
2436 return true; // things changed
2441 boost::shared_ptr<Stripable>
2442 RouteUI::stripable () const