implement midi capture alignment:
authorRobin Gareus <robin@gareus.org>
Sat, 7 Jun 2014 23:07:03 +0000 (01:07 +0200)
committerRobin Gareus <robin@gareus.org>
Sat, 7 Jun 2014 23:07:03 +0000 (01:07 +0200)
For audio: not writing frames to the capture ringbuffer offsets
the recording.
For midi: we need to keep track of the record range
and subtract the accumulated difference from the event time.

libs/ardour/ardour/midi_diskstream.h
libs/ardour/midi_diskstream.cc

index 5a100420960bc7eeb3d2526b7bb2468ec8a5be54..50ad7419e62bf3f0a9ccea993d9350ed9d315a44 100644 (file)
@@ -173,6 +173,7 @@ class LIBARDOUR_API MidiDiskstream : public Diskstream
        gint                         _frames_read_from_ringbuffer;
        volatile gint                _frames_pending_write;
        volatile gint                _num_captured_loops;
+       framepos_t                   _accumulated_capture_offset;
 
        /** A buffer that we use to put newly-arrived MIDI data in for
            the GUI to read (so that it can update itself).
index 4a878c389861b1ae638f47d1f17353a494242284..7f7f7fa34a2c4bca094235abc0ce5d40dcc3cdf7 100644 (file)
@@ -75,6 +75,7 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
        , _frames_read_from_ringbuffer(0)
        , _frames_pending_write(0)
        , _num_captured_loops(0)
+       , _accumulated_capture_offset(0)
        , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
 {
        in_set_state = true;
@@ -99,6 +100,7 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
        , _frames_read_from_ringbuffer(0)
        , _frames_pending_write(0)
        , _num_captured_loops(0)
+       , _accumulated_capture_offset(0)
        , _gui_feed_buffer(AudioEngine::instance()->raw_buffer_size (DataType::MIDI))
 {
        in_set_state = true;
@@ -362,6 +364,15 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
 
                calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset);
+               /* For audio: not writing frames to the capture ringbuffer offsets
+                * the recording. For midi: we need to keep track of the record range
+                * and subtract the accumulated difference from the event time.
+                */
+               if (rec_nframes) {
+                       _accumulated_capture_offset += rec_offset;
+               } else {
+                       _accumulated_capture_offset += nframes;
+               }
 
                if (rec_nframes && !was_recording) {
                        if (loop_loc) {
@@ -394,6 +405,9 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
 
                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
                        Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
+                       if (ev.time() + rec_offset > rec_nframes) {
+                               break;
+                       }
 #ifndef NDEBUG
                        if (DEBUG::MidiIO & PBD::debug_bits) {
                                const uint8_t* __data = ev.buffer();
@@ -416,23 +430,26 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                           any desirable behaviour.  We don't want to send event with
                           transport time here since that way the source can not
                           reconstruct their actual time; future clever MIDI looping should
-                          probabl be implemented in the source instead of here.
+                          probably be implemented in the source instead of here.
                        */
                        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) {
+                               continue;
+                       }
                        switch (mode) {
                        case AllChannels:
-                               _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                               _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(transport_frame + loop_offset + ev.time(),
+                                               _capture_buf->write(event_time,
                                                                    ev.type(), ev.size(), ev.buffer());
                                        }
                                } else {
-                                       _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                                       _capture_buf->write(event_time,
                                                            ev.type(), ev.size(), ev.buffer());
                                }
                                break;
@@ -440,7 +457,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                                if (ev.is_channel_event()) {
                                        ev.set_channel (PBD::ffs(mask) - 1);
                                }
-                               _capture_buf->write(transport_frame + loop_offset + ev.time(),
+                               _capture_buf->write(event_time,
                                                    ev.type(), ev.size(), ev.buffer());
                                break;
                        }
@@ -472,6 +489,7 @@ MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t
                if (was_recording) {
                        finish_capture ();
                }
+               _accumulated_capture_offset = 0;
 
        }
 
@@ -972,6 +990,10 @@ MidiDiskstream::transport_stopped_wallclock (struct tm& /*when*/, time_t /*twhen
 
                                RegionFactory::region_name (region_name, _write_source->name(), false);
 
+                               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 capture start @ %2 length %3 add new region %4\n",
+                                                       _name, (*ci)->start, (*ci)->frames, region_name));
+
+
                                // cerr << _name << ": based on ci of " << (*ci)->start << " for " << (*ci)->frames << " add a region\n";
 
                                try {