PluginBufferingAdapter.cpp

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Vamp
00005 
00006     An API for audio analysis and feature extraction plugins.
00007 
00008     Centre for Digital Music, Queen Mary, University of London.
00009     Copyright 2006-2007 Chris Cannam and QMUL.
00010     This file by Mark Levy and Chris Cannam.
00011   
00012     Permission is hereby granted, free of charge, to any person
00013     obtaining a copy of this software and associated documentation
00014     files (the "Software"), to deal in the Software without
00015     restriction, including without limitation the rights to use, copy,
00016     modify, merge, publish, distribute, sublicense, and/or sell copies
00017     of the Software, and to permit persons to whom the Software is
00018     furnished to do so, subject to the following conditions:
00019 
00020     The above copyright notice and this permission notice shall be
00021     included in all copies or substantial portions of the Software.
00022 
00023     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00024     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00025     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00026     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
00027     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00028     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00029     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00030 
00031     Except as contained in this notice, the names of the Centre for
00032     Digital Music; Queen Mary, University of London; and Chris Cannam
00033     shall not be used in advertising or otherwise to promote the sale,
00034     use or other dealings in this Software without prior written
00035     authorization.
00036 */
00037 
00038 #include <vector>
00039 #include <map>
00040 
00041 #include "PluginBufferingAdapter.h"
00042 
00043 using std::vector;
00044 using std::map;
00045 
00046 namespace Vamp {
00047         
00048 namespace HostExt {
00049                 
00050 class PluginBufferingAdapter::Impl
00051 {
00052 public:
00053     Impl(Plugin *plugin, float inputSampleRate);
00054     ~Impl();
00055                 
00056     bool initialise(size_t channels, size_t stepSize, size_t blockSize);
00057 
00058     OutputList getOutputDescriptors() const;
00059 
00060     void reset();
00061 
00062     FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
00063                 
00064     FeatureSet getRemainingFeatures();
00065                 
00066 protected:
00067     class RingBuffer
00068     {
00069     public:
00070         RingBuffer(int n) :
00071             m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
00072         virtual ~RingBuffer() { delete[] m_buffer; }
00073 
00074         int getSize() const { return m_size-1; }
00075         void reset() { m_writer = 0; m_reader = 0; }
00076 
00077         int getReadSpace() const {
00078             int writer = m_writer, reader = m_reader, space;
00079             if (writer > reader) space = writer - reader;
00080             else if (writer < reader) space = (writer + m_size) - reader;
00081             else space = 0;
00082             return space;
00083         }
00084 
00085         int getWriteSpace() const {
00086             int writer = m_writer;
00087             int reader = m_reader;
00088             int space = (reader + m_size - writer - 1);
00089             if (space >= m_size) space -= m_size;
00090             return space;
00091         }
00092         
00093         int peek(float *destination, int n) const {
00094 
00095             int available = getReadSpace();
00096 
00097             if (n > available) {
00098                 for (int i = available; i < n; ++i) {
00099                     destination[i] = 0.f;
00100                 }
00101                 n = available;
00102             }
00103             if (n == 0) return n;
00104 
00105             int reader = m_reader;
00106             int here = m_size - reader;
00107             const float *const bufbase = m_buffer + reader;
00108 
00109             if (here >= n) {
00110                 for (int i = 0; i < n; ++i) {
00111                     destination[i] = bufbase[i];
00112                 }
00113             } else {
00114                 for (int i = 0; i < here; ++i) {
00115                     destination[i] = bufbase[i];
00116                 }
00117                 float *const destbase = destination + here;
00118                 const int nh = n - here;
00119                 for (int i = 0; i < nh; ++i) {
00120                     destbase[i] = m_buffer[i];
00121                 }
00122             }
00123 
00124             return n;
00125         }
00126 
00127         int skip(int n) {
00128             
00129             int available = getReadSpace();
00130             if (n > available) {
00131                 n = available;
00132             }
00133             if (n == 0) return n;
00134 
00135             int reader = m_reader;
00136             reader += n;
00137             while (reader >= m_size) reader -= m_size;
00138             m_reader = reader;
00139             return n;
00140         }
00141         
00142         int write(const float *source, int n) {
00143 
00144             int available = getWriteSpace();
00145             if (n > available) {
00146                 n = available;
00147             }
00148             if (n == 0) return n;
00149 
00150             int writer = m_writer;
00151             int here = m_size - writer;
00152             float *const bufbase = m_buffer + writer;
00153             
00154             if (here >= n) {
00155                 for (int i = 0; i < n; ++i) {
00156                     bufbase[i] = source[i];
00157                 }
00158             } else {
00159                 for (int i = 0; i < here; ++i) {
00160                     bufbase[i] = source[i];
00161                 }
00162                 const int nh = n - here;
00163                 const float *const srcbase = source + here;
00164                 float *const buf = m_buffer;
00165                 for (int i = 0; i < nh; ++i) {
00166                     buf[i] = srcbase[i];
00167                 }
00168             }
00169 
00170             writer += n;
00171             while (writer >= m_size) writer -= m_size;
00172             m_writer = writer;
00173 
00174             return n;
00175         }
00176 
00177         int zero(int n) {
00178             
00179             int available = getWriteSpace();
00180             if (n > available) {
00181                 n = available;
00182             }
00183             if (n == 0) return n;
00184 
00185             int writer = m_writer;
00186             int here = m_size - writer;
00187             float *const bufbase = m_buffer + writer;
00188 
00189             if (here >= n) {
00190                 for (int i = 0; i < n; ++i) {
00191                     bufbase[i] = 0.f;
00192                 }
00193             } else {
00194                 for (int i = 0; i < here; ++i) {
00195                     bufbase[i] = 0.f;
00196                 }
00197                 const int nh = n - here;
00198                 for (int i = 0; i < nh; ++i) {
00199                     m_buffer[i] = 0.f;
00200                 }
00201             }
00202             
00203             writer += n;
00204             while (writer >= m_size) writer -= m_size;
00205             m_writer = writer;
00206 
00207             return n;
00208         }
00209 
00210     protected:
00211         float *m_buffer;
00212         int    m_writer;
00213         int    m_reader;
00214         int    m_size;
00215 
00216     private:
00217         RingBuffer(const RingBuffer &); // not provided
00218         RingBuffer &operator=(const RingBuffer &); // not provided
00219     };
00220 
00221     Plugin *m_plugin;
00222     size_t m_inputStepSize;
00223     size_t m_inputBlockSize;
00224     size_t m_stepSize;
00225     size_t m_blockSize;
00226     size_t m_channels;
00227     vector<RingBuffer *> m_queue;
00228     float **m_buffers;
00229     float m_inputSampleRate;
00230     long m_frame;
00231     bool m_unrun;
00232     mutable OutputList m_outputs;
00233     mutable std::map<int, bool> m_rewriteOutputTimes;
00234                 
00235     void processBlock(FeatureSet& allFeatureSets);
00236 };
00237                 
00238 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
00239     PluginWrapper(plugin)
00240 {
00241     m_impl = new Impl(plugin, m_inputSampleRate);
00242 }
00243                 
00244 PluginBufferingAdapter::~PluginBufferingAdapter()
00245 {
00246     delete m_impl;
00247 }
00248                 
00249 bool
00250 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
00251 {
00252     return m_impl->initialise(channels, stepSize, blockSize);
00253 }
00254 
00255 PluginBufferingAdapter::OutputList
00256 PluginBufferingAdapter::getOutputDescriptors() const
00257 {
00258     return m_impl->getOutputDescriptors();
00259 }
00260 
00261 void
00262 PluginBufferingAdapter::reset()
00263 {
00264     m_impl->reset();
00265 }
00266                 
00267 PluginBufferingAdapter::FeatureSet
00268 PluginBufferingAdapter::process(const float *const *inputBuffers,
00269                                 RealTime timestamp)
00270 {
00271     return m_impl->process(inputBuffers, timestamp);
00272 }
00273                 
00274 PluginBufferingAdapter::FeatureSet
00275 PluginBufferingAdapter::getRemainingFeatures()
00276 {
00277     return m_impl->getRemainingFeatures();
00278 }
00279                 
00280 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
00281     m_plugin(plugin),
00282     m_inputStepSize(0),
00283     m_inputBlockSize(0),
00284     m_stepSize(0),
00285     m_blockSize(0),
00286     m_channels(0), 
00287     m_queue(0),
00288     m_buffers(0),
00289     m_inputSampleRate(inputSampleRate),
00290     m_frame(0),
00291     m_unrun(true)
00292 {
00293     (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
00294 }
00295                 
00296 PluginBufferingAdapter::Impl::~Impl()
00297 {
00298     // the adapter will delete the plugin
00299 
00300     for (size_t i = 0; i < m_channels; ++i) {
00301         delete m_queue[i];
00302         delete[] m_buffers[i];
00303     }
00304     delete[] m_buffers;
00305 }
00306 
00307 size_t
00308 PluginBufferingAdapter::getPreferredStepSize() const
00309 {
00310     return getPreferredBlockSize();
00311 }
00312                 
00313 bool
00314 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
00315 {
00316     if (stepSize != blockSize) {
00317         std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
00318         return false;
00319     }
00320 
00321     m_channels = channels;      
00322     m_inputStepSize = stepSize;
00323     m_inputBlockSize = blockSize;
00324     
00325     // use the step and block sizes which the plugin prefers
00326     m_stepSize = m_plugin->getPreferredStepSize();
00327     m_blockSize = m_plugin->getPreferredBlockSize();
00328     
00329     // or sensible defaults if it has no preference
00330     if (m_blockSize == 0) {
00331         m_blockSize = 1024;
00332     }
00333     if (m_stepSize == 0) {
00334         if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
00335             m_stepSize = m_blockSize/2;
00336         } else {
00337             m_stepSize = m_blockSize;
00338         }
00339     } else if (m_stepSize > m_blockSize) {
00340         if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
00341             m_blockSize = m_stepSize * 2;
00342         } else {
00343             m_blockSize = m_stepSize;
00344         }
00345     }
00346     
00347     std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize 
00348               << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;                      
00349     
00350     // current implementation breaks if step is greater than block
00351     if (m_stepSize > m_blockSize) {
00352         std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl;
00353         return false;
00354     }
00355 
00356     m_buffers = new float *[m_channels];
00357 
00358     for (size_t i = 0; i < m_channels; ++i) {
00359         m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
00360         m_buffers[i] = new float[m_blockSize];
00361     }
00362     
00363     return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
00364 }
00365                 
00366 PluginBufferingAdapter::OutputList
00367 PluginBufferingAdapter::Impl::getOutputDescriptors() const
00368 {
00369     if (m_outputs.empty()) {
00370         m_outputs = m_plugin->getOutputDescriptors();
00371     }
00372 
00373     PluginBufferingAdapter::OutputList outs = m_outputs;
00374 
00375     for (size_t i = 0; i < outs.size(); ++i) {
00376 
00377         switch (outs[i].sampleType) {
00378 
00379         case OutputDescriptor::OneSamplePerStep:
00380             outs[i].sampleType = OutputDescriptor::FixedSampleRate;
00381             outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
00382             m_rewriteOutputTimes[i] = true;
00383             break;
00384             
00385         case OutputDescriptor::FixedSampleRate:
00386             if (outs[i].sampleRate == 0.f) {
00387                 outs[i].sampleRate = (1.f / m_inputSampleRate) * m_stepSize;
00388             }
00389             // We actually only need to rewrite output times for
00390             // features that don't have timestamps already, but we
00391             // can't tell from here whether our features will have
00392             // timestamps or not
00393             m_rewriteOutputTimes[i] = true;
00394             break;
00395 
00396         case OutputDescriptor::VariableSampleRate:
00397             m_rewriteOutputTimes[i] = false;
00398             break;
00399         }
00400     }
00401 
00402     return outs;
00403 }
00404 
00405 void
00406 PluginBufferingAdapter::Impl::reset()
00407 {
00408     m_frame = 0;
00409     m_unrun = true;
00410 
00411     for (size_t i = 0; i < m_queue.size(); ++i) {
00412         m_queue[i]->reset();
00413     }
00414 }
00415 
00416 PluginBufferingAdapter::FeatureSet
00417 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
00418                                       RealTime timestamp)
00419 {
00420     FeatureSet allFeatureSets;
00421 
00422     if (m_unrun) {
00423         m_frame = RealTime::realTime2Frame(timestamp,
00424                                            int(m_inputSampleRate + 0.5));
00425         m_unrun = false;
00426     }
00427                         
00428     // queue the new input
00429     
00430     for (size_t i = 0; i < m_channels; ++i) {
00431         int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
00432         if (written < int(m_inputBlockSize) && i == 0) {
00433             std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
00434                       << "Buffer overflow: wrote " << written 
00435                       << " of " << m_inputBlockSize 
00436                       << " input samples (for plugin step size "
00437                       << m_stepSize << ", block size " << m_blockSize << ")"
00438                       << std::endl;
00439         }
00440     }    
00441     
00442     // process as much as we can
00443 
00444     while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
00445         processBlock(allFeatureSets);
00446     }   
00447     
00448     return allFeatureSets;
00449 }
00450     
00451 PluginBufferingAdapter::FeatureSet
00452 PluginBufferingAdapter::Impl::getRemainingFeatures() 
00453 {
00454     FeatureSet allFeatureSets;
00455     
00456     // process remaining samples in queue
00457     while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
00458         processBlock(allFeatureSets);
00459     }
00460     
00461     // pad any last samples remaining and process
00462     if (m_queue[0]->getReadSpace() > 0) {
00463         for (size_t i = 0; i < m_channels; ++i) {
00464             m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
00465         }
00466         processBlock(allFeatureSets);
00467     }                   
00468     
00469     // get remaining features                   
00470 
00471     FeatureSet featureSet = m_plugin->getRemainingFeatures();
00472 
00473     for (map<int, FeatureList>::iterator iter = featureSet.begin();
00474          iter != featureSet.end(); ++iter) {
00475         FeatureList featureList = iter->second;
00476         for (size_t i = 0; i < featureList.size(); ++i) {
00477             allFeatureSets[iter->first].push_back(featureList[i]);
00478         }
00479     }
00480     
00481     return allFeatureSets;
00482 }
00483     
00484 void
00485 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
00486 {
00487     for (size_t i = 0; i < m_channels; ++i) {
00488         m_queue[i]->peek(m_buffers[i], m_blockSize);
00489     }
00490 
00491     long frame = m_frame;
00492     RealTime timestamp = RealTime::frame2RealTime
00493         (frame, int(m_inputSampleRate + 0.5));
00494 
00495     FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
00496     
00497     for (FeatureSet::iterator iter = featureSet.begin();
00498          iter != featureSet.end(); ++iter) {
00499 
00500         int outputNo = iter->first;
00501 
00502         if (m_rewriteOutputTimes[outputNo]) {
00503             
00504             FeatureList featureList = iter->second;
00505         
00506             for (size_t i = 0; i < featureList.size(); ++i) {
00507 
00508                 switch (m_outputs[outputNo].sampleType) {
00509 
00510                 case OutputDescriptor::OneSamplePerStep:
00511                     // use our internal timestamp, always
00512                     featureList[i].timestamp = timestamp;
00513                     featureList[i].hasTimestamp = true;
00514                     break;
00515 
00516                 case OutputDescriptor::FixedSampleRate:
00517                     // use our internal timestamp if feature lacks one
00518                     if (!featureList[i].hasTimestamp) {
00519                         featureList[i].timestamp = timestamp;
00520                         featureList[i].hasTimestamp = true;
00521                     }
00522                     break;
00523 
00524                 case OutputDescriptor::VariableSampleRate:
00525                     break;              // plugin must set timestamp
00526 
00527                 default:
00528                     break;
00529                 }
00530             
00531                 allFeatureSets[outputNo].push_back(featureList[i]);
00532             }
00533         } else {
00534             for (size_t i = 0; i < iter->second.size(); ++i) {
00535                 allFeatureSets[outputNo].push_back(iter->second[i]);
00536             }
00537         }
00538     }
00539     
00540     // step forward
00541 
00542     for (size_t i = 0; i < m_channels; ++i) {
00543         m_queue[i]->skip(m_stepSize);
00544     }
00545     
00546     // increment internal frame counter each time we step forward
00547     m_frame += m_stepSize;
00548 }
00549 
00550 }
00551         
00552 }
00553 
00554 

Generated on Fri Nov 7 13:10:34 2008 for VampPluginSDK by  doxygen 1.5.6