Add option to limit automatable control parmaters
[ardour.git] / libs / ardour / convolver.cc
1 /*
2  * Copyright (C) 2018 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
20 #include <assert.h>
21
22 #include "pbd/error.h"
23 #include "pbd/pthread_utils.h"
24
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"
31
32 #include "pbd/i18n.h"
33
34 using namespace ARDOUR::DSP;
35 using namespace ArdourZita;
36
37 using ARDOUR::Session;
38
39 Convolver::Convolver (Session& session, std::string const& path, IRChannelConfig irc, uint32_t pre_delay)
40         : SessionHandleRef (session)
41         , _irc (irc)
42         , _initial_delay (pre_delay)
43         , _n_samples (0)
44         , _max_size (0)
45         , _offset (0)
46         , _configured (false)
47 {
48         ARDOUR::SoundFileInfo sf_info;
49         std::string error_msg;
50
51         if (!AudioFileSource::get_soundfile_info (path, sf_info, error_msg)) {
52                 PBD::error << string_compose(_("Convolver: cannot open IR \"%1\": %2"), path, error_msg) << endmsg;
53                 throw failed_constructor ();
54         }
55
56         if (sf_info.length > 0x1000000 /*2^24*/) {
57                 PBD::error << string_compose(_("Convolver: IR \"%1\" file too long."), path) << endmsg;
58                 throw failed_constructor ();
59         }
60
61         for (unsigned int n = 0; n < sf_info.channels; ++n) {
62                 try {
63                         boost::shared_ptr<AudioFileSource> afs;
64                         afs = boost::dynamic_pointer_cast<AudioFileSource> (
65                                         SourceFactory::createExternal (DataType::AUDIO, _session,
66                                                 path, n,
67                                                 Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
68
69                         if (afs->sample_rate() != _session.nominal_sample_rate()) {
70                                 boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(_session, afs, ARDOUR::SrcBest));
71                                 _readables.push_back(sfs);
72                         } else {
73                                 _readables.push_back(afs);
74                         }
75                 } catch (failed_constructor& err) {
76                         PBD::error << string_compose(_("Convolver: Could not open IR \"%1\"."), path) << endmsg;
77                         throw failed_constructor ();
78                 }
79         }
80
81         if (_readables.empty()) {
82                 PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
83                 throw failed_constructor ();
84         }
85
86         AudioEngine::instance ()->BufferSizeChanged.connect_same_thread (*this, boost::bind (&Convolver::reconfigure, this));
87
88         reconfigure ();
89 }
90
91 void
92 Convolver::reconfigure ()
93 {
94         _convproc.stop_process ();
95         _convproc.cleanup ();
96         _convproc.set_options (0);
97
98         assert (!_readables.empty());
99
100         _offset = 0;
101         _n_samples = _session.get_block_size();
102         _max_size = _readables[0]->readable_length();
103
104         uint32_t power_of_two;
105         for (power_of_two = 1; 1U << power_of_two < _n_samples; ++power_of_two);
106         _n_samples = 1 << power_of_two;
107
108         int n_part = std::min ((uint32_t)Convproc::MAXPART, 4 * _n_samples);
109         int rv = _convproc.configure (
110                         /*in*/  n_inputs (),
111                         /*out*/ n_outputs (),
112                         /*max-convolution length */ _max_size,
113                         /*quantum, nominal-buffersize*/ _n_samples,
114                         /*Convproc::MINPART*/ _n_samples,
115                         /*Convproc::MAXPART*/ n_part,
116                         /*density*/ 0);
117
118         /* map channels
119          * - Mono:
120          *    always use first only
121          * - MonoToStereo:
122          *    mono-file: use 1st for M -> L, M -> R
123          *    else: use first two channels
124          * - Stereo
125          *    mono-file: use 1st for both L -> L, R -> R, no x-over
126          *    stereo-file: L -> L, R -> R  -- no L/R, R/L x-over
127          *    3chan-file: ignore 3rd channel, use as stereo-file.
128          *    4chan file:  L -> L, L -> R, R -> R, R -> L
129          */
130
131         uint32_t n_imp = n_inputs() * n_outputs ();
132         uint32_t n_chn = _readables.size();
133
134         if (_irc == Stereo && n_chn == 3) {
135                 /* ignore 3rd channel */
136                 n_chn = 2;
137         }
138         if (_irc == Stereo && n_chn <= 2) {
139                 /* ignore x-over */
140                 n_imp = 2;
141         }
142
143         for (uint32_t c = 0; c < n_imp && rv == 0; ++c) {
144                 int ir_c = c % n_chn;
145                 int io_o = c % n_outputs();
146                 int io_i;
147
148                 if (n_imp > n_chn && _irc == Stereo) {
149                         /*           (imp, in, out)
150                          * Stereo       (2, 2, 2)    1: L -> L, 2: R -> R
151                          */
152                         io_i = c % n_inputs();
153                 } else {
154                         /*           (imp, in, out)
155                          * Mono         (1, 1, 1)   1: M -> M
156                          * MonoToStereo (2, 1, 2)   1: M -> L, 2: M -> R
157                          * Stereo       (4, 2, 2)   1: L -> L, 2: L -> R, 3: R -> L, 4: R -> R
158                          */
159                         io_i = (c / n_outputs()) % n_inputs();
160                 }
161
162 #ifndef NDEBUG
163                 printf ("Convolver map: IR-chn %d: in %d -> out %d\n", ir_c + 1, io_i + 1, io_o + 1);
164 #endif
165
166                 boost::shared_ptr<Readable> r = _readables[ir_c % n_chn];
167                 assert (r->readable_length () == _max_size);
168                 assert (r->n_channels () == 1);
169
170                 uint32_t pos = 0;
171                 while (true) {
172                         float ir[8192];
173                         samplecnt_t to_read = std::min ((uint32_t)8192, _max_size - pos);
174                         samplecnt_t ns = r->read (ir, pos, to_read, 0);
175
176                         if (ns == 0) {
177                                 assert (pos == _max_size);
178                                 break;
179                         }
180
181                         rv = _convproc.impdata_create (
182                                         /*i/o map */ io_i, io_o,
183                                         /*stride, de-interleave */1,
184                                         ir,
185                                         _initial_delay + pos, _initial_delay + pos + ns);
186
187                         if (rv != 0) {
188                                 break;
189                         }
190
191                         pos += ns;
192
193                         if (pos == _max_size) {
194                                 break;
195                         }
196                 };
197         }
198
199         if (rv == 0) {
200                 rv = _convproc.start_process (pbd_absolute_rt_priority (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority() - 2), PBD_SCHED_FIFO);
201         }
202
203         assert (rv == 0); // bail out in debug builds
204
205         if (rv != 0) {
206                 _convproc.stop_process ();
207                 _convproc.cleanup ();
208                 _configured = false;
209                 return;
210         }
211
212         _configured = true;
213
214 #ifndef NDEBUG
215         _convproc.print (stdout);
216 #endif
217 }
218
219 bool
220 Convolver::ready () const {
221         return _configured && _convproc.state () == Convproc::ST_PROC;
222 }
223
224 void
225 Convolver::run (float* buf, uint32_t n_samples)
226 {
227         assert (_convproc.state () == Convproc::ST_PROC);
228         assert (_irc == Mono);
229
230         uint32_t done = 0;
231         uint32_t remain = n_samples;
232
233         while (remain > 0) {
234                 uint32_t ns = std::min (remain, _n_samples - _offset);
235
236                 float* const       in  = _convproc.inpdata (/*channel*/0);
237                 float const* const out = _convproc.outdata (/*channel*/0);
238
239                 memcpy (&in[_offset], &buf[done], sizeof (float) * ns);
240                 memcpy (&buf[done], &out[_offset], sizeof (float) * ns);
241
242                 _offset += ns;
243                 done    += ns;
244                 remain  -= ns;
245
246                 if (_offset == _n_samples) {
247                         _convproc.process (/*sync, freewheeling*/ true);
248                         _offset = 0;
249                 }
250         }
251 }
252
253 void
254 Convolver::run_stereo (float* left, float* right, uint32_t n_samples)
255 {
256         assert (_convproc.state () == Convproc::ST_PROC);
257         assert (_irc != Mono);
258
259         uint32_t done = 0;
260         uint32_t remain = n_samples;
261
262         while (remain > 0) {
263                 uint32_t ns = std::min (remain, _n_samples - _offset);
264
265                 memcpy (&_convproc.inpdata(0)[_offset], &left[done], sizeof (float) * ns);
266                 if (_irc >= Stereo) {
267                         memcpy (&_convproc.inpdata(1)[_offset], &right[done], sizeof (float) * ns);
268                 }
269                 memcpy (&left[done],  &_convproc.outdata(0)[_offset], sizeof (float) * ns);
270                 memcpy (&right[done], &_convproc.outdata(1)[_offset], sizeof (float) * ns);
271
272                 _offset += ns;
273                 done    += ns;
274                 remain  -= ns;
275
276                 if (_offset == _n_samples) {
277                         _convproc.process (true);
278                         _offset = 0;
279                 }
280         }
281 }