fix seamless midi-looping - fixes #5438
authorRobin Gareus <robin@gareus.org>
Sun, 29 Nov 2015 00:27:18 +0000 (01:27 +0100)
committerRobin Gareus <robin@gareus.org>
Sun, 29 Nov 2015 00:27:18 +0000 (01:27 +0100)
well, now...
 - Midi-Ports have a midi-buffer.
 - Midi-Tracks have a midi-buffer.
 - Midi-tracks have a diskstream.
 - Midi-diskstream has a midi-ring-buffer.
 - Midi-tracks have a delivery
 - The delivery can get a reference to the actual backend-ports
 - The delivery calls the Midi-Port's flush() buffer to send out queued events
   at the end of a cycle

all clear ? :)

 - when splitting the process-cycle: only the Ports are informed.
   all other objects see a "normal" short process cycle starting at "0".

The offset needs to be applied early on, so that internally routed buffers
push the event at the correct time when combining the buffer with
immediate and async events.

Luckily Port::port_offset() is a static member, available to all, objects,
which allows to bridge the conceptual gap between the diskstream and
the delivery.

There's a snag:
When there's a note-on directly at the beginning of the loop it coincides
with the panic message sent when looping.
The panic comes before note events, so it *should* be good.

Also the final note-offs (state tracker end of loop/region) are sent
1 sample too early (smells like an off-by-one), and are hence dropped.
(no matter we send a panic right after it).
It should really be at the same time, just before the panic.

libs/ardour/midi_buffer.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_track.cc
libs/ardour/plugin.cc

index 71f3e5334c33645f5906aaf7608dd24384d17b2d..3a03a03f9ee5b48545386b33be297664a5b00100 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "ardour/debug.h"
 #include "ardour/midi_buffer.h"
+#include "ardour/port.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -35,6 +36,7 @@ using namespace PBD;
 MidiBuffer::MidiBuffer(size_t capacity)
        : Buffer (DataType::MIDI)
        , _data (0)
+       , _size (0)
 {
        if (capacity) {
                resize (capacity);
@@ -85,7 +87,7 @@ MidiBuffer::copy(const MidiBuffer& copy)
  * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
  */
 void
-MidiBuffer::read_from (const Buffer& src, framecnt_t nframes, framecnt_t dst_offset, framecnt_t src_offset)
+MidiBuffer::read_from (const Buffer& src, framecnt_t nframes, framecnt_t dst_offset, framecnt_t /* src_offset*/)
 {
        assert (src.type() == DataType::MIDI);
        assert (&src != this);
@@ -99,15 +101,19 @@ MidiBuffer::read_from (const Buffer& src, framecnt_t nframes, framecnt_t dst_off
                assert (_size == 0);
        }
 
-       /* XXX use dst_offset somehow */
+       framecnt_t offset = Port::port_offset();
 
        for (MidiBuffer::const_iterator i = msrc.begin(); i != msrc.end(); ++i) {
                const Evoral::MIDIEvent<TimeType> ev(*i, false);
-               if (ev.time() >= src_offset && ev.time() < (nframes+src_offset)) {
+               if (ev.time() >= offset && ev.time() < (nframes + offset)) {
                        push_back (ev);
                } else {
                        cerr << "MIDI event @ " <<  ev.time() << " skipped, not within range "
-                            << src_offset << " .. " << (nframes + src_offset) << endl;
+                            << offset << " .. " << (nframes + offset) << ":";
+                               for (size_t xx = 0; xx < ev.size(); ++xx) {
+                                       cerr << ' ' << hex << (int) ev.buffer()[xx];
+                               }
+                               cerr << dec << endl;
                }
        }
 
index 43239f0069ee50736b8eb1f4d25dc2e6888ff921..485967b2a3ad3b5cea3edd1222117de6502e480b 100644 (file)
@@ -1437,6 +1437,7 @@ MidiDiskstream::get_playback (MidiBuffer& dst, framecnt_t nframes)
         // cerr << "----------------\n";
 
        size_t events_read = 0;
+       const size_t split_cycle_offset = Port::port_offset ();
 
        if (loc) {
                framepos_t effective_start;
@@ -1454,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
@@ -1475,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 (
index c49a2ef7f1afbb227327104cb796f0238cfd62d8..b078fa3f1b5141f2606484cc945bd9fd70f4534b 100644 (file)
@@ -935,7 +935,7 @@ MidiTrack::act_on_mute ()
                }
 
                /* Resolve active notes. */
-               midi_diskstream()->resolve_tracker(_immediate_events, 0);
+               midi_diskstream()->resolve_tracker(_immediate_events, Port::port_offset());
        }
 }
 
index d68502713c840caa2c63df731c5ed2302d53d91d..d03024b64b215a4a2c47d70dd867aaf2a68b8d56 100644 (file)
@@ -50,6 +50,7 @@
 #include "ardour/midi_state_tracker.h"
 #include "ardour/plugin.h"
 #include "ardour/plugin_manager.h"
+#include "ardour/port.h"
 #include "ardour/session.h"
 #include "ardour/types.h"
 
@@ -304,7 +305,7 @@ Plugin::resolve_midi ()
        */
 
        _pending_stop_events.get_midi(0).clear ();
-       _tracker.resolve_notes (_pending_stop_events.get_midi (0), 0);
+       _tracker.resolve_notes (_pending_stop_events.get_midi (0), /* split cycle offset*/ Port::port_offset());
        _have_pending_stop_events = true;
 }