fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / fixed_delay.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18
19 #include "ardour/audio_buffer.h"
20 #include "ardour/buffer_set.h"
21 #include "ardour/fixed_delay.h"
22 #include "ardour/midi_buffer.h"
23
24 using namespace ARDOUR;
25
26 FixedDelay::FixedDelay ()
27         : _max_delay (0)
28         , _buf_size (0)
29         , _delay (0)
30 {
31         for (size_t i = 0; i < DataType::num_types; ++i) {
32                 _buffers.push_back (BufferVec ());
33         }
34         _count.reset ();
35 }
36
37 FixedDelay::~FixedDelay ()
38 {
39         clear ();
40 }
41
42 void
43 FixedDelay::ensure_buffers (DataType type, size_t num_buffers, size_t buffer_capacity)
44 {
45         assert (type != DataType::NIL);
46         assert (type < _buffers.size ());
47         if (num_buffers == 0) {
48                 return;
49         }
50         BufferVec& bufs = _buffers[type];
51         if (bufs.size () < num_buffers || (bufs.size () > 0 && bufs[0]->buf->capacity () < buffer_capacity)) {
52                 for (BufferVec::iterator i = bufs.begin (); i != bufs.end (); ++i) {
53                         delete (*i);
54                 }
55                 bufs.clear ();
56                 for (size_t i = 0; i < num_buffers; ++i) {
57                         bufs.push_back (new DelayBuffer (type, buffer_capacity));
58                 }
59                 _count.set (type, num_buffers);
60         }
61 }
62
63 void
64 FixedDelay::clear ()
65 {
66         for (std::vector<BufferVec>::iterator i = _buffers.begin (); i != _buffers.end (); ++i) {
67                 for (BufferVec::iterator j = (*i).begin (); j != (*i).end (); ++j) {
68                         delete *j;
69                 }
70                 (*i).clear ();
71         }
72         _buffers.clear ();
73         _count.reset ();
74 }
75
76 void
77 FixedDelay::flush()
78 {
79         for (std::vector<BufferVec>::iterator i = _buffers.begin (); i != _buffers.end (); ++i) {
80                 for (BufferVec::iterator j = (*i).begin (); j != (*i).end (); ++j) {
81                         (*j)->buf->silence (_buf_size);
82                 }
83         }
84 }
85
86 void
87 FixedDelay::configure (const ChanCount& count, framecnt_t max_delay, bool shrink)
88 {
89         if (shrink) {
90                 if (max_delay == _max_delay && count == _count) {
91                         return;
92                 }
93                 _max_delay = max_delay;
94         } else if (max_delay <= _max_delay || count <= _count) {
95                 return;
96                 _max_delay = std::max (_max_delay, max_delay);
97         }
98
99         // max possible (with all engines and during export)
100         static const framecnt_t max_block_length = 8192;
101         _buf_size = _max_delay + max_block_length;
102         for (DataType::iterator i = DataType::begin (); i != DataType::end (); ++i) {
103                 ensure_buffers (*i, count.get (*i), _buf_size);
104         }
105 }
106
107 void
108 FixedDelay::set (const ChanCount& count, framecnt_t delay)
109 {
110         configure (count, delay, false);
111         if (_delay != delay) {
112                 flush ();
113         }
114         _delay = delay;
115 }
116
117 void
118 FixedDelay::delay (
119                 ARDOUR::DataType dt, uint32_t id,
120                 Buffer& out, const Buffer& in,
121                 pframes_t n_frames,
122                 framecnt_t dst_offset, framecnt_t src_offset)
123 {
124         if (_delay == 0) {
125                 out.read_from (in, n_frames, dst_offset, src_offset);
126                 return;
127         }
128
129         assert (dt < _buffers.size ());
130         assert (id < _buffers[dt].size ());
131         DelayBuffer *db = _buffers[dt][id];
132
133         if (db->pos + n_frames > _buf_size) {
134                 uint32_t w0 = _buf_size - db->pos;
135                 uint32_t w1 = db->pos + n_frames - _buf_size;
136                 db->buf->read_from (in, w0, db->pos, src_offset);
137                 db->buf->read_from (in, w1, 0, src_offset + w0);
138         } else {
139                 db->buf->read_from (in, n_frames, db->pos, src_offset);
140         }
141
142         uint32_t rp = (db->pos + _buf_size - _delay) % _buf_size;
143
144         if (rp + n_frames > _buf_size) {
145                 uint32_t r0 = _buf_size - rp;
146                 uint32_t r1 = rp + n_frames - _buf_size;
147                 out.read_from (*db->buf, r0, dst_offset, rp);
148                 out.read_from (*db->buf, r1, dst_offset + r0, 0);
149         } else {
150                 out.read_from (*db->buf, n_frames, dst_offset, rp);
151         }
152
153         db->pos = (db->pos + n_frames) % _buf_size;
154 }