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