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 @ 36:937432fc2898

History | View | Annotate | Download (9.03 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
    m_firstFrame(true)
27
{
28
    m_processor = new BeatRootProcessor(inputSampleRate, AgentParameters());
29
}
30

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

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

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

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

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

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

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

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

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

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

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

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

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

    
109
    ParameterDescriptor desc;
110

    
111
    desc.identifier = "preMarginFactor";
112
    desc.name = "Pre-Margin Factor";
113
    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.";
114
    desc.minValue = 0;
115
    desc.maxValue = 1;
116
    desc.defaultValue = AgentParameters::DEFAULT_PRE_MARGIN_FACTOR;
117
    desc.isQuantized = false;
118
    list.push_back(desc);
119
    
120
    desc.identifier = "postMarginFactor";
121
    desc.name = "Post-Margin Factor";
122
    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.";
123
    desc.minValue = 0;
124
    desc.maxValue = 1;
125
    desc.defaultValue = AgentParameters::DEFAULT_POST_MARGIN_FACTOR;
126
    desc.isQuantized = false;
127
    list.push_back(desc);
128
    
129
    desc.identifier = "maxChange";
130
    desc.name = "Maximum Change";
131
    desc.description = "The maximum allowed deviation from the initial tempo, expressed as a fraction of the initial beat period.";
132
    desc.minValue = 0;
133
    desc.maxValue = 1;
134
    desc.defaultValue = AgentParameters::DEFAULT_MAX_CHANGE;
135
    desc.isQuantized = false;
136
    list.push_back(desc);
137
    
138
    desc.identifier = "expiryTime";
139
    desc.name = "Expiry Time";
140
    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.";
141
    desc.minValue = 2;
142
    desc.maxValue = 120;
143
    desc.defaultValue = AgentParameters::DEFAULT_EXPIRY_TIME;
144
    desc.isQuantized = false;
145
    list.push_back(desc);
146

    
147
    // Simon says...
148

    
149
    // These are the parameters that should be exposed (Agent.cpp):
150

    
151
    // If Pop, both margins should be lower (0.1).  If classical
152
    // music, post margin can be increased
153
    //
154
    // double Agent::POST_MARGIN_FACTOR = 0.3;
155
    // double Agent::PRE_MARGIN_FACTOR = 0.15;
156
    //
157
    // Max Change tells us how much tempo can change - so for
158
    // classical we should make it higher
159
    // 
160
    // double Agent::MAX_CHANGE = 0.2;
161
    // 
162
    // The EXPIRY TIME default should be defaulted to 100 (usual cause
163
    // of agents dying....)  it should also be exposed in order to
164
    // troubleshoot eventual problems in songs with big silences in
165
    // the beggining/end.
166
    // 
167
    // const double Agent::DEFAULT_EXPIRY_TIME = 10.0;
168

    
169
    return list;
170
}
171

    
172
float
173
BeatRootVampPlugin::getParameter(string identifier) const
174
{
175
    if (identifier == "preMarginFactor") {
176
        return m_parameters.preMarginFactor;
177
    } else if (identifier == "postMarginFactor") {
178
        return m_parameters.postMarginFactor;
179
    } else if (identifier == "maxChange") {
180
        return m_parameters.maxChange;
181
    } else if (identifier == "expiryTime") {
182
        return m_parameters.expiryTime;
183
    }
184
    
185
    return 0;
186
}
187

    
188
void
189
BeatRootVampPlugin::setParameter(string identifier, float value) 
190
{
191
    if (identifier == "preMarginFactor") {
192
        m_parameters.preMarginFactor = value;
193
    } else if (identifier == "postMarginFactor") {
194
        m_parameters.postMarginFactor = value;
195
    } else if (identifier == "maxChange") {
196
        m_parameters.maxChange = value;
197
    } else if (identifier == "expiryTime") {
198
        m_parameters.expiryTime = value;
199
    }
200
}
201

    
202
BeatRootVampPlugin::ProgramList
203
BeatRootVampPlugin::getPrograms() const
204
{
205
    ProgramList list;
206
    return list;
207
}
208

    
209
string
210
BeatRootVampPlugin::getCurrentProgram() const
211
{
212
    return ""; // no programs
213
}
214

    
215
void
216
BeatRootVampPlugin::selectProgram(string name)
217
{
218
}
219

    
220
BeatRootVampPlugin::OutputList
221
BeatRootVampPlugin::getOutputDescriptors() const
222
{
223
    OutputList list;
224

    
225
    // See OutputDescriptor documentation for the possibilities here.
226
    // Every plugin must have at least one output.
227

    
228
    OutputDescriptor d;
229
    d.identifier = "beats";
230
    d.name = "Beats";
231
    d.description = "Estimated beat locations";
232
    d.unit = "";
233
    d.hasFixedBinCount = true;
234
    d.binCount = 0;
235
    d.hasKnownExtents = false;
236
    d.isQuantized = false;
237
    d.sampleType = OutputDescriptor::VariableSampleRate;
238
    d.sampleRate = m_inputSampleRate;
239
    d.hasDuration = false;
240
    list.push_back(d);
241

    
242
    d.identifier = "unfilled";
243
    d.name = "Un-interpolated beats";
244
    d.description = "Locations of detected beats, before agent interpolation occurs";
245
    list.push_back(d);
246

    
247
    return list;
248
}
249

    
250
bool
251
BeatRootVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
252
{
253
    if (channels < getMinChannelCount() ||
254
        channels > getMaxChannelCount()) {
255
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported number ("
256
                  << channels << ") of channels" << std::endl;
257
        return false;
258
    }
259

    
260
    if (stepSize != getPreferredStepSize()) {
261
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported step size "
262
                  << "for sample rate (" << stepSize << ", required step is "
263
                  << getPreferredStepSize() << " for rate " << m_inputSampleRate
264
                  << ")" << std::endl;
265
        return false;
266
    }
267

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

    
276
    // Delete the processor that was created with default parameters
277
    // and used to determine the expected step and block size; replace
278
    // with one using the actual parameters we have
279
    delete m_processor;
280
    m_processor = new BeatRootProcessor(m_inputSampleRate, m_parameters);
281

    
282
    return true;
283
}
284

    
285
void
286
BeatRootVampPlugin::reset()
287
{
288
    m_processor->reset();
289
    m_firstFrame = true;
290
    m_origin = Vamp::RealTime::zeroTime;
291
}
292

    
293
BeatRootVampPlugin::FeatureSet
294
BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
295
{
296
    if (m_firstFrame) {
297
        m_origin = timestamp;
298
        m_firstFrame = false;
299
    }
300

    
301
    m_processor->processFrame(inputBuffers);
302
    return FeatureSet();
303
}
304

    
305
BeatRootVampPlugin::FeatureSet
306
BeatRootVampPlugin::getRemainingFeatures()
307
{
308
    EventList unfilled;
309
    EventList el = m_processor->beatTrack(&unfilled);
310

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

    
317
    FeatureSet fs;
318

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

    
324
    for (EventList::const_iterator i = unfilled.begin(); 
325
         i != unfilled.end(); ++i) {
326
        f.timestamp = m_origin + Vamp::RealTime::fromSeconds(i->time);
327
        fs[1].push_back(f);
328
    }
329

    
330
    return fs;
331
}
332

    
333

    
334
static Vamp::PluginAdapter<BeatRootVampPlugin> brAdapter;
335

    
336
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
337
                                                    unsigned int index)
338
{
339
    if (version < 1) return 0;
340

    
341
    switch (index) {
342
    case  0: return brAdapter.getDescriptor();
343
    default: return 0;
344
    }
345
}
346