const correctness.
[ardour.git] / libs / ardour / midi_region.cc
index eaac23300b96ba55ffa17be8bd5c8676839cfe38..c65758b01e315867b6a5bbf6ba9864f8a0637427 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <set>
 
-
 #include <glibmm/thread.h>
 
 #include "pbd/basename.h"
@@ -52,7 +51,9 @@ using namespace PBD;
 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)->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);
 }
@@ -62,7 +63,9 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, frameoffset_t
        : Region (other, offset, offset_relative)
 {
        assert(_name.val().find("/") == string::npos);
-       midi_source(0)->Switched.connect_same_thread (*this, boost::bind (&MidiRegion::switch_source, this, _1));
+       // 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" */
        }
@@ -193,30 +197,7 @@ MidiRegion::_read_at (const SourceList& /*srcs*/, Evoral::EventSink<nframes_t>&
 XMLNode&
 MidiRegion::state (bool full)
 {
-       XMLNode& node (Region::state (full));
-       char buf[64];
-       char buf2[64];
-       LocaleGuard lg (X_("POSIX"));
-
-       // XXX these should move into Region
-
-       for (uint32_t n=0; n < _sources.size(); ++n) {
-               snprintf (buf2, sizeof(buf2), "source-%d", n);
-               _sources[n]->id().print (buf, sizeof(buf));
-               node.add_property (buf2, buf);
-       }
-
-       for (uint32_t n=0; n < _master_sources.size(); ++n) {
-               snprintf (buf2, sizeof(buf2), "master-source-%d", n);
-               _master_sources[n]->id().print (buf, sizeof (buf));
-               node.add_property (buf2, buf);
-       }
-
-       if (full && _extra_xml) {
-               node.add_child_copy (*_extra_xml);
-       }
-
-       return node;
+       return Region::state (full);
 }
 
 int
@@ -229,8 +210,7 @@ void
 MidiRegion::recompute_at_end ()
 {
        /* our length has changed
-        * (non destructively) "chop" notes that pass the end boundary, to
-        * prevent stuck notes.
+         * so what? stuck notes are dealt with via a note state tracker
         */
 }
 
@@ -270,14 +250,70 @@ 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);
+        SourceList srcs;
+        srcs.push_back (msrc);
 
-       set_name(msrc->name());
+        drop_sources ();
+        use_sources (srcs);
+        
+       set_name (msrc->name());
+
+       msrc->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
 }
 
+void
+MidiRegion::model_changed ()
+{
+       if (!model()) {
+               return;
+       }
+       
+       /* 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 ();
+}