svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 This file copyright 2006 Chris Cannam. 00008 00009 This program is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU General Public License as 00011 published by the Free Software Foundation; either version 2 of the 00012 License, or (at your option) any later version. See the file 00013 COPYING included with this distribution for more information. 00014 */ 00015 00016 #ifndef _NOTE_MODEL_H_ 00017 #define _NOTE_MODEL_H_ 00018 00019 #include "IntervalModel.h" 00020 #include "NoteData.h" 00021 #include "base/RealTime.h" 00022 #include "base/PlayParameterRepository.h" 00023 #include "base/Pitch.h" 00024 00038 struct Note 00039 { 00040 public: 00041 Note(long _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { } 00042 Note(long _frame, float _value, int _duration, float _level, QString _label) : 00043 frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { } 00044 00045 int getDimensions() const { return 3; } 00046 00047 long frame; 00048 float value; 00049 int duration; 00050 float level; 00051 QString label; 00052 00053 QString getLabel() const { return label; } 00054 00055 void toXml(QTextStream &stream, 00056 QString indent = "", 00057 QString extraAttributes = "") const 00058 { 00059 stream << 00060 QString("%1<point frame=\"%2\" value=\"%3\" duration=\"%4\" level=\"%5\" label=\"%6\" %7/>\n") 00061 .arg(indent).arg(frame).arg(value).arg(duration).arg(level) 00062 .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes); 00063 } 00064 00065 QString toDelimitedDataString(QString delimiter, int sampleRate) const 00066 { 00067 QStringList list; 00068 list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str(); 00069 list << QString("%1").arg(value); 00070 list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str(); 00071 list << QString("%1").arg(level); 00072 if (label != "") list << label; 00073 return list.join(delimiter); 00074 } 00075 00076 struct Comparator { 00077 bool operator()(const Note &p1, 00078 const Note &p2) const { 00079 if (p1.frame != p2.frame) return p1.frame < p2.frame; 00080 if (p1.value != p2.value) return p1.value < p2.value; 00081 if (p1.duration != p2.duration) return p1.duration < p2.duration; 00082 if (p1.level != p2.level) return p1.level < p2.level; 00083 return p1.label < p2.label; 00084 } 00085 }; 00086 00087 struct OrderComparator { 00088 bool operator()(const Note &p1, 00089 const Note &p2) const { 00090 return p1.frame < p2.frame; 00091 } 00092 }; 00093 }; 00094 00095 00096 class NoteModel : public IntervalModel<Note>, public NoteExportable 00097 { 00098 Q_OBJECT 00099 00100 public: 00101 NoteModel(int sampleRate, int resolution, 00102 bool notifyOnAdd = true) : 00103 IntervalModel<Note>(sampleRate, resolution, notifyOnAdd), 00104 m_valueQuantization(0) 00105 { 00106 PlayParameterRepository::getInstance()->addPlayable(this); 00107 } 00108 00109 NoteModel(int sampleRate, int resolution, 00110 float valueMinimum, float valueMaximum, 00111 bool notifyOnAdd = true) : 00112 IntervalModel<Note>(sampleRate, resolution, 00113 valueMinimum, valueMaximum, 00114 notifyOnAdd), 00115 m_valueQuantization(0) 00116 { 00117 PlayParameterRepository::getInstance()->addPlayable(this); 00118 } 00119 00120 virtual ~NoteModel() 00121 { 00122 PlayParameterRepository::getInstance()->removePlayable(this); 00123 } 00124 00125 float getValueQuantization() const { return m_valueQuantization; } 00126 void setValueQuantization(float q) { m_valueQuantization = q; } 00127 00128 QString getTypeName() const { return tr("Note"); } 00129 00130 virtual bool canPlay() const { return true; } 00131 00132 virtual QString getDefaultPlayClipId() const 00133 { 00134 return "elecpiano"; 00135 } 00136 00137 virtual void toXml(QTextStream &out, 00138 QString indent = "", 00139 QString extraAttributes = "") const 00140 { 00141 std::cerr << "NoteModel::toXml: extraAttributes = \"" 00142 << extraAttributes.toStdString() << std::endl; 00143 00144 IntervalModel<Note>::toXml 00145 (out, 00146 indent, 00147 QString("%1 subtype=\"note\" valueQuantization=\"%2\"") 00148 .arg(extraAttributes).arg(m_valueQuantization)); 00149 } 00150 00155 virtual int getColumnCount() const 00156 { 00157 return 6; 00158 } 00159 00160 virtual QString getHeading(int column) const 00161 { 00162 switch (column) { 00163 case 0: return tr("Time"); 00164 case 1: return tr("Frame"); 00165 case 2: return tr("Pitch"); 00166 case 3: return tr("Duration"); 00167 case 4: return tr("Level"); 00168 case 5: return tr("Label"); 00169 default: return tr("Unknown"); 00170 } 00171 } 00172 00173 virtual QVariant getData(int row, int column, int role) const 00174 { 00175 if (column < 4) { 00176 return IntervalModel<Note>::getData(row, column, role); 00177 } 00178 00179 PointListConstIterator i = getPointListIteratorForRow(row); 00180 if (i == m_points.end()) return QVariant(); 00181 00182 switch (column) { 00183 case 4: return i->level; 00184 case 5: return i->label; 00185 default: return QVariant(); 00186 } 00187 } 00188 00189 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role) 00190 { 00191 if (column < 4) { 00192 return IntervalModel<Note>::getSetDataCommand 00193 (row, column, value, role); 00194 } 00195 00196 if (role != Qt::EditRole) return 0; 00197 PointListConstIterator i = getPointListIteratorForRow(row); 00198 if (i == m_points.end()) return 0; 00199 EditCommand *command = new EditCommand(this, tr("Edit Data")); 00200 00201 Point point(*i); 00202 command->deletePoint(point); 00203 00204 switch (column) { 00205 case 4: point.level = value.toDouble(); break; 00206 case 5: point.label = value.toString(); break; 00207 } 00208 00209 command->addPoint(point); 00210 return command->finish(); 00211 } 00212 00213 virtual SortType getSortType(int column) const 00214 { 00215 if (column == 5) return SortAlphabetical; 00216 return SortNumeric; 00217 } 00218 00223 NoteList getNotes() const { 00224 return getNotesWithin(getStartFrame(), getEndFrame()); 00225 } 00226 00227 NoteList getNotesWithin(int startFrame, int endFrame) const { 00228 00229 PointList points = getPoints(startFrame, endFrame); 00230 NoteList notes; 00231 00232 for (PointList::iterator pli = 00233 points.begin(); pli != points.end(); ++pli) { 00234 00235 int duration = pli->duration; 00236 if (duration == 0 || duration == 1) { 00237 duration = getSampleRate() / 20; 00238 } 00239 00240 int pitch = lrintf(pli->value); 00241 00242 int velocity = 100; 00243 if (pli->level > 0.f && pli->level <= 1.f) { 00244 velocity = lrintf(pli->level * 127); 00245 } 00246 00247 NoteData note(pli->frame, duration, pitch, velocity); 00248 00249 if (getScaleUnits() == "Hz") { 00250 note.frequency = pli->value; 00251 note.midiPitch = Pitch::getPitchForFrequency(note.frequency); 00252 note.isMidiPitchQuantized = false; 00253 } 00254 00255 notes.push_back(note); 00256 } 00257 00258 return notes; 00259 } 00260 00261 protected: 00262 float m_valueQuantization; 00263 }; 00264 00265 #endif