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:
parent
db92d62c95
commit
5d8021bf44
@ -63,7 +63,15 @@ public:
|
|||||||
|
|
||||||
std::set<Evoral::Parameter> contained_automation();
|
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:
|
protected:
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ public:
|
|||||||
void flush (framepos_t start, framepos_t end);
|
void flush (framepos_t start, framepos_t end);
|
||||||
|
|
||||||
void reset_tracker ();
|
void reset_tracker ();
|
||||||
void loop_resolve (MidiBuffer& dst, framepos_t);
|
void resolve_tracker (MidiBuffer& dst, framepos_t);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MidiStateTracker _tracker;
|
MidiStateTracker _tracker;
|
||||||
|
@ -606,12 +606,20 @@ MidiDiskstream::set_pending_overwrite (bool yn)
|
|||||||
int
|
int
|
||||||
MidiDiskstream::overwrite_existing_buffers ()
|
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 ();
|
||||||
|
_playback_buf->reset_tracker ();
|
||||||
|
|
||||||
g_atomic_int_set (&_frames_read_from_ringbuffer, 0);
|
g_atomic_int_set (&_frames_read_from_ringbuffer, 0);
|
||||||
g_atomic_int_set (&_frames_written_to_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);
|
read (overwrite_frame, disk_io_chunk_frames, false);
|
||||||
file_frame = overwrite_frame; // it was adjusted by ::read()
|
file_frame = overwrite_frame; // it was adjusted by ::read()
|
||||||
overwrite_queued = false;
|
overwrite_queued = false;
|
||||||
@ -1398,7 +1406,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
|
|||||||
beyond the loop end.
|
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) {
|
if (loc->end() >= effective_start && loc->end() < effective_start + nframes) {
|
||||||
@ -1489,7 +1497,7 @@ MidiDiskstream::reset_tracker ()
|
|||||||
boost::shared_ptr<MidiPlaylist> mp (midi_playlist());
|
boost::shared_ptr<MidiPlaylist> mp (midi_playlist());
|
||||||
|
|
||||||
if (mp) {
|
if (mp) {
|
||||||
mp->clear_note_trackers ();
|
mp->reset_note_trackers ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,14 +288,27 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiPlaylist::clear_note_trackers ()
|
MidiPlaylist::reset_note_trackers ()
|
||||||
{
|
{
|
||||||
Playlist::RegionWriteLock rl (this, false);
|
Playlist::RegionWriteLock rl (this, false);
|
||||||
|
|
||||||
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
|
for (NoteTrackers::iterator n = _note_trackers.begin(); n != _note_trackers.end(); ++n) {
|
||||||
delete n->second;
|
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 ();
|
_note_trackers.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,6 +414,12 @@ MidiRegion::model_changed ()
|
|||||||
void
|
void
|
||||||
MidiRegion::model_contents_changed ()
|
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));
|
send_change (PropertyChange (Properties::midi_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ MidiRingBuffer<T>::reset_tracker ()
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void
|
void
|
||||||
MidiRingBuffer<T>::loop_resolve (MidiBuffer& dst, framepos_t t)
|
MidiRingBuffer<T>::resolve_tracker (MidiBuffer& dst, framepos_t t)
|
||||||
{
|
{
|
||||||
_tracker.resolve_notes (dst, t);
|
_tracker.resolve_notes (dst, t);
|
||||||
}
|
}
|
||||||
|
@ -282,13 +282,8 @@ SMFSource::read_unlocked (const Lock& lock,
|
|||||||
|
|
||||||
if (ev_frame_time < start + duration) {
|
if (ev_frame_time < start + duration) {
|
||||||
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
|
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
|
||||||
|
|
||||||
if (tracker) {
|
if (tracker) {
|
||||||
if (ev_buffer[0] & MIDI_CMD_NOTE_ON) {
|
tracker->track(ev_buffer);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user