diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h index 23ae7addb0..99513734da 100644 --- a/libs/ardour/ardour/midi_diskstream.h +++ b/libs/ardour/ardour/midi_diskstream.h @@ -63,6 +63,7 @@ class MidiDiskstream : public Diskstream float capture_buffer_load() const; void get_playback (MidiBuffer& dst, framecnt_t); + void flush_playback (framepos_t, framepos_t); void set_record_enabled (bool yn); diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h index 84575ca351..5dc55398cb 100644 --- a/libs/ardour/ardour/midi_port.h +++ b/libs/ardour/ardour/midi_port.h @@ -45,6 +45,7 @@ class MidiPort : public Port { void transport_stopped (); void realtime_locate (); void reset (); + void require_resolve (); bool input_active() const { return _input_active; } void set_input_active (bool yn); diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h index 4b352b3c4d..c6756933aa 100644 --- a/libs/ardour/ardour/midi_ring_buffer.h +++ b/libs/ardour/ardour/midi_ring_buffer.h @@ -55,6 +55,7 @@ public: size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false); void dump(std::ostream& dst); + void flush (framepos_t start, framepos_t end); /** Set the channel filtering mode. * @param mask If mode is FilterChannels, each bit represents a midi channel: diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index a8757d7575..5e2a6e23b9 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -506,6 +506,14 @@ MidiDiskstream::seek (framepos_t frame, bool complete_refill) Glib::Mutex::Lock lm (state_lock); int ret = -1; + if (g_atomic_int_get (&_frames_read_from_ringbuffer) == 0) { + /* we haven't read anything since the last seek, + so flush all note trackers to prevent + wierdness + */ + reset_tracker (); + } + _playback_buf->reset(); _capture_buf->reset(); g_atomic_int_set(&_frames_read_from_ringbuffer, 0); @@ -1269,6 +1277,13 @@ MidiDiskstream::use_pending_capture_data (XMLNode& /*node*/) return 0; } +void +MidiDiskstream::flush_playback (framepos_t start, framepos_t end) +{ + _playback_buf->flush (start, end); + g_atomic_int_add (&_frames_read_from_ringbuffer, end - start); +} + /** Writes playback events from playback_sample for nframes to dst, translating time stamps * so that an event at playback_sample has time = 0 */ diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 9a7d3eeb27..63004f658b 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -188,6 +188,12 @@ MidiPort::flush_buffers (pframes_t nframes) } } +void +MidiPort::require_resolve () +{ + _resolve_required = true; +} + void MidiPort::transport_stopped () { diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc index 30f42aba19..786ed3c080 100644 --- a/libs/ardour/midi_ring_buffer.cc +++ b/libs/ardour/midi_ring_buffer.cc @@ -98,7 +98,9 @@ MidiRingBuffer::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame break; } else if (ev_time + loop_offset < start) { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 before start @ %2\n", ev_time, start)); - break; + this->increment_read_ptr (prefix_size); + this->increment_read_ptr (ev_size); + continue; } else { DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 in range %2 .. %3\n", ev_time, start, end)); } @@ -193,6 +195,36 @@ MidiRingBuffer::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame return count; } +template +void +MidiRingBuffer::flush (framepos_t start, framepos_t end) +{ + const size_t prefix_size = sizeof(T) + sizeof(Evoral::EventType) + sizeof(uint32_t); + + while (this->read_space() >= prefix_size) { + uint8_t peekbuf[prefix_size]; + bool success; + uint32_t ev_size; + T ev_time; + + success = this->peek (peekbuf, prefix_size); + /* this cannot fail, because we've already verified that there + is prefix_space to read + */ + assert (success); + + ev_time = *((T*) peekbuf); + + if (ev_time >= end) { + break; + } + + ev_size = *((uint32_t*)(peekbuf + sizeof(T) + sizeof (Evoral::EventType))); + this->increment_read_ptr (prefix_size); + this->increment_read_ptr (ev_size); + } +} + template void MidiRingBuffer::dump(ostream& str) diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc index 8847bf13bc..a8a0e218a6 100644 --- a/libs/ardour/midi_track.cc +++ b/libs/ardour/midi_track.cc @@ -309,6 +309,7 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame return dret; } + _silent = false; if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) { @@ -329,9 +330,18 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame at least potentially (depending on monitoring options) */ + /* because the playback buffer is event based and not a + * continuous stream, we need to make sure that we empty + * it of events every cycle to avoid it filling up with events + * read from disk, while we are actually monitoring input + */ + + diskstream->flush_playback (start_frame, end_frame); + passthru (start_frame, end_frame, nframes, 0); } else { + /* XXX is it true that the earlier test on n_outputs() means that we can avoid checking it again here? i think @@ -343,7 +353,6 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame /* copy the diskstream data to all output buffers */ - //const size_t limit = n_process_buffers().n_audio(); BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers()); MidiBuffer& mbuf (bufs.get_midi (0)); @@ -735,12 +744,28 @@ MidiTrack::act_on_mute () void MidiTrack::set_monitoring (MonitorChoice mc) { - Track::set_monitoring (mc); + if (mc != _monitoring) { - boost::shared_ptr md (midi_diskstream()); + Track::set_monitoring (mc); + + /* monitoring state changed, so flush out any on notes at the + * port level. + */ - if (md) { - md->reset_tracker (); + PortSet& ports (_output->ports()); + + for (PortSet::iterator p = ports.begin(); p != ports.end(); ++p) { + boost::shared_ptr mp = boost::dynamic_pointer_cast (*p); + if (mp) { + mp->require_resolve (); + } + } + + boost::shared_ptr md (midi_diskstream()); + + if (md) { + md->reset_tracker (); + } } }