~ubuntu-branches/ubuntu/gutsy/audacity/gutsy-backports

« back to all changes in this revision

Viewing changes to lib-src/libvamp/examples/PercussionOnsetDetector.cpp

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-18 21:58:19 UTC
  • mfrom: (13.1.2 hardy)
  • Revision ID: james.westby@ubuntu.com-20080218215819-tmbcf1rx238r8gdv
Tags: 1.3.4-1.1ubuntu1~gutsy1
Automated backport upload; no source changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        float sqrmag = real * real + imag * imag;
 
243
 
 
244
        if (m_priorMagnitudes[i] > 0.f) {
 
245
            float diff = 10.f * log10f(sqrmag / m_priorMagnitudes[i]);
 
246
 
 
247
//        std::cout << "i=" << i << ", mag=" << mag << ", prior=" << m_priorMagnitudes[i] << ", diff=" << diff << ", threshold=" << m_threshold << std::endl;
 
248
 
 
249
            if (diff >= m_threshold) ++count;
 
250
        }
 
251
 
 
252
        m_priorMagnitudes[i] = sqrmag;
 
253
    }
 
254
 
 
255
    FeatureSet returnFeatures;
 
256
 
 
257
    Feature detectionFunction;
 
258
    detectionFunction.hasTimestamp = false;
 
259
    detectionFunction.values.push_back(count);
 
260
    returnFeatures[1].push_back(detectionFunction);
 
261
 
 
262
    if (m_dfMinus2 < m_dfMinus1 &&
 
263
        m_dfMinus1 >= count &&
 
264
        m_dfMinus1 > ((100 - m_sensitivity) * m_blockSize) / 200) {
 
265
 
 
266
        Feature onset;
 
267
        onset.hasTimestamp = true;
 
268
        onset.timestamp = ts - Vamp::RealTime::frame2RealTime
 
269
            (m_stepSize, lrintf(m_inputSampleRate));
 
270
        returnFeatures[0].push_back(onset);
 
271
    }
 
272
 
 
273
    m_dfMinus2 = m_dfMinus1;
 
274
    m_dfMinus1 = count;
 
275
 
 
276
    return returnFeatures;
 
277
}
 
278
 
 
279
PercussionOnsetDetector::FeatureSet
 
280
PercussionOnsetDetector::getRemainingFeatures()
 
281
{
 
282
    return FeatureSet();
 
283
}
 
284