Mercurial > hg > svcore
comparison base/Event.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/Point.h@23a29e5dc0e9 |
children | 2f9deb8d3295 |
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 This file copyright 2006 Chris Cannam. | |
8 | |
9 This program is free software; you can redistribute it and/or | |
10 modify it under the terms of the GNU General Public License as | |
11 published by the Free Software Foundation; either version 2 of the | |
12 License, or (at your option) any later version. See the file | |
13 COPYING included with this distribution for more information. | |
14 */ | |
15 | |
16 #ifndef SV_EVENT_H | |
17 #define SV_EVENT_H | |
18 | |
19 #include "BaseTypes.h" | |
20 #include "NoteData.h" | |
21 #include "XmlExportable.h" | |
22 | |
23 #include <vector> | |
24 #include <stdexcept> | |
25 | |
26 #include <QString> | |
27 | |
28 /** | |
29 * An immutable type used for point and event representation in sparse | |
30 * models, as well as for interchange within the clipboard. An event | |
31 * always has a frame and (possibly empty) label, and optionally has | |
32 * numerical value, level, duration in frames, and a mapped reference | |
33 * frame. Event has an operator< defining a total ordering, by frame | |
34 * first and then by the other properties. | |
35 * | |
36 * Event is based on the Clipboard::Point type up to SV v3.2.1 and is | |
37 * intended also to replace the custom point types previously found in | |
38 * sparse models. | |
39 */ | |
40 class Event | |
41 { | |
42 public: | |
43 Event(sv_frame_t frame) : | |
44 m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), | |
45 m_value(0.f), m_level(0.f), m_frame(frame), | |
46 m_duration(0), m_referenceFrame(0), m_label() { } | |
47 | |
48 Event(sv_frame_t frame, QString label) : | |
49 m_haveValue(false), m_haveLevel(false), m_haveReferenceFrame(false), | |
50 m_value(0.f), m_level(0.f), m_frame(frame), | |
51 m_duration(0), m_referenceFrame(0), m_label(label) { } | |
52 | |
53 Event(sv_frame_t frame, float value, QString label) : | |
54 m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), | |
55 m_value(value), m_level(0.f), m_frame(frame), | |
56 m_duration(0), m_referenceFrame(0), m_label(label) { } | |
57 | |
58 Event(sv_frame_t frame, float value, sv_frame_t duration, QString label) : | |
59 m_haveValue(true), m_haveLevel(false), m_haveReferenceFrame(false), | |
60 m_value(value), m_level(0.f), m_frame(frame), | |
61 m_duration(duration), m_referenceFrame(0), m_label(label) { | |
62 if (m_duration < 0) throw std::logic_error("duration must be >= 0"); | |
63 } | |
64 | |
65 Event(sv_frame_t frame, float value, sv_frame_t duration, | |
66 float level, QString label) : | |
67 m_haveValue(true), m_haveLevel(true), m_haveReferenceFrame(false), | |
68 m_value(value), m_level(level), m_frame(frame), | |
69 m_duration(duration), m_referenceFrame(0), m_label(label) { | |
70 if (m_duration < 0) throw std::logic_error("duration must be >= 0"); | |
71 } | |
72 | |
73 Event(const Event &event) =default; | |
74 Event &operator=(const Event &event) =default; | |
75 Event &operator=(Event &&event) =default; | |
76 | |
77 sv_frame_t getFrame() const { return m_frame; } | |
78 | |
79 Event withFrame(sv_frame_t frame) const { | |
80 Event p(*this); | |
81 p.m_frame = frame; | |
82 return p; | |
83 } | |
84 | |
85 bool hasValue() const { return m_haveValue; } | |
86 float getValue() const { return m_value; } | |
87 | |
88 Event withValue(float value) const { | |
89 Event p(*this); | |
90 p.m_haveValue = true; | |
91 p.m_value = value; | |
92 return p; | |
93 } | |
94 Event withoutValue() const { | |
95 Event p(*this); | |
96 p.m_haveValue = false; | |
97 p.m_value = 0.f; | |
98 return p; | |
99 } | |
100 | |
101 bool hasDuration() const { return m_duration != 0; } | |
102 sv_frame_t getDuration() const { return m_duration; } | |
103 | |
104 Event withDuration(sv_frame_t duration) const { | |
105 Event p(*this); | |
106 p.m_duration = duration; | |
107 if (duration < 0) throw std::logic_error("duration must be >= 0"); | |
108 return p; | |
109 } | |
110 Event withoutDuration() const { | |
111 Event p(*this); | |
112 p.m_duration = 0; | |
113 return p; | |
114 } | |
115 | |
116 QString getLabel() const { return m_label; } | |
117 | |
118 Event withLabel(QString label) const { | |
119 Event p(*this); | |
120 p.m_label = label; | |
121 return p; | |
122 } | |
123 | |
124 bool hasLevel() const { return m_haveLevel; } | |
125 float getLevel() const { return m_level; } | |
126 | |
127 Event withLevel(float level) const { | |
128 Event p(*this); | |
129 p.m_haveLevel = true; | |
130 p.m_level = level; | |
131 return p; | |
132 } | |
133 Event withoutLevel() const { | |
134 Event p(*this); | |
135 p.m_haveLevel = false; | |
136 p.m_level = 0.f; | |
137 return p; | |
138 } | |
139 | |
140 bool hasReferenceFrame() const { return m_haveReferenceFrame; } | |
141 sv_frame_t getReferenceFrame() const { return m_referenceFrame; } | |
142 | |
143 bool referenceFrameDiffers() const { // from event frame | |
144 return m_haveReferenceFrame && (m_referenceFrame != m_frame); | |
145 } | |
146 | |
147 Event withReferenceFrame(sv_frame_t frame) const { | |
148 Event p(*this); | |
149 p.m_haveReferenceFrame = true; | |
150 p.m_referenceFrame = frame; | |
151 return p; | |
152 } | |
153 Event withoutReferenceFrame() const { | |
154 Event p(*this); | |
155 p.m_haveReferenceFrame = false; | |
156 p.m_referenceFrame = 0; | |
157 return p; | |
158 } | |
159 | |
160 bool operator==(const Event &p) const { | |
161 | |
162 if (m_frame != p.m_frame) return false; | |
163 if (m_duration != p.m_duration) return false; | |
164 | |
165 if (m_haveValue != p.m_haveValue) return false; | |
166 if (m_haveValue && (m_value != p.m_value)) return false; | |
167 | |
168 if (m_haveLevel != p.m_haveLevel) return false; | |
169 if (m_haveLevel && (m_level != p.m_level)) return false; | |
170 | |
171 if (m_haveReferenceFrame != p.m_haveReferenceFrame) return false; | |
172 if (m_haveReferenceFrame && | |
173 (m_referenceFrame != p.m_referenceFrame)) return false; | |
174 | |
175 if (m_label != p.m_label) return false; | |
176 | |
177 return true; | |
178 } | |
179 | |
180 bool operator<(const Event &p) const { | |
181 | |
182 if (m_frame != p.m_frame) return m_frame < p.m_frame; | |
183 if (m_duration != p.m_duration) return m_duration < p.m_duration; | |
184 | |
185 // events without a property sort before events with that property | |
186 | |
187 if (m_haveValue != p.m_haveValue) return !m_haveValue; | |
188 if (m_haveValue && (m_value != p.m_value)) return m_value < p.m_value; | |
189 | |
190 if (m_haveLevel != p.m_haveLevel) return !m_haveLevel; | |
191 if (m_haveLevel && (m_level != p.m_level)) return m_level < p.m_level; | |
192 | |
193 if (m_haveReferenceFrame != p.m_haveReferenceFrame) { | |
194 return !m_haveReferenceFrame; | |
195 } | |
196 if (m_haveReferenceFrame && (m_referenceFrame != p.m_referenceFrame)) { | |
197 return m_referenceFrame < p.m_referenceFrame; | |
198 } | |
199 | |
200 return m_label < p.m_label; | |
201 } | |
202 | |
203 void toXml(QTextStream &stream, | |
204 QString indent = "", | |
205 QString extraAttributes = "") const { | |
206 | |
207 // For I/O purposes these are points, not events | |
208 stream << indent << QString("<point frame=\"%1\" ").arg(m_frame); | |
209 if (m_haveValue) stream << QString("value=\"%1\" ").arg(m_value); | |
210 if (m_duration) stream << QString("duration=\"%1\" ").arg(m_duration); | |
211 if (m_haveLevel) stream << QString("level=\"%1\" ").arg(m_level); | |
212 if (m_haveReferenceFrame) stream << QString("referenceFrame=\"%1\" ") | |
213 .arg(m_referenceFrame); | |
214 stream << QString("label=\"%1\" ") | |
215 .arg(XmlExportable::encodeEntities(m_label)); | |
216 stream << extraAttributes << ">\n"; | |
217 } | |
218 | |
219 QString toXmlString(QString indent = "", | |
220 QString extraAttributes = "") const { | |
221 QString s; | |
222 QTextStream out(&s); | |
223 toXml(out, indent, extraAttributes); | |
224 out.flush(); | |
225 return s; | |
226 } | |
227 | |
228 NoteData toNoteData(sv_samplerate_t sampleRate, bool valueIsMidiPitch) { | |
229 | |
230 sv_frame_t duration; | |
231 if (m_duration > 0) { | |
232 duration = m_duration; | |
233 } else { | |
234 duration = sv_frame_t(sampleRate / 6); // arbitrary short duration | |
235 } | |
236 | |
237 int midiPitch; | |
238 float frequency = 0.f; | |
239 if (m_haveValue) { | |
240 if (valueIsMidiPitch) { | |
241 midiPitch = int(roundf(m_value)); | |
242 } else { | |
243 frequency = m_value; | |
244 midiPitch = Pitch::getPitchForFrequency(frequency); | |
245 } | |
246 } else { | |
247 midiPitch = 64; | |
248 valueIsMidiPitch = true; | |
249 } | |
250 | |
251 int velocity = 100; | |
252 if (m_haveLevel) { | |
253 if (m_level > 0.f && m_level <= 1.f) { | |
254 velocity = int(roundf(m_level * 127.f)); | |
255 } | |
256 } | |
257 | |
258 NoteData n(m_frame, duration, midiPitch, velocity); | |
259 n.isMidiPitchQuantized = valueIsMidiPitch; | |
260 if (!valueIsMidiPitch) { | |
261 n.frequency = frequency; | |
262 } | |
263 | |
264 return n; | |
265 } | |
266 | |
267 private: | |
268 // The order of fields here is chosen to minimise overall size of struct. | |
269 // We potentially store very many of these objects. | |
270 // If you change something, check what difference it makes to packing. | |
271 bool m_haveValue : 1; | |
272 bool m_haveLevel : 1; | |
273 bool m_haveReferenceFrame : 1; | |
274 float m_value; | |
275 float m_level; | |
276 sv_frame_t m_frame; | |
277 sv_frame_t m_duration; | |
278 sv_frame_t m_referenceFrame; | |
279 QString m_label; | |
280 }; | |
281 | |
282 typedef std::vector<Event> EventVector; | |
283 | |
284 #endif |