comparison src/vamp-hostsdk/PluginBufferingAdapter.cpp @ 233:521734d2b498 distinct-libraries

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