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