summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <drobilla@leibniz.local>2014-12-19 18:09:36 -0500
committerDavid Robillard <drobilla@leibniz.local>2014-12-20 01:13:25 -0500
commit5d8021bf44c066ad9b5ee4e8ab824267824be738 (patch)
treeb2ebd105b0057f23fb5d59e7504c2fbd8e026621 /libs
parentdb92d62c95773d78282e752df7589cc6b8b721c3 (diff)
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...
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/midi_playlist.h10
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h2
-rw-r--r--libs/ardour/midi_diskstream.cc14
-rw-r--r--libs/ardour/midi_playlist.cc17
-rw-r--r--libs/ardour/midi_region.cc6
-rw-r--r--libs/ardour/midi_ring_buffer.cc2
-rw-r--r--libs/ardour/smf_source.cc7
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<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:
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<MidiPlaylist> 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<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 ();
}
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<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);
}
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;