a backward compatible way.
Warning: this code is unstable and experimental and may change
significantly in the coming weeks.
#include "plugins/Tempo.h"
#include "plugins/Silence.h"
+template <typename P>
+class VersionedPluginAdapter : public Vamp::PluginAdapterBase
+{
+public:
+ VersionedPluginAdapter(unsigned int v) : PluginAdapterBase(), m_v(v) { }
+ virtual ~VersionedPluginAdapter() { }
+
+protected:
+ Vamp::Plugin *createPlugin(float inputSampleRate) {
+ P *p = new P(inputSampleRate, m_v);
+ Vamp::Plugin *plugin = dynamic_cast<Vamp::Plugin *>(p);
+ return plugin;
+ }
+ unsigned int m_v;
+};
+
static Vamp::PluginAdapter<Onset> onsetAdapter;
static Vamp::PluginAdapter<Pitch> pitchAdapter;
-static Vamp::PluginAdapter<Notes> notesAdapter;
static Vamp::PluginAdapter<Tempo> tempoAdapter;
-static Vamp::PluginAdapter<Silence> silenceAdapter;
+
+// These two plugins both benefit from the Vamp v2 API if available
+static VersionedPluginAdapter<Notes> *notesAdapter = 0;
+static VersionedPluginAdapter<Silence> *silenceAdapter = 0;
+
+struct Tidy
+{
+ ~Tidy() { delete notesAdapter; delete silenceAdapter; }
+};
+static Tidy tidy;
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int vampApiVersion,
unsigned int index)
switch (index) {
case 0: return onsetAdapter.getDescriptor();
case 1: return pitchAdapter.getDescriptor();
- case 2: return notesAdapter.getDescriptor();
case 3: return tempoAdapter.getDescriptor();
- case 4: return silenceAdapter.getDescriptor();
+
+ case 2:
+ if (!notesAdapter) {
+ notesAdapter = new VersionedPluginAdapter<Notes>(vampApiVersion);
+ }
+ return notesAdapter->getDescriptor();
+
+ case 4:
+ if (!silenceAdapter) {
+ silenceAdapter = new VersionedPluginAdapter<Silence>(vampApiVersion);
+ }
+ return silenceAdapter->getDescriptor();
+
default: return 0;
}
}
Vamp feature extraction plugins using Paul Brossier's Aubio library.
Centre for Digital Music, Queen Mary, University of London.
- This file copyright 2006 Chris Cannam.
+ This file copyright 2006-2008 Chris Cannam and QMUL.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
using std::cerr;
using std::endl;
-Notes::Notes(float inputSampleRate) :
+Notes::Notes(float inputSampleRate, unsigned int apiVersion) :
Plugin(inputSampleRate),
+ m_apiVersion(apiVersion),
m_ibuf(0),
m_fftgrain(0),
m_onset(0),
m_avoidLeaps(false),
m_prevPitch(-1)
{
+ if (apiVersion == 1) {
+ cerr << "vamp-aubio: WARNING: using compatibility version 1 of the Vamp API for note\n"
+ << "tracker plugin: upgrade your host to v2 for proper duration support" << endl;
+ }
}
Notes::~Notes()
int
Notes::getPluginVersion() const
{
- return 1;
+ if (m_apiVersion == 1) return 2;
+ return 3;
}
string
d.name = "Notes";
d.unit = "Hz";
d.hasFixedBinCount = true;
- d.binCount = 2;
- d.binNames.push_back("Frequency");
- d.binNames.push_back("Duration");
- d.binNames.push_back("Velocity");
+
+ if (m_apiVersion == 1) {
+ d.binCount = 3;
+ d.binNames.push_back("Frequency");
+ d.binNames.push_back("Duration");
+ d.binNames.push_back("Velocity");
+ } else {
+ d.binCount = 2;
+ d.binNames.push_back("Frequency");
+ d.binNames.push_back("Velocity");
+ }
+
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleType = OutputDescriptor::VariableSampleRate;
if (m_currentOnset < m_delay) m_currentOnset = m_delay;
feature.timestamp = m_currentOnset - m_delay;
feature.values.push_back(freq);
- feature.values.push_back
- (Vamp::RealTime::realTime2Frame(offTime, lrintf(m_inputSampleRate)) -
- Vamp::RealTime::realTime2Frame(m_currentOnset, lrintf(m_inputSampleRate)));
+
+ if (m_apiVersion == 1) {
+ feature.values.push_back
+ (Vamp::RealTime::realTime2Frame
+ (offTime, lrintf(m_inputSampleRate)) -
+ Vamp::RealTime::realTime2Frame
+ (m_currentOnset, lrintf(m_inputSampleRate)));
+ feature.hasDuration = false;
+ } else {
+ feature.hasDuration = true;
+ feature.duration = offTime - m_currentOnset;
+ }
+
feature.values.push_back(m_currentLevel);
fs[0].push_back(feature);
}
class Notes : public Vamp::Plugin
{
public:
- Notes(float inputSampleRate);
+ Notes(float inputSampleRate, unsigned int apiVersion);
virtual ~Notes();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet getRemainingFeatures();
protected:
+ int m_apiVersion;
fvec_t *m_ibuf;
cvec_t *m_fftgrain;
fvec_t *m_onset;
Vamp feature extraction plugins using Paul Brossier's Aubio library.
Centre for Digital Music, Queen Mary, University of London.
- This file copyright 2006 Chris Cannam.
+ This file copyright 2006-2008 Chris Cannam and QMUL.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
using std::cerr;
using std::endl;
-Silence::Silence(float inputSampleRate) :
+Silence::Silence(float inputSampleRate, unsigned int apiVersion) :
Plugin(inputSampleRate),
+ m_apiVersion(apiVersion),
m_ibuf(0),
m_pbuf(0),
m_tmpptrs(0),
m_prevSilent(false),
m_first(true)
{
+ if (m_apiVersion == 1) {
+ cerr << "vamp-aubio: WARNING: using compatibility version 1 of the Vamp API for silence\n"
+ << "detector plugin: upgrade your host to v2 for proper duration support" << endl;
+ }
}
Silence::~Silence()
int
Silence::getPluginVersion() const
{
- return 1;
+ if (m_apiVersion == 1) return 2;
+ return 3;
}
string
OutputList list;
OutputDescriptor d;
- d.identifier = "silencestart";
- d.name = "Beginnings of Silent Regions";
- d.description = "Return a single instant at the point where each silent region begins";
- d.hasFixedBinCount = true;
- d.binCount = 0;
- d.sampleType = OutputDescriptor::VariableSampleRate;
- d.sampleRate = 0;
- list.push_back(d);
- d.identifier = "silenceend";
- d.name = "Ends of Silent Regions";
- d.description = "Return a single instant at the point where each silent region ends";
- d.hasFixedBinCount = true;
- d.binCount = 0;
- d.sampleType = OutputDescriptor::VariableSampleRate;
- d.sampleRate = 0;
- list.push_back(d);
+ if (m_apiVersion == 1) {
+
+ d.identifier = "silencestart";
+ d.name = "Beginnings of Silent Regions";
+ d.description = "Return a single instant at the point where each silent region begins";
+ d.hasFixedBinCount = true;
+ d.binCount = 0;
+ d.hasKnownExtents = false;
+ d.sampleType = OutputDescriptor::VariableSampleRate;
+ d.sampleRate = 0;
+ list.push_back(d);
+
+ d.identifier = "silenceend";
+ d.name = "Ends of Silent Regions";
+ d.description = "Return a single instant at the point where each silent region ends";
+ d.hasFixedBinCount = true;
+ d.binCount = 0;
+ d.hasKnownExtents = false;
+ d.sampleType = OutputDescriptor::VariableSampleRate;
+ d.sampleRate = 0;
+ list.push_back(d);
+
+ } else {
+
+ d.identifier = "silent";
+ d.name = "Silent Regions";
+ d.description = "Return an interval covering each silent region";
+ d.hasFixedBinCount = true;
+ d.binCount = 0;
+ d.hasKnownExtents = false;
+ d.sampleType = OutputDescriptor::VariableSampleRate;
+ d.sampleRate = 0;
+ list.push_back(d);
+
+ d.identifier = "noisy";
+ d.name = "Non-Silent Regions";
+ d.description = "Return an interval covering each non-silent region";
+ d.hasFixedBinCount = true;
+ d.binCount = 0;
+ d.hasKnownExtents = false;
+ d.sampleType = OutputDescriptor::VariableSampleRate;
+ d.sampleRate = 0;
+ list.push_back(d);
+ }
d.identifier = "silencelevel";
d.name = "Silence Test";
feature.timestamp = featureStamp;
feature.values.push_back(silent ? 0 : 1);
returnFeatures[2].push_back(feature);
+
feature.values.clear();
- if (silent) {
- returnFeatures[0].push_back(feature);
+ if (m_apiVersion == 1) {
+ if (silent) {
+ returnFeatures[0].push_back(feature);
+ } else {
+ returnFeatures[1].push_back(feature);
+ }
} else {
- returnFeatures[1].push_back(feature);
- }
+ if (!m_first) {
+ feature.timestamp = m_lastChange;
+ feature.hasDuration = true;
+ feature.duration = featureStamp - m_lastChange;
+ if (silent) {
+ // becoming silent, so this is a non-silent region
+ returnFeatures[1].push_back(feature);
+ } else {
+ // becoming non-silent, so this is a silent region
+ returnFeatures[0].push_back(feature);
+ }
+ }
+ m_lastChange = featureStamp;
+ }
m_prevSilent = silent;
m_first = false;
m_ibuf->data = m_pbuf->data;
m_pbuf->data = tmpdata;
+ m_lastTimestamp = timestamp;
+
return returnFeatures;
}
Silence::FeatureSet
Silence::getRemainingFeatures()
{
+ FeatureSet returnFeatures;
+
+ if (m_prevSilent) {
+ if (m_lastTimestamp > m_lastChange) {
+ Feature feature;
+ feature.hasTimestamp = true;
+ feature.timestamp = m_lastChange;
+ feature.hasDuration = true;
+ feature.duration = m_lastTimestamp - m_lastChange;
+ if (m_prevSilent) {
+ returnFeatures[0].push_back(feature);
+ } else {
+ returnFeatures[1].push_back(feature);
+ }
+ }
+ }
+
return FeatureSet();
}
class Silence : public Vamp::Plugin
{
public:
- Silence(float inputSampleRate);
+ Silence(float inputSampleRate, unsigned int apiVersion);
virtual ~Silence();
bool initialise(size_t channels, size_t stepSize, size_t blockSize);
FeatureSet getRemainingFeatures();
protected:
+ unsigned int m_apiVersion;
fvec_t *m_ibuf;
fvec_t *m_pbuf;
smpl_t **m_tmpptrs;
size_t m_channelCount;
bool m_prevSilent;
bool m_first;
+ Vamp::RealTime m_lastChange;
+ Vamp::RealTime m_lastTimestamp;
};