summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/add_route_dialog.h2
-rw-r--r--gtk2_ardour/ardour_ui.cc16
-rw-r--r--gtk2_ardour/audio_streamview.cc4
-rw-r--r--gtk2_ardour/editor_ops.cc12
-rw-r--r--gtk2_ardour/editor_routes.cc60
-rw-r--r--gtk2_ardour/gain_meter.cc10
-rw-r--r--gtk2_ardour/group_tabs.cc3
-rw-r--r--gtk2_ardour/meter_strip.cc2
-rw-r--r--gtk2_ardour/midi_streamview.cc4
-rw-r--r--gtk2_ardour/mixer_actor.cc2
-rw-r--r--gtk2_ardour/mixer_strip.cc12
-rw-r--r--gtk2_ardour/monitor_section.cc3
-rw-r--r--gtk2_ardour/route_time_axis.cc8
-rw-r--r--gtk2_ardour/route_ui.cc193
-rw-r--r--gtk2_ardour/route_ui.h2
-rw-r--r--gtk2_ardour/streamview.cc2
-rw-r--r--gtk2_ardour/time_axis_view.cc4
-rw-r--r--libs/ardour/ardour/automation_control.h52
-rw-r--r--libs/ardour/ardour/gain_control.h9
-rw-r--r--libs/ardour/ardour/midi_track.h11
-rw-r--r--libs/ardour/ardour/mute_master.h8
-rw-r--r--libs/ardour/ardour/pan_controllable.h4
-rw-r--r--libs/ardour/ardour/plugin_insert.h8
-rw-r--r--libs/ardour/ardour/route.h279
-rw-r--r--libs/ardour/ardour/route_group.h13
-rw-r--r--libs/ardour/ardour/session.h35
-rw-r--r--libs/ardour/ardour/session_event.h12
-rw-r--r--libs/ardour/ardour/stripable.h22
-rw-r--r--libs/ardour/ardour/track.h61
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/ardour/utils.h33
-rw-r--r--libs/ardour/ardour/vca.h61
-rw-r--r--libs/ardour/audio_track.cc10
-rw-r--r--libs/ardour/automation_control.cc210
-rw-r--r--libs/ardour/enums.cc15
-rw-r--r--libs/ardour/gain_control.cc42
-rw-r--r--libs/ardour/luabindings.cc8
-rw-r--r--libs/ardour/midi_track.cc80
-rw-r--r--libs/ardour/mute_master.cc4
-rw-r--r--libs/ardour/pan_controllable.cc20
-rw-r--r--libs/ardour/parameter_descriptor.cc1
-rw-r--r--libs/ardour/plugin_insert.cc32
-rw-r--r--libs/ardour/route.cc665
-rw-r--r--libs/ardour/route_controls.cc431
-rw-r--r--libs/ardour/route_graph.cc33
-rw-r--r--libs/ardour/route_group.cc115
-rw-r--r--libs/ardour/session.cc50
-rw-r--r--libs/ardour/session_midi.cc2
-rw-r--r--libs/ardour/session_rtevents.cc249
-rw-r--r--libs/ardour/session_transport.cc2
-rw-r--r--libs/ardour/track.cc246
-rw-r--r--libs/ardour/utils.cc1
-rw-r--r--libs/ardour/vca.cc100
-rw-r--r--libs/ardour/wscript13
-rw-r--r--libs/pbd/pbd/controllable.h1
-rw-r--r--libs/surfaces/control_protocol/control_protocol.cc12
-rw-r--r--libs/surfaces/faderport/faderport.cc8
-rw-r--r--libs/surfaces/faderport/operations.cc20
-rw-r--r--libs/surfaces/mackie/mcp_buttons.cc14
-rw-r--r--libs/surfaces/mackie/strip.cc8
-rw-r--r--libs/surfaces/osc/osc.cc13
61 files changed, 882 insertions, 2473 deletions
diff --git a/gtk2_ardour/add_route_dialog.h b/gtk2_ardour/add_route_dialog.h
index 51fccce4c9..f10fc11292 100644
--- a/gtk2_ardour/add_route_dialog.h
+++ b/gtk2_ardour/add_route_dialog.h
@@ -54,7 +54,7 @@ class AddRouteDialog : public ArdourDialog
MidiTrack,
MixedTrack,
AudioBus,
- MidiBus
+ MidiBus,
VCAMaster,
};
TypeWanted type_wanted() const;
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index 1a5e131d3c..65b882fe6d 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -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
}
}
diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc
index 2b0aea34cb..9351a5da1f 100644
--- a/gtk2_ardour/audio_streamview.cc
+++ b/gtk2_ardour/audio_streamview.cc
@@ -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;
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index f7617e4793..eb84428f92 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -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
diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc
index 6197e03629..9a2153f99f 100644
--- a/gtk2_ardour/editor_routes.cc
+++ b/gtk2_ardour/editor_routes.cc
@@ -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();
}
}
diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc
index b38e653bac..baf4193d27 100644
--- a/gtk2_ardour/gain_meter.cc
+++ b/gtk2_ardour/gain_meter.cc
@@ -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 ();
diff --git a/gtk2_ardour/group_tabs.cc b/gtk2_ardour/group_tabs.cc
index 0e429e562a..a930fbbce4 100644
--- a/gtk2_ardour/group_tabs.cc
+++ b/gtk2_ardour/group_tabs.cc
@@ -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);
}
}
diff --git a/gtk2_ardour/meter_strip.cc b/gtk2_ardour/meter_strip.cc
index 82acd1dad5..b324a846ff 100644
--- a/gtk2_ardour/meter_strip.cc
+++ b/gtk2_ardour/meter_strip.cc
@@ -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));
diff --git a/gtk2_ardour/midi_streamview.cc b/gtk2_ardour/midi_streamview.cc
index 9258cf027d..e369c5842d 100644
--- a/gtk2_ardour/midi_streamview.cc
+++ b/gtk2_ardour/midi_streamview.cc
@@ -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;
diff --git a/gtk2_ardour/mixer_actor.cc b/gtk2_ardour/mixer_actor.cc
index 7ffcc6f3a8..403f198d4f 100644
--- a/gtk2_ardour/mixer_actor.cc
+++ b/gtk2_ardour/mixer_actor.cc
@@ -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);
}
}
}
diff --git a/gtk2_ardour/mixer_strip.cc b/gtk2_ardour/mixer_strip.cc
index 4b4b5f1110..5c13030127 100644
--- a/gtk2_ardour/mixer_strip.cc
+++ b/gtk2_ardour/mixer_strip.cc
@@ -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));
diff --git a/gtk2_ardour/monitor_section.cc b/gtk2_ardour/monitor_section.cc
index f24cab7c3e..e14b571723 100644
--- a/gtk2_ardour/monitor_section.cc
+++ b/gtk2_ardour/monitor_section.cc
@@ -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;
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 8c475f5acc..f291af5dc5 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -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));
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index afaf4561c8..09a9dc8972 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -34,8 +34,21 @@
#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"
@@ -55,16 +68,6 @@
#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
diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h
index 788c65101b..8be2c227ff 100644
--- a/gtk2_ardour/route_ui.h
+++ b/gtk2_ardour/route_ui.h
@@ -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 ();
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 28dd1ab8f1..bf14eaf2e2 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -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());
diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc
index 6b780a7fc7..2ce40844c5 100644
--- a/gtk2_ardour/time_axis_view.cc
+++ b/gtk2_ardour/time_axis_view.cc
@@ -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;
}
diff --git a/libs/ardour/ardour/automation_control.h b/libs/ardour/ardour/automation_control.h
index 455e8891c1..d84f0a091f 100644
--- a/libs/ardour/ardour/automation_control.h
+++ b/libs/ardour/ardour/automation_control.h
@@ -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;
+
};
diff --git a/libs/ardour/ardour/gain_control.h b/libs/ardour/ardour/gain_control.h
index 4ec538e698..f68ec00452 100644
--- a/libs/ardour/ardour/gain_control.h
+++ b/libs/ardour/ardour/gain_control.h
@@ -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 */
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index ed13832360..69f4981047 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -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;
diff --git a/libs/ardour/ardour/mute_master.h b/libs/ardour/ardour/mute_master.h
index 14597cb56b..d147a58771 100644
--- a/libs/ardour/ardour/mute_master.h
+++ b/libs/ardour/ardour/mute_master.h
@@ -20,12 +20,15 @@
#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;
diff --git a/libs/ardour/ardour/pan_controllable.h b/libs/ardour/ardour/pan_controllable.h
index 85a4efe2fc..26f0707ff7 100644
--- a/libs/ardour/ardour/pan_controllable.h
+++ b/libs/ardour/ardour/pan_controllable.h
@@ -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
diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h
index 4b5f38964a..70bbd76a71 100644
--- a/libs/ardour/ardour/plugin_insert.h
+++ b/libs/ardour/ardour/plugin_insert.h
@@ -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;
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 9abe56afcb..6c0380963d 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -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>
@@ -46,12 +45,18 @@
#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
diff --git a/libs/ardour/ardour/route_group.h b/libs/ardour/ardour/route_group.h
index 95affaeaf5..feeac6a467 100644
--- a/libs/ardour/ardour/route_group.h
+++ b/libs/ardour/ardour/route_group.h
@@ -29,10 +29,12 @@
#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 */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 18507ee5d9..786751dea5 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -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;
diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h
index cca7f1274e..8bb160b90e 100644
--- a/libs/ardour/ardour/session_event.h
+++ b/libs/ardour/ardour/session_event.h
@@ -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;
diff --git a/libs/ardour/ardour/stripable.h b/libs/ardour/ardour/stripable.h
index e97fe79103..f68cb07b91 100644
--- a/libs/ardour/ardour/stripable.h
+++ b/libs/ardour/ardour/stripable.h
@@ -26,13 +26,19 @@
#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;
};
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index b378021bce..bb955265c8 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -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);
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 626109557f..bd866141d5 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -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;
diff --git a/libs/ardour/ardour/utils.h b/libs/ardour/ardour/utils.h
index f3767d471a..1dc7c2baf4 100644
--- a/libs/ardour/ardour/utils.h
+++ b/libs/ardour/ardour/utils.h
@@ -28,19 +28,26 @@
#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__ */
-
diff --git a/libs/ardour/ardour/vca.h b/libs/ardour/ardour/vca.h
index dc48ffa480..1c247c0e92 100644
--- a/libs/ardour/ardour/vca.h
+++ b/libs/ardour/ardour/vca.h
@@ -27,14 +27,19 @@
#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;
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 579b0064bc..2ed200d6f6 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -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;
diff --git a/libs/ardour/automation_control.cc b/libs/ardour/automation_control.cc
index b00c615625..7efaa07f23 100644
--- a/libs/ardour/automation_control.cc
+++ b/libs/ardour/automation_control.cc
@@ -20,14 +20,17 @@
#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;
}
diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc
index b7e77952cb..85634640b9 100644
--- a/libs/ardour/enums.cc
+++ b/libs/ardour/enums.cc
@@ -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);
diff --git a/libs/ardour/gain_control.cc b/libs/ardour/gain_control.cc
index 456fd9b248..3cb8230198 100644
--- a/libs/ardour/gain_control.cc
+++ b/libs/ardour/gain_control.cc
@@ -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 ();
}
@@ -120,6 +105,23 @@ GainControl::get_user_string () const
}
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)
{
/* Master WRITE lock must be held */
diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc
index 23dc0d26f0..28214b7e62 100644
--- a/libs/ardour/luabindings.cc
+++ b/libs/ardour/luabindings.cc
@@ -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)
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 9a38f9f05a..7c1b3a9399 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -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 ();
}
}
diff --git a/libs/ardour/mute_master.cc b/libs/ardour/mute_master.cc
index dc40d1fd6b..6817374dc7 100644
--- a/libs/ardour/mute_master.cc
+++ b/libs/ardour/mute_master.cc
@@ -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;
diff --git a/libs/ardour/pan_controllable.cc b/libs/ardour/pan_controllable.cc
index a6a96787a2..624f397b77 100644
--- a/libs/ardour/pan_controllable.cc
+++ b/libs/ardour/pan_controllable.cc
@@ -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);
}
}
diff --git a/libs/ardour/parameter_descriptor.cc b/libs/ardour/parameter_descriptor.cc
index 9fb6b89a0c..e28dbecd35 100644
--- a/libs/ardour/parameter_descriptor.cc
+++ b/libs/ardour/parameter_descriptor.cc
@@ -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;
diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc
index 451f801f1d..b0d4d2f9ac 100644
--- a/libs/ardour/plugin_insert.cc
+++ b/libs/ardour/plugin_insert.cc
@@ -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&
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 8207176729..7a3d37d2a7 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -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);
@@ -399,82 +399,10 @@ Route::ensure_track_or_route_name(string name, Session &session)
}
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
index ad5408d06d..0000000000
--- a/libs/ardour/route_controls.cc
+++ /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;
-}
diff --git a/libs/ardour/route_graph.cc b/libs/ardour/route_graph.cc
index 910141a440..70b9b48d6f 100644
--- a/libs/ardour/route_graph.cc
+++ b/libs/ardour/route_graph.cc
@@ -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 ();
}
}
}
diff --git a/libs/ardour/route_group.cc b/libs/ardour/route_group.cc
index b482bb85d3..137e2c4734 100644
--- a/libs/ardour/route_group.cc
+++ b/libs/ardour/route_group.cc
@@ -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);
+}
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index ee70d2a40f..7658ff270d 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -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 */
diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc
index c2010fd592..390f1de32f 100644
--- a/libs/ardour/session_midi.cc
+++ b/libs/ardour/session_midi.cc
@@ -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;
}
}
diff --git a/libs/ardour/session_rtevents.cc b/libs/ardour/session_rtevents.cc
index 6b807fbf52..67249d48b9 100644
--- a/libs/ardour/session_rtevents.cc
+++ b/libs/ardour/session_rtevents.cc
@@ -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
@@ -74,224 +75,6 @@ Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */
}
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)
{
ev->rt_slot ();
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 4e59da7137..47c7885b85 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -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);
}
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 8aebf09259..84a6d71349 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -23,9 +23,11 @@
#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));
}
@@ -624,18 +541,6 @@ Track::diskstream_playlist_changed ()
}
void
-Track::diskstream_record_enable_changed ()
-{
- RecordEnableChanged (); /* EMIT SIGNAL */
-}
-
-void
-Track::diskstream_record_safe_changed ()
-{
- RecordSafeChanged (); /* EMIT SIGNAL */
-}
-
-void
Track::diskstream_speed_changed ()
{
SpeedChanged (); /* EMIT SIGNAL */
@@ -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();
-}
diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc
index 08bb61065b..0ae1c569c8 100644
--- a/libs/ardour/utils.cc
+++ b/libs/ardour/utils.cc
@@ -754,3 +754,4 @@ ARDOUR::slider_position_to_gain_with_max (double g, double max_gain)
extern "C" {
void c_stacktrace() { stacktrace (cerr); }
}
+
diff --git a/libs/ardour/vca.cc b/libs/ardour/vca.cc
index d92fa67c03..39303fc8ca 100644
--- a/libs/ardour/vca.cc
+++ b/libs/ardour/vca.cc
@@ -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;
-}
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 625bac8742..17876f889b 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -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',
diff --git a/libs/pbd/pbd/controllable.h b/libs/pbd/pbd/controllable.h
index 078671c91b..11ba979198 100644
--- a/libs/pbd/pbd/controllable.h
+++ b/libs/pbd/pbd/controllable.h
@@ -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));
diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc
index 5470232ad7..f413ad82d6 100644
--- a/libs/surfaces/control_protocol/control_protocol.cc
+++ b/libs/surfaces/control_protocol/control_protocol.cc
@@ -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);
}
}
diff --git a/libs/surfaces/faderport/faderport.cc b/libs/surfaces/faderport/faderport.cc
index d08264a42d..1df2fc4865 100644
--- a/libs/surfaces/faderport/faderport.cc
+++ b/libs/surfaces/faderport/faderport.cc
@@ -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);
}
diff --git a/libs/surfaces/faderport/operations.cc b/libs/surfaces/faderport/operations.cc
index bb72794504..592b26da23 100644
--- a/libs/surfaces/faderport/operations.cc
+++ b/libs/surfaces/faderport/operations.cc
@@ -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
diff --git a/libs/surfaces/mackie/mcp_buttons.cc b/libs/surfaces/mackie/mcp_buttons.cc
index 1869d5e231..025d56d25a 100644
--- a/libs/surfaces/mackie/mcp_buttons.cc
+++ b/libs/surfaces/mackie/mcp_buttons.cc
@@ -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) {
diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc
index caa3a3bc66..0062c3b4fb 100644
--- a/libs/surfaces/mackie/strip.cc
+++ b/libs/surfaces/mackie/strip.cc
@@ -37,14 +37,17 @@
#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));
+ }
}
}
diff --git a/libs/surfaces/osc/osc.cc b/libs/surfaces/osc/osc.cc
index b26c2d8597..d758e29f03 100644
--- a/libs/surfaces/osc/osc.cc
+++ b/libs/surfaces/osc/osc.cc
@@ -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;