annotate CepstrumPitchTracker.cpp @ 26:13568f1ccff0

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