annotate data/model/Model.h @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents c546429d4c2f
children
rev   line source
Chris@150 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@150 2
Chris@150 3 /*
Chris@150 4 Sonic Visualiser
Chris@150 5 An audio file viewer and annotation editor.
Chris@150 6 Centre for Digital Music, Queen Mary, University of London.
Chris@150 7 This file copyright 2006 Chris Cannam.
Chris@150 8
Chris@150 9 This program is free software; you can redistribute it and/or
Chris@150 10 modify it under the terms of the GNU General Public License as
Chris@150 11 published by the Free Software Foundation; either version 2 of the
Chris@150 12 License, or (at your option) any later version. See the file
Chris@150 13 COPYING included with this distribution for more information.
Chris@150 14 */
Chris@150 15
Chris@1500 16 #ifndef SV_MODEL_H
Chris@1500 17 #define SV_MODEL_H
Chris@150 18
Chris@150 19 #include <vector>
Chris@1798 20 #include <atomic>
Chris@1798 21
Chris@150 22 #include <QObject>
Chris@1798 23 #include <QMutex>
Chris@150 24
Chris@1731 25 #include "base/ById.h"
Chris@150 26 #include "base/XmlExportable.h"
Chris@391 27 #include "base/Playable.h"
Chris@1038 28 #include "base/BaseTypes.h"
Chris@1060 29 #include "base/DataExportOptions.h"
Chris@150 30
Chris@179 31 class ZoomConstraint;
Chris@319 32 class AlignmentModel;
Chris@179 33
Chris@150 34 /**
Chris@150 35 * Model is the base class for all data models that represent any sort
Chris@150 36 * of data on a time scale based on an audio frame rate.
Chris@1798 37 *
Chris@1798 38 * Model classes are expected to be thread-safe, particularly with
Chris@1798 39 * regard to content rather than metadata (e.g. populating a model
Chris@1798 40 * from a transform running in a background thread while displaying it
Chris@1798 41 * in a UI layer).
Chris@1798 42 *
Chris@1798 43 * Never store a pointer to a model unless it is completely private to
Chris@1798 44 * the code owning it. Models should be referred to using their
Chris@1798 45 * ModelId id and looked up from the ById pool when needed. This
Chris@1798 46 * returns a shared pointer, which ensures a sufficient lifespan for a
Chris@1798 47 * transient operation locally. See notes in ById.h. The document
Chris@1798 48 * unregisters models when it is closed, and then they are deleted
Chris@1798 49 * when the last shared pointer instance expires.
Chris@150 50 */
Chris@179 51 class Model : public QObject,
Chris@1742 52 public WithTypedId<Model>,
Chris@1429 53 public XmlExportable,
Chris@391 54 public Playable
Chris@150 55 {
Chris@150 56 Q_OBJECT
Chris@150 57
Chris@150 58 public:
Chris@1735 59 typedef Id ModelId;
Chris@1735 60
Chris@150 61 virtual ~Model();
Chris@150 62
Chris@150 63 /**
Chris@150 64 * Return true if the model was constructed successfully. Classes
Chris@150 65 * that refer to the model should always test this before use.
Chris@150 66 */
Chris@150 67 virtual bool isOK() const = 0;
Chris@150 68
Chris@150 69 /**
Chris@150 70 * Return the first audio frame spanned by the model.
Chris@150 71 */
Chris@1038 72 virtual sv_frame_t getStartFrame() const = 0;
Chris@150 73
Chris@150 74 /**
Chris@1611 75 * Return the audio frame at the end of the model, i.e. the final
Chris@1659 76 * frame contained within the model plus 1 (rounded up to the
Chris@1659 77 * model's "resolution" granularity, if more than 1). The end
Chris@1659 78 * frame minus the start frame should yield the total duration in
Chris@1659 79 * frames (as a multiple of the resolution) spanned by the
Chris@1659 80 * model. This is broadly consistent with the definition of the
Chris@1659 81 * end frame of a Selection object.
Chris@1725 82 *
Chris@1725 83 * If the end has been extended by extendEndFrame() beyond the
Chris@1725 84 * true end frame, return the extended end instead. This is
Chris@1725 85 * usually the behaviour you want.
Chris@150 86 */
Chris@1725 87 sv_frame_t getEndFrame() const {
Chris@1725 88 sv_frame_t trueEnd = getTrueEndFrame();
Chris@1725 89 if (m_extendTo > trueEnd) {
Chris@1725 90 return m_extendTo;
Chris@1725 91 } else {
Chris@1725 92 return trueEnd;
Chris@1725 93 }
Chris@1725 94 }
Chris@1725 95
Chris@1725 96 /**
Chris@1725 97 * Return the audio frame at the end of the model. This is
Chris@1725 98 * identical to getEndFrame(), except that it ignores any extended
Chris@1725 99 * duration set with extendEndFrame().
Chris@1725 100 */
Chris@1725 101 virtual sv_frame_t getTrueEndFrame() const = 0;
Chris@1725 102
Chris@1725 103 /**
Chris@1725 104 * Extend the end of the model. If this is set to something beyond
Chris@1725 105 * the true end of the data within the model, then getEndFrame()
Chris@1725 106 * will return this value instead of the true end. (This is used
Chris@1725 107 * by the Tony application.)
Chris@1725 108 */
Chris@1725 109 void extendEndFrame(sv_frame_t to) {
Chris@1725 110 m_extendTo = to;
Chris@1725 111 }
Chris@150 112
Chris@150 113 /**
Chris@150 114 * Return the frame rate in frames per second.
Chris@150 115 */
Chris@1040 116 virtual sv_samplerate_t getSampleRate() const = 0;
Chris@150 117
Chris@150 118 /**
Chris@297 119 * Return the frame rate of the underlying material, if the model
Chris@297 120 * itself has already been resampled.
Chris@297 121 */
Chris@1040 122 virtual sv_samplerate_t getNativeRate() const { return getSampleRate(); }
Chris@297 123
Chris@297 124 /**
Chris@333 125 * Return the "work title" of the model, if known.
Chris@333 126 */
Chris@333 127 virtual QString getTitle() const;
Chris@333 128
Chris@333 129 /**
Chris@333 130 * Return the "artist" or "maker" of the model, if known.
Chris@333 131 */
Chris@333 132 virtual QString getMaker() const;
Chris@333 133
Chris@333 134 /**
Chris@345 135 * Return the location of the data in this model (e.g. source
Chris@345 136 * URL). This should not normally be returned for editable models
Chris@345 137 * that have been edited.
Chris@345 138 */
Chris@345 139 virtual QString getLocation() const;
Chris@345 140
Chris@345 141 /**
Chris@345 142 * Return the type of the model. For display purposes only.
Chris@345 143 */
Chris@345 144 virtual QString getTypeName() const = 0;
Chris@345 145
Chris@345 146 /**
cannam@1452 147 * Return true if this is a sparse model.
cannam@1452 148 */
cannam@1452 149 virtual bool isSparse() const { return false; }
Chris@1500 150
Chris@1500 151 /**
Chris@150 152 * Return true if the model has finished loading or calculating
Chris@150 153 * all its data, for a model that is capable of calculating in a
Chris@1671 154 * background thread.
Chris@150 155 *
Chris@1671 156 * If "completion" is non-NULL, return through it an estimated
Chris@1671 157 * percentage value showing how far through the background
Chris@1671 158 * operation it thinks it is (for progress reporting). This should
Chris@1671 159 * be identical to the value returned by getCompletion().
Chris@1671 160 *
Chris@1671 161 * A model that carries out all its calculation from the
Chris@1671 162 * constructor or accessor functions would typically return true
Chris@1671 163 * (and completion == 100) as long as isOK() is true. Other models
Chris@1671 164 * may make the return value here depend on the internal
Chris@1671 165 * completion status.
Chris@1669 166 *
Chris@1669 167 * See also getCompletion().
Chris@150 168 */
Chris@1671 169 virtual bool isReady(int *cp = nullptr) const {
Chris@1671 170 int c = getCompletion();
Chris@1671 171 if (cp) *cp = c;
Chris@1671 172 if (!isOK()) return false;
Chris@1671 173 else return (c == 100);
Chris@150 174 }
Chris@1671 175
Chris@1671 176 /**
Chris@1671 177 * Return an estimated percentage value showing how far through
Chris@1671 178 * any background operation used to calculate or load the model
Chris@1671 179 * data the model thinks it is. Must return 100 when the model is
Chris@1671 180 * complete.
Chris@1671 181 *
Chris@1671 182 * A model that carries out all its calculation from the
Chris@1671 183 * constructor or accessor functions might return 0 if isOK() is
Chris@1671 184 * false and 100 if isOK() is true. Other models may make the
Chris@1671 185 * return value here depend on the internal completion status.
Chris@1671 186 *
Chris@1671 187 * See also isReady().
Chris@1671 188 */
Chris@1671 189 virtual int getCompletion() const = 0;
Chris@150 190
Chris@179 191 /**
Chris@179 192 * If this model imposes a zoom constraint, i.e. some limit to the
Chris@179 193 * set of resolutions at which its data can meaningfully be
Chris@179 194 * displayed, then return it.
Chris@179 195 */
Chris@179 196 virtual const ZoomConstraint *getZoomConstraint() const {
Chris@179 197 return 0;
Chris@179 198 }
Chris@179 199
Chris@297 200 /**
Chris@1735 201 * If this model was derived from another, return the id of the
Chris@1735 202 * model it was derived from. The assumption is that the source
Chris@1735 203 * model's alignment will also apply to this model, unless some
Chris@1735 204 * other property (such as a specific alignment model set on this
Chris@1735 205 * model) indicates otherwise.
Chris@297 206 */
Chris@1735 207 virtual ModelId getSourceModel() const {
Chris@297 208 return m_sourceModel;
Chris@297 209 }
Chris@297 210
Chris@297 211 /**
Chris@297 212 * Set the source model for this model.
Chris@297 213 */
Chris@1735 214 virtual void setSourceModel(ModelId model);
Chris@319 215
Chris@319 216 /**
Chris@1735 217 * Specify an alignment between this model's timeline and that of
Chris@1735 218 * a reference model. The alignment model, of type AlignmentModel,
Chris@1761 219 * records both the reference and the alignment.
Chris@319 220 */
Chris@1735 221 virtual void setAlignment(ModelId alignmentModel);
Chris@319 222
Chris@319 223 /**
Chris@407 224 * Retrieve the alignment model for this model. This is not a
Chris@407 225 * generally useful function, as the alignment you really want may
Chris@407 226 * be performed by the source model instead. You should normally
Chris@407 227 * use getAlignmentReference, alignToReference and
Chris@407 228 * alignFromReference instead of this. The main intended
Chris@407 229 * application for this function is in streaming out alignments to
Chris@407 230 * the session file.
Chris@407 231 */
Chris@1735 232 virtual const ModelId getAlignment() const;
Chris@407 233
Chris@407 234 /**
Chris@319 235 * Return the reference model for the current alignment timeline,
Chris@319 236 * if any.
Chris@319 237 */
Chris@1735 238 virtual const ModelId getAlignmentReference() const;
Chris@319 239
Chris@319 240 /**
Chris@319 241 * Return the frame number of the reference model that corresponds
Chris@319 242 * to the given frame number in this model.
Chris@319 243 */
Chris@1038 244 virtual sv_frame_t alignToReference(sv_frame_t frame) const;
Chris@319 245
Chris@319 246 /**
Chris@319 247 * Return the frame number in this model that corresponds to the
Chris@319 248 * given frame number of the reference model.
Chris@319 249 */
Chris@1038 250 virtual sv_frame_t alignFromReference(sv_frame_t referenceFrame) const;
Chris@319 251
Chris@319 252 /**
Chris@319 253 * Return the completion percentage for the alignment model: 100
Chris@319 254 * if there is no alignment model or it has been entirely
Chris@319 255 * calculated, or less than 100 if it is still being calculated.
Chris@319 256 */
Chris@319 257 virtual int getAlignmentCompletion() const;
Chris@297 258
Chris@558 259 /**
Chris@558 260 * Set the event, feature, or signal type URI for the features
Chris@558 261 * contained in this model, according to the Audio Features RDF
Chris@558 262 * ontology.
Chris@558 263 */
Chris@558 264 void setRDFTypeURI(QString uri) { m_typeUri = uri; }
Chris@558 265
Chris@558 266 /**
Chris@558 267 * Retrieve the event, feature, or signal type URI for the
Chris@558 268 * features contained in this model, if previously set with
Chris@558 269 * setRDFTypeURI.
Chris@558 270 */
Chris@558 271 QString getRDFTypeURI() const { return m_typeUri; }
Chris@558 272
Chris@1580 273 void toXml(QTextStream &stream,
Chris@1608 274 QString indent = "",
Chris@1608 275 QString extraAttributes = "") const override;
Chris@150 276
Chris@1815 277 /**
Chris@1833 278 * Return a label for each column that would be written by
Chris@1833 279 * toStringExportRows.
Chris@1815 280 */
Chris@1833 281 virtual QVector<QString>
Chris@1833 282 getStringExportHeaders(DataExportOptions options) const = 0;
Chris@1815 283
Chris@1815 284 /**
Chris@1833 285 * Emit events starting within the given range as string rows
Chris@1833 286 * ready for conversion to an e.g. comma-separated data format.
Chris@1815 287 */
Chris@1833 288 virtual QVector<QVector<QString>>
Chris@1833 289 toStringExportRows(DataExportOptions options,
Chris@1833 290 sv_frame_t startFrame,
Chris@1833 291 sv_frame_t duration) const = 0;
Chris@150 292
Chris@150 293 signals:
Chris@150 294 /**
Chris@150 295 * Emitted when a model has been edited (or more data retrieved
Chris@150 296 * from cache, in the case of a cached model that generates slowly)
Chris@150 297 */
Chris@1752 298 void modelChanged(ModelId myId);
Chris@150 299
Chris@150 300 /**
Chris@150 301 * Emitted when a model has been edited (or more data retrieved
Chris@150 302 * from cache, in the case of a cached model that generates slowly)
Chris@150 303 */
Chris@1752 304 void modelChangedWithin(ModelId myId, sv_frame_t startFrame, sv_frame_t endFrame);
Chris@150 305
Chris@150 306 /**
Chris@150 307 * Emitted when some internal processing has advanced a stage, but
Chris@150 308 * the model has not changed externally. Views should respond by
Chris@150 309 * updating any progress meters or other monitoring, but not
Chris@150 310 * refreshing the actual view.
Chris@150 311 */
Chris@1752 312 void completionChanged(ModelId myId);
Chris@150 313
Chris@319 314 /**
Chris@411 315 * Emitted when internal processing is complete (i.e. when
Chris@411 316 * isReady() would return true, with completion at 100).
Chris@411 317 */
Chris@1752 318 void ready(ModelId myId);
Chris@411 319
Chris@411 320 /**
Chris@319 321 * Emitted when the completion percentage changes for the
Chris@1767 322 * calculation of this model's alignment model. (The ModelId
Chris@1767 323 * provided is that of this model, not the alignment model.)
Chris@319 324 */
Chris@1752 325 void alignmentCompletionChanged(ModelId myId);
Chris@319 326
Chris@1767 327 private slots:
Chris@1767 328 void alignmentModelCompletionChanged(ModelId);
Chris@1767 329
Chris@150 330 protected:
Chris@1798 331 Model() : m_extendTo(0) { }
Chris@150 332
Chris@150 333 // Not provided.
Chris@1735 334 Model(const Model &) =delete;
Chris@1735 335 Model &operator=(const Model &) =delete;
Chris@297 336
Chris@1798 337 mutable QMutex m_mutex;
Chris@1735 338 ModelId m_sourceModel;
Chris@1735 339 ModelId m_alignmentModel;
Chris@558 340 QString m_typeUri;
Chris@1798 341 std::atomic<sv_frame_t> m_extendTo;
Chris@150 342 };
Chris@150 343
Chris@1741 344 typedef Model::Id ModelId;
Chris@1742 345 typedef TypedById<Model, Model::Id> ModelById;
Chris@1731 346
Chris@150 347 #endif