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 @ 9:deae47ee00e7

History | View | Annotate | Download (9.21 KB)

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_threshold(0.5),
39
    m_medspan(11),
40
    m_stepSize(256),
41
    m_fftSize(512)
42
{
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
    return 1;
79
}
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
    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
    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
    } else if (name == "threshold") {
148
        return m_threshold;
149
    } 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
    } else if (name == "threshold") {
172
        m_threshold = value;
173
    } 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
        m_ods->thresh = m_threshold;
210
        
211
    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
}
224

    
225
size_t
226
OnsetsDSPlugin::getPreferredStepSize() const
227
{
228
    return 256;
229
}
230

    
231
size_t
232
OnsetsDSPlugin::getPreferredBlockSize() const
233
{
234
    return 512;
235
}
236

    
237
OnsetsDSPlugin::OutputList
238
OnsetsDSPlugin::getOutputDescriptors() const
239
{
240
    OutputList list;
241

    
242
    OutputDescriptor onsets;
243
    onsets.identifier = "onsets";
244
    onsets.name = "Note Onsets";
245
    onsets.description = "Note onset positions";
246
    onsets.unit = "";
247
    onsets.hasFixedBinCount = true;
248
    onsets.binCount = 0;
249
    onsets.sampleType = OutputDescriptor::VariableSampleRate;
250
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
251
    list.push_back(onsets);
252

    
253
    //--- Extracting the ODF
254
    onsets = OutputDescriptor();
255
    onsets.identifier = "odf";
256
    onsets.name = "Onset Detection Function";
257
    onsets.description = "Onset Detection Function used for detecting onsets";
258
    onsets.unit = "";
259
    onsets.hasFixedBinCount = false;
260
    onsets.binCount = 0;
261
    onsets.sampleType = OutputDescriptor::OneSamplePerStep;
262
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
263
    list.push_back(onsets);
264

    
265
    //--- Extracting the Filtered ODF
266
    onsets = OutputDescriptor();
267
    onsets.identifier = "filtered_odf";
268
    onsets.name = "Filtered Onset Detection Function";
269
    onsets.description = "Filtered Onset Detection Function used for detecting onsets";
270
    onsets.unit = "";
271
    onsets.hasFixedBinCount = false;
272
    onsets.binCount = 0;
273
    onsets.sampleType = OutputDescriptor::OneSamplePerStep;
274
    onsets.sampleRate = (m_inputSampleRate / m_stepSize);
275
    list.push_back(onsets);
276

    
277
    return list;
278
}
279

    
280
OnsetsDSPlugin::FeatureSet
281
OnsetsDSPlugin::process(const float *const *inputBuffers,
282
                       Vamp::RealTime timestamp)
283
{
284
    if (!m_ods) {
285
        cerr << "ERROR: OnsetsDSPlugin::process: Plugin has not been initialised"
286
             << endl;
287
        return FeatureSet();
288
    }
289

    
290
    // We can const_cast because we happen to know onsetsds_process
291
    // does not modify this buffer
292
    bool result = onsetsds_process(m_ods, const_cast<float *>(inputBuffers[0]));
293

    
294
    FeatureSet returnFeatures;
295

    
296
    if (result) {
297
        Feature feature;
298
        feature.hasTimestamp = true;
299
        feature.timestamp = timestamp;
300
        returnFeatures[0].push_back(feature); // onsets are output 0
301
    }
302

    
303
    //--- Extracting the ODF
304
    Feature odf_feature;
305
    odf_feature.hasTimestamp = false;
306
    odf_feature.values.push_back(m_ods->odfvals[0]);
307
    returnFeatures[1].push_back(odf_feature);
308

    
309
    //--- Extracting the Filtered ODF
310
    Feature filtered_odf_feature;
311
    filtered_odf_feature.hasTimestamp = false;
312
    filtered_odf_feature.values.push_back(m_ods->odfvalpost);
313
    returnFeatures[2].push_back(filtered_odf_feature);
314

    
315
    return returnFeatures;
316
}
317

    
318
OnsetsDSPlugin::FeatureSet
319
OnsetsDSPlugin::getRemainingFeatures()
320
{
321
    return FeatureSet();
322
}
323

    
324

    
325
static Vamp::PluginAdapter<OnsetsDSPlugin> adapter;
326

    
327
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
328
                                                    unsigned int index)
329
{
330
    if (version < 1) return 0;
331

    
332
    switch (index) {
333
    case  0: return adapter.getDescriptor();
334
    default: return 0;
335
    }
336
}
337