summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/ardour_ui.cc10
-rw-r--r--gtk2_ardour/editor_routes.cc12
-rw-r--r--gtk2_ardour/gain_meter.cc10
-rw-r--r--gtk2_ardour/route_ui.cc422
-rw-r--r--gtk2_ardour/route_ui.h25
-rw-r--r--libs/ardour/ardour/session.h104
-rw-r--r--libs/ardour/ardour/session_event.h5
-rw-r--r--libs/ardour/session.cc65
-rw-r--r--libs/ardour/session_command.cc425
-rw-r--r--libs/ardour/session_process.cc8
-rw-r--r--libs/ardour/session_rtevents.cc169
-rw-r--r--libs/ardour/session_state.cc92
-rw-r--r--libs/ardour/wscript1
-rw-r--r--libs/gtkmm2ext/gtk_ui.cc6
-rw-r--r--libs/pbd/base_ui.cc3
-rw-r--r--libs/pbd/pbd/base_ui.h10
-rw-r--r--libs/pbd/pbd/ui_callback.h47
-rw-r--r--libs/pbd/ui_callback.cc6
-rw-r--r--libs/pbd/wscript1
19 files changed, 439 insertions, 982 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc
index a4675f4a21..89abd1d3cc 100644
--- a/gtk2_ardour/ardour_ui.cc
+++ b/gtk2_ardour/ardour_ui.cc
@@ -113,6 +113,16 @@ sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
+void gui_rt_cleanup (SessionEvent* ev)
+{
+ /* a little helper function that makes sure we delete queued SessionEvents in the correct thread */
+ ENSURE_GUI_THREAD (bind (sigc::ptr_fun (&gui_rt_cleanup), ev));
+ delete ev;
+}
+
+/* wrap the above as a slot so that we can pass it to the session when queuing RT events */
+const sigc::slot<void,SessionEvent*> gui_rt_cleanup_slot (sigc::ptr_fun (&gui_rt_cleanup));
+
ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
: Gtkmm2ext::UI (X_("gui"), argcp, argvp),
diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc
index 100c552be7..9cd5231d41 100644
--- a/gtk2_ardour/editor_routes.cc
+++ b/gtk2_ardour/editor_routes.cc
@@ -170,7 +170,9 @@ EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
if (atv != 0 && atv->is_audio_track()){
- atv->reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !atv->track()->record_enabled(), this);
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (atv->route());
+ _session->set_record_enable (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
}
}
@@ -184,7 +186,9 @@ EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
if (atv != 0) {
- atv->reversibly_apply_route_boolean ("mute-enable change", &Route::set_mute, !atv->route()->muted(), this);
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (atv->route());
+ _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
}
}
@@ -198,7 +202,9 @@ EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
if (atv != 0) {
- atv->reversibly_apply_route_boolean ("solo-enable change", &Route::set_solo, !atv->route()->soloed(), this);
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (atv->route());
+ _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
}
}
diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc
index 95e41b5ee6..4bd8aee03a 100644
--- a/gtk2_ardour/gain_meter.cc
+++ b/gtk2_ardour/gain_meter.cc
@@ -519,12 +519,7 @@ GainMeterBase::meter_press(GdkEventButton* ev)
/* Primary+Tertiary-click applies change to all routes */
- _session.begin_reversible_command (_("meter point change"));
- Session::GlobalMeteringStateCommand *cmd = new Session::GlobalMeteringStateCommand (_session, this);
_session.foreach_route (this, &GainMeterBase::set_meter_point, next_meter_point (_route->meter_point()));
- cmd->mark();
- _session.add_command (cmd);
- _session.commit_reversible_command ();
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
@@ -534,12 +529,7 @@ GainMeterBase::meter_press(GdkEventButton* ev)
*/
if (ev->button == 1) {
- _session.begin_reversible_command (_("meter point change"));
- Session::GlobalMeteringStateCommand *cmd = new Session::GlobalMeteringStateCommand (_session, this);
set_mix_group_meter_point (*_route, next_meter_point (_route->meter_point()));
- cmd->mark();
- _session.add_command (cmd);
- _session.commit_reversible_command ();
}
} else {
diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc
index 821b82a0b6..f233314188 100644
--- a/gtk2_ardour/route_ui.cc
+++ b/gtk2_ardour/route_ui.cc
@@ -103,7 +103,8 @@ RouteUI::init ()
listen_mute_check = 0;
main_mute_check = 0;
ignore_toggle = false;
- wait_for_release = false;
+ _solo_release = 0;
+ _mute_release = 0;
route_active_menu_item = 0;
polarity_menu_item = 0;
denormal_menu_item = 0;
@@ -229,12 +230,14 @@ RouteUI::set_route (boost::shared_ptr<Route> rp)
}
bool
-RouteUI::mute_press(GdkEventButton* ev)
+RouteUI::mute_press (GdkEventButton* ev)
{
if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
return true;
}
+
multiple_mute_change = false;
+
if (!ignore_toggle) {
if (Keyboard::is_context_menu_event (ev)) {
@@ -251,51 +254,50 @@ RouteUI::mute_press(GdkEventButton* ev)
// Primary-button2 click is the midi binding click
// button2-click is "momentary"
- if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
- wait_for_release = true;
- } else {
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
return false;
}
+
+ _mute_release = new SoloMuteRelease (_route->muted ());
}
if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
-#if 0
- /* Primary-Tertiary-click applies change to all routes */
+ if (_mute_release) {
+ _mute_release->routes = _session.get_routes ();
+ }
- _session.begin_reversible_command (_("mute change"));
- Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
- _session.set_mute (!_route->muted());
- cmd->mark();
- _session.add_command(cmd);
- _session.commit_reversible_command ();
- multiple_mute_change = true;
-#endif
+ _session.set_mute (_session.get_routes(), !_route->muted());
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-#if 0
- /* Primary-button1 applies change to the mix group.
+ /* Primary-button1 applies change to the mix group even if it is not active
NOTE: Primary-button2 is MIDI learn.
*/
- if (ev->button == 1) {
- set_route_group_mute (_route, !_route->muted());
+ if (ev->button == 1 && _route->route_group()) {
+ if (_mute_release) {
+ _mute_release->routes = _session.get_routes ();
+ }
+
+ _session.set_mute (_session.get_routes(), !_route->muted(), Session::rt_cleanup, true);
}
-#endif
} else {
-#if 0
/* plain click applies change to this route */
- if (wait_for_release) {
- _route->set_mute (!_route->muted(), this);
- } else {
- reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
+
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (_route);
+
+ if (_mute_release) {
+ _mute_release->routes = rl;
}
-#endif
+
+ _session.set_mute (rl, !_route->muted());
+
}
}
}
@@ -306,36 +308,19 @@ RouteUI::mute_press(GdkEventButton* ev)
}
bool
-RouteUI::mute_release(GdkEventButton*)
+RouteUI::mute_release (GdkEventButton*)
{
if (!ignore_toggle) {
- if (wait_for_release){
- wait_for_release = false;
- if (multiple_mute_change) {
- multiple_mute_change = false;
- // undo the last op
- // because the press was the last undoable thing we did
- _session.undo (1U);
- } else {
- _route->set_mute (!_route->muted(), this);
- }
+ if (_mute_release){
+ _session.set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
+ delete _mute_release;
+ _mute_release = 0;
}
}
+
return true;
}
-void
-RouteUI::post_solo_cleanup (SessionEvent* ev, bool was_not_latched)
-{
- ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_solo_cleanup), ev, was_not_latched));
-
- delete ev;
-
- if (was_not_latched) {
- Config->set_solo_latched (false);
- }
-}
-
bool
RouteUI::solo_press(GdkEventButton* ev)
{
@@ -344,106 +329,115 @@ RouteUI::solo_press(GdkEventButton* ev)
if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
return true;
}
+
+ multiple_solo_change = false;
- if (Config->get_solo_control_is_listen_control()) {
-
- _route->set_listen (!_route->listening(), this);
-
- } else {
-
- multiple_solo_change = false;
- if (!ignore_toggle) {
-
- if (Keyboard::is_context_menu_event (ev)) {
-
- if (solo_menu == 0) {
- build_solo_menu ();
+ if (!ignore_toggle) {
+
+ if (Keyboard::is_context_menu_event (ev)) {
+
+ if (solo_menu == 0) {
+ build_solo_menu ();
+ }
+
+ solo_menu->popup (1, ev->time);
+
+ } else {
+
+ if (Keyboard::is_button2_event (ev)) {
+
+ // Primary-button2 click is the midi binding click
+ // button2-click is "momentary"
+
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
+ return false;
}
- solo_menu->popup (1, ev->time);
-
- } else {
-
- if (Keyboard::is_button2_event (ev)) {
-
- // Primary-button2 click is the midi binding click
- // button2-click is "momentary"
+ _solo_release = new SoloMuteRelease (_route->soloed());
+ }
+
+ if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
+
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
+
+ /* Primary-Tertiary-click applies change to all routes */
- if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
- wait_for_release = true;
+ if (_solo_release) {
+ _solo_release->routes = _session.get_routes ();
+ }
+
+ if (Config->get_solo_control_is_listen_control()) {
+ _session.set_listen (_session.get_routes(), !_route->listening(), Session::rt_cleanup, true);
} else {
- return false;
+ _session.set_solo (_session.get_routes(), !_route->soloed(), Session::rt_cleanup, true);
}
- }
-
- if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
-
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
-
- /* Primary-Tertiary-click applies change to all routes */
- bool was_not_latched = false;
-
- if (!Config->get_solo_latched ()) {
- was_not_latched = true;
- /*
- XXX it makes no sense to solo all tracks if we're
- not in latched mode, but doing nothing feels like a bug,
- so do it anyway
- */
- Config->set_solo_latched (true);
+
+ } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
+
+ // Primary-Secondary-click: exclusively solo this track
+
+ if (_solo_release) {
+ _solo_release->exclusive = true;
+
+ boost::shared_ptr<RouteList> routes = _session.get_routes();
+
+ for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+ if ((*i)->soloed ()) {
+ _solo_release->routes_on->push_back (*i);
+ } else {
+ _solo_release->routes_off->push_back (*i);
+ }
}
+ }
+
+ if (Config->get_solo_control_is_listen_control()) {
+ /* ??? we need a just_one_listen() method */
+ } else {
+ _session.set_just_one_solo (_route, true);
+ }
- SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
- ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), _session.get_routes(), !_route->soloed());
- ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_solo_cleanup), was_not_latched);
-
- _session.queue_event (ev);
-
- } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
-
- // Primary-Secondary-click: exclusively solo this track, not a toggle */
-
- //boost::shared_ptr<RouteList> rl (new RouteList);
- //rl->push_back (route());
-
- //SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
- // ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_just_one_solo), rl, true);
- //ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
-
- //_session.queue_event (ev);
-
- } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
-
- // shift-click: toggle solo isolated status
-
- _route->set_solo_isolated (!_route->solo_isolated(), this);
- wait_for_release = false;
-
- } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-
-#if 0
- /* Primary-button1: solo mix group.
- NOTE: Primary-button2 is MIDI learn.
- */
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
+
+ // shift-click: toggle solo isolated status
+
+ _route->set_solo_isolated (!_route->solo_isolated(), this);
+ delete _solo_release;
+ _solo_release = 0;
+
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+
+ /* Primary-button1: solo mix group.
+ NOTE: Primary-button2 is MIDI learn.
+ */
+
+ if (ev->button == 1 && _route->route_group()) {
- if (ev->button == 1) {
- queue_route_group_op (RouteGroup::Solo, &Session::set_all_solo, !_route->soloed());
+ if (_solo_release) {
+ _solo_release->routes = _route->route_group()->route_list();
}
-#endif
-
+
+ if (Config->get_solo_control_is_listen_control()) {
+ _session.set_listen (_route->route_group()->route_list(), !_route->listening(), Session::rt_cleanup, true);
+ } else {
+ _session.set_solo (_route->route_group()->route_list(), !_route->soloed(), Session::rt_cleanup, true);
+ }
+ }
+
+ } else {
+
+ /* click: solo this route */
+
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (route());
+
+ if (_solo_release) {
+ _solo_release->routes = rl;
+ }
+ if (Config->get_solo_control_is_listen_control()) {
+ _session.set_listen (rl, !_route->listening());
} else {
-
- /* click: solo this route */
-
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (route());
-
- SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
- ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), rl, !rec_enable_button->get_active());
- ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
-
- _session.queue_event (ev);
+ _session.set_solo (rl, !_route->soloed());
}
}
}
@@ -454,73 +448,26 @@ RouteUI::solo_press(GdkEventButton* ev)
}
bool
-RouteUI::solo_release(GdkEventButton*)
+RouteUI::solo_release (GdkEventButton*)
{
if (!ignore_toggle) {
- if (wait_for_release) {
- wait_for_release = false;
- if (multiple_solo_change) {
- multiple_solo_change = false;
- // undo the last op
- // because the press was the last undoable thing we did
- _session.undo (1U);
+
+ if (_solo_release) {
+
+ if (_solo_release->exclusive) {
+
} else {
- // we don't use "undo the last op"
- // here because its expensive for the GUI
- _route->set_solo (!_route->soloed(), this);
+ _session.set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
}
+
+ delete _solo_release;
+ _solo_release = 0;
}
}
return true;
}
-void
-RouteUI::post_rtop_cleanup (SessionEvent* ev)
-{
- ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_rtop_cleanup), ev));
- delete ev;
-}
-
-void
-RouteUI::post_group_rtop_cleanup (SessionEvent* ev, RouteGroup* rg, RouteGroup::Property prop)
-{
- ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_group_rtop_cleanup), ev, rg, prop));
- delete ev;
- rg->set_property (prop, false);
-}
-
-void
-RouteUI::queue_route_group_op (RouteGroup::Property prop, void (Session::*session_method)(boost::shared_ptr<RouteList>, bool), bool yn)
-{
- RouteGroup* rg = _route->route_group();
- bool prop_was_active;
-
- if (rg) {
- prop_was_active = rg->active_property (prop);
- rg->set_property (prop, true);
- } else {
- prop_was_active = false;
- }
-
- /* we will queue the op for just this route, but because its route group now has the relevant property marked active,
- the operation will apply to the whole group (if there is a group)
- */
-
- boost::shared_ptr<RouteList> rl (new RouteList);
- rl->push_back (route());
-
- SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
- ev->rt_slot = bind (sigc::mem_fun (_session, session_method), rl, yn);
- if (rg && !prop_was_active) {
- ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_group_rtop_cleanup), rg, prop);
- } else {
- ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
- }
-
- _session.queue_event (ev);
-}
-
bool
RouteUI::rec_enable_press(GdkEventButton* ev)
{
@@ -543,21 +490,16 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
-#if 0
- _session.set_record_enable (_session.get_route(), !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
-#endif
+ _session.set_record_enable (_session.get_routes(), !rec_enable_button->get_active());
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
/* Primary-button1 applies change to the route group (even if it is not active)
NOTE: Primary-button2 is MIDI learn.
*/
-#if 0
if (ev->button == 1 && _route->route_group()) {
- _session.set_record_enable (_route->route_group(), !rec_enable_button->get_active(),
- queue_route_group_op (RouteGroup::RecEnable, &Session::set_record_enable,
+ _session.set_record_enable (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
}
-#endif
} else if (Keyboard::is_context_menu_event (ev)) {
@@ -565,11 +507,9 @@ RouteUI::rec_enable_press(GdkEventButton* ev)
} else {
-#if 0
boost::shared_ptr<RouteList> rl (new RouteList);
rl->push_back (route());
- _session.set_record_enable (rl, !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
-#endif
+ _session.set_record_enable (rl, !rec_enable_button->get_active());
}
}
@@ -1018,80 +958,6 @@ RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
_route->set_solo_safe (check->get_active(), this);
}
-void
-RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
-{
- RouteGroup* route_group;
-
- if((route_group = route->route_group()) != 0){
- _session.begin_reversible_command (_("mix group solo change"));
- Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
- route_group->apply(&Route::set_solo, yn, this);
- cmd->mark();
- _session.add_command (cmd);
- _session.commit_reversible_command ();
- } else {
- reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
- }
-}
-
-void
-RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
-{
- _session.begin_reversible_command (name);
- XMLNode &before = _route->get_state();
- bind(mem_fun(*_route, func), yn, arg)();
- XMLNode &after = _route->get_state();
- _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
- _session.commit_reversible_command ();
-}
-
-void
-RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
-{
- _session.begin_reversible_command (name);
- XMLNode &before = track()->get_state();
- bind (mem_fun (*track(), func), yn, arg)();
- XMLNode &after = track()->get_state();
- _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
- _session.commit_reversible_command ();
-}
-
-void
-RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
-{
- RouteGroup* route_group;
-
- if((route_group = route->route_group()) != 0){
- _session.begin_reversible_command (_("mix group mute change"));
- Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
- route_group->apply(&Route::set_mute, yn, this);
- cmd->mark();
- _session.add_command(cmd);
- _session.commit_reversible_command ();
- } else {
- reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
- }
-}
-
-void
-RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
-{
- RouteGroup* route_group;
-
- if((route_group = route->route_group()) != 0){
- _session.begin_reversible_command (_("mix group rec-enable change"));
- Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
- route_group->apply (&Route::set_record_enable, yn, this);
- cmd->mark();
- _session.add_command(cmd);
- _session.commit_reversible_command ();
- } else {
- reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
- }
-}
-
-
bool
RouteUI::choose_color()
{
diff --git a/gtk2_ardour/route_ui.h b/gtk2_ardour/route_ui.h
index 90bdaa7fb7..c38a4aac6d 100644
--- a/gtk2_ardour/route_ui.h
+++ b/gtk2_ardour/route_ui.h
@@ -155,10 +155,6 @@ class RouteUI : public virtual AxisView
void build_mute_menu(void);
void init_mute_menu(ARDOUR::MuteMaster::MutePoint, Gtk::CheckMenuItem*);
- void set_route_group_solo (boost::shared_ptr<ARDOUR::Route>, bool);
- void set_route_group_mute (boost::shared_ptr<ARDOUR::Route>, bool);
- void set_route_group_rec_enable (boost::shared_ptr<ARDOUR::Route>, bool);
-
int set_color_from_route ();
void remove_this_route ();
@@ -191,9 +187,6 @@ class RouteUI : public virtual AxisView
virtual void map_frozen ();
- void reversibly_apply_route_boolean (std::string name, void (ARDOUR::Route::*func)(bool, void*), bool, void *);
- void reversibly_apply_track_boolean (std::string name, void (ARDOUR::Track::*func)(bool, void*), bool, void *);
-
void adjust_latency ();
void save_as_template ();
void open_remote_control_id_dialog ();
@@ -215,9 +208,21 @@ class RouteUI : public virtual AxisView
void parameter_changed (std::string const &);
void relabel_solo_button ();
- void post_rtop_cleanup (ARDOUR::SessionEvent* ev);
- void post_group_rtop_cleanup (ARDOUR::SessionEvent* ev, ARDOUR::RouteGroup*, ARDOUR::RouteGroup::Property);
- void post_solo_cleanup (ARDOUR::SessionEvent* ev, bool was_not_latched);
+ struct SoloMuteRelease {
+ SoloMuteRelease (bool was_active)
+ : active (was_active)
+ , exclusive (false) {}
+
+ boost::shared_ptr<ARDOUR::RouteList> routes;
+ boost::shared_ptr<ARDOUR::RouteList> routes_on;
+ boost::shared_ptr<ARDOUR::RouteList> routes_off;
+ boost::shared_ptr<ARDOUR::Route> route;
+ bool active;
+ bool exclusive;
+ };
+
+ SoloMuteRelease* _solo_release;
+ SoloMuteRelease* _mute_release;
};
#endif /* __ardour_route_ui__ */
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 4e1721bae0..c4f101ce5c 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -122,12 +122,6 @@ extern void setup_enum_writer ();
class Session : public PBD::StatefulDestructible, public SessionEventManager, public boost::noncopyable
{
- private:
- typedef std::pair<boost::weak_ptr<Route>,bool> RouteBooleanState;
- typedef std::vector<RouteBooleanState> GlobalRouteBooleanState;
- typedef std::pair<boost::weak_ptr<Route>,MeterPoint> RouteMeterState;
- typedef std::vector<RouteMeterState> GlobalRouteMeterState;
-
public:
enum RecordState {
Disabled = 0,
@@ -617,14 +611,17 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
bool soloing() const { return _non_soloed_outs_muted; }
bool listening() const { return _listen_cnt > 0; }
- void set_solo (boost::shared_ptr<RouteList>, bool);
- void set_mute (boost::shared_ptr<RouteList>, bool);
- void set_listen (boost::shared_ptr<RouteList>, bool);
+ static const sigc::slot<void,SessionEvent*> rt_cleanup;
+
+ void set_solo (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
+ void set_just_one_solo (boost::shared_ptr<Route>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup);
+ void set_mute (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
+ void set_listen (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
+ void set_record_enable (boost::shared_ptr<RouteList>, bool, sigc::slot<void,SessionEvent*> after = rt_cleanup, bool group_override = false);
sigc::signal<void,bool> SoloActive;
sigc::signal<void> SoloChanged;
- void set_record_enable (boost::shared_ptr<RouteList>, bool);
/* control/master out */
@@ -735,73 +732,6 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
Command* memento_command_factory(XMLNode* n);
void register_with_memento_command_factory(PBD::ID, PBD::StatefulThingWithGoingAway*);
- Command* global_state_command_factory (const XMLNode& n);
-
- class GlobalRouteStateCommand : public Command
- {
- public:
- GlobalRouteStateCommand (Session&, void*);
- GlobalRouteStateCommand (Session&, const XMLNode& node);
- int set_state (const XMLNode&, int version);
- XMLNode& get_state ();
-
- protected:
- GlobalRouteBooleanState before, after;
- Session& sess;
- void* src;
- };
-
- class GlobalSoloStateCommand : public GlobalRouteStateCommand
- {
- public:
- GlobalSoloStateCommand (Session &, void *src);
- GlobalSoloStateCommand (Session&, const XMLNode&);
- void operator()(); //redo
- void undo();
- XMLNode &get_state();
- void mark();
- };
-
- class GlobalMuteStateCommand : public GlobalRouteStateCommand
- {
- public:
- GlobalMuteStateCommand(Session &, void *src);
- GlobalMuteStateCommand (Session&, const XMLNode&);
- void operator()(); // redo
- void undo();
- XMLNode &get_state();
- void mark();
- };
-
- class GlobalRecordEnableStateCommand : public GlobalRouteStateCommand
- {
- public:
- GlobalRecordEnableStateCommand(Session &, void *src);
- GlobalRecordEnableStateCommand (Session&, const XMLNode&);
- void operator()(); // redo
- void undo();
- XMLNode &get_state();
- void mark();
- };
-
- class GlobalMeteringStateCommand : public Command
- {
- public:
- GlobalMeteringStateCommand(Session &, void *src);
- GlobalMeteringStateCommand (Session&, const XMLNode&);
- void operator()();
- void undo();
- XMLNode &get_state();
- int set_state (const XMLNode&, int version);
- void mark();
-
- protected:
- Session& sess;
- void* src;
- GlobalRouteMeterState before;
- GlobalRouteMeterState after;
- };
-
/* clicking */
boost::shared_ptr<IO> click_io() { return _click_io; }
@@ -1443,16 +1373,6 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
UndoHistory _history;
std::stack<UndoTransaction*> _current_trans;
- GlobalRouteBooleanState get_global_route_boolean (bool (Route::*method)(void) const);
- GlobalRouteMeterState get_global_route_metering ();
-
- void set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void *arg);
- void set_global_route_metering (GlobalRouteMeterState s, void *arg);
-
- void set_global_mute (GlobalRouteBooleanState s, void *src);
- void set_global_solo (GlobalRouteBooleanState s, void *src);
- void set_global_record_enable (GlobalRouteBooleanState s, void *src);
-
void jack_timebase_callback (jack_transport_state_t, nframes_t, jack_position_t*, int);
int jack_sync_callback (jack_transport_state_t, jack_position_t*);
void reset_jack_connection (jack_client_t* jack);
@@ -1549,6 +1469,16 @@ class Session : public PBD::StatefulDestructible, public SessionEventManager, pu
void update_have_rec_enabled_diskstream ();
gint _have_rec_enabled_diskstream;
+
+ /* realtime "apply to set of routes" operations */
+ SessionEvent* get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override,
+ void (Session::*method) (boost::shared_ptr<RouteList>, bool, bool));
+
+ void rt_set_solo (boost::shared_ptr<RouteList>, bool yn, bool group_override);
+ void rt_set_just_one_solo (boost::shared_ptr<RouteList>, bool yn, bool /* ignored*/ );
+ void rt_set_mute (boost::shared_ptr<RouteList>, bool yn, bool group_override);
+ void rt_set_listen (boost::shared_ptr<RouteList>, bool yn, bool group_override);
+ void rt_set_record_enable (boost::shared_ptr<RouteList>, bool yn, bool group_override);
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h
index 7775f4b1ad..bb5b5f49ce 100644
--- a/libs/ardour/ardour/session_event.h
+++ b/libs/ardour/ardour/session_event.h
@@ -7,6 +7,7 @@
#include "pbd/pool.h"
#include "pbd/ringbuffer.h"
+#include "pbd/ui_callback.h"
#include "ardour/types.h"
@@ -68,6 +69,7 @@ struct SessionEvent {
boost::shared_ptr<RouteList> routes;
sigc::slot<void> rt_slot; /* what to call in RT context */
sigc::slot<void,SessionEvent*> rt_return; /* called after rt_slot, with this event as an argument */
+ PBD::UICallback* ui;
std::list<AudioRange> audio_range;
std::list<MusicRange> music_range;
@@ -81,7 +83,8 @@ struct SessionEvent {
, target_frame (where)
, speed (spd)
, yes_or_no (yn)
- , second_yes_or_no (yn2) {}
+ , second_yes_or_no (yn2)
+ , ui (0) {}
void set_ptr (void* p) {
ptr = p;
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index 0bf161bb5d..24700b8893 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -117,6 +117,9 @@ sigc::signal<void> Session::AutoBindingOn;
sigc::signal<void> Session::AutoBindingOff;
sigc::signal<void, std::string, std::string> Session::Exported;
+static void clean_up_session_event (SessionEvent* ev) { delete ev; }
+const sigc::slot<void,SessionEvent*> Session::rt_cleanup (sigc::ptr_fun (&clean_up_session_event));
+
Session::Session (AudioEngine &eng,
const string& fullpath,
const string& snapshot_name,
@@ -3515,42 +3518,6 @@ Session::is_auditioning () const
}
}
-void
-Session::set_solo (boost::shared_ptr<RouteList> r, bool yn)
-{
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_hidden()) {
- (*i)->set_solo (yn, this);
- }
- }
-
- set_dirty();
-}
-
-void
-Session::set_listen (boost::shared_ptr<RouteList> r, bool yn)
-{
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_hidden()) {
- (*i)->set_listen (yn, this);
- }
- }
-
- set_dirty();
-}
-
-void
-Session::set_mute (boost::shared_ptr<RouteList> r, bool yn)
-{
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_hidden()) {
- (*i)->set_mute (yn, this);
- }
- }
-
- set_dirty();
-}
-
uint32_t
Session::n_diskstreams () const
{
@@ -3597,32 +3564,6 @@ Session::graph_reordered ()
}
void
-Session::set_record_enable (boost::shared_ptr<RouteList> rl, bool yn)
-{
- if (!writable()) {
- return;
- }
-
- for (RouteList::iterator i = rl->begin(); i != rl->end(); ) {
- boost::shared_ptr<Track> t;
-
- if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
- t->set_record_enable (yn, this);
- if (t->meter_point() == MeterCustom) {
- /* don't change metering for this track */
- i = rl->erase (i);
- } else {
- ++i;
- }
- } else {
- ++i;
- }
- }
-
- set_dirty ();
-}
-
-void
Session::add_processor (Processor* processor)
{
processor->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_processor), processor));
diff --git a/libs/ardour/session_command.cc b/libs/ardour/session_command.cc
index d1ce09cbf6..4d733264fb 100644
--- a/libs/ardour/session_command.cc
+++ b/libs/ardour/session_command.cc
@@ -124,428 +124,3 @@ Session::memento_command_factory(XMLNode *n)
return 0 ;
}
-Command *
-Session::global_state_command_factory (const XMLNode& node)
-{
- const XMLProperty* prop;
- Command* command = 0;
-
- if ((prop = node.property ("type")) == 0) {
- error << _("GlobalRouteStateCommand has no \"type\" node, ignoring") << endmsg;
- return 0;
- }
-
- try {
-
- if (prop->value() == "solo") {
- command = new GlobalSoloStateCommand (*this, node);
- } else if (prop->value() == "mute") {
- command = new GlobalMuteStateCommand (*this, node);
- } else if (prop->value() == "rec-enable") {
- command = new GlobalRecordEnableStateCommand (*this, node);
- } else if (prop->value() == "metering") {
- command = new GlobalMeteringStateCommand (*this, node);
- } else {
- error << string_compose (_("unknown type of GlobalRouteStateCommand (%1), ignored"), prop->value()) << endmsg;
- }
- }
-
- catch (failed_constructor& err) {
- return 0;
- }
-
- return command;
-}
-
-Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, void* p)
- : sess (s), src (p)
-{
-}
-
-Session::GlobalRouteStateCommand::GlobalRouteStateCommand (Session& s, const XMLNode& node)
- : sess (s), src (this)
-{
- if (set_state (node, Stateful::loading_state_version)) {
- throw failed_constructor ();
- }
-}
-
-int
-Session::GlobalRouteStateCommand::set_state (const XMLNode& node, int /*version*/)
-{
- GlobalRouteBooleanState states;
- XMLNodeList nlist;
- const XMLProperty* prop;
- XMLNode* child;
- XMLNodeConstIterator niter;
- int loop;
-
- before.clear ();
- after.clear ();
-
- for (loop = 0; loop < 2; ++loop) {
-
- const char *str;
-
- if (loop) {
- str = "after";
- } else {
- str = "before";
- }
-
- if ((child = node.child (str)) == 0) {
- warning << string_compose (_("global route state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
- return -1;
- }
-
- nlist = child->children();
-
- for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
- RouteBooleanState rbs;
- boost::shared_ptr<Route> route;
- ID id;
-
- prop = (*niter)->property ("id");
- id = prop->value ();
-
- if ((route = sess.route_by_id (id)) == 0) {
- warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
- continue;
- }
-
- rbs.first = boost::weak_ptr<Route> (route);
-
- prop = (*niter)->property ("yn");
- rbs.second = (prop->value() == "1");
-
- if (loop) {
- after.push_back (rbs);
- } else {
- before.push_back (rbs);
- }
- }
- }
-
- return 0;
-}
-
-XMLNode&
-Session::GlobalRouteStateCommand::get_state ()
-{
- XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
- XMLNode* nbefore = new XMLNode (X_("before"));
- XMLNode* nafter = new XMLNode (X_("after"));
-
- for (Session::GlobalRouteBooleanState::iterator x = before.begin(); x != before.end(); ++x) {
- XMLNode* child = new XMLNode ("s");
- boost::shared_ptr<Route> r = x->first.lock();
-
- if (r) {
- child->add_property (X_("id"), r->id().to_s());
- child->add_property (X_("yn"), (x->second ? "1" : "0"));
- nbefore->add_child_nocopy (*child);
- }
- }
-
- for (Session::GlobalRouteBooleanState::iterator x = after.begin(); x != after.end(); ++x) {
- XMLNode* child = new XMLNode ("s");
- boost::shared_ptr<Route> r = x->first.lock();
-
- if (r) {
- child->add_property (X_("id"), r->id().to_s());
- child->add_property (X_("yn"), (x->second ? "1" : "0"));
- nafter->add_child_nocopy (*child);
- }
- }
-
- node->add_child_nocopy (*nbefore);
- node->add_child_nocopy (*nafter);
-
- return *node;
-}
-
-// solo
-
-Session::GlobalSoloStateCommand::GlobalSoloStateCommand(Session &sess, void *src)
- : GlobalRouteStateCommand (sess, src)
-{
- after = before = sess.get_global_route_boolean(&Route::soloed);
-}
-
-Session::GlobalSoloStateCommand::GlobalSoloStateCommand (Session& sess, const XMLNode& node)
- : Session::GlobalRouteStateCommand (sess, node)
-{
-}
-
-void
-Session::GlobalSoloStateCommand::mark()
-{
- after = sess.get_global_route_boolean(&Route::soloed);
-}
-
-void
-Session::GlobalSoloStateCommand::operator()()
-{
- sess.set_global_solo(after, src);
-}
-
-void
-Session::GlobalSoloStateCommand::undo()
-{
- sess.set_global_solo(before, src);
-}
-
-XMLNode&
-Session::GlobalSoloStateCommand::get_state()
-{
- XMLNode& node = GlobalRouteStateCommand::get_state();
- node.add_property ("type", "solo");
- return node;
-}
-
-// mute
-Session::GlobalMuteStateCommand::GlobalMuteStateCommand(Session &sess, void *src)
- : GlobalRouteStateCommand (sess, src)
-{
- after = before = sess.get_global_route_boolean(&Route::muted);
-}
-
-Session::GlobalMuteStateCommand::GlobalMuteStateCommand (Session& sess, const XMLNode& node)
- : Session::GlobalRouteStateCommand (sess, node)
-{
-}
-
-void
-Session::GlobalMuteStateCommand::mark()
-{
- after = sess.get_global_route_boolean(&Route::muted);
-}
-
-void
-Session::GlobalMuteStateCommand::operator()()
-{
- sess.set_global_mute(after, src);
-}
-
-void
-Session::GlobalMuteStateCommand::undo()
-{
- sess.set_global_mute(before, src);
-}
-
-XMLNode&
-Session::GlobalMuteStateCommand::get_state()
-{
- XMLNode& node = GlobalRouteStateCommand::get_state();
- node.add_property ("type", "mute");
- return node;
-}
-
-// record enable
-Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand(Session &sess, void *src)
- : GlobalRouteStateCommand (sess, src)
-{
- after = before = sess.get_global_route_boolean(&Route::record_enabled);
-}
-
-Session::GlobalRecordEnableStateCommand::GlobalRecordEnableStateCommand (Session& sess, const XMLNode& node)
- : Session::GlobalRouteStateCommand (sess, node)
-{
-}
-
-void
-Session::GlobalRecordEnableStateCommand::mark()
-{
- after = sess.get_global_route_boolean(&Route::record_enabled);
-}
-
-void
-Session::GlobalRecordEnableStateCommand::operator()()
-{
- sess.set_global_record_enable(after, src);
-}
-
-void
-Session::GlobalRecordEnableStateCommand::undo()
-{
- sess.set_global_record_enable(before, src);
-}
-
-XMLNode&
-Session::GlobalRecordEnableStateCommand::get_state()
-{
- XMLNode& node = GlobalRouteStateCommand::get_state();
- node.add_property ("type", "rec-enable");
- return node;
-}
-
-// metering
-Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand(Session &s, void *p)
- : sess (s), src (p)
-{
- after = before = sess.get_global_route_metering();
-}
-
-Session::GlobalMeteringStateCommand::GlobalMeteringStateCommand (Session& s, const XMLNode& node)
- : sess (s), src (this)
-{
- if (set_state (node, Stateful::loading_state_version)) {
- throw failed_constructor();
- }
-}
-
-void
-Session::GlobalMeteringStateCommand::mark()
-{
- after = sess.get_global_route_metering();
-}
-
-void
-Session::GlobalMeteringStateCommand::operator()()
-{
- sess.set_global_route_metering(after, src);
-}
-
-void
-Session::GlobalMeteringStateCommand::undo()
-{
- sess.set_global_route_metering(before, src);
-}
-
-XMLNode&
-Session::GlobalMeteringStateCommand::get_state()
-{
- XMLNode* node = new XMLNode (X_("GlobalRouteStateCommand"));
- XMLNode* nbefore = new XMLNode (X_("before"));
- XMLNode* nafter = new XMLNode (X_("after"));
-
- for (Session::GlobalRouteMeterState::iterator x = before.begin(); x != before.end(); ++x) {
- XMLNode* child = new XMLNode ("s");
- boost::shared_ptr<Route> r = x->first.lock();
-
- if (r) {
- child->add_property (X_("id"), r->id().to_s());
-
- const char* meterstr = 0;
-
- switch (x->second) {
- case MeterInput:
- meterstr = X_("input");
- break;
- case MeterPreFader:
- meterstr = X_("pre");
- break;
- case MeterPostFader:
- meterstr = X_("post");
- break;
- default:
- fatal << string_compose (_("programming error: %1") , "no meter state in Session::GlobalMeteringStateCommand::get_state") << endmsg;
- }
-
- child->add_property (X_("meter"), meterstr);
- nbefore->add_child_nocopy (*child);
- }
- }
-
- for (Session::GlobalRouteMeterState::iterator x = after.begin(); x != after.end(); ++x) {
- XMLNode* child = new XMLNode ("s");
- boost::shared_ptr<Route> r = x->first.lock();
-
- if (r) {
- child->add_property (X_("id"), r->id().to_s());
-
- const char* meterstr;
-
- switch (x->second) {
- case MeterInput:
- meterstr = X_("input");
- break;
- case MeterPreFader:
- meterstr = X_("pre");
- break;
- case MeterPostFader:
- meterstr = X_("post");
- break;
- default: meterstr = "";
- }
-
- child->add_property (X_("meter"), meterstr);
- nafter->add_child_nocopy (*child);
- }
- }
-
- node->add_child_nocopy (*nbefore);
- node->add_child_nocopy (*nafter);
-
- node->add_property ("type", "metering");
-
- return *node;
-}
-
-int
-Session::GlobalMeteringStateCommand::set_state (const XMLNode& node, int /*version*/)
-{
- GlobalRouteBooleanState states;
- XMLNodeList nlist;
- const XMLProperty* prop;
- XMLNode* child;
- XMLNodeConstIterator niter;
- int loop;
-
- before.clear ();
- after.clear ();
-
- for (loop = 0; loop < 2; ++loop) {
-
- const char *str;
-
- if (loop) {
- str = "after";
- } else {
- str = "before";
- }
-
- if ((child = node.child (str)) == 0) {
- warning << string_compose (_("global route meter state command has no \"%1\" node, ignoring entire command"), str) << endmsg;
- return -1;
- }
-
- nlist = child->children();
-
- for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
-
- RouteMeterState rms;
- boost::shared_ptr<Route> route;
- ID id;
-
- prop = (*niter)->property ("id");
- id = prop->value ();
-
- if ((route = sess.route_by_id (id)) == 0) {
- warning << string_compose (_("cannot find track/bus \"%1\" while rebuilding a global route state command, ignored"), id.to_s()) << endmsg;
- continue;
- }
-
- rms.first = boost::weak_ptr<Route> (route);
-
- prop = (*niter)->property ("meter");
-
- if (prop->value() == X_("pre")) {
- rms.second = MeterPreFader;
- } else if (prop->value() == X_("post")) {
- rms.second = MeterPostFader;
- } else {
- rms.second = MeterInput;
- }
-
- if (loop) {
- after.push_back (rms);
- } else {
- before.push_back (rms);
- }
- }
- }
-
- return 0;
-}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 568017c064..9766a1b159 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -577,7 +577,7 @@ Session::follow_slave (nframes_t nframes)
slave_speed));
}
-#if 0
+#if 1
if (abs(average_slave_delta) > _slave->resolution()) {
cerr << "average slave delta greater than slave resolution (" << _slave->resolution() << "), going to silent motion\n";
goto silent_motion;
@@ -1141,9 +1141,3 @@ Session::process_event (SessionEvent* ev)
}
}
-void
-Session::process_rtop (SessionEvent* ev)
-{
- ev->rt_slot ();
- ev->rt_return (ev);
-}
diff --git a/libs/ardour/session_rtevents.cc b/libs/ardour/session_rtevents.cc
new file mode 100644
index 0000000000..6d3e7ce78c
--- /dev/null
+++ b/libs/ardour/session_rtevents.cc
@@ -0,0 +1,169 @@
+/*
+ Copyright (C) 1999-2009 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.
+*/
+
+#include "pbd/error.h"
+#include "pbd/compose.h"
+
+#include "ardour/session.h"
+#include "ardour/route.h"
+#include "ardour/track.h"
+
+#include "i18n.h"
+
+using namespace std;
+using namespace PBD;
+using namespace ARDOUR;
+using namespace Glib;
+
+SessionEvent*
+Session::get_rt_event (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override,
+ void (Session::*method) (boost::shared_ptr<RouteList>, bool, bool))
+{
+ SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ ev->rt_slot = bind (sigc::mem_fun (*this, method), rl, yn, group_override);
+ ev->rt_return = after;
+ ev->ui = UICallback::get_ui_for_thread ();
+
+ return ev;
+}
+
+void
+Session::set_solo (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool 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, bool group_override)
+{
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ if (!(*i)->is_hidden()) {
+ (*i)->set_solo (yn, this);
+ }
+ }
+
+ set_dirty();
+}
+
+void
+Session::set_just_one_solo (boost::shared_ptr<Route> r, bool yn, sigc::slot<void,SessionEvent*> 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, false, &Session::rt_set_just_one_solo));
+}
+
+void
+Session::rt_set_just_one_solo (boost::shared_ptr<RouteList> just_one, bool yn, bool /*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_hidden() && r != *i) {
+ (*i)->set_solo (!yn, (*i)->route_group());
+ }
+ }
+
+ r->set_solo (yn, r->route_group());
+
+ set_dirty();
+}
+
+void
+Session::set_listen (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool 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, bool group_override)
+{
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ if (!(*i)->is_hidden()) {
+ (*i)->set_listen (yn, this);
+ }
+ }
+
+ set_dirty();
+}
+
+void
+Session::set_mute (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
+{
+ 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, bool group_override)
+{
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ if (!(*i)->is_hidden()) {
+ (*i)->set_mute (yn, this);
+ }
+ }
+
+ set_dirty();
+}
+
+void
+Session::set_record_enable (boost::shared_ptr<RouteList> rl, bool yn, sigc::slot<void,SessionEvent*> after, bool group_override)
+{
+ if (!writable()) {
+ return;
+ }
+
+ queue_event (get_rt_event (rl, yn, after, group_override, &Session::rt_set_record_enable));
+}
+
+void
+Session::rt_set_record_enable (boost::shared_ptr<RouteList> rl, bool yn, bool group_override)
+{
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ if ((*i)->is_hidden()) {
+ continue;
+ }
+
+ boost::shared_ptr<Track> t;
+
+ if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
+ t->set_record_enable (yn, (group_override ? (void*) t->route_group() : (void *) this));
+ }
+ }
+
+ set_dirty ();
+}
+
+void
+Session::process_rtop (SessionEvent* ev)
+{
+ ev->rt_slot ();
+
+ if (ev->ui) {
+ ev->ui->call_slot (bind (ev->rt_return, ev));
+ } else {
+ warning << string_compose ("programming error: %1", X_("Session RT event queued from thread without a UI - cleanup in RT thread!")) << endmsg;
+ ev->rt_return (ev);
+ }
+}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index db3d9e94ae..74578039a8 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -2176,92 +2176,6 @@ Session::commit_reversible_command(Command *cmd)
_current_trans.pop();
}
-Session::GlobalRouteBooleanState
-Session::get_global_route_boolean (bool (Route::*method)(void) const)
-{
- GlobalRouteBooleanState s;
- boost::shared_ptr<RouteList> r = routes.reader ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_hidden()) {
- RouteBooleanState v;
-
- v.first =* i;
- Route* r = (*i).get();
- v.second = (r->*method)();
-
- s.push_back (v);
- }
- }
-
- return s;
-}
-
-Session::GlobalRouteMeterState
-Session::get_global_route_metering ()
-{
- GlobalRouteMeterState s;
- boost::shared_ptr<RouteList> r = routes.reader ();
-
- for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
- if (!(*i)->is_hidden()) {
- RouteMeterState v;
-
- v.first =* i;
- v.second = (*i)->meter_point();
-
- s.push_back (v);
- }
- }
-
- return s;
-}
-
-void
-Session::set_global_route_metering (GlobalRouteMeterState s, void* arg)
-{
- for (GlobalRouteMeterState::iterator i = s.begin(); i != s.end(); ++i) {
-
- boost::shared_ptr<Route> r = (i->first.lock());
-
- if (r) {
- r->set_meter_point (i->second, arg);
- }
- }
-}
-
-void
-Session::set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void* arg)
-{
- for (GlobalRouteBooleanState::iterator i = s.begin(); i != s.end(); ++i) {
-
- boost::shared_ptr<Route> r = (i->first.lock());
-
- if (r) {
- Route* rp = r.get();
- (rp->*method) (i->second, arg);
- }
- }
-}
-
-void
-Session::set_global_mute (GlobalRouteBooleanState s, void* src)
-{
- set_global_route_boolean (s, &Route::set_mute, src);
-}
-
-void
-Session::set_global_solo (GlobalRouteBooleanState s, void* src)
-{
- set_global_route_boolean (s, &Route::set_solo, src);
-}
-
-void
-Session::set_global_record_enable (GlobalRouteBooleanState s, void* src)
-{
- set_global_route_boolean (s, &Route::set_record_enable, src);
-}
-
static bool
accept_all_non_peak_files (const string& path, void */*arg*/)
{
@@ -2892,12 +2806,6 @@ Session::restore_history (string snapshot_name)
ut->add_command(c);
}
- } else if (n->name() == X_("GlobalRouteStateCommand")) {
-
- if ((c = global_state_command_factory (*n))) {
- ut->add_command (c);
- }
-
} else if (n->name() == "DeltaCommand") {
PBD::ID id(n->property("midi-source")->value());
boost::shared_ptr<MidiSource> midi_source =
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 9f056d9223..0dcfea7056 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -168,6 +168,7 @@ libardour_sources = [
'session_midi.cc',
'session_playlists.cc',
'session_process.cc',
+ 'session_rtevents.cc',
'session_state.cc',
'session_state_utils.cc',
'session_time.cc',
diff --git a/libs/gtkmm2ext/gtk_ui.cc b/libs/gtkmm2ext/gtk_ui.cc
index 1f8e919af4..3d86c6d103 100644
--- a/libs/gtkmm2ext/gtk_ui.cc
+++ b/libs/gtkmm2ext/gtk_ui.cc
@@ -80,6 +80,12 @@ UI::UI (string namestr, int *argc, char ***argv)
*/
run_loop_thread = Thread::self();
+
+ /* store "this" as the UI-for-thread of this thread, same argument
+ as for previous line.
+ */
+
+ set_ui_for_thread (this);
/* attach our request source to the default main context */
diff --git a/libs/pbd/base_ui.cc b/libs/pbd/base_ui.cc
index 9b461fb01d..ea7e469c74 100644
--- a/libs/pbd/base_ui.cc
+++ b/libs/pbd/base_ui.cc
@@ -43,8 +43,6 @@ BaseUI::BaseUI (const string& str)
: run_loop_thread (0)
, _name (str)
{
- cerr << "New BUI called " << _name << " @ " << this << endl;
-
base_ui_instance = this;
request_channel.ios()->connect (sigc::mem_fun (*this, &BaseUI::request_handler));
@@ -72,6 +70,7 @@ BaseUI::new_request_type ()
void
BaseUI::main_thread ()
{
+ set_ui_for_thread (this);
thread_init ();
_main_loop->run ();
}
diff --git a/libs/pbd/pbd/base_ui.h b/libs/pbd/pbd/base_ui.h
index e8de355b03..20534aa7fd 100644
--- a/libs/pbd/pbd/base_ui.h
+++ b/libs/pbd/pbd/base_ui.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2007 Paul Davis
+ Copyright (C) 2000-2009 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
@@ -30,8 +30,10 @@
#include <glibmm/main.h>
#include "pbd/crossthread.h"
+#include "pbd/ui_callback.h"
-class BaseUI : virtual public sigc::trackable {
+class BaseUI : virtual public sigc::trackable, public PBD::UICallback
+{
public:
BaseUI (const std::string& name);
virtual ~BaseUI();
@@ -45,7 +47,7 @@ class BaseUI : virtual public sigc::trackable {
std::string name() const { return _name; }
bool ok() const { return _ok; }
-
+
enum RequestType {
range_guarantee = ~0
};
@@ -62,8 +64,6 @@ class BaseUI : virtual public sigc::trackable {
void run ();
void quit ();
- virtual void call_slot (sigc::slot<void> theSlot) = 0;
-
protected:
CrossThreadChannel request_channel;
bool _ok;
diff --git a/libs/pbd/pbd/ui_callback.h b/libs/pbd/pbd/ui_callback.h
new file mode 100644
index 0000000000..d5f4c51f4e
--- /dev/null
+++ b/libs/pbd/pbd/ui_callback.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2009 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.
+
+*/
+
+#ifndef __pbd_ui_callback_h__
+#define __pbd_ui_callback_h__
+
+#include <glibmm/thread.h>
+#include <sigc++/slot.h>
+
+namespace PBD
+{
+
+class UICallback
+{
+ public:
+ UICallback() {}
+ virtual ~UICallback() {}
+
+ virtual void call_slot (sigc::slot<void> theSlot) = 0;
+
+ static UICallback* get_ui_for_thread() { return thread_ui.get(); }
+ static void set_ui_for_thread (UICallback* ui) { return thread_ui.set (ui); }
+
+ private:
+ static Glib::StaticPrivate<UICallback> thread_ui;
+
+};
+
+}
+
+#endif /* __pbd_ui_callback_h__ */
diff --git a/libs/pbd/ui_callback.cc b/libs/pbd/ui_callback.cc
new file mode 100644
index 0000000000..954d25f637
--- /dev/null
+++ b/libs/pbd/ui_callback.cc
@@ -0,0 +1,6 @@
+#include "pbd/ui_callback.h"
+
+using namespace PBD;
+
+Glib::StaticPrivate<UICallback> UICallback::thread_ui;
+
diff --git a/libs/pbd/wscript b/libs/pbd/wscript
index e114cbe1ae..84c18cc899 100644
--- a/libs/pbd/wscript
+++ b/libs/pbd/wscript
@@ -81,6 +81,7 @@ def build(bld):
strsplit.cc
textreceiver.cc
transmitter.cc
+ ui_callback.cc
undo.cc
uuid.cc
version.cc