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
|
Chris@434
|
46 #include <stdlib.h>
|
Chris@434
|
47 #include <stdio.h>
|
Chris@434
|
48 #include <math.h>
|
Chris@434
|
49 #include <string.h>
|
Chris@434
|
50 #include <limits.h>
|
cannam@233
|
51
|
Chris@444
|
52 // Define this symbol in the build if you want to use single-precision
|
Chris@444
|
53 // FFTs in the input domain adapter. The default is to use
|
Chris@444
|
54 // double-precision FFTs.
|
Chris@444
|
55 //
|
Chris@444
|
56 //#define SINGLE_PRECISION_INPUT_DOMAIN_ADAPTER 1
|
Chris@444
|
57
|
Chris@434
|
58 // Override C linkage for KissFFT headers. So long as we have already
|
Chris@434
|
59 // included all of the other (system etc) headers KissFFT depends on,
|
Chris@434
|
60 // this should work out OK
|
Chris@434
|
61 #undef __cplusplus
|
cannam@233
|
62
|
Chris@444
|
63 namespace Kiss {
|
Chris@444
|
64
|
Chris@434
|
65 #undef KISS_FFT_H
|
Chris@434
|
66 #undef KISS_FTR_H
|
Chris@434
|
67 #undef KISS_FFT__GUTS_H
|
Chris@434
|
68 #undef FIXED_POINT
|
Chris@434
|
69 #undef USE_SIMD
|
Chris@434
|
70 #undef kiss_fft_scalar
|
Chris@444
|
71
|
Chris@444
|
72 #ifdef SINGLE_PRECISION_INPUT_DOMAIN_ADAPTER
|
Chris@444
|
73 typedef float kiss_fft_scalar;
|
Chris@434
|
74 #define kiss_fft_scalar float
|
Chris@444
|
75 #else
|
Chris@444
|
76 typedef double kiss_fft_scalar;
|
Chris@444
|
77 #define kiss_fft_scalar double
|
Chris@444
|
78 #endif
|
Chris@444
|
79
|
Chris@434
|
80 inline void free(void *ptr) { ::free(ptr); }
|
Chris@434
|
81 #include "../vamp-sdk/ext/kiss_fft.c"
|
Chris@434
|
82 #include "../vamp-sdk/ext/kiss_fftr.c"
|
Chris@444
|
83
|
Chris@444
|
84 #undef kiss_fft_scalar // leaving only the namespaced typedef
|
Chris@444
|
85
|
Chris@434
|
86 }
|
cannam@233
|
87
|
cannam@263
|
88 _VAMP_SDK_HOSTSPACE_BEGIN(PluginInputDomainAdapter.cpp)
|
cannam@263
|
89
|
cannam@233
|
90 namespace Vamp {
|
cannam@233
|
91
|
cannam@233
|
92 namespace HostExt {
|
cannam@233
|
93
|
cannam@233
|
94 class PluginInputDomainAdapter::Impl
|
cannam@233
|
95 {
|
cannam@233
|
96 public:
|
cannam@233
|
97 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@233
|
98 ~Impl();
|
cannam@233
|
99
|
cannam@233
|
100 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@288
|
101 void reset();
|
cannam@233
|
102
|
cannam@233
|
103 size_t getPreferredStepSize() const;
|
cannam@233
|
104 size_t getPreferredBlockSize() const;
|
cannam@233
|
105
|
cannam@233
|
106 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@288
|
107
|
cannam@288
|
108 void setProcessTimestampMethod(ProcessTimestampMethod m);
|
cannam@288
|
109 ProcessTimestampMethod getProcessTimestampMethod() const;
|
cannam@233
|
110
|
cannam@233
|
111 RealTime getTimestampAdjustment() const;
|
cannam@233
|
112
|
Chris@317
|
113 WindowType getWindowType() const;
|
Chris@317
|
114 void setWindowType(WindowType type);
|
Chris@317
|
115
|
cannam@233
|
116 protected:
|
cannam@233
|
117 Plugin *m_plugin;
|
cannam@233
|
118 float m_inputSampleRate;
|
cannam@233
|
119 int m_channels;
|
cannam@288
|
120 int m_stepSize;
|
cannam@233
|
121 int m_blockSize;
|
cannam@233
|
122 float **m_freqbuf;
|
Chris@444
|
123 Kiss::kiss_fft_scalar *m_ri;
|
Chris@317
|
124
|
Chris@317
|
125 WindowType m_windowType;
|
Chris@444
|
126 typedef Window<Kiss::kiss_fft_scalar> W;
|
Chris@444
|
127 W *m_window;
|
cannam@233
|
128
|
cannam@288
|
129 ProcessTimestampMethod m_method;
|
cannam@288
|
130 int m_processCount;
|
cannam@289
|
131 float **m_shiftBuffers;
|
cannam@288
|
132
|
Chris@444
|
133 Kiss::kiss_fftr_cfg m_cfg;
|
Chris@444
|
134 Kiss::kiss_fft_cpx *m_cbuf;
|
cannam@233
|
135
|
cannam@289
|
136 FeatureSet processShiftingTimestamp(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
137 FeatureSet processShiftingData(const float *const *inputBuffers, RealTime timestamp);
|
cannam@289
|
138
|
cannam@233
|
139 size_t makeBlockSizeAcceptable(size_t) const;
|
Chris@317
|
140
|
Chris@444
|
141 W::WindowType convertType(WindowType t) const;
|
cannam@233
|
142 };
|
cannam@233
|
143
|
cannam@233
|
144 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
|
cannam@233
|
145 PluginWrapper(plugin)
|
cannam@233
|
146 {
|
cannam@233
|
147 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@233
|
148 }
|
cannam@233
|
149
|
cannam@233
|
150 PluginInputDomainAdapter::~PluginInputDomainAdapter()
|
cannam@233
|
151 {
|
cannam@233
|
152 delete m_impl;
|
cannam@233
|
153 }
|
cannam@233
|
154
|
cannam@233
|
155 bool
|
cannam@233
|
156 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
157 {
|
cannam@233
|
158 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@233
|
159 }
|
cannam@233
|
160
|
cannam@288
|
161 void
|
cannam@288
|
162 PluginInputDomainAdapter::reset()
|
cannam@288
|
163 {
|
cannam@288
|
164 m_impl->reset();
|
cannam@288
|
165 }
|
cannam@288
|
166
|
cannam@233
|
167 Plugin::InputDomain
|
cannam@233
|
168 PluginInputDomainAdapter::getInputDomain() const
|
cannam@233
|
169 {
|
cannam@233
|
170 return TimeDomain;
|
cannam@233
|
171 }
|
cannam@233
|
172
|
cannam@233
|
173 size_t
|
cannam@233
|
174 PluginInputDomainAdapter::getPreferredStepSize() const
|
cannam@233
|
175 {
|
cannam@233
|
176 return m_impl->getPreferredStepSize();
|
cannam@233
|
177 }
|
cannam@233
|
178
|
cannam@233
|
179 size_t
|
cannam@233
|
180 PluginInputDomainAdapter::getPreferredBlockSize() const
|
cannam@233
|
181 {
|
cannam@233
|
182 return m_impl->getPreferredBlockSize();
|
cannam@233
|
183 }
|
cannam@233
|
184
|
cannam@233
|
185 Plugin::FeatureSet
|
cannam@233
|
186 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
|
cannam@233
|
187 {
|
cannam@233
|
188 return m_impl->process(inputBuffers, timestamp);
|
cannam@233
|
189 }
|
cannam@233
|
190
|
cannam@288
|
191 void
|
cannam@288
|
192 PluginInputDomainAdapter::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
193 {
|
cannam@288
|
194 m_impl->setProcessTimestampMethod(m);
|
cannam@288
|
195 }
|
cannam@288
|
196
|
cannam@288
|
197 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
198 PluginInputDomainAdapter::getProcessTimestampMethod() const
|
cannam@288
|
199 {
|
cannam@288
|
200 return m_impl->getProcessTimestampMethod();
|
cannam@288
|
201 }
|
cannam@288
|
202
|
cannam@233
|
203 RealTime
|
cannam@233
|
204 PluginInputDomainAdapter::getTimestampAdjustment() const
|
cannam@233
|
205 {
|
cannam@233
|
206 return m_impl->getTimestampAdjustment();
|
cannam@233
|
207 }
|
cannam@233
|
208
|
Chris@317
|
209 PluginInputDomainAdapter::WindowType
|
Chris@317
|
210 PluginInputDomainAdapter::getWindowType() const
|
Chris@317
|
211 {
|
Chris@317
|
212 return m_impl->getWindowType();
|
Chris@317
|
213 }
|
Chris@317
|
214
|
Chris@317
|
215 void
|
Chris@317
|
216 PluginInputDomainAdapter::setWindowType(WindowType w)
|
Chris@317
|
217 {
|
Chris@317
|
218 m_impl->setWindowType(w);
|
Chris@317
|
219 }
|
Chris@317
|
220
|
cannam@233
|
221
|
cannam@233
|
222 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@233
|
223 m_plugin(plugin),
|
cannam@233
|
224 m_inputSampleRate(inputSampleRate),
|
cannam@233
|
225 m_channels(0),
|
cannam@288
|
226 m_stepSize(0),
|
cannam@233
|
227 m_blockSize(0),
|
cannam@233
|
228 m_freqbuf(0),
|
cannam@233
|
229 m_ri(0),
|
Chris@317
|
230 m_windowType(HanningWindow),
|
cannam@233
|
231 m_window(0),
|
cannam@288
|
232 m_method(ShiftTimestamp),
|
cannam@288
|
233 m_processCount(0),
|
cannam@289
|
234 m_shiftBuffers(0),
|
Chris@434
|
235 m_cfg(0),
|
cannam@233
|
236 m_cbuf(0)
|
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;
|
Chris@435
|
256 delete[] m_ri;
|
Chris@434
|
257 if (m_cfg) {
|
Chris@444
|
258 Kiss::kiss_fftr_free(m_cfg);
|
Chris@435
|
259 m_cfg = 0;
|
Chris@434
|
260 delete[] m_cbuf;
|
Chris@435
|
261 m_cbuf = 0;
|
cannam@233
|
262 }
|
Chris@317
|
263 delete m_window;
|
cannam@233
|
264 }
|
cannam@233
|
265 }
|
cannam@233
|
266
|
cannam@233
|
267 // for some visual studii apparently
|
cannam@233
|
268 #ifndef M_PI
|
cannam@233
|
269 #define M_PI 3.14159265358979232846
|
cannam@233
|
270 #endif
|
cannam@233
|
271
|
cannam@233
|
272 bool
|
cannam@233
|
273 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
274 {
|
cannam@233
|
275 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
276
|
cannam@288
|
277 m_stepSize = int(stepSize);
|
cannam@233
|
278 m_blockSize = int(blockSize);
|
cannam@233
|
279 m_channels = int(channels);
|
cannam@233
|
280
|
cannam@233
|
281 return m_plugin->initialise(channels, stepSize, blockSize);
|
cannam@233
|
282 }
|
cannam@233
|
283
|
cannam@233
|
284 if (blockSize < 2) {
|
cannam@283
|
285 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
|
cannam@233
|
286 return false;
|
cannam@233
|
287 }
|
cannam@233
|
288
|
Chris@434
|
289 if (blockSize % 2) {
|
Chris@434
|
290 std::cerr << "ERROR: PluginInputDomainAdapter::initialise: odd blocksize " << blockSize << " not supported" << std::endl;
|
cannam@233
|
291 return false;
|
cannam@233
|
292 }
|
cannam@233
|
293
|
cannam@233
|
294 if (m_channels > 0) {
|
cannam@233
|
295 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
296 delete[] m_freqbuf[c];
|
cannam@233
|
297 }
|
cannam@233
|
298 delete[] m_freqbuf;
|
Chris@435
|
299 delete[] m_ri;
|
Chris@434
|
300 if (m_cfg) {
|
Chris@444
|
301 Kiss::kiss_fftr_free(m_cfg);
|
Chris@435
|
302 m_cfg = 0;
|
Chris@434
|
303 delete[] m_cbuf;
|
Chris@435
|
304 m_cbuf = 0;
|
cannam@233
|
305 }
|
Chris@317
|
306 delete m_window;
|
cannam@233
|
307 }
|
cannam@233
|
308
|
cannam@288
|
309 m_stepSize = int(stepSize);
|
cannam@233
|
310 m_blockSize = int(blockSize);
|
cannam@233
|
311 m_channels = int(channels);
|
cannam@233
|
312
|
cannam@233
|
313 m_freqbuf = new float *[m_channels];
|
cannam@233
|
314 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
315 m_freqbuf[c] = new float[m_blockSize + 2];
|
cannam@233
|
316 }
|
Chris@444
|
317 m_ri = new Kiss::kiss_fft_scalar[m_blockSize];
|
cannam@233
|
318
|
Chris@444
|
319 m_window = new W(convertType(m_windowType), m_blockSize);
|
cannam@233
|
320
|
Chris@444
|
321 m_cfg = Kiss::kiss_fftr_alloc(m_blockSize, false, 0, 0);
|
Chris@444
|
322 m_cbuf = new Kiss::kiss_fft_cpx[m_blockSize/2+1];
|
cannam@233
|
323
|
cannam@288
|
324 m_processCount = 0;
|
cannam@288
|
325
|
Chris@435
|
326 return m_plugin->initialise(channels, stepSize, m_blockSize);
|
cannam@233
|
327 }
|
cannam@233
|
328
|
cannam@288
|
329 void
|
cannam@288
|
330 PluginInputDomainAdapter::Impl::reset()
|
cannam@288
|
331 {
|
cannam@288
|
332 m_processCount = 0;
|
cannam@288
|
333 m_plugin->reset();
|
cannam@288
|
334 }
|
cannam@288
|
335
|
cannam@233
|
336 size_t
|
cannam@233
|
337 PluginInputDomainAdapter::Impl::getPreferredStepSize() const
|
cannam@233
|
338 {
|
cannam@233
|
339 size_t step = m_plugin->getPreferredStepSize();
|
cannam@233
|
340
|
cannam@233
|
341 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
|
cannam@233
|
342 step = getPreferredBlockSize() / 2;
|
cannam@233
|
343 }
|
cannam@233
|
344
|
cannam@233
|
345 return step;
|
cannam@233
|
346 }
|
cannam@233
|
347
|
cannam@233
|
348 size_t
|
cannam@233
|
349 PluginInputDomainAdapter::Impl::getPreferredBlockSize() const
|
cannam@233
|
350 {
|
cannam@233
|
351 size_t block = m_plugin->getPreferredBlockSize();
|
cannam@233
|
352
|
cannam@233
|
353 if (m_plugin->getInputDomain() == FrequencyDomain) {
|
cannam@233
|
354 if (block == 0) {
|
cannam@233
|
355 block = 1024;
|
cannam@233
|
356 } else {
|
cannam@233
|
357 block = makeBlockSizeAcceptable(block);
|
cannam@233
|
358 }
|
cannam@233
|
359 }
|
cannam@233
|
360
|
cannam@233
|
361 return block;
|
cannam@233
|
362 }
|
cannam@233
|
363
|
cannam@233
|
364 size_t
|
cannam@233
|
365 PluginInputDomainAdapter::Impl::makeBlockSizeAcceptable(size_t blockSize) const
|
cannam@233
|
366 {
|
cannam@233
|
367 if (blockSize < 2) {
|
cannam@233
|
368
|
cannam@283
|
369 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
|
cannam@233
|
370 << "supported, increasing from " << blockSize << " to 2" << std::endl;
|
cannam@233
|
371 blockSize = 2;
|
Chris@434
|
372
|
Chris@434
|
373 } else if (blockSize % 2) {
|
cannam@233
|
374
|
Chris@434
|
375 std::cerr << "WARNING: PluginInputDomainAdapter::initialise: odd blocksize not" << std::endl
|
Chris@434
|
376 << "supported, increasing from " << blockSize << " to " << (blockSize+1) << std::endl;
|
Chris@434
|
377 blockSize = blockSize+1;
|
cannam@233
|
378 }
|
cannam@233
|
379
|
cannam@233
|
380 return blockSize;
|
cannam@233
|
381 }
|
cannam@233
|
382
|
cannam@233
|
383 RealTime
|
cannam@233
|
384 PluginInputDomainAdapter::Impl::getTimestampAdjustment() const
|
cannam@233
|
385 {
|
cannam@233
|
386 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
387 return RealTime::zeroTime;
|
cannam@298
|
388 } else if (m_method == ShiftData || m_method == NoShift) {
|
cannam@289
|
389 return RealTime::zeroTime;
|
cannam@233
|
390 } else {
|
cannam@233
|
391 return RealTime::frame2RealTime
|
cannam@233
|
392 (m_blockSize/2, int(m_inputSampleRate + 0.5));
|
cannam@233
|
393 }
|
cannam@233
|
394 }
|
cannam@233
|
395
|
cannam@288
|
396 void
|
cannam@288
|
397 PluginInputDomainAdapter::Impl::setProcessTimestampMethod(ProcessTimestampMethod m)
|
cannam@288
|
398 {
|
cannam@288
|
399 m_method = m;
|
cannam@288
|
400 }
|
cannam@288
|
401
|
cannam@288
|
402 PluginInputDomainAdapter::ProcessTimestampMethod
|
cannam@288
|
403 PluginInputDomainAdapter::Impl::getProcessTimestampMethod() const
|
cannam@288
|
404 {
|
cannam@288
|
405 return m_method;
|
cannam@288
|
406 }
|
cannam@288
|
407
|
Chris@317
|
408 void
|
Chris@317
|
409 PluginInputDomainAdapter::Impl::setWindowType(WindowType t)
|
Chris@317
|
410 {
|
Chris@317
|
411 if (m_windowType == t) return;
|
Chris@317
|
412 m_windowType = t;
|
Chris@317
|
413 if (m_window) {
|
Chris@317
|
414 delete m_window;
|
Chris@444
|
415 m_window = new W(convertType(m_windowType), m_blockSize);
|
Chris@317
|
416 }
|
Chris@317
|
417 }
|
Chris@317
|
418
|
Chris@317
|
419 PluginInputDomainAdapter::WindowType
|
Chris@317
|
420 PluginInputDomainAdapter::Impl::getWindowType() const
|
Chris@317
|
421 {
|
Chris@317
|
422 return m_windowType;
|
Chris@317
|
423 }
|
Chris@317
|
424
|
Chris@444
|
425 PluginInputDomainAdapter::Impl::W::WindowType
|
Chris@317
|
426 PluginInputDomainAdapter::Impl::convertType(WindowType t) const
|
Chris@317
|
427 {
|
Chris@317
|
428 switch (t) {
|
Chris@317
|
429 case RectangularWindow:
|
Chris@444
|
430 return W::RectangularWindow;
|
Chris@317
|
431 case BartlettWindow:
|
Chris@444
|
432 return W::BartlettWindow;
|
Chris@317
|
433 case HammingWindow:
|
Chris@444
|
434 return W::HammingWindow;
|
Chris@317
|
435 case HanningWindow:
|
Chris@444
|
436 return W::HanningWindow;
|
Chris@317
|
437 case BlackmanWindow:
|
Chris@444
|
438 return W::BlackmanWindow;
|
Chris@317
|
439 case NuttallWindow:
|
Chris@444
|
440 return W::NuttallWindow;
|
Chris@317
|
441 case BlackmanHarrisWindow:
|
Chris@444
|
442 return W::BlackmanHarrisWindow;
|
Chris@319
|
443 default:
|
Chris@444
|
444 return W::HanningWindow;
|
Chris@317
|
445 }
|
Chris@317
|
446 }
|
Chris@317
|
447
|
cannam@233
|
448 Plugin::FeatureSet
|
cannam@233
|
449 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@233
|
450 RealTime timestamp)
|
cannam@233
|
451 {
|
cannam@233
|
452 if (m_plugin->getInputDomain() == TimeDomain) {
|
cannam@233
|
453 return m_plugin->process(inputBuffers, timestamp);
|
cannam@233
|
454 }
|
cannam@233
|
455
|
cannam@298
|
456 if (m_method == ShiftTimestamp || m_method == NoShift) {
|
cannam@289
|
457 return processShiftingTimestamp(inputBuffers, timestamp);
|
cannam@289
|
458 } else {
|
cannam@289
|
459 return processShiftingData(inputBuffers, timestamp);
|
cannam@289
|
460 }
|
cannam@289
|
461 }
|
cannam@233
|
462
|
cannam@289
|
463 Plugin::FeatureSet
|
cannam@289
|
464 PluginInputDomainAdapter::Impl::processShiftingTimestamp(const float *const *inputBuffers,
|
cannam@289
|
465 RealTime timestamp)
|
cannam@289
|
466 {
|
Chris@421
|
467 unsigned int roundedRate = 1;
|
Chris@421
|
468 if (m_inputSampleRate > 0.f) {
|
Chris@421
|
469 roundedRate = (unsigned int)round(m_inputSampleRate);
|
Chris@421
|
470 }
|
Chris@421
|
471
|
cannam@298
|
472 if (m_method == ShiftTimestamp) {
|
Chris@386
|
473 // we may need to add one nsec if timestamp +
|
Chris@386
|
474 // getTimestampAdjustment() rounds down
|
cannam@298
|
475 timestamp = timestamp + getTimestampAdjustment();
|
Chris@386
|
476 RealTime nsec(0, 1);
|
Chris@421
|
477 if (RealTime::realTime2Frame(timestamp, roundedRate) <
|
Chris@421
|
478 RealTime::realTime2Frame(timestamp + nsec, roundedRate)) {
|
Chris@386
|
479 timestamp = timestamp + nsec;
|
Chris@386
|
480 }
|
cannam@298
|
481 }
|
cannam@233
|
482
|
cannam@233
|
483 for (int c = 0; c < m_channels; ++c) {
|
cannam@233
|
484
|
Chris@317
|
485 m_window->cut(inputBuffers[c], m_ri);
|
cannam@233
|
486
|
cannam@233
|
487 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@233
|
488 // FFT shift
|
Chris@444
|
489 Kiss::kiss_fft_scalar value = m_ri[i];
|
cannam@233
|
490 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@233
|
491 m_ri[i + m_blockSize/2] = value;
|
cannam@233
|
492 }
|
cannam@233
|
493
|
Chris@444
|
494 Kiss::kiss_fftr(m_cfg, m_ri, m_cbuf);
|
Chris@434
|
495
|
cannam@233
|
496 for (int i = 0; i <= m_blockSize/2; ++i) {
|
Chris@434
|
497 m_freqbuf[c][i * 2] = m_cbuf[i].r;
|
Chris@434
|
498 m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i;
|
cannam@233
|
499 }
|
cannam@233
|
500 }
|
cannam@233
|
501
|
cannam@289
|
502 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@288
|
503 }
|
cannam@288
|
504
|
cannam@288
|
505 Plugin::FeatureSet
|
cannam@289
|
506 PluginInputDomainAdapter::Impl::processShiftingData(const float *const *inputBuffers,
|
cannam@289
|
507 RealTime timestamp)
|
cannam@288
|
508 {
|
cannam@289
|
509 if (m_processCount == 0) {
|
cannam@289
|
510 if (!m_shiftBuffers) {
|
cannam@289
|
511 m_shiftBuffers = new float *[m_channels];
|
cannam@289
|
512 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
513 m_shiftBuffers[c] = new float[m_blockSize + m_blockSize/2];
|
cannam@289
|
514 }
|
cannam@289
|
515 }
|
cannam@289
|
516 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
517 for (int i = 0; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
518 m_shiftBuffers[c][i] = 0.f;
|
cannam@289
|
519 }
|
cannam@289
|
520 }
|
cannam@289
|
521 }
|
cannam@289
|
522
|
cannam@289
|
523 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
524 for (int i = m_stepSize; i < m_blockSize + m_blockSize/2; ++i) {
|
cannam@289
|
525 m_shiftBuffers[c][i - m_stepSize] = m_shiftBuffers[c][i];
|
cannam@289
|
526 }
|
cannam@289
|
527 for (int i = 0; i < m_blockSize; ++i) {
|
cannam@289
|
528 m_shiftBuffers[c][i + m_blockSize/2] = inputBuffers[c][i];
|
cannam@289
|
529 }
|
cannam@289
|
530 }
|
cannam@289
|
531
|
cannam@289
|
532 for (int c = 0; c < m_channels; ++c) {
|
cannam@289
|
533
|
Chris@317
|
534 m_window->cut(m_shiftBuffers[c], m_ri);
|
cannam@289
|
535
|
cannam@289
|
536 for (int i = 0; i < m_blockSize/2; ++i) {
|
cannam@289
|
537 // FFT shift
|
Chris@444
|
538 Kiss::kiss_fft_scalar value = m_ri[i];
|
cannam@289
|
539 m_ri[i] = m_ri[i + m_blockSize/2];
|
cannam@289
|
540 m_ri[i + m_blockSize/2] = value;
|
cannam@289
|
541 }
|
cannam@289
|
542
|
Chris@444
|
543 Kiss::kiss_fftr(m_cfg, m_ri, m_cbuf);
|
Chris@434
|
544
|
cannam@289
|
545 for (int i = 0; i <= m_blockSize/2; ++i) {
|
Chris@434
|
546 m_freqbuf[c][i * 2] = m_cbuf[i].r;
|
Chris@434
|
547 m_freqbuf[c][i * 2 + 1] = m_cbuf[i].i;
|
cannam@289
|
548 }
|
cannam@289
|
549 }
|
cannam@289
|
550
|
cannam@289
|
551 ++m_processCount;
|
cannam@289
|
552
|
cannam@289
|
553 return m_plugin->process(m_freqbuf, timestamp);
|
cannam@233
|
554 }
|
cannam@233
|
555
|
cannam@233
|
556 }
|
cannam@233
|
557
|
cannam@233
|
558 }
|
cannam@233
|
559
|
cannam@263
|
560 _VAMP_SDK_HOSTSPACE_END(PluginInputDomainAdapter.cpp)
|
cannam@263
|
561
|