13
0

Maintain correct tracker state on MIDI overwrite.

This is a little hard-edged in that edits while rolling will prematurely chop
off any playing notes, but at least the state of things actually reflects
reality.  More sophisticated solution hopefully to come...
This commit is contained in:
David Robillard 2014-12-19 18:09:36 -05:00
parent db92d62c95
commit 5d8021bf44
7 changed files with 44 additions and 14 deletions

View File

@ -63,7 +63,15 @@ public:
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:

View File

@ -54,7 +54,7 @@ public:
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;

View File

@ -606,12 +606,20 @@ MidiDiskstream::set_pending_overwrite (bool yn)
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;
@ -1398,7 +1406,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
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) {
@ -1489,7 +1497,7 @@ MidiDiskstream::reset_tracker ()
boost::shared_ptr<MidiPlaylist> mp (midi_playlist());
if (mp) {
mp->clear_note_trackers ();
mp->reset_note_trackers ();
}
}

View File

@ -288,14 +288,27 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec
}
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 ();
}

View File

@ -414,6 +414,12 @@ MidiRegion::model_changed ()
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));
}

View File

@ -241,7 +241,7 @@ MidiRingBuffer<T>::reset_tracker ()
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);
}

View File

@ -282,13 +282,8 @@ SMFSource::read_unlocked (const Lock& lock,
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;