annotate NoteHypothesis.cpp @ 34:3fb9c657d86b

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