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 NOTE_HYPOTHESIS_H
|
Chris@181
|
18 #define NOTE_HYPOTHESIS_H
|
Chris@181
|
19
|
Chris@181
|
20 #include "AgentHypothesis.h"
|
Chris@181
|
21
|
Chris@181
|
22 #include <set>
|
Chris@181
|
23 #include <vector>
|
Chris@181
|
24
|
Chris@181
|
25 /**
|
Chris@181
|
26 * An AgentHypothesis which tests a series of instantaneous pitch
|
Chris@181
|
27 * estimates to see whether they fit a single-note relationship.
|
Chris@181
|
28 * Contains rules specific to testing note pitch and timing.
|
Chris@181
|
29 */
|
Chris@181
|
30
|
Chris@181
|
31 class NoteHypothesis : public AgentHypothesis
|
Chris@181
|
32 {
|
Chris@181
|
33 public:
|
Chris@181
|
34 /**
|
Chris@181
|
35 * Construct an empty hypothesis. This will be in New state and
|
Chris@181
|
36 * will provisionally accept any estimate.
|
Chris@181
|
37 */
|
Chris@181
|
38 NoteHypothesis();
|
Chris@181
|
39
|
Chris@181
|
40 /**
|
Chris@181
|
41 * Destroy the hypothesis
|
Chris@181
|
42 */
|
Chris@181
|
43 ~NoteHypothesis();
|
Chris@181
|
44
|
Chris@181
|
45 virtual bool accept(Observation);
|
Chris@181
|
46 virtual State getState() const;
|
Chris@181
|
47 virtual Observations getAcceptedObservations() const;
|
Chris@181
|
48
|
Chris@181
|
49 struct Note {
|
Chris@184
|
50 Note() : freq(0), time(), duration(), confidence(1.0) { }
|
Chris@184
|
51 Note(double _f, Vamp::RealTime _t, Vamp::RealTime _d, double _i) :
|
Chris@184
|
52 freq(_f), time(_t), duration(_d), confidence(_i) { }
|
Chris@181
|
53 bool operator==(const Note &e) const {
|
Chris@184
|
54 return e.freq == freq && e.time == time &&
|
Chris@184
|
55 e.duration == duration && e.confidence == confidence;
|
Chris@181
|
56 }
|
Chris@181
|
57 double freq;
|
Chris@181
|
58 Vamp::RealTime time;
|
Chris@181
|
59 Vamp::RealTime duration;
|
Chris@184
|
60 double confidence;
|
Chris@181
|
61 };
|
Chris@181
|
62
|
Chris@181
|
63 /**
|
Chris@181
|
64 * Return the mean frequency of the accepted observations
|
Chris@181
|
65 */
|
Chris@181
|
66 double getMeanFrequency() const;
|
Chris@184
|
67
|
Chris@184
|
68 /**
|
Chris@184
|
69 * Return the median frequency of the accepted observations
|
Chris@184
|
70 */
|
Chris@184
|
71 double getMedianFrequency() const;
|
Chris@184
|
72
|
Chris@184
|
73 /**
|
Chris@184
|
74 * Return the median confidence of the accepted observations
|
Chris@184
|
75 */
|
Chris@184
|
76 double getMedianConfidence() const;
|
Chris@181
|
77
|
Chris@181
|
78 /**
|
Chris@181
|
79 * Return a single note roughly matching this hypothesis
|
Chris@181
|
80 */
|
Chris@181
|
81 Note getAveragedNote() const;
|
Chris@181
|
82
|
Chris@181
|
83 /**
|
Chris@181
|
84 * Return the time of the first accepted observation
|
Chris@181
|
85 */
|
Chris@181
|
86 Vamp::RealTime getStartTime() const;
|
Chris@181
|
87
|
Chris@181
|
88 /**
|
Chris@181
|
89 * Return the difference between the start time and the end of the
|
Chris@181
|
90 * final accepted observation
|
Chris@181
|
91 */
|
Chris@181
|
92 Vamp::RealTime getDuration() const;
|
Chris@181
|
93
|
Chris@181
|
94 //!!!
|
Chris@181
|
95 bool operator==(const NoteHypothesis &other) const {
|
Chris@181
|
96 return m_state == other.m_state && m_pending == other.m_pending;
|
Chris@181
|
97 }
|
Chris@181
|
98
|
Chris@181
|
99 bool operator<(const NoteHypothesis &other) const {
|
Chris@184
|
100 if (getStartTime() != other.getStartTime()) {
|
Chris@184
|
101 return getStartTime() < other.getStartTime();
|
Chris@184
|
102 } else if (m_state != other.m_state) {
|
Chris@184
|
103 return m_state < other.m_state;
|
Chris@184
|
104 } else if (m_pending.size() != other.m_pending.size()) {
|
Chris@184
|
105 return m_pending.size() < other.m_pending.size();
|
Chris@184
|
106 } else {
|
Chris@184
|
107 Observations::const_iterator i = m_pending.begin();
|
Chris@184
|
108 Observations::const_iterator j = other.m_pending.begin();
|
Chris@184
|
109 while (i != m_pending.end()) {
|
Chris@184
|
110 if (*i == *j) {
|
Chris@184
|
111 ++i;
|
Chris@184
|
112 ++j;
|
Chris@184
|
113 } else {
|
Chris@184
|
114 return *i < *j;
|
Chris@184
|
115 }
|
Chris@184
|
116 }
|
Chris@184
|
117 return false;
|
Chris@184
|
118 }
|
Chris@181
|
119 }
|
Chris@181
|
120
|
Chris@181
|
121 private:
|
Chris@181
|
122 bool isWithinTolerance(Observation) const;
|
Chris@181
|
123 bool isOutOfDateFor(Observation) const;
|
Chris@181
|
124 bool isSatisfied() const;
|
Chris@181
|
125
|
Chris@181
|
126 State m_state;
|
Chris@181
|
127 Observations m_pending;
|
Chris@181
|
128 };
|
Chris@181
|
129
|
Chris@181
|
130 #endif
|