annotate data/model/FlexiNoteModel.h @ 876:47aa3aeb687b tonioni

For outputs with unknown bin count or multiple bins with variable sample rate, create additional output models for bins beyond the first
author Chris Cannam
date Wed, 29 Jan 2014 09:31:22 +0000
parents 4dce43294740
children ecb34638ce1b
rev   line source
Chris@147 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@147 2
Chris@147 3 /*
Chris@147 4 Sonic Visualiser
Chris@147 5 An audio file viewer and annotation editor.
Chris@147 6 Centre for Digital Music, Queen Mary, University of London.
Chris@147 7 This file copyright 2006 Chris Cannam.
Chris@147 8
Chris@147 9 This program is free software; you can redistribute it and/or
Chris@147 10 modify it under the terms of the GNU General Public License as
Chris@147 11 published by the Free Software Foundation; either version 2 of the
Chris@147 12 License, or (at your option) any later version. See the file
Chris@147 13 COPYING included with this distribution for more information.
Chris@147 14 */
Chris@147 15
matthiasm@774 16 #ifndef _FLEXINOTE_MODEL_H_
matthiasm@774 17 #define _FLEXINOTE_MODEL_H_
Chris@147 18
Chris@437 19 #include "IntervalModel.h"
Chris@852 20 #include "NoteData.h"
Chris@391 21 #include "base/RealTime.h"
Chris@852 22 #include "base/Pitch.h"
Chris@150 23 #include "base/PlayParameterRepository.h"
Chris@147 24
Chris@147 25 /**
matthiasm@774 26 * FlexiNoteModel -- a concrete IntervalModel for notes.
Chris@441 27 */
Chris@441 28
Chris@441 29 /**
matthiasm@774 30 * Extension of the NoteModel for more flexible note interaction.
matthiasm@774 31 * The original NoteModel rationale is given below, will need to be
matthiasm@774 32 * updated for FlexiNoteModel:
matthiasm@774 33 *
Chris@441 34 * Note type for use in a sparse model. All we mean by a "note" is
Chris@441 35 * something that has an onset time, a single value, a duration, and a
Chris@441 36 * level. Like other points, it can also have a label. With this
Chris@441 37 * point type, the model can be thought of as representing a simple
Chris@441 38 * MIDI-type piano roll, except that the y coordinates (values) do not
Chris@441 39 * have to be discrete integers.
Chris@147 40 */
Chris@147 41
matthiasm@774 42 struct FlexiNote
Chris@147 43 {
Chris@147 44 public:
matthiasm@774 45 FlexiNote(long _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { }
matthiasm@774 46 FlexiNote(long _frame, float _value, size_t _duration, float _level, QString _label) :
Chris@340 47 frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { }
Chris@147 48
Chris@147 49 int getDimensions() const { return 3; }
Chris@147 50
Chris@147 51 long frame;
Chris@147 52 float value;
Chris@147 53 size_t duration;
Chris@340 54 float level;
Chris@147 55 QString label;
Chris@147 56
Chris@338 57 QString getLabel() const { return label; }
Chris@338 58
Chris@314 59 void toXml(QTextStream &stream,
Chris@314 60 QString indent = "",
Chris@314 61 QString extraAttributes = "") const
Chris@147 62 {
Chris@314 63 stream <<
Chris@340 64 QString("%1<point frame=\"%2\" value=\"%3\" duration=\"%4\" level=\"%5\" label=\"%6\" %7/>\n")
Chris@627 65 .arg(indent).arg(frame).arg(value).arg(duration).arg(level)
Chris@627 66 .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes);
Chris@147 67 }
Chris@147 68
Chris@147 69 QString toDelimitedDataString(QString delimiter, size_t sampleRate) const
Chris@147 70 {
Chris@147 71 QStringList list;
Chris@147 72 list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
Chris@147 73 list << QString("%1").arg(value);
Chris@340 74 list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str();
Chris@340 75 list << QString("%1").arg(level);
Chris@318 76 if (label != "") list << label;
Chris@147 77 return list.join(delimiter);
Chris@147 78 }
Chris@147 79
Chris@147 80 struct Comparator {
matthiasm@774 81 bool operator()(const FlexiNote &p1,
matthiasm@774 82 const FlexiNote &p2) const {
Chris@147 83 if (p1.frame != p2.frame) return p1.frame < p2.frame;
Chris@147 84 if (p1.value != p2.value) return p1.value < p2.value;
Chris@147 85 if (p1.duration != p2.duration) return p1.duration < p2.duration;
Chris@340 86 if (p1.level != p2.level) return p1.level < p2.level;
Chris@147 87 return p1.label < p2.label;
Chris@147 88 }
Chris@147 89 };
Chris@147 90
Chris@147 91 struct OrderComparator {
matthiasm@774 92 bool operator()(const FlexiNote &p1,
matthiasm@774 93 const FlexiNote &p2) const {
Chris@147 94 return p1.frame < p2.frame;
Chris@147 95 }
Chris@147 96 };
Chris@147 97 };
Chris@147 98
Chris@147 99
Chris@852 100 class FlexiNoteModel : public IntervalModel<FlexiNote>, public NoteExportable
Chris@147 101 {
Chris@423 102 Q_OBJECT
Chris@423 103
Chris@147 104 public:
matthiasm@774 105 FlexiNoteModel(size_t sampleRate, size_t resolution,
Chris@256 106 bool notifyOnAdd = true) :
matthiasm@774 107 IntervalModel<FlexiNote>(sampleRate, resolution, notifyOnAdd),
Chris@256 108 m_valueQuantization(0)
Chris@256 109 {
Chris@391 110 PlayParameterRepository::getInstance()->addPlayable(this);
Chris@256 111 }
Chris@256 112
matthiasm@774 113 FlexiNoteModel(size_t sampleRate, size_t resolution,
Chris@147 114 float valueMinimum, float valueMaximum,
Chris@147 115 bool notifyOnAdd = true) :
matthiasm@774 116 IntervalModel<FlexiNote>(sampleRate, resolution,
Chris@437 117 valueMinimum, valueMaximum,
Chris@437 118 notifyOnAdd),
Chris@147 119 m_valueQuantization(0)
Chris@147 120 {
Chris@391 121 PlayParameterRepository::getInstance()->addPlayable(this);
Chris@391 122 }
Chris@391 123
matthiasm@774 124 virtual ~FlexiNoteModel()
Chris@391 125 {
Chris@391 126 PlayParameterRepository::getInstance()->removePlayable(this);
Chris@147 127 }
Chris@147 128
Chris@147 129 float getValueQuantization() const { return m_valueQuantization; }
Chris@147 130 void setValueQuantization(float q) { m_valueQuantization = q; }
matthiasm@791 131 float getValueMinimum() const { return 33; }
matthiasm@791 132 float getValueMaximum() const { return 88; }
Chris@147 133
matthiasm@774 134 QString getTypeName() const { return tr("FlexiNote"); }
Chris@345 135
Chris@391 136 virtual bool canPlay() const { return true; }
Chris@391 137
Chris@866 138 virtual QString getDefaultPlayClipId() const
Chris@391 139 {
matthiasm@873 140 return "elecpiano";
Chris@391 141 }
Chris@391 142
Chris@288 143 virtual void toXml(QTextStream &out,
Chris@288 144 QString indent = "",
Chris@288 145 QString extraAttributes = "") const
Chris@147 146 {
matthiasm@774 147 std::cerr << "FlexiNoteModel::toXml: extraAttributes = \""
Chris@318 148 << extraAttributes.toStdString() << std::endl;
Chris@318 149
matthiasm@774 150 IntervalModel<FlexiNote>::toXml
Chris@288 151 (out,
Chris@288 152 indent,
Chris@452 153 QString("%1 subtype=\"note\" valueQuantization=\"%2\"")
Chris@147 154 .arg(extraAttributes).arg(m_valueQuantization));
Chris@147 155 }
Chris@147 156
Chris@424 157 /**
Chris@424 158 * TabularModel methods.
Chris@424 159 */
Chris@424 160
Chris@424 161 virtual int getColumnCount() const
Chris@424 162 {
Chris@424 163 return 6;
Chris@424 164 }
Chris@424 165
Chris@424 166 virtual QString getHeading(int column) const
Chris@424 167 {
Chris@424 168 switch (column) {
Chris@424 169 case 0: return tr("Time");
Chris@424 170 case 1: return tr("Frame");
Chris@424 171 case 2: return tr("Pitch");
Chris@424 172 case 3: return tr("Duration");
Chris@424 173 case 4: return tr("Level");
Chris@424 174 case 5: return tr("Label");
Chris@424 175 default: return tr("Unknown");
Chris@424 176 }
Chris@424 177 }
Chris@424 178
Chris@424 179 virtual QVariant getData(int row, int column, int role) const
Chris@424 180 {
Chris@437 181 if (column < 4) {
matthiasm@774 182 return IntervalModel<FlexiNote>::getData(row, column, role);
Chris@425 183 }
Chris@425 184
Chris@606 185 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@424 186 if (i == m_points.end()) return QVariant();
Chris@424 187
Chris@424 188 switch (column) {
Chris@424 189 case 4: return i->level;
Chris@424 190 case 5: return i->label;
Chris@424 191 default: return QVariant();
Chris@424 192 }
Chris@424 193 }
Chris@424 194
Chris@424 195 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
Chris@424 196 {
Chris@437 197 if (column < 4) {
matthiasm@774 198 return IntervalModel<FlexiNote>::getSetDataCommand
Chris@425 199 (row, column, value, role);
Chris@425 200 }
Chris@425 201
Chris@740 202 if (role != Qt::EditRole) return 0;
Chris@606 203 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@740 204 if (i == m_points.end()) return 0;
Chris@424 205 EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@424 206
Chris@424 207 Point point(*i);
Chris@424 208 command->deletePoint(point);
Chris@424 209
Chris@424 210 switch (column) {
Chris@424 211 case 4: point.level = value.toDouble(); break;
Chris@424 212 case 5: point.label = value.toString(); break;
Chris@424 213 }
Chris@424 214
Chris@424 215 command->addPoint(point);
Chris@424 216 return command->finish();
Chris@424 217 }
Chris@424 218
Chris@424 219 virtual SortType getSortType(int column) const
Chris@424 220 {
Chris@424 221 if (column == 5) return SortAlphabetical;
Chris@424 222 return SortNumeric;
Chris@424 223 }
Chris@424 224
Chris@852 225 /**
Chris@852 226 * NoteExportable methods.
Chris@852 227 */
Chris@852 228
Chris@852 229 NoteList getNotes() const {
Chris@852 230 return getNotes(getStartFrame(), getEndFrame());
Chris@852 231 }
Chris@852 232
Chris@852 233 NoteList getNotes(size_t startFrame, size_t endFrame) const {
Chris@852 234
Chris@852 235 PointList points = getPoints(startFrame, endFrame);
Chris@852 236 NoteList notes;
Chris@852 237
Chris@852 238 for (PointList::iterator pli =
Chris@852 239 points.begin(); pli != points.end(); ++pli) {
Chris@852 240
Chris@852 241 size_t duration = pli->duration;
Chris@852 242 if (duration == 0 || duration == 1) {
Chris@852 243 duration = getSampleRate() / 20;
Chris@852 244 }
Chris@852 245
Chris@852 246 int pitch = lrintf(pli->value);
Chris@852 247
Chris@852 248 int velocity = 100;
Chris@852 249 if (pli->level > 0.f && pli->level <= 1.f) {
Chris@852 250 velocity = lrintf(pli->level * 127);
Chris@852 251 }
Chris@852 252
Chris@852 253 NoteData note(pli->frame, duration, pitch, velocity);
Chris@852 254
Chris@852 255 if (getScaleUnits() == "Hz") {
Chris@852 256 note.frequency = pli->value;
Chris@852 257 note.midiPitch = Pitch::getPitchForFrequency(note.frequency);
Chris@852 258 note.isMidiPitchQuantized = false;
Chris@852 259 }
Chris@852 260
Chris@852 261 notes.push_back(note);
Chris@852 262 }
Chris@852 263
Chris@852 264 return notes;
Chris@852 265 }
Chris@852 266
Chris@147 267 protected:
Chris@147 268 float m_valueQuantization;
Chris@147 269 };
Chris@147 270
Chris@147 271 #endif