std::set<Evoral::Parameter> contained_automation();
- void clear_note_trackers ();
+ /** Clear all note trackers. */
+ void reset_note_trackers ();
+
+ /** Resolve all pending notes and clear all note trackers.
+ *
+ * @param dst Sink to write note offs to.
+ * @param time Time stamp of all written note offs.
+ */
+ void resolve_note_trackers (Evoral::EventSink<framepos_t>& dst, framepos_t time);
protected:
void flush (framepos_t start, framepos_t end);
void reset_tracker ();
- void loop_resolve (MidiBuffer& dst, framepos_t);
+ void resolve_tracker (MidiBuffer& dst, framepos_t);
private:
MidiStateTracker _tracker;
int
MidiDiskstream::overwrite_existing_buffers ()
{
- /* This is safe as long as the butler thread is suspended, which it should be */
+ /* Clear the playback buffer contents. This is safe as long as the butler
+ thread is suspended, which it should be. */
_playback_buf->reset ();
+ _playback_buf->reset_tracker ();
g_atomic_int_set (&_frames_read_from_ringbuffer, 0);
g_atomic_int_set (&_frames_written_to_ringbuffer, 0);
+ /* Resolve all currently active notes in the playlist. This is more
+ aggressive than it needs to be: ideally we would only resolve what is
+ absolutely necessary, but this seems difficult and/or impossible without
+ having the old data or knowing what change caused the overwrite. */
+ midi_playlist()->resolve_note_trackers (*_playback_buf, overwrite_frame);
+
read (overwrite_frame, disk_io_chunk_frames, false);
file_frame = overwrite_frame; // it was adjusted by ::read()
overwrite_queued = false;
beyond the loop end.
*/
- _playback_buf->loop_resolve (dst, 0);
+ _playback_buf->resolve_tracker (dst, 0);
}
if (loc->end() >= effective_start && loc->end() < effective_start + nframes) {
boost::shared_ptr<MidiPlaylist> mp (midi_playlist());
if (mp) {
- mp->clear_note_trackers ();
+ mp->reset_note_trackers ();
}
}
}
void
-MidiPlaylist::clear_note_trackers ()
+MidiPlaylist::reset_note_trackers ()
{
Playlist::RegionWriteLock rl (this, false);
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
delete n->second;
}
- DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 clears all note trackers\n", name()));
+ DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 reset all note trackers\n", name()));
+ _note_trackers.clear ();
+}
+
+void
+MidiPlaylist::resolve_note_trackers (Evoral::EventSink<framepos_t>& dst, framepos_t time)
+{
+ Playlist::RegionWriteLock rl (this, false);
+
+ for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
+ n->second->resolve_notes(dst, time);
+ delete n->second;
+ }
+ DEBUG_TRACE (DEBUG::MidiTrackers, string_compose ("%1 resolve all note trackers\n", name()));
_note_trackers.clear ();
}
void
MidiRegion::model_contents_changed ()
{
+ {
+ /* Invalidate source iterator to force reading new contents even if the
+ calls to read progress linearly. */
+ Glib::Threads::Mutex::Lock lm (midi_source(0)->mutex());
+ midi_source(0)->invalidate (lm);
+ }
send_change (PropertyChange (Properties::midi_data));
}
template<typename T>
void
-MidiRingBuffer<T>::loop_resolve (MidiBuffer& dst, framepos_t t)
+MidiRingBuffer<T>::resolve_tracker (MidiBuffer& dst, framepos_t t)
{
_tracker.resolve_notes (dst, t);
}
if (ev_frame_time < start + duration) {
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
-
if (tracker) {
- if (ev_buffer[0] & MIDI_CMD_NOTE_ON) {
- tracker->add (ev_buffer[1], ev_buffer[0] & 0xf);
- } else if (ev_buffer[0] & MIDI_CMD_NOTE_OFF) {
- tracker->remove (ev_buffer[1], ev_buffer[0] & 0xf);
- }
+ tracker->track(ev_buffer);
}
} else {
break;