prepare fix for copying plugin state
[ardour.git] / libs / ardour / midi_diskstream.cc
index f6ba10342ac8c08d48154ba45ff39eec8d276d02..485967b2a3ad3b5cea3edd1222117de6502e480b 100644 (file)
@@ -16,7 +16,6 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <fstream>
 #include <cstdio>
 #include <unistd.h>
 #include <cmath>
@@ -403,17 +402,10 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
        }
 
        if (nominally_recording || rec_nframes) {
-
-               // Pump entire port buffer into the ring buffer (FIXME: split cycles?)
-               MidiBuffer& buf = sp->get_midi_buffer(nframes);
-               ChannelMode mode = AllChannels;
-               uint32_t mask = 0xffff;
-
-               MidiTrack * mt = dynamic_cast<MidiTrack*> (_track);
-               if (mt) {
-                       mode = mt->get_capture_channel_mode ();
-                       mask = mt->get_capture_channel_mask ();
-               }
+               // Pump entire port buffer into the ring buffer (TODO: split cycles?)
+               MidiBuffer&        buf    = sp->get_midi_buffer(nframes);
+               MidiTrack*         mt     = dynamic_cast<MidiTrack*>(_track);
+               MidiChannelFilter* filter = mt ? &mt->capture_filter() : NULL;
 
                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
                        Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
@@ -421,7 +413,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                                break;
                        }
 #ifndef NDEBUG
-                       if (DEBUG::MidiIO & PBD::debug_bits) {
+                       if (DEBUG_ENABLED(DEBUG::MidiIO)) {
                                const uint8_t* __data = ev.buffer();
                                DEBUG_STR_DECL(a);
                                DEBUG_STR_APPEND(a, string_compose ("mididiskstream %1 capture event @ %2 + %3 sz %4 ", this, ev.time(), transport_frame, ev.size()));
@@ -447,31 +439,12 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                        const framecnt_t loop_offset = _num_captured_loops * loop_length;
                        const framepos_t event_time = transport_frame + loop_offset - _accumulated_capture_offset + ev.time();
                        if (event_time < 0 || event_time < first_recordable_frame) {
+                               /* Event out of range, skip */
                                continue;
                        }
-                       switch (mode) {
-                       case AllChannels:
-                               _capture_buf->write(event_time,
-                                                   ev.type(), ev.size(), ev.buffer());
-                               break;
-                       case FilterChannels:
-                               if (ev.is_channel_event()) {
-                                       if ((1<<ev.channel()) & mask) {
-                                               _capture_buf->write(event_time,
-                                                                   ev.type(), ev.size(), ev.buffer());
-                                       }
-                               } else {
-                                       _capture_buf->write(event_time,
-                                                           ev.type(), ev.size(), ev.buffer());
-                               }
-                               break;
-                       case ForceChannel:
-                               if (ev.is_channel_event()) {
-                                       ev.set_channel (PBD::ffs(mask) - 1);
-                               }
-                               _capture_buf->write(event_time,
-                                                   ev.type(), ev.size(), ev.buffer());
-                               break;
+
+                       if (!filter || !filter->filter(ev.buffer(), ev.size())) {
+                               _capture_buf->write(event_time, ev.type(), ev.size(), ev.buffer());
                        }
                }
                g_atomic_int_add(const_cast<gint*>(&_frames_pending_write), nframes);
@@ -484,7 +457,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                                   that it can read it if it likes.
                                */
                                _gui_feed_buffer.clear ();
-                               
+
                                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
                                        /* This may fail if buf is larger than _gui_feed_buffer, but it's not really
                                           the end of the world if it does.
@@ -535,7 +508,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
 
        if (need_disk_signal) {
                /* copy the diskstream data to all output buffers */
-               
+
                MidiBuffer& mbuf (bufs.get_midi (0));
                get_playback (mbuf, playback_distance);
 
@@ -609,7 +582,7 @@ MidiDiskstream::commit (framecnt_t playback_distance)
         * but we do need to check so that the decision on whether or not we
         * need the butler is done correctly.
         */
-       
+
        /* furthermore..
         *
         * Doing heavy GUI operations[1] can stall also the butler.
@@ -736,6 +709,9 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
        framecnt_t loop_length = 0;
        Location*  loc         = 0;
 
+       MidiTrack*         mt     = dynamic_cast<MidiTrack*>(_track);
+       MidiChannelFilter* filter = mt ? &mt->playback_filter() : NULL;
+
        if (!reversed) {
 
                loc = loop_location;
@@ -772,13 +748,13 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
 
                this_read = min(dur,this_read);
 
-               if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) {
+               if (midi_playlist()->read (*_playback_buf, start, this_read, 0, filter) != this_read) {
                        error << string_compose(
                                        _("MidiDiskstream %1: cannot read %2 from playlist at frame %3"),
                                        id(), this_read, start) << endmsg;
                        return -1;
                }
-               
+
                g_atomic_int_add (&_frames_written_to_ringbuffer, this_read);
 
                if (reversed) {
@@ -807,7 +783,7 @@ MidiDiskstream::read (framepos_t& start, framecnt_t dur, bool reversed)
 }
 
 int
-MidiDiskstream::do_refill_with_alloc ()
+MidiDiskstream::_do_refill_with_alloc (bool /* partial_fill */)
 {
        return do_refill();
 }
@@ -880,8 +856,8 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
 
        const framecnt_t total = g_atomic_int_get(const_cast<gint*> (&_frames_pending_write));
 
-       if (total == 0 || 
-           _capture_buf->read_space() == 0 || 
+       if (total == 0 ||
+           _capture_buf->read_space() == 0 ||
            (!force_flush && (total < disk_write_chunk_frames) && was_recording)) {
                goto out;
        }
@@ -913,7 +889,7 @@ MidiDiskstream::do_flush (RunContext /*context*/, bool force_flush)
                if (_write_source->midi_write (lm, *_capture_buf, get_capture_start_frame (0), to_write) != to_write) {
                        error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
                        return -1;
-               } 
+               }
                g_atomic_int_add(const_cast<gint*> (&_frames_pending_write), -to_write);
        }
 
@@ -1166,7 +1142,7 @@ MidiDiskstream::finish_capture ()
 void
 MidiDiskstream::set_record_enabled (bool yn)
 {
-       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) {
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) {
                return;
        }
 
@@ -1180,22 +1156,44 @@ MidiDiskstream::set_record_enabled (bool yn)
                } else {
                        disengage_record_enable ();
                }
-               
+
                RecordEnableChanged (); /* EMIT SIGNAL */
        }
 }
 
+void
+MidiDiskstream::set_record_safe (bool yn)
+{
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) { // REQUIRES REVIEW
+               return;
+       }
+
+       /* yes, i know that this not proof against race conditions, but its
+        good enough. i think.
+        */
+
+       if (record_safe () != yn) {
+               if (yn) {
+                       engage_record_safe ();
+               } else {
+                       disengage_record_safe ();
+               }
+
+               RecordSafeChanged (); /* EMIT SIGNAL */
+       }
+}
+
 bool
 MidiDiskstream::prep_record_enable ()
 {
-       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0) {
+       if (!recordable() || !_session.record_enabling_legal() || _io->n_ports().n_midi() == 0 || record_safe ()) { // REQUIRES REVIEW "|| record_safe ()"
                return false;
        }
 
        bool const rolling = _session.transport_speed() != 0.0f;
 
        boost::shared_ptr<MidiPort> sp = _source_port.lock ();
-       
+
        if (sp && Config->get_monitoring_model() == HardwareMonitoring) {
                sp->request_input_monitoring (!(_session.config.get_auto_input() && rolling));
        }
@@ -1322,14 +1320,14 @@ MidiDiskstream::steal_write_source_name ()
 
        try {
                string new_path = _session.new_midi_source_path (name());
-               
+
                if (_write_source->rename (new_path)) {
                        return string();
                }
        } catch (...) {
                return string ();
        }
-       
+
        return our_old_name;
 }
 
@@ -1361,7 +1359,7 @@ void
 MidiDiskstream::ensure_input_monitoring (bool yn)
 {
        boost::shared_ptr<MidiPort> sp = _source_port.lock ();
-       
+
        if (sp) {
                sp->ensure_input_monitoring (yn);
        }
@@ -1386,7 +1384,7 @@ float
 MidiDiskstream::playback_buffer_load () const
 {
        /* For MIDI it's not trivial to differentiate the following two cases:
-          
+
           1.  The playback buffer is empty because the system has run out of time to fill it.
           2.  The playback buffer is empty because there is no more data on the playlist.
 
@@ -1394,7 +1392,7 @@ MidiDiskstream::playback_buffer_load () const
           cannot keep up when #2 happens, when in fact it can.  Since MIDI data rates
           are so low compared to audio, just give a pretend answer here.
        */
-       
+
        return 1;
 }
 
@@ -1402,7 +1400,7 @@ float
 MidiDiskstream::capture_buffer_load () const
 {
        /* We don't report playback buffer load, so don't report capture load either */
-       
+
        return 1;
 }
 
@@ -1431,14 +1429,15 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
 
        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
                             "%1 MDS pre-read read %8 @ %4..%5 from %2 write to %3, LOOPED ? %6-%7\n", _name,
-                            _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes, 
+                            _playback_buf->get_read_ptr(), _playback_buf->get_write_ptr(), playback_sample, playback_sample + nframes,
                             (loc ? loc->start() : -1), (loc ? loc->end() : -1), nframes));
 
         // cerr << "================\n";
         // _playback_buf->dump (cerr);
         // cerr << "----------------\n";
 
-       size_t events_read = 0; 
+       size_t events_read = 0;
+       const size_t split_cycle_offset = Port::port_offset ();
 
        if (loc) {
                framepos_t effective_start;
@@ -1448,7 +1447,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
                } else {
                        effective_start = playback_sample;
                }
-               
+
                DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("looped, effective start adjusted to %1\n", effective_start));
 
                if (effective_start == loc->start()) {
@@ -1456,11 +1455,13 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
                           beyond the loop end.
                        */
 
-                       _playback_buf->resolve_tracker (dst, 0);
+                       _playback_buf->resolve_tracker (dst, split_cycle_offset);
                }
 
                _playback_buf->skip_to (effective_start);
 
+               /* for split-cycles we need to offset the events */
+
                if (loc->end() >= effective_start && loc->end() < effective_start + nframes) {
                        /* end of loop is within the range we are reading, so
                           split the read in two, and lie about the location
@@ -1477,23 +1478,23 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
                        if (first) {
                                DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #1, from %1 for %2\n",
                                                                                      effective_start, first));
-                               events_read = _playback_buf->read (dst, effective_start, first);
-                       } 
+                               events_read = _playback_buf->read (dst, effective_start, first, split_cycle_offset);
+                       }
 
                        if (second) {
                                DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #2, from %1 for %2\n",
                                                                                      loc->start(), second));
-                               events_read += _playback_buf->read (dst, loc->start(), second);
+                               events_read += _playback_buf->read (dst, loc->start(), second, split_cycle_offset);
                        }
-                                                                   
+
                } else {
                        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("loop read #3, adjusted start as %1 for %2\n",
                                                                              effective_start, nframes));
-                       events_read = _playback_buf->read (dst, effective_start, effective_start + nframes);
+                       events_read = _playback_buf->read (dst, effective_start, effective_start + nframes, split_cycle_offset);
                }
        } else {
                _playback_buf->skip_to (playback_sample);
-               events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes);
+               events_read = _playback_buf->read (dst, playback_sample, playback_sample + nframes, split_cycle_offset);
        }
 
        DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose (
@@ -1536,7 +1537,7 @@ boost::shared_ptr<MidiBuffer>
 MidiDiskstream::get_gui_feed_buffer () const
 {
        boost::shared_ptr<MidiBuffer> b (new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)));
-       
+
        Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex);
        b->copy (_gui_feed_buffer);
        return b;