VampPluginSDK
2.1
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Vamp 00005 00006 An API for audio analysis and feature extraction plugins. 00007 00008 Centre for Digital Music, Queen Mary, University of London. 00009 Copyright 2006 Chris Cannam. 00010 00011 Permission is hereby granted, free of charge, to any person 00012 obtaining a copy of this software and associated documentation 00013 files (the "Software"), to deal in the Software without 00014 restriction, including without limitation the rights to use, copy, 00015 modify, merge, publish, distribute, sublicense, and/or sell copies 00016 of the Software, and to permit persons to whom the Software is 00017 furnished to do so, subject to the following conditions: 00018 00019 The above copyright notice and this permission notice shall be 00020 included in all copies or substantial portions of the Software. 00021 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00023 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00024 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00025 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 00026 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 00027 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00028 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00029 00030 Except as contained in this notice, the names of the Centre for 00031 Digital Music; Queen Mary, University of London; and Chris Cannam 00032 shall not be used in advertising or otherwise to promote the sale, 00033 use or other dealings in this Software without prior written 00034 authorization. 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 // std::cout << "i=" << i << ", sqrmag=" << sqrmag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << " " << (diff >= m_threshold ? "[*]" : "") << std::endl; 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 //std::cout << "result at " << ts << "! (count == " << count << ", prev == " << m_dfMinus1 << ")" << std::endl; 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