Mercurial > hg > vamp-plugin-sdk
comparison vamp-sdk/hostext/PluginInputDomainAdapter.cpp @ 101:5c9f267c48c0
* Add optional support for FFTW through HAVE_FFTW3 flag. Off by default,
and should be off in any distro packages, for licensing reasons.
author | cannam |
---|---|
date | Mon, 28 Jan 2008 12:34:39 +0000 |
parents | c94c066a4897 |
children | 2cb46126ef59 |
comparison
equal
deleted
inserted
replaced
100:37348b65e792 | 101:5c9f267c48c0 |
---|---|
36 | 36 |
37 #include "PluginInputDomainAdapter.h" | 37 #include "PluginInputDomainAdapter.h" |
38 | 38 |
39 #include <cmath> | 39 #include <cmath> |
40 | 40 |
41 | |
42 /** | |
43 * If you want to compile using FFTW instead of the built-in FFT | |
44 * implementation for the PluginInputDomainAdapter, define HAVE_FFTW3 | |
45 * in the Makefile. | |
46 * | |
47 * Remember that FFTW is licensed under the GPL (unlike this SDK, which | |
48 * is licensed liberally in order to permit closed-source usage), so | |
49 * you should not define this symbol unless your code is also under the | |
50 * GPL. Also, parties redistributing this SDK for use in other | |
51 * programs should be careful _not_ to define this symbol in order not | |
52 * to affect the stated license of this SDK. | |
53 * | |
54 * Note: This code uses FFTW_MEASURE, and will perform badly on its | |
55 * first invocation unless the host has saved and restored FFTW wisdom | |
56 * (see the FFTW documentation). | |
57 */ | |
58 #ifdef HAVE_FFTW3 | |
59 #include <fftw3.h> | |
60 #endif | |
61 | |
62 | |
41 namespace Vamp { | 63 namespace Vamp { |
42 | 64 |
43 namespace HostExt { | 65 namespace HostExt { |
44 | 66 |
45 class PluginInputDomainAdapter::Impl | 67 class PluginInputDomainAdapter::Impl |
56 FeatureSet process(const float *const *inputBuffers, RealTime timestamp); | 78 FeatureSet process(const float *const *inputBuffers, RealTime timestamp); |
57 | 79 |
58 protected: | 80 protected: |
59 Plugin *m_plugin; | 81 Plugin *m_plugin; |
60 float m_inputSampleRate; | 82 float m_inputSampleRate; |
61 size_t m_channels; | 83 int m_channels; |
62 size_t m_blockSize; | 84 int m_blockSize; |
63 float **m_freqbuf; | 85 float **m_freqbuf; |
86 | |
64 double *m_ri; | 87 double *m_ri; |
88 double *m_window; | |
89 | |
90 #ifdef HAVE_FFTW3 | |
91 fftw_plan m_plan; | |
92 fftw_complex *m_cbuf; | |
93 #else | |
65 double *m_ro; | 94 double *m_ro; |
66 double *m_io; | 95 double *m_io; |
67 | |
68 void fft(unsigned int n, bool inverse, | 96 void fft(unsigned int n, bool inverse, |
69 double *ri, double *ii, double *ro, double *io); | 97 double *ri, double *ii, double *ro, double *io); |
98 #endif | |
70 | 99 |
71 size_t makeBlockSizeAcceptable(size_t) const; | 100 size_t makeBlockSizeAcceptable(size_t) const; |
72 }; | 101 }; |
73 | 102 |
74 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : | 103 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) : |
115 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : | 144 PluginInputDomainAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) : |
116 m_plugin(plugin), | 145 m_plugin(plugin), |
117 m_inputSampleRate(inputSampleRate), | 146 m_inputSampleRate(inputSampleRate), |
118 m_channels(0), | 147 m_channels(0), |
119 m_blockSize(0), | 148 m_blockSize(0), |
120 m_freqbuf(0) | 149 m_freqbuf(0), |
150 m_ri(0), | |
151 m_window(0), | |
152 #ifdef HAVE_FFTW3 | |
153 m_plan(0), | |
154 m_cbuf(0) | |
155 #else | |
156 m_ro(0), | |
157 m_io(0) | |
158 #endif | |
121 { | 159 { |
122 } | 160 } |
123 | 161 |
124 PluginInputDomainAdapter::Impl::~Impl() | 162 PluginInputDomainAdapter::Impl::~Impl() |
125 { | 163 { |
126 // the adapter will delete the plugin | 164 // the adapter will delete the plugin |
127 | 165 |
128 if (m_channels > 0) { | 166 if (m_channels > 0) { |
129 for (size_t c = 0; c < m_channels; ++c) { | 167 for (int c = 0; c < m_channels; ++c) { |
130 delete[] m_freqbuf[c]; | 168 delete[] m_freqbuf[c]; |
131 } | 169 } |
132 delete[] m_freqbuf; | 170 delete[] m_freqbuf; |
171 #ifdef HAVE_FFTW3 | |
172 if (m_plan) { | |
173 fftw_destroy_plan(m_plan); | |
174 fftw_free(m_ri); | |
175 fftw_free(m_cbuf); | |
176 m_plan = 0; | |
177 } | |
178 #else | |
133 delete[] m_ri; | 179 delete[] m_ri; |
134 delete[] m_ro; | 180 delete[] m_ro; |
135 delete[] m_io; | 181 delete[] m_io; |
136 } | 182 #endif |
137 } | 183 delete[] m_window; |
184 } | |
185 } | |
186 | |
187 // for some visual studii apparently | |
188 #ifndef M_PI | |
189 #define M_PI 3.14159265358979232846 | |
190 #endif | |
138 | 191 |
139 bool | 192 bool |
140 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) | 193 PluginInputDomainAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize) |
141 { | 194 { |
142 if (m_plugin->getInputDomain() == TimeDomain) { | 195 if (m_plugin->getInputDomain() == TimeDomain) { |
143 | 196 |
144 m_blockSize = blockSize; | 197 m_blockSize = int(blockSize); |
145 m_channels = channels; | 198 m_channels = int(channels); |
146 | 199 |
147 return m_plugin->initialise(channels, stepSize, blockSize); | 200 return m_plugin->initialise(channels, stepSize, blockSize); |
148 } | 201 } |
149 | 202 |
150 if (blockSize < 2) { | 203 if (blockSize < 2) { |
156 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; | 209 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl; |
157 return false; | 210 return false; |
158 } | 211 } |
159 | 212 |
160 if (m_channels > 0) { | 213 if (m_channels > 0) { |
161 for (size_t c = 0; c < m_channels; ++c) { | 214 for (int c = 0; c < m_channels; ++c) { |
162 delete[] m_freqbuf[c]; | 215 delete[] m_freqbuf[c]; |
163 } | 216 } |
164 delete[] m_freqbuf; | 217 delete[] m_freqbuf; |
218 #ifdef HAVE_FFTW3 | |
219 if (m_plan) { | |
220 fftw_destroy_plan(m_plan); | |
221 fftw_free(m_ri); | |
222 fftw_free(m_cbuf); | |
223 m_plan = 0; | |
224 } | |
225 #else | |
165 delete[] m_ri; | 226 delete[] m_ri; |
166 delete[] m_ro; | 227 delete[] m_ro; |
167 delete[] m_io; | 228 delete[] m_io; |
168 } | 229 #endif |
169 | 230 delete[] m_window; |
170 m_blockSize = blockSize; | 231 } |
171 m_channels = channels; | 232 |
233 m_blockSize = int(blockSize); | |
234 m_channels = int(channels); | |
172 | 235 |
173 m_freqbuf = new float *[m_channels]; | 236 m_freqbuf = new float *[m_channels]; |
174 for (size_t c = 0; c < m_channels; ++c) { | 237 for (int c = 0; c < m_channels; ++c) { |
175 m_freqbuf[c] = new float[m_blockSize + 2]; | 238 m_freqbuf[c] = new float[m_blockSize + 2]; |
176 } | 239 } |
240 m_window = new double[m_blockSize]; | |
241 | |
242 for (int i = 0; i < m_blockSize; ++i) { | |
243 // Hanning window | |
244 m_window[i] = (0.50 - 0.50 * cos((2.0 * M_PI * i) / m_blockSize)); | |
245 } | |
246 | |
247 #ifdef HAVE_FFTW3 | |
248 m_ri = (double *)fftw_malloc(blockSize * sizeof(double)); | |
249 m_cbuf = (fftw_complex *)fftw_malloc((blockSize/2 + 1) * sizeof(fftw_complex)); | |
250 m_plan = fftw_plan_dft_r2c_1d(blockSize, m_ri, m_cbuf, FFTW_MEASURE); | |
251 #else | |
177 m_ri = new double[m_blockSize]; | 252 m_ri = new double[m_blockSize]; |
178 m_ro = new double[m_blockSize]; | 253 m_ro = new double[m_blockSize]; |
179 m_io = new double[m_blockSize]; | 254 m_io = new double[m_blockSize]; |
255 #endif | |
180 | 256 |
181 return m_plugin->initialise(channels, stepSize, blockSize); | 257 return m_plugin->initialise(channels, stepSize, blockSize); |
182 } | 258 } |
183 | 259 |
184 size_t | 260 size_t |
218 << "supported, increasing from " << blockSize << " to 2" << std::endl; | 294 << "supported, increasing from " << blockSize << " to 2" << std::endl; |
219 blockSize = 2; | 295 blockSize = 2; |
220 | 296 |
221 } else if (blockSize & (blockSize-1)) { | 297 } else if (blockSize & (blockSize-1)) { |
222 | 298 |
223 // not a power of two, can't handle that with our current fft | 299 #ifdef HAVE_FFTW3 |
300 // not an issue with FFTW | |
301 #else | |
302 | |
303 // not a power of two, can't handle that with our built-in FFT | |
224 // implementation | 304 // implementation |
225 | 305 |
226 size_t nearest = blockSize; | 306 size_t nearest = blockSize; |
227 size_t power = 0; | 307 size_t power = 0; |
228 while (nearest > 1) { | 308 while (nearest > 1) { |
239 nearest = nearest*2; | 319 nearest = nearest*2; |
240 } | 320 } |
241 | 321 |
242 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; | 322 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::Impl::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl; |
243 blockSize = nearest; | 323 blockSize = nearest; |
324 | |
325 #endif | |
244 } | 326 } |
245 | 327 |
246 return blockSize; | 328 return blockSize; |
247 } | 329 } |
248 | |
249 // for some visual studii apparently | |
250 #ifndef M_PI | |
251 #define M_PI 3.14159265358979232846 | |
252 #endif | |
253 | 330 |
254 Plugin::FeatureSet | 331 Plugin::FeatureSet |
255 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, | 332 PluginInputDomainAdapter::Impl::process(const float *const *inputBuffers, |
256 RealTime timestamp) | 333 RealTime timestamp) |
257 { | 334 { |
306 timestamp = timestamp + RealTime::frame2RealTime | 383 timestamp = timestamp + RealTime::frame2RealTime |
307 (m_blockSize/2, int(m_inputSampleRate + 0.5)); | 384 (m_blockSize/2, int(m_inputSampleRate + 0.5)); |
308 | 385 |
309 // std::cerr << " to " << timestamp << std::endl; | 386 // std::cerr << " to " << timestamp << std::endl; |
310 | 387 |
311 for (size_t c = 0; c < m_channels; ++c) { | 388 for (int c = 0; c < m_channels; ++c) { |
312 | 389 |
313 for (size_t i = 0; i < m_blockSize; ++i) { | 390 for (int i = 0; i < m_blockSize; ++i) { |
314 // Hanning window | 391 m_ri[i] = double(inputBuffers[c][i]) * m_window[i]; |
315 m_ri[i] = double(inputBuffers[c][i]) | 392 } |
316 * (0.50 - 0.50 * cos((2 * M_PI * i) | 393 |
317 / m_blockSize)); | 394 for (int i = 0; i < m_blockSize/2; ++i) { |
318 } | |
319 | |
320 for (size_t i = 0; i < m_blockSize/2; ++i) { | |
321 // FFT shift | 395 // FFT shift |
322 double value = m_ri[i]; | 396 double value = m_ri[i]; |
323 m_ri[i] = m_ri[i + m_blockSize/2]; | 397 m_ri[i] = m_ri[i + m_blockSize/2]; |
324 m_ri[i + m_blockSize/2] = value; | 398 m_ri[i + m_blockSize/2] = value; |
325 } | 399 } |
326 | 400 |
401 #ifdef HAVE_FFTW3 | |
402 | |
403 fftw_execute(m_plan); | |
404 | |
405 for (int i = 0; i <= m_blockSize/2; ++i) { | |
406 m_freqbuf[c][i * 2] = float(m_cbuf[i][0]); | |
407 m_freqbuf[c][i * 2 + 1] = float(m_cbuf[i][1]); | |
408 } | |
409 | |
410 #else | |
411 | |
327 fft(m_blockSize, false, m_ri, 0, m_ro, m_io); | 412 fft(m_blockSize, false, m_ri, 0, m_ro, m_io); |
328 | 413 |
329 for (size_t i = 0; i <= m_blockSize/2; ++i) { | 414 for (int i = 0; i <= m_blockSize/2; ++i) { |
330 m_freqbuf[c][i * 2] = m_ro[i]; | 415 m_freqbuf[c][i * 2] = float(m_ro[i]); |
331 m_freqbuf[c][i * 2 + 1] = m_io[i]; | 416 m_freqbuf[c][i * 2 + 1] = float(m_io[i]); |
332 } | 417 } |
418 | |
419 #endif | |
333 } | 420 } |
334 | 421 |
335 return m_plugin->process(m_freqbuf, timestamp); | 422 return m_plugin->process(m_freqbuf, timestamp); |
336 } | 423 } |
424 | |
425 #ifndef HAVE_FFTW3 | |
337 | 426 |
338 void | 427 void |
339 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse, | 428 PluginInputDomainAdapter::Impl::fft(unsigned int n, bool inverse, |
340 double *ri, double *ii, double *ro, double *io) | 429 double *ri, double *ii, double *ro, double *io) |
341 { | 430 { |
450 io[i] /= denom; | 539 io[i] /= denom; |
451 } | 540 } |
452 } | 541 } |
453 } | 542 } |
454 | 543 |
544 #endif | |
545 | |
455 } | 546 } |
456 | 547 |
457 } | 548 } |
458 | 549 |