annotate CepstralPitchTracker.cpp @ 31:2c175adf8736

Pull out pitch tracker from vamp-simple-cepstrum to its own project
author Chris Cannam
date Thu, 19 Jul 2012 13:13:23 +0100
parents CepstrumPitchTracker.cpp@2554aab152a5
children 2f5b169e4a3b
rev   line source
Chris@3 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@3 2 /*
Chris@31 3 This file is Copyright (c) 2012 Chris Cannam
Chris@31 4
Chris@3 5 Permission is hereby granted, free of charge, to any person
Chris@3 6 obtaining a copy of this software and associated documentation
Chris@3 7 files (the "Software"), to deal in the Software without
Chris@3 8 restriction, including without limitation the rights to use, copy,
Chris@3 9 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@3 10 of the Software, and to permit persons to whom the Software is
Chris@3 11 furnished to do so, subject to the following conditions:
Chris@3 12
Chris@3 13 The above copyright notice and this permission notice shall be
Chris@3 14 included in all copies or substantial portions of the Software.
Chris@3 15
Chris@3 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@3 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@3 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@3 19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@3 20 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@3 21 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@3 22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@3 23 */
Chris@3 24
Chris@31 25 #include "CepstralPitchTracker.h"
Chris@3 26
Chris@26 27 #include "vamp-sdk/FFT.h"
Chris@26 28
Chris@3 29 #include <vector>
Chris@3 30 #include <algorithm>
Chris@3 31
Chris@3 32 #include <cstdio>
Chris@3 33 #include <cmath>
Chris@3 34 #include <complex>
Chris@3 35
Chris@3 36 using std::string;
Chris@7 37 using std::vector;
Chris@16 38 using Vamp::RealTime;
Chris@7 39
Chris@31 40 CepstralPitchTracker::Hypothesis::Hypothesis()
Chris@7 41 {
Chris@8 42 m_state = New;
Chris@7 43 }
Chris@7 44
Chris@31 45 CepstralPitchTracker::Hypothesis::~Hypothesis()
Chris@11 46 {
Chris@11 47 }
Chris@11 48
Chris@7 49 bool
Chris@31 50 CepstralPitchTracker::Hypothesis::isWithinTolerance(Estimate s) const
Chris@7 51 {
Chris@7 52 if (m_pending.empty()) {
Chris@7 53 return true;
Chris@7 54 }
Chris@16 55
Chris@16 56 // check we are within a relatively close tolerance of the last
Chris@16 57 // candidate
Chris@17 58 Estimate last = m_pending[m_pending.size()-1];
Chris@7 59 double r = s.freq / last.freq;
Chris@7 60 int cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@17 61 if (cents < -60 || cents > 60) return false;
Chris@16 62
Chris@17 63 // and within a slightly bigger tolerance of the current mean
Chris@17 64 double meanFreq = getMeanFrequency();
Chris@17 65 r = s.freq / meanFreq;
Chris@16 66 cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@16 67 if (cents < -80 || cents > 80) return false;
Chris@16 68
Chris@16 69 return true;
Chris@7 70 }
Chris@7 71
Chris@28 72 bool
Chris@31 73 CepstralPitchTracker::Hypothesis::isOutOfDateFor(Estimate s) const
Chris@28 74 {
Chris@28 75 if (m_pending.empty()) return false;
Chris@28 76
Chris@28 77 return ((s.time - m_pending[m_pending.size()-1].time) >
Chris@28 78 RealTime::fromMilliseconds(40));
Chris@28 79 }
Chris@28 80
Chris@7 81 bool
Chris@31 82 CepstralPitchTracker::Hypothesis::isSatisfied() const
Chris@7 83 {
Chris@15 84 if (m_pending.empty()) return false;
Chris@15 85
Chris@15 86 double meanConfidence = 0.0;
Chris@15 87 for (int i = 0; i < m_pending.size(); ++i) {
Chris@15 88 meanConfidence += m_pending[i].confidence;
Chris@15 89 }
Chris@15 90 meanConfidence /= m_pending.size();
Chris@15 91
Chris@25 92 int lengthRequired = 10000;
Chris@25 93 if (meanConfidence > 0.0) {
Chris@25 94 lengthRequired = int(2.0 / meanConfidence + 0.5);
Chris@25 95 }
Chris@15 96
Chris@15 97 return (m_pending.size() > lengthRequired);
Chris@7 98 }
Chris@7 99
Chris@7 100 bool
Chris@31 101 CepstralPitchTracker::Hypothesis::accept(Estimate s)
Chris@7 102 {
Chris@8 103 bool accept = false;
Chris@8 104
Chris@8 105 switch (m_state) {
Chris@8 106
Chris@8 107 case New:
Chris@8 108 m_state = Provisional;
Chris@8 109 accept = true;
Chris@8 110 break;
Chris@8 111
Chris@8 112 case Provisional:
Chris@28 113 if (isOutOfDateFor(s)) {
Chris@8 114 m_state = Rejected;
Chris@8 115 } else if (isWithinTolerance(s)) {
Chris@8 116 accept = true;
Chris@8 117 }
Chris@8 118 break;
Chris@8 119
Chris@8 120 case Satisfied:
Chris@28 121 if (isOutOfDateFor(s)) {
Chris@8 122 m_state = Expired;
Chris@8 123 } else if (isWithinTolerance(s)) {
Chris@8 124 accept = true;
Chris@8 125 }
Chris@8 126 break;
Chris@8 127
Chris@8 128 case Rejected:
Chris@8 129 break;
Chris@8 130
Chris@8 131 case Expired:
Chris@8 132 break;
Chris@7 133 }
Chris@7 134
Chris@8 135 if (accept) {
Chris@8 136 m_pending.push_back(s);
Chris@8 137 if (m_state == Provisional && isSatisfied()) {
Chris@8 138 m_state = Satisfied;
Chris@7 139 }
Chris@7 140 }
Chris@7 141
Chris@28 142 return accept;
Chris@8 143 }
Chris@7 144
Chris@31 145 CepstralPitchTracker::Hypothesis::State
Chris@31 146 CepstralPitchTracker::Hypothesis::getState() const
Chris@7 147 {
Chris@7 148 return m_state;
Chris@7 149 }
Chris@7 150
Chris@31 151 CepstralPitchTracker::Hypothesis::Estimates
Chris@31 152 CepstralPitchTracker::Hypothesis::getAcceptedEstimates() const
Chris@7 153 {
Chris@7 154 if (m_state == Satisfied || m_state == Expired) {
Chris@7 155 return m_pending;
Chris@7 156 } else {
Chris@7 157 return Estimates();
Chris@7 158 }
Chris@7 159 }
Chris@7 160
Chris@17 161 double
Chris@31 162 CepstralPitchTracker::Hypothesis::getMeanFrequency() const
Chris@17 163 {
Chris@17 164 double acc = 0.0;
Chris@17 165 for (int i = 0; i < m_pending.size(); ++i) {
Chris@17 166 acc += m_pending[i].freq;
Chris@17 167 }
Chris@17 168 acc /= m_pending.size();
Chris@17 169 return acc;
Chris@17 170 }
Chris@17 171
Chris@31 172 CepstralPitchTracker::Hypothesis::Note
Chris@31 173 CepstralPitchTracker::Hypothesis::getAveragedNote() const
Chris@16 174 {
Chris@16 175 Note n;
Chris@16 176
Chris@16 177 if (!(m_state == Satisfied || m_state == Expired)) {
Chris@16 178 n.freq = 0.0;
Chris@16 179 n.time = RealTime::zeroTime;
Chris@16 180 n.duration = RealTime::zeroTime;
Chris@16 181 return n;
Chris@16 182 }
Chris@16 183
Chris@16 184 n.time = m_pending.begin()->time;
Chris@16 185
Chris@30 186 Estimates::const_iterator i = m_pending.end();
Chris@16 187 --i;
Chris@16 188 n.duration = i->time - n.time;
Chris@16 189
Chris@17 190 // just mean frequency for now, but this isn't at all right perceptually
Chris@17 191 n.freq = getMeanFrequency();
Chris@16 192
Chris@16 193 return n;
Chris@16 194 }
Chris@16 195
Chris@31 196 CepstralPitchTracker::CepstralPitchTracker(float inputSampleRate) :
Chris@3 197 Plugin(inputSampleRate),
Chris@3 198 m_channels(0),
Chris@3 199 m_stepSize(256),
Chris@3 200 m_blockSize(1024),
Chris@3 201 m_fmin(50),
Chris@25 202 m_fmax(900),
Chris@18 203 m_vflen(1),
Chris@3 204 m_binFrom(0),
Chris@3 205 m_binTo(0),
Chris@15 206 m_bins(0)
Chris@3 207 {
Chris@3 208 }
Chris@3 209
Chris@31 210 CepstralPitchTracker::~CepstralPitchTracker()
Chris@3 211 {
Chris@3 212 }
Chris@3 213
Chris@3 214 string
Chris@31 215 CepstralPitchTracker::getIdentifier() const
Chris@3 216 {
Chris@3 217 return "cepstrum-pitch";
Chris@3 218 }
Chris@3 219
Chris@3 220 string
Chris@31 221 CepstralPitchTracker::getName() const
Chris@3 222 {
Chris@3 223 return "Cepstrum Pitch Tracker";
Chris@3 224 }
Chris@3 225
Chris@3 226 string
Chris@31 227 CepstralPitchTracker::getDescription() const
Chris@3 228 {
Chris@3 229 return "Estimate f0 of monophonic material using a cepstrum method.";
Chris@3 230 }
Chris@3 231
Chris@3 232 string
Chris@31 233 CepstralPitchTracker::getMaker() const
Chris@3 234 {
Chris@3 235 return "Chris Cannam";
Chris@3 236 }
Chris@3 237
Chris@3 238 int
Chris@31 239 CepstralPitchTracker::getPluginVersion() const
Chris@3 240 {
Chris@3 241 // Increment this each time you release a version that behaves
Chris@3 242 // differently from the previous one
Chris@3 243 return 1;
Chris@3 244 }
Chris@3 245
Chris@3 246 string
Chris@31 247 CepstralPitchTracker::getCopyright() const
Chris@3 248 {
Chris@3 249 return "Freely redistributable (BSD license)";
Chris@3 250 }
Chris@3 251
Chris@31 252 CepstralPitchTracker::InputDomain
Chris@31 253 CepstralPitchTracker::getInputDomain() const
Chris@3 254 {
Chris@3 255 return FrequencyDomain;
Chris@3 256 }
Chris@3 257
Chris@3 258 size_t
Chris@31 259 CepstralPitchTracker::getPreferredBlockSize() const
Chris@3 260 {
Chris@3 261 return 1024;
Chris@3 262 }
Chris@3 263
Chris@3 264 size_t
Chris@31 265 CepstralPitchTracker::getPreferredStepSize() const
Chris@3 266 {
Chris@3 267 return 256;
Chris@3 268 }
Chris@3 269
Chris@3 270 size_t
Chris@31 271 CepstralPitchTracker::getMinChannelCount() const
Chris@3 272 {
Chris@3 273 return 1;
Chris@3 274 }
Chris@3 275
Chris@3 276 size_t
Chris@31 277 CepstralPitchTracker::getMaxChannelCount() const
Chris@3 278 {
Chris@3 279 return 1;
Chris@3 280 }
Chris@3 281
Chris@31 282 CepstralPitchTracker::ParameterList
Chris@31 283 CepstralPitchTracker::getParameterDescriptors() const
Chris@3 284 {
Chris@3 285 ParameterList list;
Chris@3 286 return list;
Chris@3 287 }
Chris@3 288
Chris@3 289 float
Chris@31 290 CepstralPitchTracker::getParameter(string identifier) const
Chris@3 291 {
Chris@3 292 return 0.f;
Chris@3 293 }
Chris@3 294
Chris@3 295 void
Chris@31 296 CepstralPitchTracker::setParameter(string identifier, float value)
Chris@3 297 {
Chris@3 298 }
Chris@3 299
Chris@31 300 CepstralPitchTracker::ProgramList
Chris@31 301 CepstralPitchTracker::getPrograms() const
Chris@3 302 {
Chris@3 303 ProgramList list;
Chris@3 304 return list;
Chris@3 305 }
Chris@3 306
Chris@3 307 string
Chris@31 308 CepstralPitchTracker::getCurrentProgram() const
Chris@3 309 {
Chris@3 310 return ""; // no programs
Chris@3 311 }
Chris@3 312
Chris@3 313 void
Chris@31 314 CepstralPitchTracker::selectProgram(string name)
Chris@3 315 {
Chris@3 316 }
Chris@3 317
Chris@31 318 CepstralPitchTracker::OutputList
Chris@31 319 CepstralPitchTracker::getOutputDescriptors() const
Chris@3 320 {
Chris@3 321 OutputList outputs;
Chris@3 322
Chris@3 323 int n = 0;
Chris@3 324
Chris@3 325 OutputDescriptor d;
Chris@3 326
Chris@3 327 d.identifier = "f0";
Chris@3 328 d.name = "Estimated f0";
Chris@3 329 d.description = "Estimated fundamental frequency";
Chris@3 330 d.unit = "Hz";
Chris@3 331 d.hasFixedBinCount = true;
Chris@3 332 d.binCount = 1;
Chris@3 333 d.hasKnownExtents = true;
Chris@3 334 d.minValue = m_fmin;
Chris@3 335 d.maxValue = m_fmax;
Chris@3 336 d.isQuantized = false;
Chris@3 337 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@3 338 d.sampleRate = (m_inputSampleRate / m_stepSize);
Chris@3 339 d.hasDuration = false;
Chris@3 340 outputs.push_back(d);
Chris@3 341
Chris@16 342 d.identifier = "notes";
Chris@16 343 d.name = "Notes";
Chris@16 344 d.description = "Derived fixed-pitch note frequencies";
Chris@16 345 d.unit = "Hz";
Chris@16 346 d.hasFixedBinCount = true;
Chris@16 347 d.binCount = 1;
Chris@16 348 d.hasKnownExtents = true;
Chris@16 349 d.minValue = m_fmin;
Chris@16 350 d.maxValue = m_fmax;
Chris@16 351 d.isQuantized = false;
Chris@16 352 d.sampleType = OutputDescriptor::FixedSampleRate;
Chris@16 353 d.sampleRate = (m_inputSampleRate / m_stepSize);
Chris@16 354 d.hasDuration = true;
Chris@16 355 outputs.push_back(d);
Chris@16 356
Chris@3 357 return outputs;
Chris@3 358 }
Chris@3 359
Chris@3 360 bool
Chris@31 361 CepstralPitchTracker::initialise(size_t channels, size_t stepSize, size_t blockSize)
Chris@3 362 {
Chris@3 363 if (channels < getMinChannelCount() ||
Chris@3 364 channels > getMaxChannelCount()) return false;
Chris@3 365
Chris@31 366 // std::cerr << "CepstralPitchTracker::initialise: channels = " << channels
Chris@3 367 // << ", stepSize = " << stepSize << ", blockSize = " << blockSize
Chris@3 368 // << std::endl;
Chris@3 369
Chris@3 370 m_channels = channels;
Chris@3 371 m_stepSize = stepSize;
Chris@3 372 m_blockSize = blockSize;
Chris@3 373
Chris@3 374 m_binFrom = int(m_inputSampleRate / m_fmax);
Chris@3 375 m_binTo = int(m_inputSampleRate / m_fmin);
Chris@3 376
Chris@3 377 if (m_binTo >= (int)m_blockSize / 2) {
Chris@3 378 m_binTo = m_blockSize / 2 - 1;
Chris@3 379 }
Chris@3 380
Chris@3 381 m_bins = (m_binTo - m_binFrom) + 1;
Chris@3 382
Chris@3 383 reset();
Chris@3 384
Chris@3 385 return true;
Chris@3 386 }
Chris@3 387
Chris@3 388 void
Chris@31 389 CepstralPitchTracker::reset()
Chris@3 390 {
Chris@3 391 }
Chris@3 392
Chris@3 393 void
Chris@31 394 CepstralPitchTracker::addFeaturesFrom(Hypothesis h, FeatureSet &fs)
Chris@30 395 {
Chris@30 396 Hypothesis::Estimates es = h.getAcceptedEstimates();
Chris@30 397
Chris@30 398 for (int i = 0; i < es.size(); ++i) {
Chris@30 399 Feature f;
Chris@30 400 f.hasTimestamp = true;
Chris@30 401 f.timestamp = es[i].time;
Chris@30 402 f.values.push_back(es[i].freq);
Chris@30 403 fs[0].push_back(f);
Chris@30 404 }
Chris@30 405
Chris@30 406 Feature nf;
Chris@30 407 nf.hasTimestamp = true;
Chris@30 408 nf.hasDuration = true;
Chris@30 409 Hypothesis::Note n = h.getAveragedNote();
Chris@30 410 nf.timestamp = n.time;
Chris@30 411 nf.duration = n.duration;
Chris@30 412 nf.values.push_back(n.freq);
Chris@30 413 fs[1].push_back(nf);
Chris@30 414 }
Chris@30 415
Chris@30 416 void
Chris@31 417 CepstralPitchTracker::filter(const double *cep, double *data)
Chris@3 418 {
Chris@3 419 for (int i = 0; i < m_bins; ++i) {
Chris@5 420 double v = 0;
Chris@5 421 int n = 0;
Chris@5 422 // average according to the vertical filter length
Chris@5 423 for (int j = -m_vflen/2; j <= m_vflen/2; ++j) {
Chris@5 424 int ix = i + m_binFrom + j;
Chris@5 425 if (ix >= 0 && ix < m_blockSize) {
Chris@5 426 v += cep[ix];
Chris@5 427 ++n;
Chris@5 428 }
Chris@5 429 }
Chris@15 430 data[i] = v / n;
Chris@3 431 }
Chris@6 432 }
Chris@6 433
Chris@18 434 double
Chris@31 435 CepstralPitchTracker::cubicInterpolate(const double y[4], double x)
Chris@18 436 {
Chris@18 437 double a0 = y[3] - y[2] - y[0] + y[1];
Chris@18 438 double a1 = y[0] - y[1] - a0;
Chris@18 439 double a2 = y[2] - y[0];
Chris@18 440 double a3 = y[1];
Chris@18 441 return
Chris@18 442 a0 * x * x * x +
Chris@18 443 a1 * x * x +
Chris@18 444 a2 * x +
Chris@18 445 a3;
Chris@18 446 }
Chris@18 447
Chris@18 448 double
Chris@31 449 CepstralPitchTracker::findInterpolatedPeak(const double *in, int maxbin)
Chris@18 450 {
Chris@18 451 if (maxbin < 2 || maxbin > m_bins - 3) {
Chris@18 452 return maxbin;
Chris@18 453 }
Chris@18 454
Chris@18 455 double maxval = 0.0;
Chris@18 456 double maxidx = maxbin;
Chris@18 457
Chris@18 458 const int divisions = 10;
Chris@18 459 double y[4];
Chris@18 460
Chris@18 461 y[0] = in[maxbin-1];
Chris@18 462 y[1] = in[maxbin];
Chris@18 463 y[2] = in[maxbin+1];
Chris@18 464 y[3] = in[maxbin+2];
Chris@18 465 for (int i = 0; i < divisions; ++i) {
Chris@18 466 double probe = double(i) / double(divisions);
Chris@18 467 double value = cubicInterpolate(y, probe);
Chris@18 468 if (value > maxval) {
Chris@18 469 maxval = value;
Chris@18 470 maxidx = maxbin + probe;
Chris@18 471 }
Chris@18 472 }
Chris@18 473
Chris@18 474 y[3] = y[2];
Chris@18 475 y[2] = y[1];
Chris@18 476 y[1] = y[0];
Chris@18 477 y[0] = in[maxbin-2];
Chris@18 478 for (int i = 0; i < divisions; ++i) {
Chris@18 479 double probe = double(i) / double(divisions);
Chris@18 480 double value = cubicInterpolate(y, probe);
Chris@18 481 if (value > maxval) {
Chris@18 482 maxval = value;
Chris@18 483 maxidx = maxbin - 1 + probe;
Chris@18 484 }
Chris@18 485 }
Chris@18 486
Chris@18 487 /*
Chris@18 488 std::cerr << "centre = " << maxbin << ": ["
Chris@18 489 << in[maxbin-2] << ","
Chris@18 490 << in[maxbin-1] << ","
Chris@18 491 << in[maxbin] << ","
Chris@18 492 << in[maxbin+1] << ","
Chris@18 493 << in[maxbin+2] << "] -> " << maxidx << std::endl;
Chris@18 494 */
Chris@18 495
Chris@18 496 return maxidx;
Chris@18 497 }
Chris@18 498
Chris@31 499 CepstralPitchTracker::FeatureSet
Chris@31 500 CepstralPitchTracker::process(const float *const *inputBuffers, RealTime timestamp)
Chris@3 501 {
Chris@3 502 FeatureSet fs;
Chris@3 503
Chris@3 504 int bs = m_blockSize;
Chris@3 505 int hs = m_blockSize/2 + 1;
Chris@3 506
Chris@3 507 double *rawcep = new double[bs];
Chris@3 508 double *io = new double[bs];
Chris@3 509 double *logmag = new double[bs];
Chris@3 510
Chris@4 511 // The "inverse symmetric" method. Seems to be the most reliable
Chris@3 512
Chris@25 513 double magmean = 0.0;
Chris@25 514
Chris@3 515 for (int i = 0; i < hs; ++i) {
Chris@3 516
Chris@3 517 double power =
Chris@3 518 inputBuffers[0][i*2 ] * inputBuffers[0][i*2 ] +
Chris@3 519 inputBuffers[0][i*2+1] * inputBuffers[0][i*2+1];
Chris@3 520 double mag = sqrt(power);
Chris@25 521
Chris@25 522 magmean += mag;
Chris@25 523
Chris@3 524 double lm = log(mag + 0.00000001);
Chris@3 525
Chris@4 526 logmag[i] = lm;
Chris@4 527 if (i > 0) logmag[bs - i] = lm;
Chris@3 528 }
Chris@3 529
Chris@25 530 magmean /= hs;
Chris@25 531 double threshold = 0.1; // for magmean
Chris@25 532
Chris@26 533 Vamp::FFT::inverse(bs, logmag, 0, rawcep, io);
Chris@3 534
Chris@3 535 delete[] logmag;
Chris@3 536 delete[] io;
Chris@3 537
Chris@3 538 int n = m_bins;
Chris@3 539 double *data = new double[n];
Chris@3 540 filter(rawcep, data);
Chris@3 541 delete[] rawcep;
Chris@3 542
Chris@3 543 double maxval = 0.0;
Chris@6 544 int maxbin = -1;
Chris@3 545
Chris@3 546 for (int i = 0; i < n; ++i) {
Chris@3 547 if (data[i] > maxval) {
Chris@3 548 maxval = data[i];
Chris@3 549 maxbin = i;
Chris@3 550 }
Chris@3 551 }
Chris@3 552
Chris@15 553 if (maxbin < 0) {
Chris@15 554 delete[] data;
Chris@15 555 return fs;
Chris@15 556 }
Chris@15 557
Chris@15 558 double nextPeakVal = 0.0;
Chris@15 559 for (int i = 1; i+1 < n; ++i) {
Chris@15 560 if (data[i] > data[i-1] &&
Chris@15 561 data[i] > data[i+1] &&
Chris@15 562 i != maxbin &&
Chris@15 563 data[i] > nextPeakVal) {
Chris@15 564 nextPeakVal = data[i];
Chris@15 565 }
Chris@15 566 }
Chris@8 567
Chris@18 568 double cimax = findInterpolatedPeak(data, maxbin);
Chris@18 569 double peakfreq = m_inputSampleRate / (cimax + m_binFrom);
Chris@15 570
Chris@15 571 double confidence = 0.0;
Chris@15 572 if (nextPeakVal != 0.0) {
Chris@27 573 confidence = (maxval - nextPeakVal) * 10.0;
Chris@25 574 if (magmean < threshold) confidence = 0.0;
Chris@25 575 std::cerr << "magmean = " << magmean << ", confidence = " << confidence << std::endl;
Chris@15 576 }
Chris@15 577
Chris@8 578 Hypothesis::Estimate e;
Chris@8 579 e.freq = peakfreq;
Chris@8 580 e.time = timestamp;
Chris@15 581 e.confidence = confidence;
Chris@8 582
Chris@28 583 // m_good.advanceTime();
Chris@8 584 for (int i = 0; i < m_possible.size(); ++i) {
Chris@28 585 // m_possible[i].advanceTime();
Chris@8 586 }
Chris@8 587
Chris@28 588 if (!m_good.accept(e)) {
Chris@13 589
Chris@11 590 int candidate = -1;
Chris@13 591 bool accepted = false;
Chris@13 592
Chris@11 593 for (int i = 0; i < m_possible.size(); ++i) {
Chris@28 594 if (m_possible[i].accept(e)) {
Chris@11 595 if (m_possible[i].getState() == Hypothesis::Satisfied) {
Chris@28 596 accepted = true;
Chris@11 597 candidate = i;
Chris@11 598 }
Chris@11 599 break;
Chris@11 600 }
Chris@11 601 }
Chris@12 602
Chris@13 603 if (!accepted) {
Chris@13 604 Hypothesis h;
Chris@28 605 h.accept(e); //!!! must succeed as h is new, so perhaps there should be a ctor for this
Chris@13 606 m_possible.push_back(h);
Chris@13 607 }
Chris@13 608
Chris@28 609 if (m_good.getState() == Hypothesis::Expired) {
Chris@30 610 addFeaturesFrom(m_good, fs);
Chris@12 611 }
Chris@12 612
Chris@28 613 if (m_good.getState() == Hypothesis::Expired ||
Chris@28 614 m_good.getState() == Hypothesis::Rejected) {
Chris@11 615 if (candidate >= 0) {
Chris@28 616 m_good = m_possible[candidate];
Chris@11 617 } else {
Chris@28 618 m_good = Hypothesis();
Chris@11 619 }
Chris@11 620 }
Chris@8 621
Chris@14 622 // reap rejected/expired hypotheses from possible list
Chris@14 623 Hypotheses toReap = m_possible;
Chris@14 624 m_possible.clear();
Chris@14 625 for (int i = 0; i < toReap.size(); ++i) {
Chris@14 626 Hypothesis h = toReap[i];
Chris@14 627 if (h.getState() != Hypothesis::Rejected &&
Chris@14 628 h.getState() != Hypothesis::Expired) {
Chris@14 629 m_possible.push_back(h);
Chris@14 630 }
Chris@14 631 }
Chris@14 632 }
Chris@14 633
Chris@3 634 delete[] data;
Chris@3 635 return fs;
Chris@3 636 }
Chris@3 637
Chris@31 638 CepstralPitchTracker::FeatureSet
Chris@31 639 CepstralPitchTracker::getRemainingFeatures()
Chris@3 640 {
Chris@3 641 FeatureSet fs;
Chris@28 642 if (m_good.getState() == Hypothesis::Satisfied) {
Chris@30 643 addFeaturesFrom(m_good, fs);
Chris@11 644 }
Chris@3 645 return fs;
Chris@3 646 }