annotate CepstrumPitchTracker.cpp @ 28:7927e7afbe07

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