annotate test/TestNoteHypothesis.cpp @ 75:84d1a0647ce5 tip

Split out COPYING from README
author Chris Cannam
date Fri, 06 Mar 2020 11:01:53 +0000
parents c06fe5350b34
children 7ad142c710c6
rev   line source
Chris@33 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@33 24
Chris@38 25 #include "NoteHypothesis.h"
Chris@33 26
Chris@38 27 std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Estimate &n)
Chris@33 28 {
Chris@38 29 return out << "[" << n.freq << "@" << n.time << ":" << n.confidence << "]" << std::endl;
Chris@33 30 }
Chris@33 31
Chris@38 32 std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Estimates &e)
Chris@38 33 {
Chris@38 34 out << "( ";
Chris@38 35 for (int i = 0; i < (int)e.size(); ++i) out << e[i] << "; ";
Chris@38 36 out << " )";
Chris@38 37 return out;
Chris@38 38 }
Chris@38 39
Chris@38 40 std::ostream &operator<<(std::ostream &out, const NoteHypothesis::Note &n)
Chris@38 41 {
Chris@38 42 return out << "[" << n.freq << "@" << n.time << ":" << n.duration << "]" << std::endl;
Chris@38 43 }
Chris@38 44
Chris@38 45 #define BOOST_TEST_DYN_LINK
Chris@38 46 #define BOOST_TEST_MAIN
Chris@38 47
Chris@38 48 #include <boost/test/unit_test.hpp>
Chris@38 49
Chris@38 50 using Vamp::RealTime;
Chris@38 51
Chris@38 52 BOOST_AUTO_TEST_SUITE(TestNoteHypothesis)
Chris@38 53
Chris@38 54 BOOST_AUTO_TEST_CASE(emptyAccept)
Chris@38 55 {
Chris@58 56 // An empty hypothesis should accept any estimate with a
Chris@58 57 // non-negligible confidence, and enter provisional state
Chris@38 58 NoteHypothesis h;
Chris@58 59 NoteHypothesis::Estimate e; // default estimate has confidence 1
Chris@38 60 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 61 BOOST_CHECK(h.accept(e));
Chris@38 62 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 63 }
Chris@58 64
Chris@58 65 BOOST_AUTO_TEST_CASE(noConfidence)
Chris@58 66 {
Chris@58 67 // A hypothesis should reject any estimate that has a negligible
Chris@58 68 // confidence
Chris@58 69 NoteHypothesis h;
Chris@58 70 NoteHypothesis::Estimate e;
Chris@58 71 e.confidence = 0;
Chris@58 72 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@58 73 BOOST_CHECK(!h.accept(e));
Chris@58 74 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Rejected);
Chris@58 75 }
Chris@60 76
Chris@60 77 BOOST_AUTO_TEST_CASE(noConfidenceIgnore)
Chris@60 78 {
Chris@60 79 // But if we're already in process we don't go to rejected state,
Chris@60 80 // we just ignore this hypothesis
Chris@60 81 NoteHypothesis h;
Chris@60 82 NoteHypothesis::Estimate e;
Chris@60 83 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@60 84 BOOST_CHECK(h.accept(e));
Chris@60 85 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@60 86 e.confidence = 0;
Chris@60 87 BOOST_CHECK(!h.accept(e));
Chris@60 88 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@60 89 }
Chris@45 90
Chris@45 91 BOOST_AUTO_TEST_CASE(tooSlow)
Chris@45 92 {
Chris@45 93 // Having accepted a first estimate, a hypothesis should reject a
Chris@45 94 // second (and enter rejected state) if there is too long a gap
Chris@45 95 // between them for them to belong to a single note
Chris@45 96 NoteHypothesis h;
Chris@45 97 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
Chris@45 98 NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(50), 1);
Chris@45 99 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@45 100 BOOST_CHECK(h.accept(e1));
Chris@45 101 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@45 102 BOOST_CHECK(!h.accept(e2));
Chris@45 103 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Rejected);
Chris@45 104 }
Chris@38 105
Chris@38 106 BOOST_AUTO_TEST_CASE(simpleSatisfy)
Chris@38 107 {
Chris@45 108 // A hypothesis should enter satisfied state after accepting three
Chris@45 109 // consistent estimates, and then remain satisfied while accepting
Chris@45 110 // further consistent estimates
Chris@45 111 NoteHypothesis h;
Chris@45 112 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
Chris@45 113 NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
Chris@45 114 NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
Chris@45 115 NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
Chris@45 116 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@45 117 BOOST_CHECK(h.accept(e1));
Chris@45 118 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@45 119 BOOST_CHECK(h.accept(e2));
Chris@45 120 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@45 121 BOOST_CHECK(h.accept(e3));
Chris@45 122 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@45 123 BOOST_CHECK(h.accept(e4));
Chris@45 124 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@45 125 }
Chris@45 126
Chris@45 127 BOOST_AUTO_TEST_CASE(expiry)
Chris@45 128 {
Chris@45 129 // A hypothesis that has been satisfied, but that is subsequently
Chris@45 130 // offered an estimate that follows too long a gap, should enter
Chris@45 131 // expired state rather than rejected state (showing that it has a
Chris@45 132 // valid note but that the note has apparently finished)
Chris@38 133 NoteHypothesis h;
Chris@38 134 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
Chris@38 135 NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
Chris@38 136 NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
Chris@38 137 NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
Chris@38 138 NoteHypothesis::Estimate e5(500, RealTime::fromMilliseconds(80), 1);
Chris@38 139 NoteHypothesis::Estimate e6(500, RealTime::fromMilliseconds(90), 1);
Chris@38 140 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 141 BOOST_CHECK(h.accept(e1));
Chris@38 142 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 143 BOOST_CHECK(h.accept(e2));
Chris@38 144 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 145 BOOST_CHECK(h.accept(e3));
Chris@38 146 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 147 BOOST_CHECK(h.accept(e4));
Chris@38 148 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 149 BOOST_CHECK(!h.accept(e5));
Chris@38 150 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
Chris@38 151 BOOST_CHECK(!h.accept(e6));
Chris@38 152 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
Chris@38 153 }
Chris@38 154
Chris@45 155 BOOST_AUTO_TEST_CASE(strayReject1)
Chris@38 156 {
Chris@45 157 // A wildly different frequency occurring in the middle of a
Chris@45 158 // provisionally accepted note should be ignored
Chris@38 159 NoteHypothesis h;
Chris@38 160 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
Chris@38 161 NoteHypothesis::Estimate e2(1000, RealTime::fromMilliseconds(10), 1);
Chris@38 162 NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
Chris@38 163 NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1);
Chris@38 164 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 165 BOOST_CHECK(h.accept(e1));
Chris@38 166 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 167 BOOST_CHECK(!h.accept(e2));
Chris@38 168 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 169 BOOST_CHECK(h.accept(e3));
Chris@38 170 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 171 BOOST_CHECK(h.accept(e4));
Chris@38 172 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 173 }
Chris@45 174
Chris@45 175 BOOST_AUTO_TEST_CASE(strayReject2)
Chris@38 176 {
Chris@45 177 // A wildly different frequency occurring in the middle of a
Chris@45 178 // satisfied note should be ignored
Chris@38 179 NoteHypothesis h;
Chris@38 180 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1);
Chris@45 181 NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1);
Chris@45 182 NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1);
Chris@45 183 NoteHypothesis::Estimate e4(1000, RealTime::fromMilliseconds(30), 1);
Chris@45 184 NoteHypothesis::Estimate e5(500, RealTime::fromMilliseconds(40), 1);
Chris@38 185 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 186 BOOST_CHECK(h.accept(e1));
Chris@38 187 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@45 188 BOOST_CHECK(h.accept(e2));
Chris@45 189 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@45 190 BOOST_CHECK(h.accept(e3));
Chris@45 191 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@45 192 BOOST_CHECK(!h.accept(e4));
Chris@45 193 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@45 194 BOOST_CHECK(h.accept(e5));
Chris@45 195 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 196 }
Chris@38 197
Chris@38 198 BOOST_AUTO_TEST_CASE(weakSatisfy)
Chris@38 199 {
Chris@45 200 // Behaviour with slightly varying frequencies should be as for
Chris@45 201 // that with fixed frequency
Chris@38 202 NoteHypothesis h;
Chris@38 203 NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 0.5);
Chris@38 204 NoteHypothesis::Estimate e2(502, RealTime::fromMilliseconds(10), 0.5);
Chris@38 205 NoteHypothesis::Estimate e3(504, RealTime::fromMilliseconds(20), 0.5);
Chris@38 206 NoteHypothesis::Estimate e4(506, RealTime::fromMilliseconds(30), 0.5);
Chris@38 207 NoteHypothesis::Estimate e5(508, RealTime::fromMilliseconds(40), 0.5);
Chris@38 208 NoteHypothesis::Estimate e6(510, RealTime::fromMilliseconds(90), 0.5);
Chris@38 209 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 210 BOOST_CHECK(h.accept(e1));
Chris@38 211 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 212 BOOST_CHECK(h.accept(e2));
Chris@38 213 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 214 BOOST_CHECK(h.accept(e3));
Chris@38 215 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 216 BOOST_CHECK(h.accept(e4));
Chris@38 217 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 218 BOOST_CHECK(h.accept(e5));
Chris@38 219 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 220 BOOST_CHECK(!h.accept(e6));
Chris@38 221 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
Chris@38 222 }
Chris@38 223
Chris@38 224 BOOST_AUTO_TEST_CASE(frequencyRange)
Chris@38 225 {
Chris@45 226 // But there's a limit: outside a certain range we should reject
Chris@45 227 //!!! (but what is this range? is it part of the spec?)
Chris@38 228 NoteHypothesis h;
Chris@38 229 NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
Chris@38 230 NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
Chris@38 231 NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
Chris@38 232 NoteHypothesis::Estimate e4(470, RealTime::fromMilliseconds(30), 1);
Chris@38 233 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 234 BOOST_CHECK(h.accept(e1));
Chris@38 235 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 236 BOOST_CHECK(h.accept(e2));
Chris@38 237 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 238 BOOST_CHECK(h.accept(e3));
Chris@38 239 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 240 BOOST_CHECK(!h.accept(e4));
Chris@38 241 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 242 }
Chris@38 243
Chris@38 244 BOOST_AUTO_TEST_CASE(acceptedEstimates)
Chris@38 245 {
Chris@45 246 // Check that getAcceptedEstimates() returns the right result
Chris@38 247 NoteHypothesis h;
Chris@38 248 NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
Chris@38 249 NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
Chris@38 250 NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
Chris@38 251 NoteHypothesis::Estimate e4(470, RealTime::fromMilliseconds(30), 1);
Chris@38 252 NoteHypothesis::Estimate e5(444, RealTime::fromMilliseconds(90), 1);
Chris@38 253 NoteHypothesis::Estimates es;
Chris@38 254 es.push_back(e1);
Chris@38 255 es.push_back(e2);
Chris@38 256 es.push_back(e3);
Chris@38 257 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New);
Chris@38 258 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
Chris@38 259 BOOST_CHECK(h.accept(e1));
Chris@38 260 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 261 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
Chris@38 262 BOOST_CHECK(h.accept(e2));
Chris@38 263 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional);
Chris@38 264 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), NoteHypothesis::Estimates());
Chris@38 265 BOOST_CHECK(h.accept(e3));
Chris@38 266 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 267 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
Chris@38 268 BOOST_CHECK(!h.accept(e4));
Chris@38 269 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied);
Chris@38 270 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
Chris@38 271 BOOST_CHECK(!h.accept(e5));
Chris@38 272 BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired);
Chris@38 273 BOOST_CHECK_EQUAL(h.getAcceptedEstimates(), es);
Chris@38 274 }
Chris@38 275
Chris@38 276 BOOST_AUTO_TEST_CASE(meanFrequency)
Chris@38 277 {
Chris@45 278 // Check that the mean frequency is the mean of the frequencies
Chris@38 279 NoteHypothesis h;
Chris@38 280 NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1);
Chris@38 281 NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1);
Chris@38 282 NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(20), 1);
Chris@38 283 BOOST_CHECK(h.accept(e1));
Chris@38 284 BOOST_CHECK(h.accept(e2));
Chris@38 285 BOOST_CHECK(h.accept(e3));
Chris@38 286 BOOST_CHECK_EQUAL(h.getMeanFrequency(), 444.0);
Chris@38 287 }
Chris@38 288
Chris@38 289 BOOST_AUTO_TEST_CASE(averagedNote)
Chris@38 290 {
Chris@45 291 // Check that getAveragedNote returns something sane
Chris@38 292 NoteHypothesis h;
Chris@38 293 NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(10), 1);
Chris@38 294 NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(20), 1);
Chris@38 295 NoteHypothesis::Estimate e3(444, RealTime::fromMilliseconds(30), 1);
Chris@38 296 BOOST_CHECK(h.accept(e1));
Chris@38 297 BOOST_CHECK(h.accept(e2));
Chris@38 298 BOOST_CHECK(h.accept(e3));
Chris@38 299 BOOST_CHECK_EQUAL(h.getAveragedNote(), NoteHypothesis::Note
Chris@38 300 (444,
Chris@38 301 RealTime::fromMilliseconds(10),
Chris@38 302 RealTime::fromMilliseconds(20)));
Chris@38 303 }
Chris@38 304
Chris@45 305 //!!! Not yet tested: Confidence scores
Chris@45 306
Chris@38 307 BOOST_AUTO_TEST_SUITE_END()
Chris@38 308