prepare configurable VST scan timeout
[ardour.git] / libs / ardour / smf_source.cc
index d915bba8456025805284055bbd70604c12077a2c..c504f5000628f67008c0a6e5478194414f952435 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <glib/gstdio.h>
 #include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
 
 #include "evoral/Control.hpp"
 
@@ -67,6 +68,15 @@ SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
        }
 
        /* file is not opened until write */
+
+       if (flags & Writable) {
+               return;
+       }
+
+       if (open(_path)) {
+               throw failed_constructor ();
+       }
+       _open = true;
 }
 
 /** Constructor used for existing internal-to-session files. */
@@ -455,7 +465,14 @@ SMFSource::safe_midi_file_extension (const string& file)
        const int nmatches = 2;
        regmatch_t matches[nmatches];
        
-       if (compile && regcomp (&compiled_pattern, "[mM][iI][dD][iI]?$", REG_EXTENDED)) {
+       if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
+               if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
+                       /* exists but is not a regular file */
+                       return false;
+               }
+       }
+
+       if (compile && regcomp (&compiled_pattern, "\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
                return false;
        } else {
                compile = false;
@@ -468,6 +485,12 @@ SMFSource::safe_midi_file_extension (const string& file)
        return true;
 }
 
+static bool compare_eventlist (
+               const std::pair< Evoral::Event<double>*, gint >& a,
+               const std::pair< Evoral::Event<double>*, gint >& b) {
+       return ( a.first->time() < b.first->time() );
+}
+
 void
 SMFSource::load_model (bool lock, bool force_reload)
 {
@@ -506,60 +529,74 @@ SMFSource::load_model (bool lock, bool force_reload)
        uint8_t* buf     = NULL;
        int ret;
        gint event_id;
-       bool have_event_id = false;
-
-       while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
-
-               time += delta_t;
+       bool have_event_id;
 
-               if (ret == 0) {
+       // TODO simplify event allocation
+       std::list< std::pair< Evoral::Event<double>*, gint > > eventlist;
 
-                       /* meta-event : did we get an event ID ?
-                        */
+       for (unsigned i = 1; i <= num_tracks(); ++i) {
+               if (seek_to_track(i)) continue;
 
-                       if (event_id >= 0) {
-                               have_event_id = true;
-                       }
+               time = 0;
+               have_event_id = false;
 
-                       continue;
-               }
+               while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
 
-               if (ret > 0) {
+                       time += delta_t;
 
-                       /* not a meta-event */
+                       if (ret == 0) {
+                               /* meta-event : did we get an event ID ?  */
+                               if (event_id >= 0) {
+                                       have_event_id = true;
+                               }
+                               continue;
+                       }
 
-                       ev.set (buf, size, time / (double)ppqn());
-                       ev.set_event_type(EventTypeMap::instance().midi_event_type(buf[0]));
+                       if (ret > 0) {
+                               /* not a meta-event */
 
-                       if (!have_event_id) {
-                               event_id = Evoral::next_event_id();
-                       }
+                               if (!have_event_id) {
+                                       event_id = Evoral::next_event_id();
+                               }
+                               uint32_t event_type = EventTypeMap::instance().midi_event_type(buf[0]);
+                               double   event_time = time / (double) ppqn();
 #ifndef NDEBUG
-                       std::string ss;
+                               std::string ss;
 
-                       for (uint32_t xx = 0; xx < size; ++xx) {
-                               char b[8];
-                               snprintf (b, sizeof (b), "0x%x ", buf[xx]);
-                               ss += b;
-                       }
+                               for (uint32_t xx = 0; xx < size; ++xx) {
+                                       char b[8];
+                                       snprintf (b, sizeof (b), "0x%x ", buf[xx]);
+                                       ss += b;
+                               }
 
-                       DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
-                                                                         delta_t, time, size, ss , ev.event_type(), name()));
+                               DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
+                                                       delta_t, time, size, ss , event_type, name()));
 #endif
 
-                       _model->append (ev, event_id);
+                               eventlist.push_back(make_pair (
+                                                       new Evoral::Event<double> (
+                                                               event_type, event_time,
+                                                               size, buf, true)
+                                                       , event_id));
 
-                       // Set size to max capacity to minimize allocs in read_event
-                       scratch_size = std::max(size, scratch_size);
-                       size = scratch_size;
+                               // Set size to max capacity to minimize allocs in read_event
+                               scratch_size = std::max(size, scratch_size);
+                               size = scratch_size;
 
-                       _length_beats = max(_length_beats, ev.time());
+                               _length_beats = max(_length_beats, event_time);
+                       }
+
+                       /* event ID's must immediately precede the event they are for */
+                       have_event_id = false;
                }
+       }
 
-               /* event ID's must immediately precede the event they are for
-                */
+       eventlist.sort(compare_eventlist);
 
-               have_event_id = false;
+       std::list< std::pair< Evoral::Event<double>*, gint > >::iterator it;
+       for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
+               _model->append (*it->first, it->second);
+               delete it->first;
        }
 
        _model->end_write (Evoral::Sequence<Evoral::MusicalTime>::ResolveStuckNotes, _length_beats);