2 Copyright (C) 2006, 2013 Paul Davis
3 Copyright (C) 2013, 2014 Robin Gareus <robin@gareus.org>
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2 of the License, or (at your option)
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "pbd/compose.h"
25 #include "ardour/debug.h"
26 #include "ardour/audio_buffer.h"
27 #include "ardour/midi_buffer.h"
28 #include "ardour/buffer_set.h"
29 #include "ardour/delayline.h"
33 using namespace ARDOUR;
35 DelayLine::DelayLine (Session& s, const std::string& name)
36 : Processor (s, string_compose ("latcomp-%1-%2", name, this))
43 , _pending_flush(false)
47 DelayLine::~DelayLine ()
52 DelayLine::set_name (const string& name)
54 return Processor::set_name (string_compose ("latcomp-%1-%2", name, this));
59 DelayLine::run (BufferSet& bufs, samplepos_t /* start_sample */, samplepos_t /* end_sample */, double /* speed */, pframes_t nsamples, bool)
61 const uint32_t chn = _configured_output.n_audio();
65 const sampleoffset_t pending_delay = _pending_delay;
66 const sampleoffset_t delay_diff = _delay - pending_delay;
67 const bool pending_flush = _pending_flush;
68 _pending_flush = false;
70 /* run() and set_delay() may be called in parallel by
72 * if a larger buffer is needed, it is allocated in
73 * set_delay(), here it is just swap'ed in place
76 assert(_pending_bsiz >= _bsiz);
78 const size_t boff = _pending_bsiz - _bsiz;
80 /* write offset is retained. copy existing data to new buffer */
81 sampleoffset_t wl = _bsiz - _woff;
82 memcpy(_pending_buf.get(), _buf.get(), sizeof(Sample) * _woff * chn);
83 memcpy(_pending_buf.get() + (_pending_bsiz - wl) * chn, _buf.get() + _woff * chn, sizeof(Sample) * wl * chn);
85 /* new buffer is all zero by default, fade into the existing data copied above */
86 sampleoffset_t wo = _pending_bsiz - wl;
87 for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
88 const gain_t gain = (gain_t)pos / (gain_t)FADE_LEN;
89 for (c = 0; c < _configured_output.n_audio(); ++c) {
90 _pending_buf.get()[ wo * chn + c ] *= gain;
91 wo = (wo + 1) % (_pending_bsiz + 1);
95 /* read-pointer will be moved and may up anywhere..
96 * copy current data for smooth fade-out below
98 sampleoffset_t roold = _roff;
99 sampleoffset_t ro = _roff;
105 ro -= (_pending_bsiz + 1) * floor(ro / (float)(_pending_bsiz + 1));
107 ro = ro % (_pending_bsiz + 1);
108 for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
109 for (c = 0; c < _configured_output.n_audio(); ++c) {
110 _pending_buf.get()[ ro * chn + c ] = _buf.get()[ roold * chn + c ];
112 ro = (ro + 1) % (_pending_bsiz + 1);
113 roold = (roold + 1) % (_bsiz + 1);
121 // use shared_array::swap() ??
123 _bsiz = _pending_bsiz;
125 _pending_buf.reset();
128 /* there may be no buffer when delay == 0.
129 * we also need to check audio-channels in case all audio-channels
130 * were removed in which case no new buffer was allocated. */
131 Sample *buf = _buf.get();
132 if (buf && _configured_output.n_audio() > 0) {
134 assert (_bsiz >= pending_delay);
135 const samplecnt_t rbs = _bsiz + 1;
137 if (pending_delay != _delay || pending_flush) {
138 const pframes_t fade_len = (nsamples >= FADE_LEN) ? FADE_LEN : nsamples / 2;
140 DEBUG_TRACE (DEBUG::LatencyCompensation,
141 string_compose ("Old %1 delay: %2 bufsiz: %3 offset-diff: %4 write-offset: %5 read-offset: %6\n",
142 name(), _delay, _bsiz, ((_woff - _roff + rbs) % rbs), _woff, _roff));
144 // fade out at old position
146 for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
147 Sample * const data = i->data();
148 sampleoffset_t roff = _roff;
149 sampleoffset_t woff = _woff;
150 for (pframes_t pos = 0; pos < fade_len; ++pos) {
151 const gain_t gain = (gain_t)(fade_len - pos) / (gain_t)fade_len;
152 buf[ woff * chn + c ] = data[ pos ];
153 data[ pos ] = buf[ roff * chn + c ] * gain;
154 roff = (roff + 1) % rbs;
155 woff = (woff + 1) % rbs;
158 _roff = (_roff + fade_len) % rbs;
159 _woff = (_woff + fade_len) % rbs;
162 DEBUG_TRACE (DEBUG::LatencyCompensation,
163 string_compose ("Flush buffer: %1\n", name()));
164 memset(buf, 0, _configured_output.n_audio() * rbs * sizeof (Sample));
167 // adjust read pointer
168 _roff += _delay - pending_delay;
171 _roff -= rbs * floor(_roff / (float)rbs);
175 // fade in at new position
177 for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
178 Sample * const data = i->data();
179 sampleoffset_t roff = _roff;
180 sampleoffset_t woff = _woff;
181 for (pframes_t pos = fade_len; pos < 2 * fade_len; ++pos) {
182 const gain_t gain = (gain_t)(pos - fade_len) / (gain_t)fade_len;
183 buf[ woff * chn + c ] = data[ pos ];
184 data[ pos ] = buf[ roff * chn + c ] * gain;
185 roff = (roff + 1) % rbs;
186 woff = (woff + 1) % rbs;
189 _roff = (_roff + fade_len) % rbs;
190 _woff = (_woff + fade_len) % rbs;
193 _delay = pending_delay;
195 DEBUG_TRACE (DEBUG::LatencyCompensation,
196 string_compose ("New %1 delay: %2 bufsiz: %3 offset-diff: %4 write-offset: %5 read-offset: %6\n",
197 name(), _delay, _bsiz, ((_woff - _roff + rbs) % rbs), _woff, _roff));
200 assert(_delay == ((_woff - _roff + rbs) % rbs));
203 for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end() && c <= chn; ++i, ++c) {
204 Sample * const data = i->data();
205 sampleoffset_t roff = _roff;
206 sampleoffset_t woff = _woff;
207 for (pframes_t pos = p0; pos < nsamples; ++pos) {
208 buf[ woff * chn + c ] = data[ pos ];
209 data[ pos ] = buf[ roff * chn + c ];
210 roff = (roff + 1) % rbs;
211 woff = (woff + 1) % rbs;
214 _roff = (_roff + nsamples) % rbs;
215 _woff = (_woff + nsamples) % rbs;
218 if (_midi_buf.get()) {
219 _delay = pending_delay;
221 for (BufferSet::midi_iterator i = bufs.midi_begin(); i != bufs.midi_end(); ++i) {
222 if (i != bufs.midi_begin()) { break; } // XXX only one buffer for now
224 MidiBuffer* dly = _midi_buf.get();
227 dly->silence(nsamples);
230 // If the delay time changes, iterate over all events in the dly-buffer
231 // and adjust the time in-place. <= 0 becomes 0.
233 // iterate over all events in dly-buffer and subtract one cycle
234 // (nsamples) from the timestamp, bringing them closer to de-queue.
235 for (MidiBuffer::iterator m = dly->begin(); m != dly->end(); ++m) {
236 MidiBuffer::TimeType *t = m.timeptr();
237 if (*t > nsamples + delay_diff) {
238 *t -= nsamples + delay_diff;
245 // delay events in current-buffer, in place.
246 for (MidiBuffer::iterator m = mb.begin(); m != mb.end(); ++m) {
247 MidiBuffer::TimeType *t = m.timeptr();
252 // move events from dly-buffer into current-buffer until nsamples
253 // and remove them from the dly-buffer
254 for (MidiBuffer::iterator m = dly->begin(); m != dly->end();) {
255 const Evoral::Event<MidiBuffer::TimeType> ev (*m, false);
256 if (ev.time() >= nsamples) {
263 /* For now, this is only relevant if there is there's a positive delay.
264 * In the future this could also be used to delay 'too early' events
265 * (ie '_global_port_buffer_offset + _port_buffer_offset' - midi_port.cc)
268 // move events after nsamples from current-buffer into dly-buffer
269 // and trim current-buffer after nsamples
270 for (MidiBuffer::iterator m = mb.begin(); m != mb.end();) {
271 const Evoral::Event<MidiBuffer::TimeType> ev (*m, false);
272 if (ev.time() < nsamples) {
276 dly->insert_event(ev);
283 _delay = pending_delay;
287 DelayLine::set_delay(samplecnt_t signal_delay)
289 if (signal_delay < 0) {
291 cerr << "WARNING: latency compensation is not possible.\n";
294 if (signal_delay == _pending_delay) {
295 DEBUG_TRACE (DEBUG::LatencyCompensation,
296 string_compose ("%1 set_delay - no change: %2 samples for %3 channels\n",
297 name(), signal_delay, _configured_output.n_audio()));
301 DEBUG_TRACE (DEBUG::LatencyCompensation,
302 string_compose ("%1 set_delay to %2 samples for %3 channels\n",
303 name(), signal_delay, _configured_output.n_audio()));
305 if (signal_delay <= _bsiz) {
306 _pending_delay = signal_delay;
311 if (_pending_bsiz < signal_delay) {
312 cerr << "LatComp: buffer resize in progress. "<< name() << "pending: "<< _pending_bsiz <<" want: " << signal_delay <<"\n"; // XXX
314 _pending_delay = signal_delay;
319 allocate_pending_buffers (signal_delay);
321 _pending_delay = signal_delay;
323 DEBUG_TRACE (DEBUG::LatencyCompensation,
324 string_compose ("allocated buffer for %1 of size %2\n",
325 name(), signal_delay));
331 DelayLine::can_support_io_configuration (const ChanCount& in, ChanCount& out)
338 DelayLine::allocate_pending_buffers (samplecnt_t signal_delay)
340 assert (signal_delay >= 0);
341 const samplecnt_t rbs = signal_delay + 1;
343 if (_configured_output.n_audio() > 0 ) {
344 _pending_buf.reset(new Sample[_configured_output.n_audio() * rbs]);
345 memset(_pending_buf.get(), 0, _configured_output.n_audio() * rbs * sizeof (Sample));
346 _pending_bsiz = signal_delay;
348 _pending_buf.reset();
354 DelayLine::configure_io (ChanCount in, ChanCount out)
356 if (out != in) { // always 1:1
360 if (_configured_output != out) {
361 // run() won't be called concurrently, so it's
362 // save for replace existing _pending_buf.
364 // configure_io is either called with process-lock held
365 // from route's configure_io() or by use_target() from the c'tor.
366 allocate_pending_buffers (_pending_delay);
369 DEBUG_TRACE (DEBUG::LatencyCompensation,
370 string_compose ("configure IO: %1 Ain: %2 Aout: %3 Min: %4 Mout: %5\n",
371 name(), in.n_audio(), out.n_audio(), in.n_midi(), out.n_midi()));
373 // TODO support multiple midi buffers
374 if (in.n_midi() > 0 && !_midi_buf) {
375 _midi_buf.reset(new MidiBuffer(16384));
378 return Processor::configure_io (in, out);
384 _pending_flush = true;
388 DelayLine::state (bool full_state)
390 XMLNode& node (Processor::state (full_state));
391 node.set_property("type", "delay");