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