Merge with 2.0-ongoing R2885.
[ardour.git] / libs / vamp-sdk / vamp-sdk / PluginAdapter.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 Chris Cannam.
10   
11     Permission is hereby granted, free of charge, to any person
12     obtaining a copy of this software and associated documentation
13     files (the "Software"), to deal in the Software without
14     restriction, including without limitation the rights to use, copy,
15     modify, merge, publish, distribute, sublicense, and/or sell copies
16     of the Software, and to permit persons to whom the Software is
17     furnished to do so, subject to the following conditions:
18
19     The above copyright notice and this permission notice shall be
20     included in all copies or substantial portions of the Software.
21
22     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26     ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27     CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28     WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30     Except as contained in this notice, the names of the Centre for
31     Digital Music; Queen Mary, University of London; and Chris Cannam
32     shall not be used in advertising or otherwise to promote the sale,
33     use or other dealings in this Software without prior written
34     authorization.
35 */
36
37 #include "PluginAdapter.h"
38
39 //#define DEBUG_PLUGIN_ADAPTER 1
40
41
42 namespace Vamp {
43
44 class PluginAdapterBase::Impl
45 {
46 public:
47     Impl(PluginAdapterBase *);
48     ~Impl();
49
50     const VampPluginDescriptor *getDescriptor();
51
52 protected:
53     PluginAdapterBase *m_base;
54
55     static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc,
56                                           float inputSampleRate);
57
58     static void vampCleanup(VampPluginHandle handle);
59
60     static int vampInitialise(VampPluginHandle handle, unsigned int channels,
61                              unsigned int stepSize, unsigned int blockSize);
62
63     static void vampReset(VampPluginHandle handle);
64
65     static float vampGetParameter(VampPluginHandle handle, int param);
66     static void vampSetParameter(VampPluginHandle handle, int param, float value);
67
68     static unsigned int vampGetCurrentProgram(VampPluginHandle handle);
69     static void vampSelectProgram(VampPluginHandle handle, unsigned int program);
70
71     static unsigned int vampGetPreferredStepSize(VampPluginHandle handle);
72     static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle);
73     static unsigned int vampGetMinChannelCount(VampPluginHandle handle);
74     static unsigned int vampGetMaxChannelCount(VampPluginHandle handle);
75
76     static unsigned int vampGetOutputCount(VampPluginHandle handle);
77
78     static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle,
79                                                        unsigned int i);
80
81     static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc);
82
83     static VampFeatureList *vampProcess(VampPluginHandle handle,
84                                         const float *const *inputBuffers,
85                                         int sec,
86                                         int nsec);
87
88     static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle);
89
90     static void vampReleaseFeatureSet(VampFeatureList *fs);
91
92     void cleanup(Plugin *plugin);
93     void checkOutputMap(Plugin *plugin);
94     unsigned int getOutputCount(Plugin *plugin);
95     VampOutputDescriptor *getOutputDescriptor(Plugin *plugin,
96                                              unsigned int i);
97     VampFeatureList *process(Plugin *plugin,
98                              const float *const *inputBuffers,
99                              int sec, int nsec);
100     VampFeatureList *getRemainingFeatures(Plugin *plugin);
101     VampFeatureList *convertFeatures(Plugin *plugin,
102                                      const Plugin::FeatureSet &features);
103     
104     // maps both plugins and descriptors to adapters
105     typedef std::map<const void *, Impl *> AdapterMap;
106     static AdapterMap *m_adapterMap;
107     static Impl *lookupAdapter(VampPluginHandle);
108
109     bool m_populated;
110     VampPluginDescriptor m_descriptor;
111     Plugin::ParameterList m_parameters;
112     Plugin::ProgramList m_programs;
113     
114     typedef std::map<Plugin *, Plugin::OutputList *> OutputMap;
115     OutputMap m_pluginOutputs;
116
117     std::map<Plugin *, VampFeatureList *> m_fs;
118     std::map<Plugin *, std::vector<size_t> > m_fsizes;
119     std::map<Plugin *, std::vector<std::vector<size_t> > > m_fvsizes;
120     void resizeFS(Plugin *plugin, int n);
121     void resizeFL(Plugin *plugin, int n, size_t sz);
122     void resizeFV(Plugin *plugin, int n, int j, size_t sz);
123 };
124
125 PluginAdapterBase::PluginAdapterBase()
126 {
127     m_impl = new Impl(this);
128 }
129
130 PluginAdapterBase::~PluginAdapterBase()
131 {
132     delete m_impl;
133 }
134
135 const VampPluginDescriptor *
136 PluginAdapterBase::getDescriptor()
137 {
138     return m_impl->getDescriptor();
139 }
140
141 PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) :
142     m_base(base),
143     m_populated(false)
144 {
145 #ifdef DEBUG_PLUGIN_ADAPTER
146     std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl;
147 #endif
148 }
149
150 const VampPluginDescriptor *
151 PluginAdapterBase::Impl::getDescriptor()
152 {
153 #ifdef DEBUG_PLUGIN_ADAPTER
154     std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl;
155 #endif
156
157     if (m_populated) return &m_descriptor;
158
159     Plugin *plugin = m_base->createPlugin(48000);
160
161     if (plugin->getVampApiVersion() != VAMP_API_VERSION) {
162         std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: "
163                   << "Plugin object API version "
164                   << plugin->getVampApiVersion()
165                   << " does not match actual API version "
166                   << VAMP_API_VERSION << std::endl;
167         delete plugin;
168         return 0;
169     }
170
171     m_parameters = plugin->getParameterDescriptors();
172     m_programs = plugin->getPrograms();
173
174     m_descriptor.vampApiVersion = plugin->getVampApiVersion();
175     m_descriptor.identifier = strdup(plugin->getIdentifier().c_str());
176     m_descriptor.name = strdup(plugin->getName().c_str());
177     m_descriptor.description = strdup(plugin->getDescription().c_str());
178     m_descriptor.maker = strdup(plugin->getMaker().c_str());
179     m_descriptor.pluginVersion = plugin->getPluginVersion();
180     m_descriptor.copyright = strdup(plugin->getCopyright().c_str());
181     
182     m_descriptor.parameterCount = m_parameters.size();
183     m_descriptor.parameters = (const VampParameterDescriptor **)
184         malloc(m_parameters.size() * sizeof(VampParameterDescriptor));
185
186     unsigned int i;
187     
188     for (i = 0; i < m_parameters.size(); ++i) {
189         VampParameterDescriptor *desc = (VampParameterDescriptor *)
190             malloc(sizeof(VampParameterDescriptor));
191         desc->identifier = strdup(m_parameters[i].identifier.c_str());
192         desc->name = strdup(m_parameters[i].name.c_str());
193         desc->description = strdup(m_parameters[i].description.c_str());
194         desc->unit = strdup(m_parameters[i].unit.c_str());
195         desc->minValue = m_parameters[i].minValue;
196         desc->maxValue = m_parameters[i].maxValue;
197         desc->defaultValue = m_parameters[i].defaultValue;
198         desc->isQuantized = m_parameters[i].isQuantized;
199         desc->quantizeStep = m_parameters[i].quantizeStep;
200         desc->valueNames = 0;
201         if (desc->isQuantized && !m_parameters[i].valueNames.empty()) {
202             desc->valueNames = (const char **)
203                 malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *));
204             for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) {
205                 desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str());
206             }
207             desc->valueNames[m_parameters[i].valueNames.size()] = 0;
208         }
209         m_descriptor.parameters[i] = desc;
210     }
211     
212     m_descriptor.programCount = m_programs.size();
213     m_descriptor.programs = (const char **)
214         malloc(m_programs.size() * sizeof(const char *));
215     
216     for (i = 0; i < m_programs.size(); ++i) {
217         m_descriptor.programs[i] = strdup(m_programs[i].c_str());
218     }
219     
220     if (plugin->getInputDomain() == Plugin::FrequencyDomain) {
221         m_descriptor.inputDomain = vampFrequencyDomain;
222     } else {
223         m_descriptor.inputDomain = vampTimeDomain;
224     }
225
226     m_descriptor.instantiate = vampInstantiate;
227     m_descriptor.cleanup = vampCleanup;
228     m_descriptor.initialise = vampInitialise;
229     m_descriptor.reset = vampReset;
230     m_descriptor.getParameter = vampGetParameter;
231     m_descriptor.setParameter = vampSetParameter;
232     m_descriptor.getCurrentProgram = vampGetCurrentProgram;
233     m_descriptor.selectProgram = vampSelectProgram;
234     m_descriptor.getPreferredStepSize = vampGetPreferredStepSize;
235     m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize;
236     m_descriptor.getMinChannelCount = vampGetMinChannelCount;
237     m_descriptor.getMaxChannelCount = vampGetMaxChannelCount;
238     m_descriptor.getOutputCount = vampGetOutputCount;
239     m_descriptor.getOutputDescriptor = vampGetOutputDescriptor;
240     m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor;
241     m_descriptor.process = vampProcess;
242     m_descriptor.getRemainingFeatures = vampGetRemainingFeatures;
243     m_descriptor.releaseFeatureSet = vampReleaseFeatureSet;
244     
245     if (!m_adapterMap) {
246         m_adapterMap = new AdapterMap;
247     }
248     (*m_adapterMap)[&m_descriptor] = this;
249
250     delete plugin;
251
252     m_populated = true;
253     return &m_descriptor;
254 }
255
256 PluginAdapterBase::Impl::~Impl()
257 {
258 #ifdef DEBUG_PLUGIN_ADAPTER
259     std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl;
260 #endif
261
262     if (!m_populated) return;
263
264     free((void *)m_descriptor.identifier);
265     free((void *)m_descriptor.name);
266     free((void *)m_descriptor.description);
267     free((void *)m_descriptor.maker);
268     free((void *)m_descriptor.copyright);
269         
270     for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) {
271         const VampParameterDescriptor *desc = m_descriptor.parameters[i];
272         free((void *)desc->identifier);
273         free((void *)desc->name);
274         free((void *)desc->description);
275         free((void *)desc->unit);
276         if (desc->valueNames) {
277             for (unsigned int j = 0; desc->valueNames[j]; ++j) {
278                 free((void *)desc->valueNames[j]);
279             }
280             free((void *)desc->valueNames);
281         }
282     }
283     free((void *)m_descriptor.parameters);
284
285     for (unsigned int i = 0; i < m_descriptor.programCount; ++i) {
286         free((void *)m_descriptor.programs[i]);
287     }
288     free((void *)m_descriptor.programs);
289
290     if (m_adapterMap) {
291         
292         m_adapterMap->erase(&m_descriptor);
293
294         if (m_adapterMap->empty()) {
295             delete m_adapterMap;
296             m_adapterMap = 0;
297         }
298     }
299 }
300
301 PluginAdapterBase::Impl *
302 PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle)
303 {
304 #ifdef DEBUG_PLUGIN_ADAPTER
305     std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl;
306 #endif
307
308     if (!m_adapterMap) return 0;
309     AdapterMap::const_iterator i = m_adapterMap->find(handle);
310     if (i == m_adapterMap->end()) return 0;
311     return i->second;
312 }
313
314 VampPluginHandle
315 PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc,
316                                    float inputSampleRate)
317 {
318 #ifdef DEBUG_PLUGIN_ADAPTER
319     std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl;
320 #endif
321
322     if (!m_adapterMap) {
323         m_adapterMap = new AdapterMap();
324     }
325
326     if (m_adapterMap->find(desc) == m_adapterMap->end()) {
327         std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl;
328         return 0;
329     }
330
331     Impl *adapter = (*m_adapterMap)[desc];
332     if (desc != &adapter->m_descriptor) return 0;
333
334     Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate);
335     if (plugin) {
336         (*m_adapterMap)[plugin] = adapter;
337     }
338
339 #ifdef DEBUG_PLUGIN_ADAPTER
340     std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl;
341 #endif
342
343     return plugin;
344 }
345
346 void
347 PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle)
348 {
349 #ifdef DEBUG_PLUGIN_ADAPTER
350     std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl;
351 #endif
352
353     Impl *adapter = lookupAdapter(handle);
354     if (!adapter) {
355         delete ((Plugin *)handle);
356         return;
357     }
358     adapter->cleanup(((Plugin *)handle));
359 }
360
361 int
362 PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle,
363                                   unsigned int channels,
364                                   unsigned int stepSize,
365                                   unsigned int blockSize)
366 {
367 #ifdef DEBUG_PLUGIN_ADAPTER
368     std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl;
369 #endif
370
371     bool result = ((Plugin *)handle)->initialise
372         (channels, stepSize, blockSize);
373     return result ? 1 : 0;
374 }
375
376 void
377 PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) 
378 {
379 #ifdef DEBUG_PLUGIN_ADAPTER
380     std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl;
381 #endif
382
383     ((Plugin *)handle)->reset();
384 }
385
386 float
387 PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle,
388                                     int param) 
389 {
390 #ifdef DEBUG_PLUGIN_ADAPTER
391     std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl;
392 #endif
393
394     Impl *adapter = lookupAdapter(handle);
395     if (!adapter) return 0.0;
396     Plugin::ParameterList &list = adapter->m_parameters;
397     return ((Plugin *)handle)->getParameter(list[param].identifier);
398 }
399
400 void
401 PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle,
402                                     int param, float value)
403 {
404 #ifdef DEBUG_PLUGIN_ADAPTER
405     std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl;
406 #endif
407
408     Impl *adapter = lookupAdapter(handle);
409     if (!adapter) return;
410     Plugin::ParameterList &list = adapter->m_parameters;
411     ((Plugin *)handle)->setParameter(list[param].identifier, value);
412 }
413
414 unsigned int
415 PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle)
416 {
417 #ifdef DEBUG_PLUGIN_ADAPTER
418     std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl;
419 #endif
420
421     Impl *adapter = lookupAdapter(handle);
422     if (!adapter) return 0;
423     Plugin::ProgramList &list = adapter->m_programs;
424     std::string program = ((Plugin *)handle)->getCurrentProgram();
425     for (unsigned int i = 0; i < list.size(); ++i) {
426         if (list[i] == program) return i;
427     }
428     return 0;
429 }
430
431 void
432 PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle,
433                                      unsigned int program)
434 {
435 #ifdef DEBUG_PLUGIN_ADAPTER
436     std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl;
437 #endif
438
439     Impl *adapter = lookupAdapter(handle);
440     if (!adapter) return;
441     Plugin::ProgramList &list = adapter->m_programs;
442     ((Plugin *)handle)->selectProgram(list[program]);
443 }
444
445 unsigned int
446 PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle)
447 {
448 #ifdef DEBUG_PLUGIN_ADAPTER
449     std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl;
450 #endif
451
452     return ((Plugin *)handle)->getPreferredStepSize();
453 }
454
455 unsigned int
456 PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) 
457 {
458 #ifdef DEBUG_PLUGIN_ADAPTER
459     std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl;
460 #endif
461
462     return ((Plugin *)handle)->getPreferredBlockSize();
463 }
464
465 unsigned int
466 PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle)
467 {
468 #ifdef DEBUG_PLUGIN_ADAPTER
469     std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl;
470 #endif
471
472     return ((Plugin *)handle)->getMinChannelCount();
473 }
474
475 unsigned int
476 PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle)
477 {
478 #ifdef DEBUG_PLUGIN_ADAPTER
479     std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl;
480 #endif
481
482     return ((Plugin *)handle)->getMaxChannelCount();
483 }
484
485 unsigned int
486 PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle)
487 {
488 #ifdef DEBUG_PLUGIN_ADAPTER
489     std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl;
490 #endif
491
492     Impl *adapter = lookupAdapter(handle);
493
494 //    std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl;
495
496     if (!adapter) return 0;
497     return adapter->getOutputCount((Plugin *)handle);
498 }
499
500 VampOutputDescriptor *
501 PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle,
502                                            unsigned int i)
503 {
504 #ifdef DEBUG_PLUGIN_ADAPTER
505     std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl;
506 #endif
507
508     Impl *adapter = lookupAdapter(handle);
509
510 //    std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl;
511
512     if (!adapter) return 0;
513     return adapter->getOutputDescriptor((Plugin *)handle, i);
514 }
515
516 void
517 PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc)
518 {
519 #ifdef DEBUG_PLUGIN_ADAPTER
520     std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl;
521 #endif
522
523     if (desc->identifier) free((void *)desc->identifier);
524     if (desc->name) free((void *)desc->name);
525     if (desc->description) free((void *)desc->description);
526     if (desc->unit) free((void *)desc->unit);
527     if (desc->hasFixedBinCount && desc->binNames) {
528         for (unsigned int i = 0; i < desc->binCount; ++i) {
529             if (desc->binNames[i]) {
530                 free((void *)desc->binNames[i]);
531             }
532         }
533     }
534     if (desc->binNames) free((void *)desc->binNames);
535     free((void *)desc);
536 }
537
538 VampFeatureList *
539 PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle,
540                                const float *const *inputBuffers,
541                                int sec,
542                                int nsec)
543 {
544 #ifdef DEBUG_PLUGIN_ADAPTER
545     std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl;
546 #endif
547
548     Impl *adapter = lookupAdapter(handle);
549     if (!adapter) return 0;
550     return adapter->process((Plugin *)handle,
551                             inputBuffers, sec, nsec);
552 }
553
554 VampFeatureList *
555 PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle)
556 {
557 #ifdef DEBUG_PLUGIN_ADAPTER
558     std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl;
559 #endif
560
561     Impl *adapter = lookupAdapter(handle);
562     if (!adapter) return 0;
563     return adapter->getRemainingFeatures((Plugin *)handle);
564 }
565
566 void
567 PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs)
568 {
569 #ifdef DEBUG_PLUGIN_ADAPTER
570     std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl;
571 #endif
572 }
573
574 void 
575 PluginAdapterBase::Impl::cleanup(Plugin *plugin)
576 {
577     if (m_fs.find(plugin) != m_fs.end()) {
578         size_t outputCount = 0;
579         if (m_pluginOutputs[plugin]) {
580             outputCount = m_pluginOutputs[plugin]->size();
581         }
582         VampFeatureList *list = m_fs[plugin];
583         for (unsigned int i = 0; i < outputCount; ++i) {
584             for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) {
585                 if (list[i].features[j].label) {
586                     free(list[i].features[j].label);
587                 }
588                 if (list[i].features[j].values) {
589                     free(list[i].features[j].values);
590                 }
591             }
592             if (list[i].features) free(list[i].features);
593         }
594         m_fs.erase(plugin);
595         m_fsizes.erase(plugin);
596         m_fvsizes.erase(plugin);
597     }
598
599     if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) {
600         delete m_pluginOutputs[plugin];
601         m_pluginOutputs.erase(plugin);
602     }
603
604     if (m_adapterMap) {
605         m_adapterMap->erase(plugin);
606
607         if (m_adapterMap->empty()) {
608             delete m_adapterMap;
609             m_adapterMap = 0;
610         }
611     }
612
613     delete ((Plugin *)plugin);
614 }
615
616 void 
617 PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin)
618 {
619     if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() ||
620         !m_pluginOutputs[plugin]) {
621         m_pluginOutputs[plugin] = new Plugin::OutputList
622             (plugin->getOutputDescriptors());
623 //        std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl;
624     }
625 }
626
627 unsigned int 
628 PluginAdapterBase::Impl::getOutputCount(Plugin *plugin)
629 {
630     checkOutputMap(plugin);
631     return m_pluginOutputs[plugin]->size();
632 }
633
634 VampOutputDescriptor *
635 PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin,
636                                        unsigned int i)
637 {
638     checkOutputMap(plugin);
639     Plugin::OutputDescriptor &od =
640         (*m_pluginOutputs[plugin])[i];
641
642     VampOutputDescriptor *desc = (VampOutputDescriptor *)
643         malloc(sizeof(VampOutputDescriptor));
644
645     desc->identifier = strdup(od.identifier.c_str());
646     desc->name = strdup(od.name.c_str());
647     desc->description = strdup(od.description.c_str());
648     desc->unit = strdup(od.unit.c_str());
649     desc->hasFixedBinCount = od.hasFixedBinCount;
650     desc->binCount = od.binCount;
651
652     if (od.hasFixedBinCount && od.binCount > 0) {
653         desc->binNames = (const char **)
654             malloc(od.binCount * sizeof(const char *));
655         
656         for (unsigned int i = 0; i < od.binCount; ++i) {
657             if (i < od.binNames.size()) {
658                 desc->binNames[i] = strdup(od.binNames[i].c_str());
659             } else {
660                 desc->binNames[i] = 0;
661             }
662         }
663     } else {
664         desc->binNames = 0;
665     }
666
667     desc->hasKnownExtents = od.hasKnownExtents;
668     desc->minValue = od.minValue;
669     desc->maxValue = od.maxValue;
670     desc->isQuantized = od.isQuantized;
671     desc->quantizeStep = od.quantizeStep;
672
673     switch (od.sampleType) {
674     case Plugin::OutputDescriptor::OneSamplePerStep:
675         desc->sampleType = vampOneSamplePerStep; break;
676     case Plugin::OutputDescriptor::FixedSampleRate:
677         desc->sampleType = vampFixedSampleRate; break;
678     case Plugin::OutputDescriptor::VariableSampleRate:
679         desc->sampleType = vampVariableSampleRate; break;
680     }
681
682     desc->sampleRate = od.sampleRate;
683
684     return desc;
685 }
686     
687 VampFeatureList *
688 PluginAdapterBase::Impl::process(Plugin *plugin,
689                            const float *const *inputBuffers,
690                            int sec, int nsec)
691 {
692 //    std::cerr << "PluginAdapterBase::Impl::process" << std::endl;
693     RealTime rt(sec, nsec);
694     checkOutputMap(plugin);
695     return convertFeatures(plugin, plugin->process(inputBuffers, rt));
696 }
697     
698 VampFeatureList *
699 PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin)
700 {
701 //    std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl;
702     checkOutputMap(plugin);
703     return convertFeatures(plugin, plugin->getRemainingFeatures());
704 }
705
706 VampFeatureList *
707 PluginAdapterBase::Impl::convertFeatures(Plugin *plugin,
708                                    const Plugin::FeatureSet &features)
709 {
710     int lastN = -1;
711
712     int outputCount = 0;
713     if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size();
714     
715     resizeFS(plugin, outputCount);
716     VampFeatureList *fs = m_fs[plugin];
717
718     for (Plugin::FeatureSet::const_iterator fi = features.begin();
719          fi != features.end(); ++fi) {
720
721         int n = fi->first;
722         
723 //        std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl;
724
725         if (n >= int(outputCount)) {
726             std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl;
727             continue;
728         }
729
730         if (n > lastN + 1) {
731             for (int i = lastN + 1; i < n; ++i) {
732                 fs[i].featureCount = 0;
733             }
734         }
735
736         const Plugin::FeatureList &fl = fi->second;
737
738         size_t sz = fl.size();
739         if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz);
740         fs[n].featureCount = sz;
741         
742         for (size_t j = 0; j < sz; ++j) {
743
744 //            std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl;
745
746             VampFeature *feature = &fs[n].features[j];
747
748             feature->hasTimestamp = fl[j].hasTimestamp;
749             feature->sec = fl[j].timestamp.sec;
750             feature->nsec = fl[j].timestamp.nsec;
751             feature->valueCount = fl[j].values.size();
752
753             if (feature->label) free(feature->label);
754
755             if (fl[j].label.empty()) {
756                 feature->label = 0;
757             } else {
758                 feature->label = strdup(fl[j].label.c_str());
759             }
760
761             if (feature->valueCount > m_fvsizes[plugin][n][j]) {
762                 resizeFV(plugin, n, j, feature->valueCount);
763             }
764
765             for (unsigned int k = 0; k < feature->valueCount; ++k) {
766 //                std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl;
767                 feature->values[k] = fl[j].values[k];
768             }
769         }
770
771         lastN = n;
772     }
773
774     if (lastN == -1) return 0;
775
776     if (int(outputCount) > lastN + 1) {
777         for (int i = lastN + 1; i < int(outputCount); ++i) {
778             fs[i].featureCount = 0;
779         }
780     }
781
782     return fs;
783 }
784
785 void
786 PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n)
787 {
788 //    std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl;
789
790     int i = m_fsizes[plugin].size();
791     if (i >= n) return;
792
793 //    std::cerr << "resizing from " << i << std::endl;
794
795     m_fs[plugin] = (VampFeatureList *)realloc
796         (m_fs[plugin], n * sizeof(VampFeatureList));
797
798     while (i < n) {
799         m_fs[plugin][i].featureCount = 0;
800         m_fs[plugin][i].features = 0;
801         m_fsizes[plugin].push_back(0);
802         m_fvsizes[plugin].push_back(std::vector<size_t>());
803         i++;
804     }
805 }
806
807 void
808 PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz)
809 {
810 //    std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", "
811 //              << sz << ")" << std::endl;
812
813     size_t i = m_fsizes[plugin][n];
814     if (i >= sz) return;
815
816 //    std::cerr << "resizing from " << i << std::endl;
817
818     m_fs[plugin][n].features = (VampFeature *)realloc
819         (m_fs[plugin][n].features, sz * sizeof(VampFeature));
820
821     while (m_fsizes[plugin][n] < sz) {
822         m_fs[plugin][n].features[m_fsizes[plugin][n]].valueCount = 0;
823         m_fs[plugin][n].features[m_fsizes[plugin][n]].values = 0;
824         m_fs[plugin][n].features[m_fsizes[plugin][n]].label = 0;
825         m_fvsizes[plugin][n].push_back(0);
826         m_fsizes[plugin][n]++;
827     }
828 }
829
830 void
831 PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz)
832 {
833 //    std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", "
834 //              << j << ", " << sz << ")" << std::endl;
835
836     size_t i = m_fvsizes[plugin][n][j];
837     if (i >= sz) return;
838
839 //    std::cerr << "resizing from " << i << std::endl;
840
841     m_fs[plugin][n].features[j].values = (float *)realloc
842         (m_fs[plugin][n].features[j].values, sz * sizeof(float));
843
844     m_fvsizes[plugin][n][j] = sz;
845 }
846   
847 PluginAdapterBase::Impl::AdapterMap *
848 PluginAdapterBase::Impl::m_adapterMap = 0;
849
850 }
851