comparison onsetsdsplugin.cpp @ 0:635e8745ccc9

* First commit of plugin using Dan Stowell's OnsetsDS library code
author cannam
date Thu, 19 Jun 2008 12:30:15 +0000
parents
children 3d1928670329
comparison
equal deleted inserted replaced
-1:000000000000 0:635e8745ccc9
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3 Vamp feature extraction plugin using the OnsetsDS onset detector.
4 This file copyright (c) 2008 Chris Cannam.
5
6 OnsetsDS - real time musical onset detection library.
7 Copyright (c) 2007 Dan Stowell. All rights reserved.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "onsetsdsplugin.h"
25 #include <vamp-sdk/PluginAdapter.h>
26
27 using std::string;
28 using std::vector;
29 using std::cerr;
30 using std::endl;
31
32
33 OnsetsDSPlugin::OnsetsDSPlugin(float inputSampleRate) :
34 Vamp::Plugin(inputSampleRate),
35 m_ods(0),
36 m_odsdata(0),
37 m_dfType(ODS_ODF_RCOMPLEX),
38 m_medspan(11),
39 m_stepSize(512),
40 m_fftSize(1024)
41 {
42 }
43
44 OnsetsDSPlugin::~OnsetsDSPlugin()
45 {
46 delete[] m_odsdata;
47 delete m_ods;
48 }
49
50 string
51 OnsetsDSPlugin::getIdentifier() const
52 {
53 return "onsetsds";
54 }
55
56 string
57 OnsetsDSPlugin::getName() const
58 {
59 return "OnsetsDS Onset Detector";
60 }
61
62 string
63 OnsetsDSPlugin::getDescription() const
64 {
65 return "Detect note onsets";
66 }
67
68 string
69 OnsetsDSPlugin::getMaker() const
70 {
71 return "Dan Stowell";
72 }
73
74 int
75 OnsetsDSPlugin::getPluginVersion() const
76 {
77 return 1;
78 }
79
80 string
81 OnsetsDSPlugin::getCopyright() const
82 {
83 return "Copyright (c) 2007-2008 Dan Stowell";
84 }
85
86 OnsetsDSPlugin::ParameterList
87 OnsetsDSPlugin::getParameterDescriptors() const
88 {
89 ParameterList list;
90
91 ParameterDescriptor desc;
92 desc.identifier = "dftype";
93 desc.name = "Onset detection function";
94 desc.description = "Method used to calculate the onset detection function";
95 desc.minValue = 0;
96 desc.maxValue = 6;
97 desc.defaultValue = 3;
98 desc.isQuantized = true;
99 desc.quantizeStep = 1;
100 desc.valueNames.push_back("Power");
101 desc.valueNames.push_back("Sum of magnitudes");
102 desc.valueNames.push_back("Complex-domain deviation");
103 desc.valueNames.push_back("Rectified complex-domain deviation");
104 desc.valueNames.push_back("Phase deviation");
105 desc.valueNames.push_back("Weighted phase deviation");
106 desc.valueNames.push_back("Modified Kullback-Liebler deviation");
107 list.push_back(desc);
108
109 desc.identifier = "medspan";
110 desc.name = "Median frame span";
111 desc.description = "Number of past frames used in median calculation";
112 desc.minValue = 5;
113 desc.maxValue = 21;
114 desc.defaultValue = 11;
115 desc.isQuantized = true;
116 desc.quantizeStep = 2;
117 desc.valueNames.clear();
118 list.push_back(desc);
119
120 return list;
121 }
122
123 float
124 OnsetsDSPlugin::getParameter(std::string name) const
125 {
126 if (name == "dftype") {
127 switch (m_dfType) {
128 case ODS_ODF_POWER: return 0;
129 case ODS_ODF_MAGSUM: return 1;
130 case ODS_ODF_COMPLEX: return 2;
131 case ODS_ODF_RCOMPLEX: return 3;
132 case ODS_ODF_PHASE: return 4;
133 case ODS_ODF_WPHASE: return 5;
134 case ODS_ODF_MKL: return 6;
135 }
136 } else if (name == "medspan") {
137 return m_medspan;
138 }
139 return 0.0;
140 }
141
142 void
143 OnsetsDSPlugin::setParameter(std::string name, float value)
144 {
145 if (name == "dftype") {
146 onsetsds_odf_types dfType = m_dfType;
147 switch (lrintf(value)) {
148 case 0: dfType = ODS_ODF_POWER; break;
149 case 1: dfType = ODS_ODF_MAGSUM; break;
150 case 2: dfType = ODS_ODF_COMPLEX; break;
151 case 3: dfType = ODS_ODF_RCOMPLEX; break;
152 case 4: dfType = ODS_ODF_PHASE; break;
153 case 5: dfType = ODS_ODF_WPHASE; break;
154 case 6: dfType = ODS_ODF_MKL; break;
155 }
156 if (dfType == m_dfType) return;
157 m_dfType = dfType;
158 } else if (name == "medspan") {
159 m_medspan = lrintf(value);
160 }
161 }
162
163 bool
164 OnsetsDSPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
165 {
166 if (channels < getMinChannelCount() ||
167 channels > getMaxChannelCount()) {
168 std::cerr << "OnsetsDSPlugin::initialise: Unsupported channel count: "
169 << channels << std::endl;
170 return false;
171 }
172
173 if (stepSize != getPreferredStepSize()) {
174 std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual step size: "
175 << stepSize << " (wanted " << (getPreferredStepSize()) << ")" << std::endl;
176 }
177
178 if (blockSize != getPreferredBlockSize()) {
179 std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual block size: "
180 << blockSize << " (wanted " << (getPreferredBlockSize()) << ")" << std::endl;
181 }
182
183 m_stepSize = stepSize;
184 m_fftSize = blockSize;
185
186 delete[] m_odsdata;
187 delete m_ods;
188
189 m_odsdata = new float[onsetsds_memneeded(m_dfType, m_fftSize, m_medspan)];
190 m_ods = new OnsetsDS;
191 memset(m_ods, 0, sizeof(OnsetsDS));
192 onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
193 m_medspan, m_inputSampleRate);
194
195 return true;
196 }
197
198 void
199 OnsetsDSPlugin::reset()
200 {
201 if (!m_ods) {
202 std::cerr << "ERROR: OnsetsDSPlugin::reset: Plugin has not been initialised" << std::endl;
203 return;
204 }
205 onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
206 m_medspan, m_inputSampleRate);
207 }
208
209 size_t
210 OnsetsDSPlugin::getPreferredStepSize() const
211 {
212 return 512;
213 }
214
215 size_t
216 OnsetsDSPlugin::getPreferredBlockSize() const
217 {
218 return 1024;
219 }
220
221 OnsetsDSPlugin::OutputList
222 OnsetsDSPlugin::getOutputDescriptors() const
223 {
224 OutputList list;
225
226 OutputDescriptor onsets;
227 onsets.identifier = "onsets";
228 onsets.name = "Note Onsets";
229 onsets.description = "Note onset positions";
230 onsets.unit = "";
231 onsets.hasFixedBinCount = true;
232 onsets.binCount = 0;
233 onsets.sampleType = OutputDescriptor::VariableSampleRate;
234 onsets.sampleRate = (m_inputSampleRate / m_stepSize);
235
236 list.push_back(onsets);
237
238 return list;
239 }
240
241 OnsetsDSPlugin::FeatureSet
242 OnsetsDSPlugin::process(const float *const *inputBuffers,
243 Vamp::RealTime timestamp)
244 {
245 if (!m_ods) {
246 cerr << "ERROR: OnsetsDSPlugin::process: Plugin has not been initialised"
247 << endl;
248 return FeatureSet();
249 }
250
251 // We can const_cast because we happen to know onsetsds_process
252 // does not modify this buffer
253 bool result = onsetsds_process(m_ods, const_cast<float *>(inputBuffers[0]));
254
255 FeatureSet returnFeatures;
256
257 if (result) {
258 Feature feature;
259 feature.hasTimestamp = true;
260 feature.timestamp = timestamp;
261 returnFeatures[0].push_back(feature); // onsets are output 0
262 }
263
264 return returnFeatures;
265 }
266
267 OnsetsDSPlugin::FeatureSet
268 OnsetsDSPlugin::getRemainingFeatures()
269 {
270 return FeatureSet();
271 }
272
273
274 static Vamp::PluginAdapter<OnsetsDSPlugin> adapter;
275
276 const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
277 unsigned int index)
278 {
279 if (version < 1) return 0;
280
281 switch (index) {
282 case 0: return adapter.getDescriptor();
283 default: return 0;
284 }
285 }
286