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