- // FIXME: don't seek to start and search every read (brutal!)
- SMF::seek_to_start();
-
- // FIXME: assumes tempo never changes after start
- const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
- _session.engine().frame_rate(),
- _session.tempo_map().meter_at(_timeline_position));
-
- const uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * ppqn());
-
- while (!SMF::eof()) {
- int ret = read_event(&ev_delta_t, &ev_size, &ev_buffer);
+ BeatsFramesConverter converter(_session.tempo_map(), source_start);
+
+ const uint64_t start_ticks = (uint64_t)(converter.from(start) * ppqn());
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start in ticks %1\n", start_ticks));
+
+ if (_smf_last_read_end == 0 || start != _smf_last_read_end) {
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
+ Evoral::SMF::seek_to_start();
+ while (time < start_ticks) {
+ gint ignored;
+
+ ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
+ if (ret == -1) { // EOF
+ _smf_last_read_end = start + duration;
+ return duration;
+ }
+ time += ev_delta_t; // accumulate delta time
+ }
+ } else {
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: set time to %1\n", _smf_last_read_time));
+ time = _smf_last_read_time;
+ }
+
+ _smf_last_read_end = start + duration;
+
+ while (true) {
+ gint ignored; /* XXX don't ignore note id's ??*/
+
+ ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);