Chris@181
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@181
|
2
|
Chris@181
|
3 /*
|
Chris@181
|
4 Silvet
|
Chris@181
|
5
|
Chris@181
|
6 A Vamp plugin for note transcription.
|
Chris@181
|
7 Centre for Digital Music, Queen Mary University of London.
|
Chris@181
|
8 This file Copyright 2012 Chris Cannam.
|
Chris@181
|
9
|
Chris@181
|
10 This program is free software; you can redistribute it and/or
|
Chris@181
|
11 modify it under the terms of the GNU General Public License as
|
Chris@181
|
12 published by the Free Software Foundation; either version 2 of the
|
Chris@181
|
13 License, or (at your option) any later version. See the file
|
Chris@181
|
14 COPYING included with this distribution for more information.
|
Chris@181
|
15 */
|
Chris@181
|
16
|
Chris@181
|
17 #ifndef AGENT_HYPOTHESIS_H
|
Chris@181
|
18 #define AGENT_HYPOTHESIS_H
|
Chris@181
|
19
|
Chris@181
|
20 #include "vamp-sdk/RealTime.h"
|
Chris@181
|
21
|
Chris@181
|
22 #include <set>
|
Chris@181
|
23 #include <map>
|
Chris@181
|
24
|
Chris@181
|
25 /**
|
Chris@181
|
26 * An agent used to test an incoming series of timed observations or
|
Chris@181
|
27 * estimates to see whether they fit a consistent single-object
|
Chris@181
|
28 * relationship.
|
Chris@181
|
29 *
|
Chris@181
|
30 * A freshly constructed hypothesis object should be in New state and
|
Chris@181
|
31 * should accept any observation.
|
Chris@181
|
32 */
|
Chris@181
|
33
|
Chris@181
|
34 class AgentHypothesis
|
Chris@181
|
35 {
|
Chris@181
|
36 public:
|
Chris@181
|
37 virtual ~AgentHypothesis() { }
|
Chris@181
|
38
|
Chris@181
|
39 enum State {
|
Chris@181
|
40
|
Chris@181
|
41 /// Just constructed, will provisionally accept any observation
|
Chris@181
|
42 New,
|
Chris@181
|
43
|
Chris@181
|
44 /// Accepted at least one observation, but not enough evidence to satisfy
|
Chris@181
|
45 Provisional,
|
Chris@181
|
46
|
Chris@181
|
47 /// Could not find enough consistency in offered observations
|
Chris@181
|
48 Rejected,
|
Chris@181
|
49
|
Chris@181
|
50 /// Have accepted enough consistent observations to satisfy hypothesis
|
Chris@181
|
51 Satisfied,
|
Chris@181
|
52
|
Chris@181
|
53 /// Have been satisfied, but evidence has now changed: we're done
|
Chris@181
|
54 Expired
|
Chris@181
|
55 };
|
Chris@181
|
56
|
Chris@181
|
57 struct Observation {
|
Chris@181
|
58
|
Chris@181
|
59 Observation() : value(0), time(), confidence(1) { }
|
Chris@181
|
60
|
Chris@181
|
61 Observation(double _f, Vamp::RealTime _t, double _c) :
|
Chris@181
|
62 value(_f), time(_t), confidence(_c) { }
|
Chris@181
|
63
|
Chris@181
|
64 bool operator==(const Observation &o) const {
|
Chris@181
|
65 return o.value == value && o.time == time && o.confidence == confidence;
|
Chris@181
|
66 }
|
Chris@181
|
67 bool operator<(const Observation &o) const {
|
Chris@181
|
68 return
|
Chris@181
|
69 (time < o.time ||
|
Chris@181
|
70 (time == o.time && value < o.value) ||
|
Chris@181
|
71 (time == o.time && value == o.value && confidence < o.confidence));
|
Chris@181
|
72 }
|
Chris@181
|
73
|
Chris@181
|
74 double value;
|
Chris@181
|
75 Vamp::RealTime time;
|
Chris@181
|
76 double confidence;
|
Chris@181
|
77 };
|
Chris@181
|
78 typedef std::set<Observation> Observations;
|
Chris@181
|
79
|
Chris@181
|
80 /**
|
Chris@181
|
81 * Test the given observation to see whether it is consistent with
|
Chris@181
|
82 * this hypothesis, and adjust the hypothesis' internal state
|
Chris@181
|
83 * accordingly. If the observation is not inconsistent with the
|
Chris@181
|
84 * hypothesis, return true.
|
Chris@181
|
85 *!!! should be called e.g. test?
|
Chris@181
|
86 */
|
Chris@181
|
87 virtual bool accept(Observation) = 0;
|
Chris@181
|
88
|
Chris@181
|
89 /**
|
Chris@181
|
90 * Return the current state of this hypothesis.
|
Chris@181
|
91 */
|
Chris@181
|
92 virtual State getState() const = 0;
|
Chris@181
|
93
|
Chris@181
|
94 /**
|
Chris@181
|
95 * If the hypothesis has been satisfied (i.e. is in Satisfied or
|
Chris@181
|
96 * Expired state), return the set of observations that it
|
Chris@181
|
97 * accepted. Otherwise return an empty set
|
Chris@181
|
98 */
|
Chris@181
|
99 virtual Observations getAcceptedObservations() const = 0;
|
Chris@181
|
100
|
Chris@181
|
101 /**
|
Chris@181
|
102 * Convert the given set of accepted hypotheses (of type
|
Chris@181
|
103 * subclassed from AgentHypothesis) into a flattened set of their
|
Chris@181
|
104 * accepted observations.
|
Chris@181
|
105 *
|
Chris@181
|
106 * That is, only one is included for at any given moment, so in
|
Chris@181
|
107 * the case of overlapping hypotheses, the observations for the
|
Chris@181
|
108 * earlier are taken until the next hypothesis begins and then the
|
Chris@181
|
109 * latter's observations begin instead.
|
Chris@181
|
110 *
|
Chris@181
|
111 * (If there are gaps between hypotheses, the gaps remain in the
|
Chris@181
|
112 * output.)
|
Chris@181
|
113 */
|
Chris@181
|
114 template <typename HypothesisType>
|
Chris@181
|
115 static Observations flatten(const std::set<HypothesisType> &agents) {
|
Chris@181
|
116
|
Chris@181
|
117 typedef typename std::set<HypothesisType>::const_iterator Itr;
|
Chris@181
|
118 Observations flattened;
|
Chris@181
|
119
|
Chris@181
|
120 if (agents.empty()) return flattened;
|
Chris@181
|
121 Observations obs = agents.begin()->getAcceptedObservations();
|
Chris@181
|
122
|
Chris@181
|
123 for (Itr i = agents.begin(); i != agents.end(); ++i) {
|
Chris@181
|
124
|
Chris@181
|
125 Itr j = i;
|
Chris@181
|
126 ++j;
|
Chris@181
|
127
|
Chris@181
|
128 Observations nextObs;
|
Chris@181
|
129 if (j != agents.end()) nextObs = j->getAcceptedObservations();
|
Chris@181
|
130
|
Chris@181
|
131 for (Observations::const_iterator i = obs.begin();
|
Chris@181
|
132 i != obs.end(); ++i) {
|
Chris@181
|
133 if (!nextObs.empty() && i->time >= nextObs.begin()->time) {
|
Chris@181
|
134 break;
|
Chris@181
|
135 }
|
Chris@181
|
136 flattened.insert(*i);
|
Chris@181
|
137 }
|
Chris@181
|
138
|
Chris@181
|
139 obs = nextObs;
|
Chris@181
|
140 }
|
Chris@181
|
141
|
Chris@181
|
142 return flattened;
|
Chris@181
|
143 }
|
Chris@181
|
144 };
|
Chris@181
|
145
|
Chris@181
|
146 #endif
|