To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / test / TestNoteHypothesis.cpp @ 45:8db4a1f096f0

History | View | Annotate | Download (11.9 KB)

1
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
/*
3
    This file is Copyright (c) 2012 Chris Cannam
4
  
5
    Permission is hereby granted, free of charge, to any person
6
    obtaining a copy of this software and associated documentation
7
    files (the "Software"), to deal in the Software without
8
    restriction, including without limitation the rights to use, copy,
9
    modify, merge, publish, distribute, sublicense, and/or sell copies
10
    of the Software, and to permit persons to whom the Software is
11
    furnished to do so, subject to the following conditions:
12

13
    The above copyright notice and this permission notice shall be
14
    included in all copies or substantial portions of the Software.
15

16
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
20
    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
21
    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
*/
24

    
25
#include "NoteHypothesis.h"
26

    
27
std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Estimate &n)
28
{
29
    return out << "[" << n.freq << "@" << n.time << ":" << n.confidence << "]" << std::endl;
30
}
31

    
32
std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Estimates &e)
33
{
34
    out << "( ";
35
    for (int i = 0; i < (int)e.size(); ++i) out << e[i] << "; ";
36
    out << " )";
37
    return out;
38
}
39

    
40
std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Note &n)
41
{
42
    return out << "[" << n.freq << "@" << n.time << ":" << n.duration << "]" << std::endl;
43
}
44

    
45
#define BOOST_TEST_DYN_LINK
46
#define BOOST_TEST_MAIN
47

    
48
#include <boost/test/unit_test.hpp>
49

    
50
using Vamp::RealTime;
51

    
52
BOOST_AUTO_TEST_SUITE(TestNoteHypothesis)
53

    
54
BOOST_AUTO_TEST_CASE(emptyAccept)
55
{
56
    // An empty hypothesis should accept any estimate and enter
57
    // provisional state
58
    NoteHypothesis h;
59
    NoteHypothesis::Estimate e;
60
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
61
    BOOST_CHECK(h.accept(e));
62
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
63
}
64
                
65
BOOST_AUTO_TEST_CASE(tooSlow)
66
{
67
    // Having accepted a first estimate, a hypothesis should reject a
68
    // second (and enter rejected state) if there is too long a gap
69
    // between them for them to belong to a single note
70
    NoteHypothesis h;
71
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
72
    NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(50), 1);
73
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
74
    BOOST_CHECK(h.accept(e1));
75
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
76
    BOOST_CHECK(!h.accept(e2));
77
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Rejected);
78
}
79

    
80
BOOST_AUTO_TEST_CASE(simpleSatisfy)
81
{
82
    // A hypothesis should enter satisfied state after accepting three
83
    // consistent estimates, and then remain satisfied while accepting
84
    // further consistent estimates
85
    NoteHypothesis h;
86
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
87
    NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
88
    NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
89
    NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
90
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
91
    BOOST_CHECK(h.accept(e1));
92
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
93
    BOOST_CHECK(h.accept(e2));
94
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
95
    BOOST_CHECK(h.accept(e3));
96
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
97
    BOOST_CHECK(h.accept(e4));
98
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
99
}
100

    
101
BOOST_AUTO_TEST_CASE(expiry)
102
{
103
    // A hypothesis that has been satisfied, but that is subsequently
104
    // offered an estimate that follows too long a gap, should enter
105
    // expired state rather than rejected state (showing that it has a
106
    // valid note but that the note has apparently finished)
107
    NoteHypothesis h;
108
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
109
    NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
110
    NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
111
    NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
112
    NoteHypothesis::Estimate e5(500, RealTime::fromMilliseconds(80), 1);
113
    NoteHypothesis::Estimate e6(500, RealTime::fromMilliseconds(90), 1);
114
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
115
    BOOST_CHECK(h.accept(e1));
116
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
117
    BOOST_CHECK(h.accept(e2));
118
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
119
    BOOST_CHECK(h.accept(e3));
120
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
121
    BOOST_CHECK(h.accept(e4));
122
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
123
    BOOST_CHECK(!h.accept(e5));
124
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
125
    BOOST_CHECK(!h.accept(e6));
126
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
127
}
128
        
129
BOOST_AUTO_TEST_CASE(strayReject1)
130
{
131
    // A wildly different frequency occurring in the middle of a
132
    // provisionally accepted note should be ignored
133
    NoteHypothesis h;
134
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
135
    NoteHypothesis::Estimate e2(1000, RealTime::fromMilliseconds(10), 1);
136
    NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
137
    NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
138
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
139
    BOOST_CHECK(h.accept(e1));
140
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
141
    BOOST_CHECK(!h.accept(e2));
142
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
143
    BOOST_CHECK(h.accept(e3));
144
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
145
    BOOST_CHECK(h.accept(e4));
146
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
147
}
148

    
149
BOOST_AUTO_TEST_CASE(strayReject2)
150
{
151
    // A wildly different frequency occurring in the middle of a
152
    // satisfied note should be ignored
153
    NoteHypothesis h;
154
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
155
    NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
156
    NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
157
    NoteHypothesis::Estimate e4(1000, RealTime::fromMilliseconds(30), 1);
158
    NoteHypothesis::Estimate e5(500, RealTime::fromMilliseconds(40), 1);
159
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
160
    BOOST_CHECK(h.accept(e1));
161
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
162
    BOOST_CHECK(h.accept(e2));
163
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
164
    BOOST_CHECK(h.accept(e3));
165
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
166
    BOOST_CHECK(!h.accept(e4));
167
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
168
    BOOST_CHECK(h.accept(e5));
169
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
170
}
171
        
172
BOOST_AUTO_TEST_CASE(weakSatisfy)
173
{
174
    // Behaviour with slightly varying frequencies should be as for
175
    // that with fixed frequency
176
    NoteHypothesis h;
177
    NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 0.5);
178
    NoteHypothesis::Estimate e2(502, RealTime::fromMilliseconds(10), 0.5);
179
    NoteHypothesis::Estimate e3(504, RealTime::fromMilliseconds(20), 0.5);
180
    NoteHypothesis::Estimate e4(506, RealTime::fromMilliseconds(30), 0.5);
181
    NoteHypothesis::Estimate e5(508, RealTime::fromMilliseconds(40), 0.5);
182
    NoteHypothesis::Estimate e6(510, RealTime::fromMilliseconds(90), 0.5);
183
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
184
    BOOST_CHECK(h.accept(e1));
185
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
186
    BOOST_CHECK(h.accept(e2));
187
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
188
    BOOST_CHECK(h.accept(e3));
189
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
190
    BOOST_CHECK(h.accept(e4));
191
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
192
    BOOST_CHECK(h.accept(e5));
193
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
194
    BOOST_CHECK(!h.accept(e6));
195
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
196
}
197
        
198
BOOST_AUTO_TEST_CASE(frequencyRange)
199
{
200
    // But there's a limit: outside a certain range we should reject
201
    //!!! (but what is this range? is it part of the spec?)
202
    NoteHypothesis h;
203
    NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
204
    NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
205
    NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
206
    NoteHypothesis::Estimate e4(470, RealTime::fromMilliseconds(30), 1);
207
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
208
    BOOST_CHECK(h.accept(e1));
209
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
210
    BOOST_CHECK(h.accept(e2));
211
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
212
    BOOST_CHECK(h.accept(e3));
213
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
214
    BOOST_CHECK(!h.accept(e4));
215
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
216
}
217

    
218
BOOST_AUTO_TEST_CASE(acceptedEstimates)
219
{
220
    // Check that getAcceptedEstimates() returns the right result
221
    NoteHypothesis h;
222
    NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
223
    NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
224
    NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
225
    NoteHypothesis::Estimate e4(470, RealTime::fromMilliseconds(30), 1);
226
    NoteHypothesis::Estimate e5(444, RealTime::fromMilliseconds(90), 1);
227
    NoteHypothesis::Estimates es;
228
    es.push_back(e1);
229
    es.push_back(e2);
230
    es.push_back(e3);
231
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
232
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
233
    BOOST_CHECK(h.accept(e1));
234
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
235
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
236
    BOOST_CHECK(h.accept(e2));
237
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
238
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
239
    BOOST_CHECK(h.accept(e3));
240
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
241
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
242
    BOOST_CHECK(!h.accept(e4));
243
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
244
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
245
    BOOST_CHECK(!h.accept(e5));
246
    BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
247
    BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
248
}
249
        
250
BOOST_AUTO_TEST_CASE(meanFrequency)
251
{
252
    // Check that the mean frequency is the mean of the frequencies
253
    NoteHypothesis h;
254
    NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
255
    NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
256
    NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
257
    BOOST_CHECK(h.accept(e1));
258
    BOOST_CHECK(h.accept(e2));
259
    BOOST_CHECK(h.accept(e3));
260
    BOOST_CHECK_EQUAL(h.getMeanFrequency(), 444.0);
261
}
262

    
263
BOOST_AUTO_TEST_CASE(averagedNote)
264
{
265
    // Check that getAveragedNote returns something sane
266
    NoteHypothesis h;
267
    NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(10), 1);
268
    NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(20), 1);
269
    NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(30), 1);
270
    BOOST_CHECK(h.accept(e1));
271
    BOOST_CHECK(h.accept(e2));
272
    BOOST_CHECK(h.accept(e3));
273
    BOOST_CHECK_EQUAL(h.getAveragedNote(), NoteHypothesis::Note
274
                      (444,
275
                       RealTime::fromMilliseconds(10),
276
                       RealTime::fromMilliseconds(20)));
277
}
278

    
279
//!!! Not yet tested: Confidence scores
280

    
281
BOOST_AUTO_TEST_SUITE_END()
282