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 / CepstralPitchTracker.cpp @ 57:82b3cdf6ca6b

History | View | Annotate | Download (8.06 KB)

1 3:9366c8a58778 Chris
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
/*
3 31:2c175adf8736 Chris
    This file is Copyright (c) 2012 Chris Cannam
4

5 3:9366c8a58778 Chris
    Permission is hereby granted, free of charge, to any person
6
    obtaining a copy of this software and associated documentation
7
    files (the "Software"), to deal in the Software without
8
    restriction, including without limitation the rights to use, copy,
9
    modify, merge, publish, distribute, sublicense, and/or sell copies
10
    of the Software, and to permit persons to whom the Software is
11
    furnished to do so, subject to the following conditions:
12

13
    The above copyright notice and this permission notice shall be
14
    included in all copies or substantial portions of the Software.
15

16
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
20
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
*/
24
25 31:2c175adf8736 Chris
#include "CepstralPitchTracker.h"
26 51:0997774f5fdc Chris
#include "Cepstrum.h"
27 47:f72a470fe4b5 Chris
#include "MeanFilter.h"
28 50:d84049e20c61 Chris
#include "PeakInterpolator.h"
29 56:d8eeba570d70 Chris
#include "AgentFeeder.h"
30 3:9366c8a58778 Chris
31 26:13568f1ccff0 Chris
#include "vamp-sdk/FFT.h"
32
33 3:9366c8a58778 Chris
#include <vector>
34
#include <algorithm>
35
36
#include <cstdio>
37
#include <cmath>
38
#include <complex>
39
40
using std::string;
41 7:32defdb2f9d9 Chris
using std::vector;
42 16:d717911aca3c Chris
using Vamp::RealTime;
43 7:32defdb2f9d9 Chris
44 16:d717911aca3c Chris
45 31:2c175adf8736 Chris
CepstralPitchTracker::CepstralPitchTracker(float inputSampleRate) :
46 3:9366c8a58778 Chris
    Plugin(inputSampleRate),
47
    m_channels(0),
48
    m_stepSize(256),
49
    m_blockSize(1024),
50
    m_fmin(50),
51 25:9aee1a0e6223 Chris
    m_fmax(900),
52 18:131b1c40be1a Chris
    m_vflen(1),
53 3:9366c8a58778 Chris
    m_binFrom(0),
54
    m_binTo(0),
55 56:d8eeba570d70 Chris
    m_bins(0),
56 57:82b3cdf6ca6b Chris
    m_nAccepted(0),
57 56:d8eeba570d70 Chris
    m_feeder(0)
58 3:9366c8a58778 Chris
{
59
}
60
61 31:2c175adf8736 Chris
CepstralPitchTracker::~CepstralPitchTracker()
62 3:9366c8a58778 Chris
{
63 56:d8eeba570d70 Chris
    delete m_feeder;
64 3:9366c8a58778 Chris
}
65
66
string
67 31:2c175adf8736 Chris
CepstralPitchTracker::getIdentifier() const
68 3:9366c8a58778 Chris
{
69 39:822cf7b8e070 Chris
    return "cepstral-pitchtracker";
70 3:9366c8a58778 Chris
}
71
72
string
73 31:2c175adf8736 Chris
CepstralPitchTracker::getName() const
74 3:9366c8a58778 Chris
{
75 39:822cf7b8e070 Chris
    return "Cepstral Pitch Tracker";
76 3:9366c8a58778 Chris
}
77
78
string
79 31:2c175adf8736 Chris
CepstralPitchTracker::getDescription() const
80 3:9366c8a58778 Chris
{
81
    return "Estimate f0 of monophonic material using a cepstrum method.";
82
}
83
84
string
85 31:2c175adf8736 Chris
CepstralPitchTracker::getMaker() const
86 3:9366c8a58778 Chris
{
87
    return "Chris Cannam";
88
}
89
90
int
91 31:2c175adf8736 Chris
CepstralPitchTracker::getPluginVersion() const
92 3:9366c8a58778 Chris
{
93
    // Increment this each time you release a version that behaves
94
    // differently from the previous one
95
    return 1;
96
}
97
98
string
99 31:2c175adf8736 Chris
CepstralPitchTracker::getCopyright() const
100 3:9366c8a58778 Chris
{
101
    return "Freely redistributable (BSD license)";
102
}
103
104 31:2c175adf8736 Chris
CepstralPitchTracker::InputDomain
105
CepstralPitchTracker::getInputDomain() const
106 3:9366c8a58778 Chris
{
107
    return FrequencyDomain;
108
}
109
110
size_t
111 31:2c175adf8736 Chris
CepstralPitchTracker::getPreferredBlockSize() const
112 3:9366c8a58778 Chris
{
113
    return 1024;
114
}
115
116
size_t
117 31:2c175adf8736 Chris
CepstralPitchTracker::getPreferredStepSize() const
118 3:9366c8a58778 Chris
{
119
    return 256;
120
}
121
122
size_t
123 31:2c175adf8736 Chris
CepstralPitchTracker::getMinChannelCount() const
124 3:9366c8a58778 Chris
{
125
    return 1;
126
}
127
128
size_t
129 31:2c175adf8736 Chris
CepstralPitchTracker::getMaxChannelCount() const
130 3:9366c8a58778 Chris
{
131
    return 1;
132
}
133
134 31:2c175adf8736 Chris
CepstralPitchTracker::ParameterList
135
CepstralPitchTracker::getParameterDescriptors() const
136 3:9366c8a58778 Chris
{
137
    ParameterList list;
138
    return list;
139
}
140
141
float
142 31:2c175adf8736 Chris
CepstralPitchTracker::getParameter(string identifier) const
143 3:9366c8a58778 Chris
{
144
    return 0.f;
145
}
146
147
void
148 31:2c175adf8736 Chris
CepstralPitchTracker::setParameter(string identifier, float value)
149 3:9366c8a58778 Chris
{
150
}
151
152 31:2c175adf8736 Chris
CepstralPitchTracker::ProgramList
153
CepstralPitchTracker::getPrograms() const
154 3:9366c8a58778 Chris
{
155
    ProgramList list;
156
    return list;
157
}
158
159
string
160 31:2c175adf8736 Chris
CepstralPitchTracker::getCurrentProgram() const
161 3:9366c8a58778 Chris
{
162
    return ""; // no programs
163
}
164
165
void
166 31:2c175adf8736 Chris
CepstralPitchTracker::selectProgram(string name)
167 3:9366c8a58778 Chris
{
168
}
169
170 31:2c175adf8736 Chris
CepstralPitchTracker::OutputList
171
CepstralPitchTracker::getOutputDescriptors() const
172 3:9366c8a58778 Chris
{
173
    OutputList outputs;
174
175
    OutputDescriptor d;
176
177
    d.identifier = "f0";
178
    d.name = "Estimated f0";
179
    d.description = "Estimated fundamental frequency";
180
    d.unit = "Hz";
181
    d.hasFixedBinCount = true;
182
    d.binCount = 1;
183
    d.hasKnownExtents = true;
184
    d.minValue = m_fmin;
185
    d.maxValue = m_fmax;
186
    d.isQuantized = false;
187
    d.sampleType = OutputDescriptor::FixedSampleRate;
188
    d.sampleRate = (m_inputSampleRate / m_stepSize);
189
    d.hasDuration = false;
190
    outputs.push_back(d);
191
192 16:d717911aca3c Chris
    d.identifier = "notes";
193
    d.name = "Notes";
194
    d.description = "Derived fixed-pitch note frequencies";
195
    d.unit = "Hz";
196
    d.hasFixedBinCount = true;
197
    d.binCount = 1;
198
    d.hasKnownExtents = true;
199
    d.minValue = m_fmin;
200
    d.maxValue = m_fmax;
201
    d.isQuantized = false;
202
    d.sampleType = OutputDescriptor::FixedSampleRate;
203
    d.sampleRate = (m_inputSampleRate / m_stepSize);
204
    d.hasDuration = true;
205
    outputs.push_back(d);
206
207 3:9366c8a58778 Chris
    return outputs;
208
}
209
210
bool
211 31:2c175adf8736 Chris
CepstralPitchTracker::initialise(size_t channels, size_t stepSize, size_t blockSize)
212 3:9366c8a58778 Chris
{
213
    if (channels < getMinChannelCount() ||
214
        channels > getMaxChannelCount()) return false;
215
216 31:2c175adf8736 Chris
//    std::cerr << "CepstralPitchTracker::initialise: channels = " << channels
217 3:9366c8a58778 Chris
//              << ", stepSize = " << stepSize << ", blockSize = " << blockSize
218
//              << std::endl;
219
220
    m_channels = channels;
221
    m_stepSize = stepSize;
222
    m_blockSize = blockSize;
223
224
    m_binFrom = int(m_inputSampleRate / m_fmax);
225
    m_binTo = int(m_inputSampleRate / m_fmin);
226
227
    if (m_binTo >= (int)m_blockSize / 2) {
228
        m_binTo = m_blockSize / 2 - 1;
229
    }
230 56:d8eeba570d70 Chris
    if (m_binFrom >= m_binTo) {
231
        // shouldn't happen except for degenerate samplerate / blocksize combos
232
        m_binFrom = m_binTo - 1;
233
    }
234 3:9366c8a58778 Chris
235
    m_bins = (m_binTo - m_binFrom) + 1;
236
237
    reset();
238
239
    return true;
240
}
241
242
void
243 31:2c175adf8736 Chris
CepstralPitchTracker::reset()
244 3:9366c8a58778 Chris
{
245 56:d8eeba570d70 Chris
    delete m_feeder;
246
    m_feeder = new AgentFeeder();
247 57:82b3cdf6ca6b Chris
    m_nAccepted = 0;
248 3:9366c8a58778 Chris
}
249
250
void
251 35:2f5b169e4a3b Chris
CepstralPitchTracker::addFeaturesFrom(NoteHypothesis h, FeatureSet &fs)
252 30:2554aab152a5 Chris
{
253 35:2f5b169e4a3b Chris
    NoteHypothesis::Estimates es = h.getAcceptedEstimates();
254 30:2554aab152a5 Chris
255 35:2f5b169e4a3b Chris
    for (int i = 0; i < (int)es.size(); ++i) {
256 30:2554aab152a5 Chris
        Feature f;
257
        f.hasTimestamp = true;
258
        f.timestamp = es[i].time;
259
        f.values.push_back(es[i].freq);
260
        fs[0].push_back(f);
261
    }
262
263
    Feature nf;
264
    nf.hasTimestamp = true;
265
    nf.hasDuration = true;
266 35:2f5b169e4a3b Chris
    NoteHypothesis::Note n = h.getAveragedNote();
267 30:2554aab152a5 Chris
    nf.timestamp = n.time;
268
    nf.duration = n.duration;
269
    nf.values.push_back(n.freq);
270
    fs[1].push_back(nf);
271
}
272
273 57:82b3cdf6ca6b Chris
void
274
CepstralPitchTracker::addNewFeatures(FeatureSet &fs)
275
{
276
    int n = m_feeder->getAcceptedHypotheses().size();
277
    if (n == m_nAccepted) return;
278
279
    AgentFeeder::Hypotheses accepted = m_feeder->getAcceptedHypotheses();
280
281
    for (int i = m_nAccepted; i < n; ++i) {
282
        addFeaturesFrom(accepted[i], fs);
283
    }
284
285
    m_nAccepted = n;
286
}
287
288 31:2c175adf8736 Chris
CepstralPitchTracker::FeatureSet
289
CepstralPitchTracker::process(const float *const *inputBuffers, RealTime timestamp)
290 3:9366c8a58778 Chris
{
291 51:0997774f5fdc Chris
    double *rawcep = new double[m_blockSize];
292
    double magmean = Cepstrum(m_blockSize).process(inputBuffers[0], rawcep);
293 3:9366c8a58778 Chris
294
    int n = m_bins;
295
    double *data = new double[n];
296 51:0997774f5fdc Chris
    MeanFilter(m_vflen).filterSubsequence
297
        (rawcep, data, m_blockSize, n, m_binFrom);
298
299 3:9366c8a58778 Chris
    delete[] rawcep;
300
301
    double maxval = 0.0;
302 6:291c75f6e837 Chris
    int maxbin = -1;
303 3:9366c8a58778 Chris
304
    for (int i = 0; i < n; ++i) {
305
        if (data[i] > maxval) {
306
            maxval = data[i];
307
            maxbin = i;
308
        }
309
    }
310
311 15:bd7fb10646fc Chris
    if (maxbin < 0) {
312
        delete[] data;
313 57:82b3cdf6ca6b Chris
        return FeatureSet();
314 15:bd7fb10646fc Chris
    }
315
316
    double nextPeakVal = 0.0;
317
    for (int i = 1; i+1 < n; ++i) {
318
        if (data[i] > data[i-1] &&
319
            data[i] > data[i+1] &&
320
            i != maxbin &&
321
            data[i] > nextPeakVal) {
322
            nextPeakVal = data[i];
323
        }
324
    }
325 8:e9d86e129467 Chris
326 50:d84049e20c61 Chris
    PeakInterpolator pi;
327
    double cimax = pi.findPeakLocation(data, m_bins, maxbin);
328 18:131b1c40be1a Chris
    double peakfreq = m_inputSampleRate / (cimax + m_binFrom);
329 15:bd7fb10646fc Chris
330
    double confidence = 0.0;
331 51:0997774f5fdc Chris
    double threshold = 0.1; // for magmean
332
333 15:bd7fb10646fc Chris
    if (nextPeakVal != 0.0) {
334 27:e358f133e670 Chris
        confidence = (maxval - nextPeakVal) * 10.0;
335 25:9aee1a0e6223 Chris
        if (magmean < threshold) confidence = 0.0;
336 39:822cf7b8e070 Chris
//        std::cerr << "magmean = " << magmean << ", confidence = " << confidence << std::endl;
337 15:bd7fb10646fc Chris
    }
338
339 57:82b3cdf6ca6b Chris
    delete[] data;
340
341 35:2f5b169e4a3b Chris
    NoteHypothesis::Estimate e;
342 8:e9d86e129467 Chris
    e.freq = peakfreq;
343
    e.time = timestamp;
344 15:bd7fb10646fc Chris
    e.confidence = confidence;
345 8:e9d86e129467 Chris
346 56:d8eeba570d70 Chris
    m_feeder->feed(e);
347 14:98256077e2a2 Chris
348 57:82b3cdf6ca6b Chris
    FeatureSet fs;
349
    addNewFeatures(fs);
350 3:9366c8a58778 Chris
    return fs;
351
}
352
353 31:2c175adf8736 Chris
CepstralPitchTracker::FeatureSet
354
CepstralPitchTracker::getRemainingFeatures()
355 3:9366c8a58778 Chris
{
356 56:d8eeba570d70 Chris
    m_feeder->finish();
357
358 3:9366c8a58778 Chris
    FeatureSet fs;
359 57:82b3cdf6ca6b Chris
    addNewFeatures(fs);
360 3:9366c8a58778 Chris
    return fs;
361
}