+
+ BeatsFramesConverter converter(_session.tempo_map(), source_start);
+
+ if (_model) {
+ Evoral::Sequence<double>::const_iterator& i = _model_iter;
+
+ // 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) {
+ if (converter.to(i->time()) >= start) {
+ break;
+ }
+ }
+ _model_iter_valid = true;
+ } else {
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("*** %1 use cached iterator for %1 / %2\n", _name, source_start, start));
+ }
+
+ _last_read_end = start + cnt;
+
+ // Read events up to end
+ for (; i != _model->end(); ++i) {
+ const sframes_t time_frames = converter.to(i->time());
+ if (time_frames < start + cnt) {
+ dst.write(time_frames + stamp_offset - negative_stamp_offset,
+ i->event_type(), i->size(), i->buffer());
+ if (tracker) {
+ Evoral::MIDIEvent<Evoral::MusicalTime>& ev (*(Evoral::MIDIEvent<Evoral::MusicalTime>*) (&(*i)));
+ if (ev.is_note_on()) {
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("\t%1 add note on %2 @ %3\n", _name, ev.note(), time_frames));
+ tracker->add (ev.note(), ev.channel());
+ } else if (ev.is_note_off()) {
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("\t%1 add note off %2 @ %3\n", _name, ev.note(), time_frames));
+ tracker->remove (ev.note(), ev.channel());
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ return cnt;
+ } else {
+ return read_unlocked (dst, source_start, start, cnt, stamp_offset, negative_stamp_offset, tracker);
+ }