cannam@233
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@233
|
2
|
cannam@233
|
3 /*
|
cannam@233
|
4 Vamp
|
cannam@233
|
5
|
cannam@233
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@233
|
7
|
cannam@233
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@233
|
9 Copyright 2006-2007 Chris Cannam and QMUL.
|
cannam@233
|
10
|
cannam@233
|
11 This file is based in part on Don Cross's public domain FFT
|
cannam@233
|
12 implementation.
|
cannam@233
|
13
|
cannam@233
|
14 Permission is hereby granted, free of charge, to any person
|
cannam@233
|
15 obtaining a copy of this software and associated documentation
|
cannam@233
|
16 files (the "Software"), to deal in the Software without
|
cannam@233
|
17 restriction, including without limitation the rights to use, copy,
|
cannam@233
|
18 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@233
|
19 of the Software, and to permit persons to whom the Software is
|
cannam@233
|
20 furnished to do so, subject to the following conditions:
|
cannam@233
|
21
|
cannam@233
|
22 The above copyright notice and this permission notice shall be
|
cannam@233
|
23 included in all copies or substantial portions of the Software.
|
cannam@233
|
24
|
cannam@233
|
25 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@233
|
26 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@233
|
27 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@233
|
28 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@233
|
29 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@233
|
30 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@233
|
31 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@233
|
32
|
cannam@233
|
33 Except as contained in this notice, the names of the Centre for
|
cannam@233
|
34 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@233
|
35 shall not be used in advertising or otherwise to promote the sale,
|
cannam@233
|
36 use or other dealings in this Software without prior written
|
cannam@233
|
37 authorization.
|
cannam@233
|
38 */
|
cannam@233
|
39
|
cannam@233
|
40 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
|
cannam@233
|
41
|
cannam@233
|
42 #include <cmath>
|
cannam@233
|
43
|
cannam@233
|
44
|
cannam@233
|
45 /**
|
cannam@233
|
46 * If you want to compile using FFTW instead of the built-in FFT
|
cannam@233
|
47 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
|
cannam@233
|
48 * in the Makefile.
|
cannam@233
|
49 *
|
cannam@233
|
50 * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
|
cannam@233
|
51 * which is provided under a more liberal BSD license in order to
|
cannam@233
|
52 * permit use in closed source applications. The use of FFTW would
|
cannam@233
|
53 * mean that your code would need to be licensed under the GPL as
|
cannam@233
|
54 * well. Do not define this symbol unless you understand and accept
|
cannam@233
|
55 * the implications of this.
|
cannam@233
|
56 *
|
cannam@233
|
57 * Parties such as Linux distribution packagers who redistribute this
|
cannam@233
|
58 * SDK for use in other programs should _not_ define this symbol, as
|
cannam@233
|
59 * it would change the effective licensing terms under which the SDK
|
cannam@233
|
60 * was available to third party developers.
|
cannam@233
|
61 *
|
cannam@233
|
62 * The default is not to use FFTW, and to use the built-in FFT instead.
|
cannam@233
|
63 *
|
cannam@233
|
64 * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
|
cannam@233
|
65 * its first invocation unless the host has saved and restored FFTW
|
cannam@233
|
66 * wisdom (see the FFTW documentation).
|
cannam@233
|
67 */
|
cannam@233
|
68 #ifdef HAVE_FFTW3
|
cannam@233
|
69 #include <fftw3.h>
|
cannam@233
|
70 #endif
|
cannam@233
|
71
|
cannam@233
|
72
|
cannam@263
|
73 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
|
cannam@263
|
74
|
cannam@233
|
75 namespace Vamp {
|
cannam@233
|
76
|
cannam@233
|
77 namespace HostExt {
|
cannam@233
|
78
|
cannam@233
|
79 class PluginInputDomainAdapter::Impl
|
cannam@233
|
80 {
|
cannam@233
|
81 public:
|
cannam@233
|
82 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@233
|
83 ~Impl();
|
cannam@233
|
84
|
cannam@233
|
85 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@288
|
86 void reset();
|
cannam@233
|
87
|
cannam@233
|
88 size_t getPreferredStepSize() const;
|
cannam@233
|
89 size_t getPreferredBlockSize() const;
|
cannam@233
|
90
|
cannam@233
|
91 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@288
|
92
|
cannam@288
|
93 void setProcessTimestampMethod(ProcessTimestampMethod m);
|
cannam@288
|
94 ProcessTimestampMethod getProcessTimestampMethod() const;
|
cannam@233
|
95
|
cannam@233
|
96 RealTime getTimestampAdjustment() const;
|
cannam@233
|
97
|
cannam@233
|
98 protected:
|
cannam@233
|
99 Plugin *m_plugin;
|
cannam@233
|
100 float m_inputSampleRate;
|
cannam@233
|
101 int m_channels;
|
cannam@288
|
102 int m_stepSize;
|
cannam@233
|
103 int m_blockSize;
|
cannam@233
|
104 float **m_freqbuf;
|
cannam@233
|
105
|
cannam@233
|
106 double *m_ri;
|
cannam@233
|
107 double *m_window;
|
cannam@233
|
108
|
cannam@288
|
109 ProcessTimestampMethod m_method;
|
cannam@288
|
110 int m_processCount;
|
cannam@289
|
111 float **m_shiftBuffers;
|
cannam@289
|
112 // FeatureSet prepadProcess(const float *const *inputBuffers,
|
cannam@289
|
113 // RealTime timestamp);
|
cannam@288
|
114
|
cannam@233
|
115 #ifdef HAVE_FFTW3
|
cannam@233
|
116 fftw_plan m_plan;
|
cannam@233
|
117 fftw_complex *m_cbuf;
|
cannam@233
|
118 #else
|
cannam@233
|
119 double *m_ro;
|
cannam@233
|
120 double *m_io;
|
cannam@233
|
121 void fft(unsigned int n, bool inverse,
|
cannam@233
|
122 double *ri, double *ii, double *ro, double *io);
|
cannam@233
|
123 #endif
|
cannam@233
|
124
|
cannam@289
|
125 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
126 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
127
|
cannam@233
|
128 size_t makeBlockSizeAcceptable(size_t) const;
|
cannam@233
|
129 };
|
cannam@233
|
130
|
cannam@233
|
131 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
|
cannam@233
|
132 PluginWrapper(plugin)
|
cannam@233
|
133 {
|
cannam@233
|
134 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@233
|
135 }
|
cannam@233
|
136
|
cannam@233
|
137 PluginInputDomainAdapter::~PluginInputDomainAdapter()
|
cannam@233
|
138 {
|
cannam@233
|
139 delete m_impl;
|
cannam@233
|
140 }
|
cannam@233
|
141
|
cannam@233
|
142 bool
|
cannam@233
|
143 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
144 {
|
cannam@233
|
145 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@233
|
146 }
|
cannam@233
|
147
|
cannam@288
|
148 void
|
cannam@288
|
149 PluginInputDomainAdapter::reset()
|
cannam@288
|
150 {
|
cannam@288
|
151 m_impl->reset();
|
cannam@288
|
152 }
|
cannam@288
|
153
|
cannam@233
|
154 Plugin::InputDomain
|
cannam@233
|
155 PluginInputDomainAdapter::getInputDomain() const
|
cannam@233
|
156 {
|
cannam@233
|
157 return TimeDomain;
|
cannam@233
|
158 }
|
cannam@233
|
159
|
cannam@233
|
160 size_t
|
cannam@233
|
161 PluginInputDomainAdapter::getPreferredStepSize() const
|
cannam@233
|
162 {
|
cannam@233
|
163 return m_impl->getPreferredStepSize();
|
cannam@233
|
164 }
|
cannam@233
|
165
|
cannam@233
|
166 size_t
|
cannam@233
|
167 PluginInputDomainAdapter::getPreferredBlockSize() const
|
cannam@233
|
168 {
|
cannam@233
|
169 return m_impl->getPreferredBlockSize();
|
cannam@233
|
170 }
|
cannam@233
|
171
|
cannam@233
|
172 Plugin::FeatureSet
|
cannam@233
|
173 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@233
|
174 {
|
cannam@233
|
175 return m_impl->process(inputBuffers, timestamp);
|
cannam@233
|
176 }
|
cannam@233
|
177
|
cannam@288
|
178 void
|
cannam@288
|
179 PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
180 {
|
cannam@288
|
181 m_impl->setProcessTimestampMethod(m);
|
cannam@288
|
182 }
|
cannam@288
|
183
|
cannam@288
|
184 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
185 PluginInputDomainAdapter::getProcessTimestampMethod() const
|
cannam@288
|
186 {
|
cannam@288
|
187 return m_impl->getProcessTimestampMethod();
|
cannam@288
|
188 }
|
cannam@288
|
189
|
cannam@233
|
190 RealTime
|
cannam@233
|
191 PluginInputDomainAdapter::getTimestampAdjustment() const
|
cannam@233
|
192 {
|
cannam@233
|
193 return m_impl->getTimestampAdjustment();
|
cannam@233
|
194 }
|
cannam@233
|
195
|
cannam@233
|
196
|
cannam@233
|
197 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@233
|
198 m_plugin(plugin),
|
cannam@233
|
199 m_inputSampleRate(inputSampleRate),
|
cannam@233
|
200 m_channels(0),
|
cannam@288
|
201 m_stepSize(0),
|
cannam@233
|
202 m_blockSize(0),
|
cannam@233
|
203 m_freqbuf(0),
|
cannam@233
|
204 m_ri(0),
|
cannam@233
|
205 m_window(0),
|
cannam@288
|
206 m_method(ShiftTimestamp),
|
cannam@288
|
207 m_processCount(0),
|
cannam@289
|
208 m_shiftBuffers(0),
|
cannam@233
|
209 #ifdef HAVE_FFTW3
|
cannam@233
|
210 m_plan(0),
|
cannam@233
|
211 m_cbuf(0)
|
cannam@233
|
212 #else
|
cannam@233
|
213 m_ro(0),
|
cannam@233
|
214 m_io(0)
|
cannam@233
|
215 #endif
|
cannam@233
|
216 {
|
cannam@233
|
217 }
|
cannam@233
|
218
|
cannam@233
|
219 PluginInputDomainAdapter::Impl::~Impl()
|
cannam@233
|
220 {
|
cannam@233
|
221 // the adapter will delete the plugin
|
cannam@233
|
222
|
cannam@289
|
223 if (m_shiftBuffers) {
|
cannam@289
|
224 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
225 delete[] m_shiftBuffers[c];
|
cannam@289
|
226 }
|
cannam@289
|
227 delete[] m_shiftBuffers;
|
cannam@289
|
228 }
|
cannam@289
|
229
|
cannam@233
|
230 if (m_channels > 0) {
|
cannam@233
|
231 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
232 delete[] m_freqbuf[c];
|
cannam@233
|
233 }
|
cannam@233
|
234 delete[] m_freqbuf;
|
cannam@233
|
235 #ifdef HAVE_FFTW3
|
cannam@233
|
236 if (m_plan) {
|
cannam@233
|
237 fftw_destroy_plan(m_plan);
|
cannam@233
|
238 fftw_free(m_ri);
|
cannam@233
|
239 fftw_free(m_cbuf);
|
cannam@233
|
240 m_plan = 0;
|
cannam@233
|
241 }
|
cannam@233
|
242 #else
|
cannam@233
|
243 delete[] m_ri;
|
cannam@233
|
244 delete[] m_ro;
|
cannam@233
|
245 delete[] m_io;
|
cannam@233
|
246 #endif
|
cannam@233
|
247 delete[] m_window;
|
cannam@233
|
248 }
|
cannam@233
|
249 }
|
cannam@233
|
250
|
cannam@233
|
251 // for some visual studii apparently
|
cannam@233
|
252 #ifndef M_PI
|
cannam@233
|
253 #define M_PI 3.14159265358979232846
|
cannam@233
|
254 #endif
|
cannam@233
|
255
|
cannam@233
|
256 bool
|
cannam@233
|
257 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
258 {
|
cannam@233
|
259 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
260
|
cannam@288
|
261 m_stepSize = int(stepSize);
|
cannam@233
|
262 m_blockSize = int(blockSize);
|
cannam@233
|
263 m_channels = int(channels);
|
cannam@233
|
264
|
cannam@233
|
265 return m_plugin->initialise(channels, stepSize, blockSize);
|
cannam@233
|
266 }
|
cannam@233
|
267
|
cannam@233
|
268 if (blockSize < 2) {
|
cannam@283
|
269 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
|
cannam@233
|
270 return false;
|
cannam@233
|
271 }
|
cannam@233
|
272
|
cannam@233
|
273 if (blockSize & (blockSize-1)) {
|
cannam@283
|
274 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
|
cannam@233
|
275 return false;
|
cannam@233
|
276 }
|
cannam@233
|
277
|
cannam@233
|
278 if (m_channels > 0) {
|
cannam@233
|
279 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
280 delete[] m_freqbuf[c];
|
cannam@233
|
281 }
|
cannam@233
|
282 delete[] m_freqbuf;
|
cannam@233
|
283 #ifdef HAVE_FFTW3
|
cannam@233
|
284 if (m_plan) {
|
cannam@233
|
285 fftw_destroy_plan(m_plan);
|
cannam@233
|
286 fftw_free(m_ri);
|
cannam@233
|
287 fftw_free(m_cbuf);
|
cannam@233
|
288 m_plan = 0;
|
cannam@233
|
289 }
|
cannam@233
|
290 #else
|
cannam@233
|
291 delete[] m_ri;
|
cannam@233
|
292 delete[] m_ro;
|
cannam@233
|
293 delete[] m_io;
|
cannam@233
|
294 #endif
|
cannam@233
|
295 delete[] m_window;
|
cannam@233
|
296 }
|
cannam@233
|
297
|
cannam@288
|
298 m_stepSize = int(stepSize);
|
cannam@233
|
299 m_blockSize = int(blockSize);
|
cannam@233
|
300 m_channels = int(channels);
|
cannam@233
|
301
|
cannam@233
|
302 m_freqbuf = new float *[m_channels];
|
cannam@233
|
303 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
304 m_freqbuf[c] = new float[m_blockSize + 2];
|
cannam@233
|
305 }
|
cannam@233
|
306 m_window = new double[m_blockSize];
|
cannam@233
|
307
|
cannam@233
|
308 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@233
|
309 // Hanning window
|
cannam@233
|
310 m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize));
|
cannam@233
|
311 }
|
cannam@233
|
312
|
cannam@233
|
313 #ifdef HAVE_FFTW3
|
cannam@233
|
314 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
|
cannam@233
|
315 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
|
cannam@233
|
316 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
|
cannam@233
|
317 #else
|
cannam@233
|
318 m_ri = new double[m_blockSize];
|
cannam@233
|
319 m_ro = new double[m_blockSize];
|
cannam@233
|
320 m_io = new double[m_blockSize];
|
cannam@233
|
321 #endif
|
cannam@233
|
322
|
cannam@288
|
323 m_processCount = 0;
|
cannam@288
|
324
|
cannam@233
|
325 return m_plugin->initialise(channels, stepSize, blockSize);
|
cannam@233
|
326 }
|
cannam@233
|
327
|
cannam@288
|
328 void
|
cannam@288
|
329 PluginInputDomainAdapter::Impl::reset()
|
cannam@288
|
330 {
|
cannam@288
|
331 m_processCount = 0;
|
cannam@288
|
332 m_plugin->reset();
|
cannam@288
|
333 }
|
cannam@288
|
334
|
cannam@233
|
335 size_t
|
cannam@233
|
336 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
|
cannam@233
|
337 {
|
cannam@233
|
338 size_t step = m_plugin->getPreferredStepSize();
|
cannam@233
|
339
|
cannam@233
|
340 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
|
cannam@233
|
341 step = getPreferredBlockSize() / 2;
|
cannam@233
|
342 }
|
cannam@233
|
343
|
cannam@233
|
344 return step;
|
cannam@233
|
345 }
|
cannam@233
|
346
|
cannam@233
|
347 size_t
|
cannam@233
|
348 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
|
cannam@233
|
349 {
|
cannam@233
|
350 size_t block = m_plugin->getPreferredBlockSize();
|
cannam@233
|
351
|
cannam@233
|
352 if (m_plugin->getInputDomain() == FrequencyDomain) {
|
cannam@233
|
353 if (block == 0) {
|
cannam@233
|
354 block = 1024;
|
cannam@233
|
355 } else {
|
cannam@233
|
356 block = makeBlockSizeAcceptable(block);
|
cannam@233
|
357 }
|
cannam@233
|
358 }
|
cannam@233
|
359
|
cannam@233
|
360 return block;
|
cannam@233
|
361 }
|
cannam@233
|
362
|
cannam@233
|
363 size_t
|
cannam@233
|
364 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
|
cannam@233
|
365 {
|
cannam@233
|
366 if (blockSize < 2) {
|
cannam@233
|
367
|
cannam@283
|
368 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
|
cannam@233
|
369 << "supported, increasing from " << blockSize << " to 2" << std::endl;
|
cannam@233
|
370 blockSize = 2;
|
cannam@233
|
371
|
cannam@233
|
372 } else if (blockSize & (blockSize-1)) {
|
cannam@233
|
373
|
cannam@233
|
374 #ifdef HAVE_FFTW3
|
cannam@233
|
375 // not an issue with FFTW
|
cannam@233
|
376 #else
|
cannam@233
|
377
|
cannam@233
|
378 // not a power of two, can't handle that with our built-in FFT
|
cannam@233
|
379 // implementation
|
cannam@233
|
380
|
cannam@233
|
381 size_t nearest = blockSize;
|
cannam@233
|
382 size_t power = 0;
|
cannam@233
|
383 while (nearest > 1) {
|
cannam@233
|
384 nearest >>= 1;
|
cannam@233
|
385 ++power;
|
cannam@233
|
386 }
|
cannam@233
|
387 nearest = 1;
|
cannam@233
|
388 while (power) {
|
cannam@233
|
389 nearest <<= 1;
|
cannam@233
|
390 --power;
|
cannam@233
|
391 }
|
cannam@233
|
392
|
cannam@233
|
393 if (blockSize - nearest > (nearest*2) - blockSize) {
|
cannam@233
|
394 nearest = nearest*2;
|
cannam@233
|
395 }
|
cannam@233
|
396
|
cannam@283
|
397 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
|
cannam@233
|
398 blockSize = nearest;
|
cannam@233
|
399
|
cannam@233
|
400 #endif
|
cannam@233
|
401 }
|
cannam@233
|
402
|
cannam@233
|
403 return blockSize;
|
cannam@233
|
404 }
|
cannam@233
|
405
|
cannam@233
|
406 RealTime
|
cannam@233
|
407 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
|
cannam@233
|
408 {
|
cannam@233
|
409 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
410 return RealTime::zeroTime;
|
cannam@289
|
411 } else if (m_method == ShiftData) {
|
cannam@289
|
412 return RealTime::zeroTime;
|
cannam@233
|
413 } else {
|
cannam@233
|
414 return RealTime::frame2RealTime
|
cannam@233
|
415 (m_blockSize/2, int(m_inputSampleRate + 0.5));
|
cannam@233
|
416 }
|
cannam@233
|
417 }
|
cannam@233
|
418
|
cannam@288
|
419 void
|
cannam@288
|
420 PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
421 {
|
cannam@288
|
422 m_method = m;
|
cannam@288
|
423 }
|
cannam@288
|
424
|
cannam@288
|
425 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
426 PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
|
cannam@288
|
427 {
|
cannam@288
|
428 return m_method;
|
cannam@288
|
429 }
|
cannam@288
|
430
|
cannam@233
|
431 Plugin::FeatureSet
|
cannam@233
|
432 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@233
|
433 RealTime timestamp)
|
cannam@233
|
434 {
|
cannam@233
|
435 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
436 return m_plugin->process(inputBuffers, timestamp);
|
cannam@233
|
437 }
|
cannam@233
|
438
|
cannam@289
|
439 if (m_method == ShiftTimestamp) {
|
cannam@289
|
440 return processShiftingTimestamp(inputBuffers, timestamp);
|
cannam@289
|
441 } else {
|
cannam@289
|
442 return processShiftingData(inputBuffers, timestamp);
|
cannam@289
|
443 }
|
cannam@289
|
444 }
|
cannam@233
|
445
|
cannam@289
|
446 Plugin::FeatureSet
|
cannam@289
|
447 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
|
cannam@289
|
448 RealTime timestamp)
|
cannam@289
|
449 {
|
cannam@289
|
450 timestamp = timestamp + getTimestampAdjustment();
|
cannam@233
|
451
|
cannam@233
|
452 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
453
|
cannam@233
|
454 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@233
|
455 m_ri[i] = double(inputBuffers[c][i]) * m_window[i];
|
cannam@233
|
456 }
|
cannam@233
|
457
|
cannam@233
|
458 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@233
|
459 // FFT shift
|
cannam@233
|
460 double value = m_ri[i];
|
cannam@233
|
461 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@233
|
462 m_ri[i + m_blockSize/2] = value;
|
cannam@233
|
463 }
|
cannam@233
|
464
|
cannam@233
|
465 #ifdef HAVE_FFTW3
|
cannam@233
|
466 fftw_execute(m_plan);
|
cannam@233
|
467
|
cannam@233
|
468 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@233
|
469 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
|
cannam@233
|
470 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
|
cannam@233
|
471 }
|
cannam@233
|
472 #else
|
cannam@233
|
473 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
|
cannam@233
|
474
|
cannam@233
|
475 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@233
|
476 m_freqbuf[c][i * 2] = float(m_ro[i]);
|
cannam@233
|
477 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
|
cannam@233
|
478 }
|
cannam@233
|
479 #endif
|
cannam@233
|
480 }
|
cannam@233
|
481
|
cannam@289
|
482 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@288
|
483 }
|
cannam@288
|
484
|
cannam@288
|
485 Plugin::FeatureSet
|
cannam@289
|
486 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
|
cannam@289
|
487 RealTime timestamp)
|
cannam@288
|
488 {
|
cannam@289
|
489 if (m_processCount == 0) {
|
cannam@289
|
490 if (!m_shiftBuffers) {
|
cannam@289
|
491 m_shiftBuffers = new float *[m_channels];
|
cannam@289
|
492 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
493 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
|
cannam@289
|
494 }
|
cannam@289
|
495 }
|
cannam@289
|
496 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
497 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
498 m_shiftBuffers[c][i] = 0.f;
|
cannam@289
|
499 }
|
cannam@289
|
500 }
|
cannam@289
|
501 }
|
cannam@289
|
502
|
cannam@289
|
503 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
504 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
505 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
|
cannam@289
|
506 }
|
cannam@289
|
507 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@289
|
508 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
|
cannam@289
|
509 }
|
cannam@289
|
510 }
|
cannam@289
|
511
|
cannam@289
|
512 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
513
|
cannam@289
|
514 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@289
|
515 m_ri[i] = double(m_shiftBuffers[c][i]) * m_window[i];
|
cannam@289
|
516 }
|
cannam@289
|
517
|
cannam@289
|
518 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@289
|
519 // FFT shift
|
cannam@289
|
520 double value = m_ri[i];
|
cannam@289
|
521 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@289
|
522 m_ri[i + m_blockSize/2] = value;
|
cannam@289
|
523 }
|
cannam@289
|
524
|
cannam@289
|
525 #ifdef HAVE_FFTW3
|
cannam@289
|
526 fftw_execute(m_plan);
|
cannam@289
|
527
|
cannam@289
|
528 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@289
|
529 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
|
cannam@289
|
530 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
|
cannam@289
|
531 }
|
cannam@289
|
532 #else
|
cannam@289
|
533 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
|
cannam@289
|
534
|
cannam@289
|
535 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@289
|
536 m_freqbuf[c][i * 2] = float(m_ro[i]);
|
cannam@289
|
537 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
|
cannam@289
|
538 }
|
cannam@289
|
539 #endif
|
cannam@289
|
540 }
|
cannam@289
|
541
|
cannam@289
|
542 ++m_processCount;
|
cannam@289
|
543
|
cannam@289
|
544 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@233
|
545 }
|
cannam@233
|
546
|
cannam@233
|
547 #ifndef HAVE_FFTW3
|
cannam@233
|
548
|
cannam@233
|
549 void
|
cannam@233
|
550 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse,
|
cannam@233
|
551 double *ri, double *ii, double *ro, double *io)
|
cannam@233
|
552 {
|
cannam@233
|
553 if (!ri || !ro || !io) return;
|
cannam@233
|
554
|
cannam@233
|
555 unsigned int bits;
|
cannam@233
|
556 unsigned int i, j, k, m;
|
cannam@233
|
557 unsigned int blockSize, blockEnd;
|
cannam@233
|
558
|
cannam@233
|
559 double tr, ti;
|
cannam@233
|
560
|
cannam@233
|
561 if (n < 2) return;
|
cannam@233
|
562 if (n & (n-1)) return;
|
cannam@233
|
563
|
cannam@233
|
564 double angle = 2.0 * M_PI;
|
cannam@233
|
565 if (inverse) angle = -angle;
|
cannam@233
|
566
|
cannam@233
|
567 for (i = 0; ; ++i) {
|
cannam@233
|
568 if (n & (1 << i)) {
|
cannam@233
|
569 bits = i;
|
cannam@233
|
570 break;
|
cannam@233
|
571 }
|
cannam@233
|
572 }
|
cannam@233
|
573
|
cannam@233
|
574 static unsigned int tableSize = 0;
|
cannam@233
|
575 static int *table = 0;
|
cannam@233
|
576
|
cannam@233
|
577 if (tableSize != n) {
|
cannam@233
|
578
|
cannam@233
|
579 delete[] table;
|
cannam@233
|
580
|
cannam@233
|
581 table = new int[n];
|
cannam@233
|
582
|
cannam@233
|
583 for (i = 0; i < n; ++i) {
|
cannam@233
|
584
|
cannam@233
|
585 m = i;
|
cannam@233
|
586
|
cannam@233
|
587 for (j = k = 0; j < bits; ++j) {
|
cannam@233
|
588 k = (k << 1) | (m & 1);
|
cannam@233
|
589 m >>= 1;
|
cannam@233
|
590 }
|
cannam@233
|
591
|
cannam@233
|
592 table[i] = k;
|
cannam@233
|
593 }
|
cannam@233
|
594
|
cannam@233
|
595 tableSize = n;
|
cannam@233
|
596 }
|
cannam@233
|
597
|
cannam@233
|
598 if (ii) {
|
cannam@233
|
599 for (i = 0; i < n; ++i) {
|
cannam@233
|
600 ro[table[i]] = ri[i];
|
cannam@233
|
601 io[table[i]] = ii[i];
|
cannam@233
|
602 }
|
cannam@233
|
603 } else {
|
cannam@233
|
604 for (i = 0; i < n; ++i) {
|
cannam@233
|
605 ro[table[i]] = ri[i];
|
cannam@233
|
606 io[table[i]] = 0.0;
|
cannam@233
|
607 }
|
cannam@233
|
608 }
|
cannam@233
|
609
|
cannam@233
|
610 blockEnd = 1;
|
cannam@233
|
611
|
cannam@233
|
612 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
|
cannam@233
|
613
|
cannam@233
|
614 double delta = angle / (double)blockSize;
|
cannam@233
|
615 double sm2 = -sin(-2 * delta);
|
cannam@233
|
616 double sm1 = -sin(-delta);
|
cannam@233
|
617 double cm2 = cos(-2 * delta);
|
cannam@233
|
618 double cm1 = cos(-delta);
|
cannam@233
|
619 double w = 2 * cm1;
|
cannam@233
|
620 double ar[3], ai[3];
|
cannam@233
|
621
|
cannam@233
|
622 for (i = 0; i < n; i += blockSize) {
|
cannam@233
|
623
|
cannam@233
|
624 ar[2] = cm2;
|
cannam@233
|
625 ar[1] = cm1;
|
cannam@233
|
626
|
cannam@233
|
627 ai[2] = sm2;
|
cannam@233
|
628 ai[1] = sm1;
|
cannam@233
|
629
|
cannam@233
|
630 for (j = i, m = 0; m < blockEnd; j++, m++) {
|
cannam@233
|
631
|
cannam@233
|
632 ar[0] = w * ar[1] - ar[2];
|
cannam@233
|
633 ar[2] = ar[1];
|
cannam@233
|
634 ar[1] = ar[0];
|
cannam@233
|
635
|
cannam@233
|
636 ai[0] = w * ai[1] - ai[2];
|
cannam@233
|
637 ai[2] = ai[1];
|
cannam@233
|
638 ai[1] = ai[0];
|
cannam@233
|
639
|
cannam@233
|
640 k = j + blockEnd;
|
cannam@233
|
641 tr = ar[0] * ro[k] - ai[0] * io[k];
|
cannam@233
|
642 ti = ar[0] * io[k] + ai[0] * ro[k];
|
cannam@233
|
643
|
cannam@233
|
644 ro[k] = ro[j] - tr;
|
cannam@233
|
645 io[k] = io[j] - ti;
|
cannam@233
|
646
|
cannam@233
|
647 ro[j] += tr;
|
cannam@233
|
648 io[j] += ti;
|
cannam@233
|
649 }
|
cannam@233
|
650 }
|
cannam@233
|
651
|
cannam@233
|
652 blockEnd = blockSize;
|
cannam@233
|
653 }
|
cannam@233
|
654
|
cannam@233
|
655 if (inverse) {
|
cannam@233
|
656
|
cannam@233
|
657 double denom = (double)n;
|
cannam@233
|
658
|
cannam@233
|
659 for (i = 0; i < n; i++) {
|
cannam@233
|
660 ro[i] /= denom;
|
cannam@233
|
661 io[i] /= denom;
|
cannam@233
|
662 }
|
cannam@233
|
663 }
|
cannam@233
|
664 }
|
cannam@233
|
665
|
cannam@233
|
666 #endif
|
cannam@233
|
667
|
cannam@233
|
668 }
|
cannam@233
|
669
|
cannam@233
|
670 }
|
cannam@233
|
671
|
cannam@263
|
672 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
|
cannam@263
|
673
|