using namespace ARDOUR;
DelayLine::DelayLine (Session& s, const std::string& name)
- : Processor (s, string_compose ("latency-compensation-%1", name))
+ : Processor (s, string_compose ("latcomp-%1-%2", name, this))
, _delay(0)
, _pending_delay(0)
, _bsiz(0)
{
}
+bool
+DelayLine::set_name (const string& name)
+{
+ return Processor::set_name (string_compose ("latcomp-%1-%2", name, this));
+}
+
#define FADE_LEN (16)
void
-DelayLine::run (BufferSet& bufs, framepos_t /* start_frame */, framepos_t /* end_frame */, double /* speed */, pframes_t nsamples, bool)
+DelayLine::run (BufferSet& bufs, samplepos_t /* start_sample */, samplepos_t /* end_sample */, double /* speed */, pframes_t nsamples, bool)
{
const uint32_t chn = _configured_output.n_audio();
pframes_t p0 = 0;
uint32_t c;
- const frameoffset_t pending_delay = _pending_delay;
- const frameoffset_t delay_diff = _delay - pending_delay;
+ const sampleoffset_t pending_delay = _pending_delay;
+ const sampleoffset_t delay_diff = _delay - pending_delay;
const bool pending_flush = _pending_flush;
_pending_flush = false;
const size_t boff = _pending_bsiz - _bsiz;
if (_bsiz > 0) {
/* write offset is retained. copy existing data to new buffer */
- frameoffset_t wl = _bsiz - _woff;
+ sampleoffset_t wl = _bsiz - _woff;
memcpy(_pending_buf.get(), _buf.get(), sizeof(Sample) * _woff * chn);
memcpy(_pending_buf.get() + (_pending_bsiz - wl) * chn, _buf.get() + _woff * chn, sizeof(Sample) * wl * chn);
/* new buffer is all zero by default, fade into the existing data copied above */
- frameoffset_t wo = _pending_bsiz - wl;
+ sampleoffset_t wo = _pending_bsiz - wl;
for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
const gain_t gain = (gain_t)pos / (gain_t)FADE_LEN;
- for (c = 0; c < _configured_input.n_audio(); ++c) {
+ for (c = 0; c < _configured_output.n_audio(); ++c) {
_pending_buf.get()[ wo * chn + c ] *= gain;
wo = (wo + 1) % (_pending_bsiz + 1);
}
/* read-pointer will be moved and may up anywhere..
* copy current data for smooth fade-out below
*/
- frameoffset_t roold = _roff;
- frameoffset_t ro = _roff;
+ sampleoffset_t roold = _roff;
+ sampleoffset_t ro = _roff;
if (ro > _woff) {
ro += boff;
}
ro += delay_diff;
if (ro < 0) {
- ro -= (_pending_bsiz +1) * floor(ro / (float)(_pending_bsiz +1));
+ ro -= (_pending_bsiz + 1) * floor(ro / (float)(_pending_bsiz + 1));
}
ro = ro % (_pending_bsiz + 1);
for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
- for (c = 0; c < _configured_input.n_audio(); ++c) {
+ for (c = 0; c < _configured_output.n_audio(); ++c) {
_pending_buf.get()[ ro * chn + c ] = _buf.get()[ roold * chn + c ];
- ro = (ro + 1) % (_pending_bsiz + 1);
- roold = (roold + 1) % (_bsiz + 1);
}
+ ro = (ro + 1) % (_pending_bsiz + 1);
+ roold = (roold + 1) % (_bsiz + 1);
}
}
if (buf && _configured_output.n_audio() > 0) {
assert (_bsiz >= pending_delay);
- const framecnt_t rbs = _bsiz + 1;
+ const samplecnt_t rbs = _bsiz + 1;
if (pending_delay != _delay || pending_flush) {
const pframes_t fade_len = (nsamples >= FADE_LEN) ? FADE_LEN : nsamples / 2;
// fade out at old position
c = 0;
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
+ for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
Sample * const data = i->data();
+ sampleoffset_t roff = _roff;
+ sampleoffset_t woff = _woff;
for (pframes_t pos = 0; pos < fade_len; ++pos) {
const gain_t gain = (gain_t)(fade_len - pos) / (gain_t)fade_len;
- buf[ _woff * chn + c ] = data[ pos ];
- data[ pos ] = buf[ _roff * chn + c ] * gain;
- _roff = (_roff + 1) % rbs;
- _woff = (_woff + 1) % rbs;
+ buf[ woff * chn + c ] = data[ pos ];
+ data[ pos ] = buf[ roff * chn + c ] * gain;
+ roff = (roff + 1) % rbs;
+ woff = (woff + 1) % rbs;
}
}
+ _roff = (_roff + fade_len) % rbs;
+ _woff = (_woff + fade_len) % rbs;
if (pending_flush) {
DEBUG_TRACE (DEBUG::LatencyCompensation,
// fade in at new position
c = 0;
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
+ for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
Sample * const data = i->data();
+ sampleoffset_t roff = _roff;
+ sampleoffset_t woff = _woff;
for (pframes_t pos = fade_len; pos < 2 * fade_len; ++pos) {
const gain_t gain = (gain_t)(pos - fade_len) / (gain_t)fade_len;
- buf[ _woff * chn + c ] = data[ pos ];
- data[ pos ] = buf[ _roff * chn + c ] * gain;
- _roff = (_roff + 1) % rbs;
- _woff = (_woff + 1) % rbs;
+ buf[ woff * chn + c ] = data[ pos ];
+ data[ pos ] = buf[ roff * chn + c ] * gain;
+ roff = (roff + 1) % rbs;
+ woff = (woff + 1) % rbs;
}
}
+ _roff = (_roff + fade_len) % rbs;
+ _woff = (_woff + fade_len) % rbs;
p0 = 2 * fade_len;
_delay = pending_delay;
assert(_delay == ((_woff - _roff + rbs) % rbs));
c = 0;
- for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
+ for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
Sample * const data = i->data();
+ sampleoffset_t roff = _roff;
+ sampleoffset_t woff = _woff;
for (pframes_t pos = p0; pos < nsamples; ++pos) {
- buf[ _woff * chn + c ] = data[ pos ];
- data[ pos ] = buf[ _roff * chn + c ];
- _roff = (_roff + 1) % rbs;
- _woff = (_woff + 1) % rbs;
+ buf[ woff * chn + c ] = data[ pos ];
+ data[ pos ] = buf[ roff * chn + c ];
+ roff = (roff + 1) % rbs;
+ woff = (woff + 1) % rbs;
}
}
+ _roff = (_roff + nsamples) % rbs;
+ _woff = (_woff + nsamples) % rbs;
}
if (_midi_buf.get()) {
_delay = pending_delay;
}
-void
-DelayLine::set_delay(framecnt_t signal_delay)
+bool
+DelayLine::set_delay(samplecnt_t signal_delay)
{
if (signal_delay < 0) {
signal_delay = 0;
cerr << "WARNING: latency compensation is not possible.\n";
}
- const framecnt_t rbs = signal_delay + 1;
+ if (signal_delay == _pending_delay) {
+ DEBUG_TRACE (DEBUG::LatencyCompensation,
+ string_compose ("%1 set_delay - no change: %2 samples for %3 channels\n",
+ name(), signal_delay, _configured_output.n_audio()));
+ return false;
+ }
DEBUG_TRACE (DEBUG::LatencyCompensation,
string_compose ("%1 set_delay to %2 samples for %3 channels\n",
if (signal_delay <= _bsiz) {
_pending_delay = signal_delay;
- return;
+ return true;
}
if (_pending_bsiz) {
} else {
_pending_delay = signal_delay;
}
- return;
+ return true;
}
- if (_configured_output.n_audio() > 0 ) {
- _pending_buf.reset(new Sample[_configured_output.n_audio() * rbs]);
- memset(_pending_buf.get(), 0, _configured_output.n_audio() * rbs * sizeof (Sample));
- _pending_bsiz = signal_delay;
- } else {
- _pending_buf.reset();
- _pending_bsiz = 0;
- }
+ allocate_pending_buffers (signal_delay);
_pending_delay = signal_delay;
DEBUG_TRACE (DEBUG::LatencyCompensation,
string_compose ("allocated buffer for %1 of size %2\n",
name(), signal_delay));
+
+ return true;
}
bool
return true;
}
+void
+DelayLine::allocate_pending_buffers (samplecnt_t signal_delay)
+{
+ assert (signal_delay >= 0);
+ const samplecnt_t rbs = signal_delay + 1;
+
+ if (_configured_output.n_audio() > 0 ) {
+ _pending_buf.reset(new Sample[_configured_output.n_audio() * rbs]);
+ memset(_pending_buf.get(), 0, _configured_output.n_audio() * rbs * sizeof (Sample));
+ _pending_bsiz = signal_delay;
+ } else {
+ _pending_buf.reset();
+ _pending_bsiz = 0;
+ }
+}
+
bool
DelayLine::configure_io (ChanCount in, ChanCount out)
{
return false;
}
- // TODO realloc buffers if channel count changes..
- // TODO support multiple midi buffers
+ if (_configured_output != out) {
+ // run() won't be called concurrently, so it's
+ // save for replace existing _pending_buf.
+ //
+ // configure_io is either called with process-lock held
+ // from route's configure_io() or by use_target() from the c'tor.
+ allocate_pending_buffers (_pending_delay);
+ }
DEBUG_TRACE (DEBUG::LatencyCompensation,
string_compose ("configure IO: %1 Ain: %2 Aout: %3 Min: %4 Mout: %5\n",
name(), in.n_audio(), out.n_audio(), in.n_midi(), out.n_midi()));
+ // TODO support multiple midi buffers
if (in.n_midi() > 0 && !_midi_buf) {
_midi_buf.reset(new MidiBuffer(16384));
}
}
XMLNode&
-DelayLine::state (bool full_state)
+DelayLine::state ()
{
- XMLNode& node (Processor::state (full_state));
- node.add_property("type", "delay");
+ XMLNode& node (Processor::state ());
+ node.set_property("type", "delay");
return node;
}