make switching between input+disk monitoring work "right" for MIDI tracks; also fix...
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 18 Jun 2012 19:20:59 +0000 (19:20 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 18 Jun 2012 19:20:59 +0000 (19:20 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@12762 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/midi_diskstream.h
libs/ardour/ardour/midi_port.h
libs/ardour/ardour/midi_ring_buffer.h
libs/ardour/midi_diskstream.cc
libs/ardour/midi_port.cc
libs/ardour/midi_ring_buffer.cc
libs/ardour/midi_track.cc

index 23ae7addb0e9a06f900f504aeb2e7c1a28ad7847..99513734da9136b0b3d80e6dba89ec8887d16b1a 100644 (file)
@@ -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);
        
index 84575ca351828b65d2470d81aabdcbc3cc2608ab..5dc55398cb9c7fdb1441e3202488d534ee47a5f1 100644 (file)
@@ -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);
index 4b352b3c4dcf074d2271f090845f4529b600b479..c6756933aa06f8e2cbb3927ddfa6382f9dd78da6 100644 (file)
@@ -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:
index a8757d7575bd2dcf9372db63794032fcbd306c6d..5e2a6e23b95dbe3ce8f61f95199465b94ceff3fa 100644 (file)
@@ -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
  */
index 9a7d3eeb27fdfee4a716671d35fcd7b1583e9780..63004f658b975c7f7f13311fbb8a0a47ec05f435 100644 (file)
@@ -188,6 +188,12 @@ MidiPort::flush_buffers (pframes_t nframes)
        }
 }
 
+void
+MidiPort::require_resolve ()
+{
+       _resolve_required = true;
+}
+
 void
 MidiPort::transport_stopped ()
 {
index 30f42aba195aa029c97a55e2db269031565f40b0..786ed3c080d33fb1f7b7748076896bf4a6ec7042 100644 (file)
@@ -98,7 +98,9 @@ MidiRingBuffer<T>::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<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
        return count;
 }
 
+template<typename T>
+void
+MidiRingBuffer<T>::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<typename T>
 void
 MidiRingBuffer<T>::dump(ostream& str)
index 8847bf13bcbff96b35369960c479b7ffd319aa99..a8a0e218a6bb5ac04452c92c79c5abb34bcd9f73 100644 (file)
@@ -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<MidiDiskstream> 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<MidiPort> mp = boost::dynamic_pointer_cast<MidiPort> (*p);
+                       if (mp) {
+                               mp->require_resolve ();
+                       }
+               }
+
+               boost::shared_ptr<MidiDiskstream> md (midi_diskstream());
+               
+               if (md) {
+                       md->reset_tracker ();
+               }
        }
 }