0aa92d9efc5640b66d755bca432712b1623ad100
[ardour.git] / libs / vamp-sdk / src / vamp-hostsdk / PluginBufferingAdapter.cpp
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 _VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.cpp)
47
48 namespace Vamp {
49         
50 namespace HostExt {
51                 
52 class PluginBufferingAdapter::Impl
53 {
54 public:
55     Impl(Plugin *plugin, float inputSampleRate);
56     ~Impl();
57         
58     void setPluginStepSize(size_t stepSize);    
59     void setPluginBlockSize(size_t blockSize);
60
61     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
62
63     void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
64
65     OutputList getOutputDescriptors() const;
66
67     void setParameter(std::string, float);
68     void selectProgram(std::string);
69
70     void reset();
71
72     FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
73                 
74     FeatureSet getRemainingFeatures();
75                 
76 protected:
77     class RingBuffer
78     {
79     public:
80         RingBuffer(int n) :
81             m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
82         virtual ~RingBuffer() { delete[] m_buffer; }
83
84         int getSize() const { return m_size-1; }
85         void reset() { m_writer = 0; m_reader = 0; }
86
87         int getReadSpace() const {
88             int writer = m_writer, reader = m_reader, space;
89             if (writer > reader) space = writer - reader;
90             else if (writer < reader) space = (writer + m_size) - reader;
91             else space = 0;
92             return space;
93         }
94
95         int getWriteSpace() const {
96             int writer = m_writer;
97             int reader = m_reader;
98             int space = (reader + m_size - writer - 1);
99             if (space >= m_size) space -= m_size;
100             return space;
101         }
102         
103         int peek(float *destination, int n) const {
104
105             int available = getReadSpace();
106
107             if (n > available) {
108                 for (int i = available; i < n; ++i) {
109                     destination[i] = 0.f;
110                 }
111                 n = available;
112             }
113             if (n == 0) return n;
114
115             int reader = m_reader;
116             int here = m_size - reader;
117             const float *const bufbase = m_buffer + reader;
118
119             if (here >= n) {
120                 for (int i = 0; i < n; ++i) {
121                     destination[i] = bufbase[i];
122                 }
123             } else {
124                 for (int i = 0; i < here; ++i) {
125                     destination[i] = bufbase[i];
126                 }
127                 float *const destbase = destination + here;
128                 const int nh = n - here;
129                 for (int i = 0; i < nh; ++i) {
130                     destbase[i] = m_buffer[i];
131                 }
132             }
133
134             return n;
135         }
136
137         int skip(int n) {
138             
139             int available = getReadSpace();
140             if (n > available) {
141                 n = available;
142             }
143             if (n == 0) return n;
144
145             int reader = m_reader;
146             reader += n;
147             while (reader >= m_size) reader -= m_size;
148             m_reader = reader;
149             return n;
150         }
151         
152         int write(const float *source, int n) {
153
154             int available = getWriteSpace();
155             if (n > available) {
156                 n = available;
157             }
158             if (n == 0) return n;
159
160             int writer = m_writer;
161             int here = m_size - writer;
162             float *const bufbase = m_buffer + writer;
163             
164             if (here >= n) {
165                 for (int i = 0; i < n; ++i) {
166                     bufbase[i] = source[i];
167                 }
168             } else {
169                 for (int i = 0; i < here; ++i) {
170                     bufbase[i] = source[i];
171                 }
172                 const int nh = n - here;
173                 const float *const srcbase = source + here;
174                 float *const buf = m_buffer;
175                 for (int i = 0; i < nh; ++i) {
176                     buf[i] = srcbase[i];
177                 }
178             }
179
180             writer += n;
181             while (writer >= m_size) writer -= m_size;
182             m_writer = writer;
183
184             return n;
185         }
186
187         int zero(int n) {
188             
189             int available = getWriteSpace();
190             if (n > available) {
191                 n = available;
192             }
193             if (n == 0) return n;
194
195             int writer = m_writer;
196             int here = m_size - writer;
197             float *const bufbase = m_buffer + writer;
198
199             if (here >= n) {
200                 for (int i = 0; i < n; ++i) {
201                     bufbase[i] = 0.f;
202                 }
203             } else {
204                 for (int i = 0; i < here; ++i) {
205                     bufbase[i] = 0.f;
206                 }
207                 const int nh = n - here;
208                 for (int i = 0; i < nh; ++i) {
209                     m_buffer[i] = 0.f;
210                 }
211             }
212             
213             writer += n;
214             while (writer >= m_size) writer -= m_size;
215             m_writer = writer;
216
217             return n;
218         }
219
220     protected:
221         float *m_buffer;
222         int    m_writer;
223         int    m_reader;
224         int    m_size;
225
226     private:
227         RingBuffer(const RingBuffer &); // not provided
228         RingBuffer &operator=(const RingBuffer &); // not provided
229     };
230
231     Plugin *m_plugin;
232     size_t m_inputStepSize;  // value passed to wrapper initialise()
233     size_t m_inputBlockSize; // value passed to wrapper initialise()
234     size_t m_setStepSize;    // value passed to setPluginStepSize()
235     size_t m_setBlockSize;   // value passed to setPluginBlockSize()
236     size_t m_stepSize;       // value actually used to initialise plugin
237     size_t m_blockSize;      // value actually used to initialise plugin
238     size_t m_channels;
239     vector<RingBuffer *> m_queue;
240     float **m_buffers;
241     float m_inputSampleRate;
242     long m_frame;
243     bool m_unrun;
244     mutable OutputList m_outputs;
245     mutable std::map<int, bool> m_rewriteOutputTimes;
246                 
247     void processBlock(FeatureSet& allFeatureSets);
248 };
249                 
250 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
251     PluginWrapper(plugin)
252 {
253     m_impl = new Impl(plugin, m_inputSampleRate);
254 }
255                 
256 PluginBufferingAdapter::~PluginBufferingAdapter()
257 {
258     delete m_impl;
259 }
260
261 size_t
262 PluginBufferingAdapter::getPreferredStepSize() const
263 {
264     return getPreferredBlockSize();
265 }
266
267 size_t
268 PluginBufferingAdapter::getPreferredBlockSize() const
269 {
270     return PluginWrapper::getPreferredBlockSize();
271 }
272
273 size_t
274 PluginBufferingAdapter::getPluginPreferredStepSize() const
275 {
276     return PluginWrapper::getPreferredStepSize();
277 }
278
279 size_t
280 PluginBufferingAdapter::getPluginPreferredBlockSize() const
281 {
282     return PluginWrapper::getPreferredBlockSize();
283 }
284
285 void
286 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
287 {
288     m_impl->setPluginStepSize(stepSize);
289 }
290
291 void
292 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
293 {
294     m_impl->setPluginBlockSize(blockSize);
295 }
296
297 void
298 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
299                                                    size_t &blockSize)
300 {
301     m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
302 }
303                 
304 bool
305 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
306 {
307     return m_impl->initialise(channels, stepSize, blockSize);
308 }
309
310 PluginBufferingAdapter::OutputList
311 PluginBufferingAdapter::getOutputDescriptors() const
312 {
313     return m_impl->getOutputDescriptors();
314 }
315
316 void
317 PluginBufferingAdapter::setParameter(std::string name, float value)
318 {
319     m_impl->setParameter(name, value);
320 }
321
322 void
323 PluginBufferingAdapter::selectProgram(std::string name)
324 {
325     m_impl->selectProgram(name);
326 }
327
328 void
329 PluginBufferingAdapter::reset()
330 {
331     m_impl->reset();
332 }
333                 
334 PluginBufferingAdapter::FeatureSet
335 PluginBufferingAdapter::process(const float *const *inputBuffers,
336                                 RealTime timestamp)
337 {
338     return m_impl->process(inputBuffers, timestamp);
339 }
340                 
341 PluginBufferingAdapter::FeatureSet
342 PluginBufferingAdapter::getRemainingFeatures()
343 {
344     return m_impl->getRemainingFeatures();
345 }
346                 
347 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
348     m_plugin(plugin),
349     m_inputStepSize(0),
350     m_inputBlockSize(0),
351     m_setStepSize(0),
352     m_setBlockSize(0),
353     m_stepSize(0),
354     m_blockSize(0),
355     m_channels(0), 
356     m_queue(0),
357     m_buffers(0),
358     m_inputSampleRate(inputSampleRate),
359     m_frame(0),
360     m_unrun(true)
361 {
362     (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
363 }
364                 
365 PluginBufferingAdapter::Impl::~Impl()
366 {
367     // the adapter will delete the plugin
368
369     for (size_t i = 0; i < m_channels; ++i) {
370         delete m_queue[i];
371         delete[] m_buffers[i];
372     }
373     delete[] m_buffers;
374 }
375                 
376 void
377 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
378 {
379     if (m_inputStepSize != 0) {
380         std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
381         return;
382     }
383     m_setStepSize = stepSize;
384 }
385                 
386 void
387 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
388 {
389     if (m_inputBlockSize != 0) {
390         std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
391         return;
392     }
393     m_setBlockSize = blockSize;
394 }
395
396 void
397 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
398                                                          size_t &blockSize)
399 {
400     stepSize = m_stepSize;
401     blockSize = m_blockSize;
402 }
403
404 bool
405 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
406 {
407     if (stepSize != blockSize) {
408         std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
409         return false;
410     }
411
412     m_channels = channels;      
413     m_inputStepSize = stepSize;
414     m_inputBlockSize = blockSize;
415
416     // if the user has requested particular step or block sizes, use
417     // those; otherwise use the step and block sizes which the plugin
418     // prefers
419
420     m_stepSize = 0;
421     m_blockSize = 0;
422
423     if (m_setStepSize > 0) {
424         m_stepSize = m_setStepSize;
425     }
426     if (m_setBlockSize > 0) {
427         m_blockSize = m_setBlockSize;
428     }
429
430     if (m_stepSize == 0 && m_blockSize == 0) {
431         m_stepSize = m_plugin->getPreferredStepSize();
432         m_blockSize = m_plugin->getPreferredBlockSize();
433     }
434     
435     bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
436     
437     // or sensible defaults if it has no preference
438     if (m_blockSize == 0) {
439         if (m_stepSize == 0) {
440             m_blockSize = 1024;
441             if (freq) {
442                 m_stepSize = m_blockSize / 2;
443             } else {
444                 m_stepSize = m_blockSize;
445             }
446         } else if (freq) {
447             m_blockSize = m_stepSize * 2;
448         } else {
449             m_blockSize = m_stepSize;
450         }
451     } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
452         if (freq) {
453             m_stepSize = m_blockSize/2;
454         } else {
455             m_stepSize = m_blockSize;
456         }
457     }
458     
459     // current implementation breaks if step is greater than block
460     if (m_stepSize > m_blockSize) {
461         size_t newBlockSize;
462         if (freq) {
463             newBlockSize = m_stepSize * 2;
464         } else {
465             newBlockSize = m_stepSize;
466         }
467         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;
468         m_blockSize = newBlockSize;
469     }
470     
471 //    std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize 
472 //              << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;                    
473
474     m_buffers = new float *[m_channels];
475
476     for (size_t i = 0; i < m_channels; ++i) {
477         m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
478         m_buffers[i] = new float[m_blockSize];
479     }
480     
481     bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
482
483 //    std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
484
485     if (success) {
486         // Re-query outputs; properties such as bin count may have
487         // changed on initialise
488         m_outputs.clear();
489         (void)getOutputDescriptors();
490     }
491
492     return success;
493 }
494                 
495 PluginBufferingAdapter::OutputList
496 PluginBufferingAdapter::Impl::getOutputDescriptors() const
497 {
498     if (m_outputs.empty()) {
499 //    std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
500
501         m_outputs = m_plugin->getOutputDescriptors();
502     }
503
504     PluginBufferingAdapter::OutputList outs = m_outputs;
505
506     for (size_t i = 0; i < outs.size(); ++i) {
507
508         switch (outs[i].sampleType) {
509
510         case OutputDescriptor::OneSamplePerStep:
511             outs[i].sampleType = OutputDescriptor::FixedSampleRate;
512             outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
513             m_rewriteOutputTimes[i] = true;
514             break;
515             
516         case OutputDescriptor::FixedSampleRate:
517             if (outs[i].sampleRate == 0.f) {
518                 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
519             }
520             // We actually only need to rewrite output times for
521             // features that don't have timestamps already, but we
522             // can't tell from here whether our features will have
523             // timestamps or not
524             m_rewriteOutputTimes[i] = true;
525             break;
526
527         case OutputDescriptor::VariableSampleRate:
528             m_rewriteOutputTimes[i] = false;
529             break;
530         }
531     }
532
533     return outs;
534 }
535
536 void
537 PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
538 {
539     m_plugin->setParameter(name, value);
540
541     // Re-query outputs; properties such as bin count may have changed
542     m_outputs.clear();
543     (void)getOutputDescriptors();
544 }
545
546 void
547 PluginBufferingAdapter::Impl::selectProgram(std::string name)
548 {
549     m_plugin->selectProgram(name);
550
551     // Re-query outputs; properties such as bin count may have changed
552     m_outputs.clear();
553     (void)getOutputDescriptors();
554 }
555
556 void
557 PluginBufferingAdapter::Impl::reset()
558 {
559     m_frame = 0;
560     m_unrun = true;
561
562     for (size_t i = 0; i < m_queue.size(); ++i) {
563         m_queue[i]->reset();
564     }
565
566     m_plugin->reset();
567 }
568
569 PluginBufferingAdapter::FeatureSet
570 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
571                                       RealTime timestamp)
572 {
573     if (m_inputStepSize == 0) {
574         std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
575         return FeatureSet();
576     }
577
578     FeatureSet allFeatureSets;
579
580     if (m_unrun) {
581         m_frame = RealTime::realTime2Frame(timestamp,
582                                            int(m_inputSampleRate + 0.5));
583         m_unrun = false;
584     }
585                         
586     // queue the new input
587     
588     for (size_t i = 0; i < m_channels; ++i) {
589         int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
590         if (written < int(m_inputBlockSize) && i == 0) {
591             std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
592                       << "Buffer overflow: wrote " << written 
593                       << " of " << m_inputBlockSize 
594                       << " input samples (for plugin step size "
595                       << m_stepSize << ", block size " << m_blockSize << ")"
596                       << std::endl;
597         }
598     }    
599     
600     // process as much as we can
601
602     while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
603         processBlock(allFeatureSets);
604     }   
605     
606     return allFeatureSets;
607 }
608     
609 PluginBufferingAdapter::FeatureSet
610 PluginBufferingAdapter::Impl::getRemainingFeatures() 
611 {
612     FeatureSet allFeatureSets;
613     
614     // process remaining samples in queue
615     while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
616         processBlock(allFeatureSets);
617     }
618     
619     // pad any last samples remaining and process
620     if (m_queue[0]->getReadSpace() > 0) {
621         for (size_t i = 0; i < m_channels; ++i) {
622             m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
623         }
624         processBlock(allFeatureSets);
625     }                   
626     
627     // get remaining features                   
628
629     FeatureSet featureSet = m_plugin->getRemainingFeatures();
630
631     for (map<int, FeatureList>::iterator iter = featureSet.begin();
632          iter != featureSet.end(); ++iter) {
633         FeatureList featureList = iter->second;
634         for (size_t i = 0; i < featureList.size(); ++i) {
635             allFeatureSets[iter->first].push_back(featureList[i]);
636         }
637     }
638     
639     return allFeatureSets;
640 }
641     
642 void
643 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
644 {
645     for (size_t i = 0; i < m_channels; ++i) {
646         m_queue[i]->peek(m_buffers[i], m_blockSize);
647     }
648
649     long frame = m_frame;
650     RealTime timestamp = RealTime::frame2RealTime
651         (frame, int(m_inputSampleRate + 0.5));
652
653     FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
654     
655     for (FeatureSet::iterator iter = featureSet.begin();
656          iter != featureSet.end(); ++iter) {
657
658         int outputNo = iter->first;
659
660         if (m_rewriteOutputTimes[outputNo]) {
661             
662             FeatureList featureList = iter->second;
663         
664             for (size_t i = 0; i < featureList.size(); ++i) {
665
666                 switch (m_outputs[outputNo].sampleType) {
667
668                 case OutputDescriptor::OneSamplePerStep:
669                     // use our internal timestamp, always
670                     featureList[i].timestamp = timestamp;
671                     featureList[i].hasTimestamp = true;
672                     break;
673
674                 case OutputDescriptor::FixedSampleRate:
675                     // use our internal timestamp if feature lacks one
676                     if (!featureList[i].hasTimestamp) {
677                         featureList[i].timestamp = timestamp;
678                         featureList[i].hasTimestamp = true;
679                     }
680                     break;
681
682                 case OutputDescriptor::VariableSampleRate:
683                     break;              // plugin must set timestamp
684
685                 default:
686                     break;
687                 }
688             
689                 allFeatureSets[outputNo].push_back(featureList[i]);
690             }
691         } else {
692             for (size_t i = 0; i < iter->second.size(); ++i) {
693                 allFeatureSets[outputNo].push_back(iter->second[i]);
694             }
695         }
696     }
697     
698     // step forward
699
700     for (size_t i = 0; i < m_channels; ++i) {
701         m_queue[i]->skip(m_stepSize);
702     }
703     
704     // increment internal frame counter each time we step forward
705     m_frame += m_stepSize;
706 }
707
708 }
709         
710 }
711
712 _VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)