# HG changeset patch # User cannam # Date 1225980333 0 # Node ID 14029eb084723b39dc3ec73d5f37735fa43940be # Parent f8b38a017d9a9155e09fe96b72890380bb6331b3 * start moving things about diff -r f8b38a017d9a -r 14029eb08472 examples/AmplitudeFollower.cpp --- a/examples/AmplitudeFollower.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Dan Stowell. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "AmplitudeFollower.h" - -#include - -#include -#include -#include - -using std::string; -using std::vector; -using std::cerr; -using std::endl; - -/** - * An implementation of SuperCollider's amplitude-follower algorithm - * as a simple Vamp plugin. - */ - -AmplitudeFollower::AmplitudeFollower(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_previn(0.0f), - m_clampcoef(0.01f), - m_relaxcoef(0.01f) -{ -} - -AmplitudeFollower::~AmplitudeFollower() -{ -} - -string -AmplitudeFollower::getIdentifier() const -{ - return "amplitudefollower"; -} - -string -AmplitudeFollower::getName() const -{ - return "Amplitude Follower"; -} - -string -AmplitudeFollower::getDescription() const -{ - return "Track the amplitude of the audio signal"; -} - -string -AmplitudeFollower::getMaker() const -{ - return "Vamp SDK Example Plugins"; -} - -int -AmplitudeFollower::getPluginVersion() const -{ - return 1; -} - -string -AmplitudeFollower::getCopyright() const -{ - return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)"; -} - -bool -AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = std::min(stepSize, blockSize); - - // Translate the coefficients - // from their "convenient" 60dB convergence-time values - // to real coefficients - m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate)); - m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate)); - - return true; -} - -void -AmplitudeFollower::reset() -{ - m_previn = 0.0f; -} - -AmplitudeFollower::OutputList -AmplitudeFollower::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor sca; - sca.identifier = "amplitude"; - sca.name = "Amplitude"; - sca.description = ""; - sca.unit = "V"; - sca.hasFixedBinCount = true; - sca.binCount = 1; - sca.hasKnownExtents = false; - sca.isQuantized = false; - sca.sampleType = OutputDescriptor::OneSamplePerStep; - list.push_back(sca); - - return list; -} - -AmplitudeFollower::ParameterList -AmplitudeFollower::getParameterDescriptors() const -{ - ParameterList list; - - ParameterDescriptor att; - att.identifier = "attack"; - att.name = "Attack time"; - att.description = ""; - att.unit = "s"; - att.minValue = 0.0f; - att.maxValue = 1.f; - att.defaultValue = 0.01f; - att.isQuantized = false; - - list.push_back(att); - - ParameterDescriptor dec; - dec.identifier = "release"; - dec.name = "Release time"; - dec.description = ""; - dec.unit = "s"; - dec.minValue = 0.0f; - dec.maxValue = 1.f; - dec.defaultValue = 0.01f; - dec.isQuantized = false; - - list.push_back(dec); - - return list; -} - -void AmplitudeFollower::setParameter(std::string paramid, float newval) -{ - if (paramid == "attack") { - m_clampcoef = newval; - } else if (paramid == "release") { - m_relaxcoef = newval; - } -} - -float AmplitudeFollower::getParameter(std::string paramid) const -{ - if (paramid == "attack") { - return m_clampcoef; - } else if (paramid == "release") { - return m_relaxcoef; - } - - return 0.0f; -} - -AmplitudeFollower::FeatureSet -AmplitudeFollower::process(const float *const *inputBuffers, - Vamp::RealTime timestamp) -{ - if (m_stepSize == 0) { - cerr << "ERROR: AmplitudeFollower::process: " - << "AmplitudeFollower has not been initialised" - << endl; - return FeatureSet(); - } - - float previn = m_previn; - - FeatureSet returnFeatures; - - float val; - float peak = 0.0f; - - for (size_t i = 0; i < m_stepSize; ++i) { - - val = fabs(inputBuffers[0][i]); - - if (val < previn) { - val = val + (previn - val) * m_relaxcoef; - } else { - val = val + (previn - val) * m_clampcoef; - } - - if (val > peak) peak = val; - previn = val; - } - - m_previn = previn; - - // Now store the "feature" (peak amp) for this sample - Feature feature; - feature.hasTimestamp = false; - feature.values.push_back(peak); - returnFeatures[0].push_back(feature); - - return returnFeatures; -} - -AmplitudeFollower::FeatureSet -AmplitudeFollower::getRemainingFeatures() -{ - return FeatureSet(); -} - diff -r f8b38a017d9a -r 14029eb08472 examples/FixedTempoEstimator.cpp --- a/examples/FixedTempoEstimator.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,534 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006-2008 Chris Cannam and QMUL. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "FixedTempoEstimator.h" - -using std::string; -using std::vector; -using std::cerr; -using std::endl; - -using Vamp::RealTime; - -#include - - -FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_blockSize(0), - m_priorMagnitudes(0), - m_df(0), - m_r(0), - m_fr(0), - m_t(0), - m_n(0) -{ -} - -FixedTempoEstimator::~FixedTempoEstimator() -{ - delete[] m_priorMagnitudes; - delete[] m_df; - delete[] m_r; - delete[] m_fr; - delete[] m_t; -} - -string -FixedTempoEstimator::getIdentifier() const -{ - return "fixedtempo"; -} - -string -FixedTempoEstimator::getName() const -{ - return "Simple Fixed Tempo Estimator"; -} - -string -FixedTempoEstimator::getDescription() const -{ - return "Study a short section of audio and estimate its tempo, assuming the tempo is constant"; -} - -string -FixedTempoEstimator::getMaker() const -{ - return "Vamp SDK Example Plugins"; -} - -int -FixedTempoEstimator::getPluginVersion() const -{ - return 1; -} - -string -FixedTempoEstimator::getCopyright() const -{ - return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)"; -} - -size_t -FixedTempoEstimator::getPreferredStepSize() const -{ - return 64; -} - -size_t -FixedTempoEstimator::getPreferredBlockSize() const -{ - return 256; -} - -bool -FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = stepSize; - m_blockSize = blockSize; - - float dfLengthSecs = 10.f; - m_dfsize = (dfLengthSecs * m_inputSampleRate) / m_stepSize; - - m_priorMagnitudes = new float[m_blockSize/2]; - m_df = new float[m_dfsize]; - - for (size_t i = 0; i < m_blockSize/2; ++i) { - m_priorMagnitudes[i] = 0.f; - } - for (size_t i = 0; i < m_dfsize; ++i) { - m_df[i] = 0.f; - } - - m_n = 0; - - return true; -} - -void -FixedTempoEstimator::reset() -{ - cerr << "FixedTempoEstimator: reset called" << endl; - - if (!m_priorMagnitudes) return; - - cerr << "FixedTempoEstimator: resetting" << endl; - - for (size_t i = 0; i < m_blockSize/2; ++i) { - m_priorMagnitudes[i] = 0.f; - } - for (size_t i = 0; i < m_dfsize; ++i) { - m_df[i] = 0.f; - } - - delete[] m_r; - m_r = 0; - - delete[] m_fr; - m_fr = 0; - - delete[] m_t; - m_t = 0; - - m_n = 0; - - m_start = RealTime::zeroTime; - m_lasttime = RealTime::zeroTime; -} - -FixedTempoEstimator::ParameterList -FixedTempoEstimator::getParameterDescriptors() const -{ - ParameterList list; - return list; -} - -float -FixedTempoEstimator::getParameter(std::string id) const -{ - return 0.f; -} - -void -FixedTempoEstimator::setParameter(std::string id, float value) -{ -} - -static int TempoOutput = 0; -static int CandidatesOutput = 1; -static int DFOutput = 2; -static int ACFOutput = 3; -static int FilteredACFOutput = 4; - -FixedTempoEstimator::OutputList -FixedTempoEstimator::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor d; - d.identifier = "tempo"; - d.name = "Tempo"; - d.description = "Estimated tempo"; - d.unit = "bpm"; - d.hasFixedBinCount = true; - d.binCount = 1; - d.hasKnownExtents = false; - d.isQuantized = false; - d.sampleType = OutputDescriptor::VariableSampleRate; - d.sampleRate = m_inputSampleRate; - d.hasDuration = true; // our returned tempo spans a certain range - list.push_back(d); - - d.identifier = "candidates"; - d.name = "Tempo candidates"; - d.description = "Possible tempo estimates, one per bin with the most likely in the first bin"; - d.unit = "bpm"; - d.hasFixedBinCount = false; - list.push_back(d); - - d.identifier = "detectionfunction"; - d.name = "Detection Function"; - d.description = "Onset detection function"; - d.unit = ""; - d.hasFixedBinCount = 1; - d.binCount = 1; - d.hasKnownExtents = true; - d.minValue = 0.0; - d.maxValue = 1.0; - d.isQuantized = false; - d.quantizeStep = 0.0; - d.sampleType = OutputDescriptor::FixedSampleRate; - if (m_stepSize) { - d.sampleRate = m_inputSampleRate / m_stepSize; - } else { - d.sampleRate = m_inputSampleRate / (getPreferredBlockSize()/2); - } - d.hasDuration = false; - list.push_back(d); - - d.identifier = "acf"; - d.name = "Autocorrelation Function"; - d.description = "Autocorrelation of onset detection function"; - d.hasKnownExtents = false; - d.unit = "r"; - list.push_back(d); - - d.identifier = "filtered_acf"; - d.name = "Filtered Autocorrelation"; - d.description = "Filtered autocorrelation of onset detection function"; - d.unit = "r"; - list.push_back(d); - - return list; -} - -FixedTempoEstimator::FeatureSet -FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts) -{ - FeatureSet fs; - - if (m_stepSize == 0) { - cerr << "ERROR: FixedTempoEstimator::process: " - << "FixedTempoEstimator has not been initialised" - << endl; - return fs; - } - -// if (m_n < m_dfsize) cerr << "m_n = " << m_n << endl; - - if (m_n == 0) m_start = ts; - m_lasttime = ts; - - if (m_n == m_dfsize) { - calculate(); - fs = assembleFeatures(); - ++m_n; - return fs; - } - - if (m_n > m_dfsize) return FeatureSet(); - - float value = 0.f; - - for (size_t i = 1; i < m_blockSize/2; ++i) { - - float real = inputBuffers[0][i*2]; - float imag = inputBuffers[0][i*2 + 1]; - - float sqrmag = real * real + imag * imag; - value += fabsf(sqrmag - m_priorMagnitudes[i]); - - m_priorMagnitudes[i] = sqrmag; - } - - m_df[m_n] = value; - - ++m_n; - return fs; -} - -FixedTempoEstimator::FeatureSet -FixedTempoEstimator::getRemainingFeatures() -{ - FeatureSet fs; - if (m_n > m_dfsize) return fs; - calculate(); - fs = assembleFeatures(); - ++m_n; - return fs; -} - -float -FixedTempoEstimator::lag2tempo(int lag) -{ - return 60.f / ((lag * m_stepSize) / m_inputSampleRate); -} - -int -FixedTempoEstimator::tempo2lag(float tempo) -{ - return ((60.f / tempo) * m_inputSampleRate) / m_stepSize; -} - -void -FixedTempoEstimator::calculate() -{ - cerr << "FixedTempoEstimator::calculate: m_n = " << m_n << endl; - - if (m_r) { - cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl; - return; - } - - if (m_n < m_dfsize / 9) { - cerr << "FixedTempoEstimator::calculate: Not enough data to go on (have " << m_n << ", want at least " << m_dfsize/4 << ")" << endl; - return; // not enough data (perhaps we should return the duration of the input as the "estimated" beat length?) - } - - int n = m_n; - - m_r = new float[n/2]; - m_fr = new float[n/2]; - m_t = new float[n/2]; - - for (int i = 0; i < n/2; ++i) { - m_r[i] = 0.f; - m_fr[i] = 0.f; - m_t[i] = lag2tempo(i); - } - - for (int i = 0; i < n/2; ++i) { - - for (int j = i; j < n-1; ++j) { - m_r[i] += m_df[j] * m_df[j - i]; - } - - m_r[i] /= n - i - 1; - } - - float related[] = { 0.5, 2, 3, 4 }; - - for (int i = 1; i < n/2-1; ++i) { - - float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005; - if (weight < 0.f) weight = 0.f; - weight = weight * weight * weight; - - m_fr[i] = m_r[i]; - - int div = 1; - - for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) { - - int k0 = int(i * related[j] + 0.5); - - if (k0 >= 0 && k0 < int(n/2)) { - - int kmax = 0, kmin = 0; - float kvmax = 0, kvmin = 0; - bool have = false; - - for (int k = k0 - 1; k <= k0 + 1; ++k) { - - if (k < 0 || k >= n/2) continue; - - if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; } - if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; } - - have = true; - } - - m_fr[i] += m_r[kmax] / 5; - - if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) && - (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) && - kvmax > kvmin * 1.05) { - - m_t[i] = m_t[i] + lag2tempo(kmax) * related[j]; - ++div; - } - } - } - - m_t[i] /= div; - -// if (div > 1) { -// cerr << "adjusting tempo from " << lag2tempo(i) << " to " -// << m_t[i] << " for fr = " << m_fr[i] << " (div = " << div << ")" << endl; -// } - - m_fr[i] += m_fr[i] * (weight / 3); - } -} - - -FixedTempoEstimator::FeatureSet -FixedTempoEstimator::assembleFeatures() -{ - FeatureSet fs; - if (!m_r) return fs; // No results - - Feature feature; - feature.hasTimestamp = true; - feature.hasDuration = false; - feature.label = ""; - feature.values.clear(); - feature.values.push_back(0.f); - - char buffer[40]; - - int n = m_n; - - for (int i = 0; i < n; ++i) { - feature.timestamp = m_start + - RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); - feature.values[0] = m_df[i]; - feature.label = ""; - fs[DFOutput].push_back(feature); - } - - for (int i = 1; i < n/2; ++i) { - feature.timestamp = m_start + - RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); - feature.values[0] = m_r[i]; - sprintf(buffer, "%.1f bpm", lag2tempo(i)); - if (i == n/2-1) feature.label = ""; - else feature.label = buffer; - fs[ACFOutput].push_back(feature); - } - - float t0 = 50.f; // our minimum detected tempo (could be a parameter) - float t1 = 190.f; // our maximum detected tempo - - //!!! need some way for the host (or at least, the user) to know - //!!! that it should only pass a certain amount of - //!!! input... e.g. by making the amount configurable - - int p0 = tempo2lag(t1); - int p1 = tempo2lag(t0); - - std::map candidates; - - for (int i = p0; i <= p1 && i < n/2-1; ++i) { - - if (m_fr[i] > m_fr[i-1] && - m_fr[i] > m_fr[i+1]) { - candidates[m_fr[i]] = i; - } - - feature.timestamp = m_start + - RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); - feature.values[0] = m_fr[i]; - sprintf(buffer, "%.1f bpm", lag2tempo(i)); - if (i == p1 || i == n/2-2) feature.label = ""; - else feature.label = buffer; - fs[FilteredACFOutput].push_back(feature); - } - -// cerr << "maxpi = " << maxpi << " for tempo " << lag2tempo(maxpi) << " (value = " << maxp << ")" << endl; - - if (candidates.empty()) { - cerr << "No tempo candidates!" << endl; - return fs; - } - - feature.hasTimestamp = true; - feature.timestamp = m_start; - - feature.hasDuration = true; - feature.duration = m_lasttime - m_start; - - std::map::const_iterator ci = candidates.end(); - --ci; - int maxpi = ci->second; - - if (m_t[maxpi] > 0) { - cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl; - feature.values[0] = m_t[maxpi]; - } else { - // shouldn't happen -- it would imply that this high value was not a peak! - feature.values[0] = lag2tempo(maxpi); - cerr << "WARNING: No stored tempo for index " << maxpi << endl; - } - - sprintf(buffer, "%.1f bpm", feature.values[0]); - feature.label = buffer; - - fs[TempoOutput].push_back(feature); - - feature.values.clear(); - feature.label = ""; - - while (feature.values.size() < 8) { -// cerr << "adding tempo value from lag " << ci->second << endl; - if (m_t[ci->second] > 0) { - feature.values.push_back(m_t[ci->second]); - } else { - feature.values.push_back(lag2tempo(ci->second)); - } - if (ci == candidates.begin()) break; - --ci; - } - - fs[CandidatesOutput].push_back(feature); - - return fs; -} diff -r f8b38a017d9a -r 14029eb08472 examples/PercussionOnsetDetector.cpp --- a/examples/PercussionOnsetDetector.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,285 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "PercussionOnsetDetector.h" - -using std::string; -using std::vector; -using std::cerr; -using std::endl; - -#include - - -PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_blockSize(0), - m_threshold(3), - m_sensitivity(40), - m_priorMagnitudes(0), - m_dfMinus1(0), - m_dfMinus2(0) -{ -} - -PercussionOnsetDetector::~PercussionOnsetDetector() -{ - delete[] m_priorMagnitudes; -} - -string -PercussionOnsetDetector::getIdentifier() const -{ - return "percussiononsets"; -} - -string -PercussionOnsetDetector::getName() const -{ - return "Simple Percussion Onset Detector"; -} - -string -PercussionOnsetDetector::getDescription() const -{ - return "Detect percussive note onsets by identifying broadband energy rises"; -} - -string -PercussionOnsetDetector::getMaker() const -{ - return "Vamp SDK Example Plugins"; -} - -int -PercussionOnsetDetector::getPluginVersion() const -{ - return 2; -} - -string -PercussionOnsetDetector::getCopyright() const -{ - return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)"; -} - -size_t -PercussionOnsetDetector::getPreferredStepSize() const -{ - return 0; -} - -size_t -PercussionOnsetDetector::getPreferredBlockSize() const -{ - return 1024; -} - -bool -PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = stepSize; - m_blockSize = blockSize; - - m_priorMagnitudes = new float[m_blockSize/2]; - - for (size_t i = 0; i < m_blockSize/2; ++i) { - m_priorMagnitudes[i] = 0.f; - } - - m_dfMinus1 = 0.f; - m_dfMinus2 = 0.f; - - return true; -} - -void -PercussionOnsetDetector::reset() -{ - for (size_t i = 0; i < m_blockSize/2; ++i) { - m_priorMagnitudes[i] = 0.f; - } - - m_dfMinus1 = 0.f; - m_dfMinus2 = 0.f; -} - -PercussionOnsetDetector::ParameterList -PercussionOnsetDetector::getParameterDescriptors() const -{ - ParameterList list; - - ParameterDescriptor d; - d.identifier = "threshold"; - d.name = "Energy rise threshold"; - d.description = "Energy rise within a frequency bin necessary to count toward broadband total"; - d.unit = "dB"; - d.minValue = 0; - d.maxValue = 20; - d.defaultValue = 3; - d.isQuantized = false; - list.push_back(d); - - d.identifier = "sensitivity"; - d.name = "Sensitivity"; - d.description = "Sensitivity of peak detector applied to broadband detection function"; - d.unit = "%"; - d.minValue = 0; - d.maxValue = 100; - d.defaultValue = 40; - d.isQuantized = false; - list.push_back(d); - - return list; -} - -float -PercussionOnsetDetector::getParameter(std::string id) const -{ - if (id == "threshold") return m_threshold; - if (id == "sensitivity") return m_sensitivity; - return 0.f; -} - -void -PercussionOnsetDetector::setParameter(std::string id, float value) -{ - if (id == "threshold") { - if (value < 0) value = 0; - if (value > 20) value = 20; - m_threshold = value; - } else if (id == "sensitivity") { - if (value < 0) value = 0; - if (value > 100) value = 100; - m_sensitivity = value; - } -} - -PercussionOnsetDetector::OutputList -PercussionOnsetDetector::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor d; - d.identifier = "onsets"; - d.name = "Onsets"; - d.description = "Percussive note onset locations"; - d.unit = ""; - d.hasFixedBinCount = true; - d.binCount = 0; - d.hasKnownExtents = false; - d.isQuantized = false; - d.sampleType = OutputDescriptor::VariableSampleRate; - d.sampleRate = m_inputSampleRate; - list.push_back(d); - - d.identifier = "detectionfunction"; - d.name = "Detection Function"; - d.description = "Broadband energy rise detection function"; - d.binCount = 1; - d.isQuantized = true; - d.quantizeStep = 1.0; - d.sampleType = OutputDescriptor::OneSamplePerStep; - list.push_back(d); - - return list; -} - -PercussionOnsetDetector::FeatureSet -PercussionOnsetDetector::process(const float *const *inputBuffers, - Vamp::RealTime ts) -{ - if (m_stepSize == 0) { - cerr << "ERROR: PercussionOnsetDetector::process: " - << "PercussionOnsetDetector has not been initialised" - << endl; - return FeatureSet(); - } - - int count = 0; - - for (size_t i = 1; i < m_blockSize/2; ++i) { - - float real = inputBuffers[0][i*2]; - float imag = inputBuffers[0][i*2 + 1]; - - float sqrmag = real * real + imag * imag; - - if (m_priorMagnitudes[i] > 0.f) { - float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]); - -// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl; - - if (diff >= m_threshold) ++count; - } - - m_priorMagnitudes[i] = sqrmag; - } - - FeatureSet returnFeatures; - - Feature detectionFunction; - detectionFunction.hasTimestamp = false; - detectionFunction.values.push_back(count); - returnFeatures[1].push_back(detectionFunction); - - if (m_dfMinus2 < m_dfMinus1 && - m_dfMinus1 >= count && - m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) { - - Feature onset; - onset.hasTimestamp = true; - onset.timestamp = ts - Vamp::RealTime::frame2RealTime - (m_stepSize, int(m_inputSampleRate + 0.5)); - returnFeatures[0].push_back(onset); - } - - m_dfMinus2 = m_dfMinus1; - m_dfMinus1 = count; - - return returnFeatures; -} - -PercussionOnsetDetector::FeatureSet -PercussionOnsetDetector::getRemainingFeatures() -{ - return FeatureSet(); -} - diff -r f8b38a017d9a -r 14029eb08472 examples/SpectralCentroid.cpp --- a/examples/SpectralCentroid.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "SpectralCentroid.h" - -using std::string; -using std::vector; -using std::cerr; -using std::endl; - -#include - -#ifdef WIN32 -#define isnan(x) false -#define isinf(x) false -#endif - -SpectralCentroid::SpectralCentroid(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_blockSize(0) -{ -} - -SpectralCentroid::~SpectralCentroid() -{ -} - -string -SpectralCentroid::getIdentifier() const -{ - return "spectralcentroid"; -} - -string -SpectralCentroid::getName() const -{ - return "Spectral Centroid"; -} - -string -SpectralCentroid::getDescription() const -{ - return "Calculate the centroid frequency of the spectrum of the input signal"; -} - -string -SpectralCentroid::getMaker() const -{ - return "Vamp SDK Example Plugins"; -} - -int -SpectralCentroid::getPluginVersion() const -{ - return 2; -} - -string -SpectralCentroid::getCopyright() const -{ - return "Freely redistributable (BSD license)"; -} - -bool -SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = stepSize; - m_blockSize = blockSize; - - return true; -} - -void -SpectralCentroid::reset() -{ -} - -SpectralCentroid::OutputList -SpectralCentroid::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor d; - d.identifier = "logcentroid"; - d.name = "Log Frequency Centroid"; - d.description = "Centroid of the log weighted frequency spectrum"; - d.unit = "Hz"; - d.hasFixedBinCount = true; - d.binCount = 1; - d.hasKnownExtents = false; - d.isQuantized = false; - d.sampleType = OutputDescriptor::OneSamplePerStep; - list.push_back(d); - - d.identifier = "linearcentroid"; - d.name = "Linear Frequency Centroid"; - d.description = "Centroid of the linear frequency spectrum"; - list.push_back(d); - - return list; -} - -//static int scount = 0; - -SpectralCentroid::FeatureSet -SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp) -{ - if (m_stepSize == 0) { - cerr << "ERROR: SpectralCentroid::process: " - << "SpectralCentroid has not been initialised" - << endl; - return FeatureSet(); - } - -// std::cerr << "SpectralCentroid::process: count = " << scount++ << ", timestamp = " << timestamp << ", total power = "; - - double numLin = 0.0, numLog = 0.0, denom = 0.0; - - for (size_t i = 1; i <= m_blockSize/2; ++i) { - double freq = (double(i) * m_inputSampleRate) / m_blockSize; - double real = inputBuffers[0][i*2]; - double imag = inputBuffers[0][i*2 + 1]; - double power = sqrt(real * real + imag * imag) / (m_blockSize/2); - numLin += freq * power; - numLog += log10f(freq) * power; - denom += power; - } - -// std::cerr << denom << std::endl; - - FeatureSet returnFeatures; - - if (denom != 0.0) { - float centroidLin = float(numLin / denom); - float centroidLog = powf(10, float(numLog / denom)); - - Feature feature; - feature.hasTimestamp = false; - if (!isnan(centroidLog) && !isinf(centroidLog)) { - feature.values.push_back(centroidLog); - } - returnFeatures[0].push_back(feature); - - feature.values.clear(); - if (!isnan(centroidLin) && !isinf(centroidLin)) { - feature.values.push_back(centroidLin); - } - returnFeatures[1].push_back(feature); - } - - return returnFeatures; -} - -SpectralCentroid::FeatureSet -SpectralCentroid::getRemainingFeatures() -{ - return FeatureSet(); -} - diff -r f8b38a017d9a -r 14029eb08472 examples/ZeroCrossing.cpp --- a/examples/ZeroCrossing.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "ZeroCrossing.h" - -using std::string; -using std::vector; -using std::cerr; -using std::endl; - -#include - -ZeroCrossing::ZeroCrossing(float inputSampleRate) : - Plugin(inputSampleRate), - m_stepSize(0), - m_previousSample(0.0f) -{ -} - -ZeroCrossing::~ZeroCrossing() -{ -} - -string -ZeroCrossing::getIdentifier() const -{ - return "zerocrossing"; -} - -string -ZeroCrossing::getName() const -{ - return "Zero Crossings"; -} - -string -ZeroCrossing::getDescription() const -{ - return "Detect and count zero crossing points"; -} - -string -ZeroCrossing::getMaker() const -{ - return "Vamp SDK Example Plugins"; -} - -int -ZeroCrossing::getPluginVersion() const -{ - return 2; -} - -string -ZeroCrossing::getCopyright() const -{ - return "Freely redistributable (BSD license)"; -} - -bool -ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize) -{ - if (channels < getMinChannelCount() || - channels > getMaxChannelCount()) return false; - - m_stepSize = std::min(stepSize, blockSize); - - return true; -} - -void -ZeroCrossing::reset() -{ - m_previousSample = 0.0f; -} - -ZeroCrossing::OutputList -ZeroCrossing::getOutputDescriptors() const -{ - OutputList list; - - OutputDescriptor zc; - zc.identifier = "counts"; - zc.name = "Zero Crossing Counts"; - zc.description = "The number of zero crossing points per processing block"; - zc.unit = "crossings"; - zc.hasFixedBinCount = true; - zc.binCount = 1; - zc.hasKnownExtents = false; - zc.isQuantized = true; - zc.quantizeStep = 1.0; - zc.sampleType = OutputDescriptor::OneSamplePerStep; - list.push_back(zc); - - zc.identifier = "zerocrossings"; - zc.name = "Zero Crossings"; - zc.description = "The locations of zero crossing points"; - zc.unit = ""; - zc.hasFixedBinCount = true; - zc.binCount = 0; - zc.sampleType = OutputDescriptor::VariableSampleRate; - zc.sampleRate = m_inputSampleRate; - list.push_back(zc); - - return list; -} - -//static int scount = 0; - -ZeroCrossing::FeatureSet -ZeroCrossing::process(const float *const *inputBuffers, - Vamp::RealTime timestamp) -{ - if (m_stepSize == 0) { - cerr << "ERROR: ZeroCrossing::process: " - << "ZeroCrossing has not been initialised" - << endl; - return FeatureSet(); - } - -// std::cerr << "ZeroCrossing::process: count = " << scount++ << ", timestamp = " << timestamp << ", rms = "; - - float prev = m_previousSample; - size_t count = 0; - - FeatureSet returnFeatures; - -// double acc = 0.0; - - for (size_t i = 0; i < m_stepSize; ++i) { - - float sample = inputBuffers[0][i]; - bool crossing = false; - - if (sample <= 0.0) { - if (prev > 0.0) crossing = true; - } else if (sample > 0.0) { - if (prev <= 0.0) crossing = true; - } - - if (crossing) { - ++count; - Feature feature; - feature.hasTimestamp = true; - feature.timestamp = timestamp + - Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate); - returnFeatures[1].push_back(feature); - } - -// acc += sample * sample; - - prev = sample; - } - -// acc /= m_stepSize; -// std::cerr << sqrt(acc) << std::endl; - - m_previousSample = prev; - - Feature feature; - feature.hasTimestamp = false; - feature.values.push_back(count); - - returnFeatures[0].push_back(feature); - return returnFeatures; -} - -ZeroCrossing::FeatureSet -ZeroCrossing::getRemainingFeatures() -{ - return FeatureSet(); -} - diff -r f8b38a017d9a -r 14029eb08472 examples/plugins.cpp --- a/examples/plugins.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "vamp/vamp.h" -#include "vamp-sdk/PluginAdapter.h" - -#include "ZeroCrossing.h" -#include "SpectralCentroid.h" -#include "PercussionOnsetDetector.h" -#include "FixedTempoEstimator.h" -#include "AmplitudeFollower.h" - -static Vamp::PluginAdapter zeroCrossingAdapter; -static Vamp::PluginAdapter spectralCentroidAdapter; -static Vamp::PluginAdapter percussionOnsetAdapter; -static Vamp::PluginAdapter fixedTempoAdapter; -static Vamp::PluginAdapter amplitudeAdapter; - -const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version, - unsigned int index) -{ - if (version < 1) return 0; - - switch (index) { - case 0: return zeroCrossingAdapter.getDescriptor(); - case 1: return spectralCentroidAdapter.getDescriptor(); - case 2: return percussionOnsetAdapter.getDescriptor(); - case 3: return amplitudeAdapter.getDescriptor(); - case 4: return fixedTempoAdapter.getDescriptor(); - default: return 0; - } -} - diff -r f8b38a017d9a -r 14029eb08472 host/vamp-simple-host.cpp --- a/host/vamp-simple-host.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,644 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - FFT code from Don Cross's public domain FFT implementation. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "vamp-sdk/PluginHostAdapter.h" -#include "vamp-sdk/hostext/PluginInputDomainAdapter.h" -#include "vamp-sdk/hostext/PluginLoader.h" -#include "vamp/vamp.h" - -#include -#include -#include -#include - -#include -#include - -#include "system.h" - -#include - -using namespace std; - -using Vamp::Plugin; -using Vamp::PluginHostAdapter; -using Vamp::RealTime; -using Vamp::HostExt::PluginLoader; -using Vamp::HostExt::PluginWrapper; -using Vamp::HostExt::PluginInputDomainAdapter; - -#define HOST_VERSION "1.3" - -enum Verbosity { - PluginIds, - PluginOutputIds, - PluginInformation -}; - -void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); -void transformInput(float *, size_t); -void fft(unsigned int, bool, double *, double *, double *, double *); -void printPluginPath(bool verbose); -void printPluginCategoryList(); -void enumeratePlugins(Verbosity); -void listPluginsInLibrary(string soname); -int runPlugin(string myname, string soname, string id, string output, - int outputNo, string inputFile, string outfilename, bool frames); - -void usage(const char *name) -{ - cerr << "\n" - << name << ": A simple Vamp plugin host.\n\n" - "Centre for Digital Music, Queen Mary, University of London.\n" - "Copyright 2006-2007 Chris Cannam and QMUL.\n" - "Freely redistributable; published under a BSD-style license.\n\n" - "Usage:\n\n" - " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" - " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n" - " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" - " audio data in \"file.wav\", retrieving the named \"output\", or output\n" - " number \"outputno\" (the first output by default) and dumping it to\n" - " standard output, or to \"out.txt\" if the -o option is given.\n\n" - " \"pluginlibrary\" should be a library name, not a file path; the\n" - " standard Vamp library search path will be used to locate it. If\n" - " a file path is supplied, the directory part(s) will be ignored.\n\n" - " If the -s option is given, results will be labelled with the audio\n" - " sample frame at which they occur. Otherwise, they will be labelled\n" - " with time in seconds.\n\n" - " " << name << " -l\n\n" - " -- List the plugin libraries and Vamp plugins in the library search path\n" - " in a verbose human-readable format.\n\n" - " " << name << " --list-ids\n\n" - " -- List the plugins in the search path in a terse machine-readable format,\n" - " in the form vamp:soname:identifier.\n\n" - " " << name << " --list-outputs\n\n" - " -- List the outputs for plugins in the search path in a machine-readable\n" - " format, in the form vamp:soname:identifier:output.\n\n" - " " << name << " --list-by-category\n\n" - " -- List the plugins as a plugin index by category, in a machine-readable\n" - " format. The format may change in future releases.\n\n" - " " << name << " -p\n\n" - " -- Print out the Vamp library search path.\n\n" - " " << name << " -v\n\n" - " -- Display version information only.\n" - << endl; - exit(2); -} - -int main(int argc, char **argv) -{ - char *scooter = argv[0]; - char *name = 0; - while (scooter && *scooter) { - if (*scooter == '/' || *scooter == '\\') name = ++scooter; - else ++scooter; - } - if (!name || !*name) name = argv[0]; - - if (argc < 2) usage(name); - - if (argc == 2) { - - if (!strcmp(argv[1], "-v")) { - - cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl - << "Vamp API version: " << VAMP_API_VERSION << endl - << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; - return 0; - - } else if (!strcmp(argv[1], "-l")) { - - printPluginPath(true); - enumeratePlugins(PluginInformation); - return 0; - - } else if (!strcmp(argv[1], "-p")) { - - printPluginPath(false); - return 0; - - } else if (!strcmp(argv[1], "--list-ids")) { - - enumeratePlugins(PluginIds); - return 0; - - } else if (!strcmp(argv[1], "--list-outputs")) { - - enumeratePlugins(PluginOutputIds); - return 0; - - } else if (!strcmp(argv[1], "--list-by-category")) { - - printPluginCategoryList(); - return 0; - - } else usage(name); - } - - if (argc < 3) usage(name); - - bool useFrames = false; - - int base = 1; - if (!strcmp(argv[1], "-s")) { - useFrames = true; - base = 2; - } - - string soname = argv[base]; - string wavname = argv[base+1]; - string plugid = ""; - string output = ""; - int outputNo = -1; - string outfilename; - - if (argc >= base+3) { - - int idx = base+2; - - if (isdigit(*argv[idx])) { - outputNo = atoi(argv[idx++]); - } - - if (argc == idx + 2) { - if (!strcmp(argv[idx], "-o")) { - outfilename = argv[idx+1]; - } else usage(name); - } else if (argc != idx) { - (usage(name)); - } - } - - cerr << endl << name << ": Running..." << endl; - - cerr << "Reading file: \"" << wavname << "\", writing to "; - if (outfilename == "") { - cerr << "standard output" << endl; - } else { - cerr << "\"" << outfilename << "\"" << endl; - } - - string::size_type sep = soname.find(':'); - - if (sep != string::npos) { - plugid = soname.substr(sep + 1); - soname = soname.substr(0, sep); - - sep = plugid.find(':'); - if (sep != string::npos) { - output = plugid.substr(sep + 1); - plugid = plugid.substr(0, sep); - } - } - - if (plugid == "") { - usage(name); - } - - if (output != "" && outputNo != -1) { - usage(name); - } - - if (output == "" && outputNo == -1) { - outputNo = 0; - } - - return runPlugin(name, soname, plugid, output, outputNo, - wavname, outfilename, useFrames); -} - - -int runPlugin(string myname, string soname, string id, - string output, int outputNo, string wavname, - string outfilename, bool useFrames) -{ - PluginLoader *loader = PluginLoader::getInstance(); - - PluginLoader::PluginKey key = loader->composePluginKey(soname, id); - - SNDFILE *sndfile; - SF_INFO sfinfo; - memset(&sfinfo, 0, sizeof(SF_INFO)); - - sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); - if (!sndfile) { - cerr << myname << ": ERROR: Failed to open input file \"" - << wavname << "\": " << sf_strerror(sndfile) << endl; - return 1; - } - - ofstream *out = 0; - if (outfilename != "") { - out = new ofstream(outfilename.c_str(), ios::out); - if (!*out) { - cerr << myname << ": ERROR: Failed to open output file \"" - << outfilename << "\" for writing" << endl; - delete out; - return 1; - } - } - - Plugin *plugin = loader->loadPlugin - (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); - if (!plugin) { - cerr << myname << ": ERROR: Failed to load plugin \"" << id - << "\" from library \"" << soname << "\"" << endl; - sf_close(sndfile); - if (out) { - out->close(); - delete out; - } - return 1; - } - - cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; - - int blockSize = plugin->getPreferredBlockSize(); - int stepSize = plugin->getPreferredStepSize(); - - if (blockSize == 0) { - blockSize = 1024; - } - if (stepSize == 0) { - if (plugin->getInputDomain() == Plugin::FrequencyDomain) { - stepSize = blockSize/2; - } else { - stepSize = blockSize; - } - } else if (stepSize > blockSize) { - cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; - if (plugin->getInputDomain() == Plugin::FrequencyDomain) { - blockSize = stepSize * 2; - } else { - blockSize = stepSize; - } - cerr << blockSize << endl; - } - - int channels = sfinfo.channels; - - float *filebuf = new float[blockSize * channels]; - float **plugbuf = new float*[channels]; - for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; - - cerr << "Using block size = " << blockSize << ", step size = " - << stepSize << endl; - - int minch = plugin->getMinChannelCount(); - int maxch = plugin->getMaxChannelCount(); - cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; - cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; - - Plugin::OutputList outputs = plugin->getOutputDescriptors(); - Plugin::OutputDescriptor od; - - int returnValue = 1; - int progress = 0; - - RealTime rt; - PluginWrapper *wrapper = 0; - RealTime adjustment = RealTime::zeroTime; - - if (outputs.empty()) { - cerr << "ERROR: Plugin has no outputs!" << endl; - goto done; - } - - if (outputNo < 0) { - - for (size_t oi = 0; oi < outputs.size(); ++oi) { - if (outputs[oi].identifier == output) { - outputNo = oi; - break; - } - } - - if (outputNo < 0) { - cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; - goto done; - } - - } else { - - if (int(outputs.size()) <= outputNo) { - cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; - goto done; - } - } - - od = outputs[outputNo]; - cerr << "Output is: \"" << od.identifier << "\"" << endl; - - if (!plugin->initialise(channels, stepSize, blockSize)) { - cerr << "ERROR: Plugin initialise (channels = " << channels - << ", stepSize = " << stepSize << ", blockSize = " - << blockSize << ") failed." << endl; - goto done; - } - - wrapper = dynamic_cast(plugin); - if (wrapper) { - PluginInputDomainAdapter *ida = - wrapper->getWrapper(); - if (ida) adjustment = ida->getTimestampAdjustment(); - } - - for (size_t i = 0; i < sfinfo.frames; i += stepSize) { - - int count; - - if (sf_seek(sndfile, i, SEEK_SET) < 0) { - cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl; - break; - } - - if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { - cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; - break; - } - - for (int c = 0; c < channels; ++c) { - int j = 0; - while (j < count) { - plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; - ++j; - } - while (j < blockSize) { - plugbuf[c][j] = 0.0f; - ++j; - } - } - - rt = RealTime::frame2RealTime(i, sfinfo.samplerate); - - printFeatures - (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), - sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt), - out, useFrames); - - int pp = progress; - progress = lrintf((float(i) / sfinfo.frames) * 100.f); - if (progress != pp && out) { - cerr << "\r" << progress << "%"; - } - } - if (out) cerr << "\rDone" << endl; - - rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate); - - printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), - sfinfo.samplerate, outputNo, - plugin->getRemainingFeatures(), out, useFrames); - - returnValue = 0; - -done: - delete plugin; - if (out) { - out->close(); - delete out; - } - sf_close(sndfile); - return returnValue; -} - -void -printFeatures(int frame, int sr, int output, - Plugin::FeatureSet features, ofstream *out, bool useFrames) -{ - for (unsigned int i = 0; i < features[output].size(); ++i) { - - if (useFrames) { - - int displayFrame = frame; - - if (features[output][i].hasTimestamp) { - displayFrame = RealTime::realTime2Frame - (features[output][i].timestamp, sr); - } - - (out ? *out : cout) << displayFrame; - - if (features[output][i].hasDuration) { - displayFrame = RealTime::realTime2Frame - (features[output][i].duration, sr); - (out ? *out : cout) << "," << displayFrame; - } - - (out ? *out : cout) << ":"; - - } else { - - RealTime rt = RealTime::frame2RealTime(frame, sr); - - if (features[output][i].hasTimestamp) { - rt = features[output][i].timestamp; - } - - (out ? *out : cout) << rt.toString(); - - if (features[output][i].hasDuration) { - rt = features[output][i].duration; - (out ? *out : cout) << "," << rt.toString(); - } - - (out ? *out : cout) << ":"; - } - - for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { - (out ? *out : cout) << " " << features[output][i].values[j]; - } - - (out ? *out : cout) << endl; - } -} - -void -printPluginPath(bool verbose) -{ - if (verbose) { - cout << "\nVamp plugin search path: "; - } - - vector path = PluginHostAdapter::getPluginPath(); - for (size_t i = 0; i < path.size(); ++i) { - if (verbose) { - cout << "[" << path[i] << "]"; - } else { - cout << path[i] << endl; - } - } - - if (verbose) cout << endl; -} - -void -enumeratePlugins(Verbosity verbosity) -{ - PluginLoader *loader = PluginLoader::getInstance(); - - if (verbosity == PluginInformation) { - cout << "\nVamp plugin libraries found in search path:" << endl; - } - - vector plugins = loader->listPlugins(); - typedef multimap - LibraryMap; - LibraryMap libraryMap; - - for (size_t i = 0; i < plugins.size(); ++i) { - string path = loader->getLibraryPathForPlugin(plugins[i]); - libraryMap.insert(LibraryMap::value_type(path, plugins[i])); - } - - string prevPath = ""; - int index = 0; - - for (LibraryMap::iterator i = libraryMap.begin(); - i != libraryMap.end(); ++i) { - - string path = i->first; - PluginLoader::PluginKey key = i->second; - - if (path != prevPath) { - prevPath = path; - index = 0; - if (verbosity == PluginInformation) { - cout << "\n " << path << ":" << endl; - } - } - - Plugin *plugin = loader->loadPlugin(key, 48000); - if (plugin) { - - char c = char('A' + index); - if (c > 'Z') c = char('a' + (index - 26)); - - if (verbosity == PluginInformation) { - - cout << " [" << c << "] [v" - << plugin->getVampApiVersion() << "] " - << plugin->getName() << ", \"" - << plugin->getIdentifier() << "\"" << " [" - << plugin->getMaker() << "]" << endl; - - PluginLoader::PluginCategoryHierarchy category = - loader->getPluginCategory(key); - - if (!category.empty()) { - cout << " "; - for (size_t ci = 0; ci < category.size(); ++ci) { - cout << " > " << category[ci]; - } - cout << endl; - } - - if (plugin->getDescription() != "") { - cout << " - " << plugin->getDescription() << endl; - } - - } else if (verbosity == PluginIds) { - cout << "vamp:" << key << endl; - } - - Plugin::OutputList outputs = - plugin->getOutputDescriptors(); - - if (outputs.size() > 1 || verbosity == PluginOutputIds) { - for (size_t j = 0; j < outputs.size(); ++j) { - if (verbosity == PluginInformation) { - cout << " (" << j << ") " - << outputs[j].name << ", \"" - << outputs[j].identifier << "\"" << endl; - if (outputs[j].description != "") { - cout << " - " - << outputs[j].description << endl; - } - } else if (verbosity == PluginOutputIds) { - cout << "vamp:" << key << ":" << outputs[j].identifier << endl; - } - } - } - - ++index; - - delete plugin; - } - } - - if (verbosity == PluginInformation) { - cout << endl; - } -} - -void -printPluginCategoryList() -{ - PluginLoader *loader = PluginLoader::getInstance(); - - vector plugins = loader->listPlugins(); - - set printedcats; - - for (size_t i = 0; i < plugins.size(); ++i) { - - PluginLoader::PluginKey key = plugins[i]; - - PluginLoader::PluginCategoryHierarchy category = - loader->getPluginCategory(key); - - Plugin *plugin = loader->loadPlugin(key, 48000); - if (!plugin) continue; - - string catstr = ""; - - if (category.empty()) catstr = '|'; - else { - for (size_t j = 0; j < category.size(); ++j) { - catstr += category[j]; - catstr += '|'; - if (printedcats.find(catstr) == printedcats.end()) { - std::cout << catstr << std::endl; - printedcats.insert(catstr); - } - } - } - - std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl; - } -} - diff -r f8b38a017d9a -r 14029eb08472 src/AmplitudeFollower.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/AmplitudeFollower.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,247 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + This file copyright 2006 Dan Stowell. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "AmplitudeFollower.h" + +#include + +#include +#include +#include + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +/** + * An implementation of SuperCollider's amplitude-follower algorithm + * as a simple Vamp plugin. + */ + +AmplitudeFollower::AmplitudeFollower(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_previn(0.0f), + m_clampcoef(0.01f), + m_relaxcoef(0.01f) +{ +} + +AmplitudeFollower::~AmplitudeFollower() +{ +} + +string +AmplitudeFollower::getIdentifier() const +{ + return "amplitudefollower"; +} + +string +AmplitudeFollower::getName() const +{ + return "Amplitude Follower"; +} + +string +AmplitudeFollower::getDescription() const +{ + return "Track the amplitude of the audio signal"; +} + +string +AmplitudeFollower::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +AmplitudeFollower::getPluginVersion() const +{ + return 1; +} + +string +AmplitudeFollower::getCopyright() const +{ + return "Code copyright 2006 Dan Stowell; method from SuperCollider. Freely redistributable (BSD license)"; +} + +bool +AmplitudeFollower::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = std::min(stepSize, blockSize); + + // Translate the coefficients + // from their "convenient" 60dB convergence-time values + // to real coefficients + m_clampcoef = m_clampcoef==0.0 ? 0.0 : exp(log(0.1)/(m_clampcoef * m_inputSampleRate)); + m_relaxcoef = m_relaxcoef==0.0 ? 0.0 : exp(log(0.1)/(m_relaxcoef * m_inputSampleRate)); + + return true; +} + +void +AmplitudeFollower::reset() +{ + m_previn = 0.0f; +} + +AmplitudeFollower::OutputList +AmplitudeFollower::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor sca; + sca.identifier = "amplitude"; + sca.name = "Amplitude"; + sca.description = ""; + sca.unit = "V"; + sca.hasFixedBinCount = true; + sca.binCount = 1; + sca.hasKnownExtents = false; + sca.isQuantized = false; + sca.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(sca); + + return list; +} + +AmplitudeFollower::ParameterList +AmplitudeFollower::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor att; + att.identifier = "attack"; + att.name = "Attack time"; + att.description = ""; + att.unit = "s"; + att.minValue = 0.0f; + att.maxValue = 1.f; + att.defaultValue = 0.01f; + att.isQuantized = false; + + list.push_back(att); + + ParameterDescriptor dec; + dec.identifier = "release"; + dec.name = "Release time"; + dec.description = ""; + dec.unit = "s"; + dec.minValue = 0.0f; + dec.maxValue = 1.f; + dec.defaultValue = 0.01f; + dec.isQuantized = false; + + list.push_back(dec); + + return list; +} + +void AmplitudeFollower::setParameter(std::string paramid, float newval) +{ + if (paramid == "attack") { + m_clampcoef = newval; + } else if (paramid == "release") { + m_relaxcoef = newval; + } +} + +float AmplitudeFollower::getParameter(std::string paramid) const +{ + if (paramid == "attack") { + return m_clampcoef; + } else if (paramid == "release") { + return m_relaxcoef; + } + + return 0.0f; +} + +AmplitudeFollower::FeatureSet +AmplitudeFollower::process(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (m_stepSize == 0) { + cerr << "ERROR: AmplitudeFollower::process: " + << "AmplitudeFollower has not been initialised" + << endl; + return FeatureSet(); + } + + float previn = m_previn; + + FeatureSet returnFeatures; + + float val; + float peak = 0.0f; + + for (size_t i = 0; i < m_stepSize; ++i) { + + val = fabs(inputBuffers[0][i]); + + if (val < previn) { + val = val + (previn - val) * m_relaxcoef; + } else { + val = val + (previn - val) * m_clampcoef; + } + + if (val > peak) peak = val; + previn = val; + } + + m_previn = previn; + + // Now store the "feature" (peak amp) for this sample + Feature feature; + feature.hasTimestamp = false; + feature.values.push_back(peak); + returnFeatures[0].push_back(feature); + + return returnFeatures; +} + +AmplitudeFollower::FeatureSet +AmplitudeFollower::getRemainingFeatures() +{ + return FeatureSet(); +} + diff -r f8b38a017d9a -r 14029eb08472 src/FixedTempoEstimator.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/FixedTempoEstimator.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,534 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006-2008 Chris Cannam and QMUL. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "FixedTempoEstimator.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +using Vamp::RealTime; + +#include + + +FixedTempoEstimator::FixedTempoEstimator(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0), + m_priorMagnitudes(0), + m_df(0), + m_r(0), + m_fr(0), + m_t(0), + m_n(0) +{ +} + +FixedTempoEstimator::~FixedTempoEstimator() +{ + delete[] m_priorMagnitudes; + delete[] m_df; + delete[] m_r; + delete[] m_fr; + delete[] m_t; +} + +string +FixedTempoEstimator::getIdentifier() const +{ + return "fixedtempo"; +} + +string +FixedTempoEstimator::getName() const +{ + return "Simple Fixed Tempo Estimator"; +} + +string +FixedTempoEstimator::getDescription() const +{ + return "Study a short section of audio and estimate its tempo, assuming the tempo is constant"; +} + +string +FixedTempoEstimator::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +FixedTempoEstimator::getPluginVersion() const +{ + return 1; +} + +string +FixedTempoEstimator::getCopyright() const +{ + return "Code copyright 2008 Queen Mary, University of London. Freely redistributable (BSD license)"; +} + +size_t +FixedTempoEstimator::getPreferredStepSize() const +{ + return 64; +} + +size_t +FixedTempoEstimator::getPreferredBlockSize() const +{ + return 256; +} + +bool +FixedTempoEstimator::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = stepSize; + m_blockSize = blockSize; + + float dfLengthSecs = 10.f; + m_dfsize = (dfLengthSecs * m_inputSampleRate) / m_stepSize; + + m_priorMagnitudes = new float[m_blockSize/2]; + m_df = new float[m_dfsize]; + + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + for (size_t i = 0; i < m_dfsize; ++i) { + m_df[i] = 0.f; + } + + m_n = 0; + + return true; +} + +void +FixedTempoEstimator::reset() +{ + cerr << "FixedTempoEstimator: reset called" << endl; + + if (!m_priorMagnitudes) return; + + cerr << "FixedTempoEstimator: resetting" << endl; + + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + for (size_t i = 0; i < m_dfsize; ++i) { + m_df[i] = 0.f; + } + + delete[] m_r; + m_r = 0; + + delete[] m_fr; + m_fr = 0; + + delete[] m_t; + m_t = 0; + + m_n = 0; + + m_start = RealTime::zeroTime; + m_lasttime = RealTime::zeroTime; +} + +FixedTempoEstimator::ParameterList +FixedTempoEstimator::getParameterDescriptors() const +{ + ParameterList list; + return list; +} + +float +FixedTempoEstimator::getParameter(std::string id) const +{ + return 0.f; +} + +void +FixedTempoEstimator::setParameter(std::string id, float value) +{ +} + +static int TempoOutput = 0; +static int CandidatesOutput = 1; +static int DFOutput = 2; +static int ACFOutput = 3; +static int FilteredACFOutput = 4; + +FixedTempoEstimator::OutputList +FixedTempoEstimator::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.identifier = "tempo"; + d.name = "Tempo"; + d.description = "Estimated tempo"; + d.unit = "bpm"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::VariableSampleRate; + d.sampleRate = m_inputSampleRate; + d.hasDuration = true; // our returned tempo spans a certain range + list.push_back(d); + + d.identifier = "candidates"; + d.name = "Tempo candidates"; + d.description = "Possible tempo estimates, one per bin with the most likely in the first bin"; + d.unit = "bpm"; + d.hasFixedBinCount = false; + list.push_back(d); + + d.identifier = "detectionfunction"; + d.name = "Detection Function"; + d.description = "Onset detection function"; + d.unit = ""; + d.hasFixedBinCount = 1; + d.binCount = 1; + d.hasKnownExtents = true; + d.minValue = 0.0; + d.maxValue = 1.0; + d.isQuantized = false; + d.quantizeStep = 0.0; + d.sampleType = OutputDescriptor::FixedSampleRate; + if (m_stepSize) { + d.sampleRate = m_inputSampleRate / m_stepSize; + } else { + d.sampleRate = m_inputSampleRate / (getPreferredBlockSize()/2); + } + d.hasDuration = false; + list.push_back(d); + + d.identifier = "acf"; + d.name = "Autocorrelation Function"; + d.description = "Autocorrelation of onset detection function"; + d.hasKnownExtents = false; + d.unit = "r"; + list.push_back(d); + + d.identifier = "filtered_acf"; + d.name = "Filtered Autocorrelation"; + d.description = "Filtered autocorrelation of onset detection function"; + d.unit = "r"; + list.push_back(d); + + return list; +} + +FixedTempoEstimator::FeatureSet +FixedTempoEstimator::process(const float *const *inputBuffers, RealTime ts) +{ + FeatureSet fs; + + if (m_stepSize == 0) { + cerr << "ERROR: FixedTempoEstimator::process: " + << "FixedTempoEstimator has not been initialised" + << endl; + return fs; + } + +// if (m_n < m_dfsize) cerr << "m_n = " << m_n << endl; + + if (m_n == 0) m_start = ts; + m_lasttime = ts; + + if (m_n == m_dfsize) { + calculate(); + fs = assembleFeatures(); + ++m_n; + return fs; + } + + if (m_n > m_dfsize) return FeatureSet(); + + float value = 0.f; + + for (size_t i = 1; i < m_blockSize/2; ++i) { + + float real = inputBuffers[0][i*2]; + float imag = inputBuffers[0][i*2 + 1]; + + float sqrmag = real * real + imag * imag; + value += fabsf(sqrmag - m_priorMagnitudes[i]); + + m_priorMagnitudes[i] = sqrmag; + } + + m_df[m_n] = value; + + ++m_n; + return fs; +} + +FixedTempoEstimator::FeatureSet +FixedTempoEstimator::getRemainingFeatures() +{ + FeatureSet fs; + if (m_n > m_dfsize) return fs; + calculate(); + fs = assembleFeatures(); + ++m_n; + return fs; +} + +float +FixedTempoEstimator::lag2tempo(int lag) +{ + return 60.f / ((lag * m_stepSize) / m_inputSampleRate); +} + +int +FixedTempoEstimator::tempo2lag(float tempo) +{ + return ((60.f / tempo) * m_inputSampleRate) / m_stepSize; +} + +void +FixedTempoEstimator::calculate() +{ + cerr << "FixedTempoEstimator::calculate: m_n = " << m_n << endl; + + if (m_r) { + cerr << "FixedTempoEstimator::calculate: calculation already happened?" << endl; + return; + } + + if (m_n < m_dfsize / 9) { + cerr << "FixedTempoEstimator::calculate: Not enough data to go on (have " << m_n << ", want at least " << m_dfsize/4 << ")" << endl; + return; // not enough data (perhaps we should return the duration of the input as the "estimated" beat length?) + } + + int n = m_n; + + m_r = new float[n/2]; + m_fr = new float[n/2]; + m_t = new float[n/2]; + + for (int i = 0; i < n/2; ++i) { + m_r[i] = 0.f; + m_fr[i] = 0.f; + m_t[i] = lag2tempo(i); + } + + for (int i = 0; i < n/2; ++i) { + + for (int j = i; j < n-1; ++j) { + m_r[i] += m_df[j] * m_df[j - i]; + } + + m_r[i] /= n - i - 1; + } + + float related[] = { 0.5, 2, 3, 4 }; + + for (int i = 1; i < n/2-1; ++i) { + + float weight = 1.f - fabsf(128.f - lag2tempo(i)) * 0.005; + if (weight < 0.f) weight = 0.f; + weight = weight * weight * weight; + + m_fr[i] = m_r[i]; + + int div = 1; + + for (int j = 0; j < int(sizeof(related)/sizeof(related[0])); ++j) { + + int k0 = int(i * related[j] + 0.5); + + if (k0 >= 0 && k0 < int(n/2)) { + + int kmax = 0, kmin = 0; + float kvmax = 0, kvmin = 0; + bool have = false; + + for (int k = k0 - 1; k <= k0 + 1; ++k) { + + if (k < 0 || k >= n/2) continue; + + if (!have || (m_r[k] > kvmax)) { kmax = k; kvmax = m_r[k]; } + if (!have || (m_r[k] < kvmin)) { kmin = k; kvmin = m_r[k]; } + + have = true; + } + + m_fr[i] += m_r[kmax] / 5; + + if ((kmax == 0 || m_r[kmax] > m_r[kmax-1]) && + (kmax == n/2-1 || m_r[kmax] > m_r[kmax+1]) && + kvmax > kvmin * 1.05) { + + m_t[i] = m_t[i] + lag2tempo(kmax) * related[j]; + ++div; + } + } + } + + m_t[i] /= div; + +// if (div > 1) { +// cerr << "adjusting tempo from " << lag2tempo(i) << " to " +// << m_t[i] << " for fr = " << m_fr[i] << " (div = " << div << ")" << endl; +// } + + m_fr[i] += m_fr[i] * (weight / 3); + } +} + + +FixedTempoEstimator::FeatureSet +FixedTempoEstimator::assembleFeatures() +{ + FeatureSet fs; + if (!m_r) return fs; // No results + + Feature feature; + feature.hasTimestamp = true; + feature.hasDuration = false; + feature.label = ""; + feature.values.clear(); + feature.values.push_back(0.f); + + char buffer[40]; + + int n = m_n; + + for (int i = 0; i < n; ++i) { + feature.timestamp = m_start + + RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); + feature.values[0] = m_df[i]; + feature.label = ""; + fs[DFOutput].push_back(feature); + } + + for (int i = 1; i < n/2; ++i) { + feature.timestamp = m_start + + RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); + feature.values[0] = m_r[i]; + sprintf(buffer, "%.1f bpm", lag2tempo(i)); + if (i == n/2-1) feature.label = ""; + else feature.label = buffer; + fs[ACFOutput].push_back(feature); + } + + float t0 = 50.f; // our minimum detected tempo (could be a parameter) + float t1 = 190.f; // our maximum detected tempo + + //!!! need some way for the host (or at least, the user) to know + //!!! that it should only pass a certain amount of + //!!! input... e.g. by making the amount configurable + + int p0 = tempo2lag(t1); + int p1 = tempo2lag(t0); + + std::map candidates; + + for (int i = p0; i <= p1 && i < n/2-1; ++i) { + + if (m_fr[i] > m_fr[i-1] && + m_fr[i] > m_fr[i+1]) { + candidates[m_fr[i]] = i; + } + + feature.timestamp = m_start + + RealTime::frame2RealTime(i * m_stepSize, m_inputSampleRate); + feature.values[0] = m_fr[i]; + sprintf(buffer, "%.1f bpm", lag2tempo(i)); + if (i == p1 || i == n/2-2) feature.label = ""; + else feature.label = buffer; + fs[FilteredACFOutput].push_back(feature); + } + +// cerr << "maxpi = " << maxpi << " for tempo " << lag2tempo(maxpi) << " (value = " << maxp << ")" << endl; + + if (candidates.empty()) { + cerr << "No tempo candidates!" << endl; + return fs; + } + + feature.hasTimestamp = true; + feature.timestamp = m_start; + + feature.hasDuration = true; + feature.duration = m_lasttime - m_start; + + std::map::const_iterator ci = candidates.end(); + --ci; + int maxpi = ci->second; + + if (m_t[maxpi] > 0) { + cerr << "*** Using adjusted tempo " << m_t[maxpi] << " instead of lag tempo " << lag2tempo(maxpi) << endl; + feature.values[0] = m_t[maxpi]; + } else { + // shouldn't happen -- it would imply that this high value was not a peak! + feature.values[0] = lag2tempo(maxpi); + cerr << "WARNING: No stored tempo for index " << maxpi << endl; + } + + sprintf(buffer, "%.1f bpm", feature.values[0]); + feature.label = buffer; + + fs[TempoOutput].push_back(feature); + + feature.values.clear(); + feature.label = ""; + + while (feature.values.size() < 8) { +// cerr << "adding tempo value from lag " << ci->second << endl; + if (m_t[ci->second] > 0) { + feature.values.push_back(m_t[ci->second]); + } else { + feature.values.push_back(lag2tempo(ci->second)); + } + if (ci == candidates.begin()) break; + --ci; + } + + fs[CandidatesOutput].push_back(feature); + + return fs; +} diff -r f8b38a017d9a -r 14029eb08472 src/PercussionOnsetDetector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PercussionOnsetDetector.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,285 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "PercussionOnsetDetector.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +#include + + +PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0), + m_threshold(3), + m_sensitivity(40), + m_priorMagnitudes(0), + m_dfMinus1(0), + m_dfMinus2(0) +{ +} + +PercussionOnsetDetector::~PercussionOnsetDetector() +{ + delete[] m_priorMagnitudes; +} + +string +PercussionOnsetDetector::getIdentifier() const +{ + return "percussiononsets"; +} + +string +PercussionOnsetDetector::getName() const +{ + return "Simple Percussion Onset Detector"; +} + +string +PercussionOnsetDetector::getDescription() const +{ + return "Detect percussive note onsets by identifying broadband energy rises"; +} + +string +PercussionOnsetDetector::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +PercussionOnsetDetector::getPluginVersion() const +{ + return 2; +} + +string +PercussionOnsetDetector::getCopyright() const +{ + return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)"; +} + +size_t +PercussionOnsetDetector::getPreferredStepSize() const +{ + return 0; +} + +size_t +PercussionOnsetDetector::getPreferredBlockSize() const +{ + return 1024; +} + +bool +PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = stepSize; + m_blockSize = blockSize; + + m_priorMagnitudes = new float[m_blockSize/2]; + + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + + m_dfMinus1 = 0.f; + m_dfMinus2 = 0.f; + + return true; +} + +void +PercussionOnsetDetector::reset() +{ + for (size_t i = 0; i < m_blockSize/2; ++i) { + m_priorMagnitudes[i] = 0.f; + } + + m_dfMinus1 = 0.f; + m_dfMinus2 = 0.f; +} + +PercussionOnsetDetector::ParameterList +PercussionOnsetDetector::getParameterDescriptors() const +{ + ParameterList list; + + ParameterDescriptor d; + d.identifier = "threshold"; + d.name = "Energy rise threshold"; + d.description = "Energy rise within a frequency bin necessary to count toward broadband total"; + d.unit = "dB"; + d.minValue = 0; + d.maxValue = 20; + d.defaultValue = 3; + d.isQuantized = false; + list.push_back(d); + + d.identifier = "sensitivity"; + d.name = "Sensitivity"; + d.description = "Sensitivity of peak detector applied to broadband detection function"; + d.unit = "%"; + d.minValue = 0; + d.maxValue = 100; + d.defaultValue = 40; + d.isQuantized = false; + list.push_back(d); + + return list; +} + +float +PercussionOnsetDetector::getParameter(std::string id) const +{ + if (id == "threshold") return m_threshold; + if (id == "sensitivity") return m_sensitivity; + return 0.f; +} + +void +PercussionOnsetDetector::setParameter(std::string id, float value) +{ + if (id == "threshold") { + if (value < 0) value = 0; + if (value > 20) value = 20; + m_threshold = value; + } else if (id == "sensitivity") { + if (value < 0) value = 0; + if (value > 100) value = 100; + m_sensitivity = value; + } +} + +PercussionOnsetDetector::OutputList +PercussionOnsetDetector::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.identifier = "onsets"; + d.name = "Onsets"; + d.description = "Percussive note onset locations"; + d.unit = ""; + d.hasFixedBinCount = true; + d.binCount = 0; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::VariableSampleRate; + d.sampleRate = m_inputSampleRate; + list.push_back(d); + + d.identifier = "detectionfunction"; + d.name = "Detection Function"; + d.description = "Broadband energy rise detection function"; + d.binCount = 1; + d.isQuantized = true; + d.quantizeStep = 1.0; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + return list; +} + +PercussionOnsetDetector::FeatureSet +PercussionOnsetDetector::process(const float *const *inputBuffers, + Vamp::RealTime ts) +{ + if (m_stepSize == 0) { + cerr << "ERROR: PercussionOnsetDetector::process: " + << "PercussionOnsetDetector has not been initialised" + << endl; + return FeatureSet(); + } + + int count = 0; + + for (size_t i = 1; i < m_blockSize/2; ++i) { + + float real = inputBuffers[0][i*2]; + float imag = inputBuffers[0][i*2 + 1]; + + float sqrmag = real * real + imag * imag; + + if (m_priorMagnitudes[i] > 0.f) { + float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]); + +// std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl; + + if (diff >= m_threshold) ++count; + } + + m_priorMagnitudes[i] = sqrmag; + } + + FeatureSet returnFeatures; + + Feature detectionFunction; + detectionFunction.hasTimestamp = false; + detectionFunction.values.push_back(count); + returnFeatures[1].push_back(detectionFunction); + + if (m_dfMinus2 < m_dfMinus1 && + m_dfMinus1 >= count && + m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) { + + Feature onset; + onset.hasTimestamp = true; + onset.timestamp = ts - Vamp::RealTime::frame2RealTime + (m_stepSize, int(m_inputSampleRate + 0.5)); + returnFeatures[0].push_back(onset); + } + + m_dfMinus2 = m_dfMinus1; + m_dfMinus1 = count; + + return returnFeatures; +} + +PercussionOnsetDetector::FeatureSet +PercussionOnsetDetector::getRemainingFeatures() +{ + return FeatureSet(); +} + diff -r f8b38a017d9a -r 14029eb08472 src/PluginAdapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PluginAdapter.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,873 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "PluginAdapter.h" + +#include +#include + +//#define DEBUG_PLUGIN_ADAPTER 1 + +namespace Vamp { + +class PluginAdapterBase::Impl +{ +public: + Impl(PluginAdapterBase *); + ~Impl(); + + const VampPluginDescriptor *getDescriptor(); + +protected: + PluginAdapterBase *m_base; + + static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc, + float inputSampleRate); + + static void vampCleanup(VampPluginHandle handle); + + static int vampInitialise(VampPluginHandle handle, unsigned int channels, + unsigned int stepSize, unsigned int blockSize); + + static void vampReset(VampPluginHandle handle); + + static float vampGetParameter(VampPluginHandle handle, int param); + static void vampSetParameter(VampPluginHandle handle, int param, float value); + + static unsigned int vampGetCurrentProgram(VampPluginHandle handle); + static void vampSelectProgram(VampPluginHandle handle, unsigned int program); + + static unsigned int vampGetPreferredStepSize(VampPluginHandle handle); + static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle); + static unsigned int vampGetMinChannelCount(VampPluginHandle handle); + static unsigned int vampGetMaxChannelCount(VampPluginHandle handle); + + static unsigned int vampGetOutputCount(VampPluginHandle handle); + + static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle, + unsigned int i); + + static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc); + + static VampFeatureList *vampProcess(VampPluginHandle handle, + const float *const *inputBuffers, + int sec, + int nsec); + + static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle); + + static void vampReleaseFeatureSet(VampFeatureList *fs); + + void cleanup(Plugin *plugin); + void checkOutputMap(Plugin *plugin); + unsigned int getOutputCount(Plugin *plugin); + VampOutputDescriptor *getOutputDescriptor(Plugin *plugin, + unsigned int i); + VampFeatureList *process(Plugin *plugin, + const float *const *inputBuffers, + int sec, int nsec); + VampFeatureList *getRemainingFeatures(Plugin *plugin); + VampFeatureList *convertFeatures(Plugin *plugin, + const Plugin::FeatureSet &features); + + // maps both plugins and descriptors to adapters + typedef std::map AdapterMap; + static AdapterMap *m_adapterMap; + static Impl *lookupAdapter(VampPluginHandle); + + bool m_populated; + VampPluginDescriptor m_descriptor; + Plugin::ParameterList m_parameters; + Plugin::ProgramList m_programs; + + typedef std::map OutputMap; + OutputMap m_pluginOutputs; + + std::map m_fs; + std::map > m_fsizes; + std::map > > m_fvsizes; + void resizeFS(Plugin *plugin, int n); + void resizeFL(Plugin *plugin, int n, size_t sz); + void resizeFV(Plugin *plugin, int n, int j, size_t sz); +}; + +PluginAdapterBase::PluginAdapterBase() +{ + m_impl = new Impl(this); +} + +PluginAdapterBase::~PluginAdapterBase() +{ + delete m_impl; +} + +const VampPluginDescriptor * +PluginAdapterBase::getDescriptor() +{ + return m_impl->getDescriptor(); +} + +PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) : + m_base(base), + m_populated(false) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl; +#endif +} + +const VampPluginDescriptor * +PluginAdapterBase::Impl::getDescriptor() +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl; +#endif + + if (m_populated) return &m_descriptor; + + Plugin *plugin = m_base->createPlugin(48000); + + if (plugin->getVampApiVersion() != VAMP_API_VERSION) { + std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: " + << "API version " << plugin->getVampApiVersion() + << " for\nplugin \"" << plugin->getIdentifier() << "\" " + << "differs from version " + << VAMP_API_VERSION << " for adapter.\n" + << "This plugin is probably linked against a different version of the Vamp SDK\n" + << "from the version it was compiled with. It will need to be re-linked correctly\n" + << "before it can be used." << std::endl; + delete plugin; + return 0; + } + + m_parameters = plugin->getParameterDescriptors(); + m_programs = plugin->getPrograms(); + + m_descriptor.vampApiVersion = plugin->getVampApiVersion(); + m_descriptor.identifier = strdup(plugin->getIdentifier().c_str()); + m_descriptor.name = strdup(plugin->getName().c_str()); + m_descriptor.description = strdup(plugin->getDescription().c_str()); + m_descriptor.maker = strdup(plugin->getMaker().c_str()); + m_descriptor.pluginVersion = plugin->getPluginVersion(); + m_descriptor.copyright = strdup(plugin->getCopyright().c_str()); + + m_descriptor.parameterCount = m_parameters.size(); + m_descriptor.parameters = (const VampParameterDescriptor **) + malloc(m_parameters.size() * sizeof(VampParameterDescriptor)); + + unsigned int i; + + for (i = 0; i < m_parameters.size(); ++i) { + VampParameterDescriptor *desc = (VampParameterDescriptor *) + malloc(sizeof(VampParameterDescriptor)); + desc->identifier = strdup(m_parameters[i].identifier.c_str()); + desc->name = strdup(m_parameters[i].name.c_str()); + desc->description = strdup(m_parameters[i].description.c_str()); + desc->unit = strdup(m_parameters[i].unit.c_str()); + desc->minValue = m_parameters[i].minValue; + desc->maxValue = m_parameters[i].maxValue; + desc->defaultValue = m_parameters[i].defaultValue; + desc->isQuantized = m_parameters[i].isQuantized; + desc->quantizeStep = m_parameters[i].quantizeStep; + desc->valueNames = 0; + if (desc->isQuantized && !m_parameters[i].valueNames.empty()) { + desc->valueNames = (const char **) + malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *)); + for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) { + desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str()); + } + desc->valueNames[m_parameters[i].valueNames.size()] = 0; + } + m_descriptor.parameters[i] = desc; + } + + m_descriptor.programCount = m_programs.size(); + m_descriptor.programs = (const char **) + malloc(m_programs.size() * sizeof(const char *)); + + for (i = 0; i < m_programs.size(); ++i) { + m_descriptor.programs[i] = strdup(m_programs[i].c_str()); + } + + if (plugin->getInputDomain() == Plugin::FrequencyDomain) { + m_descriptor.inputDomain = vampFrequencyDomain; + } else { + m_descriptor.inputDomain = vampTimeDomain; + } + + m_descriptor.instantiate = vampInstantiate; + m_descriptor.cleanup = vampCleanup; + m_descriptor.initialise = vampInitialise; + m_descriptor.reset = vampReset; + m_descriptor.getParameter = vampGetParameter; + m_descriptor.setParameter = vampSetParameter; + m_descriptor.getCurrentProgram = vampGetCurrentProgram; + m_descriptor.selectProgram = vampSelectProgram; + m_descriptor.getPreferredStepSize = vampGetPreferredStepSize; + m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize; + m_descriptor.getMinChannelCount = vampGetMinChannelCount; + m_descriptor.getMaxChannelCount = vampGetMaxChannelCount; + m_descriptor.getOutputCount = vampGetOutputCount; + m_descriptor.getOutputDescriptor = vampGetOutputDescriptor; + m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor; + m_descriptor.process = vampProcess; + m_descriptor.getRemainingFeatures = vampGetRemainingFeatures; + m_descriptor.releaseFeatureSet = vampReleaseFeatureSet; + + if (!m_adapterMap) { + m_adapterMap = new AdapterMap; + } + (*m_adapterMap)[&m_descriptor] = this; + + delete plugin; + + m_populated = true; + return &m_descriptor; +} + +PluginAdapterBase::Impl::~Impl() +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl; +#endif + + if (!m_populated) return; + + free((void *)m_descriptor.identifier); + free((void *)m_descriptor.name); + free((void *)m_descriptor.description); + free((void *)m_descriptor.maker); + free((void *)m_descriptor.copyright); + + for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) { + const VampParameterDescriptor *desc = m_descriptor.parameters[i]; + free((void *)desc->identifier); + free((void *)desc->name); + free((void *)desc->description); + free((void *)desc->unit); + if (desc->valueNames) { + for (unsigned int j = 0; desc->valueNames[j]; ++j) { + free((void *)desc->valueNames[j]); + } + free((void *)desc->valueNames); + } + } + free((void *)m_descriptor.parameters); + + for (unsigned int i = 0; i < m_descriptor.programCount; ++i) { + free((void *)m_descriptor.programs[i]); + } + free((void *)m_descriptor.programs); + + if (m_adapterMap) { + + m_adapterMap->erase(&m_descriptor); + + if (m_adapterMap->empty()) { + delete m_adapterMap; + m_adapterMap = 0; + } + } +} + +PluginAdapterBase::Impl * +PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl; +#endif + + if (!m_adapterMap) return 0; + AdapterMap::const_iterator i = m_adapterMap->find(handle); + if (i == m_adapterMap->end()) return 0; + return i->second; +} + +VampPluginHandle +PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc, + float inputSampleRate) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl; +#endif + + if (!m_adapterMap) { + m_adapterMap = new AdapterMap(); + } + + if (m_adapterMap->find(desc) == m_adapterMap->end()) { + std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl; + return 0; + } + + Impl *adapter = (*m_adapterMap)[desc]; + if (desc != &adapter->m_descriptor) return 0; + + Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate); + if (plugin) { + (*m_adapterMap)[plugin] = adapter; + } + +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl; +#endif + + return plugin; +} + +void +PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) { + delete ((Plugin *)handle); + return; + } + adapter->cleanup(((Plugin *)handle)); +} + +int +PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle, + unsigned int channels, + unsigned int stepSize, + unsigned int blockSize) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl; +#endif + + bool result = ((Plugin *)handle)->initialise + (channels, stepSize, blockSize); + return result ? 1 : 0; +} + +void +PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl; +#endif + + ((Plugin *)handle)->reset(); +} + +float +PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle, + int param) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0.0; + Plugin::ParameterList &list = adapter->m_parameters; + return ((Plugin *)handle)->getParameter(list[param].identifier); +} + +void +PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle, + int param, float value) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return; + Plugin::ParameterList &list = adapter->m_parameters; + ((Plugin *)handle)->setParameter(list[param].identifier, value); +} + +unsigned int +PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + Plugin::ProgramList &list = adapter->m_programs; + std::string program = ((Plugin *)handle)->getCurrentProgram(); + for (unsigned int i = 0; i < list.size(); ++i) { + if (list[i] == program) return i; + } + return 0; +} + +void +PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle, + unsigned int program) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return; + Plugin::ProgramList &list = adapter->m_programs; + ((Plugin *)handle)->selectProgram(list[program]); +} + +unsigned int +PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl; +#endif + + return ((Plugin *)handle)->getPreferredStepSize(); +} + +unsigned int +PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl; +#endif + + return ((Plugin *)handle)->getPreferredBlockSize(); +} + +unsigned int +PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl; +#endif + + return ((Plugin *)handle)->getMinChannelCount(); +} + +unsigned int +PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl; +#endif + + return ((Plugin *)handle)->getMaxChannelCount(); +} + +unsigned int +PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + +// std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl; + + if (!adapter) return 0; + return adapter->getOutputCount((Plugin *)handle); +} + +VampOutputDescriptor * +PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle, + unsigned int i) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + +// std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl; + + if (!adapter) return 0; + return adapter->getOutputDescriptor((Plugin *)handle, i); +} + +void +PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl; +#endif + + if (desc->identifier) free((void *)desc->identifier); + if (desc->name) free((void *)desc->name); + if (desc->description) free((void *)desc->description); + if (desc->unit) free((void *)desc->unit); + if (desc->hasFixedBinCount && desc->binNames) { + for (unsigned int i = 0; i < desc->binCount; ++i) { + if (desc->binNames[i]) { + free((void *)desc->binNames[i]); + } + } + } + if (desc->binNames) free((void *)desc->binNames); + free((void *)desc); +} + +VampFeatureList * +PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle, + const float *const *inputBuffers, + int sec, + int nsec) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->process((Plugin *)handle, + inputBuffers, sec, nsec); +} + +VampFeatureList * +PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl; +#endif + + Impl *adapter = lookupAdapter(handle); + if (!adapter) return 0; + return adapter->getRemainingFeatures((Plugin *)handle); +} + +void +PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs) +{ +#ifdef DEBUG_PLUGIN_ADAPTER + std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl; +#endif +} + +void +PluginAdapterBase::Impl::cleanup(Plugin *plugin) +{ + if (m_fs.find(plugin) != m_fs.end()) { + size_t outputCount = 0; + if (m_pluginOutputs[plugin]) { + outputCount = m_pluginOutputs[plugin]->size(); + } + VampFeatureList *list = m_fs[plugin]; + for (unsigned int i = 0; i < outputCount; ++i) { + for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) { + if (list[i].features[j].v1.label) { + free(list[i].features[j].v1.label); + } + if (list[i].features[j].v1.values) { + free(list[i].features[j].v1.values); + } + } + if (list[i].features) free(list[i].features); + } + m_fs.erase(plugin); + m_fsizes.erase(plugin); + m_fvsizes.erase(plugin); + } + + if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) { + delete m_pluginOutputs[plugin]; + m_pluginOutputs.erase(plugin); + } + + if (m_adapterMap) { + m_adapterMap->erase(plugin); + + if (m_adapterMap->empty()) { + delete m_adapterMap; + m_adapterMap = 0; + } + } + + delete ((Plugin *)plugin); +} + +void +PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin) +{ + if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() || + !m_pluginOutputs[plugin]) { + m_pluginOutputs[plugin] = new Plugin::OutputList + (plugin->getOutputDescriptors()); +// std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl; + } +} + +unsigned int +PluginAdapterBase::Impl::getOutputCount(Plugin *plugin) +{ + checkOutputMap(plugin); + return m_pluginOutputs[plugin]->size(); +} + +VampOutputDescriptor * +PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin, + unsigned int i) +{ + checkOutputMap(plugin); + Plugin::OutputDescriptor &od = + (*m_pluginOutputs[plugin])[i]; + + VampOutputDescriptor *desc = (VampOutputDescriptor *) + malloc(sizeof(VampOutputDescriptor)); + + desc->identifier = strdup(od.identifier.c_str()); + desc->name = strdup(od.name.c_str()); + desc->description = strdup(od.description.c_str()); + desc->unit = strdup(od.unit.c_str()); + desc->hasFixedBinCount = od.hasFixedBinCount; + desc->binCount = od.binCount; + + if (od.hasFixedBinCount && od.binCount > 0) { + desc->binNames = (const char **) + malloc(od.binCount * sizeof(const char *)); + + for (unsigned int i = 0; i < od.binCount; ++i) { + if (i < od.binNames.size()) { + desc->binNames[i] = strdup(od.binNames[i].c_str()); + } else { + desc->binNames[i] = 0; + } + } + } else { + desc->binNames = 0; + } + + desc->hasKnownExtents = od.hasKnownExtents; + desc->minValue = od.minValue; + desc->maxValue = od.maxValue; + desc->isQuantized = od.isQuantized; + desc->quantizeStep = od.quantizeStep; + + switch (od.sampleType) { + case Plugin::OutputDescriptor::OneSamplePerStep: + desc->sampleType = vampOneSamplePerStep; break; + case Plugin::OutputDescriptor::FixedSampleRate: + desc->sampleType = vampFixedSampleRate; break; + case Plugin::OutputDescriptor::VariableSampleRate: + desc->sampleType = vampVariableSampleRate; break; + } + + desc->sampleRate = od.sampleRate; + desc->hasDuration = od.hasDuration; + + return desc; +} + +VampFeatureList * +PluginAdapterBase::Impl::process(Plugin *plugin, + const float *const *inputBuffers, + int sec, int nsec) +{ +// std::cerr << "PluginAdapterBase::Impl::process" << std::endl; + RealTime rt(sec, nsec); + checkOutputMap(plugin); + return convertFeatures(plugin, plugin->process(inputBuffers, rt)); +} + +VampFeatureList * +PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin) +{ +// std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl; + checkOutputMap(plugin); + return convertFeatures(plugin, plugin->getRemainingFeatures()); +} + +VampFeatureList * +PluginAdapterBase::Impl::convertFeatures(Plugin *plugin, + const Plugin::FeatureSet &features) +{ + int lastN = -1; + + int outputCount = 0; + if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size(); + + resizeFS(plugin, outputCount); + VampFeatureList *fs = m_fs[plugin]; + +// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl; + + for (Plugin::FeatureSet::const_iterator fi = features.begin(); + fi != features.end(); ++fi) { + + int n = fi->first; + +// std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl; + + if (n >= int(outputCount)) { + std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl; + continue; + } + + if (n > lastN + 1) { + for (int i = lastN + 1; i < n; ++i) { + fs[i].featureCount = 0; + } + } + + const Plugin::FeatureList &fl = fi->second; + + size_t sz = fl.size(); + if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz); + fs[n].featureCount = sz; + + for (size_t j = 0; j < sz; ++j) { + +// std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl; + + VampFeature *feature = &fs[n].features[j].v1; + + feature->hasTimestamp = fl[j].hasTimestamp; + feature->sec = fl[j].timestamp.sec; + feature->nsec = fl[j].timestamp.nsec; + feature->valueCount = fl[j].values.size(); + + VampFeatureV2 *v2 = &fs[n].features[j + sz].v2; + + v2->hasDuration = fl[j].hasDuration; + v2->durationSec = fl[j].duration.sec; + v2->durationNsec = fl[j].duration.nsec; + + if (feature->label) free(feature->label); + + if (fl[j].label.empty()) { + feature->label = 0; + } else { + feature->label = strdup(fl[j].label.c_str()); + } + + if (feature->valueCount > m_fvsizes[plugin][n][j]) { + resizeFV(plugin, n, j, feature->valueCount); + } + + for (unsigned int k = 0; k < feature->valueCount; ++k) { +// std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl; + feature->values[k] = fl[j].values[k]; + } + } + + lastN = n; + } + + if (lastN == -1) return 0; + + if (int(outputCount) > lastN + 1) { + for (int i = lastN + 1; i < int(outputCount); ++i) { + fs[i].featureCount = 0; + } + } + +// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl; +// for (int i = 0; i < outputCount; ++i) { +// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl; +// } + + + return fs; +} + +void +PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n) +{ +// std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl; + + int i = m_fsizes[plugin].size(); + if (i >= n) return; + +// std::cerr << "resizing from " << i << std::endl; + + m_fs[plugin] = (VampFeatureList *)realloc + (m_fs[plugin], n * sizeof(VampFeatureList)); + + while (i < n) { + m_fs[plugin][i].featureCount = 0; + m_fs[plugin][i].features = 0; + m_fsizes[plugin].push_back(0); + m_fvsizes[plugin].push_back(std::vector()); + i++; + } +} + +void +PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz) +{ +// std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", " +// << sz << ")" << std::endl; + + size_t i = m_fsizes[plugin][n]; + if (i >= sz) return; + +// std::cerr << "resizing from " << i << std::endl; + + m_fs[plugin][n].features = (VampFeatureUnion *)realloc + (m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion)); + + while (m_fsizes[plugin][n] < sz) { + m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0; + m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0; + m_fvsizes[plugin][n].push_back(0); + m_fsizes[plugin][n]++; + } +} + +void +PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz) +{ +// std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", " +// << j << ", " << sz << ")" << std::endl; + + size_t i = m_fvsizes[plugin][n][j]; + if (i >= sz) return; + +// std::cerr << "resizing from " << i << std::endl; + + m_fs[plugin][n].features[j].v1.values = (float *)realloc + (m_fs[plugin][n].features[j].v1.values, sz * sizeof(float)); + + m_fvsizes[plugin][n][j] = sz; +} + +PluginAdapterBase::Impl::AdapterMap * +PluginAdapterBase::Impl::m_adapterMap = 0; + +} + diff -r f8b38a017d9a -r 14029eb08472 src/PluginHostAdapter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/PluginHostAdapter.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,447 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "PluginHostAdapter.h" +#include + +namespace Vamp +{ + +PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, + float inputSampleRate) : + Plugin(inputSampleRate), + m_descriptor(descriptor) +{ +// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl; + m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate); + if (!m_handle) { +// std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl; + } +} + +PluginHostAdapter::~PluginHostAdapter() +{ +// std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl; + if (m_handle) m_descriptor->cleanup(m_handle); +} + +std::vector +PluginHostAdapter::getPluginPath() +{ + std::vector path; + std::string envPath; + + char *cpath = getenv("VAMP_PATH"); + if (cpath) envPath = cpath; + +#ifdef _WIN32 +#define PATH_SEPARATOR ';' +#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins" +#else +#define PATH_SEPARATOR ':' +#ifdef __APPLE__ +#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp" +#else +#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp" +#endif +#endif + + if (envPath == "") { + envPath = DEFAULT_VAMP_PATH; + char *chome = getenv("HOME"); + if (chome) { + std::string home(chome); + std::string::size_type f; + while ((f = envPath.find("$HOME")) != std::string::npos && + f < envPath.length()) { + envPath.replace(f, 5, home); + } + } +#ifdef _WIN32 + char *cpfiles = getenv("ProgramFiles"); + if (!cpfiles) cpfiles = "C:\\Program Files"; + std::string pfiles(cpfiles); + std::string::size_type f; + while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && + f < envPath.length()) { + envPath.replace(f, 14, pfiles); + } +#endif + } + + std::string::size_type index = 0, newindex = 0; + + while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { + path.push_back(envPath.substr(index, newindex - index)); + index = newindex + 1; + } + + path.push_back(envPath.substr(index)); + + return path; +} + +bool +PluginHostAdapter::initialise(size_t channels, + size_t stepSize, + size_t blockSize) +{ + if (!m_handle) return false; + return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ? + true : false; +} + +void +PluginHostAdapter::reset() +{ + if (!m_handle) { +// std::cerr << "PluginHostAdapter::reset: no handle" << std::endl; + return; + } +// std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl; + m_descriptor->reset(m_handle); +} + +PluginHostAdapter::InputDomain +PluginHostAdapter::getInputDomain() const +{ + if (m_descriptor->inputDomain == vampFrequencyDomain) { + return FrequencyDomain; + } else { + return TimeDomain; + } +} + +unsigned int +PluginHostAdapter::getVampApiVersion() const +{ + return m_descriptor->vampApiVersion; +} + +std::string +PluginHostAdapter::getIdentifier() const +{ + return m_descriptor->identifier; +} + +std::string +PluginHostAdapter::getName() const +{ + return m_descriptor->name; +} + +std::string +PluginHostAdapter::getDescription() const +{ + return m_descriptor->description; +} + +std::string +PluginHostAdapter::getMaker() const +{ + return m_descriptor->maker; +} + +int +PluginHostAdapter::getPluginVersion() const +{ + return m_descriptor->pluginVersion; +} + +std::string +PluginHostAdapter::getCopyright() const +{ + return m_descriptor->copyright; +} + +PluginHostAdapter::ParameterList +PluginHostAdapter::getParameterDescriptors() const +{ + ParameterList list; + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + const VampParameterDescriptor *spd = m_descriptor->parameters[i]; + ParameterDescriptor pd; + pd.identifier = spd->identifier; + pd.name = spd->name; + pd.description = spd->description; + pd.unit = spd->unit; + pd.minValue = spd->minValue; + pd.maxValue = spd->maxValue; + pd.defaultValue = spd->defaultValue; + pd.isQuantized = spd->isQuantized; + pd.quantizeStep = spd->quantizeStep; + if (pd.isQuantized && spd->valueNames) { + for (unsigned int j = 0; spd->valueNames[j]; ++j) { + pd.valueNames.push_back(spd->valueNames[j]); + } + } + list.push_back(pd); + } + return list; +} + +float +PluginHostAdapter::getParameter(std::string param) const +{ + if (!m_handle) return 0.0; + + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + if (param == m_descriptor->parameters[i]->identifier) { + return m_descriptor->getParameter(m_handle, i); + } + } + + return 0.0; +} + +void +PluginHostAdapter::setParameter(std::string param, + float value) +{ + if (!m_handle) return; + + for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { + if (param == m_descriptor->parameters[i]->identifier) { + m_descriptor->setParameter(m_handle, i, value); + return; + } + } +} + +PluginHostAdapter::ProgramList +PluginHostAdapter::getPrograms() const +{ + ProgramList list; + + for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { + list.push_back(m_descriptor->programs[i]); + } + + return list; +} + +std::string +PluginHostAdapter::getCurrentProgram() const +{ + if (!m_handle) return ""; + + int pn = m_descriptor->getCurrentProgram(m_handle); + return m_descriptor->programs[pn]; +} + +void +PluginHostAdapter::selectProgram(std::string program) +{ + if (!m_handle) return; + + for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { + if (program == m_descriptor->programs[i]) { + m_descriptor->selectProgram(m_handle, i); + return; + } + } +} + +size_t +PluginHostAdapter::getPreferredStepSize() const +{ + if (!m_handle) return 0; + return m_descriptor->getPreferredStepSize(m_handle); +} + +size_t +PluginHostAdapter::getPreferredBlockSize() const +{ + if (!m_handle) return 0; + return m_descriptor->getPreferredBlockSize(m_handle); +} + +size_t +PluginHostAdapter::getMinChannelCount() const +{ + if (!m_handle) return 0; + return m_descriptor->getMinChannelCount(m_handle); +} + +size_t +PluginHostAdapter::getMaxChannelCount() const +{ + if (!m_handle) return 0; + return m_descriptor->getMaxChannelCount(m_handle); +} + +PluginHostAdapter::OutputList +PluginHostAdapter::getOutputDescriptors() const +{ + OutputList list; + if (!m_handle) { +// std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl; + return list; + } + + unsigned int count = m_descriptor->getOutputCount(m_handle); + + for (unsigned int i = 0; i < count; ++i) { + VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i); + OutputDescriptor d; + d.identifier = sd->identifier; + d.name = sd->name; + d.description = sd->description; + d.unit = sd->unit; + d.hasFixedBinCount = sd->hasFixedBinCount; + d.binCount = sd->binCount; + if (d.hasFixedBinCount) { + for (unsigned int j = 0; j < sd->binCount; ++j) { + d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : ""); + } + } + d.hasKnownExtents = sd->hasKnownExtents; + d.minValue = sd->minValue; + d.maxValue = sd->maxValue; + d.isQuantized = sd->isQuantized; + d.quantizeStep = sd->quantizeStep; + + switch (sd->sampleType) { + case vampOneSamplePerStep: + d.sampleType = OutputDescriptor::OneSamplePerStep; break; + case vampFixedSampleRate: + d.sampleType = OutputDescriptor::FixedSampleRate; break; + case vampVariableSampleRate: + d.sampleType = OutputDescriptor::VariableSampleRate; break; + } + + d.sampleRate = sd->sampleRate; + + if (m_descriptor->vampApiVersion >= 2) { + d.hasDuration = sd->hasDuration; + } else { + d.hasDuration = false; + } + + list.push_back(d); + + m_descriptor->releaseOutputDescriptor(sd); + } + + return list; +} + +PluginHostAdapter::FeatureSet +PluginHostAdapter::process(const float *const *inputBuffers, + RealTime timestamp) +{ + FeatureSet fs; + if (!m_handle) return fs; + + int sec = timestamp.sec; + int nsec = timestamp.nsec; + + VampFeatureList *features = m_descriptor->process(m_handle, + inputBuffers, + sec, nsec); + + convertFeatures(features, fs); + m_descriptor->releaseFeatureSet(features); + return fs; +} + +PluginHostAdapter::FeatureSet +PluginHostAdapter::getRemainingFeatures() +{ + FeatureSet fs; + if (!m_handle) return fs; + + VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); + + convertFeatures(features, fs); + m_descriptor->releaseFeatureSet(features); + return fs; +} + +void +PluginHostAdapter::convertFeatures(VampFeatureList *features, + FeatureSet &fs) +{ + if (!features) return; + + unsigned int outputs = m_descriptor->getOutputCount(m_handle); + + for (unsigned int i = 0; i < outputs; ++i) { + + VampFeatureList &list = features[i]; + + if (list.featureCount > 0) { + + Feature feature; + feature.values.reserve(list.features[0].v1.valueCount); + + for (unsigned int j = 0; j < list.featureCount; ++j) { + + feature.hasTimestamp = list.features[j].v1.hasTimestamp; + feature.timestamp = RealTime(list.features[j].v1.sec, + list.features[j].v1.nsec); + feature.hasDuration = false; + + if (m_descriptor->vampApiVersion >= 2) { + unsigned int j2 = j + list.featureCount; + feature.hasDuration = list.features[j2].v2.hasDuration; + feature.duration = RealTime(list.features[j2].v2.durationSec, + list.features[j2].v2.durationNsec); + } + + for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) { + feature.values.push_back(list.features[j].v1.values[k]); + } + + if (list.features[j].v1.label) { + feature.label = list.features[j].v1.label; + } + + fs[i].push_back(feature); + + if (list.features[j].v1.valueCount > 0) { + feature.values.clear(); + } + + if (list.features[j].v1.label) { + feature.label = ""; + } + } + } + } +} + +} diff -r f8b38a017d9a -r 14029eb08472 src/RealTime.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/RealTime.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,245 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +/* + This is a modified version of a source file from the + Rosegarden MIDI and audio sequencer and notation editor. + This file copyright 2000-2006 Chris Cannam. + Relicensed by the author as detailed above. +*/ + +#include + +#if (__GNUC__ < 3) +#include +#define stringstream strstream +#else +#include +#endif + +using std::cerr; +using std::endl; + +#include "RealTime.h" + +#ifndef _WIN32 +#include +#endif + +namespace Vamp { + +// A RealTime consists of two ints that must be at least 32 bits each. +// A signed 32-bit int can store values exceeding +/- 2 billion. This +// means we can safely use our lower int for nanoseconds, as there are +// 1 billion nanoseconds in a second and we need to handle double that +// because of the implementations of addition etc that we use. +// +// The maximum valid RealTime on a 32-bit system is somewhere around +// 68 years: 999999999 nanoseconds longer than the classic Unix epoch. + +#define ONE_BILLION 1000000000 + +RealTime::RealTime(int s, int n) : + sec(s), nsec(n) +{ + if (sec == 0) { + while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } + while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } + } else if (sec < 0) { + while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } + while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } + } else { + while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } + while (nsec < 0) { nsec += ONE_BILLION; --sec; } + } +} + +RealTime +RealTime::fromSeconds(double sec) +{ + return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); +} + +RealTime +RealTime::fromMilliseconds(int msec) +{ + return RealTime(msec / 1000, (msec % 1000) * 1000000); +} + +#ifndef _WIN32 +RealTime +RealTime::fromTimeval(const struct timeval &tv) +{ + return RealTime(tv.tv_sec, tv.tv_usec * 1000); +} +#endif + +std::ostream &operator<<(std::ostream &out, const RealTime &rt) +{ + if (rt < RealTime::zeroTime) { + out << "-"; + } else { + out << " "; + } + + int s = (rt.sec < 0 ? -rt.sec : rt.sec); + int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); + + out << s << "."; + + int nn(n); + if (nn == 0) out << "00000000"; + else while (nn < (ONE_BILLION / 10)) { + out << "0"; + nn *= 10; + } + + out << n << "R"; + return out; +} + +std::string +RealTime::toString() const +{ + std::stringstream out; + out << *this; + +#if (__GNUC__ < 3) + out << std::ends; +#endif + + std::string s = out.str(); + + // remove trailing R + return s.substr(0, s.length() - 1); +} + +std::string +RealTime::toText(bool fixedDp) const +{ + if (*this < RealTime::zeroTime) return "-" + (-*this).toText(); + + std::stringstream out; + + if (sec >= 3600) { + out << (sec / 3600) << ":"; + } + + if (sec >= 60) { + out << (sec % 3600) / 60 << ":"; + } + + if (sec >= 10) { + out << ((sec % 60) / 10); + } + + out << (sec % 10); + + int ms = msec(); + + if (ms != 0) { + out << "."; + out << (ms / 100); + ms = ms % 100; + if (ms != 0) { + out << (ms / 10); + ms = ms % 10; + } else if (fixedDp) { + out << "0"; + } + if (ms != 0) { + out << ms; + } else if (fixedDp) { + out << "0"; + } + } else if (fixedDp) { + out << ".000"; + } + +#if (__GNUC__ < 3) + out << std::ends; +#endif + + std::string s = out.str(); + + return s; +} + + +RealTime +RealTime::operator/(int d) const +{ + int secdiv = sec / d; + int secrem = sec % d; + + double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; + + return RealTime(secdiv, int(nsecdiv + 0.5)); +} + +double +RealTime::operator/(const RealTime &r) const +{ + double lTotal = double(sec) * ONE_BILLION + double(nsec); + double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); + + if (rTotal == 0) return 0.0; + else return lTotal/rTotal; +} + +long +RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate) +{ + if (time < zeroTime) return -realTime2Frame(-time, sampleRate); + double s = time.sec + double(time.nsec + 1) / 1000000000.0; + return long(s * sampleRate); +} + +RealTime +RealTime::frame2RealTime(long frame, unsigned int sampleRate) +{ + if (frame < 0) return -frame2RealTime(-frame, sampleRate); + + RealTime rt; + rt.sec = frame / long(sampleRate); + frame -= rt.sec * long(sampleRate); + rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0); + return rt; +} + +const RealTime RealTime::zeroTime(0,0); + +} diff -r f8b38a017d9a -r 14029eb08472 src/SpectralCentroid.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SpectralCentroid.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,196 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "SpectralCentroid.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +#include + +#ifdef WIN32 +#define isnan(x) false +#define isinf(x) false +#endif + +SpectralCentroid::SpectralCentroid(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_blockSize(0) +{ +} + +SpectralCentroid::~SpectralCentroid() +{ +} + +string +SpectralCentroid::getIdentifier() const +{ + return "spectralcentroid"; +} + +string +SpectralCentroid::getName() const +{ + return "Spectral Centroid"; +} + +string +SpectralCentroid::getDescription() const +{ + return "Calculate the centroid frequency of the spectrum of the input signal"; +} + +string +SpectralCentroid::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +SpectralCentroid::getPluginVersion() const +{ + return 2; +} + +string +SpectralCentroid::getCopyright() const +{ + return "Freely redistributable (BSD license)"; +} + +bool +SpectralCentroid::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = stepSize; + m_blockSize = blockSize; + + return true; +} + +void +SpectralCentroid::reset() +{ +} + +SpectralCentroid::OutputList +SpectralCentroid::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor d; + d.identifier = "logcentroid"; + d.name = "Log Frequency Centroid"; + d.description = "Centroid of the log weighted frequency spectrum"; + d.unit = "Hz"; + d.hasFixedBinCount = true; + d.binCount = 1; + d.hasKnownExtents = false; + d.isQuantized = false; + d.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(d); + + d.identifier = "linearcentroid"; + d.name = "Linear Frequency Centroid"; + d.description = "Centroid of the linear frequency spectrum"; + list.push_back(d); + + return list; +} + +//static int scount = 0; + +SpectralCentroid::FeatureSet +SpectralCentroid::process(const float *const *inputBuffers, Vamp::RealTime timestamp) +{ + if (m_stepSize == 0) { + cerr << "ERROR: SpectralCentroid::process: " + << "SpectralCentroid has not been initialised" + << endl; + return FeatureSet(); + } + +// std::cerr << "SpectralCentroid::process: count = " << scount++ << ", timestamp = " << timestamp << ", total power = "; + + double numLin = 0.0, numLog = 0.0, denom = 0.0; + + for (size_t i = 1; i <= m_blockSize/2; ++i) { + double freq = (double(i) * m_inputSampleRate) / m_blockSize; + double real = inputBuffers[0][i*2]; + double imag = inputBuffers[0][i*2 + 1]; + double power = sqrt(real * real + imag * imag) / (m_blockSize/2); + numLin += freq * power; + numLog += log10f(freq) * power; + denom += power; + } + +// std::cerr << denom << std::endl; + + FeatureSet returnFeatures; + + if (denom != 0.0) { + float centroidLin = float(numLin / denom); + float centroidLog = powf(10, float(numLog / denom)); + + Feature feature; + feature.hasTimestamp = false; + if (!isnan(centroidLog) && !isinf(centroidLog)) { + feature.values.push_back(centroidLog); + } + returnFeatures[0].push_back(feature); + + feature.values.clear(); + if (!isnan(centroidLin) && !isinf(centroidLin)) { + feature.values.push_back(centroidLin); + } + returnFeatures[1].push_back(feature); + } + + return returnFeatures; +} + +SpectralCentroid::FeatureSet +SpectralCentroid::getRemainingFeatures() +{ + return FeatureSet(); +} + diff -r f8b38a017d9a -r 14029eb08472 src/ZeroCrossing.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ZeroCrossing.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,206 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "ZeroCrossing.h" + +using std::string; +using std::vector; +using std::cerr; +using std::endl; + +#include + +ZeroCrossing::ZeroCrossing(float inputSampleRate) : + Plugin(inputSampleRate), + m_stepSize(0), + m_previousSample(0.0f) +{ +} + +ZeroCrossing::~ZeroCrossing() +{ +} + +string +ZeroCrossing::getIdentifier() const +{ + return "zerocrossing"; +} + +string +ZeroCrossing::getName() const +{ + return "Zero Crossings"; +} + +string +ZeroCrossing::getDescription() const +{ + return "Detect and count zero crossing points"; +} + +string +ZeroCrossing::getMaker() const +{ + return "Vamp SDK Example Plugins"; +} + +int +ZeroCrossing::getPluginVersion() const +{ + return 2; +} + +string +ZeroCrossing::getCopyright() const +{ + return "Freely redistributable (BSD license)"; +} + +bool +ZeroCrossing::initialise(size_t channels, size_t stepSize, size_t blockSize) +{ + if (channels < getMinChannelCount() || + channels > getMaxChannelCount()) return false; + + m_stepSize = std::min(stepSize, blockSize); + + return true; +} + +void +ZeroCrossing::reset() +{ + m_previousSample = 0.0f; +} + +ZeroCrossing::OutputList +ZeroCrossing::getOutputDescriptors() const +{ + OutputList list; + + OutputDescriptor zc; + zc.identifier = "counts"; + zc.name = "Zero Crossing Counts"; + zc.description = "The number of zero crossing points per processing block"; + zc.unit = "crossings"; + zc.hasFixedBinCount = true; + zc.binCount = 1; + zc.hasKnownExtents = false; + zc.isQuantized = true; + zc.quantizeStep = 1.0; + zc.sampleType = OutputDescriptor::OneSamplePerStep; + list.push_back(zc); + + zc.identifier = "zerocrossings"; + zc.name = "Zero Crossings"; + zc.description = "The locations of zero crossing points"; + zc.unit = ""; + zc.hasFixedBinCount = true; + zc.binCount = 0; + zc.sampleType = OutputDescriptor::VariableSampleRate; + zc.sampleRate = m_inputSampleRate; + list.push_back(zc); + + return list; +} + +//static int scount = 0; + +ZeroCrossing::FeatureSet +ZeroCrossing::process(const float *const *inputBuffers, + Vamp::RealTime timestamp) +{ + if (m_stepSize == 0) { + cerr << "ERROR: ZeroCrossing::process: " + << "ZeroCrossing has not been initialised" + << endl; + return FeatureSet(); + } + +// std::cerr << "ZeroCrossing::process: count = " << scount++ << ", timestamp = " << timestamp << ", rms = "; + + float prev = m_previousSample; + size_t count = 0; + + FeatureSet returnFeatures; + +// double acc = 0.0; + + for (size_t i = 0; i < m_stepSize; ++i) { + + float sample = inputBuffers[0][i]; + bool crossing = false; + + if (sample <= 0.0) { + if (prev > 0.0) crossing = true; + } else if (sample > 0.0) { + if (prev <= 0.0) crossing = true; + } + + if (crossing) { + ++count; + Feature feature; + feature.hasTimestamp = true; + feature.timestamp = timestamp + + Vamp::RealTime::frame2RealTime(i, (size_t)m_inputSampleRate); + returnFeatures[1].push_back(feature); + } + +// acc += sample * sample; + + prev = sample; + } + +// acc /= m_stepSize; +// std::cerr << sqrt(acc) << std::endl; + + m_previousSample = prev; + + Feature feature; + feature.hasTimestamp = false; + feature.values.push_back(count); + + returnFeatures[0].push_back(feature); + return returnFeatures; +} + +ZeroCrossing::FeatureSet +ZeroCrossing::getRemainingFeatures() +{ + return FeatureSet(); +} + diff -r f8b38a017d9a -r 14029eb08472 src/plugins.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,66 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "vamp/vamp.h" +#include "vamp-sdk/PluginAdapter.h" + +#include "ZeroCrossing.h" +#include "SpectralCentroid.h" +#include "PercussionOnsetDetector.h" +#include "FixedTempoEstimator.h" +#include "AmplitudeFollower.h" + +static Vamp::PluginAdapter zeroCrossingAdapter; +static Vamp::PluginAdapter spectralCentroidAdapter; +static Vamp::PluginAdapter percussionOnsetAdapter; +static Vamp::PluginAdapter fixedTempoAdapter; +static Vamp::PluginAdapter amplitudeAdapter; + +const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version, + unsigned int index) +{ + if (version < 1) return 0; + + switch (index) { + case 0: return zeroCrossingAdapter.getDescriptor(); + case 1: return spectralCentroidAdapter.getDescriptor(); + case 2: return percussionOnsetAdapter.getDescriptor(); + case 3: return amplitudeAdapter.getDescriptor(); + case 4: return fixedTempoAdapter.getDescriptor(); + default: return 0; + } +} + diff -r f8b38a017d9a -r 14029eb08472 src/vamp-simple-host.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vamp-simple-host.cpp Thu Nov 06 14:05:33 2008 +0000 @@ -0,0 +1,644 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Vamp + + An API for audio analysis and feature extraction plugins. + + Centre for Digital Music, Queen Mary, University of London. + Copyright 2006 Chris Cannam. + FFT code from Don Cross's public domain FFT implementation. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +#include "vamp-sdk/PluginHostAdapter.h" +#include "vamp-sdk/hostext/PluginInputDomainAdapter.h" +#include "vamp-sdk/hostext/PluginLoader.h" +#include "vamp/vamp.h" + +#include +#include +#include +#include + +#include +#include + +#include "system.h" + +#include + +using namespace std; + +using Vamp::Plugin; +using Vamp::PluginHostAdapter; +using Vamp::RealTime; +using Vamp::HostExt::PluginLoader; +using Vamp::HostExt::PluginWrapper; +using Vamp::HostExt::PluginInputDomainAdapter; + +#define HOST_VERSION "1.3" + +enum Verbosity { + PluginIds, + PluginOutputIds, + PluginInformation +}; + +void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); +void transformInput(float *, size_t); +void fft(unsigned int, bool, double *, double *, double *, double *); +void printPluginPath(bool verbose); +void printPluginCategoryList(); +void enumeratePlugins(Verbosity); +void listPluginsInLibrary(string soname); +int runPlugin(string myname, string soname, string id, string output, + int outputNo, string inputFile, string outfilename, bool frames); + +void usage(const char *name) +{ + cerr << "\n" + << name << ": A simple Vamp plugin host.\n\n" + "Centre for Digital Music, Queen Mary, University of London.\n" + "Copyright 2006-2007 Chris Cannam and QMUL.\n" + "Freely redistributable; published under a BSD-style license.\n\n" + "Usage:\n\n" + " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" + " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n" + " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" + " audio data in \"file.wav\", retrieving the named \"output\", or output\n" + " number \"outputno\" (the first output by default) and dumping it to\n" + " standard output, or to \"out.txt\" if the -o option is given.\n\n" + " \"pluginlibrary\" should be a library name, not a file path; the\n" + " standard Vamp library search path will be used to locate it. If\n" + " a file path is supplied, the directory part(s) will be ignored.\n\n" + " If the -s option is given, results will be labelled with the audio\n" + " sample frame at which they occur. Otherwise, they will be labelled\n" + " with time in seconds.\n\n" + " " << name << " -l\n\n" + " -- List the plugin libraries and Vamp plugins in the library search path\n" + " in a verbose human-readable format.\n\n" + " " << name << " --list-ids\n\n" + " -- List the plugins in the search path in a terse machine-readable format,\n" + " in the form vamp:soname:identifier.\n\n" + " " << name << " --list-outputs\n\n" + " -- List the outputs for plugins in the search path in a machine-readable\n" + " format, in the form vamp:soname:identifier:output.\n\n" + " " << name << " --list-by-category\n\n" + " -- List the plugins as a plugin index by category, in a machine-readable\n" + " format. The format may change in future releases.\n\n" + " " << name << " -p\n\n" + " -- Print out the Vamp library search path.\n\n" + " " << name << " -v\n\n" + " -- Display version information only.\n" + << endl; + exit(2); +} + +int main(int argc, char **argv) +{ + char *scooter = argv[0]; + char *name = 0; + while (scooter && *scooter) { + if (*scooter == '/' || *scooter == '\\') name = ++scooter; + else ++scooter; + } + if (!name || !*name) name = argv[0]; + + if (argc < 2) usage(name); + + if (argc == 2) { + + if (!strcmp(argv[1], "-v")) { + + cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl + << "Vamp API version: " << VAMP_API_VERSION << endl + << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; + return 0; + + } else if (!strcmp(argv[1], "-l")) { + + printPluginPath(true); + enumeratePlugins(PluginInformation); + return 0; + + } else if (!strcmp(argv[1], "-p")) { + + printPluginPath(false); + return 0; + + } else if (!strcmp(argv[1], "--list-ids")) { + + enumeratePlugins(PluginIds); + return 0; + + } else if (!strcmp(argv[1], "--list-outputs")) { + + enumeratePlugins(PluginOutputIds); + return 0; + + } else if (!strcmp(argv[1], "--list-by-category")) { + + printPluginCategoryList(); + return 0; + + } else usage(name); + } + + if (argc < 3) usage(name); + + bool useFrames = false; + + int base = 1; + if (!strcmp(argv[1], "-s")) { + useFrames = true; + base = 2; + } + + string soname = argv[base]; + string wavname = argv[base+1]; + string plugid = ""; + string output = ""; + int outputNo = -1; + string outfilename; + + if (argc >= base+3) { + + int idx = base+2; + + if (isdigit(*argv[idx])) { + outputNo = atoi(argv[idx++]); + } + + if (argc == idx + 2) { + if (!strcmp(argv[idx], "-o")) { + outfilename = argv[idx+1]; + } else usage(name); + } else if (argc != idx) { + (usage(name)); + } + } + + cerr << endl << name << ": Running..." << endl; + + cerr << "Reading file: \"" << wavname << "\", writing to "; + if (outfilename == "") { + cerr << "standard output" << endl; + } else { + cerr << "\"" << outfilename << "\"" << endl; + } + + string::size_type sep = soname.find(':'); + + if (sep != string::npos) { + plugid = soname.substr(sep + 1); + soname = soname.substr(0, sep); + + sep = plugid.find(':'); + if (sep != string::npos) { + output = plugid.substr(sep + 1); + plugid = plugid.substr(0, sep); + } + } + + if (plugid == "") { + usage(name); + } + + if (output != "" && outputNo != -1) { + usage(name); + } + + if (output == "" && outputNo == -1) { + outputNo = 0; + } + + return runPlugin(name, soname, plugid, output, outputNo, + wavname, outfilename, useFrames); +} + + +int runPlugin(string myname, string soname, string id, + string output, int outputNo, string wavname, + string outfilename, bool useFrames) +{ + PluginLoader *loader = PluginLoader::getInstance(); + + PluginLoader::PluginKey key = loader->composePluginKey(soname, id); + + SNDFILE *sndfile; + SF_INFO sfinfo; + memset(&sfinfo, 0, sizeof(SF_INFO)); + + sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); + if (!sndfile) { + cerr << myname << ": ERROR: Failed to open input file \"" + << wavname << "\": " << sf_strerror(sndfile) << endl; + return 1; + } + + ofstream *out = 0; + if (outfilename != "") { + out = new ofstream(outfilename.c_str(), ios::out); + if (!*out) { + cerr << myname << ": ERROR: Failed to open output file \"" + << outfilename << "\" for writing" << endl; + delete out; + return 1; + } + } + + Plugin *plugin = loader->loadPlugin + (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); + if (!plugin) { + cerr << myname << ": ERROR: Failed to load plugin \"" << id + << "\" from library \"" << soname << "\"" << endl; + sf_close(sndfile); + if (out) { + out->close(); + delete out; + } + return 1; + } + + cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; + + int blockSize = plugin->getPreferredBlockSize(); + int stepSize = plugin->getPreferredStepSize(); + + if (blockSize == 0) { + blockSize = 1024; + } + if (stepSize == 0) { + if (plugin->getInputDomain() == Plugin::FrequencyDomain) { + stepSize = blockSize/2; + } else { + stepSize = blockSize; + } + } else if (stepSize > blockSize) { + cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; + if (plugin->getInputDomain() == Plugin::FrequencyDomain) { + blockSize = stepSize * 2; + } else { + blockSize = stepSize; + } + cerr << blockSize << endl; + } + + int channels = sfinfo.channels; + + float *filebuf = new float[blockSize * channels]; + float **plugbuf = new float*[channels]; + for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; + + cerr << "Using block size = " << blockSize << ", step size = " + << stepSize << endl; + + int minch = plugin->getMinChannelCount(); + int maxch = plugin->getMaxChannelCount(); + cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; + cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; + + Plugin::OutputList outputs = plugin->getOutputDescriptors(); + Plugin::OutputDescriptor od; + + int returnValue = 1; + int progress = 0; + + RealTime rt; + PluginWrapper *wrapper = 0; + RealTime adjustment = RealTime::zeroTime; + + if (outputs.empty()) { + cerr << "ERROR: Plugin has no outputs!" << endl; + goto done; + } + + if (outputNo < 0) { + + for (size_t oi = 0; oi < outputs.size(); ++oi) { + if (outputs[oi].identifier == output) { + outputNo = oi; + break; + } + } + + if (outputNo < 0) { + cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; + goto done; + } + + } else { + + if (int(outputs.size()) <= outputNo) { + cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; + goto done; + } + } + + od = outputs[outputNo]; + cerr << "Output is: \"" << od.identifier << "\"" << endl; + + if (!plugin->initialise(channels, stepSize, blockSize)) { + cerr << "ERROR: Plugin initialise (channels = " << channels + << ", stepSize = " << stepSize << ", blockSize = " + << blockSize << ") failed." << endl; + goto done; + } + + wrapper = dynamic_cast(plugin); + if (wrapper) { + PluginInputDomainAdapter *ida = + wrapper->getWrapper(); + if (ida) adjustment = ida->getTimestampAdjustment(); + } + + for (size_t i = 0; i < sfinfo.frames; i += stepSize) { + + int count; + + if (sf_seek(sndfile, i, SEEK_SET) < 0) { + cerr << "ERROR: sf_seek failed: " << sf_strerror(sndfile) << endl; + break; + } + + if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { + cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; + break; + } + + for (int c = 0; c < channels; ++c) { + int j = 0; + while (j < count) { + plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; + ++j; + } + while (j < blockSize) { + plugbuf[c][j] = 0.0f; + ++j; + } + } + + rt = RealTime::frame2RealTime(i, sfinfo.samplerate); + + printFeatures + (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), + sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt), + out, useFrames); + + int pp = progress; + progress = lrintf((float(i) / sfinfo.frames) * 100.f); + if (progress != pp && out) { + cerr << "\r" << progress << "%"; + } + } + if (out) cerr << "\rDone" << endl; + + rt = RealTime::frame2RealTime(sfinfo.frames, sfinfo.samplerate); + + printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), + sfinfo.samplerate, outputNo, + plugin->getRemainingFeatures(), out, useFrames); + + returnValue = 0; + +done: + delete plugin; + if (out) { + out->close(); + delete out; + } + sf_close(sndfile); + return returnValue; +} + +void +printFeatures(int frame, int sr, int output, + Plugin::FeatureSet features, ofstream *out, bool useFrames) +{ + for (unsigned int i = 0; i < features[output].size(); ++i) { + + if (useFrames) { + + int displayFrame = frame; + + if (features[output][i].hasTimestamp) { + displayFrame = RealTime::realTime2Frame + (features[output][i].timestamp, sr); + } + + (out ? *out : cout) << displayFrame; + + if (features[output][i].hasDuration) { + displayFrame = RealTime::realTime2Frame + (features[output][i].duration, sr); + (out ? *out : cout) << "," << displayFrame; + } + + (out ? *out : cout) << ":"; + + } else { + + RealTime rt = RealTime::frame2RealTime(frame, sr); + + if (features[output][i].hasTimestamp) { + rt = features[output][i].timestamp; + } + + (out ? *out : cout) << rt.toString(); + + if (features[output][i].hasDuration) { + rt = features[output][i].duration; + (out ? *out : cout) << "," << rt.toString(); + } + + (out ? *out : cout) << ":"; + } + + for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { + (out ? *out : cout) << " " << features[output][i].values[j]; + } + + (out ? *out : cout) << endl; + } +} + +void +printPluginPath(bool verbose) +{ + if (verbose) { + cout << "\nVamp plugin search path: "; + } + + vector path = PluginHostAdapter::getPluginPath(); + for (size_t i = 0; i < path.size(); ++i) { + if (verbose) { + cout << "[" << path[i] << "]"; + } else { + cout << path[i] << endl; + } + } + + if (verbose) cout << endl; +} + +void +enumeratePlugins(Verbosity verbosity) +{ + PluginLoader *loader = PluginLoader::getInstance(); + + if (verbosity == PluginInformation) { + cout << "\nVamp plugin libraries found in search path:" << endl; + } + + vector plugins = loader->listPlugins(); + typedef multimap + LibraryMap; + LibraryMap libraryMap; + + for (size_t i = 0; i < plugins.size(); ++i) { + string path = loader->getLibraryPathForPlugin(plugins[i]); + libraryMap.insert(LibraryMap::value_type(path, plugins[i])); + } + + string prevPath = ""; + int index = 0; + + for (LibraryMap::iterator i = libraryMap.begin(); + i != libraryMap.end(); ++i) { + + string path = i->first; + PluginLoader::PluginKey key = i->second; + + if (path != prevPath) { + prevPath = path; + index = 0; + if (verbosity == PluginInformation) { + cout << "\n " << path << ":" << endl; + } + } + + Plugin *plugin = loader->loadPlugin(key, 48000); + if (plugin) { + + char c = char('A' + index); + if (c > 'Z') c = char('a' + (index - 26)); + + if (verbosity == PluginInformation) { + + cout << " [" << c << "] [v" + << plugin->getVampApiVersion() << "] " + << plugin->getName() << ", \"" + << plugin->getIdentifier() << "\"" << " [" + << plugin->getMaker() << "]" << endl; + + PluginLoader::PluginCategoryHierarchy category = + loader->getPluginCategory(key); + + if (!category.empty()) { + cout << " "; + for (size_t ci = 0; ci < category.size(); ++ci) { + cout << " > " << category[ci]; + } + cout << endl; + } + + if (plugin->getDescription() != "") { + cout << " - " << plugin->getDescription() << endl; + } + + } else if (verbosity == PluginIds) { + cout << "vamp:" << key << endl; + } + + Plugin::OutputList outputs = + plugin->getOutputDescriptors(); + + if (outputs.size() > 1 || verbosity == PluginOutputIds) { + for (size_t j = 0; j < outputs.size(); ++j) { + if (verbosity == PluginInformation) { + cout << " (" << j << ") " + << outputs[j].name << ", \"" + << outputs[j].identifier << "\"" << endl; + if (outputs[j].description != "") { + cout << " - " + << outputs[j].description << endl; + } + } else if (verbosity == PluginOutputIds) { + cout << "vamp:" << key << ":" << outputs[j].identifier << endl; + } + } + } + + ++index; + + delete plugin; + } + } + + if (verbosity == PluginInformation) { + cout << endl; + } +} + +void +printPluginCategoryList() +{ + PluginLoader *loader = PluginLoader::getInstance(); + + vector plugins = loader->listPlugins(); + + set printedcats; + + for (size_t i = 0; i < plugins.size(); ++i) { + + PluginLoader::PluginKey key = plugins[i]; + + PluginLoader::PluginCategoryHierarchy category = + loader->getPluginCategory(key); + + Plugin *plugin = loader->loadPlugin(key, 48000); + if (!plugin) continue; + + string catstr = ""; + + if (category.empty()) catstr = '|'; + else { + for (size_t j = 0; j < category.size(); ++j) { + catstr += category[j]; + catstr += '|'; + if (printedcats.find(catstr) == printedcats.end()) { + std::cout << catstr << std::endl; + printedcats.insert(catstr); + } + } + } + + std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl; + } +} + diff -r f8b38a017d9a -r 14029eb08472 vamp-sdk/PluginAdapter.cpp --- a/vamp-sdk/PluginAdapter.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,873 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "PluginAdapter.h" - -#include -#include - -//#define DEBUG_PLUGIN_ADAPTER 1 - -namespace Vamp { - -class PluginAdapterBase::Impl -{ -public: - Impl(PluginAdapterBase *); - ~Impl(); - - const VampPluginDescriptor *getDescriptor(); - -protected: - PluginAdapterBase *m_base; - - static VampPluginHandle vampInstantiate(const VampPluginDescriptor *desc, - float inputSampleRate); - - static void vampCleanup(VampPluginHandle handle); - - static int vampInitialise(VampPluginHandle handle, unsigned int channels, - unsigned int stepSize, unsigned int blockSize); - - static void vampReset(VampPluginHandle handle); - - static float vampGetParameter(VampPluginHandle handle, int param); - static void vampSetParameter(VampPluginHandle handle, int param, float value); - - static unsigned int vampGetCurrentProgram(VampPluginHandle handle); - static void vampSelectProgram(VampPluginHandle handle, unsigned int program); - - static unsigned int vampGetPreferredStepSize(VampPluginHandle handle); - static unsigned int vampGetPreferredBlockSize(VampPluginHandle handle); - static unsigned int vampGetMinChannelCount(VampPluginHandle handle); - static unsigned int vampGetMaxChannelCount(VampPluginHandle handle); - - static unsigned int vampGetOutputCount(VampPluginHandle handle); - - static VampOutputDescriptor *vampGetOutputDescriptor(VampPluginHandle handle, - unsigned int i); - - static void vampReleaseOutputDescriptor(VampOutputDescriptor *desc); - - static VampFeatureList *vampProcess(VampPluginHandle handle, - const float *const *inputBuffers, - int sec, - int nsec); - - static VampFeatureList *vampGetRemainingFeatures(VampPluginHandle handle); - - static void vampReleaseFeatureSet(VampFeatureList *fs); - - void cleanup(Plugin *plugin); - void checkOutputMap(Plugin *plugin); - unsigned int getOutputCount(Plugin *plugin); - VampOutputDescriptor *getOutputDescriptor(Plugin *plugin, - unsigned int i); - VampFeatureList *process(Plugin *plugin, - const float *const *inputBuffers, - int sec, int nsec); - VampFeatureList *getRemainingFeatures(Plugin *plugin); - VampFeatureList *convertFeatures(Plugin *plugin, - const Plugin::FeatureSet &features); - - // maps both plugins and descriptors to adapters - typedef std::map AdapterMap; - static AdapterMap *m_adapterMap; - static Impl *lookupAdapter(VampPluginHandle); - - bool m_populated; - VampPluginDescriptor m_descriptor; - Plugin::ParameterList m_parameters; - Plugin::ProgramList m_programs; - - typedef std::map OutputMap; - OutputMap m_pluginOutputs; - - std::map m_fs; - std::map > m_fsizes; - std::map > > m_fvsizes; - void resizeFS(Plugin *plugin, int n); - void resizeFL(Plugin *plugin, int n, size_t sz); - void resizeFV(Plugin *plugin, int n, int j, size_t sz); -}; - -PluginAdapterBase::PluginAdapterBase() -{ - m_impl = new Impl(this); -} - -PluginAdapterBase::~PluginAdapterBase() -{ - delete m_impl; -} - -const VampPluginDescriptor * -PluginAdapterBase::getDescriptor() -{ - return m_impl->getDescriptor(); -} - -PluginAdapterBase::Impl::Impl(PluginAdapterBase *base) : - m_base(base), - m_populated(false) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl[" << this << "]::Impl" << std::endl; -#endif -} - -const VampPluginDescriptor * -PluginAdapterBase::Impl::getDescriptor() -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl[" << this << "]::getDescriptor" << std::endl; -#endif - - if (m_populated) return &m_descriptor; - - Plugin *plugin = m_base->createPlugin(48000); - - if (plugin->getVampApiVersion() != VAMP_API_VERSION) { - std::cerr << "Vamp::PluginAdapterBase::Impl::getDescriptor: ERROR: " - << "API version " << plugin->getVampApiVersion() - << " for\nplugin \"" << plugin->getIdentifier() << "\" " - << "differs from version " - << VAMP_API_VERSION << " for adapter.\n" - << "This plugin is probably linked against a different version of the Vamp SDK\n" - << "from the version it was compiled with. It will need to be re-linked correctly\n" - << "before it can be used." << std::endl; - delete plugin; - return 0; - } - - m_parameters = plugin->getParameterDescriptors(); - m_programs = plugin->getPrograms(); - - m_descriptor.vampApiVersion = plugin->getVampApiVersion(); - m_descriptor.identifier = strdup(plugin->getIdentifier().c_str()); - m_descriptor.name = strdup(plugin->getName().c_str()); - m_descriptor.description = strdup(plugin->getDescription().c_str()); - m_descriptor.maker = strdup(plugin->getMaker().c_str()); - m_descriptor.pluginVersion = plugin->getPluginVersion(); - m_descriptor.copyright = strdup(plugin->getCopyright().c_str()); - - m_descriptor.parameterCount = m_parameters.size(); - m_descriptor.parameters = (const VampParameterDescriptor **) - malloc(m_parameters.size() * sizeof(VampParameterDescriptor)); - - unsigned int i; - - for (i = 0; i < m_parameters.size(); ++i) { - VampParameterDescriptor *desc = (VampParameterDescriptor *) - malloc(sizeof(VampParameterDescriptor)); - desc->identifier = strdup(m_parameters[i].identifier.c_str()); - desc->name = strdup(m_parameters[i].name.c_str()); - desc->description = strdup(m_parameters[i].description.c_str()); - desc->unit = strdup(m_parameters[i].unit.c_str()); - desc->minValue = m_parameters[i].minValue; - desc->maxValue = m_parameters[i].maxValue; - desc->defaultValue = m_parameters[i].defaultValue; - desc->isQuantized = m_parameters[i].isQuantized; - desc->quantizeStep = m_parameters[i].quantizeStep; - desc->valueNames = 0; - if (desc->isQuantized && !m_parameters[i].valueNames.empty()) { - desc->valueNames = (const char **) - malloc((m_parameters[i].valueNames.size()+1) * sizeof(char *)); - for (unsigned int j = 0; j < m_parameters[i].valueNames.size(); ++j) { - desc->valueNames[j] = strdup(m_parameters[i].valueNames[j].c_str()); - } - desc->valueNames[m_parameters[i].valueNames.size()] = 0; - } - m_descriptor.parameters[i] = desc; - } - - m_descriptor.programCount = m_programs.size(); - m_descriptor.programs = (const char **) - malloc(m_programs.size() * sizeof(const char *)); - - for (i = 0; i < m_programs.size(); ++i) { - m_descriptor.programs[i] = strdup(m_programs[i].c_str()); - } - - if (plugin->getInputDomain() == Plugin::FrequencyDomain) { - m_descriptor.inputDomain = vampFrequencyDomain; - } else { - m_descriptor.inputDomain = vampTimeDomain; - } - - m_descriptor.instantiate = vampInstantiate; - m_descriptor.cleanup = vampCleanup; - m_descriptor.initialise = vampInitialise; - m_descriptor.reset = vampReset; - m_descriptor.getParameter = vampGetParameter; - m_descriptor.setParameter = vampSetParameter; - m_descriptor.getCurrentProgram = vampGetCurrentProgram; - m_descriptor.selectProgram = vampSelectProgram; - m_descriptor.getPreferredStepSize = vampGetPreferredStepSize; - m_descriptor.getPreferredBlockSize = vampGetPreferredBlockSize; - m_descriptor.getMinChannelCount = vampGetMinChannelCount; - m_descriptor.getMaxChannelCount = vampGetMaxChannelCount; - m_descriptor.getOutputCount = vampGetOutputCount; - m_descriptor.getOutputDescriptor = vampGetOutputDescriptor; - m_descriptor.releaseOutputDescriptor = vampReleaseOutputDescriptor; - m_descriptor.process = vampProcess; - m_descriptor.getRemainingFeatures = vampGetRemainingFeatures; - m_descriptor.releaseFeatureSet = vampReleaseFeatureSet; - - if (!m_adapterMap) { - m_adapterMap = new AdapterMap; - } - (*m_adapterMap)[&m_descriptor] = this; - - delete plugin; - - m_populated = true; - return &m_descriptor; -} - -PluginAdapterBase::Impl::~Impl() -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl[" << this << "]::~Impl" << std::endl; -#endif - - if (!m_populated) return; - - free((void *)m_descriptor.identifier); - free((void *)m_descriptor.name); - free((void *)m_descriptor.description); - free((void *)m_descriptor.maker); - free((void *)m_descriptor.copyright); - - for (unsigned int i = 0; i < m_descriptor.parameterCount; ++i) { - const VampParameterDescriptor *desc = m_descriptor.parameters[i]; - free((void *)desc->identifier); - free((void *)desc->name); - free((void *)desc->description); - free((void *)desc->unit); - if (desc->valueNames) { - for (unsigned int j = 0; desc->valueNames[j]; ++j) { - free((void *)desc->valueNames[j]); - } - free((void *)desc->valueNames); - } - } - free((void *)m_descriptor.parameters); - - for (unsigned int i = 0; i < m_descriptor.programCount; ++i) { - free((void *)m_descriptor.programs[i]); - } - free((void *)m_descriptor.programs); - - if (m_adapterMap) { - - m_adapterMap->erase(&m_descriptor); - - if (m_adapterMap->empty()) { - delete m_adapterMap; - m_adapterMap = 0; - } - } -} - -PluginAdapterBase::Impl * -PluginAdapterBase::Impl::lookupAdapter(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::lookupAdapter(" << handle << ")" << std::endl; -#endif - - if (!m_adapterMap) return 0; - AdapterMap::const_iterator i = m_adapterMap->find(handle); - if (i == m_adapterMap->end()) return 0; - return i->second; -} - -VampPluginHandle -PluginAdapterBase::Impl::vampInstantiate(const VampPluginDescriptor *desc, - float inputSampleRate) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << ")" << std::endl; -#endif - - if (!m_adapterMap) { - m_adapterMap = new AdapterMap(); - } - - if (m_adapterMap->find(desc) == m_adapterMap->end()) { - std::cerr << "WARNING: PluginAdapterBase::Impl::vampInstantiate: Descriptor " << desc << " not in adapter map" << std::endl; - return 0; - } - - Impl *adapter = (*m_adapterMap)[desc]; - if (desc != &adapter->m_descriptor) return 0; - - Plugin *plugin = adapter->m_base->createPlugin(inputSampleRate); - if (plugin) { - (*m_adapterMap)[plugin] = adapter; - } - -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampInstantiate(" << desc << "): returning handle " << plugin << std::endl; -#endif - - return plugin; -} - -void -PluginAdapterBase::Impl::vampCleanup(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampCleanup(" << handle << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) { - delete ((Plugin *)handle); - return; - } - adapter->cleanup(((Plugin *)handle)); -} - -int -PluginAdapterBase::Impl::vampInitialise(VampPluginHandle handle, - unsigned int channels, - unsigned int stepSize, - unsigned int blockSize) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampInitialise(" << handle << ", " << channels << ", " << stepSize << ", " << blockSize << ")" << std::endl; -#endif - - bool result = ((Plugin *)handle)->initialise - (channels, stepSize, blockSize); - return result ? 1 : 0; -} - -void -PluginAdapterBase::Impl::vampReset(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampReset(" << handle << ")" << std::endl; -#endif - - ((Plugin *)handle)->reset(); -} - -float -PluginAdapterBase::Impl::vampGetParameter(VampPluginHandle handle, - int param) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetParameter(" << handle << ", " << param << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0.0; - Plugin::ParameterList &list = adapter->m_parameters; - return ((Plugin *)handle)->getParameter(list[param].identifier); -} - -void -PluginAdapterBase::Impl::vampSetParameter(VampPluginHandle handle, - int param, float value) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampSetParameter(" << handle << ", " << param << ", " << value << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return; - Plugin::ParameterList &list = adapter->m_parameters; - ((Plugin *)handle)->setParameter(list[param].identifier, value); -} - -unsigned int -PluginAdapterBase::Impl::vampGetCurrentProgram(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetCurrentProgram(" << handle << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - Plugin::ProgramList &list = adapter->m_programs; - std::string program = ((Plugin *)handle)->getCurrentProgram(); - for (unsigned int i = 0; i < list.size(); ++i) { - if (list[i] == program) return i; - } - return 0; -} - -void -PluginAdapterBase::Impl::vampSelectProgram(VampPluginHandle handle, - unsigned int program) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampSelectProgram(" << handle << ", " << program << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return; - Plugin::ProgramList &list = adapter->m_programs; - ((Plugin *)handle)->selectProgram(list[program]); -} - -unsigned int -PluginAdapterBase::Impl::vampGetPreferredStepSize(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetPreferredStepSize(" << handle << ")" << std::endl; -#endif - - return ((Plugin *)handle)->getPreferredStepSize(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetPreferredBlockSize(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetPreferredBlockSize(" << handle << ")" << std::endl; -#endif - - return ((Plugin *)handle)->getPreferredBlockSize(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetMinChannelCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetMinChannelCount(" << handle << ")" << std::endl; -#endif - - return ((Plugin *)handle)->getMinChannelCount(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetMaxChannelCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetMaxChannelCount(" << handle << ")" << std::endl; -#endif - - return ((Plugin *)handle)->getMaxChannelCount(); -} - -unsigned int -PluginAdapterBase::Impl::vampGetOutputCount(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetOutputCount(" << handle << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - -// std::cerr << "vampGetOutputCount: handle " << handle << " -> adapter "<< adapter << std::endl; - - if (!adapter) return 0; - return adapter->getOutputCount((Plugin *)handle); -} - -VampOutputDescriptor * -PluginAdapterBase::Impl::vampGetOutputDescriptor(VampPluginHandle handle, - unsigned int i) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetOutputDescriptor(" << handle << ", " << i << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - -// std::cerr << "vampGetOutputDescriptor: handle " << handle << " -> adapter "<< adapter << std::endl; - - if (!adapter) return 0; - return adapter->getOutputDescriptor((Plugin *)handle, i); -} - -void -PluginAdapterBase::Impl::vampReleaseOutputDescriptor(VampOutputDescriptor *desc) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampReleaseOutputDescriptor(" << desc << ")" << std::endl; -#endif - - if (desc->identifier) free((void *)desc->identifier); - if (desc->name) free((void *)desc->name); - if (desc->description) free((void *)desc->description); - if (desc->unit) free((void *)desc->unit); - if (desc->hasFixedBinCount && desc->binNames) { - for (unsigned int i = 0; i < desc->binCount; ++i) { - if (desc->binNames[i]) { - free((void *)desc->binNames[i]); - } - } - } - if (desc->binNames) free((void *)desc->binNames); - free((void *)desc); -} - -VampFeatureList * -PluginAdapterBase::Impl::vampProcess(VampPluginHandle handle, - const float *const *inputBuffers, - int sec, - int nsec) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampProcess(" << handle << ", " << sec << ", " << nsec << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - return adapter->process((Plugin *)handle, - inputBuffers, sec, nsec); -} - -VampFeatureList * -PluginAdapterBase::Impl::vampGetRemainingFeatures(VampPluginHandle handle) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampGetRemainingFeatures(" << handle << ")" << std::endl; -#endif - - Impl *adapter = lookupAdapter(handle); - if (!adapter) return 0; - return adapter->getRemainingFeatures((Plugin *)handle); -} - -void -PluginAdapterBase::Impl::vampReleaseFeatureSet(VampFeatureList *fs) -{ -#ifdef DEBUG_PLUGIN_ADAPTER - std::cerr << "PluginAdapterBase::Impl::vampReleaseFeatureSet" << std::endl; -#endif -} - -void -PluginAdapterBase::Impl::cleanup(Plugin *plugin) -{ - if (m_fs.find(plugin) != m_fs.end()) { - size_t outputCount = 0; - if (m_pluginOutputs[plugin]) { - outputCount = m_pluginOutputs[plugin]->size(); - } - VampFeatureList *list = m_fs[plugin]; - for (unsigned int i = 0; i < outputCount; ++i) { - for (unsigned int j = 0; j < m_fsizes[plugin][i]; ++j) { - if (list[i].features[j].v1.label) { - free(list[i].features[j].v1.label); - } - if (list[i].features[j].v1.values) { - free(list[i].features[j].v1.values); - } - } - if (list[i].features) free(list[i].features); - } - m_fs.erase(plugin); - m_fsizes.erase(plugin); - m_fvsizes.erase(plugin); - } - - if (m_pluginOutputs.find(plugin) != m_pluginOutputs.end()) { - delete m_pluginOutputs[plugin]; - m_pluginOutputs.erase(plugin); - } - - if (m_adapterMap) { - m_adapterMap->erase(plugin); - - if (m_adapterMap->empty()) { - delete m_adapterMap; - m_adapterMap = 0; - } - } - - delete ((Plugin *)plugin); -} - -void -PluginAdapterBase::Impl::checkOutputMap(Plugin *plugin) -{ - if (m_pluginOutputs.find(plugin) == m_pluginOutputs.end() || - !m_pluginOutputs[plugin]) { - m_pluginOutputs[plugin] = new Plugin::OutputList - (plugin->getOutputDescriptors()); -// std::cerr << "PluginAdapterBase::Impl::checkOutputMap: Have " << m_pluginOutputs[plugin]->size() << " outputs for plugin " << plugin->getIdentifier() << std::endl; - } -} - -unsigned int -PluginAdapterBase::Impl::getOutputCount(Plugin *plugin) -{ - checkOutputMap(plugin); - return m_pluginOutputs[plugin]->size(); -} - -VampOutputDescriptor * -PluginAdapterBase::Impl::getOutputDescriptor(Plugin *plugin, - unsigned int i) -{ - checkOutputMap(plugin); - Plugin::OutputDescriptor &od = - (*m_pluginOutputs[plugin])[i]; - - VampOutputDescriptor *desc = (VampOutputDescriptor *) - malloc(sizeof(VampOutputDescriptor)); - - desc->identifier = strdup(od.identifier.c_str()); - desc->name = strdup(od.name.c_str()); - desc->description = strdup(od.description.c_str()); - desc->unit = strdup(od.unit.c_str()); - desc->hasFixedBinCount = od.hasFixedBinCount; - desc->binCount = od.binCount; - - if (od.hasFixedBinCount && od.binCount > 0) { - desc->binNames = (const char **) - malloc(od.binCount * sizeof(const char *)); - - for (unsigned int i = 0; i < od.binCount; ++i) { - if (i < od.binNames.size()) { - desc->binNames[i] = strdup(od.binNames[i].c_str()); - } else { - desc->binNames[i] = 0; - } - } - } else { - desc->binNames = 0; - } - - desc->hasKnownExtents = od.hasKnownExtents; - desc->minValue = od.minValue; - desc->maxValue = od.maxValue; - desc->isQuantized = od.isQuantized; - desc->quantizeStep = od.quantizeStep; - - switch (od.sampleType) { - case Plugin::OutputDescriptor::OneSamplePerStep: - desc->sampleType = vampOneSamplePerStep; break; - case Plugin::OutputDescriptor::FixedSampleRate: - desc->sampleType = vampFixedSampleRate; break; - case Plugin::OutputDescriptor::VariableSampleRate: - desc->sampleType = vampVariableSampleRate; break; - } - - desc->sampleRate = od.sampleRate; - desc->hasDuration = od.hasDuration; - - return desc; -} - -VampFeatureList * -PluginAdapterBase::Impl::process(Plugin *plugin, - const float *const *inputBuffers, - int sec, int nsec) -{ -// std::cerr << "PluginAdapterBase::Impl::process" << std::endl; - RealTime rt(sec, nsec); - checkOutputMap(plugin); - return convertFeatures(plugin, plugin->process(inputBuffers, rt)); -} - -VampFeatureList * -PluginAdapterBase::Impl::getRemainingFeatures(Plugin *plugin) -{ -// std::cerr << "PluginAdapterBase::Impl::getRemainingFeatures" << std::endl; - checkOutputMap(plugin); - return convertFeatures(plugin, plugin->getRemainingFeatures()); -} - -VampFeatureList * -PluginAdapterBase::Impl::convertFeatures(Plugin *plugin, - const Plugin::FeatureSet &features) -{ - int lastN = -1; - - int outputCount = 0; - if (m_pluginOutputs[plugin]) outputCount = m_pluginOutputs[plugin]->size(); - - resizeFS(plugin, outputCount); - VampFeatureList *fs = m_fs[plugin]; - -// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: sizeof(Feature) == " << sizeof(Plugin::Feature) << ", sizeof(VampFeature) == " << sizeof(VampFeature) << ", sizeof(VampFeatureList) == " << sizeof(VampFeatureList) << std::endl; - - for (Plugin::FeatureSet::const_iterator fi = features.begin(); - fi != features.end(); ++fi) { - - int n = fi->first; - -// std::cerr << "PluginAdapterBase::Impl::convertFeatures: n = " << n << std::endl; - - if (n >= int(outputCount)) { - std::cerr << "WARNING: PluginAdapterBase::Impl::convertFeatures: Too many outputs from plugin (" << n+1 << ", only should be " << outputCount << ")" << std::endl; - continue; - } - - if (n > lastN + 1) { - for (int i = lastN + 1; i < n; ++i) { - fs[i].featureCount = 0; - } - } - - const Plugin::FeatureList &fl = fi->second; - - size_t sz = fl.size(); - if (sz > m_fsizes[plugin][n]) resizeFL(plugin, n, sz); - fs[n].featureCount = sz; - - for (size_t j = 0; j < sz; ++j) { - -// std::cerr << "PluginAdapterBase::Impl::convertFeatures: j = " << j << std::endl; - - VampFeature *feature = &fs[n].features[j].v1; - - feature->hasTimestamp = fl[j].hasTimestamp; - feature->sec = fl[j].timestamp.sec; - feature->nsec = fl[j].timestamp.nsec; - feature->valueCount = fl[j].values.size(); - - VampFeatureV2 *v2 = &fs[n].features[j + sz].v2; - - v2->hasDuration = fl[j].hasDuration; - v2->durationSec = fl[j].duration.sec; - v2->durationNsec = fl[j].duration.nsec; - - if (feature->label) free(feature->label); - - if (fl[j].label.empty()) { - feature->label = 0; - } else { - feature->label = strdup(fl[j].label.c_str()); - } - - if (feature->valueCount > m_fvsizes[plugin][n][j]) { - resizeFV(plugin, n, j, feature->valueCount); - } - - for (unsigned int k = 0; k < feature->valueCount; ++k) { -// std::cerr << "PluginAdapterBase::Impl::convertFeatures: k = " << k << std::endl; - feature->values[k] = fl[j].values[k]; - } - } - - lastN = n; - } - - if (lastN == -1) return 0; - - if (int(outputCount) > lastN + 1) { - for (int i = lastN + 1; i < int(outputCount); ++i) { - fs[i].featureCount = 0; - } - } - -// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: have " << outputCount << " outputs" << std::endl; -// for (int i = 0; i < outputCount; ++i) { -// std::cerr << "PluginAdapter(v2)::convertFeatures: NOTE: output " << i << " has " << fs[i].featureCount << " features" << std::endl; -// } - - - return fs; -} - -void -PluginAdapterBase::Impl::resizeFS(Plugin *plugin, int n) -{ -// std::cerr << "PluginAdapterBase::Impl::resizeFS(" << plugin << ", " << n << ")" << std::endl; - - int i = m_fsizes[plugin].size(); - if (i >= n) return; - -// std::cerr << "resizing from " << i << std::endl; - - m_fs[plugin] = (VampFeatureList *)realloc - (m_fs[plugin], n * sizeof(VampFeatureList)); - - while (i < n) { - m_fs[plugin][i].featureCount = 0; - m_fs[plugin][i].features = 0; - m_fsizes[plugin].push_back(0); - m_fvsizes[plugin].push_back(std::vector()); - i++; - } -} - -void -PluginAdapterBase::Impl::resizeFL(Plugin *plugin, int n, size_t sz) -{ -// std::cerr << "PluginAdapterBase::Impl::resizeFL(" << plugin << ", " << n << ", " -// << sz << ")" << std::endl; - - size_t i = m_fsizes[plugin][n]; - if (i >= sz) return; - -// std::cerr << "resizing from " << i << std::endl; - - m_fs[plugin][n].features = (VampFeatureUnion *)realloc - (m_fs[plugin][n].features, 2 * sz * sizeof(VampFeatureUnion)); - - while (m_fsizes[plugin][n] < sz) { - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.hasTimestamp = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.valueCount = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.values = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n]].v1.label = 0; - m_fs[plugin][n].features[m_fsizes[plugin][n] + sz].v2.hasDuration = 0; - m_fvsizes[plugin][n].push_back(0); - m_fsizes[plugin][n]++; - } -} - -void -PluginAdapterBase::Impl::resizeFV(Plugin *plugin, int n, int j, size_t sz) -{ -// std::cerr << "PluginAdapterBase::Impl::resizeFV(" << plugin << ", " << n << ", " -// << j << ", " << sz << ")" << std::endl; - - size_t i = m_fvsizes[plugin][n][j]; - if (i >= sz) return; - -// std::cerr << "resizing from " << i << std::endl; - - m_fs[plugin][n].features[j].v1.values = (float *)realloc - (m_fs[plugin][n].features[j].v1.values, sz * sizeof(float)); - - m_fvsizes[plugin][n][j] = sz; -} - -PluginAdapterBase::Impl::AdapterMap * -PluginAdapterBase::Impl::m_adapterMap = 0; - -} - diff -r f8b38a017d9a -r 14029eb08472 vamp-sdk/PluginHostAdapter.cpp --- a/vamp-sdk/PluginHostAdapter.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,447 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -#include "PluginHostAdapter.h" -#include - -namespace Vamp -{ - -PluginHostAdapter::PluginHostAdapter(const VampPluginDescriptor *descriptor, - float inputSampleRate) : - Plugin(inputSampleRate), - m_descriptor(descriptor) -{ -// std::cerr << "PluginHostAdapter::PluginHostAdapter (plugin = " << descriptor->name << ")" << std::endl; - m_handle = m_descriptor->instantiate(m_descriptor, inputSampleRate); - if (!m_handle) { -// std::cerr << "WARNING: PluginHostAdapter: Plugin instantiation failed for plugin " << m_descriptor->name << std::endl; - } -} - -PluginHostAdapter::~PluginHostAdapter() -{ -// std::cerr << "PluginHostAdapter::~PluginHostAdapter (plugin = " << m_descriptor->name << ")" << std::endl; - if (m_handle) m_descriptor->cleanup(m_handle); -} - -std::vector -PluginHostAdapter::getPluginPath() -{ - std::vector path; - std::string envPath; - - char *cpath = getenv("VAMP_PATH"); - if (cpath) envPath = cpath; - -#ifdef _WIN32 -#define PATH_SEPARATOR ';' -#define DEFAULT_VAMP_PATH "%ProgramFiles%\\Vamp Plugins" -#else -#define PATH_SEPARATOR ':' -#ifdef __APPLE__ -#define DEFAULT_VAMP_PATH "$HOME/Library/Audio/Plug-Ins/Vamp:/Library/Audio/Plug-Ins/Vamp" -#else -#define DEFAULT_VAMP_PATH "$HOME/vamp:$HOME/.vamp:/usr/local/lib/vamp:/usr/lib/vamp" -#endif -#endif - - if (envPath == "") { - envPath = DEFAULT_VAMP_PATH; - char *chome = getenv("HOME"); - if (chome) { - std::string home(chome); - std::string::size_type f; - while ((f = envPath.find("$HOME")) != std::string::npos && - f < envPath.length()) { - envPath.replace(f, 5, home); - } - } -#ifdef _WIN32 - char *cpfiles = getenv("ProgramFiles"); - if (!cpfiles) cpfiles = "C:\\Program Files"; - std::string pfiles(cpfiles); - std::string::size_type f; - while ((f = envPath.find("%ProgramFiles%")) != std::string::npos && - f < envPath.length()) { - envPath.replace(f, 14, pfiles); - } -#endif - } - - std::string::size_type index = 0, newindex = 0; - - while ((newindex = envPath.find(PATH_SEPARATOR, index)) < envPath.size()) { - path.push_back(envPath.substr(index, newindex - index)); - index = newindex + 1; - } - - path.push_back(envPath.substr(index)); - - return path; -} - -bool -PluginHostAdapter::initialise(size_t channels, - size_t stepSize, - size_t blockSize) -{ - if (!m_handle) return false; - return m_descriptor->initialise(m_handle, channels, stepSize, blockSize) ? - true : false; -} - -void -PluginHostAdapter::reset() -{ - if (!m_handle) { -// std::cerr << "PluginHostAdapter::reset: no handle" << std::endl; - return; - } -// std::cerr << "PluginHostAdapter::reset(" << m_handle << ")" << std::endl; - m_descriptor->reset(m_handle); -} - -PluginHostAdapter::InputDomain -PluginHostAdapter::getInputDomain() const -{ - if (m_descriptor->inputDomain == vampFrequencyDomain) { - return FrequencyDomain; - } else { - return TimeDomain; - } -} - -unsigned int -PluginHostAdapter::getVampApiVersion() const -{ - return m_descriptor->vampApiVersion; -} - -std::string -PluginHostAdapter::getIdentifier() const -{ - return m_descriptor->identifier; -} - -std::string -PluginHostAdapter::getName() const -{ - return m_descriptor->name; -} - -std::string -PluginHostAdapter::getDescription() const -{ - return m_descriptor->description; -} - -std::string -PluginHostAdapter::getMaker() const -{ - return m_descriptor->maker; -} - -int -PluginHostAdapter::getPluginVersion() const -{ - return m_descriptor->pluginVersion; -} - -std::string -PluginHostAdapter::getCopyright() const -{ - return m_descriptor->copyright; -} - -PluginHostAdapter::ParameterList -PluginHostAdapter::getParameterDescriptors() const -{ - ParameterList list; - for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { - const VampParameterDescriptor *spd = m_descriptor->parameters[i]; - ParameterDescriptor pd; - pd.identifier = spd->identifier; - pd.name = spd->name; - pd.description = spd->description; - pd.unit = spd->unit; - pd.minValue = spd->minValue; - pd.maxValue = spd->maxValue; - pd.defaultValue = spd->defaultValue; - pd.isQuantized = spd->isQuantized; - pd.quantizeStep = spd->quantizeStep; - if (pd.isQuantized && spd->valueNames) { - for (unsigned int j = 0; spd->valueNames[j]; ++j) { - pd.valueNames.push_back(spd->valueNames[j]); - } - } - list.push_back(pd); - } - return list; -} - -float -PluginHostAdapter::getParameter(std::string param) const -{ - if (!m_handle) return 0.0; - - for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { - if (param == m_descriptor->parameters[i]->identifier) { - return m_descriptor->getParameter(m_handle, i); - } - } - - return 0.0; -} - -void -PluginHostAdapter::setParameter(std::string param, - float value) -{ - if (!m_handle) return; - - for (unsigned int i = 0; i < m_descriptor->parameterCount; ++i) { - if (param == m_descriptor->parameters[i]->identifier) { - m_descriptor->setParameter(m_handle, i, value); - return; - } - } -} - -PluginHostAdapter::ProgramList -PluginHostAdapter::getPrograms() const -{ - ProgramList list; - - for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { - list.push_back(m_descriptor->programs[i]); - } - - return list; -} - -std::string -PluginHostAdapter::getCurrentProgram() const -{ - if (!m_handle) return ""; - - int pn = m_descriptor->getCurrentProgram(m_handle); - return m_descriptor->programs[pn]; -} - -void -PluginHostAdapter::selectProgram(std::string program) -{ - if (!m_handle) return; - - for (unsigned int i = 0; i < m_descriptor->programCount; ++i) { - if (program == m_descriptor->programs[i]) { - m_descriptor->selectProgram(m_handle, i); - return; - } - } -} - -size_t -PluginHostAdapter::getPreferredStepSize() const -{ - if (!m_handle) return 0; - return m_descriptor->getPreferredStepSize(m_handle); -} - -size_t -PluginHostAdapter::getPreferredBlockSize() const -{ - if (!m_handle) return 0; - return m_descriptor->getPreferredBlockSize(m_handle); -} - -size_t -PluginHostAdapter::getMinChannelCount() const -{ - if (!m_handle) return 0; - return m_descriptor->getMinChannelCount(m_handle); -} - -size_t -PluginHostAdapter::getMaxChannelCount() const -{ - if (!m_handle) return 0; - return m_descriptor->getMaxChannelCount(m_handle); -} - -PluginHostAdapter::OutputList -PluginHostAdapter::getOutputDescriptors() const -{ - OutputList list; - if (!m_handle) { -// std::cerr << "PluginHostAdapter::getOutputDescriptors: no handle " << std::endl; - return list; - } - - unsigned int count = m_descriptor->getOutputCount(m_handle); - - for (unsigned int i = 0; i < count; ++i) { - VampOutputDescriptor *sd = m_descriptor->getOutputDescriptor(m_handle, i); - OutputDescriptor d; - d.identifier = sd->identifier; - d.name = sd->name; - d.description = sd->description; - d.unit = sd->unit; - d.hasFixedBinCount = sd->hasFixedBinCount; - d.binCount = sd->binCount; - if (d.hasFixedBinCount) { - for (unsigned int j = 0; j < sd->binCount; ++j) { - d.binNames.push_back(sd->binNames[j] ? sd->binNames[j] : ""); - } - } - d.hasKnownExtents = sd->hasKnownExtents; - d.minValue = sd->minValue; - d.maxValue = sd->maxValue; - d.isQuantized = sd->isQuantized; - d.quantizeStep = sd->quantizeStep; - - switch (sd->sampleType) { - case vampOneSamplePerStep: - d.sampleType = OutputDescriptor::OneSamplePerStep; break; - case vampFixedSampleRate: - d.sampleType = OutputDescriptor::FixedSampleRate; break; - case vampVariableSampleRate: - d.sampleType = OutputDescriptor::VariableSampleRate; break; - } - - d.sampleRate = sd->sampleRate; - - if (m_descriptor->vampApiVersion >= 2) { - d.hasDuration = sd->hasDuration; - } else { - d.hasDuration = false; - } - - list.push_back(d); - - m_descriptor->releaseOutputDescriptor(sd); - } - - return list; -} - -PluginHostAdapter::FeatureSet -PluginHostAdapter::process(const float *const *inputBuffers, - RealTime timestamp) -{ - FeatureSet fs; - if (!m_handle) return fs; - - int sec = timestamp.sec; - int nsec = timestamp.nsec; - - VampFeatureList *features = m_descriptor->process(m_handle, - inputBuffers, - sec, nsec); - - convertFeatures(features, fs); - m_descriptor->releaseFeatureSet(features); - return fs; -} - -PluginHostAdapter::FeatureSet -PluginHostAdapter::getRemainingFeatures() -{ - FeatureSet fs; - if (!m_handle) return fs; - - VampFeatureList *features = m_descriptor->getRemainingFeatures(m_handle); - - convertFeatures(features, fs); - m_descriptor->releaseFeatureSet(features); - return fs; -} - -void -PluginHostAdapter::convertFeatures(VampFeatureList *features, - FeatureSet &fs) -{ - if (!features) return; - - unsigned int outputs = m_descriptor->getOutputCount(m_handle); - - for (unsigned int i = 0; i < outputs; ++i) { - - VampFeatureList &list = features[i]; - - if (list.featureCount > 0) { - - Feature feature; - feature.values.reserve(list.features[0].v1.valueCount); - - for (unsigned int j = 0; j < list.featureCount; ++j) { - - feature.hasTimestamp = list.features[j].v1.hasTimestamp; - feature.timestamp = RealTime(list.features[j].v1.sec, - list.features[j].v1.nsec); - feature.hasDuration = false; - - if (m_descriptor->vampApiVersion >= 2) { - unsigned int j2 = j + list.featureCount; - feature.hasDuration = list.features[j2].v2.hasDuration; - feature.duration = RealTime(list.features[j2].v2.durationSec, - list.features[j2].v2.durationNsec); - } - - for (unsigned int k = 0; k < list.features[j].v1.valueCount; ++k) { - feature.values.push_back(list.features[j].v1.values[k]); - } - - if (list.features[j].v1.label) { - feature.label = list.features[j].v1.label; - } - - fs[i].push_back(feature); - - if (list.features[j].v1.valueCount > 0) { - feature.values.clear(); - } - - if (list.features[j].v1.label) { - feature.label = ""; - } - } - } - } -} - -} diff -r f8b38a017d9a -r 14029eb08472 vamp-sdk/RealTime.cpp --- a/vamp-sdk/RealTime.cpp Thu Nov 06 13:51:38 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Vamp - - An API for audio analysis and feature extraction plugins. - - Centre for Digital Music, Queen Mary, University of London. - Copyright 2006 Chris Cannam. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, copy, - modify, merge, publish, distribute, sublicense, and/or sell copies - of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR - ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the names of the Centre for - Digital Music; Queen Mary, University of London; and Chris Cannam - shall not be used in advertising or otherwise to promote the sale, - use or other dealings in this Software without prior written - authorization. -*/ - -/* - This is a modified version of a source file from the - Rosegarden MIDI and audio sequencer and notation editor. - This file copyright 2000-2006 Chris Cannam. - Relicensed by the author as detailed above. -*/ - -#include - -#if (__GNUC__ < 3) -#include -#define stringstream strstream -#else -#include -#endif - -using std::cerr; -using std::endl; - -#include "RealTime.h" - -#ifndef _WIN32 -#include -#endif - -namespace Vamp { - -// A RealTime consists of two ints that must be at least 32 bits each. -// A signed 32-bit int can store values exceeding +/- 2 billion. This -// means we can safely use our lower int for nanoseconds, as there are -// 1 billion nanoseconds in a second and we need to handle double that -// because of the implementations of addition etc that we use. -// -// The maximum valid RealTime on a 32-bit system is somewhere around -// 68 years: 999999999 nanoseconds longer than the classic Unix epoch. - -#define ONE_BILLION 1000000000 - -RealTime::RealTime(int s, int n) : - sec(s), nsec(n) -{ - if (sec == 0) { - while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } - while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } - } else if (sec < 0) { - while (nsec <= -ONE_BILLION) { nsec += ONE_BILLION; --sec; } - while (nsec > 0) { nsec -= ONE_BILLION; ++sec; } - } else { - while (nsec >= ONE_BILLION) { nsec -= ONE_BILLION; ++sec; } - while (nsec < 0) { nsec += ONE_BILLION; --sec; } - } -} - -RealTime -RealTime::fromSeconds(double sec) -{ - return RealTime(int(sec), int((sec - int(sec)) * ONE_BILLION + 0.5)); -} - -RealTime -RealTime::fromMilliseconds(int msec) -{ - return RealTime(msec / 1000, (msec % 1000) * 1000000); -} - -#ifndef _WIN32 -RealTime -RealTime::fromTimeval(const struct timeval &tv) -{ - return RealTime(tv.tv_sec, tv.tv_usec * 1000); -} -#endif - -std::ostream &operator<<(std::ostream &out, const RealTime &rt) -{ - if (rt < RealTime::zeroTime) { - out << "-"; - } else { - out << " "; - } - - int s = (rt.sec < 0 ? -rt.sec : rt.sec); - int n = (rt.nsec < 0 ? -rt.nsec : rt.nsec); - - out << s << "."; - - int nn(n); - if (nn == 0) out << "00000000"; - else while (nn < (ONE_BILLION / 10)) { - out << "0"; - nn *= 10; - } - - out << n << "R"; - return out; -} - -std::string -RealTime::toString() const -{ - std::stringstream out; - out << *this; - -#if (__GNUC__ < 3) - out << std::ends; -#endif - - std::string s = out.str(); - - // remove trailing R - return s.substr(0, s.length() - 1); -} - -std::string -RealTime::toText(bool fixedDp) const -{ - if (*this < RealTime::zeroTime) return "-" + (-*this).toText(); - - std::stringstream out; - - if (sec >= 3600) { - out << (sec / 3600) << ":"; - } - - if (sec >= 60) { - out << (sec % 3600) / 60 << ":"; - } - - if (sec >= 10) { - out << ((sec % 60) / 10); - } - - out << (sec % 10); - - int ms = msec(); - - if (ms != 0) { - out << "."; - out << (ms / 100); - ms = ms % 100; - if (ms != 0) { - out << (ms / 10); - ms = ms % 10; - } else if (fixedDp) { - out << "0"; - } - if (ms != 0) { - out << ms; - } else if (fixedDp) { - out << "0"; - } - } else if (fixedDp) { - out << ".000"; - } - -#if (__GNUC__ < 3) - out << std::ends; -#endif - - std::string s = out.str(); - - return s; -} - - -RealTime -RealTime::operator/(int d) const -{ - int secdiv = sec / d; - int secrem = sec % d; - - double nsecdiv = (double(nsec) + ONE_BILLION * double(secrem)) / d; - - return RealTime(secdiv, int(nsecdiv + 0.5)); -} - -double -RealTime::operator/(const RealTime &r) const -{ - double lTotal = double(sec) * ONE_BILLION + double(nsec); - double rTotal = double(r.sec) * ONE_BILLION + double(r.nsec); - - if (rTotal == 0) return 0.0; - else return lTotal/rTotal; -} - -long -RealTime::realTime2Frame(const RealTime &time, unsigned int sampleRate) -{ - if (time < zeroTime) return -realTime2Frame(-time, sampleRate); - double s = time.sec + double(time.nsec + 1) / 1000000000.0; - return long(s * sampleRate); -} - -RealTime -RealTime::frame2RealTime(long frame, unsigned int sampleRate) -{ - if (frame < 0) return -frame2RealTime(-frame, sampleRate); - - RealTime rt; - rt.sec = frame / long(sampleRate); - frame -= rt.sec * long(sampleRate); - rt.nsec = (int)(((double(frame) * 1000000.0) / sampleRate) * 1000.0); - return rt; -} - -const RealTime RealTime::zeroTime(0,0); - -}