use a note tracker to resolve notes cut off during render by the end of the region
[ardour.git] / libs / ardour / delayline.cc
index 666ad3e302061ddf38d41745560b93429f0c7551..2ec56c3ae242e04cb527b300ba243ded1d9a5cc0 100644 (file)
@@ -28,6 +28,8 @@
 #include "ardour/midi_buffer.h"
 #include "ardour/runtime_functions.h"
 
+#define MAX_BUFFER_SIZE 8192
+
 using namespace std;
 using namespace PBD;
 using namespace ARDOUR;
@@ -62,10 +64,16 @@ DelayLine::run (BufferSet& bufs, samplepos_t /* start_sample */, samplepos_t /*
        Glib::Threads::Mutex::Lock lm (_set_delay_mutex, Glib::Threads::TRY_LOCK);
        assert (lm.locked ());
 #endif
+       assert (n_samples <= MAX_BUFFER_SIZE);
 
        const sampleoffset_t pending_delay = _pending_delay;
        sampleoffset_t delay_diff = _delay - pending_delay;
        const bool pending_flush = _pending_flush;
+
+       if (delay_diff == 0 && _delay == 0) {
+               return;
+       }
+
        _pending_flush = false;
 
        // TODO handle pending_flush.
@@ -206,6 +214,10 @@ DelayLine::run (BufferSet& bufs, samplepos_t /* start_sample */, samplepos_t /*
        } else {
                /* set new delay for MIDI only */
                _delay = pending_delay;
+
+               /* prepare for the case that an audio-port is added */
+               _woff = _delay;
+               _roff = 0;
        }
 
        if (_midi_buf.get ()) {
@@ -296,7 +308,7 @@ DelayLine::set_delay (samplecnt_t signal_delay)
                        string_compose ("%1 set_delay to %2 samples for %3 channels\n",
                                name (), signal_delay, _configured_output.n_audio ()));
 
-       if (signal_delay + 8192 + 1 > _bsiz) {
+       if (signal_delay + MAX_BUFFER_SIZE + 1 > _bsiz) {
                allocate_pending_buffers (signal_delay, _configured_output);
        }
 
@@ -315,7 +327,19 @@ void
 DelayLine::allocate_pending_buffers (samplecnt_t signal_delay, ChanCount const& cc)
 {
        assert (signal_delay >= 0);
-       samplecnt_t rbs = signal_delay + 8192 + 1;
+#if 1
+       /* If no buffers are required, don't allocate any.
+        * This may backfire later, allocating buffers on demand
+        * may take time and cause x-runs.
+        *
+        * The default buffersize is 4 * 16kB and - once allocated -
+        * usually sufficies for the lifetime of the delayline instance.
+        */
+       if (signal_delay == _pending_delay && signal_delay == 0) {
+               return;
+       }
+#endif
+       samplecnt_t rbs = signal_delay + MAX_BUFFER_SIZE + 1;
        rbs = std::max (_bsiz, rbs);
 
        uint64_t power_of_two;
@@ -326,7 +350,6 @@ DelayLine::allocate_pending_buffers (samplecnt_t signal_delay, ChanCount const&
                return;
        }
 
-       _buf.clear ();
        if (cc.n_audio () == 0) {
                return;
        }
@@ -341,23 +364,30 @@ DelayLine::allocate_pending_buffers (samplecnt_t signal_delay, ChanCount const&
        AudioDlyBuf::iterator bo = _buf.begin ();
        AudioDlyBuf::iterator bn = pending_buf.begin ();
 
+       sampleoffset_t offset = (_roff <= _woff) ? 0 : rbs - _bsiz;
+
        for (; bo != _buf.end () && bn != pending_buf.end(); ++bo, ++bn) {
                Sample* rbo = (*bo).get ();
                Sample* rbn = (*bn).get ();
-               if (_roff < _woff) {
+               if (_roff == _woff) {
+                       continue;
+               } else if (_roff < _woff) {
                        /* copy data between _roff .. _woff to new buffer */
                        copy_vector (&rbn[_roff], &rbo[_roff], _woff - _roff);
                } else {
                        /* copy data between _roff .. old_size to end of new buffer, increment _roff
                         * copy data from 0.._woff to beginning of new buffer
                         */
-                       sampleoffset_t offset = rbs - _bsiz;
                        copy_vector (&rbn[_roff + offset], &rbo[_roff], _bsiz - _roff);
                        copy_vector (rbn, rbo, _woff);
-                       _roff += offset;
-                       assert (_roff < rbs);
                }
        }
+
+       assert (signal_delay >= _pending_delay);
+       assert ((_roff <= (_woff + signal_delay - _pending_delay) & (rbs -1)) || offset > 0);
+       _roff += offset;
+       assert (_roff < rbs);
+
        _bsiz = rbs;
        _bsiz_mask = _bsiz - 1;
        _buf.swap (pending_buf);