do not allow smf_source's reads to stomp on cached read_end position in parent class...
[ardour.git] / libs / ardour / smf_source.cc
index 74ee1fd6809ef00e4478716da6d0d96f58bc497f..7fbc8b0287d29296fc5106c292dc8dc03c92e567 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
-#include <pbd/mountpoint.h>
-#include <pbd/pathscanner.h>
-#include <pbd/stl_delete.h>
-#include <pbd/strsplit.h>
+#include "pbd/mountpoint.h"
+#include "pbd/pathscanner.h"
+#include "pbd/stl_delete.h"
+#include "pbd/strsplit.h"
 
 #include <glibmm/miscutils.h>
 
-#include <evoral/SMFReader.hpp>
-#include <evoral/Control.hpp>
+#include "evoral/SMFReader.hpp"
+#include "evoral/Control.hpp"
 
-#include <ardour/audioengine.h>
-#include <ardour/event_type_map.h>
-#include <ardour/midi_model.h>
-#include <ardour/midi_ring_buffer.h>
-#include <ardour/session.h>
-#include <ardour/smf_source.h>
+#include "ardour/audioengine.h"
+#include "ardour/event_type_map.h"
+#include "ardour/midi_model.h"
+#include "ardour/midi_ring_buffer.h"
+#include "ardour/session.h"
+#include "ardour/smf_source.h"
 
 #include "i18n.h"
 
@@ -55,6 +55,7 @@ SMFSource::SMFSource (Session& s, const ustring& path, bool embedded, Source::Fl
        , Evoral::SMF()
        , _last_ev_time_beats(0.0)
        , _last_ev_time_frames(0)
+       , _smf_last_read_end (0)
 {
        if (init(_name, false)) {
                throw failed_constructor ();
@@ -72,6 +73,7 @@ SMFSource::SMFSource (Session& s, const XMLNode& node, bool must_exist)
        , FileSource(s, node, must_exist)
        , _last_ev_time_beats(0.0)
        , _last_ev_time_frames(0)
+       , _smf_last_read_end (0)
 {
        if (set_state(node)) {
                throw failed_constructor ();
@@ -95,8 +97,8 @@ SMFSource::~SMFSource ()
 
 /** All stamps in audio frames */
 nframes_t
-SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, sframes_t position,
-               sframes_t start, nframes_t dur,
+SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& destination, sframes_t source_start,
+               sframes_t start, nframes_t duration,
                sframes_t stamp_offset, sframes_t negative_stamp_offset) const
 {
        int      ret  = 0;
@@ -112,24 +114,24 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, sframes_t position,
 
        size_t scratch_size = 0; // keep track of scratch to minimize reallocs
        
-       BeatsFramesConverter converter(_session, position);
+       BeatsFramesConverter converter(_session, source_start);
 
        const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
 
-       if (_last_read_end == 0 || start != _last_read_end) {
-               cerr << "SMFSource::read_unlocked seeking to " << start << endl;
+       if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
+               //cerr << "SMFSource::read_unlocked seeking to " << start << endl;
                Evoral::SMF::seek_to_start();
                while (time < start_ticks) {
                        ret = read_event(&ev_delta_t, &ev_size, &ev_buffer);
                        if (ret == -1) { // EOF
-                               _last_read_end = start + dur;
-                               return dur;
+                               _smf_last_read_end = start + duration;
+                               return duration;
                        }
                        time += ev_delta_t; // accumulate delta time
                }
        }
        
-       _last_read_end = start + dur;
+       _smf_last_read_end = start + duration;
 
        while (true) {
                ret = read_event(&ev_delta_t, &ev_size, &ev_buffer);
@@ -148,8 +150,8 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, sframes_t position,
                assert(time >= start_ticks);
                const sframes_t ev_frame_time = converter.to(time / (double)ppqn()) + stamp_offset;
 
-               if (ev_frame_time < start + dur) {
-                       dst.write(ev_frame_time - negative_stamp_offset, ev_type, ev_size, ev_buffer);
+               if (ev_frame_time < start + duration) {
+                       destination.write(ev_frame_time - negative_stamp_offset, ev_type, ev_size, ev_buffer);
                } else {
                        break;
                }
@@ -162,12 +164,12 @@ SMFSource::read_unlocked (MidiRingBuffer<nframes_t>& dst, sframes_t position,
                ev_size = scratch_size; // ensure read_event only allocates if necessary
        }
        
-       return dur;
+       return duration;
 }
 
 /** All stamps in audio frames */
 nframes_t
-SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& src, sframes_t position, nframes_t dur)
+SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& source, sframes_t position, nframes_t duration)
 {
        _write_data_count = 0;
                
@@ -185,12 +187,12 @@ SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& src, sframes_t position, n
        Evoral::MIDIEvent<nframes_t> ev;
 
        while (true) {
-               bool ret = src.peek_time(&time);
-               if (!ret || time > _last_write_end + dur) {
+               bool ret = source.peek_time(&time);
+               if (!ret || time > _last_write_end + duration) {
                        break;
                }
 
-               ret = src.read_prefix(&time, &type, &size);
+               ret = source.read_prefix(&time, &type, &size);
                if (!ret) {
                        cerr << "ERROR: Unable to read event prefix, corrupt MIDI ring buffer" << endl;
                        break;
@@ -201,7 +203,7 @@ SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& src, sframes_t position, n
                        buf = (uint8_t*)realloc(buf, size);
                }
 
-               ret = src.read_contents(size, buf);
+               ret = source.read_contents(size, buf);
                if (!ret) {
                        cerr << "ERROR: Read time/size but not buffer, corrupt MIDI ring buffer" << endl;
                        break;
@@ -228,9 +230,9 @@ SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& src, sframes_t position, n
        Evoral::SMF::flush();
        free(buf);
 
-       ViewDataRangeReady(position + _last_write_end, dur); /* EMIT SIGNAL */
+       ViewDataRangeReady(position + _last_write_end, duration); /* EMIT SIGNAL */
 
-       return dur;
+       return duration;
 }
                
 
@@ -256,7 +258,7 @@ SMFSource::append_event_unlocked_beats (const Evoral::Event<double>& ev)
        
        const double delta_time_beats   = ev.time() - _last_ev_time_beats;
        const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
-
+       
        Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer());
        _last_ev_time_beats = ev.time();
 
@@ -279,7 +281,6 @@ SMFSource::append_event_unlocked_frames (const Evoral::Event<nframes_t>& ev, sfr
                        name().c_str(), ev.time(), ev.size()); 
        for (size_t i=0; i < ev.size(); ++i) printf("%X ", ev.buffer()[i]); printf("\n");*/
        
-       assert(ev.time() >= 0);
        if (ev.time() < _last_ev_time_frames) {
                cerr << "SMFSource: Warning: Skipping event with non-monotonic time" << endl;
                return;
@@ -375,10 +376,10 @@ SMFSource::load_model (bool lock, bool force_reload)
 
        if (! _model) {
                _model = boost::shared_ptr<MidiModel>(new MidiModel(this));
-               cerr << _name << " loaded new model " << _model.get() << endl;
+               //cerr << _name << " loaded new model " << _model.get() << endl;
        } else {
-               cerr << _name << " reloading model " << _model.get()
-                       << " (" << _model->n_notes() << " notes)" <<endl;
+               /*cerr << _name << " reloading model " << _model.get()
+                       << " (" << _model->n_notes() << " notes)" << endl;*/
                _model->clear();
        }
 
@@ -397,7 +398,7 @@ SMFSource::load_model (bool lock, bool force_reload)
        while ((ret = read_event(&delta_t, &size, &buf)) >= 0) {
                time += delta_t;
                ev.set(buf, size, time / (double)ppqn());
-               
+
                if (ret > 0) { // didn't skip (meta) event
                        ev.set_event_type(EventTypeMap::instance().midi_event_type(buf[0]));
                        _model->append(ev);