mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-09 16:24:57 +01:00
universal change in the design of the way Route/Track controls are designed and used. The controls now own their own state, rather than proxy for state in their owners.
Massive changes all over the code to accomodate this. Many things are not finished. Consider this a backup safety commit
This commit is contained in:
parent
c107f1ab56
commit
653ae4acd6
61 changed files with 889 additions and 2480 deletions
|
|
@ -54,7 +54,7 @@ class AddRouteDialog : public ArdourDialog
|
||||||
MidiTrack,
|
MidiTrack,
|
||||||
MixedTrack,
|
MixedTrack,
|
||||||
AudioBus,
|
AudioBus,
|
||||||
MidiBus
|
MidiBus,
|
||||||
VCAMaster,
|
VCAMaster,
|
||||||
};
|
};
|
||||||
TypeWanted type_wanted() const;
|
TypeWanted type_wanted() const;
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,9 @@
|
||||||
#include "ardour/source_factory.h"
|
#include "ardour/source_factory.h"
|
||||||
#include "ardour/slave.h"
|
#include "ardour/slave.h"
|
||||||
#include "ardour/system_exec.h"
|
#include "ardour/system_exec.h"
|
||||||
|
#include "ardour/track.h"
|
||||||
#include "ardour/vca_manager.h"
|
#include "ardour/vca_manager.h"
|
||||||
|
#include "ardour/utils.h"
|
||||||
|
|
||||||
#include "LuaBridge/LuaBridge.h"
|
#include "LuaBridge/LuaBridge.h"
|
||||||
|
|
||||||
|
|
@ -1570,7 +1572,7 @@ void
|
||||||
ARDOUR_UI::count_recenabled_streams (Route& route)
|
ARDOUR_UI::count_recenabled_streams (Route& route)
|
||||||
{
|
{
|
||||||
Track* track = dynamic_cast<Track*>(&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();
|
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);
|
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
|
||||||
assert (t);
|
assert (t);
|
||||||
|
|
||||||
if (t->record_enabled()) {
|
if (t->rec_enable_control()->get_value()) {
|
||||||
none_record_enabled = false;
|
none_record_enabled = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (none_record_enabled) {
|
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;
|
return none_record_enabled;
|
||||||
|
|
@ -2388,7 +2390,7 @@ ARDOUR_UI::toggle_record_enable (uint32_t rid)
|
||||||
boost::shared_ptr<Track> t;
|
boost::shared_ptr<Track> t;
|
||||||
|
|
||||||
if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
|
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 ()
|
ARDOUR_UI::cancel_solo ()
|
||||||
{
|
{
|
||||||
if (_session) {
|
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
|
_session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ AudioStreamView::setup_rec_box ()
|
||||||
|
|
||||||
if (!rec_active &&
|
if (!rec_active &&
|
||||||
_trackview.session()->record_status() == Session::Recording &&
|
_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()) {
|
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 */
|
/* 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 &&
|
} else if (rec_active &&
|
||||||
(_trackview.session()->record_status() != Session::Recording ||
|
(_trackview.session()->record_status() != Session::Recording ||
|
||||||
!_trackview.track()->record_enabled())) {
|
!_trackview.track()->rec_enable_control()->get_value())) {
|
||||||
screen_update_connection.disconnect();
|
screen_update_connection.disconnect();
|
||||||
rec_active = false;
|
rec_active = false;
|
||||||
rec_updating = false;
|
rec_updating = false;
|
||||||
|
|
|
||||||
|
|
@ -5699,11 +5699,11 @@ Editor::toggle_record_enable ()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
new_state = !rtav->track()->record_enabled();
|
new_state = !rtav->track()->rec_enable_control()->get_value();
|
||||||
first = false;
|
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 new_state = false;
|
||||||
bool first = true;
|
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) {
|
for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
|
||||||
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
|
||||||
|
|
@ -5726,10 +5726,10 @@ Editor::toggle_solo ()
|
||||||
first = false;
|
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
|
void
|
||||||
|
|
@ -5754,7 +5754,7 @@ Editor::toggle_mute ()
|
||||||
rl->push_back (rtav->route());
|
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
|
void
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
#include "ardour/midi_track.h"
|
#include "ardour/midi_track.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/session.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_multi.h"
|
||||||
#include "gtkmm2ext/cell_renderer_pixbuf_toggle.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);
|
RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||||
|
|
||||||
if (rtv && rtv->track()) {
|
if (rtv && rtv->track()) {
|
||||||
DisplaySuspender ds;
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
|
||||||
// TODO check rec-safe and ...
|
// TODO check rec-safe and ...
|
||||||
rl->push_back (rtv->route());
|
_session->set_control (rtv->track()->rec_enable_control(), !rtv->track()->rec_enable_control()->get_value(), Controllable::UseGroup);
|
||||||
_session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,9 +454,7 @@ EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
|
||||||
RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||||
|
|
||||||
if (rtv != 0) {
|
if (rtv != 0) {
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
_session->set_control (rtv->route()->mute_control(), rtv->route()->mute_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
|
||||||
rl->push_back (rtv->route());
|
|
||||||
_session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -471,13 +468,15 @@ EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
|
||||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||||
|
|
||||||
if (rtv != 0) {
|
if (rtv != 0) {
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
bool newval;
|
||||||
rl->push_back (rtv->route());
|
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
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 {
|
} 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);
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||||
|
|
||||||
if (rtv) {
|
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);
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
|
||||||
|
|
||||||
if (rtv) {
|
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.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
|
||||||
row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
|
row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
|
||||||
row[_columns.solo_visible] = !(*x)->route()->is_master ();
|
row[_columns.solo_visible] = !(*x)->route()->is_master ();
|
||||||
row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
|
row[_columns.solo_isolate_state] = (*x)->route()->solo_isolate_control()->solo_isolated();
|
||||||
row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
|
row[_columns.solo_safe_state] = (*x)->route()->solo_safe_control()->solo_safe();
|
||||||
row[_columns.name_editable] = true;
|
row[_columns.name_editable] = true;
|
||||||
|
|
||||||
boost::weak_ptr<Route> wr ((*x)->route());
|
boost::weak_ptr<Route> wr ((*x)->route());
|
||||||
|
|
@ -745,8 +744,8 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
|
||||||
|
|
||||||
if ((*x)->is_track()) {
|
if ((*x)->is_track()) {
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
|
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->rec_enable_control()->Changed.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_safe_control()->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*x)->is_midi_track()) {
|
if ((*x)->is_midi_track()) {
|
||||||
|
|
@ -1280,25 +1279,27 @@ EditorRoutes::key_press (GdkEventKey* ev)
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
if (get_relevant_routes (rl)) {
|
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;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if (get_relevant_routes (rl)) {
|
if (get_relevant_routes (rl)) {
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
_session->set_controls (route_list_to_control_list (rl, &Route::solo_control), rl->front()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
|
||||||
_session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
|
|
||||||
} else {
|
|
||||||
_session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
if (get_relevant_routes (rl)) {
|
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;
|
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_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.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
|
||||||
(*i)[_columns.active] = route->active ();
|
(*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);
|
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) {
|
if (_session->record_status() == Session::Recording) {
|
||||||
(*i)[_columns.rec_state] = 1;
|
(*i)[_columns.rec_state] = 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1660,8 +1664,8 @@ EditorRoutes::idle_update_mute_rec_solo_etc()
|
||||||
(*i)[_columns.rec_state] = 0;
|
(*i)[_columns.rec_state] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*i)[_columns.rec_safe] = route->record_safe () ? 1 : 0;
|
(*i)[_columns.rec_safe] = !trk->rec_safe_control()->get_value();
|
||||||
(*i)[_columns.name_editable] = !route->record_enabled ();
|
(*i)[_columns.name_editable] = !trk->rec_enable_control()->get_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -479,10 +479,10 @@ GainMeterBase::gain_activated ()
|
||||||
/* clamp to displayable values */
|
/* clamp to displayable values */
|
||||||
if (_data_type == DataType::AUDIO) {
|
if (_data_type == DataType::AUDIO) {
|
||||||
f = min (f, 6.0f);
|
f = min (f, 6.0f);
|
||||||
_control->set_value (dB_to_coefficient(f), Controllable::NoGroup);
|
_control->set_value (dB_to_coefficient(f), Controllable::UseGroup);
|
||||||
} else {
|
} else {
|
||||||
f = min (fabs (f), 2.0f);
|
f = min (fabs (f), 2.0f);
|
||||||
_control->set_value (f, Controllable::NoGroup);
|
_control->set_value (f, Controllable::UseGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gain_display.has_focus()) {
|
if (gain_display.has_focus()) {
|
||||||
|
|
@ -541,11 +541,7 @@ GainMeterBase::fader_moved ()
|
||||||
value = gain_adjustment.get_value();
|
value = gain_adjustment.get_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_route && _control == _route->gain_control()) {
|
_control->set_value (value, Controllable::UseGroup);
|
||||||
_route->set_gain (value, Controllable::UseGroup);
|
|
||||||
} else {
|
|
||||||
_control->set_value (value, Controllable::NoGroup);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show_gain ();
|
show_gain ();
|
||||||
|
|
|
||||||
|
|
@ -366,7 +366,8 @@ GroupTabs::new_from_rec_enabled ()
|
||||||
RouteList rec_enabled;
|
RouteList rec_enabled;
|
||||||
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
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);
|
rec_enabled.push_back (*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -366,7 +366,7 @@ MeterStrip::set_button_names()
|
||||||
{
|
{
|
||||||
mute_button->set_text (S_("Mute|M"));
|
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));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
|
||||||
} else {
|
} else {
|
||||||
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
||||||
|
|
|
||||||
|
|
@ -440,7 +440,7 @@ MidiStreamView::setup_rec_box ()
|
||||||
|
|
||||||
if (!rec_active &&
|
if (!rec_active &&
|
||||||
_trackview.session()->record_status() == Session::Recording &&
|
_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()) {
|
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 &&
|
} else if (rec_active &&
|
||||||
(_trackview.session()->record_status() != Session::Recording ||
|
(_trackview.session()->record_status() != Session::Recording ||
|
||||||
!_trackview.track()->record_enabled())) {
|
!_trackview.track()->rec_enable_control()->get_value())) {
|
||||||
screen_update_connection.disconnect();
|
screen_update_connection.disconnect();
|
||||||
rec_active = false;
|
rec_active = false;
|
||||||
rec_updating = false;
|
rec_updating = false;
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ printf("setting gain to unity (?)");
|
||||||
BOOST_FOREACH(RouteUI* r, _route_targets) {
|
BOOST_FOREACH(RouteUI* r, _route_targets) {
|
||||||
boost::shared_ptr<Route> rp = r->route();
|
boost::shared_ptr<Route> rp = r->route();
|
||||||
if (rp) {
|
if (rp) {
|
||||||
rp->set_gain (1.0, Controllable::NoGroup);
|
rp->gain_control()->set_value (1.0, Controllable::NoGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -950,7 +950,7 @@ MixerStrip::input_press (GdkEventButton *ev)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_session->actively_recording() && _route->record_enabled())
|
if (_session->actively_recording() && is_track() && track()->rec_enable_control()->get_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
switch (ev->button) {
|
switch (ev->button) {
|
||||||
|
|
@ -1665,7 +1665,7 @@ MixerStrip::name_button_button_press (GdkEventButton* ev)
|
||||||
list_route_operations ();
|
list_route_operations ();
|
||||||
|
|
||||||
/* do not allow rename if the track is record-enabled */
|
/* 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);
|
route_ops_menu->popup (1, ev->time);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1681,7 +1681,7 @@ MixerStrip::name_button_button_release (GdkEventButton* ev)
|
||||||
list_route_operations ();
|
list_route_operations ();
|
||||||
|
|
||||||
/* do not allow rename if the track is record-enabled */
|
/* 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);
|
route_ops_menu->popup (1, ev->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1695,7 +1695,7 @@ MixerStrip::number_button_button_press (GdkEventButton* ev)
|
||||||
list_route_operations ();
|
list_route_operations ();
|
||||||
|
|
||||||
/* do not allow rename if the track is record-enabled */
|
/* 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);
|
route_ops_menu->popup (1, ev->time);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -2141,7 +2141,7 @@ MixerStrip::set_button_names ()
|
||||||
monitor_section_button->set_text (_("Mon"));
|
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));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
|
||||||
} else {
|
} else {
|
||||||
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
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"));
|
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));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
|
||||||
} else {
|
} else {
|
||||||
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include "ardour/monitor_processor.h"
|
#include "ardour/monitor_processor.h"
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
|
#include "ardour/solo_isolate_control.h"
|
||||||
#include "ardour/user_bundle.h"
|
#include "ardour/user_bundle.h"
|
||||||
#include "ardour/plugin_manager.h"
|
#include "ardour/plugin_manager.h"
|
||||||
|
|
||||||
|
|
@ -1246,7 +1247,7 @@ MonitorSection::cancel_isolate (GdkEventButton*)
|
||||||
{
|
{
|
||||||
if (_session) {
|
if (_session) {
|
||||||
boost::shared_ptr<RouteList> rl (_session->get_routes ());
|
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;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -2493,7 +2493,11 @@ RouteTimeAxisView::can_edit_name () const
|
||||||
{
|
{
|
||||||
/* we do not allow track name changes if it is record enabled
|
/* 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
|
void
|
||||||
|
|
@ -2724,7 +2728,7 @@ RouteTimeAxisView::remove_underlay (StreamView* v)
|
||||||
void
|
void
|
||||||
RouteTimeAxisView::set_button_names ()
|
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));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
|
||||||
} else {
|
} else {
|
||||||
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
solo_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,21 @@
|
||||||
|
|
||||||
#include "ardour/dB.h"
|
#include "ardour/dB.h"
|
||||||
#include "ardour/route_group.h"
|
#include "ardour/route_group.h"
|
||||||
|
#include "ardour/solo_isolate_control.h"
|
||||||
#include "ardour/vca.h"
|
#include "ardour/vca.h"
|
||||||
#include "ardour/vca_manager.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 "ardour_ui.h"
|
||||||
#include "editor.h"
|
#include "editor.h"
|
||||||
|
|
@ -55,16 +68,6 @@
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
#include "ui_config.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"
|
#include "i18n.h"
|
||||||
using namespace Gtk;
|
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_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_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());
|
_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()) {
|
if (is_track()) {
|
||||||
track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
|
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()) {
|
if (_session->writable() && is_track()) {
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
|
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->rec_enable_control()->Changed.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_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->show();
|
||||||
rec_enable_button->set_controllable (t->rec_enable_control());
|
rec_enable_button->set_controllable (t->rec_enable_control());
|
||||||
|
|
@ -309,7 +309,7 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
|
||||||
|
|
||||||
if (is_track()) {
|
if (is_track()) {
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
|
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 ();
|
update_monitoring_display ();
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +383,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||||
if (Keyboard::is_button2_event (ev)) {
|
if (Keyboard::is_button2_event (ev)) {
|
||||||
// button2-click is "momentary"
|
// 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)) {
|
if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
|
||||||
|
|
@ -415,7 +415,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySuspender ds;
|
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)) {
|
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
|
||||||
|
|
||||||
|
|
@ -444,7 +444,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySuspender ds;
|
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 {
|
} else {
|
||||||
|
|
@ -458,7 +458,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||||
_mute_release->routes = rl;
|
_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){
|
if (_mute_release){
|
||||||
DisplaySuspender ds;
|
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;
|
delete _mute_release;
|
||||||
_mute_release = 0;
|
_mute_release = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -572,11 +572,7 @@ RouteUI::solo_press(GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
_session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
|
||||||
_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
|
} 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 */
|
/* ??? we need a just_one_listen() method */
|
||||||
} else {
|
} else {
|
||||||
DisplaySuspender ds;
|
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)) {
|
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
|
||||||
|
|
||||||
// shift-click: toggle solo isolated status
|
// 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;
|
delete _solo_release;
|
||||||
_solo_release = 0;
|
_solo_release = 0;
|
||||||
|
|
||||||
|
|
@ -647,11 +645,7 @@ RouteUI::solo_press(GdkEventButton* ev)
|
||||||
|
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
|
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
_session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _solo_release;
|
delete _solo_release;
|
||||||
|
|
@ -669,11 +663,7 @@ RouteUI::solo_press(GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
_session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::UseGroup);
|
||||||
_session->set_listen (rl, !_route->listening_via_monitor());
|
|
||||||
} else {
|
|
||||||
_session->set_solo (rl, !_route->self_soloed());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -690,11 +680,7 @@ RouteUI::solo_release (GdkEventButton* /*ev*/)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
_session->set_controls (route_list_to_control_list (_solo_release->routes, &Route::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
|
||||||
_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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete _solo_release;
|
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))) {
|
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
|
||||||
|
|
||||||
DisplaySuspender ds;
|
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)) {
|
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
|
||||||
|
|
||||||
|
|
@ -757,7 +743,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
|
||||||
rl->push_back (_route);
|
rl->push_back (_route);
|
||||||
|
|
||||||
DisplaySuspender ds;
|
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)) {
|
} else if (Keyboard::is_context_menu_event (ev)) {
|
||||||
|
|
@ -766,10 +752,8 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
boost::shared_ptr<Track> trk = track();
|
||||||
rl->push_back (route());
|
_session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
|
||||||
DisplaySuspender ds;
|
|
||||||
_session->set_record_enabled (rl, !_route->record_enabled());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -777,7 +761,7 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteUI::monitoring_changed ()
|
RouteUI::monitoring_changed (bool, Controllable::GroupControlDisposition)
|
||||||
{
|
{
|
||||||
update_monitoring_display ();
|
update_monitoring_display ();
|
||||||
}
|
}
|
||||||
|
|
@ -797,7 +781,7 @@ RouteUI::update_monitoring_display ()
|
||||||
|
|
||||||
MonitorState ms = t->monitoring_state();
|
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);
|
monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
} else {
|
} else {
|
||||||
if (ms & MonitoringInput) {
|
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);
|
monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
} else {
|
} else {
|
||||||
if (ms & MonitoringDisk) {
|
if (ms & MonitoringDisk) {
|
||||||
|
|
@ -863,8 +847,8 @@ RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
|
||||||
signal together, which requires yet more buffers.
|
signal together, which requires yet more buffers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (t->monitoring_choice() & monitor_choice) {
|
if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
|
||||||
mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
|
mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
|
||||||
} else {
|
} else {
|
||||||
/* this line will change when the options are non-orthogonal */
|
/* this line will change when the options are non-orthogonal */
|
||||||
// mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
|
// mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
|
||||||
|
|
@ -887,7 +871,7 @@ RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
|
||||||
}
|
}
|
||||||
|
|
||||||
DisplaySuspender ds;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -912,7 +896,9 @@ RouteUI::build_record_menu ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step_edit_item) {
|
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());
|
step_edit_item->set_active (midi_track()->step_editing());
|
||||||
}
|
}
|
||||||
if (rec_safe_item) {
|
if (rec_safe_item) {
|
||||||
|
|
@ -924,7 +910,7 @@ RouteUI::build_record_menu ()
|
||||||
void
|
void
|
||||||
RouteUI::toggle_step_edit ()
|
RouteUI::toggle_step_edit ()
|
||||||
{
|
{
|
||||||
if (!is_midi_track() || _route->record_enabled()) {
|
if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1168,7 +1154,7 @@ RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
|
||||||
return Gtkmm2ext::Off;
|
return Gtkmm2ext::Off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->solo_isolated()) {
|
if (r->solo_isolate_control()->solo_isolated()) {
|
||||||
return Gtkmm2ext::ExplicitActive;
|
return Gtkmm2ext::ExplicitActive;
|
||||||
} else {
|
} else {
|
||||||
return Gtkmm2ext::Off;
|
return Gtkmm2ext::Off;
|
||||||
|
|
@ -1182,7 +1168,7 @@ RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
|
||||||
return Gtkmm2ext::Off;
|
return Gtkmm2ext::Off;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->solo_safe()) {
|
if (r->solo_safe_control()->solo_safe()) {
|
||||||
return Gtkmm2ext::ExplicitActive;
|
return Gtkmm2ext::ExplicitActive;
|
||||||
} else {
|
} else {
|
||||||
return Gtkmm2ext::Off;
|
return Gtkmm2ext::Off;
|
||||||
|
|
@ -1192,13 +1178,13 @@ RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
|
||||||
void
|
void
|
||||||
RouteUI::update_solo_display ()
|
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) {
|
if (solo_safe_check && solo_safe_check->get_active() != yn) {
|
||||||
solo_safe_check->set_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) {
|
if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
|
||||||
solo_isolated_check->set_active (yn);
|
solo_isolated_check->set_active (yn);
|
||||||
|
|
@ -1207,7 +1193,7 @@ RouteUI::update_solo_display ()
|
||||||
set_button_names ();
|
set_button_names ();
|
||||||
|
|
||||||
if (solo_isolated_led) {
|
if (solo_isolated_led) {
|
||||||
if (_route->solo_isolated()) {
|
if (_route->solo_isolate_control()->solo_isolated()) {
|
||||||
solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
|
solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
} else {
|
} else {
|
||||||
solo_isolated_led->unset_active_state ();
|
solo_isolated_led->unset_active_state ();
|
||||||
|
|
@ -1215,7 +1201,7 @@ RouteUI::update_solo_display ()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (solo_safe_led) {
|
if (solo_safe_led) {
|
||||||
if (_route->solo_safe()) {
|
if (_route->solo_safe_control()->solo_safe()) {
|
||||||
solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
|
solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
} else {
|
} else {
|
||||||
solo_safe_led->unset_active_state ();
|
solo_safe_led->unset_active_state ();
|
||||||
|
|
@ -1248,7 +1234,7 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
|
||||||
if (r->muted ()) {
|
if (r->muted ()) {
|
||||||
/* full mute */
|
/* full mute */
|
||||||
return Gtkmm2ext::ExplicitActive;
|
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 */
|
/* this will reflect both solo mutes AND master mutes */
|
||||||
return Gtkmm2ext::ImplicitActive;
|
return Gtkmm2ext::ImplicitActive;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1261,10 +1247,11 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
|
||||||
if (r->muted()) {
|
if (r->muted()) {
|
||||||
/* full mute */
|
/* full mute */
|
||||||
return Gtkmm2ext::ExplicitActive;
|
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
|
/* note the direct use of MuteMaster API here. We are
|
||||||
not interested in showing
|
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;
|
return Gtkmm2ext::ImplicitActive;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1335,11 +1322,16 @@ RouteUI::blink_rec_display (bool blinkOn)
|
||||||
if (!rec_enable_button || !_route) {
|
if (!rec_enable_button || !_route) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
|
if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_route->record_enabled()) {
|
if (!is_track()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track()->rec_enable_control()->get_value()) {
|
||||||
switch (_session->record_status ()) {
|
switch (_session->record_status ()) {
|
||||||
case Session::Recording:
|
case Session::Recording:
|
||||||
rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
|
rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
|
|
@ -1347,12 +1339,12 @@ RouteUI::blink_rec_display (bool blinkOn)
|
||||||
|
|
||||||
case Session::Disabled:
|
case Session::Disabled:
|
||||||
case Session::Enabled:
|
case Session::Enabled:
|
||||||
if ( UIConfiguration::instance().get_blink_rec_arm() )
|
if (UIConfiguration::instance().get_blink_rec_arm()) {
|
||||||
rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
|
rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
|
||||||
else
|
} else {
|
||||||
rec_enable_button->set_active_state ( ImplicitActive );
|
rec_enable_button->set_active_state ( ImplicitActive );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (step_edit_item) {
|
if (step_edit_item) {
|
||||||
|
|
@ -1381,14 +1373,14 @@ RouteUI::build_solo_menu (void)
|
||||||
Gtk::CheckMenuItem* check;
|
Gtk::CheckMenuItem* check;
|
||||||
|
|
||||||
check = new Gtk::CheckMenuItem(_("Solo Isolate"));
|
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));
|
check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
|
||||||
items.push_back (CheckMenuElem(*check));
|
items.push_back (CheckMenuElem(*check));
|
||||||
solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
|
solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
|
||||||
check->show_all();
|
check->show_all();
|
||||||
|
|
||||||
check = new Gtk::CheckMenuItem(_("Solo Safe"));
|
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));
|
check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
|
||||||
items.push_back (CheckMenuElem(*check));
|
items.push_back (CheckMenuElem(*check));
|
||||||
solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
|
solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
|
||||||
|
|
@ -1442,16 +1434,16 @@ RouteUI::build_mute_menu(void)
|
||||||
void
|
void
|
||||||
RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
|
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
|
void
|
||||||
RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
|
RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
|
||||||
{
|
{
|
||||||
if (check->get_active()) {
|
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 {
|
} 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)
|
ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
|
||||||
|
|
||||||
bool yn;
|
bool yn;
|
||||||
MuteMaster::MutePoint current = _route->mute_points ();
|
MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
|
||||||
|
|
||||||
yn = (current & MuteMaster::PreFader);
|
yn = (current & MuteMaster::PreFader);
|
||||||
|
|
||||||
|
|
@ -1496,7 +1488,7 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool view = solo_isolated_led->active_state();
|
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 */
|
/* called BEFORE the view has changed */
|
||||||
|
|
||||||
|
|
@ -1506,11 +1498,11 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
|
||||||
if (model) {
|
if (model) {
|
||||||
/* disable isolate for all routes */
|
/* disable isolate for all routes */
|
||||||
DisplaySuspender ds;
|
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 {
|
} else {
|
||||||
/* enable isolate for all routes */
|
/* enable isolate for all routes */
|
||||||
DisplaySuspender ds;
|
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 {
|
} else {
|
||||||
|
|
@ -1522,7 +1514,7 @@ RouteUI::solo_isolate_button_release (GdkEventButton* ev)
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
boost::shared_ptr<RouteList> rl (new RouteList);
|
||||||
rl->push_back (_route);
|
rl->push_back (_route);
|
||||||
DisplaySuspender ds;
|
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 view = solo_safe_led->active_state();
|
||||||
bool model = _route->solo_safe();
|
bool model = _route->solo_safe_control()->solo_safe();
|
||||||
|
|
||||||
if (ev->button == 1) {
|
if (ev->button == 1) {
|
||||||
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
|
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 */
|
/* disable solo safe for all routes */
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
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 {
|
} else {
|
||||||
/* enable solo safe for all routes */
|
/* enable solo safe for all routes */
|
||||||
DisplaySuspender ds;
|
DisplaySuspender ds;
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
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 {
|
else {
|
||||||
if (model == view) {
|
if (model == view) {
|
||||||
/* flip just this route */
|
/* 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)
|
RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
|
||||||
{
|
{
|
||||||
bool view = check->get_active();
|
bool view = check->get_active();
|
||||||
bool model = _route->solo_isolated();
|
bool model = _route->solo_isolate_control()->solo_isolated();
|
||||||
|
|
||||||
/* called AFTER the view has changed */
|
/* called AFTER the view has changed */
|
||||||
|
|
||||||
if (model != view) {
|
if (model != view) {
|
||||||
_route->set_solo_isolated (view, Controllable::UseGroup);
|
_route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
|
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
|
/** 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
|
void
|
||||||
RouteUI::step_gain_up ()
|
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
|
void
|
||||||
RouteUI::page_gain_up ()
|
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
|
void
|
||||||
RouteUI::step_gain_down ()
|
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
|
void
|
||||||
RouteUI::page_gain_down ()
|
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
|
void
|
||||||
|
|
@ -2158,9 +2150,9 @@ RouteUI::set_invert_button_state ()
|
||||||
|
|
||||||
ArdourButton* b = _invert_buttons.front ();
|
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);
|
b->set_active_state (Gtkmm2ext::ExplicitActive);
|
||||||
} else if (_route->phase_invert().any()) {
|
} else if (_route->phase_control()->any()) {
|
||||||
b->set_active_state (Gtkmm2ext::ImplicitActive);
|
b->set_active_state (Gtkmm2ext::ImplicitActive);
|
||||||
} else {
|
} else {
|
||||||
b->set_active_state (Gtkmm2ext::Off);
|
b->set_active_state (Gtkmm2ext::Off);
|
||||||
|
|
@ -2172,7 +2164,7 @@ RouteUI::set_invert_button_state ()
|
||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
|
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 ();
|
uint32_t const N = _route->input()->n_ports().n_audio ();
|
||||||
if (N <= _max_invert_buttons) {
|
if (N <= _max_invert_buttons) {
|
||||||
/* left-click inverts phase so long as we have a button per channel */
|
/* 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;
|
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)));
|
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 ());
|
Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
|
||||||
++_i_am_the_modifier;
|
++_i_am_the_modifier;
|
||||||
e->set_active (_route->phase_invert (i));
|
e->set_active (_route->phase_control()->inverted (i));
|
||||||
--_i_am_the_modifier;
|
--_i_am_the_modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2232,7 +2224,8 @@ RouteUI::invert_menu_toggled (uint32_t c)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_route->set_phase_invert (c, !_route->phase_invert (c));
|
|
||||||
|
_route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ class RouteUI : public virtual AxisView
|
||||||
bool monitor_input_release(GdkEventButton*);
|
bool monitor_input_release(GdkEventButton*);
|
||||||
bool monitor_disk_press(GdkEventButton*);
|
bool monitor_disk_press(GdkEventButton*);
|
||||||
bool monitor_disk_release(GdkEventButton*);
|
bool monitor_disk_release(GdkEventButton*);
|
||||||
void monitoring_changed ();
|
void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
|
||||||
void update_monitoring_display ();
|
void update_monitoring_display ();
|
||||||
|
|
||||||
void edit_input_configuration ();
|
void edit_input_configuration ();
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ StreamView::StreamView (RouteTimeAxisView& tv, ArdourCanvas::Container* canvas_g
|
||||||
|
|
||||||
if (_trackview.is_track()) {
|
if (_trackview.is_track()) {
|
||||||
_trackview.track()->DiskstreamChanged.connect (*this, invalidator (*this), boost::bind (&StreamView::diskstream_changed, this), gui_context());
|
_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()->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());
|
_trackview.session()->TransportLooped.connect (*this, invalidator (*this), boost::bind (&StreamView::transport_looped, this), gui_context());
|
||||||
|
|
|
||||||
|
|
@ -763,7 +763,7 @@ TimeAxisView::end_name_edit (int response)
|
||||||
|
|
||||||
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -794,7 +794,7 @@ TimeAxisView::end_name_edit (int response)
|
||||||
|
|
||||||
RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
class Automatable;
|
class Automatable;
|
||||||
|
class ControlGroup;
|
||||||
|
|
||||||
/** A PBD::Controllable with associated automation data (AutomationList)
|
/** A PBD::Controllable with associated automation data (AutomationList)
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,8 +87,6 @@ public:
|
||||||
void stop_touch(bool mark, double when);
|
void stop_touch(bool mark, double when);
|
||||||
|
|
||||||
/* inherited from PBD::Controllable.
|
/* 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;
|
double get_value () const;
|
||||||
/* inherited from PBD::Controllable.
|
/* inherited from PBD::Controllable.
|
||||||
|
|
@ -99,10 +97,11 @@ public:
|
||||||
/* automation related value setting */
|
/* automation related value setting */
|
||||||
virtual bool writable () const;
|
virtual bool writable () const;
|
||||||
/* Call to ::set_value() with no test for writable() because
|
/* Call to ::set_value() with no test for writable() because
|
||||||
* this is only used by automation playback. We would like
|
* this is only used by automation playback.
|
||||||
* to make it pure virtual
|
|
||||||
*/
|
*/
|
||||||
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 lower() const { return _desc.lower; }
|
||||||
double upper() const { return _desc.upper; }
|
double upper() const { return _desc.upper; }
|
||||||
|
|
@ -117,6 +116,37 @@ public:
|
||||||
const ARDOUR::Session& session() const { return _session; }
|
const ARDOUR::Session& session() const { return _session; }
|
||||||
void commit_transaction (bool did_write);
|
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 add_master (boost::shared_ptr<AutomationControl>);
|
||||||
void remove_master (boost::shared_ptr<AutomationControl>);
|
void remove_master (boost::shared_ptr<AutomationControl>);
|
||||||
void clear_masters ();
|
void clear_masters ();
|
||||||
|
|
@ -127,10 +157,6 @@ public:
|
||||||
PBD::Signal0<void> MasterStatusChange;
|
PBD::Signal0<void> MasterStatusChange;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ARDOUR::Session& _session;
|
|
||||||
|
|
||||||
const ParameterDescriptor _desc;
|
|
||||||
|
|
||||||
|
|
||||||
class MasterRecord {
|
class MasterRecord {
|
||||||
public:
|
public:
|
||||||
|
|
@ -155,12 +181,12 @@ public:
|
||||||
typedef std::map<PBD::ID,MasterRecord> Masters;
|
typedef std::map<PBD::ID,MasterRecord> Masters;
|
||||||
Masters _masters;
|
Masters _masters;
|
||||||
PBD::ScopedConnectionList masters_connections;
|
PBD::ScopedConnectionList masters_connections;
|
||||||
|
|
||||||
virtual void master_changed (bool from_self, GroupControlDisposition gcd);
|
virtual void master_changed (bool from_self, GroupControlDisposition gcd);
|
||||||
void master_going_away (boost::weak_ptr<AutomationControl>);
|
void master_going_away (boost::weak_ptr<AutomationControl>);
|
||||||
virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
|
virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
|
||||||
virtual double get_masters_value_locked () const;
|
virtual double get_masters_value_locked () const;
|
||||||
double get_value_locked() const;
|
double get_value_locked() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,11 @@ namespace ARDOUR {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
|
||||||
class LIBARDOUR_API GainControl : public AutomationControl {
|
class LIBARDOUR_API GainControl : public SlavableAutomationControl {
|
||||||
public:
|
public:
|
||||||
GainControl (Session& session, const Evoral::Parameter ¶m,
|
GainControl (Session& session, const Evoral::Parameter ¶m,
|
||||||
boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>());
|
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 internal_to_interface (double) const;
|
||||||
double interface_to_internal (double) const;
|
double interface_to_internal (double) const;
|
||||||
double internal_to_user (double) const;
|
double internal_to_user (double) const;
|
||||||
|
|
@ -54,6 +51,8 @@ class LIBARDOUR_API GainControl : public AutomationControl {
|
||||||
int set_state (XMLNode const&, int);
|
int set_state (XMLNode const&, int);
|
||||||
XMLNode& get_state();
|
XMLNode& get_state();
|
||||||
|
|
||||||
|
void inc_gain (gain_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string masters_string;
|
std::string masters_string;
|
||||||
PBD::ScopedConnection vca_loaded_connection;
|
PBD::ScopedConnection vca_loaded_connection;
|
||||||
|
|
@ -61,7 +60,7 @@ class LIBARDOUR_API GainControl : public AutomationControl {
|
||||||
void vcas_loaded();
|
void vcas_loaded();
|
||||||
void recompute_masters_ratios (double val);
|
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 */
|
} /* namespace */
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,9 @@ public:
|
||||||
|
|
||||||
boost::shared_ptr<Diskstream> create_diskstream ();
|
boost::shared_ptr<Diskstream> create_diskstream ();
|
||||||
void set_diskstream (boost::shared_ptr<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 {
|
DataType data_type () const {
|
||||||
return DataType::MIDI;
|
return DataType::MIDI;
|
||||||
|
|
@ -89,14 +90,12 @@ public:
|
||||||
, _route (route)
|
, _route (route)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
|
|
||||||
void set_value_unchecked (double);
|
|
||||||
bool writable() const { return true; }
|
bool writable() const { return true; }
|
||||||
|
|
||||||
MidiTrack* _route;
|
MidiTrack* _route;
|
||||||
|
|
||||||
private:
|
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);
|
virtual void set_parameter_automation_state (Evoral::Parameter param, AutoState);
|
||||||
|
|
@ -133,7 +132,6 @@ public:
|
||||||
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
|
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
|
||||||
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
||||||
|
|
||||||
void set_monitoring (MonitorChoice, PBD::Controllable::GroupControlDisposition);
|
|
||||||
MonitorState monitoring_state () const;
|
MonitorState monitoring_state () const;
|
||||||
|
|
||||||
void set_input_active (bool);
|
void set_input_active (bool);
|
||||||
|
|
@ -144,6 +142,7 @@ protected:
|
||||||
XMLNode& state (bool full);
|
XMLNode& state (bool full);
|
||||||
|
|
||||||
void act_on_mute ();
|
void act_on_mute ();
|
||||||
|
void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MidiRingBuffer<framepos_t> _immediate_events;
|
MidiRingBuffer<framepos_t> _immediate_events;
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,15 @@
|
||||||
#ifndef __ardour_mute_master_h__
|
#ifndef __ardour_mute_master_h__
|
||||||
#define __ardour_mute_master_h__
|
#define __ardour_mute_master_h__
|
||||||
|
|
||||||
#include "evoral/Parameter.hpp"
|
|
||||||
#include "pbd/signals.h"
|
|
||||||
#include "pbd/stateful.h"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "pbd/signals.h"
|
||||||
|
#include "pbd/stateful.h"
|
||||||
|
|
||||||
|
#include "evoral/Parameter.hpp"
|
||||||
|
|
||||||
#include "ardour/session_handle.h"
|
#include "ardour/session_handle.h"
|
||||||
|
#include "ardour/types.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
@ -73,6 +76,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
|
||||||
|
|
||||||
XMLNode& get_state();
|
XMLNode& get_state();
|
||||||
int set_state(const XMLNode&, int version);
|
int set_state(const XMLNode&, int version);
|
||||||
|
static const std::string xml_node_name;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MutePoint _mute_point;
|
MutePoint _mute_point;
|
||||||
|
|
|
||||||
|
|
@ -47,12 +47,10 @@ class LIBARDOUR_API PanControllable : public AutomationControl
|
||||||
{}
|
{}
|
||||||
|
|
||||||
double lower () const;
|
double lower () const;
|
||||||
void set_value (double, PBD::Controllable::GroupControlDisposition group_override);
|
|
||||||
void set_value_unchecked (double);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pannable* owner;
|
Pannable* owner;
|
||||||
void _set_value (double, PBD::Controllable::GroupControlDisposition group_override);
|
void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
||||||
|
|
@ -185,15 +185,13 @@ class LIBARDOUR_API PluginInsert : public Processor
|
||||||
const ParameterDescriptor& desc,
|
const ParameterDescriptor& desc,
|
||||||
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
|
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;
|
double get_value (void) const;
|
||||||
void catch_up_with_external_value (double val);
|
void catch_up_with_external_value (double val);
|
||||||
XMLNode& get_state();
|
XMLNode& get_state();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginInsert* _plugin;
|
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). */
|
/** A control that manipulates a plugin property (message). */
|
||||||
|
|
@ -204,10 +202,10 @@ class LIBARDOUR_API PluginInsert : public Processor
|
||||||
const ParameterDescriptor& desc,
|
const ParameterDescriptor& desc,
|
||||||
boost::shared_ptr<AutomationList> list=boost::shared_ptr<AutomationList>());
|
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;
|
double get_value (void) const;
|
||||||
XMLNode& get_state();
|
XMLNode& get_state();
|
||||||
|
protected:
|
||||||
|
void actually_set_value (double value, PBD::Controllable::GroupControlDisposition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PluginInsert* _plugin;
|
PluginInsert* _plugin;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/weak_ptr.hpp>
|
#include <boost/weak_ptr.hpp>
|
||||||
#include <boost/dynamic_bitset.hpp>
|
|
||||||
#include <boost/enable_shared_from_this.hpp>
|
#include <boost/enable_shared_from_this.hpp>
|
||||||
|
|
||||||
#include <glibmm/threads.h>
|
#include <glibmm/threads.h>
|
||||||
|
|
@ -46,12 +45,18 @@
|
||||||
#include "ardour/io_vector.h"
|
#include "ardour/io_vector.h"
|
||||||
#include "ardour/libardour_visibility.h"
|
#include "ardour/libardour_visibility.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
#include "ardour/monitorable.h"
|
||||||
|
#include "ardour/muteable.h"
|
||||||
#include "ardour/mute_master.h"
|
#include "ardour/mute_master.h"
|
||||||
|
#include "ardour/mute_control.h"
|
||||||
#include "ardour/route_group_member.h"
|
#include "ardour/route_group_member.h"
|
||||||
#include "ardour/stripable.h"
|
#include "ardour/stripable.h"
|
||||||
#include "ardour/graphnode.h"
|
#include "ardour/graphnode.h"
|
||||||
#include "ardour/automatable.h"
|
#include "ardour/automatable.h"
|
||||||
#include "ardour/unknown_processor.h"
|
#include "ardour/unknown_processor.h"
|
||||||
|
#include "ardour/soloable.h"
|
||||||
|
#include "ardour/solo_control.h"
|
||||||
|
#include "ardour/solo_safe_control.h"
|
||||||
|
|
||||||
class RoutePinWindowProxy;
|
class RoutePinWindowProxy;
|
||||||
|
|
||||||
|
|
@ -74,8 +79,18 @@ class Pannable;
|
||||||
class CapturingProcessor;
|
class CapturingProcessor;
|
||||||
class InternalSend;
|
class InternalSend;
|
||||||
class VCA;
|
class VCA;
|
||||||
|
class SoloIsolateControl;
|
||||||
|
class PhaseControl;
|
||||||
|
class MonitorControl;
|
||||||
|
|
||||||
class LIBARDOUR_API Route : public Stripable, public Automatable, public RouteGroupMember, public GraphNode, public boost::enable_shared_from_this<Route>
|
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:
|
public:
|
||||||
|
|
||||||
|
|
@ -119,7 +134,7 @@ public:
|
||||||
bool is_master() const { return _flags & MasterOut; }
|
bool is_master() const { return _flags & MasterOut; }
|
||||||
bool is_monitor() const { return _flags & MonitorOut; }
|
bool is_monitor() const { return _flags & MonitorOut; }
|
||||||
|
|
||||||
virtual MonitorState monitoring_state () const;
|
MonitorState monitoring_state () const;
|
||||||
virtual MeterState metering_state () const;
|
virtual MeterState metering_state () const;
|
||||||
|
|
||||||
/* these are the core of the API of a Route. see the protected sections as well */
|
/* 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 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 nonrealtime_handle_transport_stopped (bool abort, bool did_locate, bool flush_processors);
|
||||||
virtual void realtime_handle_transport_stopped () {}
|
virtual void realtime_handle_transport_stopped () {}
|
||||||
virtual void realtime_locate () {}
|
virtual void realtime_locate () {}
|
||||||
|
|
@ -149,47 +160,31 @@ public:
|
||||||
|
|
||||||
void shift (framepos_t, framecnt_t);
|
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_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
|
/* 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 ();
|
void clear_all_solo_state ();
|
||||||
|
|
||||||
bool soloed_by_others () const { return _soloed_by_others_upstream||_soloed_by_others_downstream; }
|
bool soloed_by_others () const { return _solo_control->soloed_by_others(); }
|
||||||
bool soloed_by_others_upstream () const { return _soloed_by_others_upstream; }
|
bool soloed_by_others_upstream () const { return _solo_control->soloed_by_others_upstream(); }
|
||||||
bool soloed_by_others_downstream () const { return _soloed_by_others_downstream; }
|
bool soloed_by_others_downstream () const { return _solo_control->soloed_by_others_downstream(); }
|
||||||
bool self_soloed () const { return _self_solo; }
|
bool self_soloed () const { return _solo_control->self_soloed(); }
|
||||||
|
bool soloed () const { return self_soloed () || soloed_by_others (); }
|
||||||
|
|
||||||
void set_solo_isolated (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
|
void push_solo_upstream (int32_t delta);
|
||||||
bool solo_isolated() const;
|
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_solo_safe (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
|
|
||||||
bool solo_safe() const;
|
|
||||||
|
|
||||||
void set_listen (bool yn, PBD::Controllable::GroupControlDisposition group_override = PBD::Controllable::UseGroup);
|
|
||||||
bool listening_via_monitor () const;
|
bool listening_via_monitor () const;
|
||||||
void enable_monitor_send ();
|
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);
|
void set_denormal_protection (bool yn);
|
||||||
bool denormal_protection() const;
|
bool denormal_protection() const;
|
||||||
|
|
||||||
|
|
@ -353,7 +348,6 @@ public:
|
||||||
PBD::Signal0<void> active_changed;
|
PBD::Signal0<void> active_changed;
|
||||||
PBD::Signal0<void> denormal_protection_changed;
|
PBD::Signal0<void> denormal_protection_changed;
|
||||||
PBD::Signal0<void> comment_changed;
|
PBD::Signal0<void> comment_changed;
|
||||||
PBD::Signal0<void> mute_points_changed;
|
|
||||||
|
|
||||||
/** track numbers - assigned by session
|
/** track numbers - assigned by session
|
||||||
* nubers > 0 indicate tracks (audio+midi)
|
* nubers > 0 indicate tracks (audio+midi)
|
||||||
|
|
@ -456,185 +450,32 @@ public:
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
|
boost::shared_ptr<AutomationControl> get_control (const Evoral::Parameter& param);
|
||||||
|
|
||||||
class RouteAutomationControl : public AutomationControl {
|
boost::shared_ptr<SoloControl> solo_control() const {
|
||||||
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 {
|
|
||||||
return _solo_control;
|
return _solo_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl> mute_control() const {
|
boost::shared_ptr<MuteControl> mute_control() const {
|
||||||
return _mute_control;
|
return _mute_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<MuteMaster> mute_master() const {
|
bool can_be_muted_by_others () const { return !is_master(); }
|
||||||
return _mute_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;
|
return _solo_isolate_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl> solo_safe_control() const {
|
boost::shared_ptr<SoloSafeControl> solo_safe_control() const {
|
||||||
return _solo_safe_control;
|
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;
|
/* tracks override this to provide actual monitoring control;
|
||||||
busses have no possible choices except input monitoring.
|
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
|
/* 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<Pannable> pannable() const;
|
||||||
|
|
||||||
boost::shared_ptr<GainControl> gain_control() const;
|
boost::shared_ptr<GainControl> gain_control() const;
|
||||||
boost::shared_ptr<AutomationControl> trim_control() const;
|
boost::shared_ptr<GainControl> trim_control() const;
|
||||||
boost::shared_ptr<AutomationControl> phase_control() const;
|
boost::shared_ptr<PhaseControl> phase_control() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Return the first processor that accepts has at least one MIDI input
|
Return the first processor that accepts has at least one MIDI input
|
||||||
|
|
@ -766,8 +607,8 @@ public:
|
||||||
friend class Session;
|
friend class Session;
|
||||||
|
|
||||||
void catch_up_on_solo_mute_override ();
|
void catch_up_on_solo_mute_override ();
|
||||||
void mod_solo_by_others_upstream (int32_t);
|
void set_listen (bool);
|
||||||
void mod_solo_by_others_downstream (int32_t);
|
|
||||||
void curve_reallocate ();
|
void curve_reallocate ();
|
||||||
virtual void set_block_size (pframes_t nframes);
|
virtual void set_block_size (pframes_t nframes);
|
||||||
|
|
||||||
|
|
@ -829,14 +670,6 @@ protected:
|
||||||
MeterPoint _meter_point;
|
MeterPoint _meter_point;
|
||||||
MeterPoint _pending_meter_point;
|
MeterPoint _pending_meter_point;
|
||||||
MeterType _meter_type;
|
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;
|
bool _denormal_protection;
|
||||||
|
|
||||||
|
|
@ -844,18 +677,14 @@ protected:
|
||||||
bool _silent : 1;
|
bool _silent : 1;
|
||||||
bool _declickable : 1;
|
bool _declickable : 1;
|
||||||
|
|
||||||
boost::shared_ptr<SoloControllable> _solo_control;
|
boost::shared_ptr<SoloControl> _solo_control;
|
||||||
boost::shared_ptr<MuteControllable> _mute_control;
|
boost::shared_ptr<MuteControl> _mute_control;
|
||||||
boost::shared_ptr<MuteMaster> _mute_master;
|
boost::shared_ptr<PhaseControl> _phase_control;
|
||||||
boost::shared_ptr<PhaseControllable> _phase_control;
|
boost::shared_ptr<SoloIsolateControl> _solo_isolate_control;
|
||||||
boost::shared_ptr<SoloIsolateControllable> _solo_isolate_control;
|
boost::shared_ptr<SoloSafeControl> _solo_safe_control;
|
||||||
boost::shared_ptr<SoloSafeControllable> _solo_safe_control;
|
|
||||||
|
|
||||||
virtual void act_on_mute () {}
|
|
||||||
|
|
||||||
std::string _comment;
|
std::string _comment;
|
||||||
bool _have_internal_generator;
|
bool _have_internal_generator;
|
||||||
bool _solo_safe;
|
|
||||||
DataType _default_type;
|
DataType _default_type;
|
||||||
FedBy _fed_by;
|
FedBy _fed_by;
|
||||||
|
|
||||||
|
|
@ -882,9 +711,9 @@ protected:
|
||||||
|
|
||||||
virtual void maybe_declick (BufferSet&, framecnt_t, int);
|
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<Amp> _amp;
|
||||||
boost::shared_ptr<GainControllable> _trim_control;
|
boost::shared_ptr<GainControl> _trim_control;
|
||||||
boost::shared_ptr<Amp> _trim;
|
boost::shared_ptr<Amp> _trim;
|
||||||
boost::shared_ptr<PeakMeter> _meter;
|
boost::shared_ptr<PeakMeter> _meter;
|
||||||
boost::shared_ptr<DelayLine> _delayline;
|
boost::shared_ptr<DelayLine> _delayline;
|
||||||
|
|
@ -928,7 +757,6 @@ private:
|
||||||
void placement_range (Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end);
|
void placement_range (Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end);
|
||||||
|
|
||||||
void set_self_solo (bool yn);
|
void set_self_solo (bool yn);
|
||||||
void set_mute_master_solo ();
|
|
||||||
|
|
||||||
void set_processor_positions ();
|
void set_processor_positions ();
|
||||||
framecnt_t update_port_latencies (PortSet& ports, PortSet& feeders, bool playback, framecnt_t) const;
|
framecnt_t update_port_latencies (PortSet& ports, PortSet& feeders, bool playback, framecnt_t) const;
|
||||||
|
|
@ -985,6 +813,7 @@ private:
|
||||||
void reset_instrument_info ();
|
void reset_instrument_info ();
|
||||||
|
|
||||||
void set_remote_control_id_internal (uint32_t id, bool notify_class_listeners = true);
|
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
|
} // namespace ARDOUR
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,12 @@
|
||||||
#include "pbd/signals.h"
|
#include "pbd/signals.h"
|
||||||
#include "pbd/stateful.h"
|
#include "pbd/stateful.h"
|
||||||
|
|
||||||
#include "ardour/libardour_visibility.h"
|
#include "ardour/control_group.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
#include "ardour/session_object.h"
|
#include "ardour/session_object.h"
|
||||||
|
|
||||||
|
#include "ardour/libardour_visibility.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
namespace Properties {
|
namespace Properties {
|
||||||
|
|
@ -157,8 +159,17 @@ class LIBARDOUR_API RouteGroup : public SessionObject
|
||||||
PBD::Property<bool> _color;
|
PBD::Property<bool> _color;
|
||||||
PBD::Property<bool> _monitoring;
|
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>);
|
void remove_when_going_away (boost::weak_ptr<Route>);
|
||||||
int set_state_2X (const XMLNode&, int);
|
int set_state_2X (const XMLNode&, int);
|
||||||
|
|
||||||
|
void post_set (PBD::PropertyChange const &);
|
||||||
|
void push_to_groups ();
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
|
||||||
|
|
@ -791,16 +791,13 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
||||||
|
|
||||||
static const SessionEvent::RTeventCallback rt_cleanup;
|
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 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);
|
/* Control-based methods */
|
||||||
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_controls (boost::shared_ptr<ControlList>, double val, PBD::Controllable::GroupControlDisposition);
|
||||||
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_control (boost::shared_ptr<AutomationControl>, double val, PBD::Controllable::GroupControlDisposition);
|
||||||
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);
|
|
||||||
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others = false);
|
void set_exclusive_input_active (boost::shared_ptr<RouteList> rt, bool onoff, bool flip_others = false);
|
||||||
|
|
||||||
PBD::Signal1<void,bool> SoloActive;
|
PBD::Signal1<void,bool> SoloActive;
|
||||||
|
|
@ -1936,16 +1933,18 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_set_solo (boost::shared_ptr<RouteList>, bool yn, PBD::Controllable::GroupControlDisposition group_override);
|
/* specialized version realtime "apply to set of controls" operations */
|
||||||
void rt_set_implicit_solo (boost::shared_ptr<RouteList>, int delta, bool up_or_downstream, PBD::Controllable::GroupControlDisposition);
|
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_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 */
|
/** temporary list of Diskstreams used only during load of 2.X sessions */
|
||||||
std::list<boost::shared_ptr<Diskstream> > _diskstreams_2X;
|
std::list<boost::shared_ptr<Diskstream> > _diskstreams_2X;
|
||||||
|
|
|
||||||
|
|
@ -91,16 +91,18 @@ public:
|
||||||
|
|
||||||
union {
|
union {
|
||||||
bool second_yes_or_no;
|
bool second_yes_or_no;
|
||||||
|
double control_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
bool third_yes_or_no;
|
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;
|
typedef boost::function<void (SessionEvent*)> RTeventCallback;
|
||||||
|
|
||||||
|
boost::shared_ptr<ControlList> controls; /* apply to */
|
||||||
boost::shared_ptr<RouteList> routes; /* apply to */
|
boost::shared_ptr<RouteList> routes; /* apply to */
|
||||||
boost::function<void (void)> rt_slot; /* what to call in RT context */
|
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 */
|
RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,19 @@
|
||||||
#include <boost/utility.hpp>
|
#include <boost/utility.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "ardour/gain_control.h"
|
|
||||||
#include "ardour/session_object.h"
|
#include "ardour/session_object.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class AutomationControl;
|
class AutomationControl;
|
||||||
|
class GainControl;
|
||||||
class PeakMeter;
|
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
|
/* 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
|
* 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<GainControl> gain_control() const = 0;
|
||||||
|
|
||||||
virtual boost::shared_ptr<AutomationControl> solo_control() const = 0;
|
virtual boost::shared_ptr<SoloControl> solo_control() const = 0;
|
||||||
virtual boost::shared_ptr<AutomationControl> mute_control() const = 0;
|
virtual boost::shared_ptr<MuteControl> 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<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>(); }
|
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
|
/* "well-known" controls for panning. Any or all of these may return
|
||||||
|
|
@ -131,6 +138,9 @@ class Stripable : public SessionObject {
|
||||||
* the route.
|
* the route.
|
||||||
*/
|
*/
|
||||||
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
#include "ardour/interthread_info.h"
|
#include "ardour/interthread_info.h"
|
||||||
|
#include "ardour/recordable.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/public_diskstream.h"
|
#include "ardour/public_diskstream.h"
|
||||||
|
|
||||||
|
|
@ -34,13 +35,14 @@ class Source;
|
||||||
class Region;
|
class Region;
|
||||||
class Diskstream;
|
class Diskstream;
|
||||||
class IO;
|
class IO;
|
||||||
|
class MonitorControl;
|
||||||
|
|
||||||
/** A track is an route (bus) with a recordable diskstream and
|
/** A track is an route (bus) with a recordable diskstream and
|
||||||
* related objects relevant to tracking, playback and editing.
|
* related objects relevant to tracking, playback and editing.
|
||||||
*
|
*
|
||||||
* Specifically a track has regions and playlist objects.
|
* 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:
|
public:
|
||||||
Track (Session&, std::string name, Route::Flag f = Route::Flag (0), TrackMode m = Normal, DataType default_type = DataType::AUDIO);
|
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; }
|
virtual bool can_use_mode (TrackMode /*m*/, bool& /*bounce_required*/) { return false; }
|
||||||
PBD::Signal0<void> TrackModeChanged;
|
PBD::Signal0<void> TrackModeChanged;
|
||||||
|
|
||||||
class LIBARDOUR_API MonitoringControllable : public RouteAutomationControl {
|
boost::shared_ptr<MonitorControl> monitoring_control() const { return _monitoring_control; }
|
||||||
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;
|
MonitorState monitoring_state () const;
|
||||||
PBD::Signal0<void> MonitoringChanged;
|
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl> monitoring_control() const { return _monitoring_control; }
|
|
||||||
|
|
||||||
MeterState metering_state () const;
|
MeterState metering_state () const;
|
||||||
|
|
||||||
virtual int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
|
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);
|
virtual int set_state (const XMLNode&, int version);
|
||||||
static void zero_diskstream_id_in_xml (XMLNode&);
|
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;
|
int prep_record_enabled (bool);
|
||||||
bool record_safe () const;
|
bool can_be_record_enabled ();
|
||||||
void set_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
|
bool can_be_record_safe ();
|
||||||
void set_record_safe (bool yn, PBD::Controllable::GroupControlDisposition);
|
|
||||||
void prep_record_enabled (bool yn, PBD::Controllable::GroupControlDisposition);
|
|
||||||
|
|
||||||
bool using_diskstream_id (PBD::ID) const;
|
bool using_diskstream_id (PBD::ID) const;
|
||||||
|
|
||||||
|
|
@ -204,8 +191,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
|
||||||
PBD::Signal0<void> FreezeChange;
|
PBD::Signal0<void> FreezeChange;
|
||||||
/* Emitted when our diskstream is set to use a different playlist */
|
/* Emitted when our diskstream is set to use a different playlist */
|
||||||
PBD::Signal0<void> PlaylistChanged;
|
PBD::Signal0<void> PlaylistChanged;
|
||||||
PBD::Signal0<void> RecordEnableChanged;
|
|
||||||
PBD::Signal0<void> RecordSafeChanged;
|
|
||||||
PBD::Signal0<void> SpeedChanged;
|
PBD::Signal0<void> SpeedChanged;
|
||||||
PBD::Signal0<void> AlignmentStyleChanged;
|
PBD::Signal0<void> AlignmentStyleChanged;
|
||||||
|
|
||||||
|
|
@ -216,8 +201,7 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
|
||||||
MeterPoint _saved_meter_point;
|
MeterPoint _saved_meter_point;
|
||||||
TrackMode _mode;
|
TrackMode _mode;
|
||||||
bool _needs_butler;
|
bool _needs_butler;
|
||||||
MonitorChoice _monitoring;
|
boost::shared_ptr<MonitorControl> _monitoring_control;
|
||||||
boost::shared_ptr<MonitoringControllable> _monitoring_control;
|
|
||||||
|
|
||||||
//private: (FIXME)
|
//private: (FIXME)
|
||||||
struct FreezeRecordProcessorInfo {
|
struct FreezeRecordProcessorInfo {
|
||||||
|
|
@ -242,20 +226,6 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
|
||||||
FreezeState state;
|
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;
|
virtual void set_state_part_two () = 0;
|
||||||
|
|
||||||
FreezeRecord _freeze_record;
|
FreezeRecord _freeze_record;
|
||||||
|
|
@ -264,17 +234,20 @@ class LIBARDOUR_API Track : public Route, public PublicDiskstream
|
||||||
|
|
||||||
void maybe_declick (BufferSet&, framecnt_t, int);
|
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&);
|
framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&);
|
||||||
|
virtual void monitoring_changed (bool, PBD::Controllable::GroupControlDisposition);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &) = 0;
|
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &) = 0;
|
||||||
|
|
||||||
void diskstream_playlist_changed ();
|
void diskstream_playlist_changed ();
|
||||||
void diskstream_record_enable_changed ();
|
|
||||||
void diskstream_record_safe_changed ();
|
|
||||||
void diskstream_speed_changed ();
|
void diskstream_speed_changed ();
|
||||||
void diskstream_alignment_style_changed ();
|
void diskstream_alignment_style_changed ();
|
||||||
void parameter_changed (std::string const & p);
|
void parameter_changed (std::string const & p);
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ namespace ARDOUR {
|
||||||
class Route;
|
class Route;
|
||||||
class Region;
|
class Region;
|
||||||
class VCA;
|
class VCA;
|
||||||
|
class AutomationControl;
|
||||||
|
|
||||||
typedef float Sample;
|
typedef float Sample;
|
||||||
typedef float pan_t;
|
typedef float pan_t;
|
||||||
|
|
@ -149,6 +150,7 @@ namespace ARDOUR {
|
||||||
FadeOutAutomation,
|
FadeOutAutomation,
|
||||||
EnvelopeAutomation,
|
EnvelopeAutomation,
|
||||||
RecEnableAutomation,
|
RecEnableAutomation,
|
||||||
|
RecSafeAutomation,
|
||||||
TrimAutomation,
|
TrimAutomation,
|
||||||
PhaseAutomation,
|
PhaseAutomation,
|
||||||
MonitoringAutomation,
|
MonitoringAutomation,
|
||||||
|
|
@ -565,6 +567,7 @@ namespace ARDOUR {
|
||||||
|
|
||||||
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
||||||
typedef std::list<boost::weak_ptr <Route> > WeakRouteList;
|
typedef std::list<boost::weak_ptr <Route> > WeakRouteList;
|
||||||
|
typedef std::list<boost::shared_ptr<AutomationControl> > ControlList;
|
||||||
|
|
||||||
typedef std::list<boost::shared_ptr<VCA> > VCAList;
|
typedef std::list<boost::shared_ptr<VCA> > VCAList;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,19 +28,26 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "boost/shared_ptr.hpp"
|
||||||
|
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif /* __APPLE__ */
|
#endif /* __APPLE__ */
|
||||||
|
|
||||||
#include "ardour/libardour_visibility.h"
|
|
||||||
#include "ardour/ardour.h"
|
#include "ardour/ardour.h"
|
||||||
#include "ardour/data_type.h"
|
#include "ardour/data_type.h"
|
||||||
#include "ardour/dB.h"
|
#include "ardour/dB.h"
|
||||||
|
#include "ardour/types.h"
|
||||||
|
|
||||||
|
#include "ardour/libardour_visibility.h"
|
||||||
|
|
||||||
class XMLNode;
|
class XMLNode;
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
class Route;
|
||||||
|
class Track;
|
||||||
|
|
||||||
LIBARDOUR_API std::string legalize_for_path (const std::string& str);
|
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_universal_path (const std::string& str);
|
||||||
LIBARDOUR_API std::string legalize_for_uri (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 ();
|
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__
|
#if __APPLE__
|
||||||
LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
|
LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
@ -176,4 +206,3 @@ LIBARDOUR_API std::string CFStringRefToStdString(CFStringRef stringRef);
|
||||||
} //namespave
|
} //namespave
|
||||||
|
|
||||||
#endif /* __ardour_utils_h__ */
|
#endif /* __ardour_utils_h__ */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,19 @@
|
||||||
#include "pbd/statefuldestructible.h"
|
#include "pbd/statefuldestructible.h"
|
||||||
|
|
||||||
#include "ardour/automatable.h"
|
#include "ardour/automatable.h"
|
||||||
|
#include "ardour/muteable.h"
|
||||||
|
#include "ardour/soloable.h"
|
||||||
#include "ardour/stripable.h"
|
#include "ardour/stripable.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class GainControl;
|
|
||||||
class Route;
|
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:
|
public:
|
||||||
VCA (Session& session, uint32_t num, const std::string& name);
|
VCA (Session& session, uint32_t num, const std::string& name);
|
||||||
~VCA();
|
~VCA();
|
||||||
|
|
@ -47,7 +52,15 @@ class LIBARDOUR_API VCA : public Stripable, public Automatable, public boost::en
|
||||||
int set_state (XMLNode const&, int version);
|
int set_state (XMLNode const&, int version);
|
||||||
|
|
||||||
bool soloed () const;
|
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 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 std::string default_name_template ();
|
||||||
static int next_vca_number ();
|
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);
|
static void set_next_vca_number (uint32_t);
|
||||||
|
|
||||||
virtual boost::shared_ptr<GainControl> gain_control() const { return _gain_control; }
|
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<SoloControl> solo_control() const { return _solo_control; }
|
||||||
virtual boost::shared_ptr<AutomationControl> mute_control() const { return _mute_control; }
|
virtual boost::shared_ptr<MuteControl> mute_control() const { return _mute_control; }
|
||||||
|
|
||||||
/* null Stripable API, because VCAs don't have any of this */
|
/* 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<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<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<PhaseControl> phase_control() const { return boost::shared_ptr<PhaseControl>(); }
|
||||||
virtual boost::shared_ptr<AutomationControl> trim_control() const { return boost::shared_ptr<AutomationControl>(); }
|
virtual boost::shared_ptr<GainControl> trim_control() const { return boost::shared_ptr<GainControl>(); }
|
||||||
virtual boost::shared_ptr<AutomationControl> monitoring_control() const { return boost::shared_ptr<AutomationControl>(); }
|
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> 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_azimuth_control() const { return boost::shared_ptr<AutomationControl>(); }
|
||||||
virtual boost::shared_ptr<AutomationControl> pan_elevation_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>(); }
|
virtual boost::shared_ptr<AutomationControl> master_send_enable_controllable () const { return boost::shared_ptr<AutomationControl>(); }
|
||||||
|
|
||||||
private:
|
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;
|
uint32_t _number;
|
||||||
|
|
||||||
boost::shared_ptr<GainControl> _gain_control;
|
boost::shared_ptr<GainControl> _gain_control;
|
||||||
boost::shared_ptr<VCASoloControllable> _solo_control;
|
boost::shared_ptr<SoloControl> _solo_control;
|
||||||
boost::shared_ptr<VCAMuteControllable> _mute_control;
|
boost::shared_ptr<MuteControl> _mute_control;
|
||||||
|
|
||||||
bool _solo_requested;
|
bool _solo_requested;
|
||||||
bool _mute_requested;
|
bool _mute_requested;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include "ardour/buffer_set.h"
|
#include "ardour/buffer_set.h"
|
||||||
#include "ardour/delivery.h"
|
#include "ardour/delivery.h"
|
||||||
#include "ardour/meter.h"
|
#include "ardour/meter.h"
|
||||||
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/playlist_factory.h"
|
#include "ardour/playlist_factory.h"
|
||||||
#include "ardour/processor.h"
|
#include "ardour/processor.h"
|
||||||
#include "ardour/profile.h"
|
#include "ardour/profile.h"
|
||||||
|
|
@ -349,7 +350,7 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
|
||||||
|
|
||||||
if (!_active) {
|
if (!_active) {
|
||||||
silence (nframes);
|
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();
|
_meter->reset();
|
||||||
}
|
}
|
||||||
return 0;
|
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);
|
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);
|
_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 */
|
/* reset stuff that has already been accounted for in the freeze process */
|
||||||
|
|
||||||
set_gain (GAIN_COEFF_UNITY, Controllable::NoGroup);
|
gain_control()->set_value (GAIN_COEFF_UNITY, Controllable::NoGroup);
|
||||||
_amp->gain_control()->set_automation_state (Off);
|
gain_control()->set_automation_state (Off);
|
||||||
|
|
||||||
/* XXX need to use _main_outs _panner->set_automation_state (Off); */
|
/* XXX need to use _main_outs _panner->set_automation_state (Off); */
|
||||||
|
|
||||||
_freeze_record.state = Frozen;
|
_freeze_record.state = Frozen;
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,17 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "ardour/automation_control.h"
|
|
||||||
#include "ardour/automation_watch.h"
|
|
||||||
#include "ardour/event_type_map.h"
|
|
||||||
#include "ardour/session.h"
|
|
||||||
|
|
||||||
#include "pbd/memento_command.h"
|
#include "pbd/memento_command.h"
|
||||||
#include "pbd/stacktrace.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 "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
#ifdef COMPILER_MSVC
|
#ifdef COMPILER_MSVC
|
||||||
|
|
@ -69,43 +72,39 @@ AutomationControl::writable() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double
|
|
||||||
AutomationControl::get_masters_value_locked () 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
|
||||||
AutomationControl::get_value_locked() const
|
|
||||||
{
|
|
||||||
/* read or write masters lock must be held */
|
|
||||||
|
|
||||||
if (_masters.empty()) {
|
|
||||||
return Control::get_double (false, _session.transport_frame());
|
|
||||||
}
|
|
||||||
|
|
||||||
return get_masters_value_locked ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the current effective `user' value based on automation state */
|
/** Get the current effective `user' value based on automation state */
|
||||||
double
|
double
|
||||||
AutomationControl::get_value() const
|
AutomationControl::get_value() const
|
||||||
{
|
{
|
||||||
bool from_list = _list && ((AutomationList*)_list.get())->automation_playback();
|
bool from_list = _list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback();
|
||||||
|
|
||||||
if (!from_list) {
|
|
||||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
|
||||||
return get_value_locked ();
|
|
||||||
} else {
|
|
||||||
return Control::get_double (from_list, _session.transport_frame());
|
return Control::get_double (from_list, _session.transport_frame());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposition gcd)
|
||||||
|
{
|
||||||
|
if (!writable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enforce strict double/boolean value mapping */
|
||||||
|
|
||||||
|
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 (_group && _group->use_me (gcd)) {
|
||||||
|
_group->set_group_value (shared_from_this(), val);
|
||||||
|
} else {
|
||||||
|
actually_set_value (val, gcd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the value and do the right thing based on automation state
|
/** Set the value and do the right thing based on automation state
|
||||||
|
|
@ -113,12 +112,15 @@ AutomationControl::get_value() const
|
||||||
* @param value `user' value
|
* @param value `user' value
|
||||||
*/
|
*/
|
||||||
void
|
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);
|
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);
|
Changed (true, gcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -263,147 +265,25 @@ AutomationControl::interface_to_internal (double val) const
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
AutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
|
AutomationControl::set_group (boost::shared_ptr<ControlGroup> cg)
|
||||||
{
|
{
|
||||||
double current_value;
|
if (_group) {
|
||||||
double new_value;
|
_group->remove_control (shared_from_this());
|
||||||
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 ()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_group = cg;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
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);
|
if ((flags() & Controllable::RealTime) && !AudioEngine::instance()->in_process_thread()) {
|
||||||
return _masters.find (m->id()) != _masters.end();
|
/* 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
|
return false;
|
||||||
AutomationControl::slaved () const
|
|
||||||
{
|
|
||||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
|
||||||
return !_masters.empty();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,21 +140,30 @@ setup_enum_writer ()
|
||||||
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
|
#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)
|
#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
|
||||||
|
|
||||||
|
REGISTER_ENUM (NullAutomation);
|
||||||
REGISTER_ENUM (GainAutomation);
|
REGISTER_ENUM (GainAutomation);
|
||||||
REGISTER_ENUM (TrimAutomation);
|
|
||||||
REGISTER_ENUM (PanAzimuthAutomation);
|
REGISTER_ENUM (PanAzimuthAutomation);
|
||||||
REGISTER_ENUM (PanElevationAutomation);
|
REGISTER_ENUM (PanElevationAutomation);
|
||||||
REGISTER_ENUM (PanWidthAutomation);
|
REGISTER_ENUM (PanWidthAutomation);
|
||||||
|
REGISTER_ENUM (PanFrontBackAutomation);
|
||||||
|
REGISTER_ENUM (PanLFEAutomation);
|
||||||
REGISTER_ENUM (PluginAutomation);
|
REGISTER_ENUM (PluginAutomation);
|
||||||
REGISTER_ENUM (PluginPropertyAutomation);
|
REGISTER_ENUM (PluginPropertyAutomation);
|
||||||
REGISTER_ENUM (SoloAutomation);
|
REGISTER_ENUM (SoloAutomation);
|
||||||
|
REGISTER_ENUM (SoloIsolateAutomation);
|
||||||
|
REGISTER_ENUM (SoloSafeAutomation);
|
||||||
REGISTER_ENUM (MuteAutomation);
|
REGISTER_ENUM (MuteAutomation);
|
||||||
REGISTER_ENUM (MidiCCAutomation);
|
REGISTER_ENUM (MidiCCAutomation);
|
||||||
|
REGISTER_ENUM (MidiPgmChangeAutomation);
|
||||||
|
REGISTER_ENUM (MidiPitchBenderAutomation);
|
||||||
|
REGISTER_ENUM (MidiChannelPressureAutomation);
|
||||||
|
REGISTER_ENUM (MidiSystemExclusiveAutomation);
|
||||||
REGISTER_ENUM (FadeInAutomation);
|
REGISTER_ENUM (FadeInAutomation);
|
||||||
REGISTER_ENUM (FadeOutAutomation);
|
REGISTER_ENUM (FadeOutAutomation);
|
||||||
REGISTER_ENUM (EnvelopeAutomation);
|
REGISTER_ENUM (EnvelopeAutomation);
|
||||||
REGISTER_ENUM (SoloIsolateAutomation);
|
REGISTER_ENUM (RecEnableAutomation);
|
||||||
REGISTER_ENUM (SoloSafeAutomation);
|
REGISTER_ENUM (RecSafeAutomation);
|
||||||
|
REGISTER_ENUM (TrimAutomation);
|
||||||
REGISTER_ENUM (PhaseAutomation);
|
REGISTER_ENUM (PhaseAutomation);
|
||||||
REGISTER_ENUM (MonitoringAutomation);
|
REGISTER_ENUM (MonitoringAutomation);
|
||||||
REGISTER_ENUM (EQGain);
|
REGISTER_ENUM (EQGain);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ using namespace ARDOUR;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boost::shared_ptr<AutomationList> al)
|
GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boost::shared_ptr<AutomationList> al)
|
||||||
: AutomationControl (session, param, ParameterDescriptor(param),
|
: SlavableAutomationControl (session, param, ParameterDescriptor(param),
|
||||||
al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
|
al ? al : boost::shared_ptr<AutomationList> (new AutomationList (param)),
|
||||||
param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
|
param.type() == GainAutomation ? X_("gaincontrol") : X_("trimcontrol")) {
|
||||||
|
|
||||||
|
|
@ -44,22 +44,7 @@ GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boos
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GainControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
|
GainControl::actually_set_value (double val, 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)
|
|
||||||
{
|
{
|
||||||
val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
|
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 ()
|
be retrieved by AutomationControl::get_value ()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AutomationControl::set_value (val, group_override);
|
AutomationControl::actually_set_value (val, group_override);
|
||||||
|
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +104,23 @@ GainControl::get_user_string () const
|
||||||
return std::string(theBuf);
|
return std::string(theBuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GainControl::inc_gain (gain_t factor)
|
||||||
|
{
|
||||||
|
/* To be used ONLY when doing group-relative gain adjustment, from
|
||||||
|
* ControlGroup::set_group_values().
|
||||||
|
*/
|
||||||
|
|
||||||
|
const float desired_gain = user_double();
|
||||||
|
|
||||||
|
if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
|
||||||
|
// really?! what's the idea here?
|
||||||
|
actually_set_value (0.000001f + (0.000001f * factor), Controllable::ForGroup);
|
||||||
|
} else {
|
||||||
|
actually_set_value (desired_gain + (desired_gain * factor), Controllable::ForGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GainControl::recompute_masters_ratios (double val)
|
GainControl::recompute_masters_ratios (double val)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -583,10 +583,10 @@ LuaBindings::common (lua_State* L)
|
||||||
.addCast<MidiTrack> ("to_midi_track")
|
.addCast<MidiTrack> ("to_midi_track")
|
||||||
.addFunction ("set_name", &Track::set_name)
|
.addFunction ("set_name", &Track::set_name)
|
||||||
.addFunction ("can_record", &Track::can_record)
|
.addFunction ("can_record", &Track::can_record)
|
||||||
.addFunction ("record_enabled", &Track::record_enabled)
|
//.addFunction ("record_enabled", &Track::record_enabled)
|
||||||
.addFunction ("record_safe", &Track::record_safe)
|
//.addFunction ("record_safe", &Track::record_safe)
|
||||||
.addFunction ("set_record_enabled", &Track::set_record_enabled)
|
//.addFunction ("set_record_enabled", &Track::set_record_enabled)
|
||||||
.addFunction ("set_record_safe", &Track::set_record_safe)
|
//.addFunction ("set_record_safe", &Track::set_record_safe)
|
||||||
.addFunction ("bounceable", &Track::bounceable)
|
.addFunction ("bounceable", &Track::bounceable)
|
||||||
.addFunction ("bounce", &Track::bounce)
|
.addFunction ("bounce", &Track::bounce)
|
||||||
.addFunction ("bounce_range", &Track::bounce_range)
|
.addFunction ("bounce_range", &Track::bounce_range)
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@
|
||||||
#include "ardour/midi_port.h"
|
#include "ardour/midi_port.h"
|
||||||
#include "ardour/midi_region.h"
|
#include "ardour/midi_region.h"
|
||||||
#include "ardour/midi_track.h"
|
#include "ardour/midi_track.h"
|
||||||
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/parameter_types.h"
|
#include "ardour/parameter_types.h"
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
#include "ardour/processor.h"
|
#include "ardour/processor.h"
|
||||||
|
|
@ -103,24 +104,24 @@ MidiTrack::create_diskstream ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
bool
|
||||||
MidiTrack::set_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
|
MidiTrack::can_be_record_safe ()
|
||||||
{
|
{
|
||||||
if (_step_editing) {
|
if (_step_editing) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::set_record_enabled (yn, group_override);
|
return Track::can_be_record_safe ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
MidiTrack::set_record_safe (bool yn, Controllable::GroupControlDisposition group_override)
|
MidiTrack::can_be_record_enabled ()
|
||||||
{
|
{
|
||||||
if (_step_editing) { /* REQUIRES REVIEW */
|
if (_step_editing) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track::set_record_safe (yn, group_override);
|
return Track::can_be_record_enabled ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -372,7 +373,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
|
||||||
|
|
||||||
if (!_active) {
|
if (!_active) {
|
||||||
silence (nframes);
|
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();
|
_meter->reset();
|
||||||
}
|
}
|
||||||
return 0;
|
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 */
|
/* filter captured data before meter sees it */
|
||||||
_capture_filter.filter (bufs);
|
_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);
|
_meter->run (bufs, start_frame, end_frame, nframes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -726,22 +727,7 @@ MidiTrack::set_parameter_automation_state (Evoral::Parameter param, AutoState st
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTrack::MidiControl::set_value (double val, PBD::Controllable::GroupControlDisposition group_override)
|
MidiTrack::MidiControl::actually_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)
|
|
||||||
{
|
{
|
||||||
const Evoral::Parameter ¶meter = _list ? _list->parameter() : Control::parameter();
|
const Evoral::Parameter ¶meter = _list ? _list->parameter() : Control::parameter();
|
||||||
const Evoral::ParameterDescriptor &desc = EventTypeMap::instance().descriptor(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);
|
_route->write_immediate_event(size, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomationControl::set_value(val, group_override);
|
AutomationControl::actually_set_value(val, group_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -958,16 +944,9 @@ MidiTrack::act_on_mute ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiTrack::set_monitoring (MonitorChoice mc, Controllable::GroupControlDisposition gcd)
|
MidiTrack::monitoring_changed (bool self, Controllable::GroupControlDisposition gcd)
|
||||||
{
|
{
|
||||||
if (use_group (gcd, &RouteGroup::is_monitoring)) {
|
Track::monitoring_changed (self, gcd);
|
||||||
_route_group->apply (&Track::set_monitoring, mc, Controllable::NoGroup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mc != _monitoring) {
|
|
||||||
|
|
||||||
Track::set_monitoring (mc, gcd);
|
|
||||||
|
|
||||||
/* monitoring state changed, so flush out any on notes at the
|
/* monitoring state changed, so flush out any on notes at the
|
||||||
* port level.
|
* port level.
|
||||||
|
|
@ -988,7 +967,6 @@ MidiTrack::set_monitoring (MonitorChoice mc, Controllable::GroupControlDispositi
|
||||||
md->reset_tracker ();
|
md->reset_tracker ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MonitorState
|
MonitorState
|
||||||
MidiTrack::monitoring_state () const
|
MidiTrack::monitoring_state () const
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
const string MuteMaster::xml_node_name (X_("MuteMaster"));
|
||||||
|
|
||||||
const MuteMaster::MutePoint MuteMaster::AllPoints = MuteMaster::MutePoint(
|
const MuteMaster::MutePoint MuteMaster::AllPoints = MuteMaster::MutePoint(
|
||||||
PreFader|PostFader|Listen|Main);
|
PreFader|PostFader|Listen|Main);
|
||||||
|
|
||||||
|
|
@ -155,7 +157,7 @@ MuteMaster::set_state (const XMLNode& node, int /*version*/)
|
||||||
XMLNode&
|
XMLNode&
|
||||||
MuteMaster::get_state()
|
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 ("mute-point", enum_2_string (_mute_point));
|
||||||
node->add_property ("muted", (_muted_by_self ? X_("yes") : X_("no")));
|
node->add_property ("muted", (_muted_by_self ? X_("yes") : X_("no")));
|
||||||
return *node;
|
return *node;
|
||||||
|
|
|
||||||
|
|
@ -35,27 +35,13 @@ PanControllable::lower () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PanControllable::set_value (double v, PBD::Controllable::GroupControlDisposition group_override)
|
PanControllable::actually_set_value (double v, 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)
|
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Panner> p = owner->panner();
|
boost::shared_ptr<Panner> p = owner->panner();
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
/* no panner: just do it */
|
/* no panner: just do it */
|
||||||
AutomationControl::set_value (v, group_override);
|
AutomationControl::actually_set_value (v, group_override);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +62,7 @@ PanControllable::_set_value (double v, Controllable::GroupControlDisposition gro
|
||||||
}
|
}
|
||||||
|
|
||||||
if (can_set) {
|
if (can_set) {
|
||||||
AutomationControl::set_value (v, group_override);
|
AutomationControl::actually_set_value (v, group_override);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,7 @@ ParameterDescriptor::ParameterDescriptor(const Evoral::Parameter& parameter)
|
||||||
normal = 0.0f;
|
normal = 0.0f;
|
||||||
break;
|
break;
|
||||||
case RecEnableAutomation:
|
case RecEnableAutomation:
|
||||||
|
case RecSafeAutomation:
|
||||||
lower = 0.0;
|
lower = 0.0;
|
||||||
upper = 1.0;
|
upper = 1.0;
|
||||||
toggled = true;
|
toggled = true;
|
||||||
|
|
|
||||||
|
|
@ -2614,22 +2614,9 @@ PluginInsert::PluginControl::PluginControl (PluginInsert* p,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param val `user' value */
|
/** @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
|
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.. */
|
/* 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);
|
iasp->set_parameter (_list->parameter().id(), user_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
AutomationControl::set_value (user_val, group_override);
|
AutomationControl::actually_set_value (user_val, group_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::PluginControl::catch_up_with_external_value (double user_val)
|
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&
|
XMLNode&
|
||||||
|
|
@ -2700,15 +2687,7 @@ PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert*
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PluginInsert::PluginPropertyControl::set_value (double user_val, PBD::Controllable::GroupControlDisposition /* group_override*/)
|
PluginInsert::PluginPropertyControl::actually_set_value (double user_val, Controllable::GroupControlDisposition gcd)
|
||||||
{
|
|
||||||
if (writable()) {
|
|
||||||
set_value_unchecked (user_val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
PluginInsert::PluginPropertyControl::set_value_unchecked (double user_val)
|
|
||||||
{
|
{
|
||||||
/* Old numeric set_value(), coerce to appropriate datatype if possible.
|
/* Old numeric set_value(), coerce to appropriate datatype if possible.
|
||||||
This is lossy, but better than nothing until Ardour's automation system
|
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;
|
_value = value;
|
||||||
AutomationControl::set_value (user_val, Controllable::NoGroup);
|
|
||||||
|
AutomationControl::actually_set_value (user_val, gcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode&
|
XMLNode&
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@
|
||||||
#include "ardour/panner.h"
|
#include "ardour/panner.h"
|
||||||
#include "ardour/panner_shell.h"
|
#include "ardour/panner_shell.h"
|
||||||
#include "ardour/parameter_descriptor.h"
|
#include "ardour/parameter_descriptor.h"
|
||||||
|
#include "ardour/phase_control.h"
|
||||||
#include "ardour/plugin_insert.h"
|
#include "ardour/plugin_insert.h"
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
#include "ardour/port_insert.h"
|
#include "ardour/port_insert.h"
|
||||||
|
|
@ -67,6 +68,8 @@
|
||||||
#include "ardour/route_group.h"
|
#include "ardour/route_group.h"
|
||||||
#include "ardour/send.h"
|
#include "ardour/send.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
|
#include "ardour/solo_control.h"
|
||||||
|
#include "ardour/solo_isolate_control.h"
|
||||||
#include "ardour/unknown_processor.h"
|
#include "ardour/unknown_processor.h"
|
||||||
#include "ardour/utils.h"
|
#include "ardour/utils.h"
|
||||||
#include "ardour/vca.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) */
|
/** Base class for all routable/mixable objects (tracks and busses) */
|
||||||
Route::Route (Session& sess, string name, Flag flg, DataType default_type)
|
Route::Route (Session& sess, string name, Flag flg, DataType default_type)
|
||||||
: Stripable (sess, name)
|
: Stripable (sess, name)
|
||||||
|
, Muteable (sess, name)
|
||||||
, Automatable (sess)
|
, Automatable (sess)
|
||||||
, GraphNode (sess._process_graph)
|
, GraphNode (sess._process_graph)
|
||||||
, _active (true)
|
, _active (true)
|
||||||
|
|
@ -99,18 +103,11 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
|
||||||
, _meter_point (MeterPostFader)
|
, _meter_point (MeterPostFader)
|
||||||
, _pending_meter_point (MeterPostFader)
|
, _pending_meter_point (MeterPostFader)
|
||||||
, _meter_type (MeterPeak)
|
, _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)
|
, _denormal_protection (false)
|
||||||
, _recordable (true)
|
, _recordable (true)
|
||||||
, _silent (false)
|
, _silent (false)
|
||||||
, _declickable (false)
|
, _declickable (false)
|
||||||
, _mute_master (new MuteMaster (sess, name))
|
|
||||||
, _have_internal_generator (false)
|
, _have_internal_generator (false)
|
||||||
, _solo_safe (false)
|
|
||||||
, _default_type (default_type)
|
, _default_type (default_type)
|
||||||
, _order_key (0)
|
, _order_key (0)
|
||||||
, _has_order_key (false)
|
, _has_order_key (false)
|
||||||
|
|
@ -141,21 +138,30 @@ Route::init ()
|
||||||
|
|
||||||
/* add standard controls */
|
/* add standard controls */
|
||||||
|
|
||||||
_solo_control.reset (new SoloControllable (X_("solo"), shared_from_this ()));
|
_gain_control.reset (new GainControl (_session, GainAutomation));
|
||||||
_mute_control.reset (new MuteControllable (X_("mute"), shared_from_this ()));
|
add_control (_gain_control);
|
||||||
_phase_control.reset (new PhaseControllable (X_("phase"), shared_from_this ()));
|
|
||||||
|
|
||||||
_solo_isolate_control.reset (new SoloIsolateControllable (X_("solo-iso"), shared_from_this ()));
|
_trim_control.reset (new GainControl (_session, TrimAutomation));
|
||||||
_solo_safe_control.reset (new SoloSafeControllable (X_("solo-safe"), shared_from_this ()));
|
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));
|
_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);
|
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);
|
add_control (_mute_control);
|
||||||
|
|
||||||
|
_phase_control.reset (new PhaseControl (_session, X_("phase")));
|
||||||
add_control (_phase_control);
|
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 */
|
/* panning */
|
||||||
|
|
||||||
if (!(_flags & Route::MonitorOut)) {
|
if (!(_flags & Route::MonitorOut)) {
|
||||||
|
|
@ -177,9 +183,6 @@ Route::init ()
|
||||||
* it should be the first processor to be added on every route.
|
* 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));
|
_amp.reset (new Amp (_session, X_("Fader"), _gain_control, true));
|
||||||
add_processor (_amp, PostFader);
|
add_processor (_amp, PostFader);
|
||||||
|
|
||||||
|
|
@ -196,9 +199,6 @@ Route::init ()
|
||||||
|
|
||||||
/* and input trim */
|
/* 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.reset (new Amp (_session, X_("Trim"), _trim_control, false));
|
||||||
_trim->set_display_to_user (false);
|
_trim->set_display_to_user (false);
|
||||||
|
|
||||||
|
|
@ -398,83 +398,11 @@ Route::ensure_track_or_route_name(string name, Session &session)
|
||||||
return newname;
|
return newname;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Route::inc_gain (gain_t factor)
|
|
||||||
{
|
|
||||||
/* To be used ONLY when doing group-relative gain adjustment, from
|
|
||||||
* ::set_gain()
|
|
||||||
*/
|
|
||||||
|
|
||||||
float desired_gain = _gain_control->user_double();
|
|
||||||
|
|
||||||
if (fabsf (desired_gain) < GAIN_COEFF_SMALL) {
|
|
||||||
// really?! what's the idea here?
|
|
||||||
_gain_control->route_set_value (0.000001f + (0.000001f * factor));
|
|
||||||
} else {
|
|
||||||
_gain_control->route_set_value (desired_gain + (desired_gain * factor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Route::set_gain (gain_t val, Controllable::GroupControlDisposition gcd)
|
|
||||||
{
|
|
||||||
if (use_group (gcd, &RouteGroup::is_gain)) {
|
|
||||||
|
|
||||||
if (_route_group->is_relative()) {
|
|
||||||
|
|
||||||
gain_t usable_gain = _gain_control->get_value();
|
|
||||||
if (usable_gain < 0.000001f) {
|
|
||||||
usable_gain = 0.000001f;
|
|
||||||
}
|
|
||||||
|
|
||||||
gain_t delta = val;
|
|
||||||
if (delta < 0.000001f) {
|
|
||||||
delta = 0.000001f;
|
|
||||||
}
|
|
||||||
|
|
||||||
delta -= usable_gain;
|
|
||||||
|
|
||||||
if (delta == 0.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gain_t factor = delta / usable_gain;
|
|
||||||
|
|
||||||
if (factor > 0.0f) {
|
|
||||||
factor = _route_group->get_max_factor(factor);
|
|
||||||
if (factor == 0.0f) {
|
|
||||||
_amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
factor = _route_group->get_min_factor(factor);
|
|
||||||
if (factor == 0.0f) {
|
|
||||||
_amp->gain_control()->Changed (true, gcd); /* EMIT SIGNAL */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_route_group->foreach_route (boost::bind (&Route::inc_gain, _1, factor));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
_route_group->foreach_route (boost::bind (&Route::set_gain, _1, val, Controllable::NoGroup));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == _gain_control->get_value()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_gain_control->route_set_value (val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
|
Route::set_trim (gain_t val, Controllable::GroupControlDisposition /* group override */)
|
||||||
{
|
{
|
||||||
// TODO route group, see set_gain()
|
// TODO route group, see set_gain()
|
||||||
_trim_control->route_set_value (val);
|
// _trim_control->route_set_value (val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -551,7 +479,7 @@ Route::process_output_buffers (BufferSet& bufs,
|
||||||
DENORMAL CONTROL/PHASE INVERT
|
DENORMAL CONTROL/PHASE INVERT
|
||||||
----------------------------------------------------------------------------------------- */
|
----------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
if (_phase_invert.any ()) {
|
if (!_phase_control->none()) {
|
||||||
|
|
||||||
int chn = 0;
|
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) {
|
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
|
||||||
Sample* const sp = i->data();
|
Sample* const sp = i->data();
|
||||||
|
|
||||||
if (_phase_invert[chn]) {
|
if (_phase_control->inverted (chn)) {
|
||||||
for (pframes_t nx = 0; nx < nframes; ++nx) {
|
for (pframes_t nx = 0; nx < nframes; ++nx) {
|
||||||
sp[nx] = -sp[nx];
|
sp[nx] = -sp[nx];
|
||||||
sp[nx] += 1.0e-27f;
|
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) {
|
for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) {
|
||||||
Sample* const sp = i->data();
|
Sample* const sp = i->data();
|
||||||
|
|
||||||
if (_phase_invert[chn]) {
|
if (_phase_control->inverted (chn)) {
|
||||||
for (pframes_t nx = 0; nx < nframes; ++nx) {
|
for (pframes_t nx = 0; nx < nframes; ++nx) {
|
||||||
sp[nx] = -sp[nx];
|
sp[nx] = -sp[nx];
|
||||||
}
|
}
|
||||||
|
|
@ -808,31 +736,24 @@ Route::passthru_silence (framepos_t start_frame, framepos_t end_frame, pframes_t
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override)
|
Route::set_listen (bool yn)
|
||||||
{
|
{
|
||||||
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) {
|
if (yn) {
|
||||||
_monitor_send->activate ();
|
_monitor_send->activate ();
|
||||||
_mute_master->set_soloed_by_self (true);
|
|
||||||
} else {
|
} else {
|
||||||
_monitor_send->deactivate ();
|
_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 */
|
void
|
||||||
_solo_control->Changed (false, group_override); /* EMIT SIGNAL */
|
Route::solo_control_changed (bool, Controllable::GroupControlDisposition)
|
||||||
}
|
{
|
||||||
|
/* 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 (Config->get_solo_control_is_listen_control ()) {
|
||||||
|
set_listen (_solo_control->self_soloed());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -847,244 +768,14 @@ Route::listening_via_monitor () const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition gcd)
|
Route::push_solo_isolate_upstream (int32_t delta)
|
||||||
{
|
{
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
}
|
|
||||||
} 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 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
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 */
|
/* 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 ();
|
boost::shared_ptr<RouteList> routes = _session.get_routes ();
|
||||||
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1092,85 +783,24 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o
|
||||||
bool does_feed = feeds (*i, &sends_only);
|
bool does_feed = feeds (*i, &sends_only);
|
||||||
|
|
||||||
if (does_feed && !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
|
void
|
||||||
Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override)
|
Route::push_solo_upstream (int delta)
|
||||||
{
|
{
|
||||||
if (use_group (group_override, &RouteGroup::is_mute)) {
|
DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
|
||||||
_route_group->foreach_route (boost::bind (&Route::set_mute, _1, yn, Controllable::ForGroup));
|
for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
|
||||||
return;
|
if (i->sends_only) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
boost::shared_ptr<Route> sr (i->r.lock());
|
||||||
if (muted() != yn) {
|
if (sr) {
|
||||||
_mute_master->set_muted_by_self (yn);
|
sr->solo_control()->mod_solo_by_others_downstream (-delta);
|
||||||
/* 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 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
#if 0
|
||||||
|
|
@ -2743,8 +2373,6 @@ Route::state(bool full_state)
|
||||||
|
|
||||||
node->add_property("active", _active?"yes":"no");
|
node->add_property("active", _active?"yes":"no");
|
||||||
string p;
|
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("denormal-protection", _denormal_protection?"yes":"no");
|
||||||
node->add_property("meter-point", enum_2_string (_meter_point));
|
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);
|
snprintf (buf, sizeof (buf), "%d", _order_key);
|
||||||
node->add_property ("order-key", buf);
|
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 (_input->state (full_state));
|
||||||
node->add_child_nocopy (_output->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 ());
|
node->add_child_nocopy (_mute_master->get_state ());
|
||||||
|
|
||||||
if (full_state) {
|
if (full_state) {
|
||||||
|
|
@ -2866,7 +2485,7 @@ Route::set_state (const XMLNode& node, int version)
|
||||||
_strict_io = string_is_affirmative (prop->value());
|
_strict_io = string_is_affirmative (prop->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_master() || is_monitor() || is_auditioner()) {
|
if (!can_solo()) {
|
||||||
_mute_master->set_solo_ignore (true);
|
_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
|
// this looks up the internal instrument in processors
|
||||||
reset_instrument_info();
|
reset_instrument_info();
|
||||||
|
|
||||||
if ((prop = node.property ("self-solo")) != 0) {
|
_solo_control->set_state (node, version);
|
||||||
set_self_solo (string_is_affirmative (prop->value()));
|
_solo_safe_control->set_state (node, version);
|
||||||
}
|
_solo_isolate_control->set_state (node, version);
|
||||||
|
_mute_control->set_state (node, version);
|
||||||
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 ()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((prop = node.property (X_("denormal-protection"))) != 0) {
|
if ((prop = node.property (X_("denormal-protection"))) != 0) {
|
||||||
set_denormal_protection (string_is_affirmative (prop->value()));
|
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);
|
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);
|
_mute_master->set_state (*child, version);
|
||||||
|
|
||||||
} else if (child->name() == Automatable::xml_node_name) {
|
} 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);
|
_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) {
|
if ((prop = node.property (X_("denormal-protection"))) != 0) {
|
||||||
set_denormal_protection (string_is_affirmative (prop->value()));
|
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) {
|
if ((prop = node.property (X_("muted"))) != 0) {
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
@ -3870,11 +3452,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
|
||||||
contains ConfigurationChanged
|
contains ConfigurationChanged
|
||||||
*/
|
*/
|
||||||
configure_processors (0);
|
configure_processors (0);
|
||||||
_phase_invert.resize (_input->n_ports().n_audio ());
|
_phase_control->resize (_input->n_ports().n_audio ());
|
||||||
io_changed (); /* EMIT SIGNAL */
|
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 sbou = 0;
|
||||||
int ibou = 0;
|
int ibou = 0;
|
||||||
boost::shared_ptr<RouteList> routes = _session.get_routes ();
|
boost::shared_ptr<RouteList> routes = _session.get_routes ();
|
||||||
|
|
@ -3889,38 +3471,36 @@ Route::input_change_handler (IOChange change, void * /*src*/)
|
||||||
if ((*i)->soloed()) {
|
if ((*i)->soloed()) {
|
||||||
++sbou;
|
++sbou;
|
||||||
}
|
}
|
||||||
if ((*i)->solo_isolated()) {
|
if ((*i)->solo_isolate_control()->solo_isolated()) {
|
||||||
++ibou;
|
++ibou;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int delta = sbou - _soloed_by_others_upstream;
|
int delta = sbou - _solo_control->soloed_by_others_upstream();
|
||||||
int idelta = ibou - _solo_isolated_by_upstream;
|
int idelta = ibou - _solo_isolate_control->solo_isolated_by_upstream();
|
||||||
|
|
||||||
if (idelta < -1) {
|
if (idelta < -1) {
|
||||||
PBD::warning << string_compose (
|
PBD::warning << string_compose (
|
||||||
_("Invalid Solo-Isolate propagation: from:%1 new:%2 - old:%3 = delta:%4"),
|
_("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;
|
<< endmsg;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_soloed_by_others_upstream) {
|
if (_solo_control->soloed_by_others_upstream()) {
|
||||||
// ignore new connections (they're not propagated)
|
// ignore new connections (they're not propagated)
|
||||||
if (delta <= 0) {
|
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
|
// solo-isolate currently only propagates downstream
|
||||||
if (idelta < 0) {
|
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;
|
//_solo_isolated_by_upstream = ibou;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3933,11 +3513,11 @@ Route::input_change_handler (IOChange change, void * /*src*/)
|
||||||
bool sends_only;
|
bool sends_only;
|
||||||
bool does_feed = feeds (*i, &sends_only);
|
bool does_feed = feeds (*i, &sends_only);
|
||||||
if (delta <= 0 && does_feed && !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) {
|
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 */
|
io_changed (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_soloed_by_others_downstream) {
|
if (_solo_control->soloed_by_others_downstream()) {
|
||||||
int sbod = 0;
|
int sbod = 0;
|
||||||
/* checking all all downstream routes for
|
/* checking all all downstream routes for
|
||||||
* explicit of implict solo is a rather drastic measure,
|
* 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) {
|
if (delta <= 0) {
|
||||||
// do not allow new connections to change implicit solo (no propagation)
|
// 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
|
// Session::route_solo_changed() does not propagate indirect solo-changes
|
||||||
// propagate upstream to tracks
|
// propagate upstream to tracks
|
||||||
for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
bool sends_only;
|
bool sends_only;
|
||||||
bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
|
bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
|
||||||
if (delta != 0 && does_feed && !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>();
|
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
|
void
|
||||||
Route::set_denormal_protection (bool yn)
|
Route::set_denormal_protection (bool yn)
|
||||||
{
|
{
|
||||||
|
|
@ -4735,20 +4280,16 @@ Route::gain_control() const
|
||||||
return _gain_control;
|
return _gain_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl>
|
boost::shared_ptr<GainControl>
|
||||||
Route::trim_control() const
|
Route::trim_control() const
|
||||||
{
|
{
|
||||||
return _trim_control;
|
return _trim_control;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl>
|
boost::shared_ptr<PhaseControl>
|
||||||
Route::phase_control() const
|
Route::phase_control() const
|
||||||
{
|
{
|
||||||
if (phase_invert().size()) {
|
|
||||||
return _phase_control;
|
return _phase_control;
|
||||||
} else {
|
|
||||||
return boost::shared_ptr<PhaseControllable>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<AutomationControl>
|
boost::shared_ptr<AutomationControl>
|
||||||
|
|
@ -4841,12 +4382,6 @@ Route::has_io_processor_named (const string& name)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MuteMaster::MutePoint
|
|
||||||
Route::mute_points () const
|
|
||||||
{
|
|
||||||
return _mute_master->mute_points ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Route::set_processor_positions ()
|
Route::set_processor_positions ()
|
||||||
{
|
{
|
||||||
|
|
@ -5903,7 +5438,7 @@ Route::vca_assign (boost::shared_ptr<VCA> vca)
|
||||||
{
|
{
|
||||||
_gain_control->add_master (vca->gain_control());
|
_gain_control->add_master (vca->gain_control());
|
||||||
_solo_control->add_master (vca->solo_control());
|
_solo_control->add_master (vca->solo_control());
|
||||||
_mute_control->add_master (vca->mute_control());
|
// _mute_control->add_master (vca->mute_control());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -5913,10 +5448,48 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
|
||||||
/* unassign from all */
|
/* unassign from all */
|
||||||
_gain_control->clear_masters ();
|
_gain_control->clear_masters ();
|
||||||
_solo_control->clear_masters ();
|
_solo_control->clear_masters ();
|
||||||
_mute_control->clear_masters ();
|
//_mute_control->clear_masters ();
|
||||||
} else {
|
} else {
|
||||||
_gain_control->remove_master (vca->gain_control());
|
_gain_control->remove_master (vca->gain_control());
|
||||||
_solo_control->remove_master (vca->solo_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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/route_graph.h"
|
#include "ardour/route_graph.h"
|
||||||
|
#include "ardour/track.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
@ -195,21 +196,39 @@ struct RouteRecEnabledComparator
|
||||||
{
|
{
|
||||||
bool operator () (GraphVertex r1, GraphVertex r2) const
|
bool operator () (GraphVertex r1, GraphVertex r2) const
|
||||||
{
|
{
|
||||||
if (r1->record_enabled()) {
|
boost::shared_ptr<Track> t1 (boost::dynamic_pointer_cast<Track>(r1));
|
||||||
if (r2->record_enabled()) {
|
boost::shared_ptr<Track> t2 (boost::dynamic_pointer_cast<Track>(r2));
|
||||||
/* both rec-enabled, just use signal order */
|
|
||||||
|
if (!t1) {
|
||||||
|
if (!t2) {
|
||||||
|
/* makes no difference which is first, use signal order */
|
||||||
return r1->order_key () < r2->order_key ();
|
return r1->order_key () < r2->order_key ();
|
||||||
} else {
|
} 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;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (r2->record_enabled()) {
|
if (t2->rec_enable_control()->get_value()) {
|
||||||
/* r2 rec-enabled, r1 not rec-enabled, run r1 early */
|
/* t2 rec-enabled, t1 not rec-enabled, run t1 early */
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
/* neither rec-enabled, use signal order */
|
/* neither rec-enabled, use signal order */
|
||||||
return r1->order_key () < r2->order_key ();
|
return t1->order_key () < t2->order_key ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "ardour/amp.h"
|
#include "ardour/amp.h"
|
||||||
#include "ardour/audio_track.h"
|
#include "ardour/audio_track.h"
|
||||||
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/route_group.h"
|
#include "ardour/route_group.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
|
|
@ -96,6 +97,11 @@ RouteGroup::RouteGroup (Session& s, const string &n)
|
||||||
: SessionObject (s, n)
|
: SessionObject (s, n)
|
||||||
, routes (new RouteList)
|
, routes (new RouteList)
|
||||||
, ROUTE_GROUP_DEFAULT_PROPERTIES
|
, 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");
|
_xml_node_name = X_("RouteGroup");
|
||||||
|
|
||||||
|
|
@ -114,6 +120,12 @@ RouteGroup::RouteGroup (Session& s, const string &n)
|
||||||
|
|
||||||
RouteGroup::~RouteGroup ()
|
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();) {
|
for (RouteList::iterator i = routes->begin(); i != routes->end();) {
|
||||||
RouteList::iterator tmp = i;
|
RouteList::iterator tmp = i;
|
||||||
++tmp;
|
++tmp;
|
||||||
|
|
@ -140,6 +152,15 @@ RouteGroup::add (boost::shared_ptr<Route> r)
|
||||||
|
|
||||||
routes->push_back (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->set_route_group (this);
|
||||||
r->DropReferences.connect_same_thread (*this, boost::bind (&RouteGroup::remove_when_going_away, this, boost::weak_ptr<Route> (r)));
|
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()) {
|
if ((i = find (routes->begin(), routes->end(), r)) != routes->end()) {
|
||||||
r->set_route_group (0);
|
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);
|
routes->erase (i);
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
RouteRemoved (this, boost::weak_ptr<Route> (r)); /* EMIT SIGNAL */
|
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&
|
XMLNode&
|
||||||
RouteGroup::get_state ()
|
RouteGroup::get_state ()
|
||||||
{
|
{
|
||||||
|
|
@ -269,6 +255,8 @@ RouteGroup::set_state (const XMLNode& node, int version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_to_groups ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,6 +281,8 @@ RouteGroup::set_state_2X (const XMLNode& node, int /*version*/)
|
||||||
_color = false;
|
_color = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
push_to_groups ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,6 +293,8 @@ RouteGroup::set_gain (bool yn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_gain = yn;
|
_gain = yn;
|
||||||
|
_gain_group->set_active (yn);
|
||||||
|
|
||||||
send_change (PropertyChange (Properties::gain));
|
send_change (PropertyChange (Properties::gain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,6 +305,7 @@ RouteGroup::set_mute (bool yn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_mute = yn;
|
_mute = yn;
|
||||||
|
_mute_group->set_active (yn);
|
||||||
send_change (PropertyChange (Properties::mute));
|
send_change (PropertyChange (Properties::mute));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,6 +316,7 @@ RouteGroup::set_solo (bool yn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_solo = yn;
|
_solo = yn;
|
||||||
|
_solo_group->set_active (yn);
|
||||||
send_change (PropertyChange (Properties::solo));
|
send_change (PropertyChange (Properties::solo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,6 +327,7 @@ RouteGroup::set_recenable (bool yn)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_recenable = yn;
|
_recenable = yn;
|
||||||
|
_rec_enable_group->set_active (yn);
|
||||||
send_change (PropertyChange (Properties::recenable));
|
send_change (PropertyChange (Properties::recenable));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -384,6 +379,8 @@ RouteGroup::set_monitoring (bool yn)
|
||||||
}
|
}
|
||||||
|
|
||||||
_monitoring = yn;
|
_monitoring = yn;
|
||||||
|
_monitoring_group->set_active (yn);
|
||||||
|
|
||||||
send_change (PropertyChange (Properties::monitoring));
|
send_change (PropertyChange (Properties::monitoring));
|
||||||
|
|
||||||
_session.set_dirty ();
|
_session.set_dirty ();
|
||||||
|
|
@ -531,3 +528,19 @@ RouteGroup::enabled_property (PBD::PropertyID prop)
|
||||||
|
|
||||||
return dynamic_cast<const PropertyTemplate<bool>* > (i->second)->val ();
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,7 @@
|
||||||
#include "ardour/session_directory.h"
|
#include "ardour/session_directory.h"
|
||||||
#include "ardour/session_playlists.h"
|
#include "ardour/session_playlists.h"
|
||||||
#include "ardour/smf_source.h"
|
#include "ardour/smf_source.h"
|
||||||
|
#include "ardour/solo_isolate_control.h"
|
||||||
#include "ardour/source_factory.h"
|
#include "ardour/source_factory.h"
|
||||||
#include "ardour/speakers.h"
|
#include "ardour/speakers.h"
|
||||||
#include "ardour/tempo.h"
|
#include "ardour/tempo.h"
|
||||||
|
|
@ -1506,7 +1507,7 @@ Session::set_track_monitor_input_status (bool yn)
|
||||||
boost::shared_ptr<RouteList> rl = routes.reader ();
|
boost::shared_ptr<RouteList> rl = routes.reader ();
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||||
boost::shared_ptr<AudioTrack> tr = boost::dynamic_pointer_cast<AudioTrack> (*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;
|
//cerr << "switching to input = " << !auto_input << __FILE__ << __LINE__ << endl << endl;
|
||||||
tr->request_input_monitoring (yn);
|
tr->request_input_monitoring (yn);
|
||||||
}
|
}
|
||||||
|
|
@ -1941,14 +1942,8 @@ void
|
||||||
Session::set_all_tracks_record_enabled (bool enable )
|
Session::set_all_tracks_record_enabled (bool enable )
|
||||||
{
|
{
|
||||||
boost::shared_ptr<RouteList> rl = routes.reader();
|
boost::shared_ptr<RouteList> rl = routes.reader();
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), enable, Controllable::NoGroup);
|
||||||
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
|
|
||||||
if (tr) {
|
|
||||||
tr->set_record_enabled (enable, Controllable::NoGroup);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::disable_record (bool rt_context, bool force)
|
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 for Stereo Out mode
|
||||||
// 0 Multi Out mode
|
// 0 Multi Out mode
|
||||||
if (Config->get_output_auto_connect() & AutoConnectMaster) {
|
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) {
|
if (tr) {
|
||||||
tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (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));
|
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);
|
boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
|
||||||
if (mt) {
|
if (mt) {
|
||||||
|
|
@ -3580,7 +3575,7 @@ Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*iter)->set_solo (false, Controllable::NoGroup);
|
(*iter)->solo_control()->set_value (0.0, Controllable::NoGroup);
|
||||||
|
|
||||||
rs->remove (*iter);
|
rs->remove (*iter);
|
||||||
|
|
||||||
|
|
@ -3721,7 +3716,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
|
||||||
continue;
|
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 */
|
/* route does not get solo propagated to it */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -3734,7 +3729,7 @@ Session::route_listen_changed (Controllable::GroupControlDisposition group_overr
|
||||||
*/
|
*/
|
||||||
continue;
|
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;
|
bool send_changed = false;
|
||||||
|
|
||||||
if (route->solo_isolated()) {
|
if (route->solo_isolate_control()->solo_isolated()) {
|
||||||
if (_solo_isolated_cnt == 0) {
|
if (_solo_isolated_cnt == 0) {
|
||||||
send_changed = true;
|
send_changed = true;
|
||||||
}
|
}
|
||||||
|
|
@ -3838,7 +3833,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
|
||||||
continue;
|
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 */
|
/* route does not get solo propagated to it */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -3852,7 +3847,7 @@ Session::route_solo_changed (bool self_solo_change, Controllable::GroupControlDi
|
||||||
continue;
|
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;
|
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 */
|
/* route does not get solo propagated to it */
|
||||||
continue;
|
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()));
|
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tthere is a feed from %1\n", (*i)->name()));
|
||||||
if (!via_sends_only) {
|
if (!via_sends_only) {
|
||||||
if (!route->soloed_by_others_upstream()) {
|
if (!route->soloed_by_others_upstream()) {
|
||||||
(*i)->mod_solo_by_others_downstream (delta);
|
(*i)->solo_control()->mod_solo_by_others_downstream (delta);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_TRACE (DEBUG::Solo, "\talready soloed by others upstream\n");
|
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) {
|
if (!via_sends_only) {
|
||||||
//NB. Triggers Invert Push, which handles soloed by downstream
|
//NB. Triggers Invert Push, which handles soloed by downstream
|
||||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tmod %1 by %2\n", (*i)->name(), delta));
|
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 {
|
} else {
|
||||||
DEBUG_TRACE (DEBUG::Solo, string_compose ("\tfeed to %1 ignored, sends-only\n", (*i)->name()));
|
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) {
|
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;
|
something_soloed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3978,11 +3973,11 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
|
||||||
listeners++;
|
listeners++;
|
||||||
something_listening = true;
|
something_listening = true;
|
||||||
} else {
|
} else {
|
||||||
(*i)->set_listen (false, Controllable::NoGroup);
|
(*i)->set_listen (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*i)->solo_isolated()) {
|
if ((*i)->solo_isolate_control()->solo_isolated()) {
|
||||||
isolated++;
|
isolated++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6078,7 +6073,7 @@ Session::update_route_record_state ()
|
||||||
while (i != rl->end ()) {
|
while (i != rl->end ()) {
|
||||||
|
|
||||||
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6095,7 +6090,7 @@ Session::update_route_record_state ()
|
||||||
|
|
||||||
for (i = rl->begin(); i != rl->end (); ++i) {
|
for (i = rl->begin(); i != rl->end (); ++i) {
|
||||||
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6124,12 +6119,7 @@ void
|
||||||
Session::solo_control_mode_changed ()
|
Session::solo_control_mode_changed ()
|
||||||
{
|
{
|
||||||
/* cancel all solo or all listen when solo control mode changes */
|
/* cancel all solo or all listen when solo control mode changes */
|
||||||
|
clear_all_solo_state (get_routes());
|
||||||
if (soloing()) {
|
|
||||||
set_solo (get_routes(), false);
|
|
||||||
} else if (listening()) {
|
|
||||||
set_listen (get_routes(), false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a property of one of our route groups changes */
|
/** Called when a property of one of our route groups changes */
|
||||||
|
|
|
||||||
|
|
@ -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 ((at = dynamic_cast<AudioTrack*>((*i).get())) != 0) {
|
||||||
if (trk == at->remote_control_id()) {
|
if (trk == at->remote_control_id()) {
|
||||||
at->set_record_enabled (enabled, Controllable::UseGroup);
|
at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,9 @@
|
||||||
#include "pbd/error.h"
|
#include "pbd/error.h"
|
||||||
#include "pbd/compose.h"
|
#include "pbd/compose.h"
|
||||||
|
|
||||||
#include "ardour/session.h"
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
|
#include "ardour/session.h"
|
||||||
#include "ardour/track.h"
|
#include "ardour/track.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
@ -33,26 +34,26 @@ using namespace ARDOUR;
|
||||||
using namespace Glib;
|
using namespace Glib;
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::set_monitoring (boost::shared_ptr<RouteList> rl, MonitorChoice mc,
|
Session::set_controls (boost::shared_ptr<ControlList> cl, double val, Controllable::GroupControlDisposition gcd)
|
||||||
SessionEvent::RTeventCallback after,
|
|
||||||
Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
{
|
||||||
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
|
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) {
|
boost::shared_ptr<ControlList> cl (new ControlList);
|
||||||
if (!(*i)->is_auditioner()) {
|
cl->push_back (ac);
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*i);
|
set_controls (cl, val, gcd);
|
||||||
if (t) {
|
|
||||||
t->set_monitoring (mc, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
void
|
||||||
|
|
@ -73,224 +74,6 @@ Session::rt_clear_all_solo_state (boost::shared_ptr<RouteList> rl, bool /* yn */
|
||||||
set_dirty();
|
set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after,
|
|
||||||
Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_solo (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_auditioner()) {
|
|
||||||
(*i)->set_solo (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
|
|
||||||
/* XXX boost::shared_ptr<RouteList> goes out of scope here and is likley free()ed in RT context
|
|
||||||
* because boost's shared_ptr does reference counting and free/delete in the dtor.
|
|
||||||
* (this also applies to other rt_ methods here)
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, SessionEvent::RTeventCallback after,
|
|
||||||
Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
queue_event (get_rt_event (rl, delta, upstream, after, group_override, &Session::rt_set_implicit_solo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_implicit_solo (boost::shared_ptr<RouteList> rl, int delta, bool upstream, PBD::Controllable::GroupControlDisposition)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_auditioner()) {
|
|
||||||
if (upstream) {
|
|
||||||
std::cerr << "Changing " << (*i)->name() << " upstream by " << delta << std::endl;
|
|
||||||
(*i)->mod_solo_by_others_upstream (delta);
|
|
||||||
} else {
|
|
||||||
std::cerr << "Changing " << (*i)->name() << " downstream by " << delta << std::endl;
|
|
||||||
(*i)->mod_solo_by_others_downstream (delta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
|
|
||||||
/* XXX boost::shared_ptr<RouteList> goes out of scope here and is likley free()ed in RT context
|
|
||||||
* because boost's shared_ptr does reference counting and free/delete in the dtor.
|
|
||||||
* (this also applies to other rt_ methods here)
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, SessionEvent::RTeventCallback after)
|
|
||||||
{
|
|
||||||
/* its a bit silly to have to do this, but it keeps the API for this public method sane (we're
|
|
||||||
only going to solo one route) and keeps our ability to use get_rt_event() for the internal
|
|
||||||
private method.
|
|
||||||
*/
|
|
||||||
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
|
||||||
rl->push_back (r);
|
|
||||||
|
|
||||||
queue_event (get_rt_event (rl, yn, after, Controllable::NoGroup, &Session::rt_set_just_one_solo));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, Controllable::GroupControlDisposition /*ignored*/)
|
|
||||||
{
|
|
||||||
boost::shared_ptr<RouteList> rl = routes.reader ();
|
|
||||||
boost::shared_ptr<Route> r = just_one->front();
|
|
||||||
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_auditioner() && r != *i) {
|
|
||||||
(*i)->set_solo (!yn, Controllable::NoGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r->set_solo (yn, Controllable::NoGroup);
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_listen));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_listen (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_auditioner()) {
|
|
||||||
(*i)->set_listen (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
/* Set superficial value of mute controls for automation. */
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
boost::shared_ptr<Route::MuteControllable> mc = boost::dynamic_pointer_cast<Route::MuteControllable> ((*i)->mute_control());
|
|
||||||
mc->set_superficial_value(yn);
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_mute));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_mute (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_monitor() && !(*i)->is_auditioner()) {
|
|
||||||
(*i)->set_mute (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_solo_isolated));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_solo_isolated (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if (!(*i)->is_master() && !(*i)->is_monitor() && !(*i)->is_auditioner()) {
|
|
||||||
(*i)->set_solo_isolated (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
if (!writable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do the non-RT part of rec-enabling first - the RT part will be done
|
|
||||||
* on the next process cycle. This does mean that theoretically we are
|
|
||||||
* doing things provisionally on the assumption that the rec-enable
|
|
||||||
* change will work, but this had better be a solid assumption for
|
|
||||||
* other reasons.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if ((*i)->is_auditioner() || (*i)->record_safe ()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Track> t;
|
|
||||||
|
|
||||||
if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
|
|
||||||
t->prep_record_enabled (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_record_enabled (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
|
||||||
if ((*i)->is_auditioner() || (*i)->record_safe ()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Track> t;
|
|
||||||
|
|
||||||
if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
|
|
||||||
t->set_record_enabled (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty ();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, SessionEvent::RTeventCallback after, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
set_record_enabled (rl, false, after, group_override);
|
|
||||||
queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_safe));
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Session::rt_set_record_safe (boost::shared_ptr<RouteList> rl, bool yn, Controllable::GroupControlDisposition group_override)
|
|
||||||
{
|
|
||||||
for (RouteList::iterator i = rl->begin (); i != rl->end (); ++i) {
|
|
||||||
if ((*i)->is_auditioner ()) { // REQUIRES REVIEW Can audiotioner be in Record Safe mode?
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Track> t;
|
|
||||||
|
|
||||||
if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
|
|
||||||
t->set_record_safe (yn, group_override);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_dirty ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Session::process_rtop (SessionEvent* ev)
|
Session::process_rtop (SessionEvent* ev)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
|
||||||
boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*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
|
// tell it we've looped, so it can deal with the record state
|
||||||
tr->transport_looped (_transport_frame);
|
tr->transport_looped (_transport_frame);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,11 @@
|
||||||
#include "ardour/diskstream.h"
|
#include "ardour/diskstream.h"
|
||||||
#include "ardour/io_processor.h"
|
#include "ardour/io_processor.h"
|
||||||
#include "ardour/meter.h"
|
#include "ardour/meter.h"
|
||||||
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/playlist.h"
|
#include "ardour/playlist.h"
|
||||||
#include "ardour/port.h"
|
#include "ardour/port.h"
|
||||||
#include "ardour/processor.h"
|
#include "ardour/processor.h"
|
||||||
|
#include "ardour/record_enable_control.h"
|
||||||
#include "ardour/route_group_specialized.h"
|
#include "ardour/route_group_specialized.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/session_playlists.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)
|
: Route (sess, name, flag, default_type)
|
||||||
, _saved_meter_point (_meter_point)
|
, _saved_meter_point (_meter_point)
|
||||||
, _mode (mode)
|
, _mode (mode)
|
||||||
, _monitoring (MonitorAuto)
|
|
||||||
{
|
{
|
||||||
_freeze_record.state = NoFreeze;
|
_freeze_record.state = NoFreeze;
|
||||||
_declickable = true;
|
_declickable = true;
|
||||||
|
|
@ -62,16 +63,23 @@ Track::init ()
|
||||||
|
|
||||||
boost::shared_ptr<Route> rp (shared_from_this());
|
boost::shared_ptr<Route> rp (shared_from_this());
|
||||||
boost::shared_ptr<Track> rt = boost::dynamic_pointer_cast<Track> (rp);
|
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
|
_record_enable_control.reset (new RecordEnableControl (_session, X_("recenable"), *this));
|
||||||
* appear as an automatable parameter
|
_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));
|
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));
|
_session.config.ParameterChanged.connect_same_thread (*this, boost::bind (&Track::parameter_changed, this, _1));
|
||||||
|
|
||||||
|
_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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,9 +105,7 @@ XMLNode&
|
||||||
Track::state (bool full)
|
Track::state (bool full)
|
||||||
{
|
{
|
||||||
XMLNode& root (Route::state (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_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 ());
|
root.add_child_nocopy (_diskstream->get_state ());
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
|
|
@ -137,19 +143,13 @@ Track::set_state (const XMLNode& node, int version)
|
||||||
XMLProperty const * prop;
|
XMLProperty const * prop;
|
||||||
if (child->name() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) {
|
if (child->name() == Controllable::xml_node_name && (prop = child->property ("name")) != 0) {
|
||||||
if (prop->value() == X_("recenable")) {
|
if (prop->value() == X_("recenable")) {
|
||||||
_rec_enable_control->set_state (*child, version);
|
_record_enable_control->set_state (*child, version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLProperty const * prop;
|
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) {
|
if ((prop = node.property (X_("saved-meter-point"))) != 0) {
|
||||||
_saved_meter_point = MeterPoint (string_2_enum (prop->value(), _saved_meter_point));
|
_saved_meter_point = MeterPoint (string_2_enum (prop->value(), _saved_meter_point));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -178,62 +178,6 @@ Track::freeze_state() const
|
||||||
return _freeze_record.state;
|
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
|
bool
|
||||||
Track::can_record()
|
Track::can_record()
|
||||||
{
|
{
|
||||||
|
|
@ -246,24 +190,15 @@ Track::can_record()
|
||||||
return will_record;
|
return will_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
Track::prep_record_enabled (bool yn, Controllable::GroupControlDisposition group_override)
|
Track::prep_record_enabled (bool yn)
|
||||||
{
|
{
|
||||||
if (yn && record_safe ()) {
|
if (yn && _record_safe_control->get_value()) {
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_session.writable()) {
|
if (!can_be_record_enabled()) {
|
||||||
return;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
if (_freeze_record.state == Frozen) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (use_group (group_override, &RouteGroup::is_recenable)) {
|
|
||||||
_route_group->apply (&Track::prep_record_enabled, yn, Controllable::NoGroup);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* keep track of the meter point as it was before we rec-enabled */
|
/* 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);
|
set_meter_point (_saved_meter_point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Track::set_record_enabled (bool yn, Controllable::GroupControlDisposition gcd)
|
Track::record_enable_changed (bool, Controllable::GroupControlDisposition)
|
||||||
{
|
{
|
||||||
if (_diskstream->record_safe ()) {
|
_diskstream->set_record_enabled (_record_enable_control->get_value());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_session.writable()) {
|
void
|
||||||
return;
|
Track::record_safe_changed (bool, Controllable::GroupControlDisposition)
|
||||||
}
|
{
|
||||||
|
_diskstream->set_record_safe (_record_safe_control->get_value());
|
||||||
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);
|
|
||||||
|
|
||||||
_rec_enable_control->Changed (true, gcd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
@ -336,12 +260,7 @@ Track::set_record_safe (bool yn, Controllable::GroupControlDisposition group_ove
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_group (group_override, &RouteGroup::is_recenable)) {
|
_rec_safe_control->set_value (yn, group_override);
|
||||||
_route_group->apply (&Track::set_record_safe, yn, Controllable::NoGroup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_diskstream->set_record_safe (yn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -371,7 +290,7 @@ Track::set_name (const string& str)
|
||||||
{
|
{
|
||||||
bool ret;
|
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 */
|
/* this messes things up if done while recording */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -452,7 +371,7 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
|
||||||
|
|
||||||
if (!_active) {
|
if (!_active) {
|
||||||
silence (nframes);
|
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();
|
_meter->reset();
|
||||||
}
|
}
|
||||||
return 0;
|
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));
|
ds->PlaylistChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_playlist_changed, this));
|
||||||
diskstream_playlist_changed ();
|
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->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));
|
ds->AlignmentStyleChanged.connect_same_thread (*this, boost::bind (&Track::diskstream_alignment_style_changed, this));
|
||||||
}
|
}
|
||||||
|
|
@ -623,18 +540,6 @@ Track::diskstream_playlist_changed ()
|
||||||
PlaylistChanged (); /* EMIT SIGNAL */
|
PlaylistChanged (); /* EMIT SIGNAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
Track::diskstream_record_enable_changed ()
|
|
||||||
{
|
|
||||||
RecordEnableChanged (); /* EMIT SIGNAL */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Track::diskstream_record_safe_changed ()
|
|
||||||
{
|
|
||||||
RecordSafeChanged (); /* EMIT SIGNAL */
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Track::diskstream_speed_changed ()
|
Track::diskstream_speed_changed ()
|
||||||
{
|
{
|
||||||
|
|
@ -1014,12 +919,13 @@ MonitorState
|
||||||
Track::monitoring_state () const
|
Track::monitoring_state () const
|
||||||
{
|
{
|
||||||
/* Explicit requests */
|
/* Explicit requests */
|
||||||
|
MonitorChoice m (_monitoring_control->monitoring_choice());
|
||||||
|
|
||||||
if (_monitoring & MonitorInput) {
|
if (m & MonitorInput) {
|
||||||
return MonitoringInput;
|
return MonitoringInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_monitoring & MonitorDisk) {
|
if (m & MonitorDisk) {
|
||||||
return MonitoringDisk;
|
return MonitoringDisk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1086,7 +992,7 @@ Track::maybe_declick (BufferSet& bufs, framecnt_t nframes, int declick)
|
||||||
ditto if we are monitoring inputs.
|
ditto if we are monitoring inputs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (_have_internal_generator || monitoring_choice() == MonitorInput) {
|
if (_have_internal_generator || (_monitoring_control->monitoring_choice() == MonitorInput)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1136,23 +1042,11 @@ Track::check_initial_delay (framecnt_t nframes, framepos_t& transport_frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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) {
|
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
(*i)->monitoring_changed ();
|
(*i)->monitoring_changed ();
|
||||||
}
|
}
|
||||||
|
|
||||||
MonitoringChanged (); /* EMIT SIGNAL */
|
|
||||||
_monitoring_control->Changed (true, gcd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MeterState
|
MeterState
|
||||||
|
|
@ -1161,64 +1055,10 @@ Track::metering_state () const
|
||||||
bool rv;
|
bool rv;
|
||||||
if (_session.transport_rolling ()) {
|
if (_session.transport_rolling ()) {
|
||||||
// audio_track.cc || midi_track.cc roll() runs meter IFF:
|
// 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 {
|
} else {
|
||||||
// track no_roll() always metering if
|
// track no_roll() always metering if
|
||||||
rv = _meter_point == MeterInput;
|
rv = _meter_point == MeterInput;
|
||||||
}
|
}
|
||||||
return rv ? MeteringInput : MeteringRoute;
|
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();
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -754,3 +754,4 @@ ARDOUR::slider_position_to_gain_with_max (double g, double max_gain)
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void c_stacktrace() { stacktrace (cerr); }
|
void c_stacktrace() { stacktrace (cerr); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ VCA::get_next_vca_number ()
|
||||||
|
|
||||||
VCA::VCA (Session& s, uint32_t num, const string& name)
|
VCA::VCA (Session& s, uint32_t num, const string& name)
|
||||||
: Stripable (s, name)
|
: Stripable (s, name)
|
||||||
|
, Muteable (s, name)
|
||||||
, Automatable (s)
|
, Automatable (s)
|
||||||
, _number (num)
|
, _number (num)
|
||||||
, _gain_control (new GainControl (s, Evoral::Parameter (GainAutomation), boost::shared_ptr<AutomationList> ()))
|
, _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
|
int
|
||||||
VCA::init ()
|
VCA::init ()
|
||||||
{
|
{
|
||||||
_solo_control.reset (new VCASoloControllable (X_("solo"), shared_from_this()));
|
_solo_control.reset (new SoloControl (_session, X_("solo"), *this, *this));
|
||||||
_mute_control.reset (new VCAMuteControllable (X_("mute"), shared_from_this()));
|
_mute_control.reset (new MuteControl (_session, X_("mute"), *this));
|
||||||
|
|
||||||
add_control (_gain_control);
|
add_control (_gain_control);
|
||||||
add_control (_solo_control);
|
add_control (_solo_control);
|
||||||
|
|
@ -159,98 +160,3 @@ VCA::muted () const
|
||||||
{
|
{
|
||||||
return _mute_requested;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ libardour_sources = [
|
||||||
'chan_count.cc',
|
'chan_count.cc',
|
||||||
'chan_mapping.cc',
|
'chan_mapping.cc',
|
||||||
'config_text.cc',
|
'config_text.cc',
|
||||||
|
'control_group.cc',
|
||||||
'control_protocol_manager.cc',
|
'control_protocol_manager.cc',
|
||||||
'cycle_timer.cc',
|
'cycle_timer.cc',
|
||||||
'data_type.cc',
|
'data_type.cc',
|
||||||
|
|
@ -137,12 +138,15 @@ libardour_sources = [
|
||||||
'midi_stretch.cc',
|
'midi_stretch.cc',
|
||||||
'midi_track.cc',
|
'midi_track.cc',
|
||||||
'midi_ui.cc',
|
'midi_ui.cc',
|
||||||
|
'mididm.cc',
|
||||||
'midiport_manager.cc',
|
'midiport_manager.cc',
|
||||||
'mix.cc',
|
'mix.cc',
|
||||||
|
'monitor_control.cc',
|
||||||
'monitor_processor.cc',
|
'monitor_processor.cc',
|
||||||
'mtc_slave.cc',
|
'mtc_slave.cc',
|
||||||
'mididm.cc',
|
|
||||||
'mtdm.cc',
|
'mtdm.cc',
|
||||||
|
'muteable.cc',
|
||||||
|
'mute_control.cc',
|
||||||
'mute_master.cc',
|
'mute_master.cc',
|
||||||
'note_fixer.cc',
|
'note_fixer.cc',
|
||||||
'onset_detector.cc',
|
'onset_detector.cc',
|
||||||
|
|
@ -154,6 +158,7 @@ libardour_sources = [
|
||||||
'panner_shell.cc',
|
'panner_shell.cc',
|
||||||
'parameter_descriptor.cc',
|
'parameter_descriptor.cc',
|
||||||
'pcm_utils.cc',
|
'pcm_utils.cc',
|
||||||
|
'phase_control.cc',
|
||||||
'playlist.cc',
|
'playlist.cc',
|
||||||
'playlist_factory.cc',
|
'playlist_factory.cc',
|
||||||
'playlist_source.cc',
|
'playlist_source.cc',
|
||||||
|
|
@ -170,13 +175,13 @@ libardour_sources = [
|
||||||
'quantize.cc',
|
'quantize.cc',
|
||||||
'rc_configuration.cc',
|
'rc_configuration.cc',
|
||||||
'recent_sessions.cc',
|
'recent_sessions.cc',
|
||||||
|
'record_enable_control.cc',
|
||||||
'region_factory.cc',
|
'region_factory.cc',
|
||||||
'resampled_source.cc',
|
'resampled_source.cc',
|
||||||
'region.cc',
|
'region.cc',
|
||||||
'return.cc',
|
'return.cc',
|
||||||
'reverse.cc',
|
'reverse.cc',
|
||||||
'route.cc',
|
'route.cc',
|
||||||
'route_controls.cc',
|
|
||||||
'route_graph.cc',
|
'route_graph.cc',
|
||||||
'route_group.cc',
|
'route_group.cc',
|
||||||
'route_group_member.cc',
|
'route_group_member.cc',
|
||||||
|
|
@ -206,10 +211,14 @@ libardour_sources = [
|
||||||
'session_transport.cc',
|
'session_transport.cc',
|
||||||
'sidechain.cc',
|
'sidechain.cc',
|
||||||
'slave.cc',
|
'slave.cc',
|
||||||
|
'slavable_automation_control.cc',
|
||||||
'smf_source.cc',
|
'smf_source.cc',
|
||||||
'sndfile_helpers.cc',
|
'sndfile_helpers.cc',
|
||||||
'sndfileimportable.cc',
|
'sndfileimportable.cc',
|
||||||
'sndfilesource.cc',
|
'sndfilesource.cc',
|
||||||
|
'solo_control.cc',
|
||||||
|
'solo_isolate_control.cc',
|
||||||
|
'solo_safe_control.cc',
|
||||||
'soundcloud_upload.cc',
|
'soundcloud_upload.cc',
|
||||||
'source.cc',
|
'source.cc',
|
||||||
'source_factory.cc',
|
'source_factory.cc',
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class LIBPBD_API Controllable : public PBD::StatefulDestructible {
|
||||||
enum Flag {
|
enum Flag {
|
||||||
Toggle = 0x1,
|
Toggle = 0x1,
|
||||||
GainLike = 0x2,
|
GainLike = 0x2,
|
||||||
|
RealTime = 0x4
|
||||||
};
|
};
|
||||||
|
|
||||||
Controllable (const std::string& name, Flag f = Flag (0));
|
Controllable (const std::string& name, Flag f = Flag (0));
|
||||||
|
|
|
||||||
|
|
@ -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);
|
boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
|
||||||
|
|
||||||
if (at) {
|
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);
|
boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(r);
|
||||||
|
|
||||||
if (at) {
|
if (at) {
|
||||||
return at->record_enabled ();
|
return at->rec_enable_control()->get_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
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];
|
boost::shared_ptr<Route> r = route_table[table_index];
|
||||||
|
|
||||||
if (r != 0) {
|
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 false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r->muted ();
|
return r->mute_control()->muted ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -311,7 +311,7 @@ ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
|
||||||
boost::shared_ptr<Route> r = route_table[table_index];
|
boost::shared_ptr<Route> r = route_table[table_index];
|
||||||
|
|
||||||
if (r != 0) {
|
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];
|
boost::shared_ptr<Route> r = route_table[table_index];
|
||||||
|
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
r->set_solo (yn, Controllable::UseGroup);
|
r->solo_control()->set_value (yn ? 1.0 : 0.0, Controllable::UseGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
|
||||||
single route at a time, allow the fader to
|
single route at a time, allow the fader to
|
||||||
modify the group, if appropriate.
|
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);
|
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
|
||||||
if (t) {
|
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 ();
|
boost::shared_ptr<AutomationControl> control = _current_route->gain_control ();
|
||||||
|
|
@ -1227,7 +1227,7 @@ FaderPort::map_mute ()
|
||||||
if (_current_route->muted()) {
|
if (_current_route->muted()) {
|
||||||
stop_blinking (Mute);
|
stop_blinking (Mute);
|
||||||
get_button (Mute).set_led_state (_output_port, true);
|
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);
|
start_blinking (Mute);
|
||||||
} else {
|
} else {
|
||||||
stop_blinking (Mute);
|
stop_blinking (Mute);
|
||||||
|
|
@ -1252,7 +1252,7 @@ FaderPort::map_recenable ()
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
|
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (_current_route);
|
||||||
if (t) {
|
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 {
|
} else {
|
||||||
get_button (Rec).set_led_state (_output_port, false);
|
get_button (Rec).set_led_state (_output_port, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,9 +129,9 @@ FaderPort::mute ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
boost::shared_ptr<ControlList> cl (new ControlList);
|
||||||
rl->push_back (_current_route);
|
cl->push_back (_current_route->mute_control());
|
||||||
session->set_mute (rl, !_current_route->muted());
|
session->set_controls (cl, !_current_route->muted(), PBD::Controllable::UseGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -141,14 +141,15 @@ FaderPort::solo ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
bool yn;
|
||||||
rl->push_back (_current_route);
|
|
||||||
|
|
||||||
if (Config->get_solo_control_is_listen_control()) {
|
if (Config->get_solo_control_is_listen_control()) {
|
||||||
session->set_listen (rl, !_current_route->listening_via_monitor());
|
yn = !_current_route->listening_via_monitor();
|
||||||
} else {
|
} 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
|
void
|
||||||
|
|
@ -164,10 +165,7 @@ FaderPort::rec_enable ()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<RouteList> rl (new RouteList);
|
t->rec_enable_control()->set_value (!t->rec_enable_control()->get_value(), Controllable::UseGroup);
|
||||||
rl->push_back (_current_route);
|
|
||||||
|
|
||||||
session->set_record_enabled (rl, !t->record_enabled());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -888,13 +888,7 @@ MackieControlProtocol::clearsolo_press (Mackie::Button&)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
if (session->soloing()) {
|
session->clear_all_solo_state (session->get_routes());
|
||||||
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
|
|
||||||
}
|
}
|
||||||
return none;
|
return none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,17 @@
|
||||||
#include "ardour/debug.h"
|
#include "ardour/debug.h"
|
||||||
#include "ardour/midi_ui.h"
|
#include "ardour/midi_ui.h"
|
||||||
#include "ardour/meter.h"
|
#include "ardour/meter.h"
|
||||||
|
#include "ardour/monitor_control.h"
|
||||||
#include "ardour/plugin_insert.h"
|
#include "ardour/plugin_insert.h"
|
||||||
#include "ardour/pannable.h"
|
#include "ardour/pannable.h"
|
||||||
#include "ardour/panner.h"
|
#include "ardour/panner.h"
|
||||||
#include "ardour/panner_shell.h"
|
#include "ardour/panner_shell.h"
|
||||||
|
#include "ardour/phase_control.h"
|
||||||
#include "ardour/rc_configuration.h"
|
#include "ardour/rc_configuration.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/session.h"
|
#include "ardour/session.h"
|
||||||
#include "ardour/send.h"
|
#include "ardour/send.h"
|
||||||
|
#include "ardour/solo_isolate_control.h"
|
||||||
#include "ardour/track.h"
|
#include "ardour/track.h"
|
||||||
#include "ardour/midi_track.h"
|
#include "ardour/midi_track.h"
|
||||||
#include "ardour/user_bundle.h"
|
#include "ardour/user_bundle.h"
|
||||||
|
|
@ -302,7 +305,10 @@ void
|
||||||
Strip::notify_record_enable_changed ()
|
Strip::notify_record_enable_changed ()
|
||||||
{
|
{
|
||||||
if (_route && _recenable) {
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -974,7 +974,7 @@ OSC::routes_list (lo_message msg)
|
||||||
|| boost::dynamic_pointer_cast<MidiTrack>(r)) {
|
|| boost::dynamic_pointer_cast<MidiTrack>(r)) {
|
||||||
|
|
||||||
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(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
|
//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);
|
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
r->set_mute (yn, PBD::Controllable::NoGroup);
|
r->mute_control()->set_value (yn ? 1.0 : 0.0, PBD::Controllable::NoGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -1068,7 +1068,7 @@ OSC::route_solo (int rid, int yn)
|
||||||
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
||||||
|
|
||||||
if (r) {
|
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;
|
return 0;
|
||||||
|
|
@ -1082,7 +1082,10 @@ OSC::route_recenable (int rid, int yn)
|
||||||
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
||||||
|
|
||||||
if (r) {
|
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;
|
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);
|
boost::shared_ptr<Route> r = session->route_by_remote_id (rid);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
r->set_gain (level, PBD::Controllable::NoGroup);
|
r->gain_control()->set_value (level, PBD::Controllable::NoGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue