fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / delayline.cc
1 /*
2     Copyright (C) 2006, 2013 Paul Davis
3     Copyright (C) 2013, 2014 Robin Gareus <robin@gareus.org>
4
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)
8     any later version.
9
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
13     for more details.
14
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.
18 */
19
20 #include <assert.h>
21 #include <cmath>
22
23 #include "pbd/compose.h"
24
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"
30
31 using namespace std;
32 using namespace PBD;
33 using namespace ARDOUR;
34
35 DelayLine::DelayLine (Session& s, const std::string& name)
36     : Processor (s, string_compose ("latency-compensation-%1", name))
37                 , _delay(0)
38                 , _pending_delay(0)
39                 , _bsiz(0)
40                 , _pending_bsiz(0)
41                 , _roff(0)
42                 , _woff(0)
43                 , _pending_flush(false)
44 {
45 }
46
47 DelayLine::~DelayLine ()
48 {
49 }
50
51 #define FADE_LEN (16)
52 void
53 DelayLine::run (BufferSet& bufs, framepos_t /* start_frame */, framepos_t /* end_frame */, double /* speed */, pframes_t nsamples, bool)
54 {
55         const uint32_t chn = _configured_output.n_audio();
56         pframes_t p0 = 0;
57         uint32_t c;
58
59         const frameoffset_t pending_delay = _pending_delay;
60         const frameoffset_t delay_diff = _delay - pending_delay;
61         const bool pending_flush = _pending_flush;
62         _pending_flush = false;
63
64         /* run() and set_delay() may be called in parallel by
65          * different threads.
66          * if a larger buffer is needed, it is allocated in
67          * set_delay(), here it is just swap'ed in place
68          */
69         if (_pending_bsiz) {
70                 assert(_pending_bsiz >= _bsiz);
71
72                 const size_t boff = _pending_bsiz - _bsiz;
73                 if (_bsiz > 0) {
74                         /* write offset is retained. copy existing data to new buffer */
75                         frameoffset_t wl = _bsiz - _woff;
76                         memcpy(_pending_buf.get(), _buf.get(), sizeof(Sample) * _woff * chn);
77                         memcpy(_pending_buf.get() + (_pending_bsiz - wl) * chn, _buf.get() + _woff * chn, sizeof(Sample) * wl * chn);
78
79                         /* new buffer is all zero by default, fade into the existing data copied above */
80                         frameoffset_t wo = _pending_bsiz - wl;
81                         for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
82                                 const gain_t gain = (gain_t)pos / (gain_t)FADE_LEN;
83                                 for (c = 0; c < _configured_input.n_audio(); ++c) {
84                                         _pending_buf.get()[ wo * chn + c ] *= gain;
85                                         wo = (wo + 1) % (_pending_bsiz + 1);
86                                 }
87                         }
88
89                         /* read-pointer will be moved and may up anywhere..
90                          * copy current data for smooth fade-out below
91                          */
92                         frameoffset_t roold = _roff;
93                         frameoffset_t ro = _roff;
94                         if (ro > _woff) {
95                                 ro += boff;
96                         }
97                         ro += delay_diff;
98                         if (ro < 0) {
99                                 ro -= (_pending_bsiz +1) * floor(ro / (float)(_pending_bsiz +1));
100                         }
101                         ro = ro % (_pending_bsiz + 1);
102                         for (pframes_t pos = 0; pos < FADE_LEN; ++pos) {
103                                 for (c = 0; c < _configured_input.n_audio(); ++c) {
104                                         _pending_buf.get()[ ro * chn + c ] = _buf.get()[ roold * chn + c ];
105                                         ro = (ro + 1) % (_pending_bsiz + 1);
106                                         roold = (roold + 1) % (_bsiz + 1);
107                                 }
108                         }
109                 }
110
111                 if (_roff > _woff) {
112                         _roff += boff;
113                 }
114
115                 // use shared_array::swap() ??
116                 _buf = _pending_buf;
117                 _bsiz = _pending_bsiz;
118                 _pending_bsiz = 0;
119                 _pending_buf.reset();
120         }
121
122         /* there may be no buffer when delay == 0.
123          * we also need to check audio-channels in case all audio-channels
124          * were removed in which case no new buffer was allocated. */
125         Sample *buf = _buf.get();
126         if (buf && _configured_output.n_audio() > 0) {
127
128                 assert (_bsiz >= pending_delay);
129                 const framecnt_t rbs = _bsiz + 1;
130
131                 if (pending_delay != _delay || pending_flush) {
132                         const pframes_t fade_len = (nsamples >= FADE_LEN) ? FADE_LEN : nsamples / 2;
133
134                         DEBUG_TRACE (DEBUG::LatencyCompensation,
135                                         string_compose ("Old %1 delay: %2 bufsiz: %3 offset-diff: %4 write-offset: %5 read-offset: %6\n",
136                                                 name(), _delay, _bsiz, ((_woff - _roff + rbs) % rbs), _woff, _roff));
137
138                         // fade out at old position
139                         c = 0;
140                         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
141                                 Sample * const data = i->data();
142                                 for (pframes_t pos = 0; pos < fade_len; ++pos) {
143                                         const gain_t gain = (gain_t)(fade_len - pos) / (gain_t)fade_len;
144                                         buf[ _woff * chn + c ] = data[ pos ];
145                                         data[ pos ] = buf[ _roff * chn + c ] * gain;
146                                         _roff = (_roff + 1) % rbs;
147                                         _woff = (_woff + 1) % rbs;
148                                 }
149                         }
150
151                         if (pending_flush) {
152                                 DEBUG_TRACE (DEBUG::LatencyCompensation,
153                                                 string_compose ("Flush buffer: %1\n", name()));
154                                 memset(buf, 0, _configured_output.n_audio() * rbs * sizeof (Sample));
155                         }
156
157                         // adjust read pointer
158                         _roff += _delay - pending_delay;
159
160                         if (_roff < 0) {
161                                 _roff -= rbs * floor(_roff / (float)rbs);
162                         }
163                         _roff = _roff % rbs;
164
165                         // fade in at new position
166                         c = 0;
167                         for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
168                                 Sample * const data = i->data();
169                                 for (pframes_t pos = fade_len; pos < 2 * fade_len; ++pos) {
170                                         const gain_t gain = (gain_t)(pos - fade_len) / (gain_t)fade_len;
171                                         buf[ _woff * chn + c ] = data[ pos ];
172                                         data[ pos ] = buf[ _roff * chn + c ] * gain;
173                                         _roff = (_roff + 1) % rbs;
174                                         _woff = (_woff + 1) % rbs;
175                                 }
176                         }
177                         p0  = 2 * fade_len;
178
179                         _delay = pending_delay;
180
181                         DEBUG_TRACE (DEBUG::LatencyCompensation,
182                                         string_compose ("New %1 delay: %2 bufsiz: %3 offset-diff: %4 write-offset: %5 read-offset: %6\n",
183                                                 name(), _delay, _bsiz, ((_woff - _roff + rbs) % rbs), _woff, _roff));
184                 }
185
186                 assert(_delay == ((_woff - _roff + rbs) % rbs));
187
188                 c = 0;
189                 for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++c) {
190                         Sample * const data = i->data();
191                         for (pframes_t pos = p0; pos < nsamples; ++pos) {
192                                 buf[ _woff * chn + c ] = data[ pos ];
193                                 data[ pos ] = buf[ _roff * chn + c ];
194                                 _roff = (_roff + 1) % rbs;
195                                 _woff = (_woff + 1) % rbs;
196                         }
197                 }
198         }
199
200         if (_midi_buf.get()) {
201                 _delay = pending_delay;
202
203                 for (BufferSet::midi_iterator i = bufs.midi_begin(); i != bufs.midi_end(); ++i) {
204                         if (i != bufs.midi_begin()) { break; } // XXX only one buffer for now
205
206                         MidiBuffer* dly = _midi_buf.get();
207                         MidiBuffer& mb (*i);
208                         if (pending_flush) {
209                                 dly->silence(nsamples);
210                         }
211
212                         // If the delay time changes, iterate over all events in the dly-buffer
213                         // and adjust the time in-place. <= 0 becomes 0.
214                         //
215                         // iterate over all events in dly-buffer and subtract one cycle
216                         // (nsamples) from the timestamp, bringing them closer to de-queue.
217                         for (MidiBuffer::iterator m = dly->begin(); m != dly->end(); ++m) {
218                                 MidiBuffer::TimeType *t = m.timeptr();
219                                 if (*t > nsamples + delay_diff) {
220                                         *t -= nsamples + delay_diff;
221                                 } else {
222                                         *t = 0;
223                                 }
224                         }
225
226                         if (_delay != 0) {
227                                 // delay events in current-buffer, in place.
228                                 for (MidiBuffer::iterator m = mb.begin(); m != mb.end(); ++m) {
229                                         MidiBuffer::TimeType *t = m.timeptr();
230                                         *t += _delay;
231                                 }
232                         }
233
234                         // move events from dly-buffer into current-buffer until nsamples
235                         // and remove them from the dly-buffer
236                         for (MidiBuffer::iterator m = dly->begin(); m != dly->end();) {
237                                 const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*m, false);
238                                 if (ev.time() >= nsamples) {
239                                         break;
240                                 }
241                                 mb.insert_event(ev);
242                                 m = dly->erase(m);
243                         }
244
245                         /* For now, this is only relevant if there is there's a positive delay.
246                          * In the future this could also be used to delay 'too early' events
247                          * (ie '_global_port_buffer_offset + _port_buffer_offset' - midi_port.cc)
248                          */
249                         if (_delay != 0) {
250                                 // move events after nsamples from current-buffer into dly-buffer
251                                 // and trim current-buffer after nsamples
252                                 for (MidiBuffer::iterator m = mb.begin(); m != mb.end();) {
253                                         const Evoral::MIDIEvent<MidiBuffer::TimeType> ev (*m, false);
254                                         if (ev.time() < nsamples) {
255                                                 ++m;
256                                                 continue;
257                                         }
258                                         dly->insert_event(ev);
259                                         m = mb.erase(m);
260                                 }
261                         }
262                 }
263         }
264
265         _delay = pending_delay;
266 }
267
268 void
269 DelayLine::set_delay(framecnt_t signal_delay)
270 {
271         if (signal_delay < 0) {
272                 signal_delay = 0;
273                 cerr << "WARNING: latency compensation is not possible.\n";
274         }
275
276         const framecnt_t rbs = signal_delay + 1;
277
278         DEBUG_TRACE (DEBUG::LatencyCompensation,
279                         string_compose ("%1 set_delay to %2 samples for %3 channels\n",
280                                 name(), signal_delay, _configured_output.n_audio()));
281
282         if (signal_delay <= _bsiz) {
283                 _pending_delay = signal_delay;
284                 return;
285         }
286
287         if (_pending_bsiz) {
288                 if (_pending_bsiz < signal_delay) {
289                         cerr << "LatComp: buffer resize in progress. "<< name() << "pending: "<< _pending_bsiz <<" want: " << signal_delay <<"\n"; // XXX
290                 } else {
291                         _pending_delay = signal_delay;
292                 }
293                 return;
294         }
295
296         if (_configured_output.n_audio() > 0 ) {
297                 _pending_buf.reset(new Sample[_configured_output.n_audio() * rbs]);
298                 memset(_pending_buf.get(), 0, _configured_output.n_audio() * rbs * sizeof (Sample));
299                 _pending_bsiz = signal_delay;
300         } else {
301                 _pending_buf.reset();
302                 _pending_bsiz = 0;
303         }
304
305         _pending_delay = signal_delay;
306
307         DEBUG_TRACE (DEBUG::LatencyCompensation,
308                         string_compose ("allocated buffer for %1 of size %2\n",
309                                 name(), signal_delay));
310 }
311
312 bool
313 DelayLine::can_support_io_configuration (const ChanCount& in, ChanCount& out)
314 {
315         out = in;
316         return true;
317 }
318
319 bool
320 DelayLine::configure_io (ChanCount in, ChanCount out)
321 {
322         if (out != in) { // always 1:1
323                 return false;
324         }
325
326         // TODO realloc buffers if channel count changes..
327         // TODO support multiple midi buffers
328
329         DEBUG_TRACE (DEBUG::LatencyCompensation,
330                         string_compose ("configure IO: %1 Ain: %2 Aout: %3 Min: %4 Mout: %5\n",
331                                 name(), in.n_audio(), out.n_audio(), in.n_midi(), out.n_midi()));
332
333         if (in.n_midi() > 0 && !_midi_buf) {
334                 _midi_buf.reset(new MidiBuffer(16384));
335         }
336
337         return Processor::configure_io (in, out);
338 }
339
340 void
341 DelayLine::flush()
342 {
343         _pending_flush = true;
344 }
345
346 XMLNode&
347 DelayLine::state (bool full_state)
348 {
349         XMLNode& node (Processor::state (full_state));
350         node.add_property("type", "delay");
351         return node;
352 }