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::rec_enable_press(GdkEventButton* ev)
458 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
462 if (!_session.engine().connected()) {
463 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
468 if (!ignore_toggle && is_track() && rec_enable_button) {
470 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
472 // do nothing on midi bind event
475 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
477 _session.begin_reversible_command (_("rec-enable change"));
478 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
480 if (rec_enable_button->get_active()) {
481 _session.record_disenable_all ();
483 _session.record_enable_all ();
484 check_rec_enable_sensitivity ();
488 _session.add_command(cmd);
489 _session.commit_reversible_command ();
491 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
493 /* Primary-button1 applies change to the mix group.
494 NOTE: Primary-button2 is MIDI learn.
497 set_route_group_rec_enable (_route, !_route->record_enabled());
499 } else if (Keyboard::is_context_menu_event (ev)) {
501 /* do this on release */
504 reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
505 check_rec_enable_sensitivity ();
513 RouteUI::rec_enable_release (GdkEventButton*)
519 RouteUI::build_sends_menu ()
521 using namespace Menu_Helpers;
523 sends_menu = new Menu;
524 sends_menu->set_name ("ArdourContextMenu");
525 MenuList& items = sends_menu->items();
527 items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
528 items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
529 items.push_back (MenuElem(_("Assign selected tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
530 items.push_back (MenuElem(_("Assign selected tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
531 items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
532 items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
533 items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
538 RouteUI::create_sends (Placement p)
540 _session.globally_add_internal_sends (_route, p);
544 RouteUI::create_selected_sends (Placement p)
546 boost::shared_ptr<RouteList> rlist (new RouteList);
547 TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
549 for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
550 RouteTimeAxisView* rtv;
552 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
553 if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
554 if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
555 rlist->push_back (rui->route());
561 _session.add_internal_sends (_route, p, rlist);
565 RouteUI::set_sends_gain_from_track ()
567 _session.globally_set_send_gains_from_track (_route);
571 RouteUI::set_sends_gain_to_zero ()
573 _session.globally_set_send_gains_to_zero (_route);
577 RouteUI::set_sends_gain_to_unity ()
579 _session.globally_set_send_gains_to_unity (_route);
583 RouteUI::show_sends_press(GdkEventButton* ev)
585 if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
589 if (!ignore_toggle && !is_track() && show_sends_button) {
591 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
593 // do nothing on midi bind event
596 } else if (Keyboard::is_context_menu_event (ev)) {
598 if (sends_menu == 0) {
602 sends_menu->popup (0, ev->time);
606 /* change button state */
608 show_sends_button->set_active (!show_sends_button->get_active());
612 if (show_sends_button->get_active()) {
613 /* show sends to this bus */
614 MixerStrip::SwitchIO (_route);
615 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (mem_fun(*this, &RouteUI::send_blink));
617 /* everybody back to normal */
618 send_blink_connection.disconnect ();
619 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
629 RouteUI::show_sends_release (GdkEventButton*)
635 RouteUI::send_blink (bool onoff)
637 if (!show_sends_button) {
642 show_sends_button->set_state (STATE_ACTIVE);
644 show_sends_button->set_state (STATE_NORMAL);
649 RouteUI::solo_changed(void* /*src*/)
651 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
656 RouteUI::listen_changed(void* /*src*/)
658 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
662 RouteUI::update_solo_display ()
666 if (Config->get_solo_control_is_listen_control()) {
668 if (solo_button->get_active() != (x = _route->listening())) {
669 ignore_toggle = true;
670 solo_button->set_active(x);
671 ignore_toggle = false;
675 solo_button->set_visual_state (1);
677 solo_button->set_visual_state (0);
683 if (solo_button->get_active() != (x = _route->soloed())){
684 ignore_toggle = true;
685 solo_button->set_active (x);
686 ignore_toggle = false;
689 if (_route->solo_isolated()) {
690 solo_button->set_visual_state (2);
692 solo_button->set_visual_state (1);
694 solo_button->set_visual_state (0);
700 RouteUI::solo_changed_so_update_mute ()
702 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
706 RouteUI::mute_changed(void* /*src*/)
708 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
712 RouteUI::update_mute_display ()
714 bool model = _route->muted();
715 bool view = mute_button->get_active();
717 /* first make sure the button's "depressed" visual
722 ignore_toggle = true;
723 mute_button->set_active (model);
724 ignore_toggle = false;
727 /* now attend to visual state */
729 if (Config->get_show_solo_mutes()) {
730 if (_route->muted()) {
732 mute_button->set_visual_state (2);
733 } else if (_session.soloing() && !_route->soloed() && !_route->solo_isolated()) {
734 /* mute-because-not-soloed */
735 mute_button->set_visual_state (1);
738 mute_button->set_visual_state (0);
741 if (_route->muted()) {
743 mute_button->set_visual_state (2);
746 mute_button->set_visual_state (0);
753 RouteUI::route_rec_enable_changed ()
755 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
759 RouteUI::session_rec_enable_changed ()
761 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
765 RouteUI::update_rec_display ()
767 bool model = _route->record_enabled();
768 bool view = rec_enable_button->get_active();
770 /* first make sure the button's "depressed" visual
775 ignore_toggle = true;
776 rec_enable_button->set_active (model);
777 ignore_toggle = false;
783 /* now make sure its color state is correct */
787 switch (_session.record_status ()) {
788 case Session::Recording:
789 rec_enable_button->set_visual_state (1);
792 case Session::Disabled:
793 case Session::Enabled:
794 rec_enable_button->set_visual_state (2);
800 rec_enable_button->set_visual_state (0);
805 RouteUI::build_solo_menu (void)
807 using namespace Menu_Helpers;
809 solo_menu = new Menu;
810 solo_menu->set_name ("ArdourContextMenu");
811 MenuList& items = solo_menu->items();
812 CheckMenuItem* check;
814 check = new CheckMenuItem(_("Solo Isolate"));
815 check->set_active (_route->solo_isolated());
816 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
817 _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
818 items.push_back (CheckMenuElem(*check));
821 check = new CheckMenuItem(_("Solo Safe"));
822 check->set_active (_route->solo_safe());
823 check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
824 _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
825 items.push_back (CheckMenuElem(*check));
828 //items.push_back (SeparatorElem());
829 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
834 RouteUI::build_mute_menu(void)
836 using namespace Menu_Helpers;
838 mute_menu = new Menu;
839 mute_menu->set_name ("ArdourContextMenu");
841 MenuList& items = mute_menu->items();
843 pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
844 init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
845 pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
846 items.push_back (CheckMenuElem(*pre_fader_mute_check));
847 pre_fader_mute_check->show_all();
849 post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
850 init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
851 post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
852 items.push_back (CheckMenuElem(*post_fader_mute_check));
853 post_fader_mute_check->show_all();
855 listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
856 init_mute_menu(MuteMaster::Listen, listen_mute_check);
857 listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
858 items.push_back (CheckMenuElem(*listen_mute_check));
859 listen_mute_check->show_all();
861 main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
862 init_mute_menu(MuteMaster::Main, main_mute_check);
863 main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
864 items.push_back (CheckMenuElem(*main_mute_check));
865 main_mute_check->show_all();
867 //items.push_back (SeparatorElem());
868 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
870 _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
874 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
876 check->set_active (_route->mute_points() & mp);
880 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
882 if (check->get_active()) {
883 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
885 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
890 RouteUI::muting_change ()
892 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
895 MuteMaster::MutePoint current = _route->mute_points ();
897 yn = (current & MuteMaster::PreFader);
899 if (pre_fader_mute_check->get_active() != yn) {
900 pre_fader_mute_check->set_active (yn);
903 yn = (current & MuteMaster::PostFader);
905 if (post_fader_mute_check->get_active() != yn) {
906 post_fader_mute_check->set_active (yn);
909 yn = (current & MuteMaster::Listen);
911 if (listen_mute_check->get_active() != yn) {
912 listen_mute_check->set_active (yn);
915 yn = (current & MuteMaster::Main);
917 if (main_mute_check->get_active() != yn) {
918 main_mute_check->set_active (yn);
923 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
925 _route->set_solo_isolated (check->get_active(), this);
929 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
931 _route->set_solo_safe (check->get_active(), this);
935 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
937 RouteGroup* route_group;
939 if((route_group = route->route_group()) != 0){
940 _session.begin_reversible_command (_("mix group solo change"));
941 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
942 route_group->apply(&Route::set_solo, yn, this);
944 _session.add_command (cmd);
945 _session.commit_reversible_command ();
947 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
952 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
954 _session.begin_reversible_command (name);
955 XMLNode &before = _route->get_state();
956 bind(mem_fun(*_route, func), yn, arg)();
957 XMLNode &after = _route->get_state();
958 _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
959 _session.commit_reversible_command ();
963 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
965 _session.begin_reversible_command (name);
966 XMLNode &before = track()->get_state();
967 bind (mem_fun (*track(), func), yn, arg)();
968 XMLNode &after = track()->get_state();
969 _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
970 _session.commit_reversible_command ();
974 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
976 RouteGroup* route_group;
978 if((route_group = route->route_group()) != 0){
979 _session.begin_reversible_command (_("mix group mute change"));
980 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
981 route_group->apply(&Route::set_mute, yn, this);
983 _session.add_command(cmd);
984 _session.commit_reversible_command ();
986 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
991 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
993 RouteGroup* route_group;
995 if((route_group = route->route_group()) != 0){
996 _session.begin_reversible_command (_("mix group rec-enable change"));
997 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
998 route_group->apply (&Route::set_record_enable, yn, this);
1000 _session.add_command(cmd);
1001 _session.commit_reversible_command ();
1003 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
1009 RouteUI::choose_color()
1014 color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1024 RouteUI::set_color (const Gdk::Color & c)
1031 snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1032 xml_node->add_property ("color", buf);
1034 _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1039 RouteUI::ensure_xml_node ()
1041 if (xml_node == 0) {
1042 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1043 xml_node = new XMLNode ("GUI");
1044 _route->add_extra_xml (*xml_node);
1050 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1054 XMLNodeList kids = xml_node->children();
1055 XMLNodeConstIterator iter;
1057 const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1059 for (iter = kids.begin(); iter != kids.end(); ++iter) {
1060 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1061 XMLProperty* type = (*iter)->property("automation-id");
1062 if (type && type->value() == sym)
1067 // Didn't find it, make a new one
1068 XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1069 child->add_property("automation-id", sym);
1070 xml_node->add_child_nocopy (*child);
1076 RouteUI::set_color_from_route ()
1080 RouteUI::ensure_xml_node ();
1082 if ((prop = xml_node->property ("color")) != 0) {
1084 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1086 _color.set_green(g);
1094 RouteUI::remove_this_route ()
1096 vector<string> choices;
1100 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());
1102 prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1105 choices.push_back (_("No, do nothing."));
1106 choices.push_back (_("Yes, remove it."));
1108 Choice prompter (prompt, choices);
1110 if (prompter.run () == 1) {
1111 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1116 RouteUI::idle_remove_this_route (RouteUI *rui)
1118 rui->_session.remove_route (rui->_route);
1123 RouteUI::route_rename ()
1125 ArdourPrompter name_prompter (true);
1127 name_prompter.set_prompt (_("New Name: "));
1128 name_prompter.set_initial_text (_route->name());
1129 name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1130 name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1131 name_prompter.show_all ();
1133 switch (name_prompter.run ()) {
1135 case Gtk::RESPONSE_ACCEPT:
1136 name_prompter.get_result (result);
1137 if (result.length()) {
1138 _route->set_name (result);
1148 RouteUI::name_changed ()
1150 ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1152 name_label.set_text (_route->name());
1156 RouteUI::toggle_route_active ()
1160 if (route_active_menu_item) {
1161 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1162 _route->set_active (!yn);
1168 RouteUI::route_active_changed ()
1170 if (route_active_menu_item) {
1171 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1176 RouteUI::toggle_polarity ()
1178 if (polarity_menu_item) {
1182 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1184 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1185 _route->set_phase_invert (x);
1187 name_label.set_text (X_("Ø ") + name_label.get_text());
1189 name_label.set_text (_route->name());
1196 RouteUI::polarity_changed ()
1198 if (_route->phase_invert()) {
1199 name_label.set_text (X_("Ø ") + name_label.get_text());
1201 name_label.set_text (_route->name());
1206 RouteUI::toggle_denormal_protection ()
1208 if (denormal_menu_item) {
1212 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1214 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1215 _route->set_denormal_protection (x);
1221 RouteUI::denormal_protection_changed ()
1223 if (denormal_menu_item) {
1224 denormal_menu_item->set_active (_route->denormal_protection());
1229 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1231 bool yn = _route->solo_isolated ();
1233 if (check->get_active() != yn) {
1234 check->set_active (yn);
1240 RouteUI::solo_safe_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1242 bool yn = _route->solo_safe ();
1244 if (check->get_active() != yn) {
1245 check->set_active (yn);
1250 RouteUI::disconnect_input ()
1252 _route->input()->disconnect (this);
1256 RouteUI::disconnect_output ()
1258 _route->output()->disconnect (this);
1262 RouteUI::is_track () const
1264 return boost::dynamic_pointer_cast<Track>(_route) != 0;
1267 boost::shared_ptr<Track>
1268 RouteUI::track() const
1270 return boost::dynamic_pointer_cast<Track>(_route);
1274 RouteUI::is_audio_track () const
1276 return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1279 boost::shared_ptr<AudioTrack>
1280 RouteUI::audio_track() const
1282 return boost::dynamic_pointer_cast<AudioTrack>(_route);
1286 RouteUI::is_midi_track () const
1288 return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1291 boost::shared_ptr<MidiTrack>
1292 RouteUI::midi_track() const
1294 return boost::dynamic_pointer_cast<MidiTrack>(_route);
1297 boost::shared_ptr<Diskstream>
1298 RouteUI::get_diskstream () const
1300 boost::shared_ptr<Track> t;
1302 if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1303 return t->diskstream();
1305 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1310 RouteUI::name() const
1312 return _route->name();
1316 RouteUI::map_frozen ()
1318 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1320 AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1323 switch (at->freeze_state()) {
1324 case AudioTrack::Frozen:
1325 rec_enable_button->set_sensitive (false);
1328 rec_enable_button->set_sensitive (true);
1335 RouteUI::adjust_latency ()
1337 LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1341 RouteUI::save_as_template ()
1344 Glib::ustring safe_name;
1347 path = ARDOUR::user_route_template_directory ();
1349 if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1350 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1354 Prompter p (true); // modal
1356 p.set_prompt (_("Template name:"));
1358 case RESPONSE_ACCEPT:
1365 p.get_result (name, true);
1367 safe_name = legalize_for_path (name);
1368 safe_name += template_suffix;
1372 _route->save_as_template (path.to_string(), name);
1376 RouteUI::check_rec_enable_sensitivity ()
1378 if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1379 rec_enable_button->set_sensitive (false);
1381 rec_enable_button->set_sensitive (true);
1386 RouteUI::parameter_changed (string const & p)
1388 ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1390 if (p == "disable-disarm-during-roll") {
1391 check_rec_enable_sensitivity ();
1392 } else if (p == "solo-control-is-listen-control") {
1393 set_button_names ();
1394 } else if (p == "listen-position") {
1395 set_button_names ();
1400 RouteUI::step_gain_up ()
1402 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1406 RouteUI::page_gain_up ()
1408 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1412 RouteUI::step_gain_down ()
1414 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1418 RouteUI::page_gain_down ()
1420 _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1424 RouteUI::open_remote_control_id_dialog ()
1426 ArdourDialog dialog (_("Remote Control ID"));
1428 uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1430 HBox* hbox = manage (new HBox);
1431 hbox->set_spacing (6);
1432 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1433 SpinButton* spin = manage (new SpinButton);
1434 spin->set_digits (0);
1435 spin->set_increments (1, 10);
1436 spin->set_range (0, limit);
1437 spin->set_value (_route->remote_control_id());
1438 hbox->pack_start (*spin);
1439 dialog.get_vbox()->pack_start (*hbox);
1441 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1442 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1445 int const r = dialog.run ();
1447 if (r == RESPONSE_ACCEPT) {
1448 _route->set_remote_control_id (spin->get_value_as_int ());