PercussionOnsetDetector.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "PercussionOnsetDetector.h"
00038
00039 using std::string;
00040 using std::vector;
00041 using std::cerr;
00042 using std::endl;
00043
00044 #include <cmath>
00045
00046
00047 PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
00048 Plugin(inputSampleRate),
00049 m_stepSize(0),
00050 m_blockSize(0),
00051 m_threshold(3),
00052 m_sensitivity(40),
00053 m_priorMagnitudes(0),
00054 m_dfMinus1(0),
00055 m_dfMinus2(0)
00056 {
00057 }
00058
00059 PercussionOnsetDetector::~PercussionOnsetDetector()
00060 {
00061 delete[] m_priorMagnitudes;
00062 }
00063
00064 string
00065 PercussionOnsetDetector::getIdentifier() const
00066 {
00067 return "percussiononsets";
00068 }
00069
00070 string
00071 PercussionOnsetDetector::getName() const
00072 {
00073 return "Simple Percussion Onset Detector";
00074 }
00075
00076 string
00077 PercussionOnsetDetector::getDescription() const
00078 {
00079 return "Detect percussive note onsets by identifying broadband energy rises";
00080 }
00081
00082 string
00083 PercussionOnsetDetector::getMaker() const
00084 {
00085 return "Vamp SDK Example Plugins";
00086 }
00087
00088 int
00089 PercussionOnsetDetector::getPluginVersion() const
00090 {
00091 return 2;
00092 }
00093
00094 string
00095 PercussionOnsetDetector::getCopyright() const
00096 {
00097 return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005. Freely redistributable (BSD license)";
00098 }
00099
00100 size_t
00101 PercussionOnsetDetector::getPreferredStepSize() const
00102 {
00103 return 0;
00104 }
00105
00106 size_t
00107 PercussionOnsetDetector::getPreferredBlockSize() const
00108 {
00109 return 1024;
00110 }
00111
00112 bool
00113 PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
00114 {
00115 if (channels < getMinChannelCount() ||
00116 channels > getMaxChannelCount()) return false;
00117
00118 m_stepSize = stepSize;
00119 m_blockSize = blockSize;
00120
00121 m_priorMagnitudes = new float[m_blockSize/2];
00122
00123 for (size_t i = 0; i < m_blockSize/2; ++i) {
00124 m_priorMagnitudes[i] = 0.f;
00125 }
00126
00127 m_dfMinus1 = 0.f;
00128 m_dfMinus2 = 0.f;
00129
00130 return true;
00131 }
00132
00133 void
00134 PercussionOnsetDetector::reset()
00135 {
00136 for (size_t i = 0; i < m_blockSize/2; ++i) {
00137 m_priorMagnitudes[i] = 0.f;
00138 }
00139
00140 m_dfMinus1 = 0.f;
00141 m_dfMinus2 = 0.f;
00142 }
00143
00144 PercussionOnsetDetector::ParameterList
00145 PercussionOnsetDetector::getParameterDescriptors() const
00146 {
00147 ParameterList list;
00148
00149 ParameterDescriptor d;
00150 d.identifier = "threshold";
00151 d.name = "Energy rise threshold";
00152 d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
00153 d.unit = "dB";
00154 d.minValue = 0;
00155 d.maxValue = 20;
00156 d.defaultValue = 3;
00157 d.isQuantized = false;
00158 list.push_back(d);
00159
00160 d.identifier = "sensitivity";
00161 d.name = "Sensitivity";
00162 d.description = "Sensitivity of peak detector applied to broadband detection function";
00163 d.unit = "%";
00164 d.minValue = 0;
00165 d.maxValue = 100;
00166 d.defaultValue = 40;
00167 d.isQuantized = false;
00168 list.push_back(d);
00169
00170 return list;
00171 }
00172
00173 float
00174 PercussionOnsetDetector::getParameter(std::string id) const
00175 {
00176 if (id == "threshold") return m_threshold;
00177 if (id == "sensitivity") return m_sensitivity;
00178 return 0.f;
00179 }
00180
00181 void
00182 PercussionOnsetDetector::setParameter(std::string id, float value)
00183 {
00184 if (id == "threshold") {
00185 if (value < 0) value = 0;
00186 if (value > 20) value = 20;
00187 m_threshold = value;
00188 } else if (id == "sensitivity") {
00189 if (value < 0) value = 0;
00190 if (value > 100) value = 100;
00191 m_sensitivity = value;
00192 }
00193 }
00194
00195 PercussionOnsetDetector::OutputList
00196 PercussionOnsetDetector::getOutputDescriptors() const
00197 {
00198 OutputList list;
00199
00200 OutputDescriptor d;
00201 d.identifier = "onsets";
00202 d.name = "Onsets";
00203 d.description = "Percussive note onset locations";
00204 d.unit = "";
00205 d.hasFixedBinCount = true;
00206 d.binCount = 0;
00207 d.hasKnownExtents = false;
00208 d.isQuantized = false;
00209 d.sampleType = OutputDescriptor::VariableSampleRate;
00210 d.sampleRate = m_inputSampleRate;
00211 list.push_back(d);
00212
00213 d.identifier = "detectionfunction";
00214 d.name = "Detection Function";
00215 d.description = "Broadband energy rise detection function";
00216 d.binCount = 1;
00217 d.isQuantized = true;
00218 d.quantizeStep = 1.0;
00219 d.sampleType = OutputDescriptor::OneSamplePerStep;
00220 list.push_back(d);
00221
00222 return list;
00223 }
00224
00225 PercussionOnsetDetector::FeatureSet
00226 PercussionOnsetDetector::process(const float *const *inputBuffers,
00227 Vamp::RealTime ts)
00228 {
00229 if (m_stepSize == 0) {
00230 cerr << "ERROR: PercussionOnsetDetector::process: "
00231 << "PercussionOnsetDetector has not been initialised"
00232 << endl;
00233 return FeatureSet();
00234 }
00235
00236 int count = 0;
00237
00238 for (size_t i = 1; i < m_blockSize/2; ++i) {
00239
00240 float real = inputBuffers[0][i*2];
00241 float imag = inputBuffers[0][i*2 + 1];
00242
00243 float sqrmag = real * real + imag * imag;
00244
00245 if (m_priorMagnitudes[i] > 0.f) {
00246 float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
00247
00248
00249
00250 if (diff >= m_threshold) ++count;
00251 }
00252
00253 m_priorMagnitudes[i] = sqrmag;
00254 }
00255
00256 FeatureSet returnFeatures;
00257
00258 Feature detectionFunction;
00259 detectionFunction.hasTimestamp = false;
00260 detectionFunction.values.push_back(count);
00261 returnFeatures[1].push_back(detectionFunction);
00262
00263 if (m_dfMinus2 < m_dfMinus1 &&
00264 m_dfMinus1 >= count &&
00265 m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
00266
00267
00268
00269 Feature onset;
00270 onset.hasTimestamp = true;
00271 onset.timestamp = ts - Vamp::RealTime::frame2RealTime
00272 (m_stepSize, int(m_inputSampleRate + 0.5));
00273 returnFeatures[0].push_back(onset);
00274 }
00275
00276 m_dfMinus2 = m_dfMinus1;
00277 m_dfMinus1 = count;
00278
00279 return returnFeatures;
00280 }
00281
00282 PercussionOnsetDetector::FeatureSet
00283 PercussionOnsetDetector::getRemainingFeatures()
00284 {
00285 return FeatureSet();
00286 }
00287