From 78986385e17b82a6704c8792fb21a42cd86add9a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 9 Aug 2010 22:23:23 +0000 Subject: Fix save/load of MIDI automation state. Fixes #3354. git-svn-id: svn://localhost/ardour2/branches/3.0@7578 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/automatable.h | 8 ++--- libs/ardour/ardour/automation_list.h | 2 +- libs/ardour/ardour/midi_model.h | 2 ++ libs/ardour/ardour/midi_source.h | 13 +++++++ libs/ardour/ardour/plugin_insert.h | 2 +- libs/ardour/automatable.cc | 42 ++++++++-------------- libs/ardour/automation_list.cc | 2 +- libs/ardour/midi_model.cc | 31 +++++++++++++--- libs/ardour/midi_region.cc | 2 +- libs/ardour/midi_source.cc | 70 +++++++++++++++++++++++++++++++++++- libs/ardour/plugin_insert.cc | 4 +-- 11 files changed, 133 insertions(+), 45 deletions(-) (limited to 'libs/ardour') diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index 2f35fc6b42..e0fe38e67e 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -65,7 +65,7 @@ public: virtual std::string describe_parameter(Evoral::Parameter param); - AutoState get_parameter_automation_state (Evoral::Parameter param, bool lock = true); + AutoState get_parameter_automation_state (Evoral::Parameter param); virtual void set_parameter_automation_state (Evoral::Parameter param, AutoState); AutoStyle get_parameter_automation_style (Evoral::Parameter param); @@ -95,16 +95,13 @@ public: int set_automation_state (const XMLNode&, Evoral::Parameter default_param); XMLNode& get_automation_state(); - - /** Emitted when the automation state of one of our controls changes */ - PBD::Signal1 AutomationStateChanged; protected: Session& _a_session; void can_automate(Evoral::Parameter); - virtual void auto_state_changed (Evoral::Parameter /*which*/) {} + virtual void automation_list_automation_state_changed (Evoral::Parameter, AutoState) {} int load_automation (const std::string& path); int old_set_automation_state(const XMLNode&); @@ -116,7 +113,6 @@ public: static nframes_t _automation_interval; private: - void automation_state_changed (Evoral::Parameter const &); PBD::ScopedConnectionList _control_connections; ///< connections to our controls' signals }; diff --git a/libs/ardour/ardour/automation_list.h b/libs/ardour/ardour/automation_list.h index 77b8d49dc7..acb071cca7 100644 --- a/libs/ardour/ardour/automation_list.h +++ b/libs/ardour/ardour/automation_list.h @@ -54,7 +54,7 @@ class AutomationList : public PBD::StatefulDestructible, public Evoral::ControlL void set_automation_state (AutoState); AutoState automation_state() const { return _state; } - PBD::Signal0 automation_state_changed; + PBD::Signal1 automation_state_changed; void set_automation_style (AutoStyle m); AutoStyle automation_style() const { return _style; } diff --git a/libs/ardour/ardour/midi_model.h b/libs/ardour/ardour/midi_model.h index e91d6484ea..e959535a36 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -174,7 +174,9 @@ private: friend class DeltaCommand; void source_interpolation_changed (Evoral::Parameter, Evoral::ControlList::InterpolationStyle); + void source_automation_state_changed (Evoral::Parameter, AutoState); void control_list_interpolation_changed (Evoral::Parameter, Evoral::ControlList::InterpolationStyle); + void automation_list_automation_state_changed (Evoral::Parameter, AutoState); PBD::ScopedConnectionList _midi_source_connections; diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 8d20f9c7b6..5afcc20255 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -122,10 +122,17 @@ class MidiSource : virtual public Source void copy_interpolation_from (boost::shared_ptr); void copy_interpolation_from (MidiSource *); + AutoState automation_state_of (Evoral::Parameter) const; + void set_automation_state_of (Evoral::Parameter, AutoState); + void copy_automation_state_from (boost::shared_ptr); + void copy_automation_state_from (MidiSource *); + /** Emitted when a different MidiModel is set */ PBD::Signal0 ModelChanged; /** Emitted when a parameter's interpolation style is changed */ PBD::Signal2 InterpolationChanged; + /** Emitted when a parameter's automation state is changed */ + PBD::Signal2 AutomationStateChanged; protected: virtual void flush_midi() = 0; @@ -159,6 +166,12 @@ class MidiSource : virtual public Source */ typedef std::map InterpolationStyleMap; InterpolationStyleMap _interpolation_style; + + /** Map of automation states to use for Parameters; if they are not in this map, + * the correct automation state is Off. + */ + typedef std::map AutomationStateMap; + AutomationStateMap _automation_state; }; } diff --git a/libs/ardour/ardour/plugin_insert.h b/libs/ardour/ardour/plugin_insert.h index c962832eb1..6656f755cf 100644 --- a/libs/ardour/ardour/plugin_insert.h +++ b/libs/ardour/ardour/plugin_insert.h @@ -133,7 +133,7 @@ class PluginInsert : public Processor void connect_and_run (BufferSet& bufs, nframes_t nframes, nframes_t offset, bool with_auto, nframes_t now = 0); void set_automatable (); - void auto_state_changed (Evoral::Parameter which); + void control_list_automation_state_changed (Evoral::Parameter, AutoState); void set_parameter_state (const XMLNode& node, int version); void set_parameter_state_2X (const XMLNode& node, int version); diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index c71fabda37..d6379eb38e 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -147,19 +147,17 @@ Automatable::add_control(boost::shared_ptr ac) { Evoral::Parameter param = ac->parameter(); - ControlSet::add_control(ac); - _can_automate_list.insert(param); - auto_state_changed(param); // sync everything up - - /* connect to automation_state_changed so that we can emit a signal when one of our controls' - automation state changes - */ - boost::shared_ptr c = boost::dynamic_pointer_cast (ac); - if (c) { - c->alist()->automation_state_changed.connect_same_thread ( - _control_connections, boost::bind (&Automatable::automation_state_changed, this, c->parameter()) - ); - } + boost::shared_ptr al = boost::dynamic_pointer_cast (ac->list ()); + assert (al); + + al->automation_state_changed.connect_same_thread ( + _list_connections, boost::bind (&Automatable::automation_list_automation_state_changed, this, ac->parameter(), _1) + ); + + ControlSet::add_control (ac); + _can_automate_list.insert (param); + + automation_list_automation_state_changed (param, al->automation_state ()); // sync everything up } void @@ -315,21 +313,16 @@ Automatable::set_parameter_automation_state (Evoral::Parameter param, AutoState } AutoState -Automatable::get_parameter_automation_state (Evoral::Parameter param, bool lock) +Automatable::get_parameter_automation_state (Evoral::Parameter param) { AutoState result = Off; - if (lock) - control_lock().lock(); - boost::shared_ptr c = control(param); boost::shared_ptr l = boost::dynamic_pointer_cast(c->list()); - if (c) + if (c) { result = l->automation_state(); - - if (lock) - control_lock().unlock(); + } return result; } @@ -479,16 +472,9 @@ Automatable::automation_control (const Evoral::Parameter& id) const return boost::dynamic_pointer_cast(Evoral::ControlSet::control(id)); } -void -Automatable::automation_state_changed (Evoral::Parameter const & p) -{ - AutomationStateChanged (p); /* EMIT SIGNAL */ -} - void Automatable::clear_controls () { _control_connections.drop_connections (); ControlSet::clear_controls (); } - diff --git a/libs/ardour/automation_list.cc b/libs/ardour/automation_list.cc index 17f346db1d..2270b2eff7 100644 --- a/libs/ardour/automation_list.cc +++ b/libs/ardour/automation_list.cc @@ -180,7 +180,7 @@ AutomationList::set_automation_state (AutoState s) { if (s != _state) { _state = s; - automation_state_changed (); /* EMIT SIGNAL */ + automation_state_changed (s); /* EMIT SIGNAL */ } } diff --git a/libs/ardour/midi_model.cc b/libs/ardour/midi_model.cc index 6922384e71..39daaacdea 100644 --- a/libs/ardour/midi_model.cc +++ b/libs/ardour/midi_model.cc @@ -1094,14 +1094,18 @@ MidiModel::set_midi_source (MidiSource* s) _midi_source->InterpolationChanged.connect_same_thread ( _midi_source_connections, boost::bind (&MidiModel::source_interpolation_changed, this, _1, _2) ); + + _midi_source->AutomationStateChanged.connect_same_thread ( + _midi_source_connections, boost::bind (&MidiModel::source_automation_state_changed, this, _1, _2) + ); } /** The source has signalled that the interpolation style for a parameter has changed. In order to * keep MidiSource and ControlList interpolation state the same, we pass this change onto the * appropriate ControlList. * - * The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and the - * MidiSource's InterpolationChanged signal is listened to by the GUI. + * The idea is that MidiSource and the MidiModel's ControlList states are kept in sync, and one + * or the other is listened to by the GUI. */ void MidiModel::source_interpolation_changed (Evoral::Parameter p, Evoral::ControlList::InterpolationStyle s) @@ -1119,18 +1123,37 @@ MidiModel::control_list_interpolation_changed (Evoral::Parameter p, Evoral::Cont _midi_source->set_interpolation_of (p, s); } +void +MidiModel::source_automation_state_changed (Evoral::Parameter p, AutoState s) +{ + Glib::Mutex::Lock lm (_control_lock); + boost::shared_ptr al = boost::dynamic_pointer_cast (control(p)->list ()); + al->set_automation_state (s); +} + +void +MidiModel::automation_list_automation_state_changed (Evoral::Parameter p, AutoState s) +{ + _midi_source->set_automation_state_of (p, s); +} + boost::shared_ptr MidiModel::control_factory (Evoral::Parameter const & p) { boost::shared_ptr c = Automatable::control_factory (p); - /* Set up newly created control's lists to the appropriate interpolation state - from our source. + /* Set up newly created control's lists to the appropriate interpolation and + automation state from our source. */ assert (_midi_source); c->list()->set_interpolation (_midi_source->interpolation_of (p)); + boost::shared_ptr al = boost::dynamic_pointer_cast (c->list ()); + assert (al); + + al->set_automation_state (_midi_source->automation_state_of (p)); + return c; } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index c76b6a859e..91f9ee58ed 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -291,7 +291,7 @@ MidiRegion::model_changed () } /* watch for changes to controls' AutoState */ - model()->AutomationStateChanged.connect_same_thread ( + midi_source()->AutomationStateChanged.connect_same_thread ( _model_connection, boost::bind (&MidiRegion::model_automation_state_changed, this, _1) ); } diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 5a823d332e..97fb801a6c 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -102,7 +102,13 @@ MidiSource::get_state () child->add_property (X_("parameter"), EventTypeMap::instance().to_symbol (i->first)); child->add_property (X_("style"), enum_2_string (i->second)); } - + + for (AutomationStateMap::const_iterator i = _automation_state.begin(); i != _automation_state.end(); ++i) { + XMLNode* child = node.add_child (X_("AutomationState")); + child->add_property (X_("parameter"), EventTypeMap::instance().to_symbol (i->first)); + child->add_property (X_("state"), enum_2_string (i->second)); + } + return node; } @@ -134,6 +140,25 @@ MidiSource::set_state (const XMLNode& node, int /*version*/) Evoral::ControlList::InterpolationStyle s = static_cast (string_2_enum (prop->value(), s)); set_interpolation_of (p, s); + + } else if ((*i)->name() == X_("AutomationState")) { + + XMLProperty* prop; + + if ((prop = (*i)->property (X_("parameter"))) == 0) { + error << _("Missing parameter property on AutomationState") << endmsg; + return -1; + } + + Evoral::Parameter p = EventTypeMap::instance().new_parameter (prop->value()); + + if ((prop = (*i)->property (X_("state"))) == 0) { + error << _("Missing state property on AutomationState") << endmsg; + return -1; + } + + AutoState s = static_cast (string_2_enum (prop->value(), s)); + set_automation_state_of (p, s); } } @@ -290,6 +315,7 @@ MidiSource::clone (Evoral::MusicalTime begin, Evoral::MusicalTime end) newsrc->set_timeline_position(_timeline_position); newsrc->copy_interpolation_from (this); + newsrc->copy_automation_state_from (this); if (_model) { if (begin == Evoral::MinMusicalTime && end == Evoral::MaxMusicalTime) { @@ -385,6 +411,17 @@ MidiSource::interpolation_of (Evoral::Parameter p) const return i->second; } +AutoState +MidiSource::automation_state_of (Evoral::Parameter p) const +{ + AutomationStateMap::const_iterator i = _automation_state.find (p); + if (i == _automation_state.end()) { + return Off; + } + + return i->second; +} + /** Set interpolation style to be used for a given parameter. This change will be * propagated to anyone who needs to know. */ @@ -405,12 +442,35 @@ MidiSource::set_interpolation_of (Evoral::Parameter p, Evoral::ControlList::Inte InterpolationChanged (p, s); /* EMIT SIGNAL */ } +void +MidiSource::set_automation_state_of (Evoral::Parameter p, AutoState s) +{ + if (automation_state_of (p) == s) { + return; + } + + if (s == Off) { + /* automation state is being set to the default, so we don't need a note in our map */ + _automation_state.erase (p); + } else { + _automation_state[p] = s; + } + + AutomationStateChanged (p, s); /* EMIT SIGNAL */ +} + void MidiSource::copy_interpolation_from (boost::shared_ptr s) { copy_interpolation_from (s.get ()); } +void +MidiSource::copy_automation_state_from (boost::shared_ptr s) +{ + copy_automation_state_from (s.get ()); +} + void MidiSource::copy_interpolation_from (MidiSource* s) { @@ -418,3 +478,11 @@ MidiSource::copy_interpolation_from (MidiSource* s) /* XXX: should probably emit signals here */ } + +void +MidiSource::copy_automation_state_from (MidiSource* s) +{ + _automation_state = s->_automation_state; + + /* XXX: should probably emit signals here */ +} diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index fa48156787..d1f09dd0a8 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -114,7 +114,7 @@ PluginInsert::~PluginInsert () } void -PluginInsert::auto_state_changed (Evoral::Parameter which) +PluginInsert::control_list_automation_state_changed (Evoral::Parameter which, AutoState s) { if (which.type() != PluginAutomation) return; @@ -122,7 +122,7 @@ PluginInsert::auto_state_changed (Evoral::Parameter which) boost::shared_ptr c = boost::dynamic_pointer_cast(control (which)); - if (c && ((AutomationList*)c->list().get())->automation_state() != Off) { + if (c && s != Off) { _plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame())); } } -- cgit v1.2.3