To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

root / onsetsdsplugin.cpp

History | View | Annotate | Download (9.25 KB)

1 0:635e8745ccc9 cannam
/* -*- 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 1:3d1928670329 cannam
    m_threshold(0.5),
39 0:635e8745ccc9 cannam
    m_medspan(11),
40 1:3d1928670329 cannam
    m_stepSize(256),
41
    m_fftSize(512)
42 0:635e8745ccc9 cannam
{
43
}
44
45
OnsetsDSPlugin::~OnsetsDSPlugin()
46
{
47
    delete[] m_odsdata;
48
    delete m_ods;
49
}
50
51
string
52
OnsetsDSPlugin::getIdentifier() const
53
{
54
    return "onsetsds";
55
}
56
57
string
58
OnsetsDSPlugin::getName() const
59
{
60
    return "OnsetsDS Onset Detector";
61
}
62
63
string
64
OnsetsDSPlugin::getDescription() const
65
{
66
    return "Detect note onsets";
67
}
68
69
string
70
OnsetsDSPlugin::getMaker() const
71
{
72
    return "Dan Stowell";
73
}
74
75
int
76
OnsetsDSPlugin::getPluginVersion() const
77
{
78 10:1aa45968fbad dan
    return 2;
79 0:635e8745ccc9 cannam
}
80
81
string
82
OnsetsDSPlugin::getCopyright() const
83
{
84
    return "Copyright (c) 2007-2008 Dan Stowell";
85
}
86
87
OnsetsDSPlugin::ParameterList
88
OnsetsDSPlugin::getParameterDescriptors() const
89
{
90
    ParameterList list;
91
92
    ParameterDescriptor desc;
93
    desc.identifier = "dftype";
94
    desc.name = "Onset detection function";
95
    desc.description = "Method used to calculate the onset detection function";
96
    desc.minValue = 0;
97
    desc.maxValue = 6;
98
    desc.defaultValue = 3;
99
    desc.isQuantized = true;
100
    desc.quantizeStep = 1;
101
    desc.valueNames.push_back("Power");
102
    desc.valueNames.push_back("Sum of magnitudes");
103
    desc.valueNames.push_back("Complex-domain deviation");
104
    desc.valueNames.push_back("Rectified complex-domain deviation");
105
    desc.valueNames.push_back("Phase deviation");
106
    desc.valueNames.push_back("Weighted phase deviation");
107
    desc.valueNames.push_back("Modified Kullback-Liebler deviation");
108
    list.push_back(desc);
109
110 1:3d1928670329 cannam
    desc.identifier = "threshold";
111
    desc.name = "Detection threshold";
112
    desc.description = "Onsets trigger when the function beats this value";
113
    desc.minValue = 0;
114
    desc.maxValue = 1;
115
    desc.defaultValue = 0.5;
116
    desc.isQuantized = false;
117
    desc.valueNames.clear();
118
    list.push_back(desc);
119
120 0:635e8745ccc9 cannam
    desc.identifier = "medspan";
121
    desc.name = "Median frame span";
122
    desc.description = "Number of past frames used in median calculation";
123
    desc.minValue = 5;
124
    desc.maxValue = 21;
125
    desc.defaultValue = 11;
126
    desc.isQuantized = true;
127
    desc.quantizeStep = 2;
128
    desc.valueNames.clear();
129
    list.push_back(desc);
130
131
    return list;
132
}
133
134
float
135
OnsetsDSPlugin::getParameter(std::string name) const
136
{
137
    if (name == "dftype") {
138
        switch (m_dfType) {
139
        case ODS_ODF_POWER:    return 0;
140
        case ODS_ODF_MAGSUM:   return 1;
141
        case ODS_ODF_COMPLEX:  return 2;
142
        case ODS_ODF_RCOMPLEX: return 3;
143
        case ODS_ODF_PHASE:    return 4;
144
        case ODS_ODF_WPHASE:   return 5;
145
        case ODS_ODF_MKL:      return 6;
146
        }
147 1:3d1928670329 cannam
    } else if (name == "threshold") {
148
        return m_threshold;
149 0:635e8745ccc9 cannam
    } else if (name == "medspan") {
150
        return m_medspan;
151
    }
152
    return 0.0;
153
}
154
155
void
156
OnsetsDSPlugin::setParameter(std::string name, float value)
157
{
158
    if (name == "dftype") {
159
        onsetsds_odf_types dfType = m_dfType;
160
        switch (lrintf(value)) {
161
        case 0: dfType = ODS_ODF_POWER; break;
162
        case 1: dfType = ODS_ODF_MAGSUM; break;
163
        case 2: dfType = ODS_ODF_COMPLEX; break;
164
        case 3: dfType = ODS_ODF_RCOMPLEX; break;
165
        case 4: dfType = ODS_ODF_PHASE; break;
166
        case 5: dfType = ODS_ODF_WPHASE; break;
167
        case 6: dfType = ODS_ODF_MKL; break;
168
        }
169
        if (dfType == m_dfType) return;
170
        m_dfType = dfType;
171 1:3d1928670329 cannam
    } else if (name == "threshold") {
172
        m_threshold = value;
173 0:635e8745ccc9 cannam
    } else if (name == "medspan") {
174
        m_medspan = lrintf(value);
175
    }
176
}
177
178
bool
179
OnsetsDSPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
180
{
181
    if (channels < getMinChannelCount() ||
182
        channels > getMaxChannelCount()) {
183
        std::cerr << "OnsetsDSPlugin::initialise: Unsupported channel count: "
184
                  << channels << std::endl;
185
        return false;
186
    }
187
188
    if (stepSize != getPreferredStepSize()) {
189
        std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual step size: "
190
                  << stepSize << " (wanted " << (getPreferredStepSize()) << ")" << std::endl;
191
    }
192
193
    if (blockSize != getPreferredBlockSize()) {
194
        std::cerr << "WARNING: OnsetsDSPlugin::initialise: Using unusual block size: "
195
                  << blockSize << " (wanted " << (getPreferredBlockSize()) << ")" << std::endl;
196
    }
197
198
    m_stepSize = stepSize;
199
    m_fftSize = blockSize;
200
201
    delete[] m_odsdata;
202
    delete m_ods;
203
204
    m_odsdata = new float[onsetsds_memneeded(m_dfType, m_fftSize, m_medspan)];
205
    m_ods = new OnsetsDS;
206
    memset(m_ods, 0, sizeof(OnsetsDS));
207
    onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
208
                  m_medspan, m_inputSampleRate);
209 11:1ee043ea9d06 Chris
    m_ods->thresh = m_threshold;
210 1:3d1928670329 cannam
211 0:635e8745ccc9 cannam
    return true;
212
}
213
214
void
215
OnsetsDSPlugin::reset()
216
{
217
    if (!m_ods) {
218
        std::cerr << "ERROR: OnsetsDSPlugin::reset: Plugin has not been initialised" << std::endl;
219
        return;
220
    }
221
    onsetsds_init(m_ods, m_odsdata, ODS_FFT_FFTW3_R2C, m_dfType, m_fftSize,
222
                  m_medspan, m_inputSampleRate);
223 11:1ee043ea9d06 Chris
    m_ods->thresh = m_threshold;
224 0:635e8745ccc9 cannam
}
225
226
size_t
227
OnsetsDSPlugin::getPreferredStepSize() const
228
{
229 1:3d1928670329 cannam
    return 256;
230 0:635e8745ccc9 cannam
}
231
232
size_t
233
OnsetsDSPlugin::getPreferredBlockSize() const
234
{
235 1:3d1928670329 cannam
    return 512;
236 0:635e8745ccc9 cannam
}
237
238
OnsetsDSPlugin::OutputList
239
OnsetsDSPlugin::getOutputDescriptors() const
240
{
241
    OutputList list;
242
243
    OutputDescriptor onsets;
244
    onsets.identifier = "onsets";
245
    onsets.name = "Note Onsets";
246
    onsets.description = "Note onset positions";
247
    onsets.unit = "";
248
    onsets.hasFixedBinCount = true;
249
    onsets.binCount = 0;
250
    onsets.sampleType = OutputDescriptor::VariableSampleRate;
251
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
252 9:deae47ee00e7 dan
    list.push_back(onsets);
253 0:635e8745ccc9 cannam
254 9:deae47ee00e7 dan
    //--- Extracting the ODF
255
    onsets = OutputDescriptor();
256
    onsets.identifier = "odf";
257
    onsets.name = "Onset Detection Function";
258
    onsets.description = "Onset Detection Function used for detecting onsets";
259
    onsets.unit = "";
260
    onsets.hasFixedBinCount = false;
261
    onsets.binCount = 0;
262
    onsets.sampleType = OutputDescriptor::OneSamplePerStep;
263
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
264
    list.push_back(onsets);
265
266
    //--- Extracting the Filtered ODF
267
    onsets = OutputDescriptor();
268
    onsets.identifier = "filtered_odf";
269
    onsets.name = "Filtered Onset Detection Function";
270
    onsets.description = "Filtered Onset Detection Function used for detecting onsets";
271
    onsets.unit = "";
272
    onsets.hasFixedBinCount = false;
273
    onsets.binCount = 0;
274
    onsets.sampleType = OutputDescriptor::OneSamplePerStep;
275
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
276 0:635e8745ccc9 cannam
    list.push_back(onsets);
277
278
    return list;
279
}
280
281
OnsetsDSPlugin::FeatureSet
282
OnsetsDSPlugin::process(const float *const *inputBuffers,
283
                       Vamp::RealTime timestamp)
284
{
285
    if (!m_ods) {
286
        cerr << "ERROR: OnsetsDSPlugin::process: Plugin has not been initialised"
287
             << endl;
288
        return FeatureSet();
289
    }
290
291
    // We can const_cast because we happen to know onsetsds_process
292
    // does not modify this buffer
293
    bool result = onsetsds_process(m_ods, const_cast<float *>(inputBuffers[0]));
294
295
    FeatureSet returnFeatures;
296
297
    if (result) {
298
        Feature feature;
299
        feature.hasTimestamp = true;
300
        feature.timestamp = timestamp;
301
        returnFeatures[0].push_back(feature); // onsets are output 0
302
    }
303
304 9:deae47ee00e7 dan
    //--- Extracting the ODF
305
    Feature odf_feature;
306
    odf_feature.hasTimestamp = false;
307
    odf_feature.values.push_back(m_ods->odfvals[0]);
308
    returnFeatures[1].push_back(odf_feature);
309
310
    //--- Extracting the Filtered ODF
311
    Feature filtered_odf_feature;
312
    filtered_odf_feature.hasTimestamp = false;
313
    filtered_odf_feature.values.push_back(m_ods->odfvalpost);
314
    returnFeatures[2].push_back(filtered_odf_feature);
315
316 0:635e8745ccc9 cannam
    return returnFeatures;
317
}
318
319
OnsetsDSPlugin::FeatureSet
320
OnsetsDSPlugin::getRemainingFeatures()
321
{
322
    return FeatureSet();
323
}
324
325
326
static Vamp::PluginAdapter<OnsetsDSPlugin> adapter;
327
328
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
329
                                                    unsigned int index)
330
{
331
    if (version < 1) return 0;
332
333
    switch (index) {
334
    case  0: return adapter.getDescriptor();
335
    default: return 0;
336
    }
337
}