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 @ 31:b9c2f444cdaa

History | View | Annotate | Download (8.62 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
    return list;
243
}
244

    
245
bool
246
BeatRootVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
247
{
248
    if (channels < getMinChannelCount() ||
249
        channels > getMaxChannelCount()) {
250
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported number ("
251
                  << channels << ") of channels" << std::endl;
252
        return false;
253
    }
254

    
255
    if (stepSize != getPreferredStepSize()) {
256
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported step size "
257
                  << "for sample rate (" << stepSize << ", required step is "
258
                  << getPreferredStepSize() << " for rate " << m_inputSampleRate
259
                  << ")" << std::endl;
260
        return false;
261
    }
262

    
263
    if (blockSize != getPreferredBlockSize()) {
264
        std::cerr << "BeatRootVampPlugin::initialise: Unsupported block size "
265
                  << "for sample rate (" << blockSize << ", required size is "
266
                  << getPreferredBlockSize() << " for rate " << m_inputSampleRate
267
                  << ")" << std::endl;
268
        return false;
269
    }
270

    
271
    // Delete the processor that was created with default parameters
272
    // and used to determine the expected step and block size; replace
273
    // with one using the actual parameters we have
274
    delete m_processor;
275
    m_processor = new BeatRootProcessor(m_inputSampleRate, m_parameters);
276

    
277
    return true;
278
}
279

    
280
void
281
BeatRootVampPlugin::reset()
282
{
283
    m_processor->reset();
284
    m_firstFrame = true;
285
    m_origin = Vamp::RealTime::zeroTime;
286
}
287

    
288
BeatRootVampPlugin::FeatureSet
289
BeatRootVampPlugin::process(const float *const *inputBuffers, Vamp::RealTime timestamp)
290
{
291
    if (m_firstFrame) {
292
        m_origin = timestamp;
293
        m_firstFrame = false;
294
    }
295

    
296
    m_processor->processFrame(inputBuffers);
297
    return FeatureSet();
298
}
299

    
300
BeatRootVampPlugin::FeatureSet
301
BeatRootVampPlugin::getRemainingFeatures()
302
{
303
    EventList el = m_processor->beatTrack();
304

    
305
    Feature f;
306
    f.hasTimestamp = true;
307
    f.hasDuration = false;
308
    f.label = "";
309
    f.values.clear();
310

    
311
    FeatureSet fs;
312

    
313
    for (EventList::const_iterator i = el.begin(); i != el.end(); ++i) {
314
        f.timestamp = m_origin + Vamp::RealTime::fromSeconds(i->time);
315
        fs[0].push_back(f);
316
    }
317

    
318
    return fs;
319
}
320

    
321

    
322
static Vamp::PluginAdapter<BeatRootVampPlugin> brAdapter;
323

    
324
const VampPluginDescriptor *vampGetPluginDescriptor(unsigned int version,
325
                                                    unsigned int index)
326
{
327
    if (version < 1) return 0;
328

    
329
    switch (index) {
330
    case  0: return brAdapter.getDescriptor();
331
    default: return 0;
332
    }
333
}
334