Mercurial > hg > vamp-onsetsds-plugin
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 |