diff options
Diffstat (limited to 'libs/ardour')
-rw-r--r-- | libs/ardour/ardour/automatable.h | 8 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_model.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_region.h | 6 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_source.h | 10 | ||||
-rw-r--r-- | libs/ardour/ardour/midi_track.h | 2 | ||||
-rw-r--r-- | libs/ardour/automatable.cc | 15 | ||||
-rw-r--r-- | libs/ardour/midi_region.cc | 59 | ||||
-rw-r--r-- | libs/ardour/midi_source.cc | 14 |
8 files changed, 107 insertions, 9 deletions
diff --git a/libs/ardour/ardour/automatable.h b/libs/ardour/ardour/automatable.h index 9b83705b0a..79bbec5199 100644 --- a/libs/ardour/ardour/automatable.h +++ b/libs/ardour/ardour/automatable.h @@ -24,6 +24,7 @@ #include <set> #include <string> #include <boost/shared_ptr.hpp> +#include "pbd/signals.h" #include "evoral/ControlSet.hpp" #include "ardour/types.h" @@ -94,6 +95,9 @@ 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<void, Evoral::Parameter> AutomationStateChanged; + protected: Session& _a_session; @@ -109,6 +113,10 @@ public: nframes_t _last_automation_snapshot; 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/midi_model.h b/libs/ardour/ardour/midi_model.h index 9b2c66d5f0..f879c201ee 100644 --- a/libs/ardour/ardour/midi_model.h +++ b/libs/ardour/ardour/midi_model.h @@ -146,7 +146,7 @@ public: InsertMergePolicy insert_merge_policy () const; void set_insert_merge_policy (InsertMergePolicy); - + protected: int resolve_overlaps_unlocked (const NotePtr, void* arg = 0); diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h index 568638ed21..ac65b86fc3 100644 --- a/libs/ardour/ardour/midi_region.h +++ b/libs/ardour/ardour/midi_region.h @@ -115,6 +115,12 @@ class MidiRegion : public Region void set_position_internal (framepos_t pos, bool allow_bbt_recompute); void switch_source(boost::shared_ptr<Source> source); + void model_changed (); + void model_automation_state_changed (Evoral::Parameter const &); + + std::set<Evoral::Parameter> _filtered_parameters; ///< parameters that we ask our source not to return when reading + PBD::ScopedConnection _model_connection; + PBD::ScopedConnection _source_connection; }; } /* namespace ARDOUR */ diff --git a/libs/ardour/ardour/midi_source.h b/libs/ardour/ardour/midi_source.h index 36c8548e20..0d0b744a95 100644 --- a/libs/ardour/ardour/midi_source.h +++ b/libs/ardour/ardour/midi_source.h @@ -63,7 +63,10 @@ class MidiSource : virtual public Source virtual nframes_t midi_read (Evoral::EventSink<nframes_t>& dst, sframes_t source_start, sframes_t start, nframes_t cnt, - sframes_t stamp_offset, sframes_t negative_stamp_offset, MidiStateTracker*) const; + sframes_t stamp_offset, + sframes_t negative_stamp_offset, + MidiStateTracker*, + std::set<Evoral::Parameter> const &) const; virtual nframes_t midi_write (MidiRingBuffer<nframes_t>& src, sframes_t source_start, @@ -111,9 +114,12 @@ class MidiSource : virtual public Source void set_note_mode(NoteMode mode); boost::shared_ptr<MidiModel> model() { return _model; } - void set_model(boost::shared_ptr<MidiModel> m) { _model = m; } + void set_model (boost::shared_ptr<MidiModel>); void drop_model(); + /** Emitted when a different MidiModel is set */ + PBD::Signal0<void> ModelChanged; + protected: virtual void flush_midi() = 0; diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index d181bea596..42446da70d 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -66,7 +66,7 @@ public: /** A control that will send "immediate" events to a MIDI track when twiddled */ struct MidiControl : public AutomationControl { MidiControl(MidiTrack* route, const Evoral::Parameter& param, - boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>()) + boost::shared_ptr<AutomationList> al = boost::shared_ptr<AutomationList>()) : AutomationControl (route->session(), param, al) , _route (route) {} diff --git a/libs/ardour/automatable.cc b/libs/ardour/automatable.cc index 3d705b3ea7..1e5b497bf7 100644 --- a/libs/ardour/automatable.cc +++ b/libs/ardour/automatable.cc @@ -150,6 +150,16 @@ Automatable::add_control(boost::shared_ptr<Evoral::Control> ac) 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<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl> (ac); + if (c) { + c->alist()->automation_state_changed.connect_same_thread ( + _control_connections, boost::bind (&Automatable::automation_state_changed, this, c->parameter()) + ); + } } void @@ -469,3 +479,8 @@ Automatable::automation_control (const Evoral::Parameter& id) const return boost::dynamic_pointer_cast<const AutomationControl>(Evoral::ControlSet::control(id)); } +void +Automatable::automation_state_changed (Evoral::Parameter const & p) +{ + AutomationStateChanged (p); /* EMIT SIGNAL */ +} diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index abb3191463..fe49547bf3 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -24,7 +24,6 @@ #include <set> - #include <glibmm/thread.h> #include "pbd/basename.h" @@ -53,6 +52,8 @@ MidiRegion::MidiRegion (const SourceList& srcs) : Region (srcs) { midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); + midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); + model_changed (); assert(_name.val().find("/") == string::npos); assert(_type == DataType::MIDI); } @@ -63,6 +64,8 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t { assert(_name.val().find("/") == string::npos); midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1)); + midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); + model_changed (); } MidiRegion::~MidiRegion () @@ -180,7 +183,8 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<nframes_t>& to_read, // read duration in frames output_buffer_position, // the offset in the output buffer negative_output_buffer_position, // amount to substract from note times - tracker + tracker, + _filtered_parameters ) != to_read) { return 0; /* "read nothing" */ } @@ -246,14 +250,63 @@ MidiRegion::midi_source (uint32_t n) const void MidiRegion::switch_source(boost::shared_ptr<Source> src) { + _source_connection.disconnect (); + boost::shared_ptr<MidiSource> msrc = boost::dynamic_pointer_cast<MidiSource>(src); - if (!msrc) + if (!msrc) { return; + } // MIDI regions have only one source _sources.clear(); _sources.push_back(msrc); set_name(msrc->name()); + + msrc->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); } +void +MidiRegion::model_changed () +{ + /* build list of filtered Parameters, being those whose automation state is not `Play' */ + + _filtered_parameters.clear (); + + Automatable::Controls const & c = model()->controls(); + + for (Automatable::Controls::const_iterator i = c.begin(); i != c.end(); ++i) { + boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second); + assert (ac); + if (ac->alist()->automation_state() != Play) { + _filtered_parameters.insert (ac->parameter ()); + } + } + + /* watch for changes to controls' AutoState */ + model()->AutomationStateChanged.connect_same_thread ( + _model_connection, boost::bind (&MidiRegion::model_automation_state_changed, this, _1) + ); +} + +void +MidiRegion::model_automation_state_changed (Evoral::Parameter const & p) +{ + /* Update our filtered parameters list after a change to a parameter's AutoState */ + + boost::shared_ptr<AutomationControl> ac = model()->automation_control (p); + assert (ac); + + if (ac->alist()->automation_state() == Play) { + _filtered_parameters.erase (p); + } else { + _filtered_parameters.insert (p); + } + + /* the source will have an iterator into the model, and that iterator will have been set up + for a given set of filtered_paramters, so now that we've changed that list we must invalidate + the iterator. + */ + Glib::Mutex::Lock lm (midi_source(0)->mutex()); + midi_source(0)->invalidate (); +} diff --git a/libs/ardour/midi_source.cc b/libs/ardour/midi_source.cc index 94c1a9b811..2e549b6fc6 100644 --- a/libs/ardour/midi_source.cc +++ b/libs/ardour/midi_source.cc @@ -142,11 +142,13 @@ MidiSource::invalidate () _model_iter.invalidate(); } +/** @param filtered A set of parameters whose MIDI messages will not be returned */ nframes_t MidiSource::midi_read (Evoral::EventSink<nframes_t>& dst, sframes_t source_start, sframes_t start, nframes_t cnt, sframes_t stamp_offset, sframes_t negative_stamp_offset, - MidiStateTracker* tracker) const + MidiStateTracker* tracker, + std::set<Evoral::Parameter> const & filtered) const { Glib::Mutex::Lock lm (_lock); @@ -158,7 +160,7 @@ MidiSource::midi_read (Evoral::EventSink<nframes_t>& dst, sframes_t source_start // If the cached iterator is invalid, search for the first event past start if (_last_read_end == 0 || start != _last_read_end || !_model_iter_valid) { DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("*** %1 search for relevant iterator for %1 / %2\n", _name, source_start, start)); - for (i = _model->begin(); i != _model->end(); ++i) { + for (i = _model->begin(0, filtered); i != _model->end(); ++i) { if (converter.to(i->time()) >= start) { break; } @@ -311,4 +313,12 @@ MidiSource::drop_model () { cerr << name() << " drop model\n"; _model.reset(); + ModelChanged (); /* EMIT SIGNAL */ +} + +void +MidiSource::set_model (boost::shared_ptr<MidiModel> m) +{ + _model = m; + ModelChanged (); /* EMIT SIGNAL */ } |