Mercurial > hg > svcore
comparison data/model/FlexiNoteModel.h @ 874:862fe7b20df7 tony_integration
Merge from tonioni branch
author | Chris Cannam |
---|---|
date | Tue, 28 Jan 2014 15:01:54 +0000 |
parents | 4dce43294740 |
children | ecb34638ce1b |
comparison
equal
deleted
inserted
replaced
862:786ee8d1f30e | 874:862fe7b20df7 |
---|---|
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 _FLEXINOTE_MODEL_H_ | |
17 #define _FLEXINOTE_MODEL_H_ | |
18 | |
19 #include "IntervalModel.h" | |
20 #include "NoteData.h" | |
21 #include "base/RealTime.h" | |
22 #include "base/Pitch.h" | |
23 #include "base/PlayParameterRepository.h" | |
24 | |
25 /** | |
26 * FlexiNoteModel -- a concrete IntervalModel for notes. | |
27 */ | |
28 | |
29 /** | |
30 * Extension of the NoteModel for more flexible note interaction. | |
31 * The original NoteModel rationale is given below, will need to be | |
32 * updated for FlexiNoteModel: | |
33 * | |
34 * Note type for use in a sparse model. All we mean by a "note" is | |
35 * something that has an onset time, a single value, a duration, and a | |
36 * level. Like other points, it can also have a label. With this | |
37 * point type, the model can be thought of as representing a simple | |
38 * MIDI-type piano roll, except that the y coordinates (values) do not | |
39 * have to be discrete integers. | |
40 */ | |
41 | |
42 struct FlexiNote | |
43 { | |
44 public: | |
45 FlexiNote(long _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { } | |
46 FlexiNote(long _frame, float _value, size_t _duration, float _level, QString _label) : | |
47 frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { } | |
48 | |
49 int getDimensions() const { return 3; } | |
50 | |
51 long frame; | |
52 float value; | |
53 size_t duration; | |
54 float level; | |
55 QString label; | |
56 | |
57 QString getLabel() const { return label; } | |
58 | |
59 void toXml(QTextStream &stream, | |
60 QString indent = "", | |
61 QString extraAttributes = "") const | |
62 { | |
63 stream << | |
64 QString("%1<point frame=\"%2\" value=\"%3\" duration=\"%4\" level=\"%5\" label=\"%6\" %7/>\n") | |
65 .arg(indent).arg(frame).arg(value).arg(duration).arg(level) | |
66 .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes); | |
67 } | |
68 | |
69 QString toDelimitedDataString(QString delimiter, size_t sampleRate) const | |
70 { | |
71 QStringList list; | |
72 list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str(); | |
73 list << QString("%1").arg(value); | |
74 list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str(); | |
75 list << QString("%1").arg(level); | |
76 if (label != "") list << label; | |
77 return list.join(delimiter); | |
78 } | |
79 | |
80 struct Comparator { | |
81 bool operator()(const FlexiNote &p1, | |
82 const FlexiNote &p2) const { | |
83 if (p1.frame != p2.frame) return p1.frame < p2.frame; | |
84 if (p1.value != p2.value) return p1.value < p2.value; | |
85 if (p1.duration != p2.duration) return p1.duration < p2.duration; | |
86 if (p1.level != p2.level) return p1.level < p2.level; | |
87 return p1.label < p2.label; | |
88 } | |
89 }; | |
90 | |
91 struct OrderComparator { | |
92 bool operator()(const FlexiNote &p1, | |
93 const FlexiNote &p2) const { | |
94 return p1.frame < p2.frame; | |
95 } | |
96 }; | |
97 }; | |
98 | |
99 | |
100 class FlexiNoteModel : public IntervalModel<FlexiNote>, public NoteExportable | |
101 { | |
102 Q_OBJECT | |
103 | |
104 public: | |
105 FlexiNoteModel(size_t sampleRate, size_t resolution, | |
106 bool notifyOnAdd = true) : | |
107 IntervalModel<FlexiNote>(sampleRate, resolution, notifyOnAdd), | |
108 m_valueQuantization(0) | |
109 { | |
110 PlayParameterRepository::getInstance()->addPlayable(this); | |
111 } | |
112 | |
113 FlexiNoteModel(size_t sampleRate, size_t resolution, | |
114 float valueMinimum, float valueMaximum, | |
115 bool notifyOnAdd = true) : | |
116 IntervalModel<FlexiNote>(sampleRate, resolution, | |
117 valueMinimum, valueMaximum, | |
118 notifyOnAdd), | |
119 m_valueQuantization(0) | |
120 { | |
121 PlayParameterRepository::getInstance()->addPlayable(this); | |
122 } | |
123 | |
124 virtual ~FlexiNoteModel() | |
125 { | |
126 PlayParameterRepository::getInstance()->removePlayable(this); | |
127 } | |
128 | |
129 float getValueQuantization() const { return m_valueQuantization; } | |
130 void setValueQuantization(float q) { m_valueQuantization = q; } | |
131 float getValueMinimum() const { return 33; } | |
132 float getValueMaximum() const { return 88; } | |
133 | |
134 QString getTypeName() const { return tr("FlexiNote"); } | |
135 | |
136 virtual bool canPlay() const { return true; } | |
137 | |
138 virtual QString getDefaultPlayClipId() const | |
139 { | |
140 return "elecpiano"; | |
141 } | |
142 | |
143 virtual void toXml(QTextStream &out, | |
144 QString indent = "", | |
145 QString extraAttributes = "") const | |
146 { | |
147 std::cerr << "FlexiNoteModel::toXml: extraAttributes = \"" | |
148 << extraAttributes.toStdString() << std::endl; | |
149 | |
150 IntervalModel<FlexiNote>::toXml | |
151 (out, | |
152 indent, | |
153 QString("%1 subtype=\"note\" valueQuantization=\"%2\"") | |
154 .arg(extraAttributes).arg(m_valueQuantization)); | |
155 } | |
156 | |
157 /** | |
158 * TabularModel methods. | |
159 */ | |
160 | |
161 virtual int getColumnCount() const | |
162 { | |
163 return 6; | |
164 } | |
165 | |
166 virtual QString getHeading(int column) const | |
167 { | |
168 switch (column) { | |
169 case 0: return tr("Time"); | |
170 case 1: return tr("Frame"); | |
171 case 2: return tr("Pitch"); | |
172 case 3: return tr("Duration"); | |
173 case 4: return tr("Level"); | |
174 case 5: return tr("Label"); | |
175 default: return tr("Unknown"); | |
176 } | |
177 } | |
178 | |
179 virtual QVariant getData(int row, int column, int role) const | |
180 { | |
181 if (column < 4) { | |
182 return IntervalModel<FlexiNote>::getData(row, column, role); | |
183 } | |
184 | |
185 PointListConstIterator i = getPointListIteratorForRow(row); | |
186 if (i == m_points.end()) return QVariant(); | |
187 | |
188 switch (column) { | |
189 case 4: return i->level; | |
190 case 5: return i->label; | |
191 default: return QVariant(); | |
192 } | |
193 } | |
194 | |
195 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role) | |
196 { | |
197 if (column < 4) { | |
198 return IntervalModel<FlexiNote>::getSetDataCommand | |
199 (row, column, value, role); | |
200 } | |
201 | |
202 if (role != Qt::EditRole) return 0; | |
203 PointListConstIterator i = getPointListIteratorForRow(row); | |
204 if (i == m_points.end()) return 0; | |
205 EditCommand *command = new EditCommand(this, tr("Edit Data")); | |
206 | |
207 Point point(*i); | |
208 command->deletePoint(point); | |
209 | |
210 switch (column) { | |
211 case 4: point.level = value.toDouble(); break; | |
212 case 5: point.label = value.toString(); break; | |
213 } | |
214 | |
215 command->addPoint(point); | |
216 return command->finish(); | |
217 } | |
218 | |
219 virtual SortType getSortType(int column) const | |
220 { | |
221 if (column == 5) return SortAlphabetical; | |
222 return SortNumeric; | |
223 } | |
224 | |
225 /** | |
226 * NoteExportable methods. | |
227 */ | |
228 | |
229 NoteList getNotes() const { | |
230 return getNotes(getStartFrame(), getEndFrame()); | |
231 } | |
232 | |
233 NoteList getNotes(size_t startFrame, size_t endFrame) const { | |
234 | |
235 PointList points = getPoints(startFrame, endFrame); | |
236 NoteList notes; | |
237 | |
238 for (PointList::iterator pli = | |
239 points.begin(); pli != points.end(); ++pli) { | |
240 | |
241 size_t duration = pli->duration; | |
242 if (duration == 0 || duration == 1) { | |
243 duration = getSampleRate() / 20; | |
244 } | |
245 | |
246 int pitch = lrintf(pli->value); | |
247 | |
248 int velocity = 100; | |
249 if (pli->level > 0.f && pli->level <= 1.f) { | |
250 velocity = lrintf(pli->level * 127); | |
251 } | |
252 | |
253 NoteData note(pli->frame, duration, pitch, velocity); | |
254 | |
255 if (getScaleUnits() == "Hz") { | |
256 note.frequency = pli->value; | |
257 note.midiPitch = Pitch::getPitchForFrequency(note.frequency); | |
258 note.isMidiPitchQuantized = false; | |
259 } | |
260 | |
261 notes.push_back(note); | |
262 } | |
263 | |
264 return notes; | |
265 } | |
266 | |
267 protected: | |
268 float m_valueQuantization; | |
269 }; | |
270 | |
271 #endif |