restore rec-enable, solo & mute functionality; remove all Global*Command cruft; reimplement momentary solo&mute; refactor session RT event stuff to be even cleaner and finally compatible with everything-is-a-UI idea ; make all UIs derive from a primitive type that pprovides only void call_slot (sigc::slot<void>) as a way to execute arbitrary code in the UI thread

git-svn-id: svn://localhost/ardour2/branches/3.0@6338 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-12-10 17:45:18 +00:00
parent b5ca5713fb
commit 90d6916ca3
19 changed files with 443 additions and 986 deletions

View File

@ -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),

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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);
_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 */
} 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))) {
wait_for_release = true;
} else {
return false;
if (_solo_release) {
_solo_release->routes = _session.get_routes ();
}
}
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);
}
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.
*/
if (ev->button == 1) {
queue_route_group_op (RouteGroup::Solo, &Session::set_all_solo, !_route->soloed());
}
#endif
if (Config->get_solo_control_is_listen_control()) {
_session.set_listen (_session.get_routes(), !_route->listening(), Session::rt_cleanup, true);
} else {
_session.set_solo (_session.get_routes(), !_route->soloed(), Session::rt_cleanup, true);
}
} else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
// Primary-Secondary-click: exclusively solo this track
/* click: solo this route */
if (_solo_release) {
_solo_release->exclusive = true;
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);
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);
}
} 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 (_solo_release) {
_solo_release->routes = _route->route_group()->route_list();
}
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 {
_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()
{

View File

@ -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__ */

View File

@ -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

View File

@ -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;

View File

@ -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
{
@ -3596,32 +3563,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)
{

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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 =

View File

@ -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',

View File

@ -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 */

View File

@ -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 ();
}

View File

@ -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;

View File

@ -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__ */

6
libs/pbd/ui_callback.cc Normal file
View File

@ -0,0 +1,6 @@
#include "pbd/ui_callback.h"
using namespace PBD;
Glib::StaticPrivate<UICallback> UICallback::thread_ui;

View File

@ -81,6 +81,7 @@ def build(bld):
strsplit.cc
textreceiver.cc
transmitter.cc
ui_callback.cc
undo.cc
uuid.cc
version.cc