annotate NoteHypothesis.cpp @ 35:2f5b169e4a3b

Integrate NoteHypothesis class, build fixes
author Chris Cannam
date Thu, 19 Jul 2012 13:46:45 +0100
parents 3fb9c657d86b
children 7bf67d2dfc30
rev   line source
Chris@32 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@32 2 /* Copyright Chris Cannam - All Rights Reserved */
Chris@32 3
Chris@32 4 #include "NoteHypothesis.h"
Chris@32 5
Chris@32 6 #include <cmath>
Chris@32 7
Chris@35 8 using Vamp::RealTime;
Chris@32 9
Chris@32 10 NoteHypothesis::NoteHypothesis()
Chris@32 11 {
Chris@32 12 m_state = New;
Chris@32 13 }
Chris@32 14
Chris@32 15 NoteHypothesis::~NoteHypothesis()
Chris@32 16 {
Chris@32 17 }
Chris@32 18
Chris@32 19 bool
Chris@32 20 NoteHypothesis::isWithinTolerance(Estimate s) const
Chris@32 21 {
Chris@32 22 if (m_pending.empty()) {
Chris@32 23 return true;
Chris@32 24 }
Chris@32 25
Chris@32 26 // check we are within a relatively close tolerance of the last
Chris@32 27 // candidate
Chris@32 28 Estimate last = m_pending[m_pending.size()-1];
Chris@32 29 double r = s.freq / last.freq;
Chris@32 30 int cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@32 31 if (cents < -60 || cents > 60) return false;
Chris@32 32
Chris@32 33 // and within a slightly bigger tolerance of the current mean
Chris@32 34 double meanFreq = getMeanFrequency();
Chris@32 35 r = s.freq / meanFreq;
Chris@32 36 cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@32 37 if (cents < -80 || cents > 80) return false;
Chris@32 38
Chris@32 39 return true;
Chris@32 40 }
Chris@32 41
Chris@32 42 bool
Chris@32 43 NoteHypothesis::isOutOfDateFor(Estimate s) const
Chris@32 44 {
Chris@32 45 if (m_pending.empty()) return false;
Chris@32 46
Chris@32 47 return ((s.time - m_pending[m_pending.size()-1].time) >
Chris@32 48 RealTime::fromMilliseconds(40));
Chris@32 49 }
Chris@32 50
Chris@32 51 bool
Chris@32 52 NoteHypothesis::isSatisfied() const
Chris@32 53 {
Chris@32 54 if (m_pending.empty()) return false;
Chris@32 55
Chris@32 56 double meanConfidence = 0.0;
Chris@32 57 for (int i = 0; i < (int)m_pending.size(); ++i) {
Chris@32 58 meanConfidence += m_pending[i].confidence;
Chris@32 59 }
Chris@32 60 meanConfidence /= m_pending.size();
Chris@32 61
Chris@32 62 int lengthRequired = 10000;
Chris@32 63 if (meanConfidence > 0.0) {
Chris@32 64 lengthRequired = int(2.0 / meanConfidence + 0.5);
Chris@32 65 }
Chris@32 66
Chris@32 67 return ((int)m_pending.size() > lengthRequired);
Chris@32 68 }
Chris@32 69
Chris@32 70 bool
Chris@32 71 NoteHypothesis::accept(Estimate s)
Chris@32 72 {
Chris@32 73 bool accept = false;
Chris@32 74
Chris@32 75 switch (m_state) {
Chris@32 76
Chris@32 77 case New:
Chris@32 78 m_state = Provisional;
Chris@32 79 accept = true;
Chris@32 80 break;
Chris@32 81
Chris@32 82 case Provisional:
Chris@32 83 if (isOutOfDateFor(s)) {
Chris@32 84 m_state = Rejected;
Chris@32 85 } else if (isWithinTolerance(s)) {
Chris@32 86 accept = true;
Chris@32 87 }
Chris@32 88 break;
Chris@32 89
Chris@32 90 case Satisfied:
Chris@32 91 if (isOutOfDateFor(s)) {
Chris@32 92 m_state = Expired;
Chris@32 93 } else if (isWithinTolerance(s)) {
Chris@32 94 accept = true;
Chris@32 95 }
Chris@32 96 break;
Chris@32 97
Chris@32 98 case Rejected:
Chris@32 99 break;
Chris@32 100
Chris@32 101 case Expired:
Chris@32 102 break;
Chris@32 103 }
Chris@32 104
Chris@32 105 if (accept) {
Chris@32 106 m_pending.push_back(s);
Chris@32 107 if (m_state == Provisional && isSatisfied()) {
Chris@32 108 m_state = Satisfied;
Chris@32 109 }
Chris@32 110 }
Chris@32 111
Chris@32 112 return accept;
Chris@32 113 }
Chris@32 114
Chris@32 115 NoteHypothesis::State
Chris@32 116 NoteHypothesis::getState() const
Chris@32 117 {
Chris@32 118 return m_state;
Chris@32 119 }
Chris@32 120
Chris@32 121 NoteHypothesis::Estimates
Chris@32 122 NoteHypothesis::getAcceptedEstimates() const
Chris@32 123 {
Chris@32 124 if (m_state == Satisfied || m_state == Expired) {
Chris@32 125 return m_pending;
Chris@32 126 } else {
Chris@32 127 return Estimates();
Chris@32 128 }
Chris@32 129 }
Chris@32 130
Chris@32 131 double
Chris@32 132 NoteHypothesis::getMeanFrequency() const
Chris@32 133 {
Chris@32 134 double acc = 0.0;
Chris@34 135 if (m_pending.empty()) return acc;
Chris@32 136 for (int i = 0; i < (int)m_pending.size(); ++i) {
Chris@32 137 acc += m_pending[i].freq;
Chris@32 138 }
Chris@32 139 acc /= m_pending.size();
Chris@32 140 return acc;
Chris@32 141 }
Chris@32 142
Chris@32 143 NoteHypothesis::Note
Chris@32 144 NoteHypothesis::getAveragedNote() const
Chris@32 145 {
Chris@32 146 Note n;
Chris@32 147
Chris@32 148 if (!(m_state == Satisfied || m_state == Expired)) {
Chris@32 149 n.freq = 0.0;
Chris@32 150 n.time = RealTime::zeroTime;
Chris@32 151 n.duration = RealTime::zeroTime;
Chris@32 152 return n;
Chris@32 153 }
Chris@32 154
Chris@32 155 n.time = m_pending.begin()->time;
Chris@32 156
Chris@32 157 Estimates::const_iterator i = m_pending.end();
Chris@32 158 --i;
Chris@32 159 n.duration = i->time - n.time;
Chris@32 160
Chris@32 161 // just mean frequency for now, but this isn't at all right perceptually
Chris@32 162 n.freq = getMeanFrequency();
Chris@32 163
Chris@32 164 return n;
Chris@32 165 }
Chris@32 166