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@290
|
9 Copyright 2006-2009 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
|
Chris@317
|
44 #include "Window.h"
|
Chris@317
|
45
|
cannam@233
|
46
|
cannam@233
|
47 /**
|
cannam@233
|
48 * If you want to compile using FFTW instead of the built-in FFT
|
cannam@233
|
49 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3
|
cannam@233
|
50 * in the Makefile.
|
cannam@233
|
51 *
|
cannam@233
|
52 * Be aware that FFTW is licensed under the GPL -- unlike this SDK,
|
cannam@233
|
53 * which is provided under a more liberal BSD license in order to
|
cannam@233
|
54 * permit use in closed source applications. The use of FFTW would
|
cannam@233
|
55 * mean that your code would need to be licensed under the GPL as
|
cannam@233
|
56 * well. Do not define this symbol unless you understand and accept
|
cannam@233
|
57 * the implications of this.
|
cannam@233
|
58 *
|
cannam@233
|
59 * Parties such as Linux distribution packagers who redistribute this
|
cannam@233
|
60 * SDK for use in other programs should _not_ define this symbol, as
|
cannam@233
|
61 * it would change the effective licensing terms under which the SDK
|
cannam@233
|
62 * was available to third party developers.
|
cannam@233
|
63 *
|
cannam@233
|
64 * The default is not to use FFTW, and to use the built-in FFT instead.
|
cannam@233
|
65 *
|
cannam@233
|
66 * Note: The FFTW code uses FFTW_MEASURE, and so will perform badly on
|
cannam@233
|
67 * its first invocation unless the host has saved and restored FFTW
|
cannam@233
|
68 * wisdom (see the FFTW documentation).
|
cannam@233
|
69 */
|
cannam@233
|
70 #ifdef HAVE_FFTW3
|
cannam@233
|
71 #include <fftw3.h>
|
Chris@356
|
72 #warning "Compiling with FFTW3 support will result in a GPL binary"
|
Chris@337
|
73 #else
|
Chris@337
|
74 #include "../vamp-sdk/FFTimpl.cpp"
|
cannam@233
|
75 #endif
|
cannam@233
|
76
|
cannam@233
|
77
|
cannam@263
|
78 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
|
cannam@263
|
79
|
cannam@233
|
80 namespace Vamp {
|
cannam@233
|
81
|
cannam@233
|
82 namespace HostExt {
|
cannam@233
|
83
|
cannam@233
|
84 class PluginInputDomainAdapter::Impl
|
cannam@233
|
85 {
|
cannam@233
|
86 public:
|
cannam@233
|
87 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@233
|
88 ~Impl();
|
cannam@233
|
89
|
cannam@233
|
90 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@288
|
91 void reset();
|
cannam@233
|
92
|
cannam@233
|
93 size_t getPreferredStepSize() const;
|
cannam@233
|
94 size_t getPreferredBlockSize() const;
|
cannam@233
|
95
|
cannam@233
|
96 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@288
|
97
|
cannam@288
|
98 void setProcessTimestampMethod(ProcessTimestampMethod m);
|
cannam@288
|
99 ProcessTimestampMethod getProcessTimestampMethod() const;
|
cannam@233
|
100
|
cannam@233
|
101 RealTime getTimestampAdjustment() const;
|
cannam@233
|
102
|
Chris@317
|
103 WindowType getWindowType() const;
|
Chris@317
|
104 void setWindowType(WindowType type);
|
Chris@317
|
105
|
cannam@233
|
106 protected:
|
cannam@233
|
107 Plugin *m_plugin;
|
cannam@233
|
108 float m_inputSampleRate;
|
cannam@233
|
109 int m_channels;
|
cannam@288
|
110 int m_stepSize;
|
cannam@233
|
111 int m_blockSize;
|
cannam@233
|
112 float **m_freqbuf;
|
cannam@233
|
113
|
cannam@233
|
114 double *m_ri;
|
Chris@317
|
115
|
Chris@317
|
116 WindowType m_windowType;
|
Chris@317
|
117 Window<double> *m_window;
|
cannam@233
|
118
|
cannam@288
|
119 ProcessTimestampMethod m_method;
|
cannam@288
|
120 int m_processCount;
|
cannam@289
|
121 float **m_shiftBuffers;
|
cannam@288
|
122
|
cannam@233
|
123 #ifdef HAVE_FFTW3
|
cannam@233
|
124 fftw_plan m_plan;
|
cannam@233
|
125 fftw_complex *m_cbuf;
|
cannam@233
|
126 #else
|
cannam@233
|
127 double *m_ro;
|
cannam@233
|
128 double *m_io;
|
cannam@233
|
129 #endif
|
cannam@233
|
130
|
cannam@289
|
131 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
132 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
133
|
cannam@233
|
134 size_t makeBlockSizeAcceptable(size_t) const;
|
Chris@317
|
135
|
Chris@317
|
136 Window<double>::WindowType convertType(WindowType t) const;
|
cannam@233
|
137 };
|
cannam@233
|
138
|
cannam@233
|
139 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
|
cannam@233
|
140 PluginWrapper(plugin)
|
cannam@233
|
141 {
|
cannam@233
|
142 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@233
|
143 }
|
cannam@233
|
144
|
cannam@233
|
145 PluginInputDomainAdapter::~PluginInputDomainAdapter()
|
cannam@233
|
146 {
|
cannam@233
|
147 delete m_impl;
|
cannam@233
|
148 }
|
cannam@233
|
149
|
cannam@233
|
150 bool
|
cannam@233
|
151 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
152 {
|
cannam@233
|
153 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@233
|
154 }
|
cannam@233
|
155
|
cannam@288
|
156 void
|
cannam@288
|
157 PluginInputDomainAdapter::reset()
|
cannam@288
|
158 {
|
cannam@288
|
159 m_impl->reset();
|
cannam@288
|
160 }
|
cannam@288
|
161
|
cannam@233
|
162 Plugin::InputDomain
|
cannam@233
|
163 PluginInputDomainAdapter::getInputDomain() const
|
cannam@233
|
164 {
|
cannam@233
|
165 return TimeDomain;
|
cannam@233
|
166 }
|
cannam@233
|
167
|
cannam@233
|
168 size_t
|
cannam@233
|
169 PluginInputDomainAdapter::getPreferredStepSize() const
|
cannam@233
|
170 {
|
cannam@233
|
171 return m_impl->getPreferredStepSize();
|
cannam@233
|
172 }
|
cannam@233
|
173
|
cannam@233
|
174 size_t
|
cannam@233
|
175 PluginInputDomainAdapter::getPreferredBlockSize() const
|
cannam@233
|
176 {
|
cannam@233
|
177 return m_impl->getPreferredBlockSize();
|
cannam@233
|
178 }
|
cannam@233
|
179
|
cannam@233
|
180 Plugin::FeatureSet
|
cannam@233
|
181 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@233
|
182 {
|
cannam@233
|
183 return m_impl->process(inputBuffers, timestamp);
|
cannam@233
|
184 }
|
cannam@233
|
185
|
cannam@288
|
186 void
|
cannam@288
|
187 PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
188 {
|
cannam@288
|
189 m_impl->setProcessTimestampMethod(m);
|
cannam@288
|
190 }
|
cannam@288
|
191
|
cannam@288
|
192 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
193 PluginInputDomainAdapter::getProcessTimestampMethod() const
|
cannam@288
|
194 {
|
cannam@288
|
195 return m_impl->getProcessTimestampMethod();
|
cannam@288
|
196 }
|
cannam@288
|
197
|
cannam@233
|
198 RealTime
|
cannam@233
|
199 PluginInputDomainAdapter::getTimestampAdjustment() const
|
cannam@233
|
200 {
|
cannam@233
|
201 return m_impl->getTimestampAdjustment();
|
cannam@233
|
202 }
|
cannam@233
|
203
|
Chris@317
|
204 PluginInputDomainAdapter::WindowType
|
Chris@317
|
205 PluginInputDomainAdapter::getWindowType() const
|
Chris@317
|
206 {
|
Chris@317
|
207 return m_impl->getWindowType();
|
Chris@317
|
208 }
|
Chris@317
|
209
|
Chris@317
|
210 void
|
Chris@317
|
211 PluginInputDomainAdapter::setWindowType(WindowType w)
|
Chris@317
|
212 {
|
Chris@317
|
213 m_impl->setWindowType(w);
|
Chris@317
|
214 }
|
Chris@317
|
215
|
cannam@233
|
216
|
cannam@233
|
217 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@233
|
218 m_plugin(plugin),
|
cannam@233
|
219 m_inputSampleRate(inputSampleRate),
|
cannam@233
|
220 m_channels(0),
|
cannam@288
|
221 m_stepSize(0),
|
cannam@233
|
222 m_blockSize(0),
|
cannam@233
|
223 m_freqbuf(0),
|
cannam@233
|
224 m_ri(0),
|
Chris@317
|
225 m_windowType(HanningWindow),
|
cannam@233
|
226 m_window(0),
|
cannam@288
|
227 m_method(ShiftTimestamp),
|
cannam@288
|
228 m_processCount(0),
|
cannam@289
|
229 m_shiftBuffers(0),
|
cannam@233
|
230 #ifdef HAVE_FFTW3
|
cannam@233
|
231 m_plan(0),
|
cannam@233
|
232 m_cbuf(0)
|
cannam@233
|
233 #else
|
cannam@233
|
234 m_ro(0),
|
cannam@233
|
235 m_io(0)
|
cannam@233
|
236 #endif
|
cannam@233
|
237 {
|
cannam@233
|
238 }
|
cannam@233
|
239
|
cannam@233
|
240 PluginInputDomainAdapter::Impl::~Impl()
|
cannam@233
|
241 {
|
cannam@233
|
242 // the adapter will delete the plugin
|
cannam@233
|
243
|
cannam@289
|
244 if (m_shiftBuffers) {
|
cannam@289
|
245 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
246 delete[] m_shiftBuffers[c];
|
cannam@289
|
247 }
|
cannam@289
|
248 delete[] m_shiftBuffers;
|
cannam@289
|
249 }
|
cannam@289
|
250
|
cannam@233
|
251 if (m_channels > 0) {
|
cannam@233
|
252 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
253 delete[] m_freqbuf[c];
|
cannam@233
|
254 }
|
cannam@233
|
255 delete[] m_freqbuf;
|
cannam@233
|
256 #ifdef HAVE_FFTW3
|
cannam@233
|
257 if (m_plan) {
|
cannam@233
|
258 fftw_destroy_plan(m_plan);
|
cannam@233
|
259 fftw_free(m_ri);
|
cannam@233
|
260 fftw_free(m_cbuf);
|
cannam@233
|
261 m_plan = 0;
|
cannam@233
|
262 }
|
cannam@233
|
263 #else
|
cannam@233
|
264 delete[] m_ri;
|
cannam@233
|
265 delete[] m_ro;
|
cannam@233
|
266 delete[] m_io;
|
cannam@233
|
267 #endif
|
Chris@317
|
268
|
Chris@317
|
269 delete m_window;
|
cannam@233
|
270 }
|
cannam@233
|
271 }
|
cannam@233
|
272
|
cannam@233
|
273 // for some visual studii apparently
|
cannam@233
|
274 #ifndef M_PI
|
cannam@233
|
275 #define M_PI 3.14159265358979232846
|
cannam@233
|
276 #endif
|
cannam@233
|
277
|
cannam@233
|
278 bool
|
cannam@233
|
279 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
280 {
|
cannam@233
|
281 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
282
|
cannam@288
|
283 m_stepSize = int(stepSize);
|
cannam@233
|
284 m_blockSize = int(blockSize);
|
cannam@233
|
285 m_channels = int(channels);
|
cannam@233
|
286
|
cannam@233
|
287 return m_plugin->initialise(channels, stepSize, blockSize);
|
cannam@233
|
288 }
|
cannam@233
|
289
|
cannam@233
|
290 if (blockSize < 2) {
|
cannam@283
|
291 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
|
cannam@233
|
292 return false;
|
cannam@233
|
293 }
|
cannam@233
|
294
|
Chris@384
|
295 #ifndef HAVE_FFTW3
|
cannam@233
|
296 if (blockSize & (blockSize-1)) {
|
cannam@283
|
297 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
|
cannam@233
|
298 return false;
|
cannam@233
|
299 }
|
Chris@384
|
300 #endif
|
cannam@233
|
301
|
cannam@233
|
302 if (m_channels > 0) {
|
cannam@233
|
303 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
304 delete[] m_freqbuf[c];
|
cannam@233
|
305 }
|
cannam@233
|
306 delete[] m_freqbuf;
|
cannam@233
|
307 #ifdef HAVE_FFTW3
|
cannam@233
|
308 if (m_plan) {
|
cannam@233
|
309 fftw_destroy_plan(m_plan);
|
cannam@233
|
310 fftw_free(m_ri);
|
cannam@233
|
311 fftw_free(m_cbuf);
|
cannam@233
|
312 m_plan = 0;
|
cannam@233
|
313 }
|
cannam@233
|
314 #else
|
cannam@233
|
315 delete[] m_ri;
|
cannam@233
|
316 delete[] m_ro;
|
cannam@233
|
317 delete[] m_io;
|
cannam@233
|
318 #endif
|
Chris@317
|
319 delete m_window;
|
cannam@233
|
320 }
|
cannam@233
|
321
|
cannam@288
|
322 m_stepSize = int(stepSize);
|
cannam@233
|
323 m_blockSize = int(blockSize);
|
cannam@233
|
324 m_channels = int(channels);
|
cannam@233
|
325
|
cannam@233
|
326 m_freqbuf = new float *[m_channels];
|
cannam@233
|
327 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
328 m_freqbuf[c] = new float[m_blockSize + 2];
|
cannam@233
|
329 }
|
cannam@233
|
330
|
Chris@317
|
331 m_window = new Window<double>(convertType(m_windowType), m_blockSize);
|
cannam@233
|
332
|
cannam@233
|
333 #ifdef HAVE_FFTW3
|
cannam@233
|
334 m_ri = (double *)fftw_malloc(blockSize * sizeof(double));
|
cannam@233
|
335 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex));
|
cannam@233
|
336 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE);
|
cannam@233
|
337 #else
|
cannam@233
|
338 m_ri = new double[m_blockSize];
|
cannam@233
|
339 m_ro = new double[m_blockSize];
|
cannam@233
|
340 m_io = new double[m_blockSize];
|
cannam@233
|
341 #endif
|
cannam@233
|
342
|
cannam@288
|
343 m_processCount = 0;
|
cannam@288
|
344
|
cannam@233
|
345 return m_plugin->initialise(channels, stepSize, blockSize);
|
cannam@233
|
346 }
|
cannam@233
|
347
|
cannam@288
|
348 void
|
cannam@288
|
349 PluginInputDomainAdapter::Impl::reset()
|
cannam@288
|
350 {
|
cannam@288
|
351 m_processCount = 0;
|
cannam@288
|
352 m_plugin->reset();
|
cannam@288
|
353 }
|
cannam@288
|
354
|
cannam@233
|
355 size_t
|
cannam@233
|
356 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
|
cannam@233
|
357 {
|
cannam@233
|
358 size_t step = m_plugin->getPreferredStepSize();
|
cannam@233
|
359
|
cannam@233
|
360 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
|
cannam@233
|
361 step = getPreferredBlockSize() / 2;
|
cannam@233
|
362 }
|
cannam@233
|
363
|
cannam@233
|
364 return step;
|
cannam@233
|
365 }
|
cannam@233
|
366
|
cannam@233
|
367 size_t
|
cannam@233
|
368 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
|
cannam@233
|
369 {
|
cannam@233
|
370 size_t block = m_plugin->getPreferredBlockSize();
|
cannam@233
|
371
|
cannam@233
|
372 if (m_plugin->getInputDomain() == FrequencyDomain) {
|
cannam@233
|
373 if (block == 0) {
|
cannam@233
|
374 block = 1024;
|
cannam@233
|
375 } else {
|
cannam@233
|
376 block = makeBlockSizeAcceptable(block);
|
cannam@233
|
377 }
|
cannam@233
|
378 }
|
cannam@233
|
379
|
cannam@233
|
380 return block;
|
cannam@233
|
381 }
|
cannam@233
|
382
|
cannam@233
|
383 size_t
|
cannam@233
|
384 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
|
cannam@233
|
385 {
|
cannam@233
|
386 if (blockSize < 2) {
|
cannam@233
|
387
|
cannam@283
|
388 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
|
cannam@233
|
389 << "supported, increasing from " << blockSize << " to 2" << std::endl;
|
cannam@233
|
390 blockSize = 2;
|
cannam@233
|
391
|
cannam@233
|
392 } else if (blockSize & (blockSize-1)) {
|
cannam@233
|
393
|
cannam@233
|
394 #ifdef HAVE_FFTW3
|
cannam@233
|
395 // not an issue with FFTW
|
cannam@233
|
396 #else
|
cannam@233
|
397
|
cannam@233
|
398 // not a power of two, can't handle that with our built-in FFT
|
cannam@233
|
399 // implementation
|
cannam@233
|
400
|
cannam@233
|
401 size_t nearest = blockSize;
|
cannam@233
|
402 size_t power = 0;
|
cannam@233
|
403 while (nearest > 1) {
|
cannam@233
|
404 nearest >>= 1;
|
cannam@233
|
405 ++power;
|
cannam@233
|
406 }
|
cannam@233
|
407 nearest = 1;
|
cannam@233
|
408 while (power) {
|
cannam@233
|
409 nearest <<= 1;
|
cannam@233
|
410 --power;
|
cannam@233
|
411 }
|
cannam@233
|
412
|
cannam@233
|
413 if (blockSize - nearest > (nearest*2) - blockSize) {
|
cannam@233
|
414 nearest = nearest*2;
|
cannam@233
|
415 }
|
cannam@233
|
416
|
cannam@283
|
417 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
|
cannam@233
|
418 blockSize = nearest;
|
cannam@233
|
419
|
cannam@233
|
420 #endif
|
cannam@233
|
421 }
|
cannam@233
|
422
|
cannam@233
|
423 return blockSize;
|
cannam@233
|
424 }
|
cannam@233
|
425
|
cannam@233
|
426 RealTime
|
cannam@233
|
427 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
|
cannam@233
|
428 {
|
cannam@233
|
429 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
430 return RealTime::zeroTime;
|
cannam@298
|
431 } else if (m_method == ShiftData || m_method == NoShift) {
|
cannam@289
|
432 return RealTime::zeroTime;
|
cannam@233
|
433 } else {
|
cannam@233
|
434 return RealTime::frame2RealTime
|
cannam@233
|
435 (m_blockSize/2, int(m_inputSampleRate + 0.5));
|
cannam@233
|
436 }
|
cannam@233
|
437 }
|
cannam@233
|
438
|
cannam@288
|
439 void
|
cannam@288
|
440 PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
441 {
|
cannam@288
|
442 m_method = m;
|
cannam@288
|
443 }
|
cannam@288
|
444
|
cannam@288
|
445 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
446 PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
|
cannam@288
|
447 {
|
cannam@288
|
448 return m_method;
|
cannam@288
|
449 }
|
cannam@288
|
450
|
Chris@317
|
451 void
|
Chris@317
|
452 PluginInputDomainAdapter::Impl::setWindowType(WindowType t)
|
Chris@317
|
453 {
|
Chris@317
|
454 if (m_windowType == t) return;
|
Chris@317
|
455 m_windowType = t;
|
Chris@317
|
456 if (m_window) {
|
Chris@317
|
457 delete m_window;
|
Chris@317
|
458 m_window = new Window<double>(convertType(m_windowType), m_blockSize);
|
Chris@317
|
459 }
|
Chris@317
|
460 }
|
Chris@317
|
461
|
Chris@317
|
462 PluginInputDomainAdapter::WindowType
|
Chris@317
|
463 PluginInputDomainAdapter::Impl::getWindowType() const
|
Chris@317
|
464 {
|
Chris@317
|
465 return m_windowType;
|
Chris@317
|
466 }
|
Chris@317
|
467
|
Chris@317
|
468 Window<double>::WindowType
|
Chris@317
|
469 PluginInputDomainAdapter::Impl::convertType(WindowType t) const
|
Chris@317
|
470 {
|
Chris@317
|
471 switch (t) {
|
Chris@317
|
472 case RectangularWindow:
|
Chris@317
|
473 return Window<double>::RectangularWindow;
|
Chris@317
|
474 case BartlettWindow:
|
Chris@317
|
475 return Window<double>::BartlettWindow;
|
Chris@317
|
476 case HammingWindow:
|
Chris@317
|
477 return Window<double>::HammingWindow;
|
Chris@317
|
478 case HanningWindow:
|
Chris@317
|
479 return Window<double>::HanningWindow;
|
Chris@317
|
480 case BlackmanWindow:
|
Chris@317
|
481 return Window<double>::BlackmanWindow;
|
Chris@317
|
482 case NuttallWindow:
|
Chris@317
|
483 return Window<double>::NuttallWindow;
|
Chris@317
|
484 case BlackmanHarrisWindow:
|
Chris@317
|
485 return Window<double>::BlackmanHarrisWindow;
|
Chris@319
|
486 default:
|
Chris@319
|
487 return Window<double>::HanningWindow;
|
Chris@317
|
488 }
|
Chris@317
|
489 }
|
Chris@317
|
490
|
cannam@233
|
491 Plugin::FeatureSet
|
cannam@233
|
492 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@233
|
493 RealTime timestamp)
|
cannam@233
|
494 {
|
cannam@233
|
495 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
496 return m_plugin->process(inputBuffers, timestamp);
|
cannam@233
|
497 }
|
cannam@233
|
498
|
cannam@298
|
499 if (m_method == ShiftTimestamp || m_method == NoShift) {
|
cannam@289
|
500 return processShiftingTimestamp(inputBuffers, timestamp);
|
cannam@289
|
501 } else {
|
cannam@289
|
502 return processShiftingData(inputBuffers, timestamp);
|
cannam@289
|
503 }
|
cannam@289
|
504 }
|
cannam@233
|
505
|
cannam@289
|
506 Plugin::FeatureSet
|
cannam@289
|
507 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
|
cannam@289
|
508 RealTime timestamp)
|
cannam@289
|
509 {
|
cannam@298
|
510 if (m_method == ShiftTimestamp) {
|
Chris@386
|
511 // we may need to add one nsec if timestamp +
|
Chris@386
|
512 // getTimestampAdjustment() rounds down
|
cannam@298
|
513 timestamp = timestamp + getTimestampAdjustment();
|
Chris@386
|
514 RealTime nsec(0, 1);
|
Chris@386
|
515 if (RealTime::realTime2Frame(timestamp, m_inputSampleRate) <
|
Chris@386
|
516 RealTime::realTime2Frame(timestamp + nsec, m_inputSampleRate)) {
|
Chris@386
|
517 timestamp = timestamp + nsec;
|
Chris@386
|
518 }
|
cannam@298
|
519 }
|
cannam@233
|
520
|
cannam@233
|
521 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
522
|
Chris@317
|
523 m_window->cut(inputBuffers[c], m_ri);
|
cannam@233
|
524
|
cannam@233
|
525 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@233
|
526 // FFT shift
|
cannam@233
|
527 double value = m_ri[i];
|
cannam@233
|
528 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@233
|
529 m_ri[i + m_blockSize/2] = value;
|
cannam@233
|
530 }
|
cannam@233
|
531
|
cannam@233
|
532 #ifdef HAVE_FFTW3
|
cannam@233
|
533 fftw_execute(m_plan);
|
cannam@233
|
534
|
cannam@233
|
535 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@233
|
536 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
|
cannam@233
|
537 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
|
cannam@233
|
538 }
|
cannam@233
|
539 #else
|
cannam@233
|
540 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
|
cannam@233
|
541
|
cannam@233
|
542 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@233
|
543 m_freqbuf[c][i * 2] = float(m_ro[i]);
|
cannam@233
|
544 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
|
cannam@233
|
545 }
|
cannam@233
|
546 #endif
|
cannam@233
|
547 }
|
cannam@233
|
548
|
cannam@289
|
549 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@288
|
550 }
|
cannam@288
|
551
|
cannam@288
|
552 Plugin::FeatureSet
|
cannam@289
|
553 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
|
cannam@289
|
554 RealTime timestamp)
|
cannam@288
|
555 {
|
cannam@289
|
556 if (m_processCount == 0) {
|
cannam@289
|
557 if (!m_shiftBuffers) {
|
cannam@289
|
558 m_shiftBuffers = new float *[m_channels];
|
cannam@289
|
559 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
560 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
|
cannam@289
|
561 }
|
cannam@289
|
562 }
|
cannam@289
|
563 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
564 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
565 m_shiftBuffers[c][i] = 0.f;
|
cannam@289
|
566 }
|
cannam@289
|
567 }
|
cannam@289
|
568 }
|
cannam@289
|
569
|
cannam@289
|
570 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
571 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
572 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
|
cannam@289
|
573 }
|
cannam@289
|
574 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@289
|
575 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
|
cannam@289
|
576 }
|
cannam@289
|
577 }
|
cannam@289
|
578
|
cannam@289
|
579 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
580
|
Chris@317
|
581 m_window->cut(m_shiftBuffers[c], m_ri);
|
cannam@289
|
582
|
cannam@289
|
583 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@289
|
584 // FFT shift
|
cannam@289
|
585 double value = m_ri[i];
|
cannam@289
|
586 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@289
|
587 m_ri[i + m_blockSize/2] = value;
|
cannam@289
|
588 }
|
cannam@289
|
589
|
cannam@289
|
590 #ifdef HAVE_FFTW3
|
cannam@289
|
591 fftw_execute(m_plan);
|
cannam@289
|
592
|
cannam@289
|
593 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@289
|
594 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]);
|
cannam@289
|
595 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]);
|
cannam@289
|
596 }
|
cannam@289
|
597 #else
|
cannam@289
|
598 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
|
cannam@289
|
599
|
cannam@289
|
600 for (int i = 0; i <= m_blockSize/2; ++i) {
|
cannam@289
|
601 m_freqbuf[c][i * 2] = float(m_ro[i]);
|
cannam@289
|
602 m_freqbuf[c][i * 2 + 1] = float(m_io[i]);
|
cannam@289
|
603 }
|
cannam@289
|
604 #endif
|
cannam@289
|
605 }
|
cannam@289
|
606
|
cannam@289
|
607 ++m_processCount;
|
cannam@289
|
608
|
cannam@289
|
609 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@233
|
610 }
|
cannam@233
|
611
|
cannam@233
|
612 #ifndef HAVE_FFTW3
|
cannam@233
|
613
|
cannam@233
|
614 #endif
|
cannam@233
|
615
|
cannam@233
|
616 }
|
cannam@233
|
617
|
cannam@233
|
618 }
|
cannam@233
|
619
|
cannam@263
|
620 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
|
cannam@263
|
621
|