annotate data/model/SparseOneDimensionalModel.h @ 1008:d9e0e59a1581

When using an aggregate model to pass data to a transform, zero-pad the shorter input to the duration of the longer rather than truncating the longer. (This is better behaviour for e.g. MATCH, and in any case the code was previously truncating incorrectly and ending up with garbage data at the end.)
author Chris Cannam
date Fri, 14 Nov 2014 13:51:33 +0000
parents 59e7fe1b1003
children cc27f35aa75c
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
Chris@147 16 #ifndef _SPARSE_ONE_DIMENSIONAL_MODEL_H_
Chris@147 17 #define _SPARSE_ONE_DIMENSIONAL_MODEL_H_
Chris@147 18
Chris@147 19 #include "SparseModel.h"
Chris@852 20 #include "NoteData.h"
Chris@150 21 #include "base/PlayParameterRepository.h"
Chris@147 22 #include "base/RealTime.h"
Chris@147 23
Chris@387 24 #include <QStringList>
Chris@387 25
Chris@147 26 struct OneDimensionalPoint
Chris@147 27 {
Chris@147 28 public:
Chris@929 29 OneDimensionalPoint(int _frame) : frame(_frame) { }
Chris@929 30 OneDimensionalPoint(int _frame, QString _label) : frame(_frame), label(_label) { }
Chris@147 31
Chris@147 32 int getDimensions() const { return 1; }
Chris@147 33
Chris@929 34 int frame;
Chris@147 35 QString label;
Chris@338 36
Chris@338 37 QString getLabel() const { return label; }
Chris@338 38
Chris@314 39 void toXml(QTextStream &stream,
Chris@314 40 QString indent = "",
Chris@314 41 QString extraAttributes = "") const
Chris@147 42 {
Chris@314 43 stream << QString("%1<point frame=\"%2\" label=\"%3\" %4/>\n")
Chris@603 44 .arg(indent).arg(frame).arg(XmlExportable::encodeEntities(label))
Chris@603 45 .arg(extraAttributes);
Chris@147 46 }
Chris@147 47
Chris@929 48 QString toDelimitedDataString(QString delimiter, int sampleRate) const
Chris@147 49 {
Chris@147 50 QStringList list;
Chris@147 51 list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
Chris@318 52 if (label != "") list << label;
Chris@147 53 return list.join(delimiter);
Chris@147 54 }
Chris@147 55
Chris@147 56 struct Comparator {
Chris@147 57 bool operator()(const OneDimensionalPoint &p1,
Chris@147 58 const OneDimensionalPoint &p2) const {
Chris@147 59 if (p1.frame != p2.frame) return p1.frame < p2.frame;
Chris@147 60 return p1.label < p2.label;
Chris@147 61 }
Chris@147 62 };
Chris@147 63
Chris@147 64 struct OrderComparator {
Chris@147 65 bool operator()(const OneDimensionalPoint &p1,
Chris@147 66 const OneDimensionalPoint &p2) const {
Chris@147 67 return p1.frame < p2.frame;
Chris@147 68 }
Chris@147 69 };
Chris@147 70 };
Chris@147 71
Chris@147 72
Chris@852 73 class SparseOneDimensionalModel : public SparseModel<OneDimensionalPoint>,
Chris@852 74 public NoteExportable
Chris@147 75 {
Chris@423 76 Q_OBJECT
Chris@423 77
Chris@147 78 public:
Chris@929 79 SparseOneDimensionalModel(int sampleRate, int resolution,
Chris@147 80 bool notifyOnAdd = true) :
Chris@147 81 SparseModel<OneDimensionalPoint>(sampleRate, resolution, notifyOnAdd)
Chris@147 82 {
Chris@391 83 PlayParameterRepository::getInstance()->addPlayable(this);
Chris@391 84 }
Chris@391 85
Chris@391 86 virtual ~SparseOneDimensionalModel()
Chris@391 87 {
Chris@391 88 PlayParameterRepository::getInstance()->removePlayable(this);
Chris@391 89 }
Chris@391 90
Chris@391 91 virtual bool canPlay() const { return true; }
Chris@391 92
Chris@866 93 virtual QString getDefaultPlayClipId() const
Chris@391 94 {
Chris@864 95 return "tap";
Chris@147 96 }
Chris@147 97
Chris@420 98 int getIndexOf(const Point &point)
Chris@420 99 {
Chris@147 100 // slow
Chris@147 101 int i = 0;
Chris@147 102 Point::Comparator comparator;
Chris@147 103 for (PointList::const_iterator j = m_points.begin();
Chris@147 104 j != m_points.end(); ++j, ++i) {
Chris@147 105 if (!comparator(*j, point) && !comparator(point, *j)) return i;
Chris@147 106 }
Chris@147 107 return -1;
Chris@147 108 }
Chris@345 109
Chris@345 110 QString getTypeName() const { return tr("Sparse 1-D"); }
Chris@420 111
Chris@420 112 /**
Chris@420 113 * TabularModel methods.
Chris@420 114 */
Chris@420 115
Chris@420 116 virtual int getColumnCount() const
Chris@420 117 {
Chris@420 118 return 3;
Chris@420 119 }
Chris@420 120
Chris@420 121 virtual QString getHeading(int column) const
Chris@420 122 {
Chris@420 123 switch (column) {
Chris@420 124 case 0: return tr("Time");
Chris@420 125 case 1: return tr("Frame");
Chris@420 126 case 2: return tr("Label");
Chris@420 127 default: return tr("Unknown");
Chris@420 128 }
Chris@420 129 }
Chris@420 130
Chris@420 131 virtual QVariant getData(int row, int column, int role) const
Chris@420 132 {
Chris@425 133 if (column < 2) {
Chris@425 134 return SparseModel<OneDimensionalPoint>::getData
Chris@425 135 (row, column, role);
Chris@425 136 }
Chris@425 137
Chris@606 138 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@420 139 if (i == m_points.end()) return QVariant();
Chris@420 140
Chris@420 141 switch (column) {
Chris@422 142 case 2: return i->label;
Chris@420 143 default: return QVariant();
Chris@420 144 }
Chris@420 145 }
Chris@420 146
Chris@424 147 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
Chris@424 148 {
Chris@425 149 if (column < 2) {
Chris@425 150 return SparseModel<OneDimensionalPoint>::getSetDataCommand
Chris@425 151 (row, column, value, role);
Chris@425 152 }
Chris@425 153
Chris@740 154 if (role != Qt::EditRole) return 0;
Chris@606 155 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@740 156 if (i == m_points.end()) return 0;
Chris@424 157 EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@424 158
Chris@424 159 Point point(*i);
Chris@424 160 command->deletePoint(point);
Chris@424 161
Chris@424 162 switch (column) {
Chris@424 163 case 2: point.label = value.toString(); break;
Chris@424 164 }
Chris@424 165
Chris@424 166 command->addPoint(point);
Chris@424 167 return command->finish();
Chris@424 168 }
Chris@424 169
Chris@427 170
Chris@420 171 virtual bool isColumnTimeValue(int column) const
Chris@420 172 {
Chris@420 173 return (column < 2);
Chris@420 174 }
Chris@422 175
Chris@422 176 virtual SortType getSortType(int column) const
Chris@422 177 {
Chris@422 178 if (column == 2) return SortAlphabetical;
Chris@422 179 return SortNumeric;
Chris@422 180 }
Chris@852 181
Chris@852 182 /**
Chris@852 183 * NoteExportable methods.
Chris@852 184 */
Chris@852 185
Chris@852 186 NoteList getNotes() const {
Chris@929 187 return getNotesWithin(getStartFrame(), getEndFrame());
Chris@852 188 }
Chris@852 189
Chris@929 190 NoteList getNotesWithin(int startFrame, int endFrame) const {
Chris@852 191
Chris@852 192 PointList points = getPoints(startFrame, endFrame);
Chris@852 193 NoteList notes;
Chris@852 194
Chris@852 195 for (PointList::iterator pli =
Chris@852 196 points.begin(); pli != points.end(); ++pli) {
Chris@852 197
Chris@852 198 notes.push_back
Chris@852 199 (NoteData(pli->frame,
Chris@852 200 getSampleRate() / 6, // arbitrary short duration
Chris@852 201 64, // default pitch
Chris@852 202 100)); // default velocity
Chris@852 203 }
Chris@852 204
Chris@852 205 return notes;
Chris@852 206 }
Chris@147 207 };
Chris@147 208
Chris@147 209 #endif
Chris@147 210
Chris@147 211
Chris@147 212