universal change in the design of the way Route/Track controls are designed and used...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 8 Apr 2016 20:49:47 +0000 (16:49 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:40 +0000 (15:30 -0400)
Massive changes all over the code to accomodate this. Many things are not finished. Consider this a backup safety commit

61 files changed:
gtk2_ardour/add_route_dialog.h
gtk2_ardour/ardour_ui.cc
gtk2_ardour/audio_streamview.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/editor_routes.cc
gtk2_ardour/gain_meter.cc
gtk2_ardour/group_tabs.cc
gtk2_ardour/meter_strip.cc
gtk2_ardour/midi_streamview.cc
gtk2_ardour/mixer_actor.cc
gtk2_ardour/mixer_strip.cc
gtk2_ardour/monitor_section.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/route_ui.cc
gtk2_ardour/route_ui.h
gtk2_ardour/streamview.cc
gtk2_ardour/time_axis_view.cc
libs/ardour/ardour/automation_control.h
libs/ardour/ardour/gain_control.h
libs/ardour/ardour/midi_track.h
libs/ardour/ardour/mute_master.h
libs/ardour/ardour/pan_controllable.h
libs/ardour/ardour/plugin_insert.h
libs/ardour/ardour/route.h
libs/ardour/ardour/route_group.h
libs/ardour/ardour/session.h
libs/ardour/ardour/session_event.h
libs/ardour/ardour/stripable.h
libs/ardour/ardour/track.h
libs/ardour/ardour/types.h
libs/ardour/ardour/utils.h
libs/ardour/ardour/vca.h
libs/ardour/audio_track.cc
libs/ardour/automation_control.cc
libs/ardour/enums.cc
libs/ardour/gain_control.cc
libs/ardour/luabindings.cc
libs/ardour/midi_track.cc
libs/ardour/mute_master.cc
libs/ardour/pan_controllable.cc
libs/ardour/parameter_descriptor.cc
libs/ardour/plugin_insert.cc
libs/ardour/route.cc
libs/ardour/route_controls.cc [deleted file]
libs/ardour/route_graph.cc
libs/ardour/route_group.cc
libs/ardour/session.cc
libs/ardour/session_midi.cc
libs/ardour/session_rtevents.cc
libs/ardour/session_transport.cc
libs/ardour/track.cc
libs/ardour/utils.cc
libs/ardour/vca.cc
libs/ardour/wscript
libs/pbd/pbd/controllable.h
libs/surfaces/control_protocol/control_protocol.cc
libs/surfaces/faderport/faderport.cc
libs/surfaces/faderport/operations.cc
libs/surfaces/mackie/mcp_buttons.cc
libs/surfaces/mackie/strip.cc
libs/surfaces/osc/osc.cc

index 51fccce4c94f5e5c9b16e709bac9735cb6845eb3..f10fc11292cd45d07d76304f2d571fa1e432a456 100644 (file)
@@ -54,7 +54,7 @@ class AddRouteDialog : public ArdourDialog
                MidiTrack,
                MixedTrack,
                AudioBus,
-               MidiBus
+               MidiBus,
                VCAMaster,
        };
        TypeWanted type_wanted() const;
index 1a5e131d3c614ed678581d7ec0fa05454b9b45ed..65b882fe6de1b81b49296dddc70119351fffb066 100644 (file)
@@ -92,7 +92,9 @@
 #include "ardour/source_factory.h"
 #include "ardour/slave.h"
 #include "ardour/system_exec.h"
+#include "ardour/track.h"
 #include "ardour/vca_manager.h"
+#include "ardour/utils.h"
 
 #include "LuaBridge/LuaBridge.h"
 
@@ -1570,7 +1572,7 @@ void
 ARDOUR_UI::count_recenabled_streams (Route& route)
 {
        Track* track = dynamic_cast<Track*>(&route);
-       if (track && track->record_enabled()) {
+       if (track && track->rec_enable_control()->get_value()) {
                rec_enabled_streams += track->n_inputs().n_total();
        }
 }
@@ -2083,14 +2085,14 @@ ARDOUR_UI::trx_record_enable_all_tracks ()
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
                assert (t);
 
-               if (t->record_enabled()) {
+               if (t->rec_enable_control()->get_value()) {
                        none_record_enabled = false;
                        break;
                }
        }
 
        if (none_record_enabled) {
-               _session->set_record_enabled (rl, true, Session::rt_cleanup);
+               _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), 1.0, Controllable::NoGroup);
        }
 
        return none_record_enabled;
@@ -2388,7 +2390,7 @@ ARDOUR_UI::toggle_record_enable (uint32_t rid)
                boost::shared_ptr<Track> t;
 
                if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
-                       t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
+                       t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
                }
        }
 }
@@ -5587,12 +5589,6 @@ void
 ARDOUR_UI::cancel_solo ()
 {
        if (_session) {
-               if (_session->soloing()) {
-                       _session->set_solo (_session->get_routes(), false);
-               } else if (_session->listening()) {
-                       _session->set_listen (_session->get_routes(), false);
-               }
-
                _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
        }
 }
index 2b0aea34cb9a8c6080121b4cbeeeefe9e2026874..9351a5da1f397183924923770fa0669d22c2f943 100644 (file)
@@ -186,7 +186,7 @@ AudioStreamView::setup_rec_box ()
 
                if (!rec_active &&
                    _trackview.session()->record_status() == Session::Recording &&
-                   _trackview.track()->record_enabled()) {
+                   _trackview.track()->rec_enable_control()->get_value()) {
                        if (_trackview.audio_track()->mode() == Normal && UIConfiguration::instance().get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) {
 
                                /* add a new region, but don't bother if they set show-waveforms-while-recording mid-record */
@@ -240,7 +240,7 @@ AudioStreamView::setup_rec_box ()
 
                } else if (rec_active &&
                           (_trackview.session()->record_status() != Session::Recording ||
-                           !_trackview.track()->record_enabled())) {
+                           !_trackview.track()->rec_enable_control()->get_value())) {
                        screen_update_connection.disconnect();
                        rec_active = false;
                        rec_updating = false;
index f7617e47933fea2e837a159a2b764838ee7d474c..eb84428f92b75f1b28edc0820d4e3ae6c993b214 100644 (file)
@@ -5699,11 +5699,11 @@ Editor::toggle_record_enable ()
                        continue;
 
                if (first) {
-                       new_state = !rtav->track()->record_enabled();
+                       new_state = !rtav->track()->rec_enable_control()->get_value();
                        first = false;
                }
 
-               rtav->track()->set_record_enabled (new_state, Controllable::UseGroup);
+               rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
        }
 }
 
@@ -5712,7 +5712,7 @@ Editor::toggle_solo ()
 {
        bool new_state = false;
        bool first = true;
-       boost::shared_ptr<RouteList> rl (new RouteList);
+       boost::shared_ptr<ControlList> cl (new ControlList);
 
        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
                RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
@@ -5726,10 +5726,10 @@ Editor::toggle_solo ()
                        first = false;
                }
 
-               rl->push_back (rtav->route());
+               cl->push_back (rtav->route()->solo_control());
        }
 
-       _session->set_solo (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
+       _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
 }
 
 void
@@ -5754,7 +5754,7 @@ Editor::toggle_mute ()
                rl->push_back (rtav->route());
        }
 
-       _session->set_mute (rl, new_state, Session::rt_cleanup, Controllable::UseGroup);
+       _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), new_state, Controllable::UseGroup);
 }
 
 void
index 6197e036293532b0e24528e739d2fd2748869212..9a2153f99f7866af3a23082b792e76e97e117864 100644 (file)
@@ -31,6 +31,8 @@
 #include "ardour/midi_track.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
+#include "ardour/solo_isolate_control.h"
+#include "ardour/utils.h"
 
 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
@@ -422,11 +424,8 @@ EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
        RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
        if (rtv && rtv->track()) {
-               DisplaySuspender ds;
-               boost::shared_ptr<RouteList> rl (new RouteList);
                // TODO check rec-safe and ...
-               rl->push_back (rtv->route());
-               _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
+               _session->set_control (rtv->track()->rec_enable_control(), !rtv->track()->rec_enable_control()->get_value(), Controllable::UseGroup);
        }
 }
 
@@ -455,9 +454,7 @@ EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
        RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
        if (rtv != 0) {
-               boost::shared_ptr<RouteList> rl (new RouteList);
-               rl->push_back (rtv->route());
-               _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
+               _session->set_control (rtv->route()->mute_control(), rtv->route()->mute_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
        }
 }
 
@@ -471,13 +468,15 @@ EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
        if (rtv != 0) {
-               boost::shared_ptr<RouteList> rl (new RouteList);
-               rl->push_back (rtv->route());
+               bool newval;
+
                if (Config->get_solo_control_is_listen_control()) {
-                       _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
+                       newval = !rtv->route()->listening_via_monitor();
                } else {
-                       _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
+                       newval = !rtv->route()->self_soloed();
                }
+
+               rtv->route()->solo_control()->set_value (newval ? 1.0 : 0.0, Controllable::UseGroup);
        }
 }
 
@@ -491,7 +490,7 @@ EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
        if (rtv) {
-               rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), Controllable::UseGroup);
+               rtv->route()->solo_isolate_control()->set_value (rtv->route()->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
        }
 }
 
@@ -505,7 +504,7 @@ EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
        if (rtv) {
-               rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), Controllable::UseGroup);
+               rtv->route()->solo_safe_control()->set_value (rtv->route()->solo_safe_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
        }
 }
 
@@ -734,8 +733,8 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
                row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
                row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
                row[_columns.solo_visible] = !(*x)->route()->is_master ();
-               row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
-               row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
+               row[_columns.solo_isolate_state] = (*x)->route()->solo_isolate_control()->solo_isolated();
+               row[_columns.solo_safe_state] = (*x)->route()->solo_safe_control()->solo_safe();
                row[_columns.name_editable] = true;
 
                boost::weak_ptr<Route> wr ((*x)->route());
@@ -745,8 +744,8 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
 
                if ((*x)->is_track()) {
                        boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
-                       t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
-                       t->RecordSafeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
+                       t->rec_enable_control()->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
+                       t->rec_safe_control()->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
                }
 
                if ((*x)->is_midi_track()) {
@@ -1280,25 +1279,27 @@ EditorRoutes::key_press (GdkEventKey* ev)
 
                case 'm':
                        if (get_relevant_routes (rl)) {
-                               _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
+                               _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), rl->front()->muted() ? 0.0 : 1.0, Controllable::NoGroup);
                        }
                        return true;
                        break;
 
                case 's':
                        if (get_relevant_routes (rl)) {
-                               if (Config->get_solo_control_is_listen_control()) {
-                                       _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
-                               } else {
-                                       _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
-                               }
+                               _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), rl->front()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
                        }
                        return true;
                        break;
 
                case 'r':
                        if (get_relevant_routes (rl)) {
-                               _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
+                               for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
+                                       boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
+                                       if (t) {
+                                               _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), !t->rec_enable_control()->get_value(), Controllable::NoGroup);
+                                               break;
+                                       }
+                               }
                        }
                        break;
 
@@ -1645,10 +1646,13 @@ EditorRoutes::idle_update_mute_rec_solo_etc()
                (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
                (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
                (*i)[_columns.active] = route->active ();
-               if (boost::dynamic_pointer_cast<Track> (route)) {
+
+               boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track>(route));
+
+               if (trk) {
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
 
-                       if (route->record_enabled()) {
+                       if (trk->rec_enable_control()->get_value()) {
                                if (_session->record_status() == Session::Recording) {
                                        (*i)[_columns.rec_state] = 1;
                                } else {
@@ -1660,8 +1664,8 @@ EditorRoutes::idle_update_mute_rec_solo_etc()
                                (*i)[_columns.rec_state] = 0;
                        }
 
-                       (*i)[_columns.rec_safe] = route->record_safe () ? 1 : 0;
-                       (*i)[_columns.name_editable] = !route->record_enabled ();
+                       (*i)[_columns.rec_safe] = !trk->rec_safe_control()->get_value();
+                       (*i)[_columns.name_editable] = !trk->rec_enable_control()->get_value();
                }
        }
 
index b38e653bac3edd7c0b4364092bbd1e5586782a70..baf4193d27fa0466b7bc345e9619f6e036388f3c 100644 (file)
@@ -479,10 +479,10 @@ GainMeterBase::gain_activated ()
        /* clamp to displayable values */
        if (_data_type == DataType::AUDIO) {
                f = min (f, 6.0f);
-               _control->set_value (dB_to_coefficient(f), Controllable::NoGroup);
+               _control->set_value (dB_to_coefficient(f), Controllable::UseGroup);
        } else {
                f = min (fabs (f), 2.0f);
-               _control->set_value (f, Controllable::NoGroup);
+               _control->set_value (f, Controllable::UseGroup);
        }
 
        if (gain_display.has_focus()) {
@@ -541,11 +541,7 @@ GainMeterBase::fader_moved ()
                        value = gain_adjustment.get_value();
                }
 
-               if (_route && _control == _route->gain_control()) {
-                       _route->set_gain (value, Controllable::UseGroup);
-               } else {
-                       _control->set_value (value, Controllable::NoGroup);
-               }
+               _control->set_value (value, Controllable::UseGroup);
        }
 
        show_gain ();
index 0e429e562a845ff760fb508f13f4a394c2bbe711..a930fbbce4b59d194cb71e8e8d68b31d0300617f 100644 (file)
@@ -366,7 +366,8 @@ GroupTabs::new_from_rec_enabled ()
        RouteList rec_enabled;
 
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if ((*i)->record_enabled()) {
+               boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (*i));
+               if (trk && trk->rec_enable_control()->get_value()) {
                        rec_enabled.push_back (*i);
                }
        }
index 82acd1dad579dc57de0c66eafbe8b59e47e9d5f1..b324a846ff7b68836ea3a24ea852108fc921c737 100644 (file)
@@ -366,7 +366,7 @@ MeterStrip::set_button_names()
 {
        mute_button->set_text (S_("Mute|M"));
 
-       if (_route && _route->solo_safe()) {
+       if (_route && _route->solo_safe_control()->solo_safe()) {
                solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
        } else {
                solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
index 9258cf027d385973dd4080f64bcce0a4c881cc31..e369c5842dfadd46cc68ae7f8be11143ea2ca5ce 100644 (file)
@@ -440,7 +440,7 @@ MidiStreamView::setup_rec_box ()
 
                if (!rec_active &&
                    _trackview.session()->record_status() == Session::Recording &&
-                   _trackview.track()->record_enabled()) {
+                   _trackview.track()->rec_enable_control()->get_value()) {
 
                        if (UIConfiguration::instance().get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) {
 
@@ -512,7 +512,7 @@ MidiStreamView::setup_rec_box ()
 
                } else if (rec_active &&
                           (_trackview.session()->record_status() != Session::Recording ||
-                           !_trackview.track()->record_enabled())) {
+                           !_trackview.track()->rec_enable_control()->get_value())) {
                        screen_update_connection.disconnect();
                        rec_active = false;
                        rec_updating = false;
index 7ffcc6f3a8698213f7f1546fe63bf917e6cc30fb..403f198d4fbe35fcdca18e1673d6ec014ff687e6 100644 (file)
@@ -172,7 +172,7 @@ printf("setting gain to unity (?)");
        BOOST_FOREACH(RouteUI* r, _route_targets) {
                boost::shared_ptr<Route> rp = r->route();
                if (rp) {
-                       rp->set_gain (1.0, Controllable::NoGroup);
+                       rp->gain_control()->set_value (1.0, Controllable::NoGroup);
                }
        }
 }
index 4b4b5f1110fe60bc5a7f7a2142184230bc8a88a6..5c130301279adf0b1747fae50aad9f237995f0ec 100644 (file)
@@ -950,7 +950,7 @@ MixerStrip::input_press (GdkEventButton *ev)
                return true;
        }
 
-       if (_session->actively_recording() && _route->record_enabled())
+       if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
                return true;
 
        switch (ev->button) {
@@ -1665,7 +1665,7 @@ MixerStrip::name_button_button_press (GdkEventButton* ev)
                list_route_operations ();
 
                /* do not allow rename if the track is record-enabled */
-               rename_menu_item->set_sensitive (!_route->record_enabled());
+               rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
                route_ops_menu->popup (1, ev->time);
 
                return true;
@@ -1681,7 +1681,7 @@ MixerStrip::name_button_button_release (GdkEventButton* ev)
                list_route_operations ();
 
                /* do not allow rename if the track is record-enabled */
-               rename_menu_item->set_sensitive (!_route->record_enabled());
+               rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
                route_ops_menu->popup (1, ev->time);
        }
 
@@ -1695,7 +1695,7 @@ MixerStrip::number_button_button_press (GdkEventButton* ev)
                list_route_operations ();
 
                /* do not allow rename if the track is record-enabled */
-               rename_menu_item->set_sensitive (!_route->record_enabled());
+               rename_menu_item->set_sensitive (!is_track() || !track()->rec_enable_control()->get_value());
                route_ops_menu->popup (1, ev->time);
 
                return true;
@@ -2141,7 +2141,7 @@ MixerStrip::set_button_names ()
                        monitor_section_button->set_text (_("Mon"));
                }
 
-               if (_route && _route->solo_safe()) {
+               if (_route && _route->solo_safe_control()->solo_safe()) {
                        solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
                } else {
                        solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
@@ -2170,7 +2170,7 @@ MixerStrip::set_button_names ()
                        monitor_section_button->set_text (S_("Mon|O"));
                }
 
-               if (_route && _route->solo_safe()) {
+               if (_route && _route->solo_safe_control()->solo_safe()) {
                        solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
                } else {
                        solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
index f24cab7c3e68a7c67444a6a5b1ff51c903dd23f8..e14b571723bd9ec53b090e3ab244258709bc8f08 100644 (file)
@@ -36,6 +36,7 @@
 #include "ardour/monitor_processor.h"
 #include "ardour/port.h"
 #include "ardour/route.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/user_bundle.h"
 #include "ardour/plugin_manager.h"
 
@@ -1246,7 +1247,7 @@ MonitorSection::cancel_isolate (GdkEventButton*)
 {
        if (_session) {
                boost::shared_ptr<RouteList> rl (_session->get_routes ());
-               _session->set_solo_isolated (rl, false, Session::rt_cleanup, Controllable::NoGroup);
+               _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
        }
 
        return true;
index 8c475f5acc9e4d19df421fc367dc65498b7beb56..f291af5dc58f286e3c95c0ce781c427f57b92ff3 100644 (file)
@@ -2493,7 +2493,11 @@ RouteTimeAxisView::can_edit_name () const
 {
        /* we do not allow track name changes if it is record enabled
         */
-       return !_route->record_enabled();
+       boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track> (_route));
+       if (!trk) {
+               return true;
+       }
+       return !trk->rec_enable_control()->get_value();
 }
 
 void
@@ -2724,7 +2728,7 @@ RouteTimeAxisView::remove_underlay (StreamView* v)
 void
 RouteTimeAxisView::set_button_names ()
 {
-       if (_route && _route->solo_safe()) {
+       if (_route && _route->solo_safe_control()->solo_safe()) {
                solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
        } else {
                solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
index afaf4561c8cd97e2fe0e5c2944308a159b25d4a6..09a9dc8972bd82e948bb081e8fd7ea54d2fbe30e 100644 (file)
 
 #include "ardour/dB.h"
 #include "ardour/route_group.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/vca.h"
 #include "ardour/vca_manager.h"
+#include "ardour/audio_track.h"
+#include "ardour/audioengine.h"
+#include "ardour/filename_extensions.h"
+#include "ardour/midi_track.h"
+#include "ardour/monitor_control.h"
+#include "ardour/internal_send.h"
+#include "ardour/profile.h"
+#include "ardour/phase_control.h"
+#include "ardour/send.h"
+#include "ardour/route.h"
+#include "ardour/session.h"
+#include "ardour/template_utils.h"
 
 #include "ardour_ui.h"
 #include "editor.h"
 #include "timers.h"
 #include "ui_config.h"
 
-#include "ardour/audio_track.h"
-#include "ardour/audioengine.h"
-#include "ardour/filename_extensions.h"
-#include "ardour/midi_track.h"
-#include "ardour/internal_send.h"
-#include "ardour/profile.h"
-#include "ardour/send.h"
-#include "ardour/route.h"
-#include "ardour/session.h"
-#include "ardour/template_utils.h"
 
 #include "i18n.h"
 using namespace Gtk;
@@ -270,10 +273,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
        _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
        _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
        _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
-
-       if (_route->phase_control()) {
-               _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
-       }
+       _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
 
        if (is_track()) {
                track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
@@ -290,8 +290,8 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
        if (_session->writable() && is_track()) {
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
 
-               t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
-               t->RecordSafeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
+               t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
+               t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
 
                rec_enable_button->show();
                rec_enable_button->set_controllable (t->rec_enable_control());
@@ -309,7 +309,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
 
        if (is_track()) {
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
-               t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
+               t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this, _1, _2), gui_context());
 
                update_monitoring_display ();
        }
@@ -383,7 +383,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                if (Keyboard::is_button2_event (ev)) {
                        // button2-click is "momentary"
 
-                       _mute_release = new SoloMuteRelease (_route->muted ());
+                       _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
                }
 
                if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
@@ -415,7 +415,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                }
 
                                DisplaySuspender ds;
-                               _session->set_mute (copy, !_route->muted());
+                               _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
 
                        } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
@@ -444,7 +444,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                        }
 
                                        DisplaySuspender ds;
-                                       _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, Controllable::InverseGroup);
+                                       _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::InverseGroup);
                                }
 
                        } else {
@@ -458,7 +458,7 @@ RouteUI::mute_press (GdkEventButton* ev)
                                        _mute_release->routes = rl;
                                }
 
-                               _session->set_mute (rl, !_route->muted());
+                               _session->set_control (_route->mute_control(), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
 
                        }
                }
@@ -472,7 +472,7 @@ RouteUI::mute_release (GdkEventButton* /*ev*/)
 {
        if (_mute_release){
                DisplaySuspender ds;
-               _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, Controllable::UseGroup);
+               _session->set_controls (route_list_to_control_list (_mute_release->routes, &Route::mute_control), _mute_release->active, Controllable::UseGroup);
                delete _mute_release;
                _mute_release = 0;
        }
@@ -572,11 +572,7 @@ RouteUI::solo_press(GdkEventButton* ev)
                                }
 
                                DisplaySuspender ds;
-                               if (Config->get_solo_control_is_listen_control()) {
-                                       _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::UseGroup);
-                               } else {
-                                       _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, Controllable::UseGroup);
-                               }
+                               _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
 
                        } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
 
@@ -600,14 +596,16 @@ RouteUI::solo_press(GdkEventButton* ev)
                                        /* ??? we need a just_one_listen() method */
                                } else {
                                        DisplaySuspender ds;
-                                       _session->set_just_one_solo (_route, true);
+                                       boost::shared_ptr<ControlList> cl (new ControlList);
+                                       cl->push_back (_route->solo_control());
+                                       _session->set_controls (cl, 1.0, Controllable::NoGroup);
                                }
 
                        } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
 
                                // shift-click: toggle solo isolated status
 
-                               _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
+                               _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
                                delete _solo_release;
                                _solo_release = 0;
 
@@ -647,11 +645,7 @@ RouteUI::solo_press(GdkEventButton* ev)
 
                                        DisplaySuspender ds;
 
-                                       if (Config->get_solo_control_is_listen_control()) {
-                                               _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::InverseGroup);
-                                       } else {
-                                               _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, Controllable::InverseGroup);
-                                       }
+                                       _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
                                }
 
                                delete _solo_release;
@@ -669,11 +663,7 @@ RouteUI::solo_press(GdkEventButton* ev)
                                }
 
                                DisplaySuspender ds;
-                               if (Config->get_solo_control_is_listen_control()) {
-                                       _session->set_listen (rl, !_route->listening_via_monitor());
-                               } else {
-                                       _session->set_solo (rl, !_route->self_soloed());
-                               }
+                               _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::UseGroup);
                        }
                }
        }
@@ -690,11 +680,7 @@ RouteUI::solo_release (GdkEventButton* /*ev*/)
 
                } else {
                        DisplaySuspender ds;
-                       if (Config->get_solo_control_is_listen_control()) {
-                               _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
-                       } else {
-                               _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
-                       }
+                       _session->set_controls (route_list_to_control_list (_solo_release->routes, &Route::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
                }
 
                delete _solo_release;
@@ -741,7 +727,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
                } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
 
                        DisplaySuspender ds;
-                       _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
+                       _session->set_controls (route_list_to_control_list (_session->get_routes(), &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
 
                } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
 
@@ -757,7 +743,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
                                rl->push_back (_route);
 
                                DisplaySuspender ds;
-                               _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
+                               _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
                        }
 
                } else if (Keyboard::is_context_menu_event (ev)) {
@@ -766,10 +752,8 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
 
                } else {
 
-                       boost::shared_ptr<RouteList> rl (new RouteList);
-                       rl->push_back (route());
-                       DisplaySuspender ds;
-                       _session->set_record_enabled (rl, !_route->record_enabled());
+                       boost::shared_ptr<Track> trk = track();
+                       _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
                }
        }
 
@@ -777,7 +761,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
 }
 
 void
-RouteUI::monitoring_changed ()
+RouteUI::monitoring_changed (bool, Controllable::GroupControlDisposition)
 {
        update_monitoring_display ();
 }
@@ -797,7 +781,7 @@ RouteUI::update_monitoring_display ()
 
        MonitorState ms = t->monitoring_state();
 
-       if (t->monitoring_choice() & MonitorInput) {
+       if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
                monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
        } else {
                if (ms & MonitoringInput) {
@@ -807,7 +791,7 @@ RouteUI::update_monitoring_display ()
                }
        }
 
-       if (t->monitoring_choice() & MonitorDisk) {
+       if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
                monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
        } else {
                if (ms & MonitoringDisk) {
@@ -863,8 +847,8 @@ RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
           signal together, which requires yet more buffers.
        */
 
-       if (t->monitoring_choice() & monitor_choice) {
-               mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
+       if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
+               mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
        } else {
                /* this line will change when the options are non-orthogonal */
                // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
@@ -887,7 +871,7 @@ RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
        }
 
        DisplaySuspender ds;
-       _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
+       _session->set_controls (route_list_to_control_list (rl, &Route::monitoring_control), (double) mc, Controllable::UseGroup);
 
        return false;
 }
@@ -912,7 +896,9 @@ RouteUI::build_record_menu ()
        }
 
        if (step_edit_item) {
-               step_edit_item->set_sensitive (!_route->record_enabled());
+               if (track()->rec_enable_control()->get_value()) {
+                       step_edit_item->set_sensitive (false);
+               }
                step_edit_item->set_active (midi_track()->step_editing());
        }
        if (rec_safe_item) {
@@ -924,7 +910,7 @@ RouteUI::build_record_menu ()
 void
 RouteUI::toggle_step_edit ()
 {
-       if (!is_midi_track() || _route->record_enabled()) {
+       if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
                return;
        }
 
@@ -1168,7 +1154,7 @@ RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
                return Gtkmm2ext::Off;
        }
 
-       if (r->solo_isolated()) {
+       if (r->solo_isolate_control()->solo_isolated()) {
                return Gtkmm2ext::ExplicitActive;
        } else {
                return Gtkmm2ext::Off;
@@ -1182,7 +1168,7 @@ RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
                return Gtkmm2ext::Off;
        }
 
-       if (r->solo_safe()) {
+       if (r->solo_safe_control()->solo_safe()) {
                return Gtkmm2ext::ExplicitActive;
        } else {
                return Gtkmm2ext::Off;
@@ -1192,13 +1178,13 @@ RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
 void
 RouteUI::update_solo_display ()
 {
-       bool yn = _route->solo_safe ();
+       bool yn = _route->solo_safe_control()->solo_safe ();
 
        if (solo_safe_check && solo_safe_check->get_active() != yn) {
                solo_safe_check->set_active (yn);
        }
 
-       yn = _route->solo_isolated ();
+       yn = _route->solo_isolate_control()->solo_isolated ();
 
        if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
                solo_isolated_check->set_active (yn);
@@ -1207,7 +1193,7 @@ RouteUI::update_solo_display ()
         set_button_names ();
 
         if (solo_isolated_led) {
-               if (_route->solo_isolated()) {
+               if (_route->solo_isolate_control()->solo_isolated()) {
                        solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
                } else {
                        solo_isolated_led->unset_active_state ();
@@ -1215,7 +1201,7 @@ RouteUI::update_solo_display ()
         }
 
         if (solo_safe_led) {
-               if (_route->solo_safe()) {
+               if (_route->solo_safe_control()->solo_safe()) {
                        solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
                } else {
                        solo_safe_led->unset_active_state ();
@@ -1248,7 +1234,7 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
                if (r->muted ()) {
                        /* full mute */
                        return Gtkmm2ext::ExplicitActive;
-               } else if (r->muted_by_others ()) {
+               } else if (r->muted_by_others_soloing ()) {
                        /* this will reflect both solo mutes AND master mutes */
                        return Gtkmm2ext::ImplicitActive;
                } else {
@@ -1261,10 +1247,11 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
                if (r->muted()) {
                        /* full mute */
                        return Gtkmm2ext::ExplicitActive;
-               } else if (r->mute_master()->muted_by_others()) {
+               } else if (r->muted_by_others()) {
                        /* note the direct use of MuteMaster API here. We are
                           not interested in showing
-                          others-soloed-so-this-muted status in this branch.
+                          others-soloed-so-this-muted status in this
+                          conditional branch.
                        */
                        return Gtkmm2ext::ImplicitActive;
                } else {
@@ -1335,11 +1322,16 @@ RouteUI::blink_rec_display (bool blinkOn)
        if (!rec_enable_button || !_route) {
                return;
        }
+
        if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
                return;
        }
 
-       if (_route->record_enabled()) {
+       if (!is_track()) {
+               return;
+       }
+
+       if (track()->rec_enable_control()->get_value()) {
                 switch (_session->record_status ()) {
                 case Session::Recording:
                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
@@ -1347,12 +1339,12 @@ RouteUI::blink_rec_display (bool blinkOn)
 
                 case Session::Disabled:
                 case Session::Enabled:
-                        if ( UIConfiguration::instance().get_blink_rec_arm() )
-                                                       rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
-                                               else
-                                                       rec_enable_button->set_active_state ( ImplicitActive );
+                       if (UIConfiguration::instance().get_blink_rec_arm()) {
+                               rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
+                       } else {
+                               rec_enable_button->set_active_state ( ImplicitActive );
+                       }
                         break;
-
                 }
 
                 if (step_edit_item) {
@@ -1381,14 +1373,14 @@ RouteUI::build_solo_menu (void)
        Gtk::CheckMenuItem* check;
 
        check = new Gtk::CheckMenuItem(_("Solo Isolate"));
-       check->set_active (_route->solo_isolated());
+       check->set_active (_route->solo_isolate_control()->solo_isolated());
        check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
        items.push_back (CheckMenuElem(*check));
         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
        check->show_all();
 
        check = new Gtk::CheckMenuItem(_("Solo Safe"));
-       check->set_active (_route->solo_safe());
+       check->set_active (_route->solo_safe_control()->solo_safe());
        check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
        items.push_back (CheckMenuElem(*check));
         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
@@ -1442,16 +1434,16 @@ RouteUI::build_mute_menu(void)
 void
 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
 {
-       check->set_active (_route->mute_points() & mp);
+       check->set_active (_route->mute_control()->mute_points() & mp);
 }
 
 void
 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
 {
        if (check->get_active()) {
-               _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
+               _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
        } else {
-               _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
+               _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
        }
 }
 
@@ -1461,7 +1453,7 @@ RouteUI::muting_change ()
        ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
 
        bool yn;
-       MuteMaster::MutePoint current = _route->mute_points ();
+       MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
 
        yn = (current & MuteMaster::PreFader);
 
@@ -1496,7 +1488,7 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
        }
 
        bool view = solo_isolated_led->active_state();
-       bool model = _route->solo_isolated();
+       bool model = _route->solo_isolate_control()->solo_isolated();
 
        /* called BEFORE the view has changed */
 
@@ -1506,11 +1498,11 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
                        if (model) {
                                /* disable isolate for all routes */
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
+                               _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
                        } else {
                                /* enable isolate for all routes */
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
+                               _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 1.0, Controllable::NoGroup);
                        }
 
                } else {
@@ -1522,7 +1514,7 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
                                boost::shared_ptr<RouteList> rl (new RouteList);
                                rl->push_back (_route);
                                DisplaySuspender ds;
-                               _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
+                               _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
                        }
                }
        }
@@ -1538,7 +1530,7 @@ RouteUI::solo_safe_button_release (GdkEventButton* ev)
        }
 
        bool view = solo_safe_led->active_state();
-       bool model = _route->solo_safe();
+       bool model = _route->solo_safe_control()->solo_safe();
 
        if (ev->button == 1) {
                if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
@@ -1547,20 +1539,20 @@ RouteUI::solo_safe_button_release (GdkEventButton* ev)
                                /* disable solo safe for all routes */
                                DisplaySuspender ds;
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                                       (*i)->set_solo_safe (false, Controllable::NoGroup);
+                                       (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
                                }
                        } else {
                                /* enable solo safe for all routes */
                                DisplaySuspender ds;
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-                                       (*i)->set_solo_safe (true, Controllable::NoGroup);
+                                       (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
                                }
                        }
                }
                else {
                        if (model == view) {
                                /* flip just this route */
-                               _route->set_solo_safe (!view, Controllable::NoGroup);
+                               _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
                        }
                }
        }
@@ -1572,19 +1564,19 @@ void
 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
 {
         bool view = check->get_active();
-        bool model = _route->solo_isolated();
+        bool model = _route->solo_isolate_control()->solo_isolated();
 
         /* called AFTER the view has changed */
 
         if (model != view) {
-               _route->set_solo_isolated (view, Controllable::UseGroup);
+               _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
         }
 }
 
 void
 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
 {
-       _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
+       _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
 }
 
 /** Ask the user to choose a colour, and then apply that color to my route
@@ -2022,25 +2014,25 @@ RouteUI::parameter_changed (string const & p)
 void
 RouteUI::step_gain_up ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
+       _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
 }
 
 void
 RouteUI::page_gain_up ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
+       _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
 }
 
 void
 RouteUI::step_gain_down ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
+       _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
 }
 
 void
 RouteUI::page_gain_down ()
 {
-       _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
+       _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
 }
 
 void
@@ -2158,9 +2150,9 @@ RouteUI::set_invert_button_state ()
 
                ArdourButton* b = _invert_buttons.front ();
 
-               if (_route->phase_invert().count() == _route->phase_invert().size()) {
+               if (_route->phase_control()->count() == _route->phase_control()->size()) {
                        b->set_active_state (Gtkmm2ext::ExplicitActive);
-               } else if (_route->phase_invert().any()) {
+               } else if (_route->phase_control()->any()) {
                        b->set_active_state (Gtkmm2ext::ImplicitActive);
                } else {
                        b->set_active_state (Gtkmm2ext::Off);
@@ -2172,7 +2164,7 @@ RouteUI::set_invert_button_state ()
 
                int j = 0;
                for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
-                       (*i)->set_active (_route->phase_invert (j));
+                       (*i)->set_active (_route->phase_control()->inverted (j));
                }
 
        }
@@ -2185,7 +2177,7 @@ RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
                uint32_t const N = _route->input()->n_ports().n_audio ();
                if (N <= _max_invert_buttons) {
                        /* left-click inverts phase so long as we have a button per channel */
-                       _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
+                       _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
                        return false;
                }
        }
@@ -2216,7 +2208,7 @@ RouteUI::invert_press (GdkEventButton* ev)
                items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
                Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
                ++_i_am_the_modifier;
-               e->set_active (_route->phase_invert (i));
+               e->set_active (_route->phase_control()->inverted (i));
                --_i_am_the_modifier;
        }
 
@@ -2232,7 +2224,8 @@ RouteUI::invert_menu_toggled (uint32_t c)
                return;
        }
 
-       _route->set_phase_invert (c, !_route->phase_invert (c));
+
+       _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
 }
 
 void
index 788c65101b60137472a13b2413762098229f2a3a..8be2c227fff3b3db7fd5f5b2a081e0fef425a22a 100644 (file)
@@ -156,7 +156,7 @@ class RouteUI : public virtual AxisView
        bool monitor_input_release(GdkEventButton*);
        bool monitor_disk_press(GdkEventButton*);
        bool monitor_disk_release(GdkEventButton*);
-       void monitoring_changed ();
+       void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
        void update_monitoring_display ();
 
        void edit_input_configuration ();
index 28dd1ab8f10c775dad6db99ff39fed09aa0b788d..bf14eaf2e29f1f6f8a6d9f05978c324b9c2133bf 100644 (file)
@@ -78,7 +78,7 @@ StreamView::StreamView (RouteTimeAxisView& tv, ArdourCanvas::Container* canvas_g
 
        if (_trackview.is_track()) {
                _trackview.track()->DiskstreamChanged.connect (*this, invalidator (*this), boost::bind (&StreamView::diskstream_changed, this), gui_context());
-               _trackview.track()->RecordEnableChanged.connect (*this, invalidator (*this), boost::bind (&StreamView::rec_enable_changed, this), gui_context());
+               _trackview.track()->rec_enable_control()->Changed.connect (*this, invalidator (*this), boost::bind (&StreamView::rec_enable_changed, this), gui_context());
 
                _trackview.session()->TransportStateChange.connect (*this, invalidator (*this), boost::bind (&StreamView::transport_changed, this), gui_context());
                _trackview.session()->TransportLooped.connect (*this, invalidator (*this), boost::bind (&StreamView::transport_looped, this), gui_context());
index 6b780a7fc7e899b9ed4fecace543687b568a3134..2ce40844c5dd00fae4cee0ccbd8e52bf4d6f4839 100644 (file)
@@ -763,7 +763,7 @@ TimeAxisView::end_name_edit (int response)
 
                                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
 
-                               if (rtav && rtav->route()->record_enabled()) {
+                               if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
                                        continue;
                                }
 
@@ -794,7 +794,7 @@ TimeAxisView::end_name_edit (int response)
 
                                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
 
-                               if (rtav && rtav->route()->record_enabled()) {
+                               if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
                                        continue;
                                }
 
index 455e8891c108fc187c3f7b6ba021de4bc72e5ef7..d84f0a091fc8573af4922fc99c06faee074b5290 100644 (file)
@@ -41,7 +41,7 @@ namespace ARDOUR {
 
 class Session;
 class Automatable;
-
+class ControlGroup;
 
 /** A PBD::Controllable with associated automation data (AutomationList)
  */
@@ -50,7 +50,7 @@ class LIBARDOUR_API AutomationControl
        , public Evoral::Control
        , public boost::enable_shared_from_this<AutomationControl>
 {
-public:
+    public:
        AutomationControl(ARDOUR::Session&,
                          const Evoral::Parameter&                  parameter,
                          const ParameterDescriptor&                desc,
@@ -87,8 +87,6 @@ public:
        void stop_touch(bool mark, double when);
 
        /* inherited from PBD::Controllable.
-        * Derived classes MUST call ::writable() to verify
-        * that writing to the parameter is legal at that time.
         */
        double get_value () const;
        /* inherited from PBD::Controllable.
@@ -99,10 +97,11 @@ public:
        /* automation related value setting */
        virtual bool writable () const;
        /* Call to ::set_value() with no test for writable() because
-        * this is only used by automation playback. We would like
-        * to make it pure virtual
+        * this is only used by automation playback.
         */
-       virtual void set_value_unchecked (double val) {}
+       void set_value_unchecked (double val) {
+               actually_set_value (val, PBD::Controllable::NoGroup);
+       }
 
        double lower()   const { return _desc.lower; }
        double upper()   const { return _desc.upper; }
@@ -117,6 +116,37 @@ public:
        const ARDOUR::Session& session() const { return _session; }
        void commit_transaction (bool did_write);
 
+       void set_group (boost::shared_ptr<ControlGroup>);
+
+  protected:
+       ARDOUR::Session& _session;
+       boost::shared_ptr<ControlGroup> _group;
+
+       const ParameterDescriptor _desc;
+
+       bool check_rt (double val, Controllable::GroupControlDisposition gcd);
+
+       /* derived classes may reimplement this, but should either
+          call this explicitly inside their version OR make sure that the
+          Controllable::Changed signal is emitted when necessary.
+       */
+
+       virtual void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
+};
+
+class SlavableAutomationControl : public AutomationControl
+{
+    public:
+       SlavableAutomationControl(ARDOUR::Session&,
+                         const Evoral::Parameter&                  parameter,
+                         const ParameterDescriptor&                desc,
+                         boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
+                         const std::string&                        name="");
+
+       ~SlavableAutomationControl ();
+
+       double get_value () const;
+
        void add_master (boost::shared_ptr<AutomationControl>);
        void remove_master (boost::shared_ptr<AutomationControl>);
        void clear_masters ();
@@ -126,11 +156,7 @@ public:
 
        PBD::Signal0<void> MasterStatusChange;
 
-  protected:
-       ARDOUR::Session& _session;
-
-       const ParameterDescriptor _desc;
-
+    protected:
 
        class MasterRecord {
           public:
@@ -155,12 +181,12 @@ public:
        typedef std::map<PBD::ID,MasterRecord> Masters;
        Masters _masters;
        PBD::ScopedConnectionList masters_connections;
-
        virtual void master_changed (bool from_self, GroupControlDisposition gcd);
        void master_going_away (boost::weak_ptr<AutomationControl>);
        virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
        virtual double get_masters_value_locked () const;
        double get_value_locked() const;
+
 };
 
 
index 4ec538e698192577371e7c27739f23cf188501ef..f68ec00452513423dbeada87e965fd4086ddf272 100644 (file)
@@ -34,14 +34,11 @@ namespace ARDOUR {
 
 class Session;
 
-class LIBARDOUR_API GainControl : public AutomationControl {
+class LIBARDOUR_API GainControl : public SlavableAutomationControl {
   public:
        GainControl (Session& session, const Evoral::Parameter &param,
                     boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>());
 
-       void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
-       void set_value_unchecked (double);
-
        double internal_to_interface (double) const;
        double interface_to_internal (double) const;
        double internal_to_user (double) const;
@@ -54,6 +51,8 @@ class LIBARDOUR_API GainControl : public AutomationControl {
        int set_state (XMLNode const&, int);
        XMLNode& get_state();
 
+       void inc_gain (gain_t);
+
   private:
        std::string masters_string;
        PBD::ScopedConnection vca_loaded_connection;
@@ -61,7 +60,7 @@ class LIBARDOUR_API GainControl : public AutomationControl {
        void vcas_loaded();
        void recompute_masters_ratios (double val);
 
-       void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+       void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
 };
 
 } /* namespace */
index ed138323601de36bc5ac3fc36223274881fbae5d..69f498104756dc2a10258ed0351e443eabe3e437 100644 (file)
@@ -50,8 +50,9 @@ public:
 
        boost::shared_ptr<Diskstream> create_diskstream ();
        void set_diskstream (boost::shared_ptr<Diskstream>);
-       void set_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
-       void set_record_safe (bool yn, PBD::Controllable::GroupControlDisposition);
+
+       bool can_be_record_enabled ();
+       bool can_be_record_safe ();
 
        DataType data_type () const {
                return DataType::MIDI;
@@ -89,14 +90,12 @@ public:
                        , _route (route)
                {}
 
-               void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
                bool writable() const { return true; }
 
                MidiTrack* _route;
 
        private:
-               void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+               void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
        };
 
        virtual void set_parameter_automation_state (Evoral::Parameter param, AutoState);
@@ -133,7 +132,6 @@ public:
        PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
        boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
 
-       void set_monitoring (MonitorChoice, PBD::Controllable::GroupControlDisposition);
        MonitorState monitoring_state () const;
 
        void set_input_active (bool);
@@ -144,6 +142,7 @@ protected:
        XMLNode& state (bool full);
 
        void act_on_mute ();
+       void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
 
 private:
        MidiRingBuffer<framepos_t> _immediate_events;
index 14597cb56b1aa906fd14bc2c74738fdcd5426bb2..d147a587716d8a349c51272043b58d785ee16b0a 100644 (file)
 #ifndef __ardour_mute_master_h__
 #define __ardour_mute_master_h__
 
-#include "evoral/Parameter.hpp"
+#include <string>
+
 #include "pbd/signals.h"
 #include "pbd/stateful.h"
-#include <string>
+
+#include "evoral/Parameter.hpp"
 
 #include "ardour/session_handle.h"
+#include "ardour/types.h"
 
 namespace ARDOUR {
 
@@ -73,6 +76,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
 
        XMLNode& get_state();
        int set_state(const XMLNode&, int version);
+       static const std::string xml_node_name;
 
   private:
        MutePoint _mute_point;
index 85a4efe2fc17dbace82686bb80abc63b422f32a5..26f0707ff7d7c6147d0ca196ff830dbd290616ae 100644 (file)
@@ -47,12 +47,10 @@ class LIBARDOUR_API PanControllable : public AutomationControl
        {}
 
        double lower () const;
-       void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       void set_value_unchecked (double);
 
   private:
        Pannable* owner;
-       void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
+       void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
 };
 
 } // namespace
index 4b5f38964a3f528ad4dd2e09edeac9c359e7caa1..70bbd76a714fce8c69fe0de33bd965f9129db6e4 100644 (file)
@@ -185,15 +185,13 @@ class LIBARDOUR_API PluginInsert : public Processor
                               const ParameterDescriptor&        desc,
                               boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
 
-               void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
                double get_value (void) const;
                void catch_up_with_external_value (double val);
                XMLNode& get_state();
 
        private:
                PluginInsert* _plugin;
-               void _set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
+               void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
        };
 
        /** A control that manipulates a plugin property (message). */
@@ -204,10 +202,10 @@ class LIBARDOUR_API PluginInsert : public Processor
                                       const ParameterDescriptor&        desc,
                                       boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
 
-               void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
                double get_value (void) const;
                XMLNode& get_state();
+        protected:
+               void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
 
        private:
                PluginInsert* _plugin;
index 9abe56afcb13fba5831ba7054933e937bd6b73db..6c0380963df8f5210dab3b0ea6cebc6205e78177 100644 (file)
@@ -28,7 +28,6 @@
 
 #include <boost/shared_ptr.hpp>
 #include <boost/weak_ptr.hpp>
-#include <boost/dynamic_bitset.hpp>
 #include <boost/enable_shared_from_this.hpp>
 
 #include <glibmm/threads.h>
 #include "ardour/io_vector.h"
 #include "ardour/libardour_visibility.h"
 #include "ardour/types.h"
+#include "ardour/monitorable.h"
+#include "ardour/muteable.h"
 #include "ardour/mute_master.h"
+#include "ardour/mute_control.h"
 #include "ardour/route_group_member.h"
 #include "ardour/stripable.h"
 #include "ardour/graphnode.h"
 #include "ardour/automatable.h"
 #include "ardour/unknown_processor.h"
+#include "ardour/soloable.h"
+#include "ardour/solo_control.h"
+#include "ardour/solo_safe_control.h"
 
 class RoutePinWindowProxy;
 
@@ -74,8 +79,18 @@ class Pannable;
 class CapturingProcessor;
 class InternalSend;
 class VCA;
-
-class LIBARDOUR_API Route : public Stripable, public Automatable, public RouteGroupMember, public GraphNode, public boost::enable_shared_from_this<Route>
+class SoloIsolateControl;
+class PhaseControl;
+class MonitorControl;
+
+class LIBARDOUR_API Route : public Stripable,
+                            public Soloable,
+                            public Muteable,
+                            public Monitorable,
+                            public Automatable,
+                            public RouteGroupMember,
+                            public GraphNode,
+                            public boost::enable_shared_from_this<Route>
 {
 public:
 
@@ -119,7 +134,7 @@ public:
        bool is_master() const { return _flags & MasterOut; }
        bool is_monitor() const { return _flags & MonitorOut; }
 
-       virtual MonitorState monitoring_state () const;
+       MonitorState monitoring_state () const;
        virtual MeterState metering_state () const;
 
        /* these are the core of the API of a Route. see the protected sections as well */
@@ -135,10 +150,6 @@ public:
 
        virtual bool can_record() { return false; }
 
-       virtual void set_record_enabled (bool /*yn*/, PBD::Controllable::GroupControlDisposition) {}
-       virtual bool record_enabled() const { return false; }
-       virtual void set_record_safe (bool /*yn*/, PBD::Controllable::GroupControlDisposition) {}
-       virtual bool record_safe () const {return false; }
        virtual void nonrealtime_handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
        virtual void realtime_handle_transport_stopped () {}
        virtual void realtime_locate () {}
@@ -149,47 +160,31 @@ public:
 
        void shift (framepos_t, framecnt_t);
 
-       void set_gain (gain_t val, PBD::Controllable::GroupControlDisposition);
-       void inc_gain (gain_t delta);
-
        void set_trim (gain_t val, PBD::Controllable::GroupControlDisposition);
 
-       void set_mute_points (MuteMaster::MutePoint);
-       MuteMaster::MutePoint mute_points () const;
-
-       bool muted () const;
-       void set_mute (bool yn, PBD::Controllable::GroupControlDisposition);
-
-       bool muted_by_others_soloing () const;
-       bool muted_by_others () const;
-
        /* controls use set_solo() to modify this route's solo state
         */
 
-       void set_solo (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       bool soloed () const { return self_soloed () || soloed_by_others (); }
        void clear_all_solo_state ();
 
-       bool soloed_by_others () const { return _soloed_by_others_upstream||_soloed_by_others_downstream; }
-       bool soloed_by_others_upstream () const { return _soloed_by_others_upstream; }
-       bool soloed_by_others_downstream () const { return _soloed_by_others_downstream; }
-       bool self_soloed () const { return _self_solo; }
-
-       void set_solo_isolated (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       bool solo_isolated() const;
+       bool soloed_by_others () const { return _solo_control->soloed_by_others(); }
+       bool soloed_by_others_upstream () const { return _solo_control->soloed_by_others_upstream(); }
+       bool soloed_by_others_downstream () const { return _solo_control->soloed_by_others_downstream(); }
+       bool self_soloed () const { return _solo_control->self_soloed(); }
+       bool soloed () const { return self_soloed () || soloed_by_others (); }
 
-       void set_solo_safe (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       bool solo_safe() const;
+       void push_solo_upstream (int32_t delta);
+       void push_solo_isolate_upstream (int32_t delta);
+       bool can_solo () const {
+               return !(is_master() || is_monitor() || is_auditioner());
+       }
+       bool is_safe () const {
+               return _solo_safe_control->get_value();
+       }
 
-       void set_listen (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
        bool listening_via_monitor () const;
        void enable_monitor_send ();
 
-       void set_phase_invert (uint32_t, bool yn);
-       void set_phase_invert (boost::dynamic_bitset<>);
-       bool phase_invert (uint32_t) const;
-       boost::dynamic_bitset<> phase_invert () const;
-
        void set_denormal_protection (bool yn);
        bool denormal_protection() const;
 
@@ -353,7 +348,6 @@ public:
        PBD::Signal0<void>       active_changed;
        PBD::Signal0<void>       denormal_protection_changed;
        PBD::Signal0<void>       comment_changed;
-       PBD::Signal0<void>       mute_points_changed;
 
        /** track numbers - assigned by session
         * nubers > 0 indicate tracks (audio+midi)
@@ -456,185 +450,32 @@ public:
 
        boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
 
-       class RouteAutomationControl : public AutomationControl {
-       public:
-               RouteAutomationControl (const std::string& name,
-                                       AutomationType atype,
-                                       boost::shared_ptr<AutomationList> alist,
-                                       boost::shared_ptr<Route> route);
-       protected:
-               friend class Route;
-
-               void route_set_value (double val) {
-                       AutomationControl::set_value (val, Controllable::NoGroup);
-               }
-
-               boost::weak_ptr<Route> _route;
-       };
-
-       class BooleanRouteAutomationControl : public RouteAutomationControl {
-       public:
-               BooleanRouteAutomationControl (const std::string& name,
-                                              AutomationType atype,
-                                              boost::shared_ptr<AutomationList> alist,
-                                              boost::shared_ptr<Route> route)
-                       : RouteAutomationControl (name, atype, alist, route) {}
-       protected:
-               double get_masters_value_locked() const;
-
-       };
-
-       class GainControllable : public GainControl  {
-       public:
-               GainControllable (Session& session,
-                                 AutomationType type,
-                                 boost::shared_ptr<Route> route);
-
-               void set_value (double val, PBD::Controllable::GroupControlDisposition group_override) {
-                       boost::shared_ptr<Route> r = _route.lock();
-                       if (r) {
-                               /* Route must mediate group control */
-                               r->set_control ((AutomationType) parameter().type(), val, group_override);
-                       }
-               }
-
-       protected:
-               friend class Route;
-
-               void route_set_value (double val) {
-                       GainControl::set_value (val, Controllable::NoGroup);
-               }
-
-               boost::weak_ptr<Route> _route;
-       };
-
-       class SoloControllable : public BooleanRouteAutomationControl {
-           public:
-               SoloControllable (std::string name, boost::shared_ptr<Route>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
-               double get_value () const;
-
-               /* Export additional API so that objects that only get access
-                * to a Controllable/AutomationControl can do more fine-grained
-                * operations with respect to solo. Obviously, they would need
-                * to dynamic_cast<Route::SoloControllable> first.
-                *
-                * Solo state is not representable by a single scalar value,
-                * so this AutomationControl maps set_value() and get_value()
-                * to r->set_self_solo() and r->soloed() respectively. This
-                * means that the Controllable is technically asymmetric. It is
-                * possible to call ::set_value (0.0) to disable (self)solo,
-                * and then call ::get_value() and get a return of 1.0 because
-                * the Route owner is soloed by upstream/downstream.
-                */
-
-               void set_self_solo (bool yn) {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) r->set_self_solo (yn);
-               }
-               void mod_solo_by_others_upstream (int32_t delta) {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) r->mod_solo_by_others_upstream (delta);
-               }
-               void mod_solo_by_others_downstream (int32_t delta) {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) r->mod_solo_by_others_downstream (delta);
-               }
-               bool soloed_by_others () const {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others(); else return false;
-               }
-               bool soloed_by_others_upstream () const {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others_upstream(); else return false;
-               }
-               bool soloed_by_others_downstream () const {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) return r->soloed_by_others_downstream(); else return false;
-               }
-               bool self_soloed () const {
-                       boost::shared_ptr<Route> r(_route.lock()); if (r) return r->self_soloed(); else return false;
-               }
-
-           protected:
-               void master_changed (bool, PBD::Controllable::GroupControlDisposition);
-
-           private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       struct MuteControllable : public BooleanRouteAutomationControl {
-           public:
-               MuteControllable (std::string name, boost::shared_ptr<Route>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
-               double get_value () const;
-
-               /* Pretend to change value, but do not affect actual route mute. */
-               void set_superficial_value(bool muted);
-           protected:
-               void master_changed (bool, PBD::Controllable::GroupControlDisposition);
-
-           private:
-               boost::weak_ptr<Route> _route;
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       class LIBARDOUR_API PhaseControllable : public BooleanRouteAutomationControl {
-       public:
-               PhaseControllable (std::string name, boost::shared_ptr<Route>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               /* currently no automation, so no need for set_value_unchecked() */
-               void set_channel (uint32_t);
-               double get_value () const;
-               uint32_t channel() const;
-       private:
-               uint32_t _current_phase;
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       class LIBARDOUR_API SoloIsolateControllable : public BooleanRouteAutomationControl {
-       public:
-               SoloIsolateControllable (std::string name, boost::shared_ptr<Route>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               /* currently no automation, so no need for set_value_unchecked() */
-               double get_value () const;
-       private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       class LIBARDOUR_API SoloSafeControllable : public BooleanRouteAutomationControl {
-       public:
-               SoloSafeControllable (std::string name, boost::shared_ptr<Route>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               /* currently no automation, so no need for set_value_unchecked() */
-               double get_value () const;
-       private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       void set_control (AutomationType, double val, PBD::Controllable::GroupControlDisposition group_override);
-
-       boost::shared_ptr<AutomationControl> solo_control() const {
+       boost::shared_ptr<SoloControl> solo_control() const {
                return _solo_control;
        }
 
-       boost::shared_ptr<AutomationControl> mute_control() const {
+       boost::shared_ptr<MuteControl> mute_control() const {
                return _mute_control;
        }
 
-       boost::shared_ptr<MuteMaster> mute_master() const {
-               return _mute_master;
-       }
+       bool can_be_muted_by_others () const { return !is_master(); }
+       bool muted () const { return _mute_control->muted(); }
+       bool muted_by_others_soloing () const;
+       bool muted_by_others () const;
 
-       boost::shared_ptr<AutomationControl> solo_isolate_control() const {
+       boost::shared_ptr<SoloIsolateControl> solo_isolate_control() const {
                return _solo_isolate_control;
        }
 
-       boost::shared_ptr<AutomationControl> solo_safe_control() const {
+       boost::shared_ptr<SoloSafeControl> solo_safe_control() const {
                return _solo_safe_control;
        }
 
-       boost::shared_ptr<AutomationControl> monitoring_control() const {
+       boost::shared_ptr<MonitorControl> monitoring_control() const {
                /* tracks override this to provide actual monitoring control;
                   busses have no possible choices except input monitoring.
                */
-               return boost::shared_ptr<AutomationControl> ();
+               return boost::shared_ptr<MonitorControl> ();
        }
 
        /* Route doesn't own these items, but sub-objects that it does own have them
@@ -647,8 +488,8 @@ public:
        boost::shared_ptr<Pannable> pannable() const;
 
        boost::shared_ptr<GainControl> gain_control() const;
-       boost::shared_ptr<AutomationControl> trim_control() const;
-       boost::shared_ptr<AutomationControl> phase_control() const;
+       boost::shared_ptr<GainControl> trim_control() const;
+       boost::shared_ptr<PhaseControl> phase_control() const;
 
        /**
           Return the first processor that accepts has at least one MIDI input
@@ -766,8 +607,8 @@ public:
         friend class Session;
 
        void catch_up_on_solo_mute_override ();
-       void mod_solo_by_others_upstream (int32_t);
-       void mod_solo_by_others_downstream (int32_t);
+       void set_listen (bool);
+
        void curve_reallocate ();
        virtual void set_block_size (pframes_t nframes);
 
@@ -829,14 +670,6 @@ protected:
        MeterPoint     _meter_point;
        MeterPoint     _pending_meter_point;
        MeterType      _meter_type;
-       boost::dynamic_bitset<> _phase_invert;
-       bool           _self_solo;
-       uint32_t       _soloed_by_others_upstream;
-       uint32_t       _soloed_by_others_downstream;
-       bool           _solo_isolated;
-       uint32_t       _solo_isolated_by_upstream;
-
-       void mod_solo_isolated_by_upstream (bool);
 
        bool           _denormal_protection;
 
@@ -844,18 +677,14 @@ protected:
        bool _silent : 1;
        bool _declickable : 1;
 
-       boost::shared_ptr<SoloControllable> _solo_control;
-       boost::shared_ptr<MuteControllable> _mute_control;
-       boost::shared_ptr<MuteMaster> _mute_master;
-       boost::shared_ptr<PhaseControllable> _phase_control;
-       boost::shared_ptr<SoloIsolateControllable> _solo_isolate_control;
-       boost::shared_ptr<SoloSafeControllable> _solo_safe_control;
-
-       virtual void act_on_mute () {}
+       boost::shared_ptr<SoloControl> _solo_control;
+       boost::shared_ptr<MuteControl> _mute_control;
+       boost::shared_ptr<PhaseControl> _phase_control;
+       boost::shared_ptr<SoloIsolateControl> _solo_isolate_control;
+       boost::shared_ptr<SoloSafeControl> _solo_safe_control;
 
        std::string    _comment;
        bool           _have_internal_generator;
-       bool           _solo_safe;
        DataType       _default_type;
        FedBy          _fed_by;
 
@@ -882,9 +711,9 @@ protected:
 
        virtual void maybe_declick (BufferSet&, framecnt_t, int);
 
-       boost::shared_ptr<GainControllable> _gain_control;
+       boost::shared_ptr<GainControl> _gain_control;
        boost::shared_ptr<Amp>       _amp;
-       boost::shared_ptr<GainControllable> _trim_control;
+       boost::shared_ptr<GainControl> _trim_control;
        boost::shared_ptr<Amp>       _trim;
        boost::shared_ptr<PeakMeter> _meter;
        boost::shared_ptr<DelayLine> _delayline;
@@ -928,7 +757,6 @@ private:
        void placement_range (Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end);
 
        void set_self_solo (bool yn);
-       void set_mute_master_solo ();
 
        void set_processor_positions ();
        framecnt_t update_port_latencies (PortSet& ports, PortSet& feeders, bool playback, framecnt_t) const;
@@ -985,6 +813,7 @@ private:
        void reset_instrument_info ();
 
        void set_remote_control_id_internal (uint32_t id, bool notify_class_listeners = true);
+        void solo_control_changed (bool self, PBD::Controllable::GroupControlDisposition);
 };
 
 } // namespace ARDOUR
index 95affaeaf5073925879b160194c1577fc36fc2a6..feeac6a467cba170104ff4f87888ef191377c6cd 100644 (file)
 #include "pbd/signals.h"
 #include "pbd/stateful.h"
 
-#include "ardour/libardour_visibility.h"
+#include "ardour/control_group.h"
 #include "ardour/types.h"
 #include "ardour/session_object.h"
 
+#include "ardour/libardour_visibility.h"
+
 namespace ARDOUR {
 
 namespace Properties {
@@ -157,8 +159,17 @@ class LIBARDOUR_API RouteGroup : public SessionObject
        PBD::Property<bool> _color;
        PBD::Property<bool> _monitoring;
 
+       boost::shared_ptr<ControlGroup> _solo_group;
+       boost::shared_ptr<ControlGroup> _mute_group;
+       boost::shared_ptr<ControlGroup> _rec_enable_group;
+       boost::shared_ptr<ControlGroup> _gain_group;
+       boost::shared_ptr<ControlGroup> _monitoring_group;
+
        void remove_when_going_away (boost::weak_ptr<Route>);
        int set_state_2X (const XMLNode&, int);
+
+       void post_set (PBD::PropertyChange const &);
+       void push_to_groups ();
 };
 
 } /* namespace */
index 18507ee5d9d59dc465ce64472699da54a516f5df..786751dea52a64f2fc80659dde8477e5e58e372c 100644 (file)
@@ -791,16 +791,13 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
 
        static const SessionEvent::RTeventCallback rt_cleanup;
 
-       void set_solo (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_implicit_solo (boost::shared_ptr<RouteList>, int delta, bool up_or_downstream, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
        void clear_all_solo_state (boost::shared_ptr<RouteList>);
-       void set_just_one_solo (boost::shared_ptr<Route>, bool, SessionEvent::RTeventCallback after = rt_cleanup);
-       void set_mute (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_listen (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_record_enabled (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_record_safe (boost::shared_ptr<RouteList>, bool yn, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_solo_isolated (boost::shared_ptr<RouteList>, bool, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
-       void set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, SessionEvent::RTeventCallback after = rt_cleanup, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
+
+       /* Control-based methods */
+
+       void set_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition);
+       void set_control (boost::shared_ptr<AutomationControl>, double val, PBD::Controllable::GroupControlDisposition);
+
        void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others = false);
 
        PBD::Signal1<void,bool> SoloActive;
@@ -1936,16 +1933,18 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
                return ev;
        }
 
-       void rt_set_solo (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_implicit_solo (boost::shared_ptr<RouteList>, int delta, bool up_or_downstream, PBD::Controllable::GroupControlDisposition);
+       /* specialized version realtime "apply to set of controls" operations */
+       SessionEvent* get_rt_event (boost::shared_ptr<ControlList> cl, double arg, PBD::Controllable::GroupControlDisposition group_override) {
+               SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+               ev->rt_slot = boost::bind (&Session::rt_set_controls, this, cl, arg, group_override);
+               ev->rt_return = Session::rt_cleanup;
+               ev->event_loop = PBD::EventLoop::get_event_loop_for_thread ();
+
+               return ev;
+       }
+
+       void rt_set_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition group_override);
        void rt_clear_all_solo_state (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_just_one_solo (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition  /* ignored*/ );
-       void rt_set_mute (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_listen (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_solo_isolated (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_record_enabled (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_record_safe (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
-       void rt_set_monitoring (boost::shared_ptr<RouteList>, MonitorChoice, PBD::Controllable::GroupControlDisposition group_override);
 
        /** temporary list of Diskstreams used only during load of 2.X sessions */
        std::list<boost::shared_ptr<Diskstream> > _diskstreams_2X;
index cca7f1274e5c189cc4f4e4aecf865a14a0b0a95b..8bb160b90e2abde07b308d7f9334028790043557 100644 (file)
@@ -84,26 +84,28 @@ public:
        union {
                void*        ptr;
                bool         yes_or_no;
-               framepos_t  target2_frame;
+               framepos_t   target2_frame;
                Slave*       slave;
                Route*       route;
        };
 
        union {
                bool second_yes_or_no;
+               double control_value;
        };
 
        union {
                bool third_yes_or_no;
        };
 
-       /* 4 members to handle a multi-group event handled in RT context */
+       /* 5 members to handle a multi-group event handled in RT context */
 
        typedef boost::function<void (SessionEvent*)> RTeventCallback;
 
-       boost::shared_ptr<RouteList> routes;    /* apply to */
-       boost::function<void (void)> rt_slot;   /* what to call in RT context */
-       RTeventCallback              rt_return; /* called after rt_slot, with this event as an argument */
+       boost::shared_ptr<ControlList> controls; /* apply to */
+       boost::shared_ptr<RouteList> routes;     /* apply to */
+       boost::function<void (void)> rt_slot;    /* what to call in RT context */
+       RTeventCallback              rt_return;  /* called after rt_slot, with this event as an argument */
        PBD::EventLoop*              event_loop;
 
        std::list<AudioRange> audio_range;
index e97fe79103614a4641de921925c3daa3b135ae63..f68cb07b91d967a40636b024221c328d8ea1e2e3 100644 (file)
 #include <boost/utility.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include "ardour/gain_control.h"
 #include "ardour/session_object.h"
 
 namespace ARDOUR {
 
 class AutomationControl;
+class GainControl;
 class PeakMeter;
+class SoloControl;
+class MuteControl;
+class PhaseControl;
+class SoloIsolateControl;
+class SoloSafeControl;
+class MonitorControl;
 
 /* This is a virtual base class for any object that needs to be potentially
  * represented by a control-centric user interface using the general model of a
@@ -58,12 +64,13 @@ class Stripable : public SessionObject {
 
        virtual boost::shared_ptr<GainControl> gain_control() const = 0;
 
-       virtual boost::shared_ptr<AutomationControl> solo_control() const = 0;
-       virtual boost::shared_ptr<AutomationControl> mute_control() const = 0;
-       virtual boost::shared_ptr<AutomationControl> phase_control() const = 0;
-       virtual boost::shared_ptr<AutomationControl> trim_control() const = 0;
+       virtual boost::shared_ptr<SoloControl> solo_control() const = 0;
+       virtual boost::shared_ptr<MuteControl> mute_control() const = 0;
 
-       virtual boost::shared_ptr<AutomationControl> monitoring_control() const = 0;
+       virtual boost::shared_ptr<PhaseControl> phase_control() const = 0;
+       virtual boost::shared_ptr<GainControl> trim_control() const = 0;
+
+       virtual boost::shared_ptr<MonitorControl> monitoring_control() const = 0;
        virtual boost::shared_ptr<AutomationControl> recenable_control() const { return boost::shared_ptr<AutomationControl>(); }
 
        /* "well-known" controls for panning. Any or all of these may return
@@ -131,6 +138,9 @@ class Stripable : public SessionObject {
          * the route.
          */
        virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const = 0;
+
+       virtual bool muted_by_others_soloing () const = 0;
+       virtual bool muted_by_others () const = 0;
 };
 
 
index b378021bcefe57ca56d6246c43d626882b169a75..bb955265c806c68fedd3ca2cf537c5ccf6bb7393 100644 (file)
@@ -22,6 +22,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include "ardour/interthread_info.h"
+#include "ardour/recordable.h"
 #include "ardour/route.h"
 #include "ardour/public_diskstream.h"
 
@@ -34,13 +35,14 @@ class Source;
 class Region;
 class Diskstream;
 class IO;
+class MonitorControl;
 
 /** A track is an route (bus) with a recordable diskstream and
  * related objects relevant to tracking, playback and editing.
  *
  * Specifically a track has regions and playlist objects.
  */
-class LIBARDOUR_API Track : public Route, public PublicDiskstream
+class LIBARDOUR_API Track : public Route, public Recordable, public PublicDiskstream
 {
   public:
        Track (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
@@ -56,23 +58,9 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
        virtual bool can_use_mode (TrackMode /*m*/, bool& /*bounce_required*/) { return false; }
        PBD::Signal0<void> TrackModeChanged;
 
-       class LIBARDOUR_API MonitoringControllable : public RouteAutomationControl {
-       public:
-               MonitoringControllable (std::string name, boost::shared_ptr<Track>);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               /* currently no automation, so no need for set_value_unchecked() */
-               double get_value () const;
-       private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-       };
-
-       void set_monitoring (MonitorChoice, PBD::Controllable::GroupControlDisposition group_override);
-       MonitorChoice monitoring_choice() const { return _monitoring; }
-        MonitorState monitoring_state () const;
-       PBD::Signal0<void> MonitoringChanged;
-
-       boost::shared_ptr<AutomationControl> monitoring_control() const { return _monitoring_control; }
+       boost::shared_ptr<MonitorControl> monitoring_control() const { return _monitoring_control; }
 
+       MonitorState monitoring_state () const;
        MeterState metering_state () const;
 
        virtual int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
@@ -142,13 +130,12 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
        virtual int set_state (const XMLNode&, int version);
        static void zero_diskstream_id_in_xml (XMLNode&);
 
-       boost::shared_ptr<AutomationControl> rec_enable_control() { return _rec_enable_control; }
+       boost::shared_ptr<AutomationControl> rec_enable_control() const { return _record_enable_control; }
+       boost::shared_ptr<AutomationControl> rec_safe_control() const { return _record_safe_control; }
 
-       bool record_enabled() const;
-       bool record_safe () const;
-       void set_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
-       void set_record_safe (bool yn, PBD::Controllable::GroupControlDisposition);
-       void prep_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
+       int prep_record_enabled (bool);
+       bool can_be_record_enabled ();
+       bool can_be_record_safe ();
 
        bool using_diskstream_id (PBD::ID) const;
 
@@ -204,8 +191,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
        PBD::Signal0<void> FreezeChange;
        /* Emitted when our diskstream is set to use a different playlist */
        PBD::Signal0<void> PlaylistChanged;
-       PBD::Signal0<void> RecordEnableChanged;
-       PBD::Signal0<void> RecordSafeChanged;
        PBD::Signal0<void> SpeedChanged;
        PBD::Signal0<void> AlignmentStyleChanged;
 
@@ -216,8 +201,7 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
        MeterPoint    _saved_meter_point;
        TrackMode     _mode;
        bool          _needs_butler;
-       MonitorChoice _monitoring;
-       boost::shared_ptr<MonitoringControllable> _monitoring_control;
+       boost::shared_ptr<MonitorControl> _monitoring_control;
 
        //private: (FIXME)
        struct FreezeRecordProcessorInfo {
@@ -242,20 +226,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
                FreezeState                        state;
        };
 
-       class RecEnableControl : public AutomationControl {
-       public:
-               RecEnableControl (boost::shared_ptr<Track> t);
-
-               void set_value (double, PBD::Controllable::GroupControlDisposition);
-               void set_value_unchecked (double);
-               double get_value (void) const;
-
-               boost::weak_ptr<Track> track;
-
-       private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition);
-       };
-
        virtual void set_state_part_two () = 0;
 
        FreezeRecord          _freeze_record;
@@ -264,17 +234,20 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
 
        void maybe_declick (BufferSet&, framecnt_t, int);
 
-       boost::shared_ptr<RecEnableControl> _rec_enable_control;
+       boost::shared_ptr<AutomationControl> _record_enable_control;
+       boost::shared_ptr<AutomationControl> _record_safe_control;
+
+       virtual void record_enable_changed (bool, PBD::Controllable::GroupControlDisposition);
+       virtual void record_safe_changed (bool, PBD::Controllable::GroupControlDisposition);
 
        framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&);
+       virtual void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
 
 private:
 
        virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &) = 0;
 
        void diskstream_playlist_changed ();
-       void diskstream_record_enable_changed ();
-       void diskstream_record_safe_changed ();
        void diskstream_speed_changed ();
        void diskstream_alignment_style_changed ();
        void parameter_changed (std::string const & p);
index 626109557f59051b266d4893a61da878af841111..bd866141d526be53f72bfaaa7612b3eaaf331132 100644 (file)
@@ -53,6 +53,7 @@ namespace ARDOUR {
        class Route;
        class Region;
        class VCA;
+       class AutomationControl;
 
        typedef float    Sample;
        typedef float    pan_t;
@@ -149,6 +150,7 @@ namespace ARDOUR {
                FadeOutAutomation,
                EnvelopeAutomation,
                RecEnableAutomation,
+               RecSafeAutomation,
                TrimAutomation,
                PhaseAutomation,
                MonitoringAutomation,
@@ -565,6 +567,7 @@ namespace ARDOUR {
 
        typedef std::list<boost::shared_ptr<Route> > RouteList;
        typedef std::list<boost::weak_ptr  <Route> > WeakRouteList;
+       typedef std::list<boost::shared_ptr<AutomationControl> > ControlList;
 
        typedef std::list<boost::shared_ptr<VCA> > VCAList;
 
index f3767d471a3c4a03a4ce90a7ef01fde5fd7b817f..1dc7c2baf4ac591af5914a99bda717a9d057a7d6 100644 (file)
 #include <string>
 #include <cmath>
 
+#include "boost/shared_ptr.hpp"
+
 #if __APPLE__
 #include <CoreFoundation/CoreFoundation.h>
 #endif /* __APPLE__ */
 
-#include "ardour/libardour_visibility.h"
 #include "ardour/ardour.h"
 #include "ardour/data_type.h"
 #include "ardour/dB.h"
+#include "ardour/types.h"
+
+#include "ardour/libardour_visibility.h"
 
 class XMLNode;
 
 namespace ARDOUR {
 
+class Route;
+class Track;
+
 LIBARDOUR_API std::string legalize_for_path (const std::string& str);
 LIBARDOUR_API std::string legalize_for_universal_path (const std::string& str);
 LIBARDOUR_API std::string legalize_for_uri (const std::string& str);
@@ -169,6 +176,29 @@ LIBARDOUR_API bool matching_unsuffixed_filename_exists_in (const std::string& di
 
 LIBARDOUR_API uint32_t how_many_dsp_threads ();
 
+template<typename T> boost::shared_ptr<ControlList> route_list_to_control_list (boost::shared_ptr<RouteList> rl, boost::shared_ptr<T> (Route::*get_control)() const) {
+       boost::shared_ptr<ControlList> cl (new ControlList);
+       for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
+               boost::shared_ptr<AutomationControl> ac = ((*r).get()->*get_control)();
+               if (ac) {
+                       cl->push_back (ac);
+               }
+       }
+       return cl;
+}
+
+template<typename T> boost::shared_ptr<ControlList> route_list_to_control_list (boost::shared_ptr<RouteList> rl, boost::shared_ptr<T> (Track::*get_control)() const) {
+       boost::shared_ptr<ControlList> cl (new ControlList);
+       for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
+               boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
+               boost::shared_ptr<AutomationControl> ac = (t.get()->*get_control)();
+               if (ac) {
+                       cl->push_back (ac);
+               }
+       }
+       return cl;
+}
+
 #if __APPLE__
 LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
 #endif // __APPLE__
@@ -176,4 +206,3 @@ LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
 } //namespave
 
 #endif /* __ardour_utils_h__ */
-
index dc48ffa4809bb48f733724e0a0caa999f55a7fc3..1c247c0e929c004316ebaa8fd9bc5566f1556499 100644 (file)
 #include "pbd/statefuldestructible.h"
 
 #include "ardour/automatable.h"
+#include "ardour/muteable.h"
+#include "ardour/soloable.h"
 #include "ardour/stripable.h"
 
 namespace ARDOUR {
 
-class GainControl;
 class Route;
+class GainControl;
+class SoloControl;
+class MuteControl;
+class MonitorControl;
 
-class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::enable_shared_from_this<VCA> {
+class LIBARDOUR_API VCA : public Stripable, public Soloable, public Muteable, public Automatable, public boost::enable_shared_from_this<VCA> {
   public:
        VCA (Session& session,  uint32_t num, const std::string& name);
        ~VCA();
@@ -47,7 +52,15 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
        int set_state (XMLNode const&, int version);
 
        bool soloed () const;
+       void push_solo_upstream (int32_t) {}
+       void push_solo_isolate_upstream (int32_t) {}
+       bool can_solo() const { return true; }
+       bool is_safe () const { return false; }
+
        bool muted () const;
+       bool can_be_muted_by_others () const { return true; }
+       bool muted_by_others_soloing() const { return false; }
+       bool muted_by_others() const { return false; }
 
        static std::string default_name_template ();
        static int next_vca_number ();
@@ -58,16 +71,16 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
        static void set_next_vca_number (uint32_t);
 
        virtual boost::shared_ptr<GainControl> gain_control() const { return _gain_control; }
-       virtual boost::shared_ptr<AutomationControl> solo_control() const { return _solo_control; }
-       virtual boost::shared_ptr<AutomationControl> mute_control() const { return _mute_control; }
+       virtual boost::shared_ptr<SoloControl> solo_control() const { return _solo_control; }
+       virtual boost::shared_ptr<MuteControl> mute_control() const { return _mute_control; }
 
        /* null Stripable API, because VCAs don't have any of this */
 
-       virtual boost::shared_ptr<PeakMeter>       peak_meter() { return boost::shared_ptr<PeakMeter>(); }
-       virtual boost::shared_ptr<const PeakMeter> peak_meter() const { return boost::shared_ptr<PeakMeter>(); }
-       virtual boost::shared_ptr<AutomationControl> phase_control() const { return boost::shared_ptr<AutomationControl>(); }
-       virtual boost::shared_ptr<AutomationControl> trim_control() const { return boost::shared_ptr<AutomationControl>(); }
-       virtual boost::shared_ptr<AutomationControl> monitoring_control() const { return boost::shared_ptr<AutomationControl>(); }
+       virtual boost::shared_ptr<PeakMeter>         peak_meter() { return boost::shared_ptr<PeakMeter>(); }
+       virtual boost::shared_ptr<const PeakMeter>   peak_meter() const { return boost::shared_ptr<PeakMeter>(); }
+       virtual boost::shared_ptr<PhaseControl>      phase_control() const { return boost::shared_ptr<PhaseControl>(); }
+       virtual boost::shared_ptr<GainControl>       trim_control() const { return boost::shared_ptr<GainControl>(); }
+       virtual boost::shared_ptr<MonitorControl>    monitoring_control() const { return boost::shared_ptr<MonitorControl>(); }
        virtual boost::shared_ptr<AutomationControl> recenable_control() const { return boost::shared_ptr<AutomationControl>(); }
        virtual boost::shared_ptr<AutomationControl> pan_azimuth_control() const { return boost::shared_ptr<AutomationControl>(); }
        virtual boost::shared_ptr<AutomationControl> pan_elevation_control() const { return boost::shared_ptr<AutomationControl>(); }
@@ -96,36 +109,12 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
        virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const { return boost::shared_ptr<AutomationControl>(); }
 
   private:
-       class VCASoloControllable : public AutomationControl {
-          public:
-               VCASoloControllable (std::string const & name, boost::shared_ptr<VCA> vca);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
-               double get_value () const;
-         private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               boost::weak_ptr<VCA> _vca;
-       };
-
-       class VCAMuteControllable : public AutomationControl {
-          public:
-               VCAMuteControllable (std::string const & name, boost::shared_ptr<VCA> vca);
-               void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               void set_value_unchecked (double);
-               double get_value () const;
-         private:
-               void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
-               boost::weak_ptr<VCA> _vca;
-       };
-
-       friend class VCASoloControllable;
-       friend class VCAMuteControllable;
-
        uint32_t    _number;
 
        boost::shared_ptr<GainControl> _gain_control;
-       boost::shared_ptr<VCASoloControllable> _solo_control;
-       boost::shared_ptr<VCAMuteControllable> _mute_control;
+       boost::shared_ptr<SoloControl> _solo_control;
+       boost::shared_ptr<MuteControl> _mute_control;
+
        bool _solo_requested;
        bool _mute_requested;
 
index 579b0064bc2b09d18485ee6dabe138d634566e22..2ed200d6f6c6fdaa71cbe5c909e54f762de94f2d 100644 (file)
@@ -33,6 +33,7 @@
 #include "ardour/buffer_set.h"
 #include "ardour/delivery.h"
 #include "ardour/meter.h"
+#include "ardour/monitor_control.h"
 #include "ardour/playlist_factory.h"
 #include "ardour/processor.h"
 #include "ardour/profile.h"
@@ -349,7 +350,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
 
        if (!_active) {
                silence (nframes);
-               if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+               if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
                        _meter->reset();
                }
                return 0;
@@ -391,7 +392,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
 
        fill_buffers_with_input (bufs, _input, nframes);
 
-       if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+       if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
                _meter->run (bufs, start_frame, end_frame, nframes, true);
        }
 
@@ -629,8 +630,9 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
 
        /* reset stuff that has already been accounted for in the freeze process */
 
-       set_gain (GAIN_COEFF_UNITY, Controllable::NoGroup);
-       _amp->gain_control()->set_automation_state (Off);
+       gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
+       gain_control()->set_automation_state (Off);
+
        /* XXX need to use _main_outs _panner->set_automation_state (Off); */
 
        _freeze_record.state = Frozen;
index b00c615625982e0c5fc7a80a670a4fed5d9f6862..7efaa07f233158c345af4bdd718abb9dd86315a8 100644 (file)
 
 #include <math.h>
 #include <iostream>
+
+#include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
+
+#include "ardour/audioengine.h"
 #include "ardour/automation_control.h"
 #include "ardour/automation_watch.h"
+#include "ardour/control_group.h"
 #include "ardour/event_type_map.h"
 #include "ardour/session.h"
 
-#include "pbd/memento_command.h"
-#include "pbd/stacktrace.h"
-
 #include "i18n.h"
 
 #ifdef COMPILER_MSVC
@@ -69,42 +72,38 @@ AutomationControl::writable() const
        return true;
 }
 
+/** Get the current effective `user' value based on automation state */
 double
-AutomationControl::get_masters_value_locked () const
+AutomationControl::get_value() const
 {
-       gain_t v = 1.0;
-
-       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
-               /* get current master value, scale by our current ratio with that master */
-               v *= mr->second.master()->get_value () * mr->second.ratio();
-       }
-
-       return min (_desc.upper, v);
+       bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
+       return Control::get_double (from_list, _session.transport_frame());
 }
 
-double
-AutomationControl::get_value_locked() const
+void
+AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
 {
-       /* read or write masters lock must be held */
-
-       if (_masters.empty()) {
-               return Control::get_double (false, _session.transport_frame());
+       if (!writable()) {
+               return;
        }
 
-       return get_masters_value_locked ();
-}
+       /* enforce strict double/boolean value mapping */
 
-/** Get the current effective `user' value based on automation state */
-double
-AutomationControl::get_value() const
-{
-       bool from_list = _list && ((AutomationList*)_list.get())->automation_playback();
+       if (_desc.toggled) {
+               if (val != 0.0) {
+                       val = 1.0;
+               }
+       }
+
+       if (check_rt (val, gcd)) {
+               /* change has been queued to take place in an RT context */
+               return;
+       }
 
-       if (!from_list) {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               return get_value_locked ();
+       if (_group && _group->use_me (gcd)) {
+               _group->set_group_value (shared_from_this(), val);
        } else {
-               return Control::get_double (from_list, _session.transport_frame());
+               actually_set_value (val, gcd);
        }
 }
 
@@ -113,12 +112,15 @@ AutomationControl::get_value() const
  *  @param value `user' value
  */
 void
-AutomationControl::set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
+AutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
 {
-       bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
+       bool to_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_write();
 
        Control::set_double (value, _session.transport_frame(), to_list);
 
+       AutomationType at = (AutomationType) _parameter.type();
+
+       std::cerr << "++++ Changed (" << enum_2_string (at) << ", " << enum_2_string (gcd) << ") = " << value << " @ " << this << std::endl;
        Changed (true, gcd);
 }
 
@@ -263,147 +265,25 @@ AutomationControl::interface_to_internal (double val) const
        return val;
 }
 
-
-void
-AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
-{
-       double current_value;
-       double new_value;
-       std::pair<Masters::iterator,bool> res;
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
-               current_value = get_value_locked ();
-
-               /* ratio will be recomputed below */
-
-               res = _masters.insert (make_pair<PBD::ID,MasterRecord> (m->id(), MasterRecord (m, 1.0)));
-
-               if (res.second) {
-
-                       recompute_masters_ratios (current_value);
-
-                       /* note that we bind @param m as a weak_ptr<AutomationControl>, thus
-                          avoiding holding a reference to the control in the binding
-                          itself.
-                       */
-
-                       m->DropReferences.connect_same_thread (masters_connections, boost::bind (&AutomationControl::master_going_away, this, m));
-
-                       /* Store the connection inside the MasterRecord, so that when we destroy it, the connection is destroyed
-                          and we no longer hear about changes to the AutomationControl.
-
-                          Note that we fix the "from_self" argument that will
-                          be given to our own Changed signal to "false",
-                          because the change came from the master.
-                       */
-
-
-                       m->Changed.connect_same_thread (res.first->second.connection, boost::bind (&AutomationControl::master_changed, this, _1, _2));
-               }
-
-               new_value = get_value_locked ();
-       }
-
-       if (res.second) {
-               /* this will notify everyone that we're now slaved to the master */
-               MasterStatusChange (); /* EMIT SIGNAL */
-       }
-
-       if (new_value != current_value) {
-               /* force a call to to ::master_changed() to carry the
-                * consequences that would occur if the master assumed
-                * its current value WHILE we were slaved.
-                */
-               master_changed (false, Controllable::NoGroup);
-               /* effective value changed by master */
-               Changed (false, Controllable::NoGroup);
-       }
-
-}
-
-void
-AutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd)
-{
-       /* our value has (likely) changed, but not because we were
-        * modified. Just the master.
-        */
-
-       Changed (false, gcd); /* EMIT SIGNAL */
-}
-
-void
-AutomationControl::master_going_away (boost::weak_ptr<AutomationControl> wm)
-{
-       boost::shared_ptr<AutomationControl> m = wm.lock();
-       if (m) {
-               remove_master (m);
-       }
-}
-
-void
-AutomationControl::remove_master (boost::shared_ptr<AutomationControl> m)
-{
-       double current_value;
-       double new_value;
-       Masters::size_type erased = 0;
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
-               current_value = get_value_locked ();
-               erased = _masters.erase (m->id());
-               if (erased) {
-                       recompute_masters_ratios (current_value);
-               }
-               new_value = get_value_locked ();
-       }
-
-       if (erased) {
-               MasterStatusChange (); /* EMIT SIGNAL */
-       }
-
-       if (new_value != current_value) {
-               Changed (false, Controllable::NoGroup);
-       }
-}
-
 void
-AutomationControl::clear_masters ()
+AutomationControl::set_group (boost::shared_ptr<ControlGroup> cg)
 {
-       double current_value;
-       double new_value;
-       bool had_masters = false;
-
-       {
-               Glib::Threads::RWLock::WriterLock lm (master_lock);
-               current_value = get_value_locked ();
-               if (!_masters.empty()) {
-                       had_masters = true;
-               }
-               _masters.clear ();
-               new_value = get_value_locked ();
-       }
-
-       if (had_masters) {
-               MasterStatusChange (); /* EMIT SIGNAL */
-       }
-
-       if (new_value != current_value) {
-               Changed (false, Controllable::NoGroup);
+       if (_group) {
+               _group->remove_control (shared_from_this());
        }
 
+       _group = cg;
 }
 
 bool
-AutomationControl::slaved_to (boost::shared_ptr<AutomationControl> m) const
+AutomationControl::check_rt (double val, Controllable::GroupControlDisposition gcd)
 {
-       Glib::Threads::RWLock::ReaderLock lm (master_lock);
-       return _masters.find (m->id()) != _masters.end();
-}
+       if ((flags() & Controllable::RealTime) && !AudioEngine::instance()->in_process_thread()) {
+               /* queue change in RT context */
+               std::cerr << "::set_value (" << val << ", " << enum_2_string (gcd) << ") called for " << enum_2_string ((AutomationType) _parameter.type()) << ", queueing in RT context\n";
+               _session.set_control (shared_from_this(), val, gcd);
+               return true;
+       }
 
-bool
-AutomationControl::slaved () const
-{
-       Glib::Threads::RWLock::ReaderLock lm (master_lock);
-       return !_masters.empty();
+       return false;
 }
index b7e77952cb2926e46db3fc4338214856f2362bd3..85634640b95ddb7a0311557a021747dd35638328 100644 (file)
@@ -140,21 +140,30 @@ setup_enum_writer ()
 #define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
 #define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
 
+       REGISTER_ENUM (NullAutomation);
        REGISTER_ENUM (GainAutomation);
-       REGISTER_ENUM (TrimAutomation);
        REGISTER_ENUM (PanAzimuthAutomation);
        REGISTER_ENUM (PanElevationAutomation);
        REGISTER_ENUM (PanWidthAutomation);
+       REGISTER_ENUM (PanFrontBackAutomation);
+       REGISTER_ENUM (PanLFEAutomation);
        REGISTER_ENUM (PluginAutomation);
        REGISTER_ENUM (PluginPropertyAutomation);
        REGISTER_ENUM (SoloAutomation);
+       REGISTER_ENUM (SoloIsolateAutomation);
+       REGISTER_ENUM (SoloSafeAutomation);
        REGISTER_ENUM (MuteAutomation);
        REGISTER_ENUM (MidiCCAutomation);
+       REGISTER_ENUM (MidiPgmChangeAutomation);
+       REGISTER_ENUM (MidiPitchBenderAutomation);
+       REGISTER_ENUM (MidiChannelPressureAutomation);
+       REGISTER_ENUM (MidiSystemExclusiveAutomation);
        REGISTER_ENUM (FadeInAutomation);
        REGISTER_ENUM (FadeOutAutomation);
        REGISTER_ENUM (EnvelopeAutomation);
-       REGISTER_ENUM (SoloIsolateAutomation);
-       REGISTER_ENUM (SoloSafeAutomation);
+       REGISTER_ENUM (RecEnableAutomation);
+       REGISTER_ENUM (RecSafeAutomation);
+       REGISTER_ENUM (TrimAutomation);
        REGISTER_ENUM (PhaseAutomation);
        REGISTER_ENUM (MonitoringAutomation);
        REGISTER_ENUM (EQGain);
index 456fd9b248d4e0bbea8553d7e3a5a357871e63df..3cb82301985f01f9747af96f91e93f18a02bf230 100644 (file)
@@ -33,9 +33,9 @@ using namespace ARDOUR;
 using namespace std;
 
 GainControl::GainControl (Session& session, const Evoral::Parameter &param, boost::shared_ptr<AutomationList> al)
-       : AutomationControl (session, param, ParameterDescriptor(param),
-                            al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
-                            param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
+       : SlavableAutomationControl (session, param, ParameterDescriptor(param),
+                                    al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
+                                    param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
 
        alist()->reset_default (1.0);
 
@@ -44,22 +44,7 @@ GainControl::GainControl (Session& session, const Evoral::Parameter &param, boos
 }
 
 void
-GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (val, group_override);
-       }
-}
-
-void
-GainControl::set_value_unchecked (double val)
-{
-       /* used only automation playback */
-       _set_value (val, Controllable::NoGroup);
-}
-
-void
-GainControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
+GainControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
 {
        val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
 
@@ -75,7 +60,7 @@ GainControl::_set_value (double val, Controllable::GroupControlDisposition group
           be retrieved by AutomationControl::get_value ()
        */
 
-       AutomationControl::set_value (val, group_override);
+       AutomationControl::actually_set_value (val, group_override);
 
        _session.set_dirty ();
 }
@@ -119,6 +104,23 @@ GainControl::get_user_string () const
        return std::string(theBuf);
 }
 
+void
+GainControl::inc_gain (gain_t factor)
+{
+       /* To be used ONLY when doing group-relative gain adjustment, from
+        * ControlGroup::set_group_values().
+        */
+
+       const float desired_gain = user_double();
+
+       if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
+               // really?! what's the idea here?
+               actually_set_value (0.000001f + (0.000001f * factor), Controllable::ForGroup);
+       } else {
+               actually_set_value (desired_gain + (desired_gain * factor), Controllable::ForGroup);
+       }
+}
+
 void
 GainControl::recompute_masters_ratios (double val)
 {
index 23dc0d26f06ea0962ff94282f363a111760e0666..28214b7e62dcf89e052807a1b7b66a33bb5fb9e5 100644 (file)
@@ -583,10 +583,10 @@ LuaBindings::common (lua_State* L)
                .addCast<MidiTrack> ("to_midi_track")
                .addFunction ("set_name", &Track::set_name)
                .addFunction ("can_record", &Track::can_record)
-               .addFunction ("record_enabled", &Track::record_enabled)
-               .addFunction ("record_safe", &Track::record_safe)
-               .addFunction ("set_record_enabled", &Track::set_record_enabled)
-               .addFunction ("set_record_safe", &Track::set_record_safe)
+               //.addFunction ("record_enabled", &Track::record_enabled)
+               //.addFunction ("record_safe", &Track::record_safe)
+               //.addFunction ("set_record_enabled", &Track::set_record_enabled)
+               //.addFunction ("set_record_safe", &Track::set_record_safe)
                .addFunction ("bounceable", &Track::bounceable)
                .addFunction ("bounce", &Track::bounce)
                .addFunction ("bounce_range", &Track::bounce_range)
index 9a38f9f05a9c30ead8d94fd5019e3076b04fe9c4..7c1b3a9399cc99a0b0be44a54b20a3ddafef7a79 100644 (file)
@@ -44,6 +44,7 @@
 #include "ardour/midi_port.h"
 #include "ardour/midi_region.h"
 #include "ardour/midi_track.h"
+#include "ardour/monitor_control.h"
 #include "ardour/parameter_types.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
@@ -103,24 +104,24 @@ MidiTrack::create_diskstream ()
 }
 
 
-void
-MidiTrack::set_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
+bool
+MidiTrack::can_be_record_safe ()
 {
        if (_step_editing) {
-               return;
+               return false;
        }
 
-       Track::set_record_enabled (yn, group_override);
+       return Track::can_be_record_safe ();
 }
 
-void
-MidiTrack::set_record_safe (bool yn, Controllable::GroupControlDisposition group_override)
+bool
+MidiTrack::can_be_record_enabled ()
 {
-       if (_step_editing) { /* REQUIRES REVIEW */
-               return;
+       if (_step_editing) {
+               return false;
        }
 
-       Track::set_record_safe (yn, group_override);
+       return Track::can_be_record_enabled ();
 }
 
 void
@@ -372,7 +373,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
 
        if (!_active) {
                silence (nframes);
-               if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+               if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
                        _meter->reset();
                }
                return 0;
@@ -412,7 +413,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
        /* filter captured data before meter sees it */
        _capture_filter.filter (bufs);
 
-       if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+       if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
                _meter->run (bufs, start_frame, end_frame, nframes, true);
        }
 
@@ -726,22 +727,7 @@ MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState st
 }
 
 void
-MidiTrack::MidiControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (val, group_override);
-       }
-}
-
-void
-MidiTrack::MidiControl::set_value_unchecked (double val)
-{
-       /* used only by automation playback */
-       _set_value (val, Controllable::NoGroup);
-}
-
-void
-MidiTrack::MidiControl::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
+MidiTrack::MidiControl::actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
 {
        const Evoral::Parameter &parameter = _list ? _list->parameter() : Control::parameter();
        const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(parameter);
@@ -798,7 +784,7 @@ MidiTrack::MidiControl::_set_value (double val, PBD::Controllable::GroupControlD
                _route->write_immediate_event(size,  ev);
        }
 
-       AutomationControl::set_value(val, group_override);
+       AutomationControl::actually_set_value(val, group_override);
 }
 
 void
@@ -958,35 +944,27 @@ MidiTrack::act_on_mute ()
 }
 
 void
-MidiTrack::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
+MidiTrack::monitoring_changed (bool self, Controllable::GroupControlDisposition gcd)
 {
-       if (use_group (gcd, &RouteGroup::is_monitoring)) {
-               _route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
-               return;
-       }
-
-       if (mc != _monitoring) {
+       Track::monitoring_changed (self, gcd);
+       
+       /* monitoring state changed, so flush out any on notes at the
+        * port level.
+        */
 
-               Track::set_monitoring (mc, gcd);
+       PortSet& ports (_output->ports());
 
-               /* monitoring state changed, so flush out any on notes at the
-                * port level.
-                */
-
-               PortSet& ports (_output->ports());
-
-               for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
-                       boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
-                       if (mp) {
-                               mp->require_resolve ();
-                       }
+       for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) {
+               boost::shared_ptr<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
+               if (mp) {
+                       mp->require_resolve ();
                }
+       }
 
-               boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
+       boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
 
-               if (md) {
-                       md->reset_tracker ();
-               }
+       if (md) {
+               md->reset_tracker ();
        }
 }
 
index dc40d1fd6b596b1dd3e3d9d371dec4196d5207d0..6817374dc7ad18c0b76ac604e2771110b1e0241e 100644 (file)
@@ -31,6 +31,8 @@
 using namespace ARDOUR;
 using namespace std;
 
+const string MuteMaster::xml_node_name (X_("MuteMaster"));
+
 const MuteMaster::MutePoint MuteMaster::AllPoints = MuteMaster::MutePoint(
        PreFader|PostFader|Listen|Main);
 
@@ -155,7 +157,7 @@ MuteMaster::set_state (const XMLNode& node, int /*version*/)
 XMLNode&
 MuteMaster::get_state()
 {
-       XMLNode* node = new XMLNode (X_("MuteMaster"));
+       XMLNode* node = new XMLNode (xml_node_name);
        node->add_property ("mute-point", enum_2_string (_mute_point));
        node->add_property ("muted", (_muted_by_self ? X_("yes") : X_("no")));
        return *node;
index a6a96787a28e4bf3904b1e8c503f18acc668fd83..624f397b7762771c09cabeeb39dbe74ad33aad1d 100644 (file)
@@ -35,27 +35,13 @@ PanControllable::lower () const
 }
 
 void
-PanControllable::set_value (double v, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (v, group_override);
-       }
-}
-void
-PanControllable::set_value_unchecked (double v)
-{
-       /* used only automation playback */
-       _set_value (v, Controllable::NoGroup);
-}
-
-void
-PanControllable::_set_value (double v, Controllable::GroupControlDisposition group_override)
+PanControllable::actually_set_value (double v, Controllable::GroupControlDisposition group_override)
 {
        boost::shared_ptr<Panner> p = owner->panner();
 
         if (!p) {
                 /* no panner: just do it */
-               AutomationControl::set_value (v, group_override);
+               AutomationControl::actually_set_value (v, group_override);
                 return;
         }
 
@@ -76,7 +62,7 @@ PanControllable::_set_value (double v, Controllable::GroupControlDisposition gro
         }
 
         if (can_set) {
-               AutomationControl::set_value (v, group_override);
+               AutomationControl::actually_set_value (v, group_override);
         }
 }
 
index 9fb6b89a0c5548c0ae7aca654d7aab3c7db14a71..e28dbecd3586afec3875d71c4da92db4e29ee176 100644 (file)
@@ -75,6 +75,7 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
                normal = 0.0f;
                break;
        case RecEnableAutomation:
+       case RecSafeAutomation:
                lower  = 0.0;
                upper  = 1.0;
                toggled = true;
index 451f801f1d77e1d879e86336d42c8e18eb400966..b0d4d2f9ac7ba3c49279afbe3bb17c10e411f221 100644 (file)
@@ -2614,22 +2614,9 @@ PluginInsert::PluginControl::PluginControl (PluginInsert*                     p,
 }
 
 /** @param val `user' value */
-void
-PluginInsert::PluginControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (user_val, group_override);
-       }
-}
-void
-PluginInsert::PluginControl::set_value_unchecked (double user_val)
-{
-       /* used only by automation playback */
-       _set_value (user_val, Controllable::NoGroup);
-}
 
 void
-PluginInsert::PluginControl::_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
+PluginInsert::PluginControl::actually_set_value (double user_val, PBD::Controllable::GroupControlDisposition group_override)
 {
        /* FIXME: probably should be taking out some lock here.. */
 
@@ -2642,13 +2629,13 @@ PluginInsert::PluginControl::_set_value (double user_val, PBD::Controllable::Gro
                iasp->set_parameter (_list->parameter().id(), user_val);
        }
 
-       AutomationControl::set_value (user_val, group_override);
+       AutomationControl::actually_set_value (user_val, group_override);
 }
 
 void
 PluginInsert::PluginControl::catch_up_with_external_value (double user_val)
 {
-       AutomationControl::set_value (user_val, Controllable::NoGroup);
+       AutomationControl::actually_set_value (user_val, Controllable::NoGroup);
 }
 
 XMLNode&
@@ -2700,15 +2687,7 @@ PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert*
 }
 
 void
-PluginInsert::PluginPropertyControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition /* group_override*/)
-{
-       if (writable()) {
-               set_value_unchecked (user_val);
-       }
-}
-
-void
-PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
+PluginInsert::PluginPropertyControl::actually_set_value (double user_val, Controllable::GroupControlDisposition gcd)
 {
        /* Old numeric set_value(), coerce to appropriate datatype if possible.
           This is lossy, but better than nothing until Ardour's automation system
@@ -2724,7 +2703,8 @@ PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
        }
 
        _value = value;
-       AutomationControl::set_value (user_val, Controllable::NoGroup);
+
+       AutomationControl::actually_set_value (user_val, gcd);
 }
 
 XMLNode&
index 8207176729c43223043ec8e240a11e573022bda5..7a3d37d2a777772f66598b703c4503cbdbd3e841 100644 (file)
@@ -58,6 +58,7 @@
 #include "ardour/panner.h"
 #include "ardour/panner_shell.h"
 #include "ardour/parameter_descriptor.h"
+#include "ardour/phase_control.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/port.h"
 #include "ardour/port_insert.h"
@@ -67,6 +68,8 @@
 #include "ardour/route_group.h"
 #include "ardour/send.h"
 #include "ardour/session.h"
+#include "ardour/solo_control.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/unknown_processor.h"
 #include "ardour/utils.h"
 #include "ardour/vca.h"
@@ -84,6 +87,7 @@ PBD::Signal3<int,boost::shared_ptr<Route>, boost::shared_ptr<PluginInsert>, Rout
 /** Base class for all routable/mixable objects (tracks and busses) */
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        : Stripable (sess, name)
+       , Muteable (sess, name)
        , Automatable (sess)
        , GraphNode (sess._process_graph)
        , _active (true)
@@ -99,18 +103,11 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        , _meter_point (MeterPostFader)
        , _pending_meter_point (MeterPostFader)
        , _meter_type (MeterPeak)
-       , _self_solo (false)
-       , _soloed_by_others_upstream (0)
-       , _soloed_by_others_downstream (0)
-       , _solo_isolated (false)
-       , _solo_isolated_by_upstream (0)
        , _denormal_protection (false)
        , _recordable (true)
        , _silent (false)
        , _declickable (false)
-       , _mute_master (new MuteMaster (sess, name))
        , _have_internal_generator (false)
-       , _solo_safe (false)
        , _default_type (default_type)
        , _order_key (0)
        , _has_order_key (false)
@@ -141,21 +138,30 @@ Route::init ()
 
        /* add standard controls */
 
-       _solo_control.reset (new SoloControllable (X_("solo"), shared_from_this ()));
-       _mute_control.reset (new MuteControllable (X_("mute"), shared_from_this ()));
-       _phase_control.reset (new PhaseControllable (X_("phase"), shared_from_this ()));
+       _gain_control.reset (new GainControl (_session, GainAutomation));
+       add_control (_gain_control);
 
-       _solo_isolate_control.reset (new SoloIsolateControllable (X_("solo-iso"), shared_from_this ()));
-       _solo_safe_control.reset (new SoloSafeControllable (X_("solo-safe"), shared_from_this ()));
+       _trim_control.reset (new GainControl (_session, TrimAutomation));
+       add_control (_trim_control);
 
+       _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
        _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
-       _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
-       _phase_control->set_flags (Controllable::Flag (_phase_control->flags() | Controllable::Toggle));
-
        add_control (_solo_control);
+       _solo_control->Changed.connect_same_thread (*this, boost::bind (&Route::solo_control_changed, this, _1, _2));
+
+       _mute_control.reset (new MuteControl (_session, X_("mute"), *this));
+       _mute_control->set_flags (Controllable::Flag (_mute_control->flags() | Controllable::Toggle));
        add_control (_mute_control);
+
+       _phase_control.reset (new PhaseControl (_session, X_("phase")));
        add_control (_phase_control);
 
+       _solo_isolate_control.reset (new SoloIsolateControl (_session, X_("solo-iso"), *this, *this));
+       add_control (_solo_isolate_control);
+
+       _solo_safe_control.reset (new SoloSafeControl (_session, X_("solo-safe")));
+       add_control (_solo_safe_control);
+
        /* panning */
 
        if (!(_flags & Route::MonitorOut)) {
@@ -177,9 +183,6 @@ Route::init ()
         * it should be the first processor to be added on every route.
         */
 
-       _gain_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, GainAutomation, shared_from_this ()));
-       add_control (_gain_control);
-
        _amp.reset (new Amp (_session, X_("Fader"), _gain_control, true));
        add_processor (_amp, PostFader);
 
@@ -196,9 +199,6 @@ Route::init ()
 
        /* and input trim */
 
-       _trim_control = boost::shared_ptr<GainControllable> (new GainControllable (_session, TrimAutomation, shared_from_this ()));
-       add_control (_trim_control);
-
        _trim.reset (new Amp (_session, X_("Trim"), _trim_control, false));
        _trim->set_display_to_user (false);
 
@@ -398,83 +398,11 @@ Route::ensure_track_or_route_name(string name, Session &session)
        return newname;
 }
 
-void
-Route::inc_gain (gain_t factor)
-{
-       /* To be used ONLY when doing group-relative gain adjustment, from
-        * ::set_gain()
-        */
-
-       float desired_gain = _gain_control->user_double();
-
-       if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
-               // really?! what's the idea here?
-               _gain_control->route_set_value (0.000001f + (0.000001f * factor));
-       } else {
-               _gain_control->route_set_value (desired_gain + (desired_gain * factor));
-       }
-}
-
-void
-Route::set_gain (gain_t val, Controllable::GroupControlDisposition gcd)
-{
-       if (use_group (gcd, &RouteGroup::is_gain)) {
-
-               if (_route_group->is_relative()) {
-
-                       gain_t usable_gain = _gain_control->get_value();
-                       if (usable_gain < 0.000001f) {
-                               usable_gain = 0.000001f;
-                       }
-
-                       gain_t delta = val;
-                       if (delta < 0.000001f) {
-                               delta = 0.000001f;
-                       }
-
-                       delta -= usable_gain;
-
-                       if (delta == 0.0f)
-                               return;
-
-                       gain_t factor = delta / usable_gain;
-
-                       if (factor > 0.0f) {
-                               factor = _route_group->get_max_factor(factor);
-                               if (factor == 0.0f) {
-                                       _amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
-                                       return;
-                               }
-                       } else {
-                               factor = _route_group->get_min_factor(factor);
-                               if (factor == 0.0f) {
-                                       _amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
-                                       return;
-                               }
-                       }
-
-                       _route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor));
-
-               } else {
-
-                       _route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, Controllable::NoGroup));
-               }
-
-               return;
-       }
-
-       if (val == _gain_control->get_value()) {
-               return;
-       }
-
-       _gain_control->route_set_value (val);
-}
-
 void
 Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
 {
        // TODO route group, see set_gain()
-       _trim_control->route_set_value (val);
+       // _trim_control->route_set_value (val);
 }
 
 void
@@ -551,7 +479,7 @@ Route::process_output_buffers (BufferSet& bufs,
           DENORMAL CONTROL/PHASE INVERT
           ----------------------------------------------------------------------------------------- */
 
-       if (_phase_invert.any ()) {
+       if (!_phase_control->none()) {
 
                int chn = 0;
 
@@ -560,7 +488,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert[chn]) {
+                               if (_phase_control->inverted (chn)) {
                                        for (pframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx]  = -sp[nx];
                                                sp[nx] += 1.0e-27f;
@@ -577,7 +505,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
                                Sample* const sp = i->data();
 
-                               if (_phase_invert[chn]) {
+                               if (_phase_control->inverted (chn)) {
                                        for (pframes_t nx = 0; nx < nframes; ++nx) {
                                                sp[nx] = -sp[nx];
                                        }
@@ -808,283 +736,46 @@ Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t
 }
 
 void
-Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override)
-{
-       if (_solo_safe) {
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_listen, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       if (_monitor_send) {
-               if (yn != _monitor_send->active()) {
-                       if (yn) {
-                               _monitor_send->activate ();
-                               _mute_master->set_soloed_by_self (true);
-                       } else {
-                               _monitor_send->deactivate ();
-                               _mute_master->set_soloed_by_self (false);
-                       }
-                       _mute_master->set_soloed_by_others (false);
-
-                       /* first argument won't matter because solo <=> listen right now */
-                       _solo_control->Changed (false, group_override); /* EMIT SIGNAL */
-               }
-       }
-}
-
-bool
-Route::listening_via_monitor () const
+Route::set_listen (bool yn)
 {
-       if (_monitor_send) {
-               return _monitor_send->active ();
+       if (yn) {
+               _monitor_send->activate ();
        } else {
-               return false;
+               _monitor_send->deactivate ();
        }
 }
 
 void
-Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition gcd)
+Route::solo_control_changed (bool, Controllable::GroupControlDisposition)
 {
-       if (_solo_safe != yn) {
-               _solo_safe = yn;
-               _solo_safe_control->Changed (true, gcd); /* EMIT SIGNAL */
-       }
-}
-
-bool
-Route::solo_safe() const
-{
-       return _solo_safe;
-}
-
-void
-Route::clear_all_solo_state ()
-{
-       // ideally this function will never do anything, it only exists to forestall Murphy
-       bool emit_changed = false;
-
-#ifndef NDEBUG
-       // these are really debug messages, but of possible interest.
-       if (_self_solo) {
-               PBD::info << string_compose (_("Cleared Explicit solo: %1\n"), name());
-       }
-       if (_soloed_by_others_upstream || _soloed_by_others_downstream) {
-               PBD::info << string_compose (_("Cleared Implicit solo: %1 up:%2 down:%3\n"),
-                               name(), _soloed_by_others_upstream, _soloed_by_others_downstream);
-       }
-#endif
-
-       if (!_self_solo && (_soloed_by_others_upstream || _soloed_by_others_downstream)) {
-               // if self-soled, set_solo() will do signal emission
-               emit_changed = true;
-       }
-
-       _soloed_by_others_upstream = 0;
-       _soloed_by_others_downstream = 0;
-
-       {
-               PBD::Unwinder<bool> uw (_solo_safe, false);
-               set_solo (false, Controllable::NoGroup);
-       }
-
-       if (emit_changed) {
-               set_mute_master_solo ();
-               _solo_control->Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
-       }
-}
-
-void
-Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set solo => %2, grp ? %3 currently self-soloed ? %4\n",
-                                                 name(), yn, enum_2_string(group_override), self_soloed()));
-
-       if (_solo_safe) {
-               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change due to solo-safe\n", name()));
-               return;
-       }
-
-       if (is_master() || is_monitor() || is_auditioner()) {
-               DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo change (master, monitor or auditioner)\n", name()));
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_solo, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       if (self_soloed() != yn) {
-               set_self_solo (yn);
-               _solo_control->Changed (true, group_override); /* EMIT SIGNAL */
-       }
-
-       assert (Config->get_solo_control_is_listen_control() || !_monitor_send || !_monitor_send->active());
-}
-
-void
-Route::set_self_solo (bool yn)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1: set SELF solo => %2\n", name(), yn));
-       _self_solo = yn;
-       set_mute_master_solo ();
-}
-
-void
-Route::mod_solo_by_others_upstream (int32_t delta)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n",
-                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
-       uint32_t old_sbu = _soloed_by_others_upstream;
-
-       if (delta < 0) {
-               if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) {
-                       _soloed_by_others_upstream += delta;
-               } else {
-                       _soloed_by_others_upstream = 0;
-               }
-       } else {
-               _soloed_by_others_upstream += delta;
-       }
-
-       DEBUG_TRACE (DEBUG::Solo, string_compose (
-                            "%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n",
-                            name(), delta, _soloed_by_others_upstream, old_sbu,
-                            _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo()));
-
-       /* push the inverse solo change to everything that feeds us.
-
-          This is important for solo-within-group. When we solo 1 track out of N that
-          feed a bus, that track will cause mod_solo_by_upstream (+1) to be called
-          on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all
-          tracks that feed it. This will silence them if they were audible because
-          of a bus solo, but the newly soloed track will still be audible (because
-          it is self-soloed).
-
-          but .. do this only when we are being told to solo-by-upstream (i.e delta = +1),
-          not in reverse.
+       /* nothing to do if we're not using AFL/PFL. But if we are, we need
+          to alter the active state of the monitor send.
        */
 
-       if ((_self_solo || _soloed_by_others_downstream) &&
-           ((old_sbu == 0 && _soloed_by_others_upstream > 0) ||
-            (old_sbu > 0 && _soloed_by_others_upstream == 0))) {
-
-               if (delta > 0 || !Config->get_exclusive_solo()) {
-                       DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
-                       for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
-                               if (i->sends_only) {
-                                       continue;
-                               }
-                               boost::shared_ptr<Route> sr = i->r.lock();
-                               if (sr) {
-                                       sr->mod_solo_by_others_downstream (-delta);
-                               }
-                       }
-               }
-       }
-
-       set_mute_master_solo ();
-       cerr << name() << " SC->Changed (false, UseGroup)\n";
-       _solo_control->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
-}
-
-void
-Route::mod_solo_by_others_downstream (int32_t delta)
-{
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n",
-                                                 name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
-
-       if (delta < 0) {
-               if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) {
-                       _soloed_by_others_downstream += delta;
-               } else {
-                       _soloed_by_others_downstream = 0;
-               }
-       } else {
-               _soloed_by_others_downstream += delta;
+       if (Config->get_solo_control_is_listen_control ()) {
+               set_listen (_solo_control->self_soloed());
        }
-
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream));
-
-       set_mute_master_solo ();
-       _solo_control->Changed (false, Controllable::UseGroup); /* EMIT SIGNAL */
-}
-
-void
-Route::set_mute_master_solo ()
-{
-       _mute_master->set_soloed_by_self (self_soloed());
-       _mute_master->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream());
 }
 
-void
-Route::mod_solo_isolated_by_upstream (bool yn)
+bool
+Route::listening_via_monitor () const
 {
-       bool old = solo_isolated ();
-       DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod_solo_isolated_by_upstream cur: %2 d: %3\n",
-                               name(), _solo_isolated_by_upstream, yn ? "+1" : "-1"));
-
-       if (!yn) {
-               if (_solo_isolated_by_upstream >= 1) {
-                       _solo_isolated_by_upstream--;
-               } else {
-                       _solo_isolated_by_upstream = 0;
-               }
+       if (_monitor_send) {
+               return _monitor_send->active ();
        } else {
-               _solo_isolated_by_upstream++;
-       }
-
-       if (solo_isolated() != old) {
-               /* solo isolated status changed */
-               _mute_master->set_solo_ignore (solo_isolated());
-               _solo_isolate_control->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
+               return false;
        }
 }
 
 void
-Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_isolate_upstream (int32_t delta)
 {
-       if (is_master() || is_monitor() || is_auditioner()) {
-               return;
-       }
-
-       if (use_group (group_override, &RouteGroup::is_solo)) {
-               _route_group->foreach_route (boost::bind (&Route::set_solo_isolated, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       bool changed = false;
-
-       if (yn) {
-               if (_solo_isolated == false) {
-                       _mute_master->set_solo_ignore (true);
-                       changed = true;
-               }
-               _solo_isolated = true;
-       } else {
-               if (_solo_isolated == true) {
-                       _solo_isolated = false;
-                       _mute_master->set_solo_ignore (false);
-                       changed = true;
-               }
-       }
-
-
-       if (!changed) {
-               return;
-       }
-
        /* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
 
        boost::shared_ptr<RouteList> routes = _session.get_routes ();
        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
 
-               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+               if ((*i).get() == this || !(*i)->can_solo()) {
                        continue;
                }
 
@@ -1092,87 +783,26 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o
                bool does_feed = feeds (*i, &sends_only);
 
                if (does_feed && !sends_only) {
-                       (*i)->mod_solo_isolated_by_upstream (yn);
+                       (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (delta);
                }
        }
-
-       /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
-
-       _solo_isolate_control->Changed (true, group_override); /* EMIT SIGNAL */
-}
-
-bool
-Route::solo_isolated () const
-{
-       return (_solo_isolated == true) || (_solo_isolated_by_upstream > 0);
-}
-
-void
-Route::set_mute_points (MuteMaster::MutePoint mp)
-{
-       _mute_master->set_mute_points (mp);
-       mute_points_changed (); /* EMIT SIGNAL */
-
-       if (_mute_master->muted_by_self()) {
-               _mute_control->Changed (true, Controllable::UseGroup); /* EMIT SIGNAL */
-       }
 }
 
 void
-Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
+Route::push_solo_upstream (int delta)
 {
-       if (use_group (group_override, &RouteGroup::is_mute)) {
-               _route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, Controllable::ForGroup));
-               return;
-       }
-
-       if (muted() != yn) {
-               _mute_master->set_muted_by_self (yn);
-               /* allow any derived classes to respond to the mute change
-                  before anybody else knows about it.
-               */
-               act_on_mute ();
-               /* tell everyone else */
-               _mute_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
+       DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
+       for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+               if (i->sends_only) {
+                       continue;
+               }
+               boost::shared_ptr<Route> sr (i->r.lock());
+               if (sr) {
+                       sr->solo_control()->mod_solo_by_others_downstream (-delta);
+               }
        }
 }
 
-bool
-Route::muted () const
-{
-       return _mute_master->muted_by_self();
-}
-
-bool
-Route::muted_by_others_soloing () const
-{
-       // This method is only used by route_ui for display state.
-       // The real thing is MuteMaster::muted_by_others_at()
-
-       //master is never muted by others
-       if (is_master())
-               return false;
-
-       //now check to see if something is soloed (and I am not)
-       //see also MuteMaster::mute_gain_at()
-       return _session.soloing() && !soloed() && !solo_isolated();
-}
-
-bool
-Route::muted_by_others () const
-{
-       // This method is only used by route_ui for display state.
-       // The real thing is MuteMaster::muted_by_others_at()
-
-       //master is never muted by others
-       if (is_master())
-               return false;
-
-       //now check to see if something is soloed (and I am not)
-       //see also MuteMaster::mute_gain_at()
-       return _mute_master->muted_by_others() || (_session.soloing() && !soloed() && !solo_isolated());
-}
-
 #if 0
 static void
 dump_processors(const string& name, const list<boost::shared_ptr<Processor> >& procs)
@@ -2743,8 +2373,6 @@ Route::state(bool full_state)
 
        node->add_property("active", _active?"yes":"no");
        string p;
-       boost::to_string (_phase_invert, p);
-       node->add_property("phase-invert", p);
        node->add_property("denormal-protection", _denormal_protection?"yes":"no");
        node->add_property("meter-point", enum_2_string (_meter_point));
 
@@ -2756,18 +2384,9 @@ Route::state(bool full_state)
 
        snprintf (buf, sizeof (buf), "%d", _order_key);
        node->add_property ("order-key", buf);
-       node->add_property ("self-solo", (_self_solo ? "yes" : "no"));
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream);
-       node->add_property ("soloed-by-upstream", buf);
-       snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream);
-       node->add_property ("soloed-by-downstream", buf);
-       node->add_property ("solo-isolated", solo_isolated() ? "yes" : "no");
-       node->add_property ("solo-safe", _solo_safe ? "yes" : "no");
 
        node->add_child_nocopy (_input->state (full_state));
        node->add_child_nocopy (_output->state (full_state));
-       node->add_child_nocopy (_solo_control->get_state ());
-       node->add_child_nocopy (_mute_control->get_state ());
        node->add_child_nocopy (_mute_master->get_state ());
 
        if (full_state) {
@@ -2866,7 +2485,7 @@ Route::set_state (const XMLNode& node, int version)
                _strict_io = string_is_affirmative (prop->value());
        }
 
-       if (is_master() || is_monitor() || is_auditioner()) {
+       if (!can_solo()) {
                _mute_master->set_solo_ignore (true);
        }
 
@@ -2933,31 +2552,10 @@ Route::set_state (const XMLNode& node, int version)
        // this looks up the internal instrument in processors
        reset_instrument_info();
 
-       if ((prop = node.property ("self-solo")) != 0) {
-               set_self_solo (string_is_affirmative (prop->value()));
-       }
-
-       if ((prop = node.property ("soloed-by-upstream")) != 0) {
-               _soloed_by_others_upstream = 0; // needed for mod_.... () to work
-               mod_solo_by_others_upstream (atoi (prop->value()));
-       }
-
-       if ((prop = node.property ("soloed-by-downstream")) != 0) {
-               _soloed_by_others_downstream = 0; // needed for mod_.... () to work
-               mod_solo_by_others_downstream (atoi (prop->value()));
-       }
-
-       if ((prop = node.property ("solo-isolated")) != 0) {
-               set_solo_isolated (string_is_affirmative (prop->value()), Controllable::NoGroup);
-       }
-
-       if ((prop = node.property ("solo-safe")) != 0) {
-               set_solo_safe (string_is_affirmative (prop->value()), Controllable::NoGroup);
-       }
-
-       if ((prop = node.property (X_("phase-invert"))) != 0) {
-               set_phase_invert (boost::dynamic_bitset<> (prop->value ()));
-       }
+       _solo_control->set_state (node, version);
+       _solo_safe_control->set_state (node, version);
+       _solo_isolate_control->set_state (node, version);
+       _mute_control->set_state (node, version);
 
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
@@ -3046,7 +2644,7 @@ Route::set_state (const XMLNode& node, int version)
                                set_remote_control_id_internal (x);
                        }
 
-               } else if (child->name() == X_("MuteMaster")) {
+               } else if (child->name() == MuteMaster::xml_node_name) {
                        _mute_master->set_state (*child, version);
 
                } else if (child->name() == Automatable::xml_node_name) {
@@ -3089,26 +2687,10 @@ Route::set_state_2X (const XMLNode& node, int version)
                _mute_master->set_solo_ignore (true);
        }
 
-       if ((prop = node.property (X_("phase-invert"))) != 0) {
-               boost::dynamic_bitset<> p (_input->n_ports().n_audio ());
-               if (string_is_affirmative (prop->value ())) {
-                       p.set ();
-               }
-               set_phase_invert (p);
-       }
-
        if ((prop = node.property (X_("denormal-protection"))) != 0) {
                set_denormal_protection (string_is_affirmative (prop->value()));
        }
 
-       if ((prop = node.property (X_("soloed"))) != 0) {
-               bool yn = string_is_affirmative (prop->value());
-
-               /* XXX force reset of solo status */
-
-               set_solo (yn);
-       }
-
        if ((prop = node.property (X_("muted"))) != 0) {
 
                bool first = true;
@@ -3870,11 +3452,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                   contains ConfigurationChanged
                */
                configure_processors (0);
-               _phase_invert.resize (_input->n_ports().n_audio ());
+               _phase_control->resize (_input->n_ports().n_audio ());
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (_soloed_by_others_upstream || _solo_isolated_by_upstream) {
+       if (_solo_control->soloed_by_others_upstream() || _solo_isolate_control->solo_isolated_by_upstream()) {
                int sbou = 0;
                int ibou = 0;
                boost::shared_ptr<RouteList> routes = _session.get_routes ();
@@ -3889,38 +3471,36 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                                        if ((*i)->soloed()) {
                                                ++sbou;
                                        }
-                                       if ((*i)->solo_isolated()) {
+                                       if ((*i)->solo_isolate_control()->solo_isolated()) {
                                                ++ibou;
                                        }
                                }
                        }
                }
 
-               int delta  = sbou - _soloed_by_others_upstream;
-               int idelta = ibou - _solo_isolated_by_upstream;
+               int delta  = sbou - _solo_control->soloed_by_others_upstream();
+               int idelta = ibou - _solo_isolate_control->solo_isolated_by_upstream();
 
                if (idelta < -1) {
                        PBD::warning << string_compose (
                                        _("Invalid Solo-Isolate propagation: from:%1 new:%2 - old:%3 = delta:%4"),
-                                       _name, ibou, _solo_isolated_by_upstream, idelta)
+                                       _name, ibou, _solo_isolate_control->solo_isolated_by_upstream(), idelta)
                                     << endmsg;
 
                }
 
-               if (_soloed_by_others_upstream) {
+               if (_solo_control->soloed_by_others_upstream()) {
                        // ignore new connections (they're not propagated)
                        if (delta <= 0) {
-                               mod_solo_by_others_upstream (delta);
+                               _solo_control->mod_solo_by_others_upstream (delta);
                        }
                }
 
-               if (_solo_isolated_by_upstream) {
+               if (_solo_isolate_control->solo_isolated_by_upstream()) {
                        // solo-isolate currently only propagates downstream
                        if (idelta < 0) {
-                               mod_solo_isolated_by_upstream (false);
+                               _solo_isolate_control->mod_solo_isolated_by_upstream (1);
                        }
-                       // TODO think: mod_solo_isolated_by_upstream() does not take delta arg,
-                       // but idelta can't be smaller than -1, can it?
                        //_solo_isolated_by_upstream = ibou;
                }
 
@@ -3933,11 +3513,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
                        bool sends_only;
                        bool does_feed = feeds (*i, &sends_only);
                        if (delta <= 0 && does_feed && !sends_only) {
-                               (*i)->mod_solo_by_others_upstream (delta);
+                               (*i)->solo_control()->mod_solo_by_others_upstream (delta);
                        }
 
                        if (idelta < 0 && does_feed && !sends_only) {
-                               (*i)->mod_solo_isolated_by_upstream (false);
+                               (*i)->solo_isolate_control()->mod_solo_isolated_by_upstream (-1);
                        }
                }
        }
@@ -3963,7 +3543,7 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (_soloed_by_others_downstream) {
+       if (_solo_control->soloed_by_others_downstream()) {
                int sbod = 0;
                /* checking all all downstream routes for
                 * explicit of implict solo is a rather drastic measure,
@@ -3986,20 +3566,20 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                                }
                        }
                }
-               int delta = sbod - _soloed_by_others_downstream;
+               int delta = sbod - _solo_control->soloed_by_others_downstream();
                if (delta <= 0) {
                        // do not allow new connections to change implicit solo (no propagation)
-                       mod_solo_by_others_downstream (delta);
+                       _solo_control->mod_solo_by_others_downstream (delta);
                        // Session::route_solo_changed() does not propagate indirect solo-changes
                        // propagate upstream to tracks
                        for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i).get() == this || !can_solo()) {
                                        continue;
                                }
                                bool sends_only;
                                bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
                                if (delta != 0 && does_feed && !sends_only) {
-                                       (*i)->mod_solo_by_others_downstream (delta);
+                                       (*i)->solo_control()->mod_solo_by_others_downstream (delta);
                                }
                        }
 
@@ -4639,41 +4219,6 @@ Route::internal_send_for (boost::shared_ptr<const Route> target) const
        return boost::shared_ptr<Send>();
 }
 
-/** @param c Audio channel index.
- *  @param yn true to invert phase, otherwise false.
- */
-void
-Route::set_phase_invert (uint32_t c, bool yn)
-{
-       if (_phase_invert[c] != yn) {
-               _phase_invert[c] = yn;
-               _phase_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-}
-
-void
-Route::set_phase_invert (boost::dynamic_bitset<> p)
-{
-       if (_phase_invert != p) {
-               _phase_invert = p;
-               _phase_control->Changed (true, Controllable::NoGroup); /* EMIT SIGNAL */
-               _session.set_dirty ();
-       }
-}
-
-bool
-Route::phase_invert (uint32_t c) const
-{
-       return _phase_invert[c];
-}
-
-boost::dynamic_bitset<>
-Route::phase_invert () const
-{
-       return _phase_invert;
-}
-
 void
 Route::set_denormal_protection (bool yn)
 {
@@ -4735,20 +4280,16 @@ Route::gain_control() const
        return _gain_control;
 }
 
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<GainControl>
 Route::trim_control() const
 {
        return _trim_control;
 }
 
-boost::shared_ptr<AutomationControl>
+boost::shared_ptr<PhaseControl>
 Route::phase_control() const
 {
-       if (phase_invert().size()) {
-               return _phase_control;
-       } else {
-               return boost::shared_ptr<PhaseControllable>();
-       }
+       return _phase_control;
 }
 
 boost::shared_ptr<AutomationControl>
@@ -4841,12 +4382,6 @@ Route::has_io_processor_named (const string& name)
        return false;
 }
 
-MuteMaster::MutePoint
-Route::mute_points () const
-{
-       return _mute_master->mute_points ();
-}
-
 void
 Route::set_processor_positions ()
 {
@@ -5903,7 +5438,7 @@ Route::vca_assign (boost::shared_ptr<VCA> vca)
 {
        _gain_control->add_master (vca->gain_control());
        _solo_control->add_master (vca->solo_control());
-       _mute_control->add_master (vca->mute_control());
+       // _mute_control->add_master (vca->mute_control());
 }
 
 void
@@ -5913,10 +5448,48 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
                /* unassign from all */
                _gain_control->clear_masters ();
                _solo_control->clear_masters ();
-               _mute_control->clear_masters ();
+               //_mute_control->clear_masters ();
        } else {
                _gain_control->remove_master (vca->gain_control());
                _solo_control->remove_master (vca->solo_control());
-               _mute_control->remove_master (vca->mute_control());
+               //_mute_control->remove_master (vca->mute_control());
+       }
+}
+
+bool
+Route::muted_by_others_soloing () const
+{
+       // This method is only used by route_ui for display state.
+       // The DSP version is MuteMaster::muted_by_others_at()
+
+       if (!can_be_muted_by_others ()) {
+               return false;
+       }
+
+       return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
+}
+
+bool
+Route::muted_by_others () const
+{
+       // This method is only used by route_ui for display state.
+       // The DSP version is MuteMaster::muted_by_others_at()
+
+       if (!can_be_muted_by_others()) {
+               return false;
+       }
+
+       return _mute_master->muted_by_others();
+}
+
+void
+Route::clear_all_solo_state ()
+{
+       double v = _solo_safe_control->get_value ();
+
+       _solo_control->clear_all_solo_state ();
+
+       if (v != 0.0) {
+               _solo_safe_control->set_value (v, Controllable::NoGroup);
        }
 }
diff --git a/libs/ardour/route_controls.cc b/libs/ardour/route_controls.cc
deleted file mode 100644 (file)
index ad5408d..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
-    Copyright (C) 2000 Paul Davis
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifdef WAF_BUILD
-#include "libardour-config.h"
-#endif
-
-#include "ardour/automation_control.h"
-#include "ardour/parameter_descriptor.h"
-#include "ardour/route.h"
-#include "ardour/session.h"
-
-#include "i18n.h"
-
-using namespace std;
-using namespace ARDOUR;
-using namespace PBD;
-
-void
-Route::set_control (AutomationType type, double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       boost::shared_ptr<RouteList> rl;
-
-       switch (type) {
-       case GainAutomation:
-               /* route must mediate group control */
-               set_gain (val, group_override);
-               break;
-
-       case TrimAutomation:
-               /* route must mediate group control */
-               set_trim (val, group_override);
-               break;
-
-       case RecEnableAutomation:
-               /* session must mediate group control */
-               rl.reset (new RouteList);
-               rl->push_back (shared_from_this());
-               _session.set_record_enabled (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
-               break;
-
-       case SoloAutomation:
-               /* session must mediate group control */
-               rl.reset (new RouteList);
-               rl->push_back (shared_from_this());
-               if (Config->get_solo_control_is_listen_control()) {
-                       _session.set_listen (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
-               } else {
-                       _session.set_solo (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
-               }
-               break;
-
-       case MuteAutomation:
-               /* session must mediate group control */
-               rl.reset (new RouteList);
-               rl->push_back (shared_from_this());
-               _session.set_mute (rl, val >= 0.5 ? true : false, Session::rt_cleanup, group_override);
-               return;
-               break;
-
-       default:
-               /* Not a route automation control */
-               fatal << string_compose (_("programming error: %1%2\n"), X_("illegal type of route automation control passed to Route::set_control(): "), enum_2_string(type)) << endmsg;
-               /*NOTREACHED*/
-               return;
-       }
-}
-
-
-Route::RouteAutomationControl::RouteAutomationControl (const std::string& name,
-                                                       AutomationType atype,
-                                                       boost::shared_ptr<AutomationList> alist,
-                                                       boost::shared_ptr<Route> r)
-       : AutomationControl (r->session(), Evoral::Parameter (atype),
-                            ParameterDescriptor (Evoral::Parameter (atype)),
-                            alist, name)
-       , _route (r)
-{
-}
-
-double
-Route::BooleanRouteAutomationControl::get_masters_value_locked () const
-{
-       /* masters (read/write) lock must be held */
-
-       /* if any master is enabled (val > 0.0) then we consider the master
-          value to be 1.0
-       */
-
-       for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
-               if (mr->second.master()->get_value()) {
-                       return 1.0;
-               }
-       }
-
-       return 0.0;
-}
-
-
-
-Route::GainControllable::GainControllable (Session& s, AutomationType atype, boost::shared_ptr<Route> r)
-       : GainControl (s, Evoral::Parameter(atype))
-       , _route (r)
-{
-
-}
-
-Route::SoloControllable::SoloControllable (std::string name, boost::shared_ptr<Route> r)
-       : BooleanRouteAutomationControl (name, SoloAutomation, boost::shared_ptr<AutomationList>(), r)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-void
-Route::SoloControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-
-       if (!r) {
-               return;
-       }
-
-       bool master_soloed;
-
-       {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               master_soloed = (bool) get_masters_value_locked ();
-       }
-
-       /* Master is considered equivalent to an upstream solo control, not
-        * direct control over self-soloed.
-        */
-
-       r->mod_solo_by_others_upstream (master_soloed ? 1 : -1);
-
-       AutomationControl::master_changed (false, gcd);
-}
-
-void
-Route::SoloControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (val, group_override);
-       }
-}
-
-void
-Route::SoloControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return;
-       }
-       r->set_control (SoloAutomation, val, group_override);
-}
-
-void
-Route::SoloControllable::set_value_unchecked (double val)
-{
-       /* Used only by automation playback */
-
-       _set_value (val, Controllable::NoGroup);
-}
-
-double
-Route::SoloControllable::get_value () const
-{
-       if (slaved()) {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               return get_masters_value_locked () ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
-       }
-
-       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
-               // Playing back automation, get the value from the list
-               return AutomationControl::get_value();
-       }
-
-       boost::shared_ptr<Route> r = _route.lock ();
-
-       if (!r) {
-               return 0;
-       }
-
-       if (Config->get_solo_control_is_listen_control()) {
-               return r->listening_via_monitor() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
-       } else {
-               return r->self_soloed() ? GAIN_COEFF_UNITY : GAIN_COEFF_ZERO;
-       }
-}
-
-Route::MuteControllable::MuteControllable (std::string name, boost::shared_ptr<Route> r)
-       : BooleanRouteAutomationControl (name, MuteAutomation, boost::shared_ptr<AutomationList>(), r)
-       , _route (r)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-void
-Route::MuteControllable::set_superficial_value(bool muted)
-{
-       /* Note we can not use AutomationControl::set_value here since it will emit
-          Changed(), but the value will not be correct to the observer. */
-
-       const bool to_list = _list && ((AutomationList*)_list.get ())->automation_write ();
-       const double where = _session.audible_frame ();
-
-       if (to_list) {
-               /* Note that we really need this:
-                *  if (as == Touch && _list->in_new_write_pass ()) {
-                *       alist->start_write_pass (_session.audible_frame ());
-                *  }
-                * here in the case of the user calling from a GUI or whatever.
-                * Without the ability to distinguish between user and
-                * automation-initiated changes, we lose the "touch mute"
-                * behaviour we have in AutomationController::toggled ().
-                */
-               _list->set_in_write_pass (true, false, where);
-       }
-
-       Control::set_double (muted, where, to_list);
-}
-
-void
-Route::MuteControllable::master_changed (bool from_self, PBD::Controllable::GroupControlDisposition gcd)
-{
-       bool master_muted;
-
-       {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               master_muted = (bool) get_masters_value_locked ();
-       }
-
-       boost::shared_ptr<Route> r (_route.lock());
-       if (r) {
-               r->mute_master()->mod_muted_by_others (master_muted ? 1 : -1);
-       }
-
-       AutomationControl::master_changed (false, gcd);
-}
-
-void
-Route::MuteControllable::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (val, group_override);
-       }
-}
-
-void
-Route::MuteControllable::set_value_unchecked (double val)
-{
-       /* used only automation playback */
-       _set_value (val, Controllable::NoGroup);
-}
-
-void
-Route::MuteControllable::_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-
-       if (!r) {
-               return;
-       }
-
-       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
-               // Set superficial/automation value to drive controller (and possibly record)
-               const bool bval = ((val >= 0.5) ? true : false);
-               set_superficial_value (bval);
-               // Playing back automation, set route mute directly
-               r->set_mute (bval, Controllable::NoGroup);
-       } else {
-               r->set_control (MuteAutomation, val, group_override);
-       }
-}
-
-double
-Route::MuteControllable::get_value () const
-{
-       if (slaved()) {
-               Glib::Threads::RWLock::ReaderLock lm (master_lock);
-               return get_masters_value_locked () ? 1.0 : 0.0;
-       }
-
-       if (_list && ((AutomationList*)_list.get())->automation_playback()) {
-               // Playing back automation, get the value from the list
-               return AutomationControl::get_value();
-       }
-
-       // Not playing back automation, get the actual route mute value
-       boost::shared_ptr<Route> r = _route.lock ();
-       return (r && r->muted()) ? 1.0 : 0.0;
-}
-
-Route::PhaseControllable::PhaseControllable (std::string name, boost::shared_ptr<Route> r)
-       : BooleanRouteAutomationControl (name, PhaseAutomation, boost::shared_ptr<AutomationList>(), r)
-       , _current_phase (0)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(PhaseAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-void
-Route::PhaseControllable::set_value (double v, PBD::Controllable::GroupControlDisposition /* group_override */)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (r->phase_invert().size()) {
-               if (v == 0 || (v < 1 && v > 0.9) ) {
-                       r->set_phase_invert (_current_phase, false);
-               } else {
-                       r->set_phase_invert (_current_phase, true);
-               }
-       }
-}
-
-double
-Route::PhaseControllable::get_value () const
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return 0.0;
-       }
-       return (double) r->phase_invert (_current_phase);
-}
-
-void
-Route::PhaseControllable::set_channel (uint32_t c)
-{
-       _current_phase = c;
-}
-
-uint32_t
-Route::PhaseControllable::channel () const
-{
-       return _current_phase;
-}
-
-Route::SoloIsolateControllable::SoloIsolateControllable (std::string name, boost::shared_ptr<Route> r)
-       : BooleanRouteAutomationControl (name, SoloIsolateAutomation, boost::shared_ptr<AutomationList>(), r)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloIsolateAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-
-double
-Route::SoloIsolateControllable::get_value () const
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return 0.0; /* "false" */
-       }
-
-       return r->solo_isolated() ? 1.0 : 0.0;
-}
-
-void
-Route::SoloIsolateControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       _set_value (val, gcd);
-}
-
-void
-Route::SoloIsolateControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return;
-       }
-
-       /* no group semantics yet */
-       r->set_solo_isolated (val >= 0.5 ? true : false);
-}
-
-Route::SoloSafeControllable::SoloSafeControllable (std::string name, boost::shared_ptr<Route> r)
-       : BooleanRouteAutomationControl (name, SoloSafeAutomation, boost::shared_ptr<AutomationList>(), r)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(SoloSafeAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-void
-Route::SoloSafeControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       _set_value (val, gcd);
-}
-
-void
-Route::SoloSafeControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition)
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return;
-       }
-
-       /* no group semantics yet */
-       r->set_solo_safe (val >= 0.5 ? true : false);
-}
-
-double
-Route::SoloSafeControllable::get_value () const
-{
-       boost::shared_ptr<Route> r = _route.lock ();
-       if (!r) {
-               return 0.0; /* "false" */
-       }
-
-       return r->solo_safe() ? 1.0 : 0.0;
-}
index 910141a44029c901343c43a8720d5f5d45d839d7..70b9b48d6feb95241e93f002b5c742ca622c6720 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "ardour/route.h"
 #include "ardour/route_graph.h"
+#include "ardour/track.h"
 
 #include "i18n.h"
 
@@ -195,21 +196,39 @@ struct RouteRecEnabledComparator
 {
        bool operator () (GraphVertex r1, GraphVertex r2) const
        {
-               if (r1->record_enabled()) {
-                       if (r2->record_enabled()) {
-                               /* both rec-enabled, just use signal order */
+               boost::shared_ptr<Track> t1 (boost::dynamic_pointer_cast<Track>(r1));
+               boost::shared_ptr<Track> t2 (boost::dynamic_pointer_cast<Track>(r2));
+
+               if (!t1) {
+                       if (!t2) {
+                               /* makes no difference which is first, use signal order */
                                return r1->order_key () < r2->order_key ();
                        } else {
-                               /* r1 rec-enabled, r2 not rec-enabled, run r2 early */
+                               /* r1 is not a track, r2 is, run it early */
+                               return false;
+                       }
+               }
+
+               if (!t2) {
+                       /* we already tested !t1, so just use signal order */
+                       return r1->order_key () < r2->order_key ();
+               }
+
+               if (t1->rec_enable_control()->get_value()) {
+                       if (t2->rec_enable_control()->get_value()) {
+                               /* both rec-enabled, just use signal order */
+                               return t1->order_key () < t2->order_key ();
+                       } else {
+                               /* t1 rec-enabled, t2 not rec-enabled, run t2 early */
                                return false;
                        }
                } else {
-                       if (r2->record_enabled()) {
-                               /* r2 rec-enabled, r1 not rec-enabled, run r1 early */
+                       if (t2->rec_enable_control()->get_value()) {
+                               /* t2 rec-enabled, t1 not rec-enabled, run t1 early */
                                return true;
                        } else {
                                /* neither rec-enabled, use signal order */
-                               return r1->order_key () < r2->order_key ();
+                               return t1->order_key () < t2->order_key ();
                        }
                }
        }
index b482bb85d32fa704b6507c9317044577e426914f..137e2c4734edd324a96f505dd9708765ab7f4d3f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/audio_track.h"
+#include "ardour/monitor_control.h"
 #include "ardour/route.h"
 #include "ardour/route_group.h"
 #include "ardour/session.h"
@@ -57,21 +58,21 @@ void
 RouteGroup::make_property_quarks ()
 {
        Properties::relative.property_id = g_quark_from_static_string (X_("relative"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n",   Properties::relative.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for relative = %1\n",   Properties::relative.property_id));
        Properties::active.property_id = g_quark_from_static_string (X_("active"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n",     Properties::active.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for active = %1\n",     Properties::active.property_id));
        Properties::hidden.property_id = g_quark_from_static_string (X_("hidden"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",     Properties::hidden.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for hidden = %1\n",     Properties::hidden.property_id));
        Properties::gain.property_id = g_quark_from_static_string (X_("gain"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n",       Properties::gain.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for gain = %1\n",       Properties::gain.property_id));
        Properties::mute.property_id = g_quark_from_static_string (X_("mute"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n",       Properties::mute.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for mute = %1\n",       Properties::mute.property_id));
        Properties::solo.property_id = g_quark_from_static_string (X_("solo"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n",       Properties::solo.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for solo = %1\n",       Properties::solo.property_id));
        Properties::recenable.property_id = g_quark_from_static_string (X_("recenable"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n",  Properties::recenable.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for recenable = %1\n",  Properties::recenable.property_id));
        Properties::select.property_id = g_quark_from_static_string (X_("select"));
-        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n",     Properties::select.property_id));
+        DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for select = %1\n",     Properties::select.property_id));
        Properties::route_active.property_id = g_quark_from_static_string (X_("route-active"));
         DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for route-active = %1\n", Properties::route_active.property_id));
        Properties::color.property_id = g_quark_from_static_string (X_("color"));
@@ -96,6 +97,11 @@ RouteGroup::RouteGroup (Session& s, const string &n)
        : SessionObject (s, n)
        , routes (new RouteList)
        , ROUTE_GROUP_DEFAULT_PROPERTIES
+       , _solo_group (new ControlGroup (SoloAutomation))
+       , _mute_group (new ControlGroup (MuteAutomation))
+       , _rec_enable_group (new ControlGroup (RecEnableAutomation))
+       , _gain_group (new ControlGroup (GainAutomation))
+       , _monitoring_group (new ControlGroup (MonitoringAutomation))
 {
        _xml_node_name = X_("RouteGroup");
 
@@ -114,6 +120,12 @@ RouteGroup::RouteGroup (Session& s, const string &n)
 
 RouteGroup::~RouteGroup ()
 {
+       _solo_group->clear ();
+       _mute_group->clear ();
+       _gain_group->clear ();
+       _rec_enable_group->clear ();
+       _monitoring_group->clear ();
+
        for (RouteList::iterator i = routes->begin(); i != routes->end();) {
                RouteList::iterator tmp = i;
                ++tmp;
@@ -140,6 +152,15 @@ RouteGroup::add (boost::shared_ptr<Route> r)
 
        routes->push_back (r);
 
+       _solo_group->add_control (r->solo_control());
+       _mute_group->add_control (r->mute_control());
+       _gain_group->add_control (r->gain_control());
+       boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+       if (trk) {
+               _rec_enable_group->add_control (trk->rec_enable_control());
+               _monitoring_group->add_control (trk->monitoring_control());
+       }
+
        r->set_route_group (this);
        r->DropReferences.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
 
@@ -165,6 +186,14 @@ RouteGroup::remove (boost::shared_ptr<Route> r)
 
        if ((i = find (routes->begin(), routes->end(), r)) != routes->end()) {
                r->set_route_group (0);
+               _solo_group->remove_control (r->solo_control());
+               _mute_group->remove_control (r->mute_control());
+               _gain_group->remove_control (r->gain_control());
+               boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+               if (trk) {
+                       _rec_enable_group->remove_control (trk->rec_enable_control());
+                       _monitoring_group->remove_control (trk->monitoring_control());
+               }
                routes->erase (i);
                _session.set_dirty ();
                RouteRemoved (this, boost::weak_ptr<Route> (r)); /* EMIT SIGNAL */
@@ -175,49 +204,6 @@ RouteGroup::remove (boost::shared_ptr<Route> r)
 }
 
 
-gain_t
-RouteGroup::get_min_factor (gain_t factor)
-{
-       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-               gain_t const g = (*i)->gain_control()->get_value();
-
-               if ((g + g * factor) >= 0.0f) {
-                       continue;
-               }
-
-               if (g <= 0.0000003f) {
-                       return 0.0f;
-               }
-
-               factor = 0.0000003f / g - 1.0f;
-       }
-
-       return factor;
-}
-
-gain_t
-RouteGroup::get_max_factor (gain_t factor)
-{
-       for (RouteList::iterator i = routes->begin(); i != routes->end(); i++) {
-               gain_t const g = (*i)->gain_control()->get_value();
-
-               // if the current factor woulnd't raise this route above maximum
-               if ((g + g * factor) <= 1.99526231f) {
-                       continue;
-               }
-
-               // if route gain is already at peak, return 0.0f factor
-               if (g >= 1.99526231f) {
-                       return 0.0f;
-               }
-
-               // factor is calculated so that it would raise current route to max
-               factor = 1.99526231f / g - 1.0f;
-       }
-
-       return factor;
-}
-
 XMLNode&
 RouteGroup::get_state ()
 {
@@ -269,6 +255,8 @@ RouteGroup::set_state (const XMLNode& node, int version)
                }
        }
 
+       push_to_groups ();
+
        return 0;
 }
 
@@ -293,6 +281,8 @@ RouteGroup::set_state_2X (const XMLNode& node, int /*version*/)
                _color = false;
        }
 
+       push_to_groups ();
+
        return 0;
 }
 
@@ -303,6 +293,8 @@ RouteGroup::set_gain (bool yn)
                return;
        }
        _gain = yn;
+       _gain_group->set_active (yn);
+
        send_change (PropertyChange (Properties::gain));
 }
 
@@ -313,6 +305,7 @@ RouteGroup::set_mute (bool yn)
                return;
        }
        _mute = yn;
+       _mute_group->set_active (yn);
        send_change (PropertyChange (Properties::mute));
 }
 
@@ -323,6 +316,7 @@ RouteGroup::set_solo (bool yn)
                return;
        }
        _solo = yn;
+       _solo_group->set_active (yn);
        send_change (PropertyChange (Properties::solo));
 }
 
@@ -333,6 +327,7 @@ RouteGroup::set_recenable (bool yn)
                return;
        }
        _recenable = yn;
+       _rec_enable_group->set_active (yn);
        send_change (PropertyChange (Properties::recenable));
 }
 
@@ -384,6 +379,8 @@ RouteGroup::set_monitoring (bool yn)
        }
 
        _monitoring = yn;
+       _monitoring_group->set_active (yn);
+
        send_change (PropertyChange (Properties::monitoring));
 
        _session.set_dirty ();
@@ -531,3 +528,19 @@ RouteGroup::enabled_property (PBD::PropertyID prop)
 
        return dynamic_cast<const PropertyTemplate<bool>* > (i->second)->val ();
 }
+
+void
+RouteGroup::post_set (PBD::PropertyChange const &)
+{
+       push_to_groups ();
+}
+
+void
+RouteGroup::push_to_groups ()
+{
+       _gain_group->set_active (_gain);
+       _solo_group->set_active (_solo);
+       _mute_group->set_active (_mute);
+       _rec_enable_group->set_active (_recenable);
+       _monitoring_group->set_active (_monitoring);
+}
index ee70d2a40f14810f2d5686bab9d5798082781905..7658ff270d066bff56a95af88285f31559a0e7bf 100644 (file)
@@ -98,6 +98,7 @@
 #include "ardour/session_directory.h"
 #include "ardour/session_playlists.h"
 #include "ardour/smf_source.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/source_factory.h"
 #include "ardour/speakers.h"
 #include "ardour/tempo.h"
@@ -1506,7 +1507,7 @@ Session::set_track_monitor_input_status (bool yn)
        boost::shared_ptr<RouteList> rl = routes.reader ();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                boost::shared_ptr<AudioTrack> tr = boost::dynamic_pointer_cast<AudioTrack> (*i);
-               if (tr && tr->record_enabled ()) {
+               if (tr && tr->rec_enable_control()->get_value()) {
                        //cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
                        tr->request_input_monitoring (yn);
                }
@@ -1941,15 +1942,9 @@ void
 Session::set_all_tracks_record_enabled (bool enable )
 {
        boost::shared_ptr<RouteList> rl = routes.reader();
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr) {
-                       tr->set_record_enabled (enable, Controllable::NoGroup);
-               }
-       }
+       set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), enable, Controllable::NoGroup);
 }
 
-
 void
 Session::disable_record (bool rt_context, bool force)
 {
@@ -2981,7 +2976,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                //  0 for Stereo Out mode
                                //  0 Multi Out mode
                                if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       track->set_gain (dB_to_coefficient (0), Controllable::NoGroup);
+                                       track->gain_control()->set_value (dB_to_coefficient (0), Controllable::NoGroup);
                                }
                        }
 
@@ -3430,7 +3425,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                if (tr) {
                        tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
                        track_playlist_changed (boost::weak_ptr<Track> (tr));
-                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
+                       tr->rec_enable_control()->Changed.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
                        if (mt) {
@@ -3580,7 +3575,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
                                continue;
                        }
 
-                       (*iter)->set_solo (false, Controllable::NoGroup);
+                       (*iter)->solo_control()->set_value (0.0, Controllable::NoGroup);
 
                        rs->remove (*iter);
 
@@ -3721,7 +3716,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
                                        continue;
                                }
 
-                               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                               if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
                                        /* route does not get solo propagated to it */
                                        continue;
                                }
@@ -3734,7 +3729,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
                                         */
                                        continue;
                                }
-                               (*i)->set_listen (false, Controllable::NoGroup);
+                               (*i)->solo_control()->set_value (0.0, Controllable::NoGroup);
                        }
                }
 
@@ -3759,7 +3754,7 @@ Session::route_solo_isolated_changed (boost::weak_ptr<Route> wpr)
 
        bool send_changed = false;
 
-       if (route->solo_isolated()) {
+       if (route->solo_isolate_control()->solo_isolated()) {
                if (_solo_isolated_cnt == 0) {
                        send_changed = true;
                }
@@ -3838,7 +3833,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                                continue;
                        }
 
-                       if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                       if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
                                /* route does not get solo propagated to it */
                                continue;
                        }
@@ -3852,7 +3847,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                                continue;
                        }
 
-                       (*i)->set_solo (false, group_override);
+                       (*i)->solo_control()->set_value (0.0, group_override);
                }
        }
 
@@ -3871,7 +3866,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                        continue;
                }
 
-               if ((*i)->solo_isolated() || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+               if ((*i)->solo_isolate_control()->solo_isolated() || !(*i)->can_solo()) {
                        /* route does not get solo propagated to it */
                        continue;
                }
@@ -3893,7 +3888,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                        DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
                        if (!via_sends_only) {
                                if (!route->soloed_by_others_upstream()) {
-                                       (*i)->mod_solo_by_others_downstream (delta);
+                                       (*i)->solo_control()->mod_solo_by_others_downstream (delta);
                                } else {
                                        DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others upstream\n");
                                }
@@ -3922,7 +3917,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
                        if (!via_sends_only) {
                                //NB. Triggers Invert Push, which handles soloed by downstream
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
-                               (*i)->mod_solo_by_others_upstream (delta);
+                               (*i)->solo_control()->mod_solo_by_others_upstream (delta);
                        } else {
                                DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
                        }
@@ -3969,7 +3964,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
        }
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner() && (*i)->self_soloed()) {
+               if ((*i)->can_solo() && (*i)->self_soloed()) {
                        something_soloed = true;
                }
 
@@ -3978,11 +3973,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
                                listeners++;
                                something_listening = true;
                        } else {
-                               (*i)->set_listen (false, Controllable::NoGroup);
+                               (*i)->set_listen (false);
                        }
                }
 
-               if ((*i)->solo_isolated()) {
+               if ((*i)->solo_isolate_control()->solo_isolated()) {
                        isolated++;
                }
        }
@@ -6078,7 +6073,7 @@ Session::update_route_record_state ()
        while (i != rl->end ()) {
 
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && tr->record_enabled ()) {
+                                   if (tr && tr->rec_enable_control()->get_value()) {
                        break;
                }
 
@@ -6095,7 +6090,7 @@ Session::update_route_record_state ()
 
        for (i = rl->begin(); i != rl->end (); ++i) {
                boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
-               if (tr && !tr->record_enabled ()) {
+               if (tr && !tr->rec_enable_control()->get_value()) {
                        break;
                }
        }
@@ -6124,12 +6119,7 @@ void
 Session::solo_control_mode_changed ()
 {
        /* cancel all solo or all listen when solo control mode changes */
-
-       if (soloing()) {
-               set_solo (get_routes(), false);
-       } else if (listening()) {
-               set_listen (get_routes(), false);
-       }
+       clear_all_solo_state (get_routes());
 }
 
 /** Called when a property of one of our route groups changes */
index c2010fd5921a63b0b95a2ae8a6888283bed9bb5c..390f1de32f6dea56900a265c111d5d43c2a45040 100644 (file)
@@ -350,7 +350,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
 
                if ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) {
                        if (trk == at->remote_control_id()) {
-                               at->set_record_enabled (enabled, Controllable::UseGroup);
+                               at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
                                break;
                        }
                }
index 6b807fbf52555bd6b6757fd5407cddc90bacf4dd..67249d48b9482d0f0751bf0f1c94512e578f2864 100644 (file)
@@ -21,8 +21,9 @@
 #include "pbd/error.h"
 #include "pbd/compose.h"
 
-#include "ardour/session.h"
+#include "ardour/monitor_control.h"
 #include "ardour/route.h"
+#include "ardour/session.h"
 #include "ardour/track.h"
 
 #include "i18n.h"
@@ -33,26 +34,26 @@ using namespace ARDOUR;
 using namespace Glib;
 
 void
-Session::set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, 
-                         SessionEvent::RTeventCallback after,
-                         Controllable::GroupControlDisposition group_override)
+Session::set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
 {
-       queue_event (get_rt_event (rl, mc, after, group_override, &Session::rt_set_monitoring));
+       std::cerr << "Session::set_controls called on " << cl->size() << " controls, group = " << enum_2_string (gcd) << std::endl;
+       queue_event (get_rt_event (cl, val, gcd));
 }
 
 void
-Session::rt_set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc, Controllable::GroupControlDisposition group_override)
+Session::set_control (boost::shared_ptr<AutomationControl> ac, double val, Controllable::GroupControlDisposition gcd)
 {
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_auditioner()) {
-                       boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i);
-                       if (t) {
-                               t->set_monitoring (mc, group_override);
-                       }
-               }
-       }
+       boost::shared_ptr<ControlList> cl (new ControlList);
+       cl->push_back (ac);
+       set_controls (cl, val, gcd);
+}
 
-       set_dirty();
+void
+Session::rt_set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
+{
+       for (ControlList::iterator c = cl->begin(); c != cl->end(); ++c) {
+               (*c)->set_value (val, gcd);
+       }
 }
 
 void
@@ -73,224 +74,6 @@ Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */
        set_dirty();
 }
 
-void
-Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after,
-                   Controllable::GroupControlDisposition group_override)
-{
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
-}
-
-void
-Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_auditioner()) {
-                       (*i)->set_solo (yn, group_override);
-               }
-       }
-
-       set_dirty();
-
-       /* XXX boost::shared_ptr<RouteList>  goes out of scope here and is likley free()ed in RT context
-        * because boost's shared_ptr does reference counting and free/delete in the dtor.
-        * (this also applies to other rt_  methods here)
-        */
-}
-
-void
-Session::set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, SessionEvent::RTeventCallback after,
-                   Controllable::GroupControlDisposition group_override)
-{
-       queue_event (get_rt_event (rl, delta, upstream, after, group_override, &Session::rt_set_implicit_solo));
-}
-
-void
-Session::rt_set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, PBD::Controllable::GroupControlDisposition)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_auditioner()) {
-                       if (upstream) {
-                               std::cerr << "Changing " << (*i)->name() << " upstream by " << delta << std::endl;
-                               (*i)->mod_solo_by_others_upstream (delta);
-                       } else {
-                               std::cerr << "Changing " << (*i)->name() << " downstream by " << delta << std::endl;
-                               (*i)->mod_solo_by_others_downstream (delta);
-                       }
-               }
-       }
-
-       set_dirty();
-
-       /* XXX boost::shared_ptr<RouteList>  goes out of scope here and is likley free()ed in RT context
-        * because boost's shared_ptr does reference counting and free/delete in the dtor.
-        * (this also applies to other rt_  methods here)
-        */
-}
-
-void
-Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
-{
-       /* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
-          only going to solo one route) and keeps our ability to use get_rt_event() for the internal
-          private method.
-       */
-
-       boost::shared_ptr<RouteList> rl (new RouteList);
-       rl->push_back (r);
-
-       queue_event (get_rt_event (rl, yn, after, Controllable::NoGroup, &Session::rt_set_just_one_solo));
-}
-
-void
-Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, Controllable::GroupControlDisposition /*ignored*/)
-{
-       boost::shared_ptr<RouteList> rl = routes.reader ();
-       boost::shared_ptr<Route> r = just_one->front();
-
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_auditioner() && r != *i) {
-                       (*i)->set_solo (!yn, Controllable::NoGroup);
-               }
-       }
-
-       r->set_solo (yn, Controllable::NoGroup);
-
-       set_dirty();
-}
-
-void
-Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
-}
-
-void
-Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_auditioner()) {
-                       (*i)->set_listen (yn, group_override);
-               }
-       }
-
-       set_dirty();
-}
-
-void
-Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
-       /* Set superficial value of mute controls for automation. */
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               boost::shared_ptr<Route::MuteControllable> mc = boost::dynamic_pointer_cast<Route::MuteControllable> ((*i)->mute_control());
-               mc->set_superficial_value(yn);
-       }
-
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
-}
-
-void
-Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_monitor() && !(*i)->is_auditioner()) {
-                       (*i)->set_mute (yn, group_override);
-               }
-       }
-
-       set_dirty();
-}
-
-void
-Session::set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated));
-}
-
-void
-Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) {
-                       (*i)->set_solo_isolated (yn, group_override);
-               }
-       }
-
-       set_dirty();
-}
-
-void
-Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
-       if (!writable()) {
-               return;
-       }
-
-       /* do the non-RT part of rec-enabling first - the RT part will be done
-        * on the next process cycle. This does mean that theoretically we are
-        * doing things provisionally on the assumption that the rec-enable
-        * change will work, but this had better be a solid assumption for
-        * other reasons.
-        */
-
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if ((*i)->is_auditioner() || (*i)->record_safe ()) {
-                       continue;
-               }
-
-               boost::shared_ptr<Track> t;
-
-               if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
-                       t->prep_record_enabled (yn, group_override);
-               }
-       }
-
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enabled));
-}
-
-void
-Session::rt_set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
-               if ((*i)->is_auditioner() || (*i)->record_safe ()) {
-                       continue;
-               }
-
-               boost::shared_ptr<Track> t;
-
-               if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
-                       t->set_record_enabled (yn, group_override);
-               }
-       }
-
-       set_dirty ();
-}
-
-
-void
-Session::set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
-{
-       set_record_enabled (rl, false, after, group_override);
-       queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe));
-}
-
-void
-Session::rt_set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
-{
-       for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) {
-               if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode?
-                       continue;
-               }
-
-               boost::shared_ptr<Track> t;
-
-               if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
-                       t->set_record_safe (yn, group_override);
-               }
-       }
-
-       set_dirty ();
-}
-
 void
 Session::process_rtop (SessionEvent* ev)
 {
index 4e59da7137f2c664d5fd74aa3b43b7518b41e047..47c7885b85dde84780a04e06e9ea4f6cd8d91529 100644 (file)
@@ -1265,7 +1265,7 @@ Session::locate (framepos_t target_frame, bool with_roll, bool with_flush, bool
                                for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
                                        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
 
-                                       if (tr && tr->record_enabled ()) {
+                                       if (tr && tr->rec_enable_control()->get_value()) {
                                                // tell it we've looped, so it can deal with the record state
                                                tr->transport_looped (_transport_frame);
                                        }
index 8aebf0925901aa38ec199d16fced11c91da576ed..84a6d713497aa382a9e81b9b06302ee36ed3a41c 100644 (file)
 #include "ardour/diskstream.h"
 #include "ardour/io_processor.h"
 #include "ardour/meter.h"
+#include "ardour/monitor_control.h"
 #include "ardour/playlist.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
+#include "ardour/record_enable_control.h"
 #include "ardour/route_group_specialized.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
@@ -42,7 +44,6 @@ Track::Track (Session& sess, string name, Route::Flag flag, TrackMode mode, Data
        : Route (sess, name, flag, default_type)
         , _saved_meter_point (_meter_point)
         , _mode (mode)
-       , _monitoring (MonitorAuto)
 {
        _freeze_record.state = NoFreeze;
         _declickable = true;
@@ -62,17 +63,24 @@ Track::init ()
 
        boost::shared_ptr<Route> rp (shared_from_this());
        boost::shared_ptr<Track> rt = boost::dynamic_pointer_cast<Track> (rp);
-       _rec_enable_control = boost::shared_ptr<RecEnableControl> (new RecEnableControl(rt));
-       _rec_enable_control->set_flags (Controllable::Toggle);
-        _monitoring_control.reset (new MonitoringControllable (X_("monitoring"), rt));
 
-       /* don't add rec_enable_control to controls because we don't want it to
-        * appear as an automatable parameter
-        */
+       _record_enable_control.reset (new RecordEnableControl (_session, X_("recenable"), *this));
+       _record_enable_control->set_flags (Controllable::Toggle);
+
+       _monitoring_control.reset (new MonitorControl (_session, X_("monitoring"), *this));
+
+       _record_safe_control.reset (new AutomationControl (_session, RecSafeAutomation, ParameterDescriptor (RecSafeAutomation),
+                                                          boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (RecSafeAutomation))),
+                                                          X_("recsafe")));
+
        track_number_changed.connect_same_thread (*this, boost::bind (&Track::resync_track_name, this));
        _session.config.ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1));
 
-       return 0;
+        _monitoring_control->Changed.connect_same_thread (*this, boost::bind (&Track::monitoring_changed, this, _1, _2));
+        _record_safe_control->Changed.connect_same_thread (*this, boost::bind (&Track::record_safe_changed, this, _1, _2));
+        _record_enable_control->Changed.connect_same_thread (*this, boost::bind (&Track::record_enable_changed, this, _1, _2));
+
+        return 0;
 }
 
 void
@@ -97,9 +105,7 @@ XMLNode&
 Track::state (bool full)
 {
        XMLNode& root (Route::state (full));
-       root.add_property (X_("monitoring"), enum_2_string (_monitoring));
        root.add_property (X_("saved-meter-point"), enum_2_string (_saved_meter_point));
-       root.add_child_nocopy (_rec_enable_control->get_state());
        root.add_child_nocopy (_diskstream->get_state ());
 
        return root;
@@ -137,19 +143,13 @@ Track::set_state (const XMLNode& node, int version)
                XMLProperty const * prop;
                if (child->name() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) {
                        if (prop->value() == X_("recenable")) {
-                               _rec_enable_control->set_state (*child, version);
+                               _record_enable_control->set_state (*child, version);
                        }
                }
        }
 
        XMLProperty const * prop;
 
-       if ((prop = node.property (X_("monitoring"))) != 0) {
-               _monitoring = MonitorChoice (string_2_enum (prop->value(), _monitoring));
-       } else {
-               _monitoring = MonitorAuto;
-       }
-
        if ((prop = node.property (X_("saved-meter-point"))) != 0) {
                _saved_meter_point = MeterPoint (string_2_enum (prop->value(), _saved_meter_point));
        } else {
@@ -178,62 +178,6 @@ Track::freeze_state() const
        return _freeze_record.state;
 }
 
-Track::RecEnableControl::RecEnableControl (boost::shared_ptr<Track> t)
-       : AutomationControl (t->session(),
-                            RecEnableAutomation,
-                            ParameterDescriptor(Evoral::Parameter(RecEnableAutomation)),
-                            boost::shared_ptr<AutomationList>(),
-                            X_("recenable"))
-       , track (t)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(RecEnableAutomation)));
-       set_list (gl);
-}
-
-void
-Track::RecEnableControl::set_value (double val, Controllable::GroupControlDisposition group_override)
-{
-       if (writable()) {
-               _set_value (val, group_override);
-       }
-}
-
-void
-Track::RecEnableControl::set_value_unchecked (double val)
-{
-       if (writable()) {
-               _set_value (val, Controllable::NoGroup);
-       }
-}
-
-void
-Track::RecEnableControl::_set_value (double val, Controllable::GroupControlDisposition group_override)
-{
-       boost::shared_ptr<Track> t = track.lock ();
-       if (!t) {
-               return;
-       }
-
-       t->set_record_enabled (val >= 0.5 ? true : false, group_override);
-}
-
-double
-Track::RecEnableControl::get_value () const
-{
-       boost::shared_ptr<Track> t = track.lock ();
-       if (!t) {
-               return 0;
-       }
-
-       return (t->record_enabled() ? 1.0 : 0.0);
-}
-
-bool
-Track::record_enabled () const
-{
-       return _diskstream && _diskstream->record_enabled ();
-}
-
 bool
 Track::can_record()
 {
@@ -246,24 +190,15 @@ Track::can_record()
        return will_record;
 }
 
-void
-Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
+int
+Track::prep_record_enabled (bool yn)
 {
-       if (yn && record_safe ()) {
-           return;
-       }
-
-       if (!_session.writable()) {
-               return;
-       }
-
-       if (_freeze_record.state == Frozen) {
-               return;
+       if (yn && _record_safe_control->get_value()) {
+               return -1;
        }
 
-       if (use_group (group_override, &RouteGroup::is_recenable)) {
-               _route_group->apply (&Track::prep_record_enabled, yn, Controllable::NoGroup);
-               return;
+       if (!can_be_record_enabled()) {
+               return -1;
        }
 
        /* keep track of the meter point as it was before we rec-enabled */
@@ -288,31 +223,20 @@ Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group
                        set_meter_point (_saved_meter_point);
                }
        }
+
+       return 0;
 }
 
 void
-Track::set_record_enabled (bool yn, Controllable::GroupControlDisposition gcd)
+Track::record_enable_changed (bool, Controllable::GroupControlDisposition)
 {
-       if (_diskstream->record_safe ()) {
-           return;
-       }
-
-       if (!_session.writable()) {
-               return;
-       }
-
-       if (_freeze_record.state == Frozen) {
-               return;
-       }
-
-       if (use_group (gcd, &RouteGroup::is_recenable)) {
-               _route_group->apply (&Track::set_record_enabled, yn, Controllable::NoGroup);
-               return;
-       }
-
-       _diskstream->set_record_enabled (yn);
+       _diskstream->set_record_enabled (_record_enable_control->get_value());
+}
 
-       _rec_enable_control->Changed (true, gcd);
+void
+Track::record_safe_changed (bool, Controllable::GroupControlDisposition)
+{
+       _diskstream->set_record_safe (_record_safe_control->get_value());
 }
 
 bool
@@ -336,12 +260,7 @@ Track::set_record_safe (bool yn, Controllable::GroupControlDisposition group_ove
                return;
        }
 
-       if (use_group (group_override, &RouteGroup::is_recenable)) {
-               _route_group->apply (&Track::set_record_safe, yn, Controllable::NoGroup);
-               return;
-       }
-
-       _diskstream->set_record_safe (yn);
+       _rec_safe_control->set_value (yn, group_override);
 }
 
 void
@@ -371,7 +290,7 @@ Track::set_name (const string& str)
 {
        bool ret;
 
-       if (record_enabled() && _session.actively_recording()) {
+       if (_record_enable_control->get_value() && _session.actively_recording()) {
                /* this messes things up if done while recording */
                return false;
        }
@@ -452,7 +371,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
 
        if (!_active) {
                silence (nframes);
-               if (_meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled())) {
+               if (_meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled())) {
                        _meter->reset();
                }
                return 0;
@@ -611,8 +530,6 @@ Track::set_diskstream (boost::shared_ptr<Diskstream> ds)
 
        ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this));
        diskstream_playlist_changed ();
-       ds->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_enable_changed, this));
-       ds->RecordSafeChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_record_safe_changed, this));
        ds->SpeedChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_speed_changed, this));
        ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this));
 }
@@ -623,18 +540,6 @@ Track::diskstream_playlist_changed ()
        PlaylistChanged (); /* EMIT SIGNAL */
 }
 
-void
-Track::diskstream_record_enable_changed ()
-{
-       RecordEnableChanged (); /* EMIT SIGNAL */
-}
-
-void
-Track::diskstream_record_safe_changed ()
-{
-       RecordSafeChanged (); /* EMIT SIGNAL */
-}
-
 void
 Track::diskstream_speed_changed ()
 {
@@ -1014,12 +919,13 @@ MonitorState
 Track::monitoring_state () const
 {
        /* Explicit requests */
+       MonitorChoice m (_monitoring_control->monitoring_choice());
 
-       if (_monitoring & MonitorInput) {
+       if (m & MonitorInput) {
                return MonitoringInput;
        }
 
-       if (_monitoring & MonitorDisk) {
+       if (m & MonitorDisk) {
                return MonitoringDisk;
        }
 
@@ -1086,7 +992,7 @@ Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick)
           ditto if we are monitoring inputs.
         */
 
-        if (_have_internal_generator || monitoring_choice() == MonitorInput) {
+       if (_have_internal_generator || (_monitoring_control->monitoring_choice() == MonitorInput)) {
                 return;
         }
 
@@ -1136,22 +1042,10 @@ Track::check_initial_delay (framecnt_t nframes, framepos_t& transport_frame)
 }
 
 void
-Track::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
+Track::monitoring_changed (bool, Controllable::GroupControlDisposition)
 {
-       if (use_group (gcd, &RouteGroup::is_monitoring)) {
-               _route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
-               return;
-       }
-
-       if (mc !=  _monitoring) {
-               _monitoring = mc;
-
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-                       (*i)->monitoring_changed ();
-               }
-
-               MonitoringChanged (); /* EMIT SIGNAL */
-               _monitoring_control->Changed (true, gcd);
+       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               (*i)->monitoring_changed ();
        }
 }
 
@@ -1161,64 +1055,10 @@ Track::metering_state () const
        bool rv;
        if (_session.transport_rolling ()) {
                // audio_track.cc || midi_track.cc roll() runs meter IFF:
-               rv = _meter_point == MeterInput && (_monitoring & MonitorInput || _diskstream->record_enabled());
+               rv = _meter_point == MeterInput && ((_monitoring_control->monitoring_choice() & MonitorInput) || _diskstream->record_enabled());
        } else {
                // track no_roll() always metering if
                rv = _meter_point == MeterInput;
        }
        return rv ? MeteringInput : MeteringRoute;
 }
-
-Track::MonitoringControllable::MonitoringControllable (std::string name, boost::shared_ptr<Track> r)
-       : RouteAutomationControl (name, MonitoringAutomation, boost::shared_ptr<AutomationList>(), r)
-{
-       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MonitoringAutomation)));
-       gl->set_interpolation(Evoral::ControlList::Discrete);
-       set_list (gl);
-}
-
-void
-Track::MonitoringControllable::set_value (double val, Controllable::GroupControlDisposition gcd)
-{
-       _set_value (val, gcd);
-}
-
-void
-Track::MonitoringControllable::_set_value (double val, Controllable::GroupControlDisposition gcd)
-{
-       boost::shared_ptr<Route> r = _route.lock();
-       if (!r) {
-               return;
-       }
-
-       boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
-       if (!t) {
-               return;
-       }
-
-       int mc = (int) val;
-
-       if (mc < MonitorAuto || mc > MonitorDisk) {
-               return;
-       }
-
-       /* no group effect at present */
-
-       t->set_monitoring ((MonitorChoice) mc, gcd);
-}
-
-double
-Track::MonitoringControllable::get_value () const
-{
-       boost::shared_ptr<Route> r = _route.lock();
-       if (!r) {
-               return 0.0;
-       }
-
-       boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (r);
-       if (!t) {
-               return 0.0;
-       }
-
-       return t->monitoring_choice();
-}
index 08bb61065b2fe950d39983d63688fba87f2efbc1..0ae1c569c8a38c8a48591492e9aef1b3e5f54071 100644 (file)
@@ -754,3 +754,4 @@ ARDOUR::slider_position_to_gain_with_max (double g, double max_gain)
 extern "C" {
        void c_stacktrace() { stacktrace (cerr); }
 }
+
index d92fa67c0356d111b85e2d3855165053ae8fa434..39303fc8cadbe9818ffdadfefba64cfc2f91c882 100644 (file)
@@ -63,6 +63,7 @@ VCA::get_next_vca_number ()
 
 VCA::VCA (Session& s,  uint32_t num, const string& name)
        : Stripable (s, name)
+       , Muteable (s, name)
        , Automatable (s)
        , _number (num)
        , _gain_control (new GainControl (s, Evoral::Parameter (GainAutomation), boost::shared_ptr<AutomationList> ()))
@@ -74,8 +75,8 @@ VCA::VCA (Session& s,  uint32_t num, const string& name)
 int
 VCA::init ()
 {
-       _solo_control.reset (new VCASoloControllable (X_("solo"), shared_from_this()));
-       _mute_control.reset (new VCAMuteControllable (X_("mute"), shared_from_this()));
+       _solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
+       _mute_control.reset (new MuteControl (_session, X_("mute"), *this));
 
        add_control (_gain_control);
        add_control (_solo_control);
@@ -159,98 +160,3 @@ VCA::muted () const
 {
        return _mute_requested;
 }
-
-VCA::VCASoloControllable::VCASoloControllable (string const & name, boost::shared_ptr<VCA> vca)
-       : AutomationControl (vca->session(), Evoral::Parameter (SoloAutomation), ParameterDescriptor (Evoral::Parameter (SoloAutomation)),
-                            boost::shared_ptr<AutomationList>(), name)
-       , _vca (vca)
-{
-}
-
-void
-VCA::VCASoloControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       if (writable()) {
-               _set_value (val, gcd);
-       }
-}
-
-void
-VCA::VCASoloControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       boost::shared_ptr<VCA> vca = _vca.lock();
-       if (!vca) {
-               return;
-       }
-
-       vca->set_solo (val >= 0.5);
-
-       AutomationControl::set_value (val, gcd);
-}
-
-void
-VCA::VCASoloControllable::set_value_unchecked (double val)
-{
-       /* used only by automation playback */
-       _set_value (val, Controllable::NoGroup);
-}
-
-double
-VCA::VCASoloControllable::get_value() const
-{
-       boost::shared_ptr<VCA> vca = _vca.lock();
-       if (!vca) {
-               return 0.0;
-       }
-
-       return vca->soloed() ? 1.0 : 0.0;
-}
-
-/*----*/
-
-VCA::VCAMuteControllable::VCAMuteControllable (string const & name, boost::shared_ptr<VCA> vca)
-       : AutomationControl (vca->session(), Evoral::Parameter (MuteAutomation), ParameterDescriptor (Evoral::Parameter (MuteAutomation)),
-                            boost::shared_ptr<AutomationList>(), name)
-       , _vca (vca)
-{
-}
-
-void
-VCA::VCAMuteControllable::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       if (writable()) {
-               _set_value (val, gcd);
-       }
-}
-
-void
-VCA::VCAMuteControllable::_set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
-{
-       boost::shared_ptr<VCA> vca = _vca.lock();
-
-       if (!vca) {
-               return;
-       }
-
-       vca->set_mute (val >= 0.5);
-
-       AutomationControl::set_value (val, gcd);
-}
-
-void
-VCA::VCAMuteControllable::set_value_unchecked (double val)
-{
-       /* used only by automation playback */
-       _set_value (val, Controllable::NoGroup);
-}
-
-double
-VCA::VCAMuteControllable::get_value() const
-{
-       boost::shared_ptr<VCA> vca = _vca.lock();
-       if (!vca) {
-               return 0.0;
-       }
-
-       return vca->muted() ? 1.0 : 0.0;
-}
index 625bac8742eacb9d238f795106e3886c1b161c96..17876f889b9a4445c3052b9db98fcf247e2f95e8 100644 (file)
@@ -57,6 +57,7 @@ libardour_sources = [
         'chan_count.cc',
         'chan_mapping.cc',
         'config_text.cc',
+        'control_group.cc',
         'control_protocol_manager.cc',
         'cycle_timer.cc',
         'data_type.cc',
@@ -137,12 +138,15 @@ libardour_sources = [
         'midi_stretch.cc',
         'midi_track.cc',
         'midi_ui.cc',
+        'mididm.cc',
         'midiport_manager.cc',
         'mix.cc',
+        'monitor_control.cc',
         'monitor_processor.cc',
         'mtc_slave.cc',
-        'mididm.cc',
         'mtdm.cc',
+        'muteable.cc',
+        'mute_control.cc',
         'mute_master.cc',
         'note_fixer.cc',
         'onset_detector.cc',
@@ -154,6 +158,7 @@ libardour_sources = [
         'panner_shell.cc',
         'parameter_descriptor.cc',
         'pcm_utils.cc',
+        'phase_control.cc',
         'playlist.cc',
         'playlist_factory.cc',
         'playlist_source.cc',
@@ -170,13 +175,13 @@ libardour_sources = [
         'quantize.cc',
         'rc_configuration.cc',
         'recent_sessions.cc',
+        'record_enable_control.cc',
         'region_factory.cc',
         'resampled_source.cc',
         'region.cc',
         'return.cc',
         'reverse.cc',
         'route.cc',
-        'route_controls.cc',
         'route_graph.cc',
         'route_group.cc',
         'route_group_member.cc',
@@ -206,10 +211,14 @@ libardour_sources = [
         'session_transport.cc',
         'sidechain.cc',
         'slave.cc',
+        'slavable_automation_control.cc',
         'smf_source.cc',
         'sndfile_helpers.cc',
         'sndfileimportable.cc',
         'sndfilesource.cc',
+        'solo_control.cc',
+        'solo_isolate_control.cc',
+        'solo_safe_control.cc',
         'soundcloud_upload.cc',
         'source.cc',
         'source_factory.cc',
index 078671c91b4bf5318237437f90970e3b06f041a5..11ba979198e114e49803d83f283f2250f37137b3 100644 (file)
@@ -54,6 +54,7 @@ class LIBPBD_API Controllable : public PBD::StatefulDestructible {
        enum Flag {
                Toggle = 0x1,
                GainLike = 0x2,
+               RealTime = 0x4
        };
 
        Controllable (const std::string& name, Flag f = Flag (0));
index 5470232ad795474703572a6702b7c4adb4673a79..f413ad82d60ab2068e00d617391121ba3589f06b 100644 (file)
@@ -199,7 +199,7 @@ ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn)
        boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
 
        if (at) {
-               at->set_record_enabled (yn, Controllable::NoGroup);
+               at->rec_enable_control()->set_value (1.0, Controllable::UseGroup);
        }
 }
 
@@ -215,7 +215,7 @@ ControlProtocol::route_get_rec_enable (uint32_t table_index)
        boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
 
        if (at) {
-               return at->record_enabled ();
+               return at->rec_enable_control()->get_value();
        }
 
        return false;
@@ -248,7 +248,7 @@ ControlProtocol::route_set_gain (uint32_t table_index, float gain)
        boost::shared_ptr<Route> r = route_table[table_index];
 
        if (r != 0) {
-               r->set_gain (gain, Controllable::UseGroup);
+               r->gain_control()->set_value (gain, Controllable::UseGroup);
        }
 }
 
@@ -298,7 +298,7 @@ ControlProtocol::route_get_muted (uint32_t table_index)
                return false;
        }
 
-       return r->muted ();
+       return r->mute_control()->muted ();
 }
 
 void
@@ -311,7 +311,7 @@ ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
        boost::shared_ptr<Route> r = route_table[table_index];
 
        if (r != 0) {
-               r->set_mute (yn, Controllable::UseGroup);
+               r->mute_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
        }
 }
 
@@ -342,7 +342,7 @@ ControlProtocol::route_set_soloed (uint32_t table_index, bool yn)
        boost::shared_ptr<Route> r = route_table[table_index];
 
        if (r != 0) {
-               r->set_solo (yn, Controllable::UseGroup);
+               r->solo_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
        }
 }
 
index d08264a42d007c9314a8e0551773e730669d9f85..1df2fc48651ae2bb56d96f14054bacd2a107ce13 100644 (file)
@@ -507,7 +507,7 @@ FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
                                   single route at a time, allow the fader to
                                   modify the group, if appropriate.
                                */
-                               _current_route->set_gain (val, Controllable::UseGroup);
+                               _current_route->gain_control()->set_value (val, Controllable::UseGroup);
                        }
                }
        }
@@ -1147,7 +1147,7 @@ FaderPort::set_current_route (boost::shared_ptr<Route> r)
 
                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
                if (t) {
-                       t->RecordEnableChanged.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable, this), this);
+                       t->rec_enable_control()->Changed.connect (route_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort::map_recenable, this), this);
                }
 
                boost::shared_ptr<AutomationControl> control = _current_route->gain_control ();
@@ -1227,7 +1227,7 @@ FaderPort::map_mute ()
                if (_current_route->muted()) {
                        stop_blinking (Mute);
                        get_button (Mute).set_led_state (_output_port, true);
-               } else if (_current_route->muted_by_others()) {
+               } else if (_current_route->mute_control()->muted_by_others()) {
                        start_blinking (Mute);
                } else {
                        stop_blinking (Mute);
@@ -1252,7 +1252,7 @@ FaderPort::map_recenable ()
 {
        boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
        if (t) {
-               get_button (Rec).set_led_state (_output_port, t->record_enabled());
+               get_button (Rec).set_led_state (_output_port, t->rec_enable_control()->get_value());
        } else {
                get_button (Rec).set_led_state (_output_port, false);
        }
index bb727945049aa4a40885588ed38055187cd4d951..592b26da23068979341cba81f810458d7d5f64c0 100644 (file)
@@ -129,9 +129,9 @@ FaderPort::mute ()
                return;
        }
 
-       boost::shared_ptr<RouteList> rl (new RouteList);
-       rl->push_back (_current_route);
-       session->set_mute (rl, !_current_route->muted());
+       boost::shared_ptr<ControlList> cl (new ControlList);
+       cl->push_back (_current_route->mute_control());
+       session->set_controls (cl, !_current_route->muted(), PBD::Controllable::UseGroup);
 }
 
 void
@@ -141,14 +141,15 @@ FaderPort::solo ()
                return;
        }
 
-       boost::shared_ptr<RouteList> rl (new RouteList);
-       rl->push_back (_current_route);
+       bool yn;
 
        if (Config->get_solo_control_is_listen_control()) {
-               session->set_listen (rl, !_current_route->listening_via_monitor());
+               yn = !_current_route->listening_via_monitor();
        } else {
-               session->set_solo (rl, !_current_route->soloed());
+               yn = !_current_route->soloed();
        }
+
+       _current_route->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::UseGroup);
 }
 
 void
@@ -164,10 +165,7 @@ FaderPort::rec_enable ()
                return;
        }
 
-       boost::shared_ptr<RouteList> rl (new RouteList);
-       rl->push_back (_current_route);
-
-       session->set_record_enabled (rl, !t->record_enabled());
+       t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
 }
 
 void
index 1869d5e2317dba4114f866723d1983a40ce84b4b..025d56d25ac717a1aea3227d53ef742ff2a28a88 100644 (file)
@@ -383,7 +383,7 @@ MackieControlProtocol::save_press (Button &)
        } else {
                save_state ();
        }
-       
+
        return none;
 }
 
@@ -886,15 +886,9 @@ MackieControlProtocol::clearsolo_press (Mackie::Button&)
                access_action ("Editor/set-session-from-edit-range");
                return none;
        }
-       
-       if (session) {
-               if (session->soloing()) {
-                       session->set_solo (session->get_routes(), false);
-               } else if (session->listening()) {
-                       session->set_listen (session->get_routes(), false);
-               }
 
-               session->clear_all_solo_state (session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
+       if (session) {
+               session->clear_all_solo_state (session->get_routes()); 
        }
        return none;
 }
@@ -1063,7 +1057,7 @@ MackieControlProtocol::nudge_release (Mackie::Button&)
        _modifier_state &= ~MODIFIER_NUDGE;
 
        /* XXX these action names are stupid, because the action can affect
-        * regions, markers or the playhead depending on selection state. 
+        * regions, markers or the playhead depending on selection state.
         */
 
        if (main_modifier_state() & MODIFIER_SHIFT) {
index caa3a3bc6620e629d7f8f2fb6a882ef2c5d4a0dc..0062c3b4fb85874d9e8a17364b787bf217457af8 100644 (file)
 #include "ardour/debug.h"
 #include "ardour/midi_ui.h"
 #include "ardour/meter.h"
+#include "ardour/monitor_control.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/pannable.h"
 #include "ardour/panner.h"
 #include "ardour/panner_shell.h"
+#include "ardour/phase_control.h"
 #include "ardour/rc_configuration.h"
 #include "ardour/route.h"
 #include "ardour/session.h"
 #include "ardour/send.h"
+#include "ardour/solo_isolate_control.h"
 #include "ardour/track.h"
 #include "ardour/midi_track.h"
 #include "ardour/user_bundle.h"
@@ -302,7 +305,10 @@ void
 Strip::notify_record_enable_changed ()
 {
        if (_route && _recenable)  {
-               _surface->write (_recenable->set_state (_route->record_enabled() ? on : off));
+               boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (_route);
+               if (trk) {
+                       _surface->write (_recenable->set_state (trk->rec_enable_control()->get_value() ? on : off));
+               }
        }
 }
 
index b26c2d859791dc54031af987038b07ac1bb5f728..d758e29f03d93c6fcfef9816aa9cf2d05a0e551d 100644 (file)
@@ -974,7 +974,7 @@ OSC::routes_list (lo_message msg)
                                        || boost::dynamic_pointer_cast<MidiTrack>(r)) {
 
                                boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
-                               lo_message_add_int32 (reply, t->record_enabled());
+                               lo_message_add_int32 (reply, (int32_t) t->rec_enable_control()->get_value());
                        }
 
                        //Automatically listen to routes listed
@@ -1054,7 +1054,7 @@ OSC::route_mute (int rid, int yn)
        boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
 
        if (r) {
-               r->set_mute (yn, PBD::Controllable::NoGroup);
+               r->mute_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
        }
 
        return 0;
@@ -1068,7 +1068,7 @@ OSC::route_solo (int rid, int yn)
        boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
 
        if (r) {
-               r->solo_control()->set_value(yn, PBD::Controllable::NoGroup);
+               r->solo_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
        }
 
        return 0;
@@ -1082,7 +1082,10 @@ OSC::route_recenable (int rid, int yn)
        boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
 
        if (r) {
-               r->set_record_enabled (yn, PBD::Controllable::NoGroup);
+               boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (r);
+               if (trk) {
+                       trk->rec_enable_control()->set_value (yn, PBD::Controllable::UseGroup);
+               }
        }
 
        return 0;
@@ -1096,7 +1099,7 @@ OSC::route_set_gain_abs (int rid, float level)
        boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
 
        if (r) {
-               r->set_gain (level, PBD::Controllable::NoGroup);
+               r->gain_control()->set_value (level, PBD::Controllable::NoGroup);
        }
 
        return 0;