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 <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
28 #include "ardour/route_group.h"
29 #include "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/shiva.h"
33 #include "pbd/controllable.h"
34 #include "pbd/enumwriter.h"
36 #include "ardour_ui.h"
42 #include "gui_thread.h"
43 #include "ardour_dialog.h"
44 #include "latency_gui.h"
45 #include "mixer_strip.h"
46 #include "automation_time_axis.h"
47 #include "route_time_axis.h"
49 #include "ardour/route.h"
50 #include "ardour/event_type_map.h"
51 #include "ardour/session.h"
52 #include "ardour/audioengine.h"
53 #include "ardour/audio_track.h"
54 #include "ardour/audio_diskstream.h"
55 #include "ardour/midi_track.h"
56 #include "ardour/midi_diskstream.h"
57 #include "ardour/template_utils.h"
58 #include "ardour/filename_extensions.h"
59 #include "ardour/directory_names.h"
60 #include "ardour/profile.h"
65 using namespace Gtkmm2ext;
66 using namespace ARDOUR;
69 RouteUI::RouteUI (ARDOUR::Session& sess)
75 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess)
84 /* derived classes should emit GoingAway so that they receive the signal
85 when the object is still a legal derived instance.
101 pre_fader_mute_check = 0;
102 post_fader_mute_check = 0;
103 listen_mute_check = 0;
105 ignore_toggle = false;
106 wait_for_release = false;
107 route_active_menu_item = 0;
108 polarity_menu_item = 0;
109 denormal_menu_item = 0;
110 multiple_mute_change = false;
111 multiple_solo_change = false;
113 mute_button = manage (new BindableToggleButton ());
114 mute_button->set_self_managed (true);
115 mute_button->set_name ("MuteButton");
116 mute_button->add (mute_button_label);
117 mute_button_label.show ();
118 UI::instance()->set_tip (mute_button, _("Mute this track"), "");
120 solo_button = manage (new BindableToggleButton ());
121 solo_button->set_self_managed (true);
122 solo_button->set_name ("SoloButton");
123 solo_button->add (solo_button_label);
124 solo_button_label.show ();
125 UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
126 solo_button->set_no_show_all (true);
128 rec_enable_button = manage (new BindableToggleButton ());
129 rec_enable_button->set_name ("RecordEnableButton");
130 rec_enable_button->set_self_managed (true);
131 rec_enable_button->add (rec_enable_button_label);
132 rec_enable_button_label.show ();
133 UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
135 show_sends_button = manage (new BindableToggleButton (""));
136 show_sends_button->set_name ("SendAlert");
137 show_sends_button->set_self_managed (true);
138 UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
140 _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
141 _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
143 Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
149 //Remove route connections associated with us.
150 for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
154 connections.clear ();
163 /* do not delete the node - its owned by the route */
167 route_active_menu_item = 0;
168 polarity_menu_item = 0;
169 denormal_menu_item = 0;
173 RouteUI::set_route (boost::shared_ptr<Route> rp)
179 if (set_color_from_route()) {
180 set_color (unique_random_color());
183 /* no, there is no memory leak here. This object cleans itself (and other stuff)
184 up when the route is destroyed.
188 new PairedShiva<Route,RouteUI> (*_route, *this);
191 mute_button->set_controllable (_route->mute_control());
192 solo_button->set_controllable (_route->solo_control());
194 connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
195 connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
196 connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
197 connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
198 connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
200 if (_session.writable() && is_track()) {
201 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
203 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
204 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
206 rec_enable_button->show();
207 rec_enable_button->set_controllable (t->rec_enable_control());
209 update_rec_display ();
212 mute_button->unset_flags (Gtk::CAN_FOCUS);
213 solo_button->unset_flags (Gtk::CAN_FOCUS);
217 if (_route->is_control()) {
218 solo_button->hide ();
223 /* map the current state */
232 RouteUI::mute_press(GdkEventButton* ev)
234 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
237 multiple_mute_change = false;
238 if (!ignore_toggle) {
240 if (Keyboard::is_context_menu_event (ev)) {
246 mute_menu->popup(0,ev->time);
250 if (Keyboard::is_button2_event (ev)) {
251 // Primary-button2 click is the midi binding click
252 // button2-click is "momentary"
254 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
255 wait_for_release = true;
261 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
263 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
265 /* Primary-Tertiary-click applies change to all routes */
267 _session.begin_reversible_command (_("mute change"));
268 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
269 _session.set_all_mute (!_route->muted());
271 _session.add_command(cmd);
272 _session.commit_reversible_command ();
273 multiple_mute_change = true;
275 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
277 /* Primary-button1 applies change to the mix group.
278 NOTE: Primary-button2 is MIDI learn.
281 if (ev->button == 1) {
282 set_route_group_mute (_route, !_route->muted());
287 /* plain click applies change to this route */
288 if (wait_for_release) {
289 _route->set_mute (!_route->muted(), this);
291 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
303 RouteUI::mute_release(GdkEventButton*)
305 if (!ignore_toggle) {
306 if (wait_for_release){
307 wait_for_release = false;
308 if (multiple_mute_change) {
309 multiple_mute_change = false;
311 // because the press was the last undoable thing we did
314 _route->set_mute (!_route->muted(), this);
322 RouteUI::solo_press(GdkEventButton* ev)
324 /* ignore double/triple clicks */
326 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
330 if (Config->get_solo_control_is_listen_control()) {
332 _route->set_listen (!_route->listening(), this);
336 multiple_solo_change = false;
337 if (!ignore_toggle) {
339 if (Keyboard::is_context_menu_event (ev)) {
341 if (solo_menu == 0) {
345 solo_menu->popup (1, ev->time);
349 if (Keyboard::is_button2_event (ev)) {
351 // Primary-button2 click is the midi binding click
352 // button2-click is "momentary"
354 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
355 wait_for_release = true;
361 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
363 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
365 /* Primary-Tertiary-click applies change to all routes */
366 bool was_not_latched = false;
367 if (!Config->get_solo_latched ()) {
368 was_not_latched = true;
370 XXX it makes no sense to solo all tracks if we're
371 not in latched mode, but doing nothing feels like a bug,
374 Config->set_solo_latched (true);
376 _session.begin_reversible_command (_("solo change"));
377 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
378 _session.set_all_solo (!_route->soloed());
380 _session.add_command (cmd);
381 _session.commit_reversible_command ();
382 multiple_solo_change = true;
383 if (was_not_latched) {
384 Config->set_solo_latched (false);
387 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
389 // Primary-Secondary-click: exclusively solo this track, not a toggle */
391 _session.begin_reversible_command (_("solo change"));
392 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
393 _session.set_all_solo (false);
394 _route->set_solo (true, this);
396 _session.add_command(cmd);
397 _session.commit_reversible_command ();
399 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
401 // shift-click: toggle solo isolated status
403 _route->set_solo_isolated (!_route->solo_isolated(), this);
404 wait_for_release = false;
406 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
408 /* Primary-button1: solo mix group.
409 NOTE: Primary-button2 is MIDI learn.
412 if (ev->button == 1) {
413 set_route_group_solo (_route, !_route->soloed());
418 /* click: solo this route */
419 if (wait_for_release) {
420 _route->set_solo (!_route->soloed(), this);
422 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
434 RouteUI::solo_release(GdkEventButton*)
436 if (!ignore_toggle) {
437 if (wait_for_release) {
438 wait_for_release = false;
439 if (multiple_solo_change) {
440 multiple_solo_change = false;
442 // because the press was the last undoable thing we did
445 // we don't use "undo the last op"
446 // here because its expensive for the GUI
447 _route->set_solo (!_route->soloed(), this);
456 RouteUI::post_rtop_cleanup (SessionEvent* ev)
458 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_rtop_cleanup), ev));
463 RouteUI::post_group_rtop_cleanup (SessionEvent* ev, RouteGroup* rg, RouteGroup::Property prop)
465 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_group_rtop_cleanup), ev, rg, prop));
467 rg->set_property (prop, false);
471 RouteUI::queue_route_group_op (RouteGroup::Property prop, void (Session::*session_method)(boost::shared_ptr<RouteList>, bool), bool yn)
473 RouteGroup* rg = _route->route_group();
474 bool prop_was_active;
477 prop_was_active = rg->active_property (prop);
478 rg->set_property (prop, true);
480 prop_was_active = false;
483 /* we will queue the op for just this route, but because its route group now has the relevant property marked active,
484 the operation will apply to the whole group (if there is a group)
487 boost::shared_ptr<RouteList> rl (new RouteList);
488 rl->push_back (route());
490 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
491 ev->rt_slot = bind (sigc::mem_fun (_session, session_method), rl, yn);
492 if (rg && !prop_was_active) {
493 ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_group_rtop_cleanup), rg, prop);
495 ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
498 _session.queue_event (ev);
502 RouteUI::rec_enable_press(GdkEventButton* ev)
504 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
508 if (!_session.engine().connected()) {
509 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
514 if (!ignore_toggle && is_track() && rec_enable_button) {
516 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
518 // do nothing on midi bind event
521 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
523 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
524 ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_all_record_enable), _session.get_routes(), !rec_enable_button->get_active());
525 ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
527 _session.queue_event (ev);
529 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
531 /* Primary-button1 applies change to the route group (even if it is not active)
532 NOTE: Primary-button2 is MIDI learn.
535 if (ev->button == 1) {
536 queue_route_group_op (RouteGroup::RecEnable, &Session::set_all_record_enable, !rec_enable_button->get_active());
539 } else if (Keyboard::is_context_menu_event (ev)) {
541 /* do this on release */
544 boost::shared_ptr<RouteList> rl (new RouteList);
545 rl->push_back (route());
547 SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
548 ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_all_record_enable), rl, !rec_enable_button->get_active());
549 ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
551 _session.queue_event (ev);
559 RouteUI::rec_enable_release (GdkEventButton*)
565 RouteUI::build_sends_menu ()
567 using namespace Menu_Helpers;
569 sends_menu = new Menu;
570 sends_menu->set_name ("ArdourContextMenu");
571 MenuList& items = sends_menu->items();
573 items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
574 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
575 items.push_back (MenuElem(_("Assign selected tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
576 items.push_back (MenuElem(_("Assign selected tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
577 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
578 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
579 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
584 RouteUI::create_sends (Placement p)
586 _session.globally_add_internal_sends (_route, p);
590 RouteUI::create_selected_sends (Placement p)
592 boost::shared_ptr<RouteList> rlist (new RouteList);
593 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
595 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
596 RouteTimeAxisView* rtv;
598 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
599 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
600 if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
601 rlist->push_back (rui->route());
607 _session.add_internal_sends (_route, p, rlist);
611 RouteUI::set_sends_gain_from_track ()
613 _session.globally_set_send_gains_from_track (_route);
617 RouteUI::set_sends_gain_to_zero ()
619 _session.globally_set_send_gains_to_zero (_route);
623 RouteUI::set_sends_gain_to_unity ()
625 _session.globally_set_send_gains_to_unity (_route);
629 RouteUI::show_sends_press(GdkEventButton* ev)
631 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
635 if (!ignore_toggle && !is_track() && show_sends_button) {
637 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
639 // do nothing on midi bind event
642 } else if (Keyboard::is_context_menu_event (ev)) {
644 if (sends_menu == 0) {
648 sends_menu->popup (0, ev->time);
652 /* change button state */
654 show_sends_button->set_active (!show_sends_button->get_active());
658 if (show_sends_button->get_active()) {
659 /* show sends to this bus */
660 MixerStrip::SwitchIO (_route);
661 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
663 /* everybody back to normal */
664 send_blink_connection.disconnect ();
665 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
675 RouteUI::show_sends_release (GdkEventButton*)
681 RouteUI::send_blink (bool onoff)
683 if (!show_sends_button) {
688 show_sends_button->set_state (STATE_ACTIVE);
690 show_sends_button->set_state (STATE_NORMAL);
695 RouteUI::solo_changed(void* /*src*/)
697 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
702 RouteUI::listen_changed(void* /*src*/)
704 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
708 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
710 if (Config->get_solo_control_is_listen_control()) {
712 if (r->listening()) {
720 if (r->solo_isolated()) {
722 } else if (r->soloed()) {
733 RouteUI::update_solo_display ()
737 if (Config->get_solo_control_is_listen_control()) {
739 if (solo_button->get_active() != (x = _route->listening())) {
740 ignore_toggle = true;
741 solo_button->set_active(x);
742 ignore_toggle = false;
747 if (solo_button->get_active() != (x = _route->soloed())) {
748 ignore_toggle = true;
749 solo_button->set_active (x);
750 ignore_toggle = false;
755 solo_button->set_visual_state (solo_visual_state (_route));
759 RouteUI::solo_changed_so_update_mute ()
761 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
765 RouteUI::mute_changed(void* /*src*/)
767 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
771 RouteUI::mute_visual_state (Session& s, boost::shared_ptr<Route> r)
773 if (Config->get_show_solo_mutes()) {
778 } else if (s.soloing() && !r->soloed() && !r->solo_isolated()) {
779 /* mute-because-not-soloed */
801 RouteUI::update_mute_display ()
803 bool model = _route->muted();
804 bool view = mute_button->get_active();
806 /* first make sure the button's "depressed" visual
811 ignore_toggle = true;
812 mute_button->set_active (model);
813 ignore_toggle = false;
816 mute_button->set_visual_state (mute_visual_state (_session, _route));
820 RouteUI::route_rec_enable_changed ()
822 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
826 RouteUI::session_rec_enable_changed ()
828 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
832 RouteUI::update_rec_display ()
834 bool model = _route->record_enabled();
835 bool view = rec_enable_button->get_active();
837 /* first make sure the button's "depressed" visual
842 ignore_toggle = true;
843 rec_enable_button->set_active (model);
844 ignore_toggle = false;
847 /* now make sure its color state is correct */
851 switch (_session.record_status ()) {
852 case Session::Recording:
853 rec_enable_button->set_visual_state (1);
856 case Session::Disabled:
857 case Session::Enabled:
858 rec_enable_button->set_visual_state (2);
864 rec_enable_button->set_visual_state (0);
867 check_rec_enable_sensitivity ();
871 RouteUI::build_solo_menu (void)
873 using namespace Menu_Helpers;
875 solo_menu = new Menu;
876 solo_menu->set_name ("ArdourContextMenu");
877 MenuList& items = solo_menu->items();
878 CheckMenuItem* check;
880 check = new CheckMenuItem(_("Solo Isolate"));
881 check->set_active (_route->solo_isolated());
882 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
883 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
884 items.push_back (CheckMenuElem(*check));
887 check = new CheckMenuItem(_("Solo Safe"));
888 check->set_active (_route->solo_safe());
889 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
890 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
891 items.push_back (CheckMenuElem(*check));
894 //items.push_back (SeparatorElem());
895 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
900 RouteUI::build_mute_menu(void)
902 using namespace Menu_Helpers;
904 mute_menu = new Menu;
905 mute_menu->set_name ("ArdourContextMenu");
907 MenuList& items = mute_menu->items();
909 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
910 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
911 pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
912 items.push_back (CheckMenuElem(*pre_fader_mute_check));
913 pre_fader_mute_check->show_all();
915 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
916 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
917 post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
918 items.push_back (CheckMenuElem(*post_fader_mute_check));
919 post_fader_mute_check->show_all();
921 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
922 init_mute_menu(MuteMaster::Listen, listen_mute_check);
923 listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
924 items.push_back (CheckMenuElem(*listen_mute_check));
925 listen_mute_check->show_all();
927 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
928 init_mute_menu(MuteMaster::Main, main_mute_check);
929 main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
930 items.push_back (CheckMenuElem(*main_mute_check));
931 main_mute_check->show_all();
933 //items.push_back (SeparatorElem());
934 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
936 _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
940 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
942 check->set_active (_route->mute_points() & mp);
946 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
948 if (check->get_active()) {
949 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
951 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
956 RouteUI::muting_change ()
958 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
961 MuteMaster::MutePoint current = _route->mute_points ();
963 yn = (current & MuteMaster::PreFader);
965 if (pre_fader_mute_check->get_active() != yn) {
966 pre_fader_mute_check->set_active (yn);
969 yn = (current & MuteMaster::PostFader);
971 if (post_fader_mute_check->get_active() != yn) {
972 post_fader_mute_check->set_active (yn);
975 yn = (current & MuteMaster::Listen);
977 if (listen_mute_check->get_active() != yn) {
978 listen_mute_check->set_active (yn);
981 yn = (current & MuteMaster::Main);
983 if (main_mute_check->get_active() != yn) {
984 main_mute_check->set_active (yn);
989 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
991 _route->set_solo_isolated (check->get_active(), this);
995 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
997 _route->set_solo_safe (check->get_active(), this);
1001 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
1003 RouteGroup* route_group;
1005 if((route_group = route->route_group()) != 0){
1006 _session.begin_reversible_command (_("mix group solo change"));
1007 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
1008 route_group->apply(&Route::set_solo, yn, this);
1010 _session.add_command (cmd);
1011 _session.commit_reversible_command ();
1013 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
1018 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
1020 _session.begin_reversible_command (name);
1021 XMLNode &before = _route->get_state();
1022 bind(mem_fun(*_route, func), yn, arg)();
1023 XMLNode &after = _route->get_state();
1024 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
1025 _session.commit_reversible_command ();
1029 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
1031 _session.begin_reversible_command (name);
1032 XMLNode &before = track()->get_state();
1033 bind (mem_fun (*track(), func), yn, arg)();
1034 XMLNode &after = track()->get_state();
1035 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
1036 _session.commit_reversible_command ();
1040 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
1042 RouteGroup* route_group;
1044 if((route_group = route->route_group()) != 0){
1045 _session.begin_reversible_command (_("mix group mute change"));
1046 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
1047 route_group->apply(&Route::set_mute, yn, this);
1049 _session.add_command(cmd);
1050 _session.commit_reversible_command ();
1052 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
1057 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
1059 RouteGroup* route_group;
1061 if((route_group = route->route_group()) != 0){
1062 _session.begin_reversible_command (_("mix group rec-enable change"));
1063 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
1064 route_group->apply (&Route::set_record_enable, yn, this);
1066 _session.add_command(cmd);
1067 _session.commit_reversible_command ();
1069 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
1075 RouteUI::choose_color()
1080 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1090 RouteUI::set_color (const Gdk::Color & c)
1097 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1098 xml_node->add_property ("color", buf);
1100 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1105 RouteUI::ensure_xml_node ()
1107 if (xml_node == 0) {
1108 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1109 xml_node = new XMLNode ("GUI");
1110 _route->add_extra_xml (*xml_node);
1116 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1120 XMLNodeList kids = xml_node->children();
1121 XMLNodeConstIterator iter;
1123 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1125 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1126 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1127 XMLProperty* type = (*iter)->property("automation-id");
1128 if (type && type->value() == sym)
1133 // Didn't find it, make a new one
1134 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1135 child->add_property("automation-id", sym);
1136 xml_node->add_child_nocopy (*child);
1142 RouteUI::set_color_from_route ()
1146 RouteUI::ensure_xml_node ();
1148 if ((prop = xml_node->property ("color")) != 0) {
1150 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1152 _color.set_green(g);
1160 RouteUI::remove_this_route ()
1162 vector<string> choices;
1166 prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(cannot be undone)"), _route->name());
1168 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1171 choices.push_back (_("No, do nothing."));
1172 choices.push_back (_("Yes, remove it."));
1174 Choice prompter (prompt, choices);
1176 if (prompter.run () == 1) {
1177 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1182 RouteUI::idle_remove_this_route (RouteUI *rui)
1184 rui->_session.remove_route (rui->_route);
1189 RouteUI::route_rename ()
1191 ArdourPrompter name_prompter (true);
1193 name_prompter.set_prompt (_("New Name: "));
1194 name_prompter.set_initial_text (_route->name());
1195 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1196 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1197 name_prompter.show_all ();
1199 switch (name_prompter.run ()) {
1201 case Gtk::RESPONSE_ACCEPT:
1202 name_prompter.get_result (result);
1203 if (result.length()) {
1204 _route->set_name (result);
1214 RouteUI::name_changed ()
1216 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1218 name_label.set_text (_route->name());
1222 RouteUI::toggle_route_active ()
1226 if (route_active_menu_item) {
1227 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1228 _route->set_active (!yn);
1234 RouteUI::route_active_changed ()
1236 if (route_active_menu_item) {
1237 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1242 RouteUI::toggle_polarity ()
1244 if (polarity_menu_item) {
1248 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1250 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1251 _route->set_phase_invert (x);
1253 name_label.set_text (X_("Ø ") + name_label.get_text());
1255 name_label.set_text (_route->name());
1262 RouteUI::polarity_changed ()
1264 if (_route->phase_invert()) {
1265 name_label.set_text (X_("Ø ") + name_label.get_text());
1267 name_label.set_text (_route->name());
1272 RouteUI::toggle_denormal_protection ()
1274 if (denormal_menu_item) {
1278 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1280 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1281 _route->set_denormal_protection (x);
1287 RouteUI::denormal_protection_changed ()
1289 if (denormal_menu_item) {
1290 denormal_menu_item->set_active (_route->denormal_protection());
1295 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1297 bool yn = _route->solo_isolated ();
1299 if (check->get_active() != yn) {
1300 check->set_active (yn);
1306 RouteUI::solo_safe_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1308 bool yn = _route->solo_safe ();
1310 if (check->get_active() != yn) {
1311 check->set_active (yn);
1316 RouteUI::disconnect_input ()
1318 _route->input()->disconnect (this);
1322 RouteUI::disconnect_output ()
1324 _route->output()->disconnect (this);
1328 RouteUI::is_track () const
1330 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1333 boost::shared_ptr<Track>
1334 RouteUI::track() const
1336 return boost::dynamic_pointer_cast<Track>(_route);
1340 RouteUI::is_audio_track () const
1342 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1345 boost::shared_ptr<AudioTrack>
1346 RouteUI::audio_track() const
1348 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1352 RouteUI::is_midi_track () const
1354 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1357 boost::shared_ptr<MidiTrack>
1358 RouteUI::midi_track() const
1360 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1363 boost::shared_ptr<Diskstream>
1364 RouteUI::get_diskstream () const
1366 boost::shared_ptr<Track> t;
1368 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1369 return t->diskstream();
1371 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1376 RouteUI::name() const
1378 return _route->name();
1382 RouteUI::map_frozen ()
1384 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1386 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1389 switch (at->freeze_state()) {
1390 case AudioTrack::Frozen:
1391 rec_enable_button->set_sensitive (false);
1394 rec_enable_button->set_sensitive (true);
1401 RouteUI::adjust_latency ()
1403 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1407 RouteUI::save_as_template ()
1410 Glib::ustring safe_name;
1413 path = ARDOUR::user_route_template_directory ();
1415 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1416 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1420 Prompter p (true); // modal
1422 p.set_prompt (_("Template name:"));
1424 case RESPONSE_ACCEPT:
1431 p.get_result (name, true);
1433 safe_name = legalize_for_path (name);
1434 safe_name += template_suffix;
1438 _route->save_as_template (path.to_string(), name);
1442 RouteUI::check_rec_enable_sensitivity ()
1444 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1445 rec_enable_button->set_sensitive (false);
1447 rec_enable_button->set_sensitive (true);
1452 RouteUI::parameter_changed (string const & p)
1454 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1456 if (p == "disable-disarm-during-roll") {
1457 check_rec_enable_sensitivity ();
1458 } else if (p == "solo-control-is-listen-control") {
1459 set_button_names ();
1460 } else if (p == "listen-position") {
1461 set_button_names ();
1466 RouteUI::step_gain_up ()
1468 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1472 RouteUI::page_gain_up ()
1474 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1478 RouteUI::step_gain_down ()
1480 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1484 RouteUI::page_gain_down ()
1486 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1490 RouteUI::open_remote_control_id_dialog ()
1492 ArdourDialog dialog (_("Remote Control ID"));
1494 uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1496 HBox* hbox = manage (new HBox);
1497 hbox->set_spacing (6);
1498 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1499 SpinButton* spin = manage (new SpinButton);
1500 spin->set_digits (0);
1501 spin->set_increments (1, 10);
1502 spin->set_range (0, limit);
1503 spin->set_value (_route->remote_control_id());
1504 hbox->pack_start (*spin);
1505 dialog.get_vbox()->pack_start (*hbox);
1507 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1508 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1511 int const r = dialog.run ();
1513 if (r == RESPONSE_ACCEPT) {
1514 _route->set_remote_control_id (spin->get_value_as_int ());