From 5d8021bf44c066ad9b5ee4e8ab824267824be738 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 19 Dec 2014 18:09:36 -0500 Subject: 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... --- libs/ardour/ardour/midi_playlist.h | 10 +++++++++- libs/ardour/ardour/midi_ring_buffer.h | 2 +- libs/ardour/midi_diskstream.cc | 14 +++++++++++--- libs/ardour/midi_playlist.cc | 17 +++++++++++++++-- libs/ardour/midi_region.cc | 6 ++++++ libs/ardour/midi_ring_buffer.cc | 2 +- libs/ardour/smf_source.cc | 7 +------ 7 files changed, 44 insertions(+), 14 deletions(-) diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h index 2603de45f7..5e334d5546 100644 --- a/libs/ardour/ardour/midi_playlist.h +++ b/libs/ardour/ardour/midi_playlist.h @@ -63,7 +63,15 @@ public: std::set 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& dst, framepos_t time); protected: diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index 15e4d2689b..0d27de3c16 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -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; diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index e2fd6d1681..e52a7c3ad7 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -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 mp (midi_playlist()); if (mp) { - mp->clear_note_trackers (); + mp->reset_note_trackers (); } } diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc index 36b6fce75f..63c3b49858 100644 --- a/libs/ardour/midi_playlist.cc +++ b/libs/ardour/midi_playlist.cc @@ -288,14 +288,27 @@ MidiPlaylist::read (Evoral::EventSink& 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& 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 (); } diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc index f79e5ef203..e94e4e4854 100644 --- a/libs/ardour/midi_region.cc +++ b/libs/ardour/midi_region.cc @@ -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)); } diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 0da3ba6835..9fbd9dfdff 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -241,7 +241,7 @@ MidiRingBuffer::reset_tracker () template void -MidiRingBuffer::loop_resolve (MidiBuffer& dst, framepos_t t) +MidiRingBuffer::resolve_tracker (MidiBuffer& dst, framepos_t t) { _tracker.resolve_notes (dst, t); } diff --git a/libs/ardour/smf_source.cc b/libs/ardour/smf_source.cc index 519d8bbf10..d1a82eb685 100644 --- a/libs/ardour/smf_source.cc +++ b/libs/ardour/smf_source.cc @@ -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; -- cgit v1.2.3