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 / BeatRootVampPlugin.cpp @ 23:633ec097fa56

History | View | Annotate | Download (8.96 KB)

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

    
3
/*
4
    Vamp feature extraction plugin for the BeatRoot beat tracker.
5

6
    Centre for Digital Music, Queen Mary, University of London.
7
    This file copyright 2011 Simon Dixon, Chris Cannam and QMUL.
8
    
9
    This program is free software; you can redistribute it and/or
10
    modify it under the terms of the GNU General Public License as
11
    published by the Free Software Foundation; either version 2 of the
12
    License, or (at your option) any later version.  See the file
13
    COPYING included with this distribution for more information.
14
*/
15

    
16
#include "BeatRootVampPlugin.h"
17
#include "BeatRootProcessor.h"
18

    
19
#include "Event.h"
20

    
21
#include <vamp-sdk/RealTime.h>
22
#include <vamp-sdk/PluginAdapter.h>
23

    
24
BeatRootVampPlugin::BeatRootVampPlugin(float inputSampleRate) :
25
    Plugin(inputSampleRate)
26
{
27
    m_processor = new BeatRootProcessor(inputSampleRate, AgentParameters());
28
}
29

    
30
BeatRootVampPlugin::~BeatRootVampPlugin()
31
{
32
    delete m_processor;
33
}
34

    
35
string
36
BeatRootVampPlugin::getIdentifier() const
37
{
38
    return "beatroot";
39
}
40

    
41
string
42
BeatRootVampPlugin::getName() const
43
{
44
    return "BeatRoot Beat Tracker";
45
}
46

    
47
string
48
BeatRootVampPlugin::getDescription() const
49
{
50
    return "Identify beat locations in music";
51
}
52

    
53
string
54
BeatRootVampPlugin::getMaker() const
55
{
56
    return "Simon Dixon (plugin by Chris Cannam)";
57
}
58

    
59
int
60
BeatRootVampPlugin::getPluginVersion() const
61
{
62
    // Increment this each time you release a version that behaves
63
    // differently from the previous one
64
    return 1;
65
}
66

    
67
string
68
BeatRootVampPlugin::getCopyright() const
69
{
70
    return "GPL";
71
}
72

    
73
BeatRootVampPlugin::InputDomain
74
BeatRootVampPlugin::getInputDomain() const
75
{
76
    return FrequencyDomain;
77
}
78

    
79
size_t
80
BeatRootVampPlugin::getPreferredBlockSize() const
81
{
82
    return m_processor->getFFTSize();
83
}
84

    
85
size_t 
86
BeatRootVampPlugin::getPreferredStepSize() const
87
{
88
    return m_processor->getHopSize();
89
}
90

    
91
size_t
92
BeatRootVampPlugin::getMinChannelCount() const
93
{
94
    return 1;
95
}
96

    
97
size_t
98
BeatRootVampPlugin::getMaxChannelCount() const
99
{
100
    return 1;
101
}
102

    
103
BeatRootVampPlugin::ParameterList
104
BeatRootVampPlugin::getParameterDescriptors() const
105
{
106
    ParameterList list;
107

    
108
    ParameterDescriptor desc;
109

    
110
    double postMarginFactor;
111

    
112
    /** The maximum amount by which a beat can be earlier than the
113
     *  predicted beat time, expressed as a fraction of the beat
114
     *  period. */
115
    double preMarginFactor;
116

    
117
    /** The maximum allowed deviation from the initial tempo,
118
     * expressed as a fraction of the initial beat period. */
119
    double maxChange;
120

    
121
    /** The default value of expiryTime, which is the time (in
122
     *  seconds) after which an Agent that has no Event matching its
123
     *  beat predictions will be destroyed. */
124
    
125
    desc.identifier = "preMarginFactor";
126
    desc.name = "Pre-Margin Factor";
127
    desc.description = "The maximum amount by which a beat can be earlier than the predicted beat time, expressed as a fraction of the beat period.";
128
    desc.minValue = 0;
129
    desc.maxValue = 1;
130
    desc.defaultValue = AgentParameters::DEFAULT_PRE_MARGIN_FACTOR;
131
    desc.isQuantized = false;
132
    list.push_back(desc);
133
    
134
    desc.identifier = "postMarginFactor";
135
    desc.name = "Post-Margin Factor";
136
    desc.description = "The maximum amount by which a beat can be later than the predicted beat time, expressed as a fraction of the beat period.";
137
    desc.minValue = 0;
138
    desc.maxValue = 1;
139
    desc.defaultValue = AgentParameters::DEFAULT_POST_MARGIN_FACTOR;
140
    desc.isQuantized = false;
141
    list.push_back(desc);
142
    
143
    desc.identifier = "maxChange";
144
    desc.name = "Maximum Change";
145
    desc.description = "The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period.";
146
    desc.minValue = 0;
147
    desc.maxValue = 1;
148
    desc.defaultValue = AgentParameters::DEFAULT_MAX_CHANGE;
149
    desc.isQuantized = false;
150
    list.push_back(desc);
151
    
152
    desc.identifier = "expiryTime";
153
    desc.name = "Expiry Time";
154
    desc.description = "The default value of expiryTime, which is the time (in seconds) after which an Agent that has no Event matching its beat predictions will be destroyed.";
155
    desc.minValue = 2;
156
    desc.maxValue = 120;
157
    desc.defaultValue = AgentParameters::DEFAULT_EXPIRY_TIME;
158
    desc.isQuantized = false;
159
    list.push_back(desc);
160

    
161
    // Simon says...
162

    
163
    // These are the parameters that should be exposed (Agent.cpp):
164

    
165
    // If Pop, both margins should be lower (0.1).  If classical
166
    // music, post margin can be increased
167
    //
168
    // double Agent::POST_MARGIN_FACTOR = 0.3;
169
    // double Agent::PRE_MARGIN_FACTOR = 0.15;
170
    //
171
    // Max Change tells us how much tempo can change - so for
172
    // classical we should make it higher
173
    // 
174
    // double Agent::MAX_CHANGE = 0.2;
175
    // 
176
    // The EXPIRY TIME default should be defaulted to 100 (usual cause
177
    // of agents dying....)  it should also be exposed in order to
178
    // troubleshoot eventual problems in songs with big silences in
179
    // the beggining/end.
180
    // 
181
    // const double Agent::DEFAULT_EXPIRY_TIME = 10.0;
182

    
183
    return list;
184
}
185

    
186
float
187
BeatRootVampPlugin::getParameter(string identifier) const
188
{
189
    if (identifier == "preMarginFactor") {
190
        return m_parameters.preMarginFactor;
191
    } else if (identifier == "postMarginFactor") {
192
        return m_parameters.postMarginFactor;
193
    } else if (identifier == "maxChange") {
194
        return m_parameters.maxChange;
195
    } else if (identifier == "expiryTime") {
196
        return m_parameters.expiryTime;
197
    }
198
    
199
    return 0;
200
}
201

    
202
void
203
BeatRootVampPlugin::setParameter(string identifier, float value) 
204
{
205
    if (identifier == "preMarginFactor") {
206
        m_parameters.preMarginFactor = value;
207
    } else if (identifier == "postMarginFactor") {
208
        m_parameters.postMarginFactor = value;
209
    } else if (identifier == "maxChange") {
210
        m_parameters.maxChange = value;
211
    } else if (identifier == "expiryTime") {
212
        m_parameters.expiryTime = value;
213
    }
214
}
215

    
216
BeatRootVampPlugin::ProgramList
217
BeatRootVampPlugin::getPrograms() const
218
{
219
    ProgramList list;
220
    return list;
221
}
222

    
223
string
224
BeatRootVampPlugin::getCurrentProgram() const
225
{
226
    return ""; // no programs
227
}
228

    
229
void
230
BeatRootVampPlugin::selectProgram(string name)
231
{
232
}
233

    
234
BeatRootVampPlugin::OutputList
235
BeatRootVampPlugin::getOutputDescriptors() const
236
{
237
    OutputList list;
238

    
239
    // See OutputDescriptor documentation for the possibilities here.
240
    // Every plugin must have at least one output.
241

    
242
    OutputDescriptor d;
243
    d.identifier = "beats";
244
    d.name = "Beats";
245
    d.description = "Estimated beat locations";
246
    d.unit = "";
247
    d.hasFixedBinCount = true;
248
    d.binCount = 0;
249
    d.hasKnownExtents = false;
250
    d.isQuantized = false;
251
    d.sampleType = OutputDescriptor::VariableSampleRate;
252
    d.sampleRate = m_inputSampleRate;
253
    d.hasDuration = false;
254
    list.push_back(d);
255

    
256
    return list;
257
}
258

    
259
bool
260
BeatRootVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
261
{
262
    if (channels < getMinChannelCount() ||
263
        channels > getMaxChannelCount()) {
264
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported number ("
265
                  << channels << ") of channels" << std::endl;
266
        return false;
267
    }
268

    
269
    if (stepSize != getPreferredStepSize()) {
270
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported step size "
271
                  << "for sample rate (" << stepSize << ", required step is "
272
                  << getPreferredStepSize() << " for rate " << m_inputSampleRate
273
                  << ")" << std::endl;
274
        return false;
275
    }
276

    
277
    if (blockSize != getPreferredBlockSize()) {
278
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported block size "
279
                  << "for sample rate (" << blockSize << ", required size is "
280
                  << getPreferredBlockSize() << " for rate " << m_inputSampleRate
281
                  << ")" << std::endl;
282
        return false;
283
    }
284

    
285
    // Delete the processor that was created with default parameters
286
    // and used to determine the expected step and block size; replace
287
    // with one using the actual parameters we have
288
    delete m_processor;
289
    m_processor = new BeatRootProcessor(m_inputSampleRate, m_parameters);
290

    
291
    return true;
292
}
293

    
294
void
295
BeatRootVampPlugin::reset()
296
{
297
    m_processor->reset();
298
}
299

    
300
BeatRootVampPlugin::FeatureSet
301
BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
302
{
303
    m_processor->processFrame(inputBuffers);
304
    return FeatureSet();
305
}
306

    
307
BeatRootVampPlugin::FeatureSet
308
BeatRootVampPlugin::getRemainingFeatures()
309
{
310
    EventList el = m_processor->beatTrack();
311

    
312
    Feature f;
313
    f.hasTimestamp = true;
314
    f.hasDuration = false;
315
    f.label = "";
316
    f.values.clear();
317

    
318
    FeatureSet fs;
319

    
320
    for (EventList::const_iterator i = el.begin(); i != el.end(); ++i) {
321
        f.timestamp = Vamp::RealTime::fromSeconds(i->time);
322
        fs[0].push_back(f);
323
    }
324

    
325
    return fs;
326
}
327

    
328

    
329
static Vamp::PluginAdapter<BeatRootVampPlugin> brAdapter;
330

    
331
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
332
                                                    unsigned int index)
333
{
334
    if (version < 1) return 0;
335

    
336
    switch (index) {
337
    case  0: return brAdapter.getDescriptor();
338
    default: return 0;
339
    }
340
}
341