Chris@1611
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1611
|
2
|
Chris@1611
|
3 /*
|
Chris@1611
|
4 Sonic Visualiser
|
Chris@1611
|
5 An audio file viewer and annotation editor.
|
Chris@1611
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1611
|
7 This file copyright 2006 Chris Cannam.
|
Chris@1611
|
8
|
Chris@1611
|
9 This program is free software; you can redistribute it and/or
|
Chris@1611
|
10 modify it under the terms of the GNU General Public License as
|
Chris@1611
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@1611
|
12 License, or (at your option) any later version. See the file
|
Chris@1611
|
13 COPYING included with this distribution for more information.
|
Chris@1611
|
14 */
|
Chris@1611
|
15
|
Chris@1615
|
16 #ifndef SV_EVENT_H
|
Chris@1615
|
17 #define SV_EVENT_H
|
Chris@1615
|
18
|
Chris@1615
|
19 #include "BaseTypes.h"
|
Chris@1615
|
20 #include "NoteData.h"
|
Chris@1615
|
21 #include "XmlExportable.h"
|
Chris@1629
|
22 #include "DataExportOptions.h"
|
Chris@1615
|
23
|
Chris@1615
|
24 #include <vector>
|
Chris@1615
|
25 #include <stdexcept>
|
Chris@1611
|
26
|
Chris@1611
|
27 #include <QString>
|
Chris@1611
|
28
|
Chris@1615
|
29 /**
|
Chris@1647
|
30 * An immutable(-ish) type used for point and event representation in
|
Chris@1647
|
31 * sparse models, as well as for interchange within the clipboard. An
|
Chris@1647
|
32 * event always has a frame and (possibly empty) label, and optionally
|
Chris@1647
|
33 * has numerical value, level, duration in frames, and a mapped
|
Chris@1647
|
34 * reference frame. Event has an operator< defining a total ordering,
|
Chris@1647
|
35 * by frame first and then by the other properties.
|
Chris@1615
|
36 *
|
Chris@1615
|
37 * Event is based on the Clipboard::Point type up to SV v3.2.1 and is
|
Chris@1615
|
38 * intended also to replace the custom point types previously found in
|
Chris@1615
|
39 * sparse models.
|
Chris@1615
|
40 */
|
Chris@1615
|
41 class Event
|
Chris@1611
|
42 {
|
Chris@1611
|
43 public:
|
Chris@1623
|
44 Event() :
|
Chris@1629
|
45 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
46 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1623
|
47 m_value(0.f), m_level(0.f), m_frame(0),
|
Chris@1623
|
48 m_duration(0), m_referenceFrame(0), m_label() { }
|
Chris@1623
|
49
|
Chris@1615
|
50 Event(sv_frame_t frame) :
|
Chris@1629
|
51 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
52 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1615
|
53 m_value(0.f), m_level(0.f), m_frame(frame),
|
Chris@1615
|
54 m_duration(0), m_referenceFrame(0), m_label() { }
|
Chris@1615
|
55
|
Chris@1615
|
56 Event(sv_frame_t frame, QString label) :
|
Chris@1629
|
57 m_haveValue(false), m_haveLevel(false),
|
Chris@1629
|
58 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1611
|
59 m_value(0.f), m_level(0.f), m_frame(frame),
|
Chris@1611
|
60 m_duration(0), m_referenceFrame(0), m_label(label) { }
|
Chris@1611
|
61
|
Chris@1615
|
62 Event(sv_frame_t frame, float value, QString label) :
|
Chris@1629
|
63 m_haveValue(true), m_haveLevel(false),
|
Chris@1629
|
64 m_haveDuration(false), m_haveReferenceFrame(false),
|
Chris@1611
|
65 m_value(value), m_level(0.f), m_frame(frame),
|
Chris@1611
|
66 m_duration(0), m_referenceFrame(0), m_label(label) { }
|
Chris@1611
|
67
|
Chris@1615
|
68 Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) :
|
Chris@1629
|
69 m_haveValue(true), m_haveLevel(false),
|
Chris@1629
|
70 m_haveDuration(true), m_haveReferenceFrame(false),
|
Chris@1611
|
71 m_value(value), m_level(0.f), m_frame(frame),
|
Chris@1615
|
72 m_duration(duration), m_referenceFrame(0), m_label(label) {
|
Chris@1615
|
73 if (m_duration < 0) throw std::logic_error("duration must be >= 0");
|
Chris@1615
|
74 }
|
Chris@1611
|
75
|
Chris@1615
|
76 Event(sv_frame_t frame, float value, sv_frame_t duration,
|
Chris@1612
|
77 float level, QString label) :
|
Chris@1629
|
78 m_haveValue(true), m_haveLevel(true),
|
Chris@1629
|
79 m_haveDuration(true), m_haveReferenceFrame(false),
|
Chris@1611
|
80 m_value(value), m_level(level), m_frame(frame),
|
Chris@1615
|
81 m_duration(duration), m_referenceFrame(0), m_label(label) {
|
Chris@1615
|
82 if (m_duration < 0) throw std::logic_error("duration must be >= 0");
|
Chris@1615
|
83 }
|
Chris@1611
|
84
|
Chris@1615
|
85 Event(const Event &event) =default;
|
Chris@1647
|
86
|
Chris@1647
|
87 // We would ideally like Event to be immutable - but we have to
|
Chris@1647
|
88 // have these because otherwise we can't put Events in vectors
|
Chris@1647
|
89 // etc. Let's call it conceptually immutable
|
Chris@1615
|
90 Event &operator=(const Event &event) =default;
|
Chris@1615
|
91 Event &operator=(Event &&event) =default;
|
Chris@1611
|
92
|
Chris@1611
|
93 sv_frame_t getFrame() const { return m_frame; }
|
Chris@1611
|
94
|
Chris@1615
|
95 Event withFrame(sv_frame_t frame) const {
|
Chris@1615
|
96 Event p(*this);
|
Chris@1611
|
97 p.m_frame = frame;
|
Chris@1611
|
98 return p;
|
Chris@1611
|
99 }
|
Chris@1611
|
100
|
Chris@1615
|
101 bool hasValue() const { return m_haveValue; }
|
Chris@1634
|
102 float getValue() const { return m_haveValue ? m_value : 0.f; }
|
Chris@1611
|
103
|
Chris@1615
|
104 Event withValue(float value) const {
|
Chris@1615
|
105 Event p(*this);
|
Chris@1611
|
106 p.m_haveValue = true;
|
Chris@1611
|
107 p.m_value = value;
|
Chris@1611
|
108 return p;
|
Chris@1611
|
109 }
|
Chris@1615
|
110 Event withoutValue() const {
|
Chris@1615
|
111 Event p(*this);
|
Chris@1615
|
112 p.m_haveValue = false;
|
Chris@1615
|
113 p.m_value = 0.f;
|
Chris@1615
|
114 return p;
|
Chris@1615
|
115 }
|
Chris@1611
|
116
|
Chris@1629
|
117 bool hasDuration() const { return m_haveDuration; }
|
Chris@1634
|
118 sv_frame_t getDuration() const { return m_haveDuration ? m_duration : 0; }
|
Chris@1611
|
119
|
Chris@1615
|
120 Event withDuration(sv_frame_t duration) const {
|
Chris@1615
|
121 Event p(*this);
|
Chris@1611
|
122 p.m_duration = duration;
|
Chris@1629
|
123 p.m_haveDuration = true;
|
Chris@1615
|
124 if (duration < 0) throw std::logic_error("duration must be >= 0");
|
Chris@1615
|
125 return p;
|
Chris@1615
|
126 }
|
Chris@1615
|
127 Event withoutDuration() const {
|
Chris@1615
|
128 Event p(*this);
|
Chris@1629
|
129 p.m_haveDuration = false;
|
Chris@1615
|
130 p.m_duration = 0;
|
Chris@1611
|
131 return p;
|
Chris@1611
|
132 }
|
Chris@1620
|
133
|
Chris@1620
|
134 bool hasLabel() const { return m_label != QString(); }
|
Chris@1611
|
135 QString getLabel() const { return m_label; }
|
Chris@1611
|
136
|
Chris@1615
|
137 Event withLabel(QString label) const {
|
Chris@1615
|
138 Event p(*this);
|
Chris@1611
|
139 p.m_label = label;
|
Chris@1611
|
140 return p;
|
Chris@1611
|
141 }
|
Chris@1663
|
142
|
Chris@1663
|
143 bool hasUri() const { return m_uri != QString(); }
|
Chris@1663
|
144 QString getURI() const { return m_uri; }
|
Chris@1663
|
145
|
Chris@1663
|
146 Event withURI(QString uri) const {
|
Chris@1663
|
147 Event p(*this);
|
Chris@1663
|
148 p.m_uri = uri;
|
Chris@1663
|
149 return p;
|
Chris@1663
|
150 }
|
Chris@1611
|
151
|
Chris@1615
|
152 bool hasLevel() const { return m_haveLevel; }
|
Chris@1634
|
153 float getLevel() const { return m_haveLevel ? m_level : 0.f; }
|
Chris@1615
|
154
|
Chris@1615
|
155 Event withLevel(float level) const {
|
Chris@1615
|
156 Event p(*this);
|
Chris@1611
|
157 p.m_haveLevel = true;
|
Chris@1611
|
158 p.m_level = level;
|
Chris@1611
|
159 return p;
|
Chris@1611
|
160 }
|
Chris@1615
|
161 Event withoutLevel() const {
|
Chris@1615
|
162 Event p(*this);
|
Chris@1615
|
163 p.m_haveLevel = false;
|
Chris@1615
|
164 p.m_level = 0.f;
|
Chris@1615
|
165 return p;
|
Chris@1615
|
166 }
|
Chris@1611
|
167
|
Chris@1615
|
168 bool hasReferenceFrame() const { return m_haveReferenceFrame; }
|
Chris@1634
|
169 sv_frame_t getReferenceFrame() const {
|
Chris@1634
|
170 return m_haveReferenceFrame ? m_referenceFrame : m_frame;
|
Chris@1634
|
171 }
|
Chris@1611
|
172
|
Chris@1615
|
173 bool referenceFrameDiffers() const { // from event frame
|
Chris@1611
|
174 return m_haveReferenceFrame && (m_referenceFrame != m_frame);
|
Chris@1611
|
175 }
|
Chris@1611
|
176
|
Chris@1615
|
177 Event withReferenceFrame(sv_frame_t frame) const {
|
Chris@1615
|
178 Event p(*this);
|
Chris@1611
|
179 p.m_haveReferenceFrame = true;
|
Chris@1611
|
180 p.m_referenceFrame = frame;
|
Chris@1611
|
181 return p;
|
Chris@1611
|
182 }
|
Chris@1615
|
183 Event withoutReferenceFrame() const {
|
Chris@1615
|
184 Event p(*this);
|
Chris@1615
|
185 p.m_haveReferenceFrame = false;
|
Chris@1615
|
186 p.m_referenceFrame = 0;
|
Chris@1615
|
187 return p;
|
Chris@1615
|
188 }
|
Chris@1612
|
189
|
Chris@1615
|
190 bool operator==(const Event &p) const {
|
Chris@1612
|
191
|
Chris@1612
|
192 if (m_frame != p.m_frame) return false;
|
Chris@1629
|
193
|
Chris@1629
|
194 if (m_haveDuration != p.m_haveDuration) return false;
|
Chris@1629
|
195 if (m_haveDuration && (m_duration != p.m_duration)) return false;
|
Chris@1612
|
196
|
Chris@1612
|
197 if (m_haveValue != p.m_haveValue) return false;
|
Chris@1612
|
198 if (m_haveValue && (m_value != p.m_value)) return false;
|
Chris@1612
|
199
|
Chris@1612
|
200 if (m_haveLevel != p.m_haveLevel) return false;
|
Chris@1612
|
201 if (m_haveLevel && (m_level != p.m_level)) return false;
|
Chris@1612
|
202
|
Chris@1612
|
203 if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false;
|
Chris@1612
|
204 if (m_haveReferenceFrame &&
|
Chris@1612
|
205 (m_referenceFrame != p.m_referenceFrame)) return false;
|
Chris@1612
|
206
|
Chris@1612
|
207 if (m_label != p.m_label) return false;
|
Chris@1663
|
208 if (m_uri != p.m_uri) return false;
|
Chris@1612
|
209
|
Chris@1612
|
210 return true;
|
Chris@1612
|
211 }
|
Chris@1612
|
212
|
Chris@1630
|
213 bool operator!=(const Event &p) const {
|
Chris@1630
|
214 return !operator==(p);
|
Chris@1630
|
215 }
|
Chris@1630
|
216
|
Chris@1615
|
217 bool operator<(const Event &p) const {
|
Chris@1612
|
218
|
Chris@1629
|
219 if (m_frame != p.m_frame) {
|
Chris@1629
|
220 return m_frame < p.m_frame;
|
Chris@1629
|
221 }
|
Chris@1612
|
222
|
Chris@1615
|
223 // events without a property sort before events with that property
|
Chris@1612
|
224
|
Chris@1629
|
225 if (m_haveDuration != p.m_haveDuration) {
|
Chris@1629
|
226 return !m_haveDuration;
|
Chris@1629
|
227 }
|
Chris@1629
|
228 if (m_haveDuration && (m_duration != p.m_duration)) {
|
Chris@1629
|
229 return m_duration < p.m_duration;
|
Chris@1629
|
230 }
|
Chris@1629
|
231
|
Chris@1629
|
232 if (m_haveValue != p.m_haveValue) {
|
Chris@1629
|
233 return !m_haveValue;
|
Chris@1629
|
234 }
|
Chris@1629
|
235 if (m_haveValue && (m_value != p.m_value)) {
|
Chris@1629
|
236 return m_value < p.m_value;
|
Chris@1629
|
237 }
|
Chris@1612
|
238
|
Chris@1629
|
239 if (m_haveLevel != p.m_haveLevel) {
|
Chris@1629
|
240 return !m_haveLevel;
|
Chris@1629
|
241 }
|
Chris@1629
|
242 if (m_haveLevel && (m_level != p.m_level)) {
|
Chris@1629
|
243 return m_level < p.m_level;
|
Chris@1629
|
244 }
|
Chris@1612
|
245
|
Chris@1612
|
246 if (m_haveReferenceFrame != p.m_haveReferenceFrame) {
|
Chris@1612
|
247 return !m_haveReferenceFrame;
|
Chris@1612
|
248 }
|
Chris@1612
|
249 if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) {
|
Chris@1612
|
250 return m_referenceFrame < p.m_referenceFrame;
|
Chris@1612
|
251 }
|
Chris@1612
|
252
|
Chris@1663
|
253 if (m_label != p.m_label) {
|
Chris@1663
|
254 return m_label < p.m_label;
|
Chris@1663
|
255 }
|
Chris@1663
|
256 return m_uri < p.m_uri;
|
Chris@1612
|
257 }
|
Chris@1612
|
258
|
Chris@1674
|
259 struct ExportNameOptions {
|
Chris@1674
|
260
|
Chris@1674
|
261 ExportNameOptions() :
|
Chris@1789
|
262 valueAttributeName("value"),
|
Chris@1789
|
263 levelAttributeName("level"),
|
Chris@1674
|
264 uriAttributeName("uri") { }
|
Chris@1674
|
265
|
Chris@1789
|
266 QString valueAttributeName;
|
Chris@1789
|
267 QString levelAttributeName;
|
Chris@1674
|
268 QString uriAttributeName;
|
Chris@1674
|
269 };
|
Chris@1674
|
270
|
Chris@1612
|
271 void toXml(QTextStream &stream,
|
Chris@1612
|
272 QString indent = "",
|
Chris@1674
|
273 QString extraAttributes = "",
|
Chris@1674
|
274 ExportNameOptions opts = ExportNameOptions()) const {
|
Chris@1612
|
275
|
Chris@1615
|
276 // For I/O purposes these are points, not events
|
Chris@1612
|
277 stream << indent << QString("<point frame=\"%1\" ").arg(m_frame);
|
Chris@1674
|
278 if (m_haveValue) {
|
Chris@1674
|
279 stream << QString("%1=\"%2\" ")
|
Chris@1789
|
280 .arg(opts.valueAttributeName).arg(m_value);
|
Chris@1674
|
281 }
|
Chris@1674
|
282 if (m_haveDuration) {
|
Chris@1674
|
283 stream << QString("duration=\"%1\" ").arg(m_duration);
|
Chris@1674
|
284 }
|
Chris@1674
|
285 if (m_haveLevel) {
|
Chris@1789
|
286 stream << QString("%1=\"%2\" ")
|
Chris@1789
|
287 .arg(opts.levelAttributeName)
|
Chris@1789
|
288 .arg(m_level);
|
Chris@1674
|
289 }
|
Chris@1674
|
290 if (m_haveReferenceFrame) {
|
Chris@1674
|
291 stream << QString("referenceFrame=\"%1\" ")
|
Chris@1674
|
292 .arg(m_referenceFrame);
|
Chris@1674
|
293 }
|
Chris@1682
|
294
|
Chris@1682
|
295 stream << QString("label=\"%1\" ")
|
Chris@1682
|
296 .arg(XmlExportable::encodeEntities(m_label));
|
Chris@1682
|
297
|
Chris@1663
|
298 if (m_uri != QString()) {
|
Chris@1674
|
299 stream << QString("%1=\"%2\" ")
|
Chris@1674
|
300 .arg(opts.uriAttributeName)
|
Chris@1663
|
301 .arg(XmlExportable::encodeEntities(m_uri));
|
Chris@1663
|
302 }
|
Chris@1641
|
303 stream << extraAttributes << "/>\n";
|
Chris@1612
|
304 }
|
Chris@1612
|
305
|
Chris@1612
|
306 QString toXmlString(QString indent = "",
|
Chris@1612
|
307 QString extraAttributes = "") const {
|
Chris@1612
|
308 QString s;
|
Chris@1612
|
309 QTextStream out(&s);
|
Chris@1612
|
310 toXml(out, indent, extraAttributes);
|
Chris@1612
|
311 out.flush();
|
Chris@1612
|
312 return s;
|
Chris@1612
|
313 }
|
Chris@1615
|
314
|
Chris@1629
|
315 NoteData toNoteData(sv_samplerate_t sampleRate,
|
Chris@1637
|
316 bool valueIsMidiPitch) const {
|
Chris@1615
|
317
|
Chris@1615
|
318 sv_frame_t duration;
|
Chris@1629
|
319 if (m_haveDuration && m_duration > 0) {
|
Chris@1615
|
320 duration = m_duration;
|
Chris@1615
|
321 } else {
|
Chris@1615
|
322 duration = sv_frame_t(sampleRate / 6); // arbitrary short duration
|
Chris@1615
|
323 }
|
Chris@1615
|
324
|
Chris@1615
|
325 int midiPitch;
|
Chris@1615
|
326 float frequency = 0.f;
|
Chris@1615
|
327 if (m_haveValue) {
|
Chris@1615
|
328 if (valueIsMidiPitch) {
|
Chris@1615
|
329 midiPitch = int(roundf(m_value));
|
Chris@1615
|
330 } else {
|
Chris@1615
|
331 frequency = m_value;
|
Chris@1615
|
332 midiPitch = Pitch::getPitchForFrequency(frequency);
|
Chris@1615
|
333 }
|
Chris@1615
|
334 } else {
|
Chris@1615
|
335 midiPitch = 64;
|
Chris@1615
|
336 valueIsMidiPitch = true;
|
Chris@1615
|
337 }
|
Chris@1615
|
338
|
Chris@1615
|
339 int velocity = 100;
|
Chris@1615
|
340 if (m_haveLevel) {
|
Chris@1615
|
341 if (m_level > 0.f && m_level <= 1.f) {
|
Chris@1615
|
342 velocity = int(roundf(m_level * 127.f));
|
Chris@1615
|
343 }
|
Chris@1615
|
344 }
|
Chris@1615
|
345
|
Chris@1615
|
346 NoteData n(m_frame, duration, midiPitch, velocity);
|
Chris@1615
|
347 n.isMidiPitchQuantized = valueIsMidiPitch;
|
Chris@1615
|
348 if (!valueIsMidiPitch) {
|
Chris@1615
|
349 n.frequency = frequency;
|
Chris@1615
|
350 }
|
Chris@1615
|
351
|
Chris@1615
|
352 return n;
|
Chris@1615
|
353 }
|
Chris@1623
|
354
|
Chris@1629
|
355 QString toDelimitedDataString(QString delimiter,
|
Chris@1629
|
356 DataExportOptions opts,
|
Chris@1629
|
357 sv_samplerate_t sampleRate) const {
|
Chris@1629
|
358 QStringList list;
|
Chris@1629
|
359
|
Chris@1629
|
360 list << RealTime::frame2RealTime(m_frame, sampleRate)
|
Chris@1629
|
361 .toString().c_str();
|
Chris@1629
|
362
|
Chris@1629
|
363 if (m_haveValue) {
|
Chris@1629
|
364 list << QString("%1").arg(m_value);
|
Chris@1629
|
365 }
|
Chris@1629
|
366
|
Chris@1629
|
367 if (m_haveDuration) {
|
Chris@1629
|
368 list << RealTime::frame2RealTime(m_duration, sampleRate)
|
Chris@1629
|
369 .toString().c_str();
|
Chris@1629
|
370 }
|
Chris@1629
|
371
|
Chris@1629
|
372 if (m_haveLevel) {
|
Chris@1629
|
373 if (!(opts & DataExportOmitLevels)) {
|
Chris@1629
|
374 list << QString("%1").arg(m_level);
|
Chris@1629
|
375 }
|
Chris@1629
|
376 }
|
Chris@1787
|
377
|
Chris@1787
|
378 // Put URI before label, to preserve the ordering previously
|
Chris@1787
|
379 // used in the custom Image model exporter. We shouldn't
|
Chris@1787
|
380 // change the column ordering unless (until?) we provide a
|
Chris@1787
|
381 // facility for the user to customise it
|
Chris@1787
|
382 if (m_uri != "") list << m_uri;
|
Chris@1629
|
383 if (m_label != "") list << m_label;
|
Chris@1629
|
384
|
Chris@1629
|
385 return list.join(delimiter);
|
Chris@1629
|
386 }
|
Chris@1629
|
387
|
Chris@1623
|
388 uint hash(uint seed = 0) const {
|
Chris@1623
|
389 uint h = qHash(m_label, seed);
|
Chris@1623
|
390 if (m_haveValue) h ^= qHash(m_value);
|
Chris@1623
|
391 if (m_haveLevel) h ^= qHash(m_level);
|
Chris@1623
|
392 h ^= qHash(m_frame);
|
Chris@1629
|
393 if (m_haveDuration) h ^= qHash(m_duration);
|
Chris@1623
|
394 if (m_haveReferenceFrame) h ^= qHash(m_referenceFrame);
|
Chris@1663
|
395 h ^= qHash(m_uri);
|
Chris@1623
|
396 return h;
|
Chris@1623
|
397 }
|
Chris@1611
|
398
|
Chris@1611
|
399 private:
|
Chris@1611
|
400 // The order of fields here is chosen to minimise overall size of struct.
|
Chris@1612
|
401 // We potentially store very many of these objects.
|
Chris@1611
|
402 // If you change something, check what difference it makes to packing.
|
Chris@1611
|
403 bool m_haveValue : 1;
|
Chris@1611
|
404 bool m_haveLevel : 1;
|
Chris@1629
|
405 bool m_haveDuration : 1;
|
Chris@1611
|
406 bool m_haveReferenceFrame : 1;
|
Chris@1611
|
407 float m_value;
|
Chris@1611
|
408 float m_level;
|
Chris@1611
|
409 sv_frame_t m_frame;
|
Chris@1611
|
410 sv_frame_t m_duration;
|
Chris@1611
|
411 sv_frame_t m_referenceFrame;
|
Chris@1611
|
412 QString m_label;
|
Chris@1663
|
413 QString m_uri;
|
Chris@1611
|
414 };
|
Chris@1611
|
415
|
Chris@1623
|
416 inline uint qHash(const Event &e, uint seed = 0) {
|
Chris@1623
|
417 return e.hash(seed);
|
Chris@1623
|
418 }
|
Chris@1623
|
419
|
Chris@1615
|
420 typedef std::vector<Event> EventVector;
|
Chris@1612
|
421
|
Chris@1611
|
422 #endif
|