cannam@227
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@227
|
2
|
cannam@227
|
3 /*
|
cannam@227
|
4 Vamp
|
cannam@227
|
5
|
cannam@227
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@227
|
7
|
cannam@227
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@227
|
9 Copyright 2006-2007 Chris Cannam and QMUL.
|
cannam@227
|
10 This file by Mark Levy and Chris Cannam, Copyright 2007-2008 QMUL.
|
cannam@227
|
11
|
cannam@227
|
12 Permission is hereby granted, free of charge, to any person
|
cannam@227
|
13 obtaining a copy of this software and associated documentation
|
cannam@227
|
14 files (the "Software"), to deal in the Software without
|
cannam@227
|
15 restriction, including without limitation the rights to use, copy,
|
cannam@227
|
16 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@227
|
17 of the Software, and to permit persons to whom the Software is
|
cannam@227
|
18 furnished to do so, subject to the following conditions:
|
cannam@227
|
19
|
cannam@227
|
20 The above copyright notice and this permission notice shall be
|
cannam@227
|
21 included in all copies or substantial portions of the Software.
|
cannam@227
|
22
|
cannam@227
|
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@227
|
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@227
|
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@227
|
26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@227
|
27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@227
|
28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@227
|
29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@227
|
30
|
cannam@227
|
31 Except as contained in this notice, the names of the Centre for
|
cannam@227
|
32 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@227
|
33 shall not be used in advertising or otherwise to promote the sale,
|
cannam@227
|
34 use or other dealings in this Software without prior written
|
cannam@227
|
35 authorization.
|
cannam@227
|
36 */
|
cannam@227
|
37
|
cannam@227
|
38 #include <vector>
|
cannam@227
|
39 #include <map>
|
cannam@227
|
40
|
cannam@227
|
41 #include "PluginBufferingAdapter.h"
|
cannam@227
|
42
|
cannam@227
|
43 using std::vector;
|
cannam@227
|
44 using std::map;
|
cannam@227
|
45
|
cannam@227
|
46 namespace Vamp {
|
cannam@227
|
47
|
cannam@227
|
48 namespace HostExt {
|
cannam@227
|
49
|
cannam@227
|
50 class PluginBufferingAdapter::Impl
|
cannam@227
|
51 {
|
cannam@227
|
52 public:
|
cannam@227
|
53 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@227
|
54 ~Impl();
|
cannam@227
|
55
|
cannam@227
|
56 void setPluginStepSize(size_t stepSize);
|
cannam@227
|
57 void setPluginBlockSize(size_t blockSize);
|
cannam@227
|
58
|
cannam@227
|
59 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@227
|
60
|
cannam@227
|
61 void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
|
cannam@227
|
62
|
cannam@227
|
63 OutputList getOutputDescriptors() const;
|
cannam@227
|
64
|
cannam@227
|
65 void reset();
|
cannam@227
|
66
|
cannam@227
|
67 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@227
|
68
|
cannam@227
|
69 FeatureSet getRemainingFeatures();
|
cannam@227
|
70
|
cannam@227
|
71 protected:
|
cannam@227
|
72 class RingBuffer
|
cannam@227
|
73 {
|
cannam@227
|
74 public:
|
cannam@227
|
75 RingBuffer(int n) :
|
cannam@227
|
76 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
|
cannam@227
|
77 virtual ~RingBuffer() { delete[] m_buffer; }
|
cannam@227
|
78
|
cannam@227
|
79 int getSize() const { return m_size-1; }
|
cannam@227
|
80 void reset() { m_writer = 0; m_reader = 0; }
|
cannam@227
|
81
|
cannam@227
|
82 int getReadSpace() const {
|
cannam@227
|
83 int writer = m_writer, reader = m_reader, space;
|
cannam@227
|
84 if (writer > reader) space = writer - reader;
|
cannam@227
|
85 else if (writer < reader) space = (writer + m_size) - reader;
|
cannam@227
|
86 else space = 0;
|
cannam@227
|
87 return space;
|
cannam@227
|
88 }
|
cannam@227
|
89
|
cannam@227
|
90 int getWriteSpace() const {
|
cannam@227
|
91 int writer = m_writer;
|
cannam@227
|
92 int reader = m_reader;
|
cannam@227
|
93 int space = (reader + m_size - writer - 1);
|
cannam@227
|
94 if (space >= m_size) space -= m_size;
|
cannam@227
|
95 return space;
|
cannam@227
|
96 }
|
cannam@227
|
97
|
cannam@227
|
98 int peek(float *destination, int n) const {
|
cannam@227
|
99
|
cannam@227
|
100 int available = getReadSpace();
|
cannam@227
|
101
|
cannam@227
|
102 if (n > available) {
|
cannam@227
|
103 for (int i = available; i < n; ++i) {
|
cannam@227
|
104 destination[i] = 0.f;
|
cannam@227
|
105 }
|
cannam@227
|
106 n = available;
|
cannam@227
|
107 }
|
cannam@227
|
108 if (n == 0) return n;
|
cannam@227
|
109
|
cannam@227
|
110 int reader = m_reader;
|
cannam@227
|
111 int here = m_size - reader;
|
cannam@227
|
112 const float *const bufbase = m_buffer + reader;
|
cannam@227
|
113
|
cannam@227
|
114 if (here >= n) {
|
cannam@227
|
115 for (int i = 0; i < n; ++i) {
|
cannam@227
|
116 destination[i] = bufbase[i];
|
cannam@227
|
117 }
|
cannam@227
|
118 } else {
|
cannam@227
|
119 for (int i = 0; i < here; ++i) {
|
cannam@227
|
120 destination[i] = bufbase[i];
|
cannam@227
|
121 }
|
cannam@227
|
122 float *const destbase = destination + here;
|
cannam@227
|
123 const int nh = n - here;
|
cannam@227
|
124 for (int i = 0; i < nh; ++i) {
|
cannam@227
|
125 destbase[i] = m_buffer[i];
|
cannam@227
|
126 }
|
cannam@227
|
127 }
|
cannam@227
|
128
|
cannam@227
|
129 return n;
|
cannam@227
|
130 }
|
cannam@227
|
131
|
cannam@227
|
132 int skip(int n) {
|
cannam@227
|
133
|
cannam@227
|
134 int available = getReadSpace();
|
cannam@227
|
135 if (n > available) {
|
cannam@227
|
136 n = available;
|
cannam@227
|
137 }
|
cannam@227
|
138 if (n == 0) return n;
|
cannam@227
|
139
|
cannam@227
|
140 int reader = m_reader;
|
cannam@227
|
141 reader += n;
|
cannam@227
|
142 while (reader >= m_size) reader -= m_size;
|
cannam@227
|
143 m_reader = reader;
|
cannam@227
|
144 return n;
|
cannam@227
|
145 }
|
cannam@227
|
146
|
cannam@227
|
147 int write(const float *source, int n) {
|
cannam@227
|
148
|
cannam@227
|
149 int available = getWriteSpace();
|
cannam@227
|
150 if (n > available) {
|
cannam@227
|
151 n = available;
|
cannam@227
|
152 }
|
cannam@227
|
153 if (n == 0) return n;
|
cannam@227
|
154
|
cannam@227
|
155 int writer = m_writer;
|
cannam@227
|
156 int here = m_size - writer;
|
cannam@227
|
157 float *const bufbase = m_buffer + writer;
|
cannam@227
|
158
|
cannam@227
|
159 if (here >= n) {
|
cannam@227
|
160 for (int i = 0; i < n; ++i) {
|
cannam@227
|
161 bufbase[i] = source[i];
|
cannam@227
|
162 }
|
cannam@227
|
163 } else {
|
cannam@227
|
164 for (int i = 0; i < here; ++i) {
|
cannam@227
|
165 bufbase[i] = source[i];
|
cannam@227
|
166 }
|
cannam@227
|
167 const int nh = n - here;
|
cannam@227
|
168 const float *const srcbase = source + here;
|
cannam@227
|
169 float *const buf = m_buffer;
|
cannam@227
|
170 for (int i = 0; i < nh; ++i) {
|
cannam@227
|
171 buf[i] = srcbase[i];
|
cannam@227
|
172 }
|
cannam@227
|
173 }
|
cannam@227
|
174
|
cannam@227
|
175 writer += n;
|
cannam@227
|
176 while (writer >= m_size) writer -= m_size;
|
cannam@227
|
177 m_writer = writer;
|
cannam@227
|
178
|
cannam@227
|
179 return n;
|
cannam@227
|
180 }
|
cannam@227
|
181
|
cannam@227
|
182 int zero(int n) {
|
cannam@227
|
183
|
cannam@227
|
184 int available = getWriteSpace();
|
cannam@227
|
185 if (n > available) {
|
cannam@227
|
186 n = available;
|
cannam@227
|
187 }
|
cannam@227
|
188 if (n == 0) return n;
|
cannam@227
|
189
|
cannam@227
|
190 int writer = m_writer;
|
cannam@227
|
191 int here = m_size - writer;
|
cannam@227
|
192 float *const bufbase = m_buffer + writer;
|
cannam@227
|
193
|
cannam@227
|
194 if (here >= n) {
|
cannam@227
|
195 for (int i = 0; i < n; ++i) {
|
cannam@227
|
196 bufbase[i] = 0.f;
|
cannam@227
|
197 }
|
cannam@227
|
198 } else {
|
cannam@227
|
199 for (int i = 0; i < here; ++i) {
|
cannam@227
|
200 bufbase[i] = 0.f;
|
cannam@227
|
201 }
|
cannam@227
|
202 const int nh = n - here;
|
cannam@227
|
203 for (int i = 0; i < nh; ++i) {
|
cannam@227
|
204 m_buffer[i] = 0.f;
|
cannam@227
|
205 }
|
cannam@227
|
206 }
|
cannam@227
|
207
|
cannam@227
|
208 writer += n;
|
cannam@227
|
209 while (writer >= m_size) writer -= m_size;
|
cannam@227
|
210 m_writer = writer;
|
cannam@227
|
211
|
cannam@227
|
212 return n;
|
cannam@227
|
213 }
|
cannam@227
|
214
|
cannam@227
|
215 protected:
|
cannam@227
|
216 float *m_buffer;
|
cannam@227
|
217 int m_writer;
|
cannam@227
|
218 int m_reader;
|
cannam@227
|
219 int m_size;
|
cannam@227
|
220
|
cannam@227
|
221 private:
|
cannam@227
|
222 RingBuffer(const RingBuffer &); // not provided
|
cannam@227
|
223 RingBuffer &operator=(const RingBuffer &); // not provided
|
cannam@227
|
224 };
|
cannam@227
|
225
|
cannam@227
|
226 Plugin *m_plugin;
|
cannam@227
|
227 size_t m_inputStepSize; // value passed to wrapper initialise()
|
cannam@227
|
228 size_t m_inputBlockSize; // value passed to wrapper initialise()
|
cannam@227
|
229 size_t m_setStepSize; // value passed to setPluginStepSize()
|
cannam@227
|
230 size_t m_setBlockSize; // value passed to setPluginBlockSize()
|
cannam@227
|
231 size_t m_stepSize; // value actually used to initialise plugin
|
cannam@227
|
232 size_t m_blockSize; // value actually used to initialise plugin
|
cannam@227
|
233 size_t m_channels;
|
cannam@227
|
234 vector<RingBuffer *> m_queue;
|
cannam@227
|
235 float **m_buffers;
|
cannam@227
|
236 float m_inputSampleRate;
|
cannam@227
|
237 long m_frame;
|
cannam@227
|
238 bool m_unrun;
|
cannam@227
|
239 mutable OutputList m_outputs;
|
cannam@227
|
240 mutable std::map<int, bool> m_rewriteOutputTimes;
|
cannam@227
|
241
|
cannam@227
|
242 void processBlock(FeatureSet& allFeatureSets);
|
cannam@227
|
243 };
|
cannam@227
|
244
|
cannam@227
|
245 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
|
cannam@227
|
246 PluginWrapper(plugin)
|
cannam@227
|
247 {
|
cannam@227
|
248 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@227
|
249 }
|
cannam@227
|
250
|
cannam@227
|
251 PluginBufferingAdapter::~PluginBufferingAdapter()
|
cannam@227
|
252 {
|
cannam@227
|
253 delete m_impl;
|
cannam@227
|
254 }
|
cannam@227
|
255
|
cannam@227
|
256 size_t
|
cannam@227
|
257 PluginBufferingAdapter::getPreferredStepSize() const
|
cannam@227
|
258 {
|
cannam@227
|
259 return getPreferredBlockSize();
|
cannam@227
|
260 }
|
cannam@227
|
261
|
cannam@227
|
262 size_t
|
cannam@227
|
263 PluginBufferingAdapter::getPreferredBlockSize() const
|
cannam@227
|
264 {
|
cannam@227
|
265 return PluginWrapper::getPreferredBlockSize();
|
cannam@227
|
266 }
|
cannam@227
|
267
|
cannam@227
|
268 size_t
|
cannam@227
|
269 PluginBufferingAdapter::getPluginPreferredStepSize() const
|
cannam@227
|
270 {
|
cannam@227
|
271 return PluginWrapper::getPreferredStepSize();
|
cannam@227
|
272 }
|
cannam@227
|
273
|
cannam@227
|
274 size_t
|
cannam@227
|
275 PluginBufferingAdapter::getPluginPreferredBlockSize() const
|
cannam@227
|
276 {
|
cannam@227
|
277 return PluginWrapper::getPreferredBlockSize();
|
cannam@227
|
278 }
|
cannam@227
|
279
|
cannam@227
|
280 void
|
cannam@227
|
281 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
|
cannam@227
|
282 {
|
cannam@227
|
283 m_impl->setPluginStepSize(stepSize);
|
cannam@227
|
284 }
|
cannam@227
|
285
|
cannam@227
|
286 void
|
cannam@227
|
287 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
|
cannam@227
|
288 {
|
cannam@227
|
289 m_impl->setPluginBlockSize(blockSize);
|
cannam@227
|
290 }
|
cannam@227
|
291
|
cannam@227
|
292 void
|
cannam@227
|
293 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
|
cannam@227
|
294 size_t &blockSize)
|
cannam@227
|
295 {
|
cannam@227
|
296 m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
|
cannam@227
|
297 }
|
cannam@227
|
298
|
cannam@227
|
299 bool
|
cannam@227
|
300 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@227
|
301 {
|
cannam@227
|
302 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@227
|
303 }
|
cannam@227
|
304
|
cannam@227
|
305 PluginBufferingAdapter::OutputList
|
cannam@227
|
306 PluginBufferingAdapter::getOutputDescriptors() const
|
cannam@227
|
307 {
|
cannam@227
|
308 return m_impl->getOutputDescriptors();
|
cannam@227
|
309 }
|
cannam@227
|
310
|
cannam@227
|
311 void
|
cannam@227
|
312 PluginBufferingAdapter::reset()
|
cannam@227
|
313 {
|
cannam@227
|
314 m_impl->reset();
|
cannam@227
|
315 }
|
cannam@227
|
316
|
cannam@227
|
317 PluginBufferingAdapter::FeatureSet
|
cannam@227
|
318 PluginBufferingAdapter::process(const float *const *inputBuffers,
|
cannam@227
|
319 RealTime timestamp)
|
cannam@227
|
320 {
|
cannam@227
|
321 return m_impl->process(inputBuffers, timestamp);
|
cannam@227
|
322 }
|
cannam@227
|
323
|
cannam@227
|
324 PluginBufferingAdapter::FeatureSet
|
cannam@227
|
325 PluginBufferingAdapter::getRemainingFeatures()
|
cannam@227
|
326 {
|
cannam@227
|
327 return m_impl->getRemainingFeatures();
|
cannam@227
|
328 }
|
cannam@227
|
329
|
cannam@227
|
330 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@227
|
331 m_plugin(plugin),
|
cannam@227
|
332 m_inputStepSize(0),
|
cannam@227
|
333 m_inputBlockSize(0),
|
cannam@227
|
334 m_setStepSize(0),
|
cannam@227
|
335 m_setBlockSize(0),
|
cannam@227
|
336 m_stepSize(0),
|
cannam@227
|
337 m_blockSize(0),
|
cannam@227
|
338 m_channels(0),
|
cannam@227
|
339 m_queue(0),
|
cannam@227
|
340 m_buffers(0),
|
cannam@227
|
341 m_inputSampleRate(inputSampleRate),
|
cannam@227
|
342 m_frame(0),
|
cannam@227
|
343 m_unrun(true)
|
cannam@227
|
344 {
|
cannam@227
|
345 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
|
cannam@227
|
346 }
|
cannam@227
|
347
|
cannam@227
|
348 PluginBufferingAdapter::Impl::~Impl()
|
cannam@227
|
349 {
|
cannam@227
|
350 // the adapter will delete the plugin
|
cannam@227
|
351
|
cannam@227
|
352 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
353 delete m_queue[i];
|
cannam@227
|
354 delete[] m_buffers[i];
|
cannam@227
|
355 }
|
cannam@227
|
356 delete[] m_buffers;
|
cannam@227
|
357 }
|
cannam@227
|
358
|
cannam@227
|
359 void
|
cannam@227
|
360 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
|
cannam@227
|
361 {
|
cannam@227
|
362 if (m_inputStepSize != 0) {
|
cannam@227
|
363 std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
|
cannam@227
|
364 return;
|
cannam@227
|
365 }
|
cannam@227
|
366 m_setStepSize = stepSize;
|
cannam@227
|
367 }
|
cannam@227
|
368
|
cannam@227
|
369 void
|
cannam@227
|
370 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
|
cannam@227
|
371 {
|
cannam@227
|
372 if (m_inputBlockSize != 0) {
|
cannam@227
|
373 std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
|
cannam@227
|
374 return;
|
cannam@227
|
375 }
|
cannam@227
|
376 m_setBlockSize = blockSize;
|
cannam@227
|
377 }
|
cannam@227
|
378
|
cannam@227
|
379 void
|
cannam@227
|
380 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
|
cannam@227
|
381 size_t &blockSize)
|
cannam@227
|
382 {
|
cannam@227
|
383 stepSize = m_stepSize;
|
cannam@227
|
384 blockSize = m_blockSize;
|
cannam@227
|
385 }
|
cannam@227
|
386
|
cannam@227
|
387 bool
|
cannam@227
|
388 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@227
|
389 {
|
cannam@227
|
390 if (stepSize != blockSize) {
|
cannam@227
|
391 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
|
cannam@227
|
392 return false;
|
cannam@227
|
393 }
|
cannam@227
|
394
|
cannam@227
|
395 m_channels = channels;
|
cannam@227
|
396 m_inputStepSize = stepSize;
|
cannam@227
|
397 m_inputBlockSize = blockSize;
|
cannam@227
|
398
|
cannam@227
|
399 // if the user has requested particular step or block sizes, use
|
cannam@227
|
400 // those; otherwise use the step and block sizes which the plugin
|
cannam@227
|
401 // prefers
|
cannam@227
|
402
|
cannam@227
|
403 m_stepSize = 0;
|
cannam@227
|
404 m_blockSize = 0;
|
cannam@227
|
405
|
cannam@227
|
406 if (m_setStepSize > 0) {
|
cannam@227
|
407 m_stepSize = m_setStepSize;
|
cannam@227
|
408 }
|
cannam@227
|
409 if (m_setBlockSize > 0) {
|
cannam@227
|
410 m_blockSize = m_setBlockSize;
|
cannam@227
|
411 }
|
cannam@227
|
412
|
cannam@227
|
413 if (m_stepSize == 0 && m_blockSize == 0) {
|
cannam@227
|
414 m_stepSize = m_plugin->getPreferredStepSize();
|
cannam@227
|
415 m_blockSize = m_plugin->getPreferredBlockSize();
|
cannam@227
|
416 }
|
cannam@227
|
417
|
cannam@227
|
418 bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
|
cannam@227
|
419
|
cannam@227
|
420 // or sensible defaults if it has no preference
|
cannam@227
|
421 if (m_blockSize == 0) {
|
cannam@227
|
422 if (m_stepSize == 0) {
|
cannam@227
|
423 m_blockSize = 1024;
|
cannam@227
|
424 } else if (freq) {
|
cannam@227
|
425 m_blockSize = m_stepSize * 2;
|
cannam@227
|
426 } else {
|
cannam@227
|
427 m_blockSize = m_stepSize;
|
cannam@227
|
428 }
|
cannam@227
|
429 } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
|
cannam@227
|
430 if (freq) {
|
cannam@227
|
431 m_stepSize = m_blockSize/2;
|
cannam@227
|
432 } else {
|
cannam@227
|
433 m_stepSize = m_blockSize;
|
cannam@227
|
434 }
|
cannam@227
|
435 }
|
cannam@227
|
436
|
cannam@227
|
437 // current implementation breaks if step is greater than block
|
cannam@227
|
438 if (m_stepSize > m_blockSize) {
|
cannam@227
|
439 size_t newBlockSize;
|
cannam@227
|
440 if (freq) {
|
cannam@227
|
441 newBlockSize = m_stepSize * 2;
|
cannam@227
|
442 } else {
|
cannam@227
|
443 newBlockSize = m_stepSize;
|
cannam@227
|
444 }
|
cannam@227
|
445 std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
|
cannam@227
|
446 m_blockSize = newBlockSize;
|
cannam@227
|
447 }
|
cannam@227
|
448
|
cannam@227
|
449 std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
|
cannam@227
|
450 << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
|
cannam@227
|
451
|
cannam@227
|
452 m_buffers = new float *[m_channels];
|
cannam@227
|
453
|
cannam@227
|
454 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
455 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
|
cannam@227
|
456 m_buffers[i] = new float[m_blockSize];
|
cannam@227
|
457 }
|
cannam@227
|
458
|
cannam@227
|
459 return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
|
cannam@227
|
460 }
|
cannam@227
|
461
|
cannam@227
|
462 PluginBufferingAdapter::OutputList
|
cannam@227
|
463 PluginBufferingAdapter::Impl::getOutputDescriptors() const
|
cannam@227
|
464 {
|
cannam@227
|
465 if (m_outputs.empty()) {
|
cannam@227
|
466 m_outputs = m_plugin->getOutputDescriptors();
|
cannam@227
|
467 }
|
cannam@227
|
468
|
cannam@227
|
469 PluginBufferingAdapter::OutputList outs = m_outputs;
|
cannam@227
|
470
|
cannam@227
|
471 for (size_t i = 0; i < outs.size(); ++i) {
|
cannam@227
|
472
|
cannam@227
|
473 switch (outs[i].sampleType) {
|
cannam@227
|
474
|
cannam@227
|
475 case OutputDescriptor::OneSamplePerStep:
|
cannam@227
|
476 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
|
cannam@227
|
477 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
|
cannam@227
|
478 m_rewriteOutputTimes[i] = true;
|
cannam@227
|
479 break;
|
cannam@227
|
480
|
cannam@227
|
481 case OutputDescriptor::FixedSampleRate:
|
cannam@227
|
482 if (outs[i].sampleRate == 0.f) {
|
cannam@227
|
483 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
|
cannam@227
|
484 }
|
cannam@227
|
485 // We actually only need to rewrite output times for
|
cannam@227
|
486 // features that don't have timestamps already, but we
|
cannam@227
|
487 // can't tell from here whether our features will have
|
cannam@227
|
488 // timestamps or not
|
cannam@227
|
489 m_rewriteOutputTimes[i] = true;
|
cannam@227
|
490 break;
|
cannam@227
|
491
|
cannam@227
|
492 case OutputDescriptor::VariableSampleRate:
|
cannam@227
|
493 m_rewriteOutputTimes[i] = false;
|
cannam@227
|
494 break;
|
cannam@227
|
495 }
|
cannam@227
|
496 }
|
cannam@227
|
497
|
cannam@227
|
498 return outs;
|
cannam@227
|
499 }
|
cannam@227
|
500
|
cannam@227
|
501 void
|
cannam@227
|
502 PluginBufferingAdapter::Impl::reset()
|
cannam@227
|
503 {
|
cannam@227
|
504 m_frame = 0;
|
cannam@227
|
505 m_unrun = true;
|
cannam@227
|
506
|
cannam@227
|
507 for (size_t i = 0; i < m_queue.size(); ++i) {
|
cannam@227
|
508 m_queue[i]->reset();
|
cannam@227
|
509 }
|
cannam@227
|
510
|
cannam@227
|
511 m_plugin->reset();
|
cannam@227
|
512 }
|
cannam@227
|
513
|
cannam@227
|
514 PluginBufferingAdapter::FeatureSet
|
cannam@227
|
515 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@227
|
516 RealTime timestamp)
|
cannam@227
|
517 {
|
cannam@227
|
518 if (m_inputStepSize == 0) {
|
cannam@227
|
519 std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
|
cannam@227
|
520 return FeatureSet();
|
cannam@227
|
521 }
|
cannam@227
|
522
|
cannam@227
|
523 FeatureSet allFeatureSets;
|
cannam@227
|
524
|
cannam@227
|
525 if (m_unrun) {
|
cannam@227
|
526 m_frame = RealTime::realTime2Frame(timestamp,
|
cannam@227
|
527 int(m_inputSampleRate + 0.5));
|
cannam@227
|
528 m_unrun = false;
|
cannam@227
|
529 }
|
cannam@227
|
530
|
cannam@227
|
531 // queue the new input
|
cannam@227
|
532
|
cannam@227
|
533 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
534 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
|
cannam@227
|
535 if (written < int(m_inputBlockSize) && i == 0) {
|
cannam@227
|
536 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
|
cannam@227
|
537 << "Buffer overflow: wrote " << written
|
cannam@227
|
538 << " of " << m_inputBlockSize
|
cannam@227
|
539 << " input samples (for plugin step size "
|
cannam@227
|
540 << m_stepSize << ", block size " << m_blockSize << ")"
|
cannam@227
|
541 << std::endl;
|
cannam@227
|
542 }
|
cannam@227
|
543 }
|
cannam@227
|
544
|
cannam@227
|
545 // process as much as we can
|
cannam@227
|
546
|
cannam@227
|
547 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@227
|
548 processBlock(allFeatureSets);
|
cannam@227
|
549 }
|
cannam@227
|
550
|
cannam@227
|
551 return allFeatureSets;
|
cannam@227
|
552 }
|
cannam@227
|
553
|
cannam@227
|
554 PluginBufferingAdapter::FeatureSet
|
cannam@227
|
555 PluginBufferingAdapter::Impl::getRemainingFeatures()
|
cannam@227
|
556 {
|
cannam@227
|
557 FeatureSet allFeatureSets;
|
cannam@227
|
558
|
cannam@227
|
559 // process remaining samples in queue
|
cannam@227
|
560 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@227
|
561 processBlock(allFeatureSets);
|
cannam@227
|
562 }
|
cannam@227
|
563
|
cannam@227
|
564 // pad any last samples remaining and process
|
cannam@227
|
565 if (m_queue[0]->getReadSpace() > 0) {
|
cannam@227
|
566 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
567 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
|
cannam@227
|
568 }
|
cannam@227
|
569 processBlock(allFeatureSets);
|
cannam@227
|
570 }
|
cannam@227
|
571
|
cannam@227
|
572 // get remaining features
|
cannam@227
|
573
|
cannam@227
|
574 FeatureSet featureSet = m_plugin->getRemainingFeatures();
|
cannam@227
|
575
|
cannam@227
|
576 for (map<int, FeatureList>::iterator iter = featureSet.begin();
|
cannam@227
|
577 iter != featureSet.end(); ++iter) {
|
cannam@227
|
578 FeatureList featureList = iter->second;
|
cannam@227
|
579 for (size_t i = 0; i < featureList.size(); ++i) {
|
cannam@227
|
580 allFeatureSets[iter->first].push_back(featureList[i]);
|
cannam@227
|
581 }
|
cannam@227
|
582 }
|
cannam@227
|
583
|
cannam@227
|
584 return allFeatureSets;
|
cannam@227
|
585 }
|
cannam@227
|
586
|
cannam@227
|
587 void
|
cannam@227
|
588 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
|
cannam@227
|
589 {
|
cannam@227
|
590 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
591 m_queue[i]->peek(m_buffers[i], m_blockSize);
|
cannam@227
|
592 }
|
cannam@227
|
593
|
cannam@227
|
594 long frame = m_frame;
|
cannam@227
|
595 RealTime timestamp = RealTime::frame2RealTime
|
cannam@227
|
596 (frame, int(m_inputSampleRate + 0.5));
|
cannam@227
|
597
|
cannam@227
|
598 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
|
cannam@227
|
599
|
cannam@227
|
600 for (FeatureSet::iterator iter = featureSet.begin();
|
cannam@227
|
601 iter != featureSet.end(); ++iter) {
|
cannam@227
|
602
|
cannam@227
|
603 int outputNo = iter->first;
|
cannam@227
|
604
|
cannam@227
|
605 if (m_rewriteOutputTimes[outputNo]) {
|
cannam@227
|
606
|
cannam@227
|
607 FeatureList featureList = iter->second;
|
cannam@227
|
608
|
cannam@227
|
609 for (size_t i = 0; i < featureList.size(); ++i) {
|
cannam@227
|
610
|
cannam@227
|
611 switch (m_outputs[outputNo].sampleType) {
|
cannam@227
|
612
|
cannam@227
|
613 case OutputDescriptor::OneSamplePerStep:
|
cannam@227
|
614 // use our internal timestamp, always
|
cannam@227
|
615 featureList[i].timestamp = timestamp;
|
cannam@227
|
616 featureList[i].hasTimestamp = true;
|
cannam@227
|
617 break;
|
cannam@227
|
618
|
cannam@227
|
619 case OutputDescriptor::FixedSampleRate:
|
cannam@227
|
620 // use our internal timestamp if feature lacks one
|
cannam@227
|
621 if (!featureList[i].hasTimestamp) {
|
cannam@227
|
622 featureList[i].timestamp = timestamp;
|
cannam@227
|
623 featureList[i].hasTimestamp = true;
|
cannam@227
|
624 }
|
cannam@227
|
625 break;
|
cannam@227
|
626
|
cannam@227
|
627 case OutputDescriptor::VariableSampleRate:
|
cannam@227
|
628 break; // plugin must set timestamp
|
cannam@227
|
629
|
cannam@227
|
630 default:
|
cannam@227
|
631 break;
|
cannam@227
|
632 }
|
cannam@227
|
633
|
cannam@227
|
634 allFeatureSets[outputNo].push_back(featureList[i]);
|
cannam@227
|
635 }
|
cannam@227
|
636 } else {
|
cannam@227
|
637 for (size_t i = 0; i < iter->second.size(); ++i) {
|
cannam@227
|
638 allFeatureSets[outputNo].push_back(iter->second[i]);
|
cannam@227
|
639 }
|
cannam@227
|
640 }
|
cannam@227
|
641 }
|
cannam@227
|
642
|
cannam@227
|
643 // step forward
|
cannam@227
|
644
|
cannam@227
|
645 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@227
|
646 m_queue[i]->skip(m_stepSize);
|
cannam@227
|
647 }
|
cannam@227
|
648
|
cannam@227
|
649 // increment internal frame counter each time we step forward
|
cannam@227
|
650 m_frame += m_stepSize;
|
cannam@227
|
651 }
|
cannam@227
|
652
|
cannam@227
|
653 }
|
cannam@227
|
654
|
cannam@227
|
655 }
|
cannam@227
|
656
|
cannam@227
|
657
|