Fix dropped MIDI events, especially with record enabled.
[ardour.git] / libs / ardour / midi_region.cc
index 518413e2de20da3d3eca1a2e919c045701fc5a3b..cb0d103b1e58d0f45f2674cb296d06579b6c1b26 100644 (file)
@@ -24,7 +24,9 @@
 
 #include <set>
 
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
 
 #include "pbd/xml++.h"
 #include "pbd/basename.h"
@@ -36,6 +38,7 @@
 #include "ardour/midi_source.h"
 #include "ardour/region_factory.h"
 #include "ardour/session.h"
+#include "ardour/source_factory.h"
 #include "ardour/tempo.h"
 #include "ardour/types.h"
 
@@ -126,16 +129,32 @@ MidiRegion::~MidiRegion ()
  */
 boost::shared_ptr<MidiRegion>
 MidiRegion::clone (string path) const
+{
+       boost::shared_ptr<MidiSource> newsrc;
+
+       /* caller must check for pre-existing file */
+       assert (!path.empty());
+       assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS));
+       newsrc = boost::dynamic_pointer_cast<MidiSource>(
+               SourceFactory::createWritable(DataType::MIDI, _session,
+                                             path, false, _session.frame_rate()));
+       return clone (newsrc);
+}
+
+boost::shared_ptr<MidiRegion>
+MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc) const
 {
        BeatsFramesConverter bfc (_session.tempo_map(), _position);
        Evoral::MusicalTime const bbegin = bfc.from (_start);
        Evoral::MusicalTime const bend = bfc.from (_start + _length);
 
-       boost::shared_ptr<MidiSource> ms = midi_source(0)->clone (path, bbegin, bend);
+       if (midi_source(0)->write_to (newsrc, bbegin, bend)) {
+               return boost::shared_ptr<MidiRegion> ();
+       }
 
        PropertyList plist;
 
-       plist.add (Properties::name, PBD::basename_nosuffix (ms->name()));
+       plist.add (Properties::name, PBD::basename_nosuffix (newsrc->name()));
        plist.add (Properties::whole_file, true);
        plist.add (Properties::start, _start);
        plist.add (Properties::start_beats, _start_beats);
@@ -143,7 +162,7 @@ MidiRegion::clone (string path) const
        plist.add (Properties::length_beats, _length_beats);
        plist.add (Properties::layer, 0);
 
-       return boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (ms, plist, true));
+       return boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (newsrc, plist, true));
 }
 
 void
@@ -395,20 +414,13 @@ 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) {
+       if (!ac || ac->alist()->automation_state() == Play) {
+               /* It should be "impossible" for ac to be NULL, but if it is, don't
+                  filter the parameter so events aren't lost. */
                _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_parameters, 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 ();
 }
 
 /** This is called when a trim drag has resulted in a -ve _start time for this region.