1 /*
2 * Copyright (C) 2018-2021 Robin Gareus <robin@gareus.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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 along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <assert.h>
20
21 #include "pbd/error.h"
22 #include "pbd/pthread_utils.h"
23
24 #include "ardour/audio_buffer.h"
25 #include "ardour/audioengine.h"
26 #include "ardour/audiofilesource.h"
27 #include "ardour/chan_mapping.h"
28 #include "ardour/convolver.h"
29 #include "ardour/dsp_filter.h"
30 #include "ardour/readable.h"
31 #include "ardour/session.h"
32 #include "ardour/source_factory.h"
33 #include "ardour/srcfilesource.h"
34 #include "ardour/types.h"
35
36 #include "pbd/i18n.h"
37
38 using namespace ARDOUR;
39 using namespace ARDOUR::DSP;
40 using namespace ArdourZita;
41
Convolution(Session & session,uint32_t n_in,uint32_t n_out)42 Convolution::Convolution (Session& session, uint32_t n_in, uint32_t n_out)
43 : SessionHandleRef (session)
44 , _n_samples (0)
45 , _max_size (0)
46 , _offset (0)
47 , _configured (false)
48 , _threaded (false)
49 , _n_inputs (n_in)
50 , _n_outputs (n_out)
51 {
52 AudioEngine::instance ()->BufferSizeChanged.connect_same_thread (*this, boost::bind (&Convolution::restart, this));
53 }
54
55 bool
add_impdata(uint32_t c_in,uint32_t c_out,boost::shared_ptr<Readable> readable,float gain,uint32_t pre_delay,sampleoffset_t offset,samplecnt_t length,uint32_t channel)56 Convolution::add_impdata (
57 uint32_t c_in,
58 uint32_t c_out,
59 boost::shared_ptr<Readable> readable,
60 float gain,
61 uint32_t pre_delay,
62 sampleoffset_t offset,
63 samplecnt_t length,
64 uint32_t channel)
65 {
66 if (_configured || c_in >= _n_inputs || c_out >= _n_outputs) {
67 return false;
68 }
69 if (!readable || readable->readable_length () <= offset || readable->n_channels () <= channel) {
70 return false;
71 }
72
73 _impdata.push_back (ImpData (c_in, c_out, readable, gain, pre_delay, offset, length));
74 return true;
75 }
76
77 bool
ready() const78 Convolution::ready () const
79 {
80 return _configured && _convproc.state () == Convproc::ST_PROC;
81 }
82
83 void
restart()84 Convolution::restart ()
85 {
86 _convproc.stop_process ();
87 _convproc.cleanup ();
88 _convproc.set_options (0);
89
90 uint32_t n_part;
91
92 if (_threaded) {
93 _n_samples = 64;
94 n_part = Convproc::MAXPART;
95 } else {
96 _n_samples = _session.get_block_size ();
97 uint32_t power_of_two;
98 for (power_of_two = 1; 1U << power_of_two < _n_samples; ++power_of_two) ;
99 _n_samples = 1 << power_of_two;
100 n_part = std::min ((uint32_t)Convproc::MAXPART, _n_samples);
101 }
102
103 _offset = 0;
104 _max_size = 0;
105
106 for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) {
107 _max_size = std::max (_max_size, (uint32_t)i->readable_length ());
108 }
109
110 int rv = _convproc.configure (
111 /*in*/ _n_inputs,
112 /*out*/ _n_outputs,
113 /*max-convolution length */ _max_size,
114 /*quantum, nominal-buffersize*/ _n_samples,
115 /*Convproc::MINPART*/ _n_samples,
116 /*Convproc::MAXPART*/ n_part,
117 /*density 0 = auto, i/o dependent */ 0);
118
119 for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) {
120 uint32_t pos = 0;
121
122 const float ir_gain = i->gain;
123 const uint32_t ir_delay = i->delay;
124 const uint32_t ir_len = i->readable_length ();
125
126 while (true) {
127 float ir[8192];
128
129 samplecnt_t to_read = std::min ((uint32_t)8192, ir_len - pos);
130 samplecnt_t ns = i->read (ir, pos, to_read);
131
132 if (ns == 0) {
133 break;
134 }
135
136 if (ir_gain != 1.f) {
137 for (samplecnt_t i = 0; i < ns; ++i) {
138 ir[i] *= ir_gain;
139 }
140 }
141
142 rv = _convproc.impdata_create (
143 /*i/o map */ i->c_in, i->c_out,
144 /*stride, de-interleave */ 1,
145 ir,
146 ir_delay + pos, ir_delay + pos + ns);
147
148 if (rv != 0) {
149 break;
150 }
151
152 pos += ns;
153
154 if (pos == _max_size) {
155 break;
156 }
157 }
158 }
159
160 if (rv == 0) {
161 rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance ()->client_real_time_priority () - 1), PBD_SCHED_FIFO);
162 }
163
164 assert (rv == 0); // bail out in debug builds
165
166 if (rv != 0) {
167 _convproc.stop_process ();
168 _convproc.cleanup ();
169 _configured = false;
170 return;
171 }
172
173 _configured = true;
174
175 #ifndef NDEBUG
176 _convproc.print (stdout);
177 #endif
178 }
179
180 void
run(BufferSet & bufs,ChanMapping const & in_map,ChanMapping const & out_map,pframes_t n_samples,samplecnt_t offset)181 Convolution::run (BufferSet& bufs, ChanMapping const& in_map, ChanMapping const& out_map, pframes_t n_samples, samplecnt_t offset)
182 {
183 if (!ready ()) {
184 process_map (&bufs, ChanCount (DataType::AUDIO, _n_outputs), in_map, out_map, n_samples, offset);
185 return;
186 }
187
188 uint32_t done = 0;
189 uint32_t remain = n_samples;
190
191 while (remain > 0) {
192 uint32_t ns = std::min (remain, _n_samples - _offset);
193
194 for (uint32_t c = 0; c < _n_inputs; ++c) {
195 bool valid;
196 const uint32_t idx = in_map.get (DataType::AUDIO, c, &valid);
197 if (!valid) {
198 ::memset (&_convproc.inpdata (c)[_offset], 0, sizeof (float) * ns);
199 } else {
200 AudioBuffer const& ab (bufs.get_audio (idx));
201 memcpy (&_convproc.inpdata (c)[_offset], ab.data (done + offset), sizeof (float) * ns);
202 }
203 }
204
205 for (uint32_t c = 0; c < _n_outputs; ++c) {
206 bool valid;
207 const uint32_t idx = out_map.get (DataType::AUDIO, c, &valid);
208 if (valid) {
209 AudioBuffer& ab (bufs.get_audio (idx));
210 memcpy (ab.data (done + offset), &_convproc.outdata (c)[_offset], sizeof (float) * ns);
211 }
212 }
213
214 _offset += ns;
215 done += ns;
216 remain -= ns;
217
218 if (_offset == _n_samples) {
219 _convproc.process ();
220 _offset = 0;
221 }
222 }
223 }
224
225 /* ****************************************************************************/
226
Convolver(Session & session,std::string const & path,IRChannelConfig irc,IRSettings irs)227 Convolver::Convolver (
228 Session& session,
229 std::string const& path,
230 IRChannelConfig irc,
231 IRSettings irs)
232 : Convolution (session, ircc_in (irc), ircc_out (irc))
233 , _irc (irc)
234 , _ir_settings (irs)
235 {
236 _threaded = true;
237
238 std::vector<boost::shared_ptr<Readable> > readables = Readable::load (_session, path);
239
240 if (readables.empty ()) {
241 PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
242 throw failed_constructor ();
243 }
244
245 if (readables[0]->readable_length () > 0x1000000 /*2^24*/) {
246 PBD::error << string_compose (_("Convolver: IR \"%1\" file too long."), path) << endmsg;
247 throw failed_constructor ();
248 }
249
250 /* map channels
251 * - Mono:
252 * always use first only
253 * - MonoToStereo:
254 * mono-file: use 1st for M -> L, M -> R
255 * else: use first two channels
256 * - Stereo
257 * mono-file: use 1st for both L -> L, R -> R, no x-over
258 * stereo-file: L -> L, R -> R -- no L/R, R/L x-over
259 * 3chan-file: ignore 3rd channel, use as stereo-file.
260 * 4chan file: L -> L, L -> R, R -> R, R -> L
261 */
262
263 uint32_t n_imp = n_inputs () * n_outputs ();
264 uint32_t n_chn = readables.size ();
265
266 if (_irc == Stereo && n_chn == 3) {
267 /* ignore 3rd channel */
268 n_chn = 2;
269 }
270 if (_irc == Stereo && n_chn <= 2) {
271 /* ignore x-over */
272 n_imp = 2;
273 }
274
275 #ifndef NDEBUG
276 printf ("Convolver: Nin=%d Nout=%d Nimp=%d Nchn=%d\n", n_inputs (), n_outputs (), n_imp, n_chn);
277 #endif
278
279 assert (n_imp <= 4);
280
281 for (uint32_t c = 0; c < n_imp; ++c) {
282 int ir_c = c % n_chn;
283 int io_o = c % n_outputs ();
284 int io_i;
285
286 if (n_imp == 2 && _irc == Stereo) {
287 /* (imp, in, out)
288 * Stereo (2, 2, 2) 1: L -> L, 2: R -> R
289 */
290 io_i = c % n_inputs ();
291 } else {
292 /* (imp, in, out)
293 * Mono (1, 1, 1) 1: M -> M
294 * MonoToStereo (2, 1, 2) 1: M -> L, 2: M -> R
295 * Stereo (4, 2, 2) 1: L -> L, 2: L -> R, 3: R -> L, 4: R -> R
296 */
297 io_i = (c / n_outputs ()) % n_inputs ();
298 }
299
300 boost::shared_ptr<Readable> r = readables[ir_c];
301 assert (r->n_channels () == 1);
302
303 const float chan_gain = _ir_settings.gain * _ir_settings.channel_gain[c];
304 const uint32_t chan_delay = _ir_settings.pre_delay + _ir_settings.channel_delay[c];
305
306 #ifndef NDEBUG
307 printf ("Convolver map: IR-chn %d: in %d -> out %d (gain: %.1fdB delay; %d)\n", ir_c + 1, io_i + 1, io_o + 1, 20.f * log10f (chan_gain), chan_delay);
308 #endif
309
310 add_impdata (io_i, io_o, r, chan_gain, chan_delay);
311 }
312
313 Convolution::restart ();
314 }
315
316 void
run_mono_buffered(float * buf,uint32_t n_samples)317 Convolver::run_mono_buffered (float* buf, uint32_t n_samples)
318 {
319 assert (_convproc.state () == Convproc::ST_PROC);
320 assert (_irc == Mono);
321
322 uint32_t done = 0;
323 uint32_t remain = n_samples;
324
325 while (remain > 0) {
326 uint32_t ns = std::min (remain, _n_samples - _offset);
327
328 float* const in = _convproc.inpdata (/*channel*/ 0);
329 float const* const out = _convproc.outdata (/*channel*/ 0);
330
331 memcpy (&in[_offset], &buf[done], sizeof (float) * ns);
332 memcpy (&buf[done], &out[_offset], sizeof (float) * ns);
333
334 _offset += ns;
335 done += ns;
336 remain -= ns;
337
338 if (_offset == _n_samples) {
339 _convproc.process ();
340 _offset = 0;
341 }
342 }
343 }
344
345 void
run_stereo_buffered(float * left,float * right,uint32_t n_samples)346 Convolver::run_stereo_buffered (float* left, float* right, uint32_t n_samples)
347 {
348 assert (_convproc.state () == Convproc::ST_PROC);
349 assert (_irc != Mono);
350
351 uint32_t done = 0;
352 uint32_t remain = n_samples;
353
354 while (remain > 0) {
355 uint32_t ns = std::min (remain, _n_samples - _offset);
356
357 memcpy (&_convproc.inpdata (0)[_offset], &left[done], sizeof (float) * ns);
358 if (_irc >= Stereo) {
359 memcpy (&_convproc.inpdata (1)[_offset], &right[done], sizeof (float) * ns);
360 }
361 memcpy (&left[done], &_convproc.outdata (0)[_offset], sizeof (float) * ns);
362 memcpy (&right[done], &_convproc.outdata (1)[_offset], sizeof (float) * ns);
363
364 _offset += ns;
365 done += ns;
366 remain -= ns;
367
368 if (_offset == _n_samples) {
369 _convproc.process ();
370 _offset = 0;
371 }
372 }
373 }
374
375 void
run_mono_no_latency(float * buf,uint32_t n_samples)376 Convolver::run_mono_no_latency (float* buf, uint32_t n_samples)
377 {
378 assert (_convproc.state () == Convproc::ST_PROC);
379 assert (_irc == Mono);
380
381 uint32_t done = 0;
382 uint32_t remain = n_samples;
383
384 while (remain > 0) {
385 uint32_t ns = std::min (remain, _n_samples - _offset);
386
387 float* const in = _convproc.inpdata (/*channel*/ 0);
388 float* const out = _convproc.outdata (/*channel*/ 0);
389
390 memcpy (&in[_offset], &buf[done], sizeof (float) * ns);
391
392 if (_offset + ns == _n_samples) {
393 _convproc.process ();
394 memcpy (&buf[done], &out[_offset], sizeof (float) * ns);
395 _offset = 0;
396 } else {
397 assert (remain == ns);
398 _convproc.tailonly (_offset + ns);
399 memcpy (&buf[done], &out[_offset], sizeof (float) * ns);
400 _offset += ns;
401 }
402 done += ns;
403 remain -= ns;
404 }
405 }
406
407 void
run_stereo_no_latency(float * left,float * right,uint32_t n_samples)408 Convolver::run_stereo_no_latency (float* left, float* right, uint32_t n_samples)
409 {
410 assert (_convproc.state () == Convproc::ST_PROC);
411 assert (_irc != Mono);
412
413 uint32_t done = 0;
414 uint32_t remain = n_samples;
415
416 float* const outL = _convproc.outdata (0);
417 float* const outR = _convproc.outdata (1);
418
419 while (remain > 0) {
420 uint32_t ns = std::min (remain, _n_samples - _offset);
421
422 memcpy (&_convproc.inpdata (0)[_offset], &left[done], sizeof (float) * ns);
423 if (_irc >= Stereo) {
424 memcpy (&_convproc.inpdata (1)[_offset], &right[done], sizeof (float) * ns);
425 }
426
427 if (_offset + ns == _n_samples) {
428 _convproc.process ();
429 memcpy (&left[done], &outL[_offset], sizeof (float) * ns);
430 memcpy (&right[done], &outR[_offset], sizeof (float) * ns);
431 _offset = 0;
432 } else {
433 assert (remain == ns);
434 _convproc.tailonly (_offset + ns);
435 memcpy (&left[done], &outL[_offset], sizeof (float) * ns);
436 memcpy (&right[done], &outR[_offset], sizeof (float) * ns);
437 _offset += ns;
438 }
439 done += ns;
440 remain -= ns;
441 }
442 }
443