2 * Copyright (C) 2018 Robin Gareus <robin@gareus.org>
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.
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.
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.
22 #include "pbd/error.h"
23 #include "pbd/pthread_utils.h"
25 #include "ardour/audioengine.h"
26 #include "ardour/audiofilesource.h"
27 #include "ardour/convolver.h"
28 #include "ardour/session.h"
29 #include "ardour/srcfilesource.h"
30 #include "ardour/source_factory.h"
34 using namespace ARDOUR::DSP;
35 using namespace ArdourZita;
37 using ARDOUR::Session;
39 Convolver::Convolver (
41 std::string const& path,
44 : SessionHandleRef (session)
52 ARDOUR::SoundFileInfo sf_info;
53 std::string error_msg;
55 if (!AudioFileSource::get_soundfile_info (path, sf_info, error_msg)) {
56 PBD::error << string_compose(_("Convolver: cannot open IR \"%1\": %2"), path, error_msg) << endmsg;
57 throw failed_constructor ();
60 if (sf_info.length > 0x1000000 /*2^24*/) {
61 PBD::error << string_compose(_("Convolver: IR \"%1\" file too long."), path) << endmsg;
62 throw failed_constructor ();
65 for (unsigned int n = 0; n < sf_info.channels; ++n) {
67 boost::shared_ptr<AudioFileSource> afs;
68 afs = boost::dynamic_pointer_cast<AudioFileSource> (
69 SourceFactory::createExternal (DataType::AUDIO, _session,
71 Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
73 if (afs->sample_rate() != _session.nominal_sample_rate()) {
74 boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(_session, afs, ARDOUR::SrcBest));
75 _readables.push_back(sfs);
77 _readables.push_back(afs);
79 } catch (failed_constructor& err) {
80 PBD::error << string_compose(_("Convolver: Could not open IR \"%1\"."), path) << endmsg;
81 throw failed_constructor ();
85 if (_readables.empty()) {
86 PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
87 throw failed_constructor ();
90 AudioEngine::instance ()->BufferSizeChanged.connect_same_thread (*this, boost::bind (&Convolver::reconfigure, this));
96 Convolver::reconfigure ()
98 _convproc.stop_process ();
100 _convproc.set_options (0);
102 assert (!_readables.empty());
105 _n_samples = _session.get_block_size();
106 _max_size = _readables[0]->readable_length();
108 uint32_t power_of_two;
109 for (power_of_two = 1; 1U << power_of_two < _n_samples; ++power_of_two);
110 _n_samples = 1 << power_of_two;
112 int n_part = std::min ((uint32_t)Convproc::MAXPART, 4 * _n_samples);
113 int rv = _convproc.configure (
115 /*out*/ n_outputs (),
116 /*max-convolution length */ _max_size,
117 /*quantum, nominal-buffersize*/ _n_samples,
118 /*Convproc::MINPART*/ _n_samples,
119 /*Convproc::MAXPART*/ n_part,
124 * always use first only
126 * mono-file: use 1st for M -> L, M -> R
127 * else: use first two channels
129 * mono-file: use 1st for both L -> L, R -> R, no x-over
130 * stereo-file: L -> L, R -> R -- no L/R, R/L x-over
131 * 3chan-file: ignore 3rd channel, use as stereo-file.
132 * 4chan file: L -> L, L -> R, R -> R, R -> L
135 uint32_t n_imp = n_inputs() * n_outputs ();
136 uint32_t n_chn = _readables.size();
139 printf ("Convolver::reconfigure Nin %d Nout %d Nimp %d Nchn %d\n", n_inputs (), n_outputs (), n_imp, n_chn);
142 if (_irc == Stereo && n_chn == 3) {
143 /* ignore 3rd channel */
146 if (_irc == Stereo && n_chn <= 2) {
153 for (uint32_t c = 0; c < n_imp && rv == 0; ++c) {
154 int ir_c = c % n_chn;
155 int io_o = c % n_outputs();
158 if (n_imp == 2 && _irc == Stereo) {
160 * Stereo (2, 2, 2) 1: L -> L, 2: R -> R
162 io_i = c % n_inputs();
165 * Mono (1, 1, 1) 1: M -> M
166 * MonoToStereo (2, 1, 2) 1: M -> L, 2: M -> R
167 * Stereo (4, 2, 2) 1: L -> L, 2: L -> R, 3: R -> L, 4: R -> R
169 io_i = (c / n_outputs()) % n_inputs();
173 boost::shared_ptr<Readable> r = _readables[ir_c];
174 assert (r->readable_length () == _max_size);
175 assert (r->n_channels () == 1);
177 const float chan_gain = _ir_settings.gain * _ir_settings.channel_gain[c];
178 const uint32_t chan_delay = _ir_settings.pre_delay + _ir_settings.channel_delay[c];
181 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);
187 samplecnt_t to_read = std::min ((uint32_t)8192, _max_size - pos);
188 samplecnt_t ns = r->read (ir, pos, to_read, 0);
191 assert (pos == _max_size);
195 if (chan_gain != 1.f) {
196 for (samplecnt_t i = 0; i < ns; ++i) {
201 rv = _convproc.impdata_create (
202 /*i/o map */ io_i, io_o,
203 /*stride, de-interleave */1,
205 chan_delay + pos, chan_delay + pos + ns);
213 if (pos == _max_size) {
220 rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority() - 2), PBD_SCHED_FIFO);
223 assert (rv == 0); // bail out in debug builds
226 _convproc.stop_process ();
227 _convproc.cleanup ();
235 _convproc.print (stdout);
240 Convolver::ready () const {
241 return _configured && _convproc.state () == Convproc::ST_PROC;
245 Convolver::run (float* buf, uint32_t n_samples)
247 assert (_convproc.state () == Convproc::ST_PROC);
248 assert (_irc == Mono);
251 uint32_t remain = n_samples;
254 uint32_t ns = std::min (remain, _n_samples - _offset);
256 float* const in = _convproc.inpdata (/*channel*/0);
257 float const* const out = _convproc.outdata (/*channel*/0);
259 memcpy (&in[_offset], &buf[done], sizeof (float) * ns);
260 memcpy (&buf[done], &out[_offset], sizeof (float) * ns);
266 if (_offset == _n_samples) {
267 _convproc.process (/*sync, freewheeling*/ true);
274 Convolver::run_stereo (float* left, float* right, uint32_t n_samples)
276 assert (_convproc.state () == Convproc::ST_PROC);
277 assert (_irc != Mono);
280 uint32_t remain = n_samples;
283 uint32_t ns = std::min (remain, _n_samples - _offset);
285 memcpy (&_convproc.inpdata(0)[_offset], &left[done], sizeof (float) * ns);
286 if (_irc >= Stereo) {
287 memcpy (&_convproc.inpdata(1)[_offset], &right[done], sizeof (float) * ns);
289 memcpy (&left[done], &_convproc.outdata(0)[_offset], sizeof (float) * ns);
290 memcpy (&right[done], &_convproc.outdata(1)[_offset], sizeof (float) * ns);
296 if (_offset == _n_samples) {
297 _convproc.process (true);