comparison base/EventSeries.h @ 1615:24dc8cb42755 single-point

Rename a number of classes and methods (including Point -> Event); comments
author Chris Cannam
date Thu, 07 Mar 2019 15:44:09 +0000
parents base/PointSeries.h@2e14a7876945
children de446dd905e6
comparison
equal deleted inserted replaced
1614:2e14a7876945 1615:24dc8cb42755
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Sonic Visualiser
5 An audio file viewer and annotation editor.
6 Centre for Digital Music, Queen Mary, University of London.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version. See the file
12 COPYING included with this distribution for more information.
13 */
14
15 #ifndef SV_EVENT_SERIES_H
16 #define SV_EVENT_SERIES_H
17
18 #include "Event.h"
19
20 #include <set>
21
22 //#define DEBUG_EVENT_SERIES 1
23
24 /**
25 * Container storing a series of events, with or without durations,
26 * and supporting the ability to query which events span a given frame
27 * time. To that end, in addition to the series of events, it stores a
28 * series of "seam points", which are the frame positions at which the
29 * set of simultaneous events changes (i.e. an event of non-zero
30 * duration starts or ends). These are updated when event is added or
31 * removed.
32 */
33 class EventSeries
34 {
35 public:
36 EventSeries() : m_count(0) { }
37
38 void add(const Event &p) {
39
40 m_events.insert(p);
41 ++m_count;
42
43 if (p.hasDuration()) {
44 sv_frame_t frame = p.getFrame();
45 sv_frame_t endFrame = p.getFrame() + p.getDuration();
46
47 createSeam(frame);
48 createSeam(endFrame);
49
50 auto i0 = m_seams.find(frame); // must succeed after createSeam
51 auto i1 = m_seams.find(endFrame); // likewise
52
53 for (auto i = i0; i != i1; ++i) {
54 if (i == m_seams.end()) {
55 SVCERR << "ERROR: EventSeries::add: "
56 << "reached end of seam map"
57 << endl;
58 break;
59 }
60 i->second.insert(p);
61 }
62 }
63
64 #ifdef DEBUG_EVENT_SERIES
65 std::cerr << "after add:" << std::endl;
66 dumpEvents();
67 dumpSeams();
68 #endif
69 }
70
71 void remove(const Event &p) {
72
73 // erase first itr that matches p; if there is more than one
74 // p, erase(p) would remove all of them, but we only want to
75 // remove (any) one
76 auto pitr = m_events.find(p);
77 if (pitr == m_events.end()) {
78 return; // we don't know this event
79 } else {
80 m_events.erase(pitr);
81 --m_count;
82 }
83
84 if (p.hasDuration()) {
85 sv_frame_t frame = p.getFrame();
86 sv_frame_t endFrame = p.getFrame() + p.getDuration();
87
88 auto i0 = m_seams.find(frame);
89 auto i1 = m_seams.find(endFrame);
90
91 #ifdef DEBUG_EVENT_SERIES
92 // This should be impossible if we found p in m_events above
93 if (i0 == m_seams.end() || i1 == m_seams.end()) {
94 SVCERR << "ERROR: EventSeries::remove: either frame " << frame
95 << " or endFrame " << endFrame
96 << " for event not found in seam map: event is "
97 << p.toXmlString() << endl;
98 }
99 #endif
100
101 for (auto i = i0; i != i1; ++i) {
102 if (i == m_seams.end()) {
103 // This can happen only if we have a negative
104 // duration, which Event forbids, but we don't
105 // protect against it in this class, so we'll
106 // leave this check in
107 SVCERR << "ERROR: EventSeries::remove: "
108 << "reached end of seam map"
109 << endl;
110 break;
111 }
112 // Can't just erase(p) as that would erase all of
113 // them, if there are several identical ones
114 auto si = i->second.find(p);
115 if (si != i->second.end()) {
116 i->second.erase(si);
117 }
118 }
119
120 // Shall we "garbage-collect" here? We could be leaving
121 // lots of empty event-sets, or consecutive identical
122 // ones, which are a pure irrelevance that take space and
123 // slow us down. But a lot depends on whether callers ever
124 // really delete anything much.
125 }
126
127 #ifdef DEBUG_EVENT_SERIES
128 std::cerr << "after remove:" << std::endl;
129 dumpEvents();
130 dumpSeams();
131 #endif
132 }
133
134 bool contains(const Event &p) {
135 return m_events.find(p) != m_events.end();
136 }
137
138 int count() const {
139 return m_count;
140 }
141
142 bool isEmpty() const {
143 return m_count == 0;
144 }
145
146 void clear() {
147 m_events.clear();
148 m_seams.clear();
149 m_count = 0;
150 }
151
152 /**
153 * Retrieve all events that span the given frame. A event without
154 * duration spans a frame if its own frame is equal to it. A event
155 * with duration spans a frame if its start frame is less than or
156 * equal to it and its end frame (start + duration) is greater
157 * than it.
158 */
159 EventVector getEventsSpanning(sv_frame_t frame) const {
160 EventVector span;
161
162 // first find any zero-duration events
163 auto pitr = m_events.lower_bound(Event(frame, QString()));
164 if (pitr != m_events.end()) {
165 while (pitr->getFrame() == frame) {
166 if (!pitr->hasDuration()) {
167 span.push_back(*pitr);
168 }
169 ++pitr;
170 }
171 }
172
173 // now any non-zero-duration ones from the seam map
174 auto sitr = m_seams.lower_bound(frame);
175 if (sitr == m_seams.end() || sitr->first > frame) {
176 if (sitr != m_seams.begin()) {
177 --sitr;
178 }
179 }
180 if (sitr != m_seams.end() && sitr->first <= frame) {
181 for (auto p: sitr->second) {
182 span.push_back(p);
183 }
184 }
185
186 return span;
187 }
188
189 private:
190 int m_count;
191
192 typedef std::multiset<Event> EventMultiset;
193 EventMultiset m_events;
194
195 typedef std::map<sv_frame_t, std::multiset<Event>> FrameEventsMap;
196 FrameEventsMap m_seams;
197
198 /** Create a seam at the given frame, copying from the prior seam
199 * if there is one. If a seam already exists at the given frame,
200 * leave it untouched.
201 */
202 void createSeam(sv_frame_t frame) {
203 auto itr = m_seams.lower_bound(frame);
204 if (itr == m_seams.end() || itr->first > frame) {
205 if (itr != m_seams.begin()) {
206 --itr;
207 }
208 }
209 if (itr == m_seams.end()) {
210 m_seams[frame] = {};
211 } else if (itr->first < frame) {
212 m_seams[frame] = itr->second;
213 } else if (itr->first > frame) { // itr must be begin()
214 m_seams[frame] = {};
215 }
216 }
217
218 #ifdef DEBUG_EVENT_SERIES
219 void dumpEvents() const {
220 std::cerr << "EVENTS [" << std::endl;
221 for (const auto &p: m_events) {
222 std::cerr << p.toXmlString(" ");
223 }
224 std::cerr << "]" << std::endl;
225 }
226
227 void dumpSeams() const {
228 std::cerr << "SEAMS [" << std::endl;
229 for (const auto &s: m_seams) {
230 std::cerr << " " << s.first << " -> {" << std::endl;
231 for (const auto &p: s.second) {
232 std::cerr << p.toXmlString(" ");
233 }
234 std::cerr << " }" << std::endl;
235 }
236 std::cerr << "]" << std::endl;
237 }
238 #endif
239 };
240
241 #endif