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.
20 #include <boost/algorithm/string.hpp>
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
30 #include "ardour/route_group.h"
31 #include "ardour/dB.h"
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/controllable.h"
35 #include "pbd/enumwriter.h"
37 #include "ardour_ui.h"
40 #include "ardour_button.h"
44 #include "gui_thread.h"
45 #include "ardour_dialog.h"
46 #include "latency_gui.h"
47 #include "mixer_strip.h"
48 #include "automation_time_axis.h"
49 #include "route_time_axis.h"
50 #include "group_tabs.h"
52 #include "ui_config.h"
54 #include "ardour/audio_track.h"
55 #include "ardour/audioengine.h"
56 #include "ardour/filename_extensions.h"
57 #include "ardour/midi_track.h"
58 #include "ardour/internal_send.h"
59 #include "ardour/profile.h"
60 #include "ardour/send.h"
61 #include "ardour/route.h"
62 #include "ardour/session.h"
63 #include "ardour/template_utils.h"
67 using namespace Gtkmm2ext;
68 using namespace ARDOUR;
69 using namespace ARDOUR_UI_UTILS;
73 uint32_t RouteUI::_max_invert_buttons = 3;
74 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
75 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
76 std::string RouteUI::program_port_prefix;
78 RouteUI::RouteUI (ARDOUR::Session* sess)
90 if (program_port_prefix.empty()) {
91 // compare to gtk2_ardour/port_group.cc
92 string lpn (PROGRAM_NAME);
93 boost::to_lower (lpn);
94 program_port_prefix = lpn + ":"; // e.g. "ardour:"
102 gui_object_state().remove_node (route_state_id());
105 _route.reset (); /* drop reference to route, so that it can be cleaned up */
106 route_connections.drop_connections ();
112 delete comment_window;
113 delete input_selector;
114 delete output_selector;
117 send_blink_connection.disconnect ();
118 rec_blink_connection.disconnect ();
124 self_destruct = true;
130 pre_fader_mute_check = 0;
131 post_fader_mute_check = 0;
132 listen_mute_check = 0;
135 solo_isolated_check = 0;
136 solo_isolated_led = 0;
140 denormal_menu_item = 0;
142 multiple_mute_change = false;
143 multiple_solo_change = false;
144 _i_am_the_modifier = 0;
149 setup_invert_buttons ();
151 mute_button = manage (new ArdourButton);
152 mute_button->set_name ("mute button");
153 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
155 solo_button = manage (new ArdourButton);
156 solo_button->set_name ("solo button");
157 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
158 solo_button->set_no_show_all (true);
160 rec_enable_button = manage (new ArdourButton);
161 rec_enable_button->set_name ("record enable button");
162 rec_enable_button->set_icon (ArdourIcon::RecButton);
163 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
165 if (UIConfiguration::instance().get_blink_rec_arm()) {
166 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
169 show_sends_button = manage (new ArdourButton);
170 show_sends_button->set_name ("send alert button");
171 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
173 monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
174 monitor_input_button->set_name ("monitor button");
175 monitor_input_button->set_text (_("In"));
176 UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
177 monitor_input_button->set_no_show_all (true);
179 monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
180 monitor_disk_button->set_name ("monitor button");
181 monitor_disk_button->set_text (_("Disk"));
182 UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
183 monitor_disk_button->set_no_show_all (true);
185 _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
186 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
187 _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
189 _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
190 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
192 rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
193 rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
195 show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
196 show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
198 solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
199 solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
200 mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
201 mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
203 monitor_input_button->set_distinct_led_click (false);
204 monitor_disk_button->set_distinct_led_click (false);
206 monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
207 monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
209 monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
210 monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
212 BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
218 route_connections.drop_connections ();
226 denormal_menu_item = 0;
230 RouteUI::self_delete ()
236 RouteUI::set_route (boost::shared_ptr<Route> rp)
242 if (set_color_from_route()) {
243 set_color (unique_random_color());
247 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
250 delete input_selector;
253 delete output_selector;
256 mute_button->set_controllable (_route->mute_control());
257 solo_button->set_controllable (_route->solo_control());
259 _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
260 _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
262 _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
264 _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
265 _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
266 _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
267 _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
269 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
270 track_mode_changed();
273 _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
274 _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
276 _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
277 _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
279 if (_session->writable() && is_track()) {
280 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
282 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
284 rec_enable_button->show();
285 rec_enable_button->set_controllable (t->rec_enable_control());
287 if (is_midi_track()) {
288 midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
289 boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
294 /* this will work for busses and tracks, and needs to be called to
295 set up the name entry/name label display.
299 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
300 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
302 update_monitoring_display ();
305 mute_button->unset_flags (Gtk::CAN_FOCUS);
306 solo_button->unset_flags (Gtk::CAN_FOCUS);
310 if (_route->is_monitor() || _route->is_master()) {
311 solo_button->hide ();
318 setup_invert_buttons ();
319 set_invert_button_state ();
321 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
322 bus_send_display_changed (s);
324 update_mute_display ();
325 update_solo_display ();
327 if (!UIConfiguration::instance().get_blink_rec_arm()) {
328 blink_rec_display(true); // set initial rec-en button state
331 route_color_changed();
335 RouteUI::polarity_changed ()
341 set_invert_button_state ();
345 RouteUI::mute_press (GdkEventButton* ev)
347 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
351 //if this is a binding action, let the ArdourButton handle it
352 if ( BindingProxy::is_bind_action(ev) )
355 multiple_mute_change = false;
357 if (Keyboard::is_context_menu_event (ev)) {
363 mute_menu->popup(0,ev->time);
369 if (Keyboard::is_button2_event (ev)) {
370 // button2-click is "momentary"
372 _mute_release = new SoloMuteRelease (_route->muted ());
375 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
377 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
379 /* toggle mute on everything (but
380 * exclude the master and monitor)
382 * because we are going to erase
383 * elements of the list we need to work
387 boost::shared_ptr<RouteList> copy (new RouteList);
389 *copy = *_session->get_routes ();
391 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
392 if ((*i)->is_master() || (*i)->is_monitor()) {
400 _mute_release->routes = copy;
404 _session->set_mute (copy, !_route->muted());
406 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
408 /* Primary-button1 inverts the implication of
409 the group being active. If the group is
410 active (for mute), then this modifier means
411 "do not apply to mute". If the group is
412 inactive (for mute), then this modifier
413 means "apply to route". This is all
414 accomplished by passing just the actual
415 route, along with the InverseGroup group
418 NOTE: Primary-button2 is MIDI learn.
421 boost::shared_ptr<RouteList> rl;
423 if (ev->button == 1) {
425 rl.reset (new RouteList);
426 rl->push_back (_route);
429 _mute_release->routes = rl;
433 _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
438 /* plain click applies change to this route */
440 boost::shared_ptr<RouteList> rl (new RouteList);
441 rl->push_back (_route);
444 _mute_release->routes = rl;
447 _session->set_mute (rl, !_route->muted());
457 RouteUI::mute_release (GdkEventButton* /*ev*/)
461 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
462 delete _mute_release;
470 RouteUI::edit_output_configuration ()
472 if (output_selector == 0) {
474 boost::shared_ptr<Send> send;
475 boost::shared_ptr<IO> output;
477 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
478 if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
479 output = send->output();
481 output = _route->output ();
484 output = _route->output ();
487 output_selector = new IOSelectorWindow (_session, output);
490 if (output_selector->is_visible()) {
491 output_selector->get_toplevel()->get_window()->raise();
493 output_selector->present ();
496 //output_selector->set_keep_above (true);
500 RouteUI::edit_input_configuration ()
502 if (input_selector == 0) {
503 input_selector = new IOSelectorWindow (_session, _route->input());
506 if (input_selector->is_visible()) {
507 input_selector->get_toplevel()->get_window()->raise();
509 input_selector->present ();
512 //input_selector->set_keep_above (true);
516 RouteUI::solo_press(GdkEventButton* ev)
518 /* ignore double/triple clicks */
520 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
524 //if this is a binding action, let the ArdourButton handle it
525 if ( BindingProxy::is_bind_action(ev) )
528 multiple_solo_change = false;
530 if (Keyboard::is_context_menu_event (ev)) {
532 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
533 ! (solo_safe_led && solo_safe_led->is_visible())) {
535 if (solo_menu == 0) {
539 solo_menu->popup (1, ev->time);
544 if (Keyboard::is_button2_event (ev)) {
546 // button2-click is "momentary"
547 _solo_release = new SoloMuteRelease (_route->self_soloed());
550 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
552 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
554 /* Primary-Tertiary-click applies change to all routes */
557 _solo_release->routes = _session->get_routes ();
561 if (Config->get_solo_control_is_listen_control()) {
562 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::NoGroup);
564 _session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, Controllable::NoGroup);
567 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
569 // Primary-Secondary-click: exclusively solo this track
572 _solo_release->exclusive = true;
574 boost::shared_ptr<RouteList> routes = _session->get_routes();
576 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
577 if ((*i)->soloed ()) {
578 _solo_release->routes_on->push_back (*i);
580 _solo_release->routes_off->push_back (*i);
585 if (Config->get_solo_control_is_listen_control()) {
586 /* ??? we need a just_one_listen() method */
589 _session->set_just_one_solo (_route, true);
592 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
594 // shift-click: toggle solo isolated status
596 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
597 delete _solo_release;
600 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
602 /* Primary-button1: solo mix group.
603 NOTE: Primary-button2 is MIDI learn.
606 /* Primary-button1 applies change to the mix group even if it is not active
607 NOTE: Primary-button2 is MIDI learn.
610 boost::shared_ptr<RouteList> rl;
612 if (ev->button == 1) {
614 /* Primary-button1 inverts the implication of
615 the group being active. If the group is
616 active (for solo), then this modifier means
617 "do not apply to solo". If the group is
618 inactive (for mute), then this modifier
619 means "apply to route". This is all
620 accomplished by passing just the actual
621 route, along with the InverseGroup group
624 NOTE: Primary-button2 is MIDI learn.
627 rl.reset (new RouteList);
628 rl->push_back (_route);
631 _solo_release->routes = rl;
636 if (Config->get_solo_control_is_listen_control()) {
637 _session->set_listen (rl, !_route->listening_via_monitor(), Session::rt_cleanup, Controllable::InverseGroup);
639 _session->set_solo (rl, !_route->self_soloed(), Session::rt_cleanup, Controllable::InverseGroup);
643 delete _solo_release;
648 /* click: solo this route */
650 boost::shared_ptr<RouteList> rl (new RouteList);
651 rl->push_back (route());
654 _solo_release->routes = rl;
658 if (Config->get_solo_control_is_listen_control()) {
659 _session->set_listen (rl, !_route->listening_via_monitor());
661 _session->set_solo (rl, !_route->self_soloed());
671 RouteUI::solo_release (GdkEventButton* /*ev*/)
675 if (_solo_release->exclusive) {
679 if (Config->get_solo_control_is_listen_control()) {
680 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
682 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
686 delete _solo_release;
694 RouteUI::rec_enable_press(GdkEventButton* ev)
696 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
700 //if this is a binding action, let the ArdourButton handle it
701 if ( BindingProxy::is_bind_action(ev) )
704 if (!_session->engine().connected()) {
705 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
710 if (is_midi_track()) {
712 /* rec-enable button exits from step editing */
714 if (midi_track()->step_editing()) {
715 midi_track()->set_step_editing (false);
720 if (is_track() && rec_enable_button) {
722 if (Keyboard::is_button2_event (ev)) {
724 //rec arm does not have a momentary mode
727 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
730 _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
732 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
734 /* Primary-button1 applies change to the route group (even if it is not active)
735 NOTE: Primary-button2 is MIDI learn.
738 if (ev->button == 1) {
740 boost::shared_ptr<RouteList> rl;
742 if (_route->route_group()) {
744 rl = _route->route_group()->route_list();
747 rl.reset (new RouteList);
748 rl->push_back (_route);
752 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
755 } else if (Keyboard::is_context_menu_event (ev)) {
757 /* do this on release */
761 boost::shared_ptr<RouteList> rl (new RouteList);
762 rl->push_back (route());
764 _session->set_record_enabled (rl, !_route->record_enabled());
772 RouteUI::monitoring_changed ()
774 update_monitoring_display ();
778 RouteUI::update_monitoring_display ()
784 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
790 MonitorState ms = t->monitoring_state();
792 if (t->monitoring_choice() & MonitorInput) {
793 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
795 if (ms & MonitoringInput) {
796 monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
798 monitor_input_button->unset_active_state ();
802 if (t->monitoring_choice() & MonitorDisk) {
803 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
805 if (ms & MonitoringDisk) {
806 monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
808 monitor_disk_button->unset_active_state ();
814 RouteUI::monitor_input_press(GdkEventButton*)
820 RouteUI::monitor_input_release(GdkEventButton* ev)
822 return monitor_release (ev, MonitorInput);
826 RouteUI::monitor_disk_press (GdkEventButton*)
832 RouteUI::monitor_disk_release (GdkEventButton* ev)
834 return monitor_release (ev, MonitorDisk);
838 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
840 if (ev->button != 1) {
844 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
851 boost::shared_ptr<RouteList> rl;
853 /* XXX for now, monitoring choices are orthogonal. cue monitoring
854 will follow in 3.X but requires mixing the input and playback (disk)
855 signal together, which requires yet more buffers.
858 if (t->monitoring_choice() & monitor_choice) {
859 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
861 /* this line will change when the options are non-orthogonal */
862 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
866 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
867 rl = _session->get_routes ();
869 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
870 if (_route->route_group() && _route->route_group()->is_monitoring()) {
871 rl = _route->route_group()->route_list();
873 rl.reset (new RouteList);
874 rl->push_back (route());
877 rl.reset (new RouteList);
878 rl->push_back (route());
882 _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
888 RouteUI::build_record_menu ()
894 /* no rec-button context menu for non-MIDI tracks
897 if (is_midi_track()) {
898 record_menu = new Menu;
899 record_menu->set_name ("ArdourContextMenu");
901 using namespace Menu_Helpers;
902 MenuList& items = record_menu->items();
904 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
905 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
907 if (_route->record_enabled()) {
908 step_edit_item->set_sensitive (false);
911 step_edit_item->set_active (midi_track()->step_editing());
916 RouteUI::toggle_step_edit ()
918 if (!is_midi_track() || _route->record_enabled()) {
922 midi_track()->set_step_editing (step_edit_item->get_active());
926 RouteUI::step_edit_changed (bool yn)
929 if (rec_enable_button) {
930 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
933 start_step_editing ();
935 if (step_edit_item) {
936 step_edit_item->set_active (true);
941 if (rec_enable_button) {
942 rec_enable_button->unset_active_state ();
945 stop_step_editing ();
947 if (step_edit_item) {
948 step_edit_item->set_active (false);
954 RouteUI::rec_enable_release (GdkEventButton* ev)
956 if (Keyboard::is_context_menu_event (ev)) {
957 build_record_menu ();
959 record_menu->popup (1, ev->time);
968 RouteUI::build_sends_menu ()
970 using namespace Menu_Helpers;
972 sends_menu = new Menu;
973 sends_menu->set_name ("ArdourContextMenu");
974 MenuList& items = sends_menu->items();
977 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
981 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
985 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
989 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
993 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
997 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1000 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1004 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1007 items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1008 items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1009 items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1014 RouteUI::create_sends (Placement p, bool include_buses)
1016 _session->globally_add_internal_sends (_route, p, include_buses);
1020 RouteUI::create_selected_sends (Placement p, bool include_buses)
1022 boost::shared_ptr<RouteList> rlist (new RouteList);
1023 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1025 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1026 RouteTimeAxisView* rtv;
1028 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1029 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1030 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1031 rlist->push_back (rui->route());
1037 _session->add_internal_sends (_route, p, rlist);
1041 RouteUI::set_sends_gain_from_track ()
1043 _session->globally_set_send_gains_from_track (_route);
1047 RouteUI::set_sends_gain_to_zero ()
1049 _session->globally_set_send_gains_to_zero (_route);
1053 RouteUI::set_sends_gain_to_unity ()
1055 _session->globally_set_send_gains_to_unity (_route);
1059 RouteUI::show_sends_press(GdkEventButton* ev)
1061 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1065 if (!is_track() && show_sends_button) {
1067 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1069 // do nothing on midi sigc::bind event
1072 } else if (Keyboard::is_context_menu_event (ev)) {
1074 if (sends_menu == 0) {
1075 build_sends_menu ();
1078 sends_menu->popup (0, ev->time);
1082 boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1085 set_showing_sends_to (boost::shared_ptr<Route> ());
1087 set_showing_sends_to (_route);
1096 RouteUI::show_sends_release (GdkEventButton*)
1102 RouteUI::send_blink (bool onoff)
1104 if (!show_sends_button) {
1109 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1111 show_sends_button->unset_active_state ();
1115 Gtkmm2ext::ActiveState
1116 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1118 if (r->is_master() || r->is_monitor()) {
1119 return Gtkmm2ext::Off;
1122 if (Config->get_solo_control_is_listen_control()) {
1124 if (r->listening_via_monitor()) {
1125 return Gtkmm2ext::ExplicitActive;
1127 return Gtkmm2ext::Off;
1133 if (!r->self_soloed()) {
1134 return Gtkmm2ext::ImplicitActive;
1136 return Gtkmm2ext::ExplicitActive;
1139 return Gtkmm2ext::Off;
1143 Gtkmm2ext::ActiveState
1144 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1146 if (r->is_master() || r->is_monitor()) {
1147 return Gtkmm2ext::Off;
1150 if (r->solo_isolated()) {
1151 return Gtkmm2ext::ExplicitActive;
1153 return Gtkmm2ext::Off;
1157 Gtkmm2ext::ActiveState
1158 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1160 if (r->is_master() || r->is_monitor()) {
1161 return Gtkmm2ext::Off;
1164 if (r->solo_safe()) {
1165 return Gtkmm2ext::ExplicitActive;
1167 return Gtkmm2ext::Off;
1172 RouteUI::update_solo_display ()
1174 bool yn = _route->solo_safe ();
1176 if (solo_safe_check && solo_safe_check->get_active() != yn) {
1177 solo_safe_check->set_active (yn);
1180 yn = _route->solo_isolated ();
1182 if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1183 solo_isolated_check->set_active (yn);
1186 set_button_names ();
1188 if (solo_isolated_led) {
1189 if (_route->solo_isolated()) {
1190 solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1192 solo_isolated_led->unset_active_state ();
1196 if (solo_safe_led) {
1197 if (_route->solo_safe()) {
1198 solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1200 solo_safe_led->unset_active_state ();
1204 solo_button->set_active_state (solo_active_state (_route));
1206 /* some changes to solo status can affect mute display, so catch up
1209 update_mute_display ();
1213 RouteUI::solo_changed_so_update_mute ()
1215 update_mute_display ();
1219 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1221 if (r->is_monitor()) {
1222 return ActiveState(0);
1226 if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1230 return Gtkmm2ext::ExplicitActive;
1231 } else if (r->muted_by_others()) {
1232 return Gtkmm2ext::ImplicitActive;
1234 /* no mute at all */
1235 return Gtkmm2ext::Off;
1242 return Gtkmm2ext::ExplicitActive;
1244 /* no mute at all */
1245 return Gtkmm2ext::Off;
1249 return ActiveState(0);
1253 RouteUI::update_mute_display ()
1259 mute_button->set_active_state (mute_active_state (_session, _route));
1263 RouteUI::route_rec_enable_changed ()
1265 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1266 update_monitoring_display ();
1270 RouteUI::session_rec_enable_changed ()
1272 blink_rec_display(true); //this lets the button change "immediately" rather than wait for the next blink
1273 update_monitoring_display ();
1277 RouteUI::blink_rec_display (bool blinkOn)
1279 if (!rec_enable_button || !_route) {
1282 if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1286 if (_route->record_enabled()) {
1287 switch (_session->record_status ()) {
1288 case Session::Recording:
1289 rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1292 case Session::Disabled:
1293 case Session::Enabled:
1294 if ( UIConfiguration::instance().get_blink_rec_arm() )
1295 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1297 rec_enable_button->set_active_state ( ImplicitActive );
1302 if (step_edit_item) {
1303 step_edit_item->set_sensitive (false);
1307 rec_enable_button->unset_active_state ();
1309 if (step_edit_item) {
1310 step_edit_item->set_sensitive (true);
1315 check_rec_enable_sensitivity ();
1319 RouteUI::build_solo_menu (void)
1321 using namespace Menu_Helpers;
1323 solo_menu = new Menu;
1324 solo_menu->set_name ("ArdourContextMenu");
1325 MenuList& items = solo_menu->items();
1326 Gtk::CheckMenuItem* check;
1328 check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1329 check->set_active (_route->solo_isolated());
1330 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1331 items.push_back (CheckMenuElem(*check));
1332 solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1335 check = new Gtk::CheckMenuItem(_("Solo Safe"));
1336 check->set_active (_route->solo_safe());
1337 check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1338 items.push_back (CheckMenuElem(*check));
1339 solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1342 //items.push_back (SeparatorElem());
1343 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1348 RouteUI::build_mute_menu(void)
1350 using namespace Menu_Helpers;
1352 mute_menu = new Menu;
1353 mute_menu->set_name ("ArdourContextMenu");
1355 MenuList& items = mute_menu->items();
1357 pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1358 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1359 pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1360 items.push_back (CheckMenuElem(*pre_fader_mute_check));
1361 pre_fader_mute_check->show_all();
1363 post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1364 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1365 post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1366 items.push_back (CheckMenuElem(*post_fader_mute_check));
1367 post_fader_mute_check->show_all();
1369 listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1370 init_mute_menu(MuteMaster::Listen, listen_mute_check);
1371 listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1372 items.push_back (CheckMenuElem(*listen_mute_check));
1373 listen_mute_check->show_all();
1375 main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1376 init_mute_menu(MuteMaster::Main, main_mute_check);
1377 main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1378 items.push_back (CheckMenuElem(*main_mute_check));
1379 main_mute_check->show_all();
1381 //items.push_back (SeparatorElem());
1382 // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1384 _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1388 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1390 check->set_active (_route->mute_points() & mp);
1394 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1396 if (check->get_active()) {
1397 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1399 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1404 RouteUI::muting_change ()
1406 ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1409 MuteMaster::MutePoint current = _route->mute_points ();
1411 yn = (current & MuteMaster::PreFader);
1413 if (pre_fader_mute_check->get_active() != yn) {
1414 pre_fader_mute_check->set_active (yn);
1417 yn = (current & MuteMaster::PostFader);
1419 if (post_fader_mute_check->get_active() != yn) {
1420 post_fader_mute_check->set_active (yn);
1423 yn = (current & MuteMaster::Listen);
1425 if (listen_mute_check->get_active() != yn) {
1426 listen_mute_check->set_active (yn);
1429 yn = (current & MuteMaster::Main);
1431 if (main_mute_check->get_active() != yn) {
1432 main_mute_check->set_active (yn);
1437 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1439 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1443 bool view = solo_isolated_led->active_state();
1444 bool model = _route->solo_isolated();
1446 /* called BEFORE the view has changed */
1448 if (ev->button == 1) {
1449 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1452 /* disable isolate for all routes */
1453 DisplaySuspender ds;
1454 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1456 /* enable isolate for all routes */
1457 DisplaySuspender ds;
1458 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1463 if (model == view) {
1465 /* flip just this route */
1467 boost::shared_ptr<RouteList> rl (new RouteList);
1468 rl->push_back (_route);
1469 DisplaySuspender ds;
1470 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1479 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1481 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1485 bool view = solo_safe_led->active_state();
1486 bool model = _route->solo_safe();
1488 if (ev->button == 1) {
1489 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1490 boost::shared_ptr<RouteList> rl (_session->get_routes());
1492 /* disable solo safe for all routes */
1493 DisplaySuspender ds;
1494 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1495 (*i)->set_solo_safe (false, Controllable::NoGroup);
1498 /* enable solo safe for all routes */
1499 DisplaySuspender ds;
1500 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1501 (*i)->set_solo_safe (true, Controllable::NoGroup);
1506 if (model == view) {
1507 /* flip just this route */
1508 _route->set_solo_safe (!view, Controllable::NoGroup);
1517 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1519 bool view = check->get_active();
1520 bool model = _route->solo_isolated();
1522 /* called AFTER the view has changed */
1524 if (model != view) {
1525 _route->set_solo_isolated (view, Controllable::UseGroup);
1530 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1532 _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1535 /** Ask the user to choose a colour, and then apply that color to my route
1538 RouteUI::choose_color ()
1541 Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1548 /** Set the route's own color. This may not be used for display if
1549 * the route is in a group which shares its color with its routes.
1552 RouteUI::set_color (const Gdk::Color & c)
1554 /* leave _color alone in the group case so that tracks can retain their
1555 * own pre-group colors.
1560 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1562 /* note: we use the route state ID here so that color is the same for both
1563 the time axis view and the mixer strip
1566 gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1567 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1570 /** @return GUI state ID for things that are common to the route in all its representations */
1572 RouteUI::route_state_id () const
1574 return string_compose (X_("route %1"), _route->id().to_s());
1578 RouteUI::set_color_from_route ()
1580 const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1588 sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1591 _color.set_green (g);
1592 _color.set_blue (b);
1597 /** @return true if this name should be used for the route, otherwise false */
1599 RouteUI::verify_new_route_name (const std::string& name)
1601 if (name.find (':') == string::npos) {
1605 MessageDialog colon_msg (
1606 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1607 false, MESSAGE_QUESTION, BUTTONS_NONE
1610 colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1611 colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1613 return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1617 RouteUI::route_rename ()
1619 ArdourPrompter name_prompter (true);
1624 name_prompter.set_title (_("Rename Track"));
1626 name_prompter.set_title (_("Rename Bus"));
1628 name_prompter.set_prompt (_("New name:"));
1629 name_prompter.set_initial_text (_route->name());
1630 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1631 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1632 name_prompter.show_all ();
1635 switch (name_prompter.run ()) {
1636 case Gtk::RESPONSE_ACCEPT:
1637 name_prompter.get_result (result);
1638 name_prompter.hide ();
1639 if (result.length()) {
1640 if (verify_new_route_name (result)) {
1641 _route->set_name (result);
1644 /* back to name prompter */
1648 /* nothing entered, just get out of here */
1663 RouteUI::property_changed (const PropertyChange& what_changed)
1665 if (what_changed.contains (ARDOUR::Properties::name)) {
1666 name_label.set_text (_route->name());
1671 RouteUI::toggle_comment_editor ()
1673 // if (ignore_toggle) {
1677 if (comment_window && comment_window->is_visible ()) {
1678 comment_window->hide ();
1680 open_comment_editor ();
1686 RouteUI::open_comment_editor ()
1688 if (comment_window == 0) {
1689 setup_comment_editor ();
1693 title = _route->name();
1694 title += _(": comment editor");
1696 comment_window->set_title (title);
1697 comment_window->present();
1701 RouteUI::setup_comment_editor ()
1703 comment_window = new ArdourWindow (""); // title will be reset to show route
1704 comment_window->set_skip_taskbar_hint (true);
1705 comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1706 comment_window->set_default_size (400, 200);
1708 comment_area = manage (new TextView());
1709 comment_area->set_name ("MixerTrackCommentArea");
1710 comment_area->set_wrap_mode (WRAP_WORD);
1711 comment_area->set_editable (true);
1712 comment_area->get_buffer()->set_text (_route->comment());
1713 comment_area->show ();
1715 comment_window->add (*comment_area);
1719 RouteUI::comment_changed ()
1721 ignore_comment_edit = true;
1723 comment_area->get_buffer()->set_text (_route->comment());
1725 ignore_comment_edit = false;
1729 RouteUI::comment_editor_done_editing ()
1731 ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1733 string const str = comment_area->get_buffer()->get_text();
1734 if (str == _route->comment ()) {
1738 _route->set_comment (str, this);
1742 RouteUI::set_route_active (bool a, bool apply_to_selection)
1744 if (apply_to_selection) {
1745 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1747 _route->set_active (a, this);
1752 RouteUI::duplicate_selected_routes ()
1754 ARDOUR_UI::instance()->start_duplicate_routes();
1758 RouteUI::toggle_denormal_protection ()
1760 if (denormal_menu_item) {
1764 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1766 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1767 _route->set_denormal_protection (x);
1773 RouteUI::denormal_protection_changed ()
1775 if (denormal_menu_item) {
1776 denormal_menu_item->set_active (_route->denormal_protection());
1781 RouteUI::disconnect_input ()
1783 _route->input()->disconnect (this);
1787 RouteUI::disconnect_output ()
1789 _route->output()->disconnect (this);
1793 RouteUI::is_track () const
1795 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1798 boost::shared_ptr<Track>
1799 RouteUI::track() const
1801 return boost::dynamic_pointer_cast<Track>(_route);
1805 RouteUI::is_audio_track () const
1807 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1810 boost::shared_ptr<AudioTrack>
1811 RouteUI::audio_track() const
1813 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1817 RouteUI::is_midi_track () const
1819 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1822 boost::shared_ptr<MidiTrack>
1823 RouteUI::midi_track() const
1825 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1829 RouteUI::has_audio_outputs () const
1831 return (_route->n_outputs().n_audio() > 0);
1835 RouteUI::name() const
1837 return _route->name();
1841 RouteUI::map_frozen ()
1843 ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1845 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1848 switch (at->freeze_state()) {
1849 case AudioTrack::Frozen:
1850 rec_enable_button->set_sensitive (false);
1853 rec_enable_button->set_sensitive (true);
1860 RouteUI::adjust_latency ()
1862 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1866 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1869 std::string safe_name;
1872 prompter.get_result (name, true);
1874 safe_name = legalize_for_path (name);
1875 safe_name += template_suffix;
1877 path = Glib::build_filename (dir, safe_name);
1879 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1880 bool overwrite = overwrite_file_dialog (prompter,
1881 _("Confirm Template Overwrite"),
1882 _("A template already exists with that name. Do you want to overwrite it?"));
1889 _route->save_as_template (path, name);
1895 RouteUI::save_as_template ()
1899 dir = ARDOUR::user_route_template_directory ();
1901 if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1902 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1906 ArdourPrompter prompter (true); // modal
1908 prompter.set_title (_("Save As Template"));
1909 prompter.set_prompt (_("Template name:"));
1910 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1912 bool finished = false;
1914 switch (prompter.run()) {
1915 case RESPONSE_ACCEPT:
1916 finished = process_save_template_prompter (prompter, dir);
1926 RouteUI::check_rec_enable_sensitivity ()
1928 if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1929 rec_enable_button->set_sensitive (false);
1931 rec_enable_button->set_sensitive (true);
1934 update_monitoring_display ();
1938 RouteUI::parameter_changed (string const & p)
1940 /* this handles RC and per-session parameter changes */
1942 if (p == "disable-disarm-during-roll") {
1943 check_rec_enable_sensitivity ();
1944 } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1945 set_button_names ();
1946 } else if (p == "auto-input") {
1947 update_monitoring_display ();
1948 } else if (p == "blink-rec-arm") {
1949 if (UIConfiguration::instance().get_blink_rec_arm()) {
1950 rec_blink_connection.disconnect ();
1951 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1953 rec_blink_connection.disconnect ();
1954 RouteUI::blink_rec_display(false);
1960 RouteUI::step_gain_up ()
1962 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1966 RouteUI::page_gain_up ()
1968 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1972 RouteUI::step_gain_down ()
1974 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1978 RouteUI::page_gain_down ()
1980 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1984 RouteUI::open_remote_control_id_dialog ()
1986 ArdourDialog dialog (_("Remote Control ID"));
1987 SpinButton* spin = 0;
1989 dialog.get_vbox()->set_border_width (18);
1991 if (Config->get_remote_model() == UserOrdered) {
1992 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1994 HBox* hbox = manage (new HBox);
1995 hbox->set_spacing (6);
1996 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1997 spin = manage (new SpinButton);
1998 spin->set_digits (0);
1999 spin->set_increments (1, 10);
2000 spin->set_range (0, limit);
2001 spin->set_value (_route->remote_control_id());
2002 hbox->pack_start (*spin);
2003 dialog.get_vbox()->pack_start (*hbox);
2005 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2006 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2008 Label* l = manage (new Label());
2009 if (_route->is_master() || _route->is_monitor()) {
2010 l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2011 "The remote control ID of %3 cannot be changed."),
2012 Gtkmm2ext::markup_escape_text (_route->name()),
2013 _route->remote_control_id(),
2014 (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2016 l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2017 "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2018 "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2019 (is_track() ? _("track") : _("bus")),
2020 _route->remote_control_id(),
2021 "<span size=\"small\" style=\"italic\">",
2023 Gtkmm2ext::markup_escape_text (_route->name()),
2026 dialog.get_vbox()->pack_start (*l);
2027 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2031 int const r = dialog.run ();
2033 if (r == RESPONSE_ACCEPT && spin) {
2034 _route->set_remote_control_id (spin->get_value_as_int ());
2039 RouteUI::setup_invert_buttons ()
2041 /* remove old invert buttons */
2042 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2043 _invert_button_box.remove (**i);
2046 _invert_buttons.clear ();
2048 if (!_route || !_route->input()) {
2052 uint32_t const N = _route->input()->n_ports().n_audio ();
2054 uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2056 for (uint32_t i = 0; i < to_add; ++i) {
2057 ArdourButton* b = manage (new ArdourButton);
2058 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2059 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2061 b->set_name (X_("invert button"));
2064 b->set_text (string_compose (X_("Ø (%1)"), N));
2066 b->set_text (X_("Ø"));
2069 b->set_text (string_compose (X_("Ø%1"), i + 1));
2072 if (N <= _max_invert_buttons) {
2073 UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track. Right-click to show menu."), i + 1));
2075 UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2078 _invert_buttons.push_back (b);
2079 _invert_button_box.pack_start (*b);
2082 _invert_button_box.set_spacing (1);
2083 _invert_button_box.show_all ();
2087 RouteUI::set_invert_button_state ()
2089 uint32_t const N = _route->input()->n_ports().n_audio();
2090 if (N > _max_invert_buttons) {
2092 /* One button for many channels; explicit active if all channels are inverted,
2093 implicit active if some are, off if none are.
2096 ArdourButton* b = _invert_buttons.front ();
2098 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2099 b->set_active_state (Gtkmm2ext::ExplicitActive);
2100 } else if (_route->phase_invert().any()) {
2101 b->set_active_state (Gtkmm2ext::ImplicitActive);
2103 b->set_active_state (Gtkmm2ext::Off);
2108 /* One button per channel; just set active */
2111 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2112 (*i)->set_active (_route->phase_invert (j));
2119 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2121 if (ev->button == 1 && i < _invert_buttons.size()) {
2122 uint32_t const N = _route->input()->n_ports().n_audio ();
2123 if (N <= _max_invert_buttons) {
2124 /* left-click inverts phase so long as we have a button per channel */
2125 _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2134 RouteUI::invert_press (GdkEventButton* ev)
2136 using namespace Menu_Helpers;
2138 uint32_t const N = _route->input()->n_ports().n_audio();
2139 if (N <= _max_invert_buttons && ev->button != 3) {
2140 /* If we have an invert button per channel, we only pop
2141 up a menu on right-click; left click is handled
2147 delete _invert_menu;
2148 _invert_menu = new Menu;
2149 _invert_menu->set_name ("ArdourContextMenu");
2150 MenuList& items = _invert_menu->items ();
2152 for (uint32_t i = 0; i < N; ++i) {
2153 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2154 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2155 ++_i_am_the_modifier;
2156 e->set_active (_route->phase_invert (i));
2157 --_i_am_the_modifier;
2160 _invert_menu->popup (0, ev->time);
2166 RouteUI::invert_menu_toggled (uint32_t c)
2168 if (_i_am_the_modifier) {
2172 _route->set_phase_invert (c, !_route->phase_invert (c));
2176 RouteUI::set_invert_sensitive (bool yn)
2178 for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2179 (*b)->set_sensitive (yn);
2184 RouteUI::request_redraw ()
2187 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2191 /** The Route's gui_changed signal has been emitted */
2193 RouteUI::route_gui_changed (string what_changed)
2195 if (what_changed == "color") {
2196 if (set_color_from_route () == 0) {
2197 route_color_changed ();
2203 RouteUI::track_mode_changed (void)
2206 switch (track()->mode()) {
2207 case ARDOUR::NonLayered:
2208 case ARDOUR::Normal:
2209 rec_enable_button->set_icon (ArdourIcon::RecButton);
2211 case ARDOUR::Destructive:
2212 rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2215 rec_enable_button->queue_draw();
2218 /** @return the color that this route should use; it maybe its own,
2219 or it maybe that of its route group.
2222 RouteUI::color () const
2224 RouteGroup* g = _route->route_group ();
2226 if (g && g->is_color()) {
2228 set_color_from_rgba (c, GroupTabs::group_color (g));
2236 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2238 _showing_sends_to = send_to;
2239 BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2243 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2245 if (_route == send_to) {
2246 show_sends_button->set_active (true);
2247 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2249 show_sends_button->set_active (false);
2250 send_blink_connection.disconnect ();
2255 RouteUI::route_group() const
2257 return _route->route_group();