Mercurial > hg > cepstral-pitchtracker
changeset 45:8db4a1f096f0
Comments
author | Chris Cannam |
---|---|
date | Tue, 14 Aug 2012 16:48:19 +0100 |
parents | c5cd88de5809 |
children | c666067fb8da |
files | NoteHypothesis.h test/TestNoteHypothesis.cpp |
diffstat | 2 files changed, 85 insertions(+), 21 deletions(-) [+] |
line wrap: on
line diff
--- a/NoteHypothesis.h Fri Jul 20 22:12:29 2012 +0100 +++ b/NoteHypothesis.h Tue Aug 14 16:48:19 2012 +0100 @@ -40,20 +40,20 @@ public: enum State { - /// Just constructed, will provisionally accept any estimate - New, + /// Just constructed, will provisionally accept any estimate + New, - /// Accepted at least one estimate, but not enough evidence to satisfy - Provisional, + /// Accepted at least one estimate, but not enough evidence to satisfy + Provisional, - /// Could not find enough consistency in offered estimates - Rejected, + /// Could not find enough consistency in offered estimates + Rejected, - /// Have accepted enough consistent estimates to satisfy hypothesis - Satisfied, + /// Have accepted enough consistent estimates to satisfy hypothesis + Satisfied, - /// Have been satisfied, but evidence has now changed: we're done - Expired + /// Have been satisfied, but evidence has now changed: we're done + Expired }; /** @@ -74,9 +74,9 @@ bool operator==(const Estimate &e) const { return e.freq == freq && e.time == time && e.confidence == confidence; } - double freq; + double freq; Vamp::RealTime time; - double confidence; + double confidence; }; typedef std::vector<Estimate> Estimates; @@ -107,9 +107,9 @@ bool operator==(const Note &e) const { return e.freq == freq && e.time == time && e.duration == duration; } - double freq; - Vamp::RealTime time; - Vamp::RealTime duration; + double freq; + Vamp::RealTime time; + Vamp::RealTime duration; }; /**
--- a/test/TestNoteHypothesis.cpp Fri Jul 20 22:12:29 2012 +0100 +++ b/test/TestNoteHypothesis.cpp Tue Aug 14 16:48:19 2012 +0100 @@ -53,15 +53,57 @@ BOOST_AUTO_TEST_CASE(emptyAccept) { + // An empty hypothesis should accept any estimate and enter + // provisional state NoteHypothesis h; NoteHypothesis::Estimate e; BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New); BOOST_CHECK(h.accept(e)); BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); } + +BOOST_AUTO_TEST_CASE(tooSlow) +{ + // Having accepted a first estimate, a hypothesis should reject a + // second (and enter rejected state) if there is too long a gap + // between them for them to belong to a single note + NoteHypothesis h; + NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1); + NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(50), 1); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New); + BOOST_CHECK(h.accept(e1)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); + BOOST_CHECK(!h.accept(e2)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Rejected); +} BOOST_AUTO_TEST_CASE(simpleSatisfy) { + // A hypothesis should enter satisfied state after accepting three + // consistent estimates, and then remain satisfied while accepting + // further consistent estimates + NoteHypothesis h; + NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1); + NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1); + NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1); + NoteHypothesis::Estimate e4(500, RealTime::fromMilliseconds(30), 1); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New); + BOOST_CHECK(h.accept(e1)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); + BOOST_CHECK(h.accept(e2)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); + BOOST_CHECK(h.accept(e3)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); + BOOST_CHECK(h.accept(e4)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); +} + +BOOST_AUTO_TEST_CASE(expiry) +{ + // A hypothesis that has been satisfied, but that is subsequently + // offered an estimate that follows too long a gap, should enter + // expired state rather than rejected state (showing that it has a + // valid note but that the note has apparently finished) NoteHypothesis h; NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1); NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1); @@ -84,8 +126,10 @@ BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Expired); } -BOOST_AUTO_TEST_CASE(strayReject) +BOOST_AUTO_TEST_CASE(strayReject1) { + // A wildly different frequency occurring in the middle of a + // provisionally accepted note should be ignored NoteHypothesis h; NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1); NoteHypothesis::Estimate e2(1000, RealTime::fromMilliseconds(10), 1); @@ -101,21 +145,34 @@ BOOST_CHECK(h.accept(e4)); BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); } - -BOOST_AUTO_TEST_CASE(tooSlow) + +BOOST_AUTO_TEST_CASE(strayReject2) { + // A wildly different frequency occurring in the middle of a + // satisfied note should be ignored NoteHypothesis h; NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 1); - NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(50), 1); + NoteHypothesis::Estimate e2(500, RealTime::fromMilliseconds(10), 1); + NoteHypothesis::Estimate e3(500, RealTime::fromMilliseconds(20), 1); + NoteHypothesis::Estimate e4(1000, RealTime::fromMilliseconds(30), 1); + NoteHypothesis::Estimate e5(500, RealTime::fromMilliseconds(40), 1); BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::New); BOOST_CHECK(h.accept(e1)); BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); - BOOST_CHECK(!h.accept(e2)); - BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Rejected); + BOOST_CHECK(h.accept(e2)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Provisional); + BOOST_CHECK(h.accept(e3)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); + BOOST_CHECK(!h.accept(e4)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); + BOOST_CHECK(h.accept(e5)); + BOOST_CHECK_EQUAL(h.getState(), NoteHypothesis::Satisfied); } BOOST_AUTO_TEST_CASE(weakSatisfy) { + // Behaviour with slightly varying frequencies should be as for + // that with fixed frequency NoteHypothesis h; NoteHypothesis::Estimate e1(500, RealTime::fromMilliseconds(0), 0.5); NoteHypothesis::Estimate e2(502, RealTime::fromMilliseconds(10), 0.5); @@ -140,6 +197,8 @@ BOOST_AUTO_TEST_CASE(frequencyRange) { + // But there's a limit: outside a certain range we should reject + //!!! (but what is this range? is it part of the spec?) NoteHypothesis h; NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1); NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1); @@ -158,6 +217,7 @@ BOOST_AUTO_TEST_CASE(acceptedEstimates) { + // Check that getAcceptedEstimates() returns the right result NoteHypothesis h; NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1); NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1); @@ -189,6 +249,7 @@ BOOST_AUTO_TEST_CASE(meanFrequency) { + // Check that the mean frequency is the mean of the frequencies NoteHypothesis h; NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(0), 1); NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(10), 1); @@ -201,6 +262,7 @@ BOOST_AUTO_TEST_CASE(averagedNote) { + // Check that getAveragedNote returns something sane NoteHypothesis h; NoteHypothesis::Estimate e1(440, RealTime::fromMilliseconds(10), 1); NoteHypothesis::Estimate e2(448, RealTime::fromMilliseconds(20), 1); @@ -214,5 +276,7 @@ RealTime::fromMilliseconds(20))); } +//!!! Not yet tested: Confidence scores + BOOST_AUTO_TEST_SUITE_END()