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: | Tag: | Revision:

root / examples / PercussionOnsetDetector.cpp

History | View | Annotate | Download (7.36 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2

    
3
/*
4
    Vamp
5

6
    An API for audio analysis and feature extraction plugins.
7

8
    Centre for Digital Music, Queen Mary, University of London.
9
    Copyright 2006 Chris Cannam.
10
  
11
    Permission is hereby granted, free of charge, to any person
12
    obtaining a copy of this software and associated documentation
13
    files (the "Software"), to deal in the Software without
14
    restriction, including without limitation the rights to use, copy,
15
    modify, merge, publish, distribute, sublicense, and/or sell copies
16
    of the Software, and to permit persons to whom the Software is
17
    furnished to do so, subject to the following conditions:
18

19
    The above copyright notice and this permission notice shall be
20
    included in all copies or substantial portions of the Software.
21

22
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
26
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
27
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29

30
    Except as contained in this notice, the names of the Centre for
31
    Digital Music; Queen Mary, University of London; and Chris Cannam
32
    shall not be used in advertising or otherwise to promote the sale,
33
    use or other dealings in this Software without prior written
34
    authorization.
35
*/
36

    
37
#include "PercussionOnsetDetector.h"
38

    
39
using std::string;
40
using std::vector;
41
using std::cerr;
42
using std::endl;
43

    
44
#include <cmath>
45

    
46

    
47
PercussionOnsetDetector::PercussionOnsetDetector(float inputSampleRate) :
48
    Plugin(inputSampleRate),
49
    m_stepSize(0),
50
    m_blockSize(0),
51
    m_threshold(3),
52
    m_sensitivity(40),
53
    m_priorMagnitudes(0),
54
    m_dfMinus1(0),
55
    m_dfMinus2(0)
56
{
57
}
58

    
59
PercussionOnsetDetector::~PercussionOnsetDetector()
60
{
61
    delete[] m_priorMagnitudes;
62
}
63

    
64
string
65
PercussionOnsetDetector::getIdentifier() const
66
{
67
    return "percussiononsets";
68
}
69

    
70
string
71
PercussionOnsetDetector::getName() const
72
{
73
    return "Simple Percussion Onset Detector";
74
}
75

    
76
string
77
PercussionOnsetDetector::getDescription() const
78
{
79
    return "Detect percussive note onsets by identifying broadband energy rises";
80
}
81

    
82
string
83
PercussionOnsetDetector::getMaker() const
84
{
85
    return "Vamp SDK Example Plugins";
86
}
87

    
88
int
89
PercussionOnsetDetector::getPluginVersion() const
90
{
91
    return 2;
92
}
93

    
94
string
95
PercussionOnsetDetector::getCopyright() const
96
{
97
    return "Code copyright 2006 Queen Mary, University of London, after Dan Barry et al 2005.  Freely redistributable (BSD license)";
98
}
99

    
100
size_t
101
PercussionOnsetDetector::getPreferredStepSize() const
102
{
103
    return 0;
104
}
105

    
106
size_t
107
PercussionOnsetDetector::getPreferredBlockSize() const
108
{
109
    return 1024;
110
}
111

    
112
bool
113
PercussionOnsetDetector::initialise(size_t channels, size_t stepSize, size_t blockSize)
114
{
115
    if (channels < getMinChannelCount() ||
116
        channels > getMaxChannelCount()) return false;
117

    
118
    m_stepSize = stepSize;
119
    m_blockSize = blockSize;
120

    
121
    m_priorMagnitudes = new float[m_blockSize/2];
122

    
123
    for (size_t i = 0; i < m_blockSize/2; ++i) {
124
        m_priorMagnitudes[i] = 0.f;
125
    }
126

    
127
    m_dfMinus1 = 0.f;
128
    m_dfMinus2 = 0.f;
129

    
130
    return true;
131
}
132

    
133
void
134
PercussionOnsetDetector::reset()
135
{
136
    for (size_t i = 0; i < m_blockSize/2; ++i) {
137
        m_priorMagnitudes[i] = 0.f;
138
    }
139

    
140
    m_dfMinus1 = 0.f;
141
    m_dfMinus2 = 0.f;
142
}
143

    
144
PercussionOnsetDetector::ParameterList
145
PercussionOnsetDetector::getParameterDescriptors() const
146
{
147
    ParameterList list;
148

    
149
    ParameterDescriptor d;
150
    d.identifier = "threshold";
151
    d.name = "Energy rise threshold";
152
    d.description = "Energy rise within a frequency bin necessary to count toward broadband total";
153
    d.unit = "dB";
154
    d.minValue = 0;
155
    d.maxValue = 20;
156
    d.defaultValue = 3;
157
    d.isQuantized = false;
158
    list.push_back(d);
159

    
160
    d.identifier = "sensitivity";
161
    d.name = "Sensitivity";
162
    d.description = "Sensitivity of peak detector applied to broadband detection function";
163
    d.unit = "%";
164
    d.minValue = 0;
165
    d.maxValue = 100;
166
    d.defaultValue = 40;
167
    d.isQuantized = false;
168
    list.push_back(d);
169

    
170
    return list;
171
}
172

    
173
float
174
PercussionOnsetDetector::getParameter(std::string id) const
175
{
176
    if (id == "threshold") return m_threshold;
177
    if (id == "sensitivity") return m_sensitivity;
178
    return 0.f;
179
}
180

    
181
void
182
PercussionOnsetDetector::setParameter(std::string id, float value)
183
{
184
    if (id == "threshold") {
185
        if (value < 0) value = 0;
186
        if (value > 20) value = 20;
187
        m_threshold = value;
188
    } else if (id == "sensitivity") {
189
        if (value < 0) value = 0;
190
        if (value > 100) value = 100;
191
        m_sensitivity = value;
192
    }
193
}
194

    
195
PercussionOnsetDetector::OutputList
196
PercussionOnsetDetector::getOutputDescriptors() const
197
{
198
    OutputList list;
199

    
200
    OutputDescriptor d;
201
    d.identifier = "onsets";
202
    d.name = "Onsets";
203
    d.description = "Percussive note onset locations";
204
    d.unit = "";
205
    d.hasFixedBinCount = true;
206
    d.binCount = 0;
207
    d.hasKnownExtents = false;
208
    d.isQuantized = false;
209
    d.sampleType = OutputDescriptor::VariableSampleRate;
210
    d.sampleRate = m_inputSampleRate;
211
    list.push_back(d);
212

    
213
    d.identifier = "detectionfunction";
214
    d.name = "Detection Function";
215
    d.description = "Broadband energy rise detection function";
216
    d.binCount = 1;
217
    d.isQuantized = true;
218
    d.quantizeStep = 1.0;
219
    d.sampleType = OutputDescriptor::OneSamplePerStep;
220
    list.push_back(d);
221

    
222
    return list;
223
}
224

    
225
PercussionOnsetDetector::FeatureSet
226
PercussionOnsetDetector::process(const float *const *inputBuffers,
227
                                 Vamp::RealTime ts)
228
{
229
    if (m_stepSize == 0) {
230
        cerr << "ERROR: PercussionOnsetDetector::process: "
231
             << "PercussionOnsetDetector has not been initialised"
232
             << endl;
233
        return FeatureSet();
234
    }
235

    
236
    int count = 0;
237

    
238
    for (size_t i = 1; i < m_blockSize/2; ++i) {
239

    
240
        float real = inputBuffers[0][i*2];
241
        float imag = inputBuffers[0][i*2 + 1];
242

    
243
        float sqrmag = real * real + imag * imag;
244

    
245
        if (m_priorMagnitudes[i] > 0.f) {
246
            float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
247

    
248
//        std::cout << "i=" << i << ", sqrmag=" << sqrmag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << " " << (diff >= m_threshold ? "[*]" : "") << std::endl;
249

    
250
            if (diff >= m_threshold) ++count;
251
        }
252

    
253
        m_priorMagnitudes[i] = sqrmag;
254
    }
255

    
256
    FeatureSet returnFeatures;
257

    
258
    Feature detectionFunction;
259
    detectionFunction.hasTimestamp = false;
260
    detectionFunction.values.push_back(count);
261
    returnFeatures[1].push_back(detectionFunction);
262

    
263
    if (m_dfMinus2 < m_dfMinus1 &&
264
        m_dfMinus1 >= count &&
265
        m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
266

    
267
//std::cout << "result at " << ts << "! (count == " << count << ", prev == " << m_dfMinus1 << ")" << std::endl;
268

    
269
        Feature onset;
270
        onset.hasTimestamp = true;
271
        onset.timestamp = ts - Vamp::RealTime::frame2RealTime
272
            (m_stepSize, int(m_inputSampleRate + 0.5));
273
        returnFeatures[0].push_back(onset);
274
    }
275

    
276
    m_dfMinus2 = m_dfMinus1;
277
    m_dfMinus1 = count;
278

    
279
    return returnFeatures;
280
}
281

    
282
PercussionOnsetDetector::FeatureSet
283
PercussionOnsetDetector::getRemainingFeatures()
284
{
285
    return FeatureSet();
286
}
287