annotate NoteHypothesis.cpp @ 37:7bf67d2dfc30

Copyrights
author Chris Cannam
date Thu, 19 Jul 2012 13:48:03 +0100
parents 2f5b169e4a3b
children 34f42a384a7f
rev   line source
Chris@32 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@37 2 /*
Chris@37 3 This file is Copyright (c) 2012 Chris Cannam
Chris@37 4
Chris@37 5 Permission is hereby granted, free of charge, to any person
Chris@37 6 obtaining a copy of this software and associated documentation
Chris@37 7 files (the "Software"), to deal in the Software without
Chris@37 8 restriction, including without limitation the rights to use, copy,
Chris@37 9 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@37 10 of the Software, and to permit persons to whom the Software is
Chris@37 11 furnished to do so, subject to the following conditions:
Chris@37 12
Chris@37 13 The above copyright notice and this permission notice shall be
Chris@37 14 included in all copies or substantial portions of the Software.
Chris@37 15
Chris@37 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@37 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@37 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@37 19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
Chris@37 20 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@37 21 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@37 22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@37 23 */
Chris@32 24
Chris@32 25 #include "NoteHypothesis.h"
Chris@32 26
Chris@32 27 #include <cmath>
Chris@32 28
Chris@35 29 using Vamp::RealTime;
Chris@32 30
Chris@32 31 NoteHypothesis::NoteHypothesis()
Chris@32 32 {
Chris@32 33 m_state = New;
Chris@32 34 }
Chris@32 35
Chris@32 36 NoteHypothesis::~NoteHypothesis()
Chris@32 37 {
Chris@32 38 }
Chris@32 39
Chris@32 40 bool
Chris@32 41 NoteHypothesis::isWithinTolerance(Estimate s) const
Chris@32 42 {
Chris@32 43 if (m_pending.empty()) {
Chris@32 44 return true;
Chris@32 45 }
Chris@32 46
Chris@32 47 // check we are within a relatively close tolerance of the last
Chris@32 48 // candidate
Chris@32 49 Estimate last = m_pending[m_pending.size()-1];
Chris@32 50 double r = s.freq / last.freq;
Chris@32 51 int cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@32 52 if (cents < -60 || cents > 60) return false;
Chris@32 53
Chris@32 54 // and within a slightly bigger tolerance of the current mean
Chris@32 55 double meanFreq = getMeanFrequency();
Chris@32 56 r = s.freq / meanFreq;
Chris@32 57 cents = lrint(1200.0 * (log(r) / log(2.0)));
Chris@32 58 if (cents < -80 || cents > 80) return false;
Chris@32 59
Chris@32 60 return true;
Chris@32 61 }
Chris@32 62
Chris@32 63 bool
Chris@32 64 NoteHypothesis::isOutOfDateFor(Estimate s) const
Chris@32 65 {
Chris@32 66 if (m_pending.empty()) return false;
Chris@32 67
Chris@32 68 return ((s.time - m_pending[m_pending.size()-1].time) >
Chris@32 69 RealTime::fromMilliseconds(40));
Chris@32 70 }
Chris@32 71
Chris@32 72 bool
Chris@32 73 NoteHypothesis::isSatisfied() const
Chris@32 74 {
Chris@32 75 if (m_pending.empty()) return false;
Chris@32 76
Chris@32 77 double meanConfidence = 0.0;
Chris@32 78 for (int i = 0; i < (int)m_pending.size(); ++i) {
Chris@32 79 meanConfidence += m_pending[i].confidence;
Chris@32 80 }
Chris@32 81 meanConfidence /= m_pending.size();
Chris@32 82
Chris@32 83 int lengthRequired = 10000;
Chris@32 84 if (meanConfidence > 0.0) {
Chris@32 85 lengthRequired = int(2.0 / meanConfidence + 0.5);
Chris@32 86 }
Chris@32 87
Chris@32 88 return ((int)m_pending.size() > lengthRequired);
Chris@32 89 }
Chris@32 90
Chris@32 91 bool
Chris@32 92 NoteHypothesis::accept(Estimate s)
Chris@32 93 {
Chris@32 94 bool accept = false;
Chris@32 95
Chris@32 96 switch (m_state) {
Chris@32 97
Chris@32 98 case New:
Chris@32 99 m_state = Provisional;
Chris@32 100 accept = true;
Chris@32 101 break;
Chris@32 102
Chris@32 103 case Provisional:
Chris@32 104 if (isOutOfDateFor(s)) {
Chris@32 105 m_state = Rejected;
Chris@32 106 } else if (isWithinTolerance(s)) {
Chris@32 107 accept = true;
Chris@32 108 }
Chris@32 109 break;
Chris@32 110
Chris@32 111 case Satisfied:
Chris@32 112 if (isOutOfDateFor(s)) {
Chris@32 113 m_state = Expired;
Chris@32 114 } else if (isWithinTolerance(s)) {
Chris@32 115 accept = true;
Chris@32 116 }
Chris@32 117 break;
Chris@32 118
Chris@32 119 case Rejected:
Chris@32 120 break;
Chris@32 121
Chris@32 122 case Expired:
Chris@32 123 break;
Chris@32 124 }
Chris@32 125
Chris@32 126 if (accept) {
Chris@32 127 m_pending.push_back(s);
Chris@32 128 if (m_state == Provisional && isSatisfied()) {
Chris@32 129 m_state = Satisfied;
Chris@32 130 }
Chris@32 131 }
Chris@32 132
Chris@32 133 return accept;
Chris@32 134 }
Chris@32 135
Chris@32 136 NoteHypothesis::State
Chris@32 137 NoteHypothesis::getState() const
Chris@32 138 {
Chris@32 139 return m_state;
Chris@32 140 }
Chris@32 141
Chris@32 142 NoteHypothesis::Estimates
Chris@32 143 NoteHypothesis::getAcceptedEstimates() const
Chris@32 144 {
Chris@32 145 if (m_state == Satisfied || m_state == Expired) {
Chris@32 146 return m_pending;
Chris@32 147 } else {
Chris@32 148 return Estimates();
Chris@32 149 }
Chris@32 150 }
Chris@32 151
Chris@32 152 double
Chris@32 153 NoteHypothesis::getMeanFrequency() const
Chris@32 154 {
Chris@32 155 double acc = 0.0;
Chris@34 156 if (m_pending.empty()) return acc;
Chris@32 157 for (int i = 0; i < (int)m_pending.size(); ++i) {
Chris@32 158 acc += m_pending[i].freq;
Chris@32 159 }
Chris@32 160 acc /= m_pending.size();
Chris@32 161 return acc;
Chris@32 162 }
Chris@32 163
Chris@32 164 NoteHypothesis::Note
Chris@32 165 NoteHypothesis::getAveragedNote() const
Chris@32 166 {
Chris@32 167 Note n;
Chris@32 168
Chris@32 169 if (!(m_state == Satisfied || m_state == Expired)) {
Chris@32 170 n.freq = 0.0;
Chris@32 171 n.time = RealTime::zeroTime;
Chris@32 172 n.duration = RealTime::zeroTime;
Chris@32 173 return n;
Chris@32 174 }
Chris@32 175
Chris@32 176 n.time = m_pending.begin()->time;
Chris@32 177
Chris@32 178 Estimates::const_iterator i = m_pending.end();
Chris@32 179 --i;
Chris@32 180 n.duration = i->time - n.time;
Chris@32 181
Chris@32 182 // just mean frequency for now, but this isn't at all right perceptually
Chris@32 183 n.freq = getMeanFrequency();
Chris@32 184
Chris@32 185 return n;
Chris@32 186 }
Chris@32 187