annotate data/model/Model.h @ 1752:6d09d68165a4 by-id

Further review of ById: make IDs only available when adding a model to the ById store, not by querying the item directly. This means any id encountered in the wild must have been added to the store at some point (even if later released), which simplifies reasoning about lifecycles
author Chris Cannam
date Fri, 05 Jul 2019 15:28:07 +0100
parents 498b426191e5
children 8529763e2258
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@150 20 #include <QObject>
Chris@150 21
Chris@1731 22 #include "base/ById.h"
Chris@150 23 #include "base/XmlExportable.h"
Chris@391 24 #include "base/Playable.h"
Chris@1038 25 #include "base/BaseTypes.h"
Chris@1060 26 #include "base/DataExportOptions.h"
Chris@150 27
Chris@179 28 class ZoomConstraint;
Chris@319 29 class AlignmentModel;
Chris@179 30
Chris@150 31 /**
Chris@150 32 * Model is the base class for all data models that represent any sort
Chris@150 33 * of data on a time scale based on an audio frame rate.
Chris@150 34 */
Chris@179 35 class Model : public QObject,
Chris@1742 36 public WithTypedId<Model>,
Chris@1429 37 public XmlExportable,
Chris@391 38 public Playable
Chris@150 39 {
Chris@150 40 Q_OBJECT
Chris@150 41
Chris@150 42 public:
Chris@1735 43 typedef Id ModelId;
Chris@1735 44
Chris@150 45 virtual ~Model();
Chris@150 46
Chris@150 47 /**
Chris@150 48 * Return true if the model was constructed successfully. Classes
Chris@150 49 * that refer to the model should always test this before use.
Chris@150 50 */
Chris@150 51 virtual bool isOK() const = 0;
Chris@150 52
Chris@150 53 /**
Chris@150 54 * Return the first audio frame spanned by the model.
Chris@150 55 */
Chris@1038 56 virtual sv_frame_t getStartFrame() const = 0;
Chris@150 57
Chris@150 58 /**
Chris@1611 59 * Return the audio frame at the end of the model, i.e. the final
Chris@1659 60 * frame contained within the model plus 1 (rounded up to the
Chris@1659 61 * model's "resolution" granularity, if more than 1). The end
Chris@1659 62 * frame minus the start frame should yield the total duration in
Chris@1659 63 * frames (as a multiple of the resolution) spanned by the
Chris@1659 64 * model. This is broadly consistent with the definition of the
Chris@1659 65 * end frame of a Selection object.
Chris@1725 66 *
Chris@1725 67 * If the end has been extended by extendEndFrame() beyond the
Chris@1725 68 * true end frame, return the extended end instead. This is
Chris@1725 69 * usually the behaviour you want.
Chris@150 70 */
Chris@1725 71 sv_frame_t getEndFrame() const {
Chris@1725 72 sv_frame_t trueEnd = getTrueEndFrame();
Chris@1725 73 if (m_extendTo > trueEnd) {
Chris@1725 74 return m_extendTo;
Chris@1725 75 } else {
Chris@1725 76 return trueEnd;
Chris@1725 77 }
Chris@1725 78 }
Chris@1725 79
Chris@1725 80 /**
Chris@1725 81 * Return the audio frame at the end of the model. This is
Chris@1725 82 * identical to getEndFrame(), except that it ignores any extended
Chris@1725 83 * duration set with extendEndFrame().
Chris@1725 84 */
Chris@1725 85 virtual sv_frame_t getTrueEndFrame() const = 0;
Chris@1725 86
Chris@1725 87 /**
Chris@1725 88 * Extend the end of the model. If this is set to something beyond
Chris@1725 89 * the true end of the data within the model, then getEndFrame()
Chris@1725 90 * will return this value instead of the true end. (This is used
Chris@1725 91 * by the Tony application.)
Chris@1725 92 */
Chris@1725 93 void extendEndFrame(sv_frame_t to) {
Chris@1725 94 m_extendTo = to;
Chris@1725 95 }
Chris@150 96
Chris@150 97 /**
Chris@150 98 * Return the frame rate in frames per second.
Chris@150 99 */
Chris@1040 100 virtual sv_samplerate_t getSampleRate() const = 0;
Chris@150 101
Chris@150 102 /**
Chris@297 103 * Return the frame rate of the underlying material, if the model
Chris@297 104 * itself has already been resampled.
Chris@297 105 */
Chris@1040 106 virtual sv_samplerate_t getNativeRate() const { return getSampleRate(); }
Chris@297 107
Chris@297 108 /**
Chris@333 109 * Return the "work title" of the model, if known.
Chris@333 110 */
Chris@333 111 virtual QString getTitle() const;
Chris@333 112
Chris@333 113 /**
Chris@333 114 * Return the "artist" or "maker" of the model, if known.
Chris@333 115 */
Chris@333 116 virtual QString getMaker() const;
Chris@333 117
Chris@333 118 /**
Chris@345 119 * Return the location of the data in this model (e.g. source
Chris@345 120 * URL). This should not normally be returned for editable models
Chris@345 121 * that have been edited.
Chris@345 122 */
Chris@345 123 virtual QString getLocation() const;
Chris@345 124
Chris@345 125 /**
Chris@345 126 * Return the type of the model. For display purposes only.
Chris@345 127 */
Chris@345 128 virtual QString getTypeName() const = 0;
Chris@345 129
Chris@345 130 /**
cannam@1452 131 * Return true if this is a sparse model.
cannam@1452 132 */
cannam@1452 133 virtual bool isSparse() const { return false; }
Chris@1500 134
Chris@1500 135 /**
Chris@923 136 * Mark the model as abandoning. This means that the application
Chris@923 137 * no longer needs it, so it can stop doing any background
Chris@923 138 * calculations it may be involved in. Note that as far as the
Chris@923 139 * model API is concerned, this does nothing more than tell the
Chris@923 140 * model to return true from isAbandoning(). The actual response
Chris@923 141 * to this will depend on the model's context -- it's possible
Chris@923 142 * nothing at all will change.
Chris@923 143 */
Chris@1747 144 //!!! aim to lose this (???)
Chris@1735 145 /*!!!
Chris@923 146 virtual void abandon() {
Chris@923 147 m_abandoning = true;
Chris@923 148 }
Chris@1735 149 */
Chris@1735 150
Chris@923 151 /**
Chris@923 152 * Query whether the model has been marked as abandoning.
Chris@923 153 */
Chris@1735 154 //!!! aim to lose this
Chris@1735 155 /*!!!
Chris@923 156 virtual bool isAbandoning() const {
Chris@923 157 return m_abandoning;
Chris@923 158 }
Chris@1735 159 */
Chris@150 160 /**
Chris@150 161 * Return true if the model has finished loading or calculating
Chris@150 162 * all its data, for a model that is capable of calculating in a
Chris@1671 163 * background thread.
Chris@150 164 *
Chris@1671 165 * If "completion" is non-NULL, return through it an estimated
Chris@1671 166 * percentage value showing how far through the background
Chris@1671 167 * operation it thinks it is (for progress reporting). This should
Chris@1671 168 * be identical to the value returned by getCompletion().
Chris@1671 169 *
Chris@1671 170 * A model that carries out all its calculation from the
Chris@1671 171 * constructor or accessor functions would typically return true
Chris@1671 172 * (and completion == 100) as long as isOK() is true. Other models
Chris@1671 173 * may make the return value here depend on the internal
Chris@1671 174 * completion status.
Chris@1669 175 *
Chris@1669 176 * See also getCompletion().
Chris@150 177 */
Chris@1671 178 virtual bool isReady(int *cp = nullptr) const {
Chris@1671 179 int c = getCompletion();
Chris@1671 180 if (cp) *cp = c;
Chris@1671 181 if (!isOK()) return false;
Chris@1671 182 else return (c == 100);
Chris@150 183 }
Chris@1671 184
Chris@1671 185 /**
Chris@1671 186 * Return an estimated percentage value showing how far through
Chris@1671 187 * any background operation used to calculate or load the model
Chris@1671 188 * data the model thinks it is. Must return 100 when the model is
Chris@1671 189 * complete.
Chris@1671 190 *
Chris@1671 191 * A model that carries out all its calculation from the
Chris@1671 192 * constructor or accessor functions might return 0 if isOK() is
Chris@1671 193 * false and 100 if isOK() is true. Other models may make the
Chris@1671 194 * return value here depend on the internal completion status.
Chris@1671 195 *
Chris@1671 196 * See also isReady().
Chris@1671 197 */
Chris@1671 198 virtual int getCompletion() const = 0;
Chris@150 199
Chris@179 200 /**
Chris@179 201 * If this model imposes a zoom constraint, i.e. some limit to the
Chris@179 202 * set of resolutions at which its data can meaningfully be
Chris@179 203 * displayed, then return it.
Chris@179 204 */
Chris@179 205 virtual const ZoomConstraint *getZoomConstraint() const {
Chris@179 206 return 0;
Chris@179 207 }
Chris@179 208
Chris@297 209 /**
Chris@1735 210 * If this model was derived from another, return the id of the
Chris@1735 211 * model it was derived from. The assumption is that the source
Chris@1735 212 * model's alignment will also apply to this model, unless some
Chris@1735 213 * other property (such as a specific alignment model set on this
Chris@1735 214 * model) indicates otherwise.
Chris@297 215 */
Chris@1735 216 virtual ModelId getSourceModel() const {
Chris@297 217 return m_sourceModel;
Chris@297 218 }
Chris@297 219
Chris@297 220 /**
Chris@297 221 * Set the source model for this model.
Chris@297 222 */
Chris@1735 223 virtual void setSourceModel(ModelId model);
Chris@319 224
Chris@319 225 /**
Chris@1735 226 * Specify an alignment between this model's timeline and that of
Chris@1735 227 * a reference model. The alignment model, of type AlignmentModel,
Chris@1735 228 * records both the reference and the alignment. This model "takes
Chris@1735 229 * ownership" of alignmentModel, in that we take responsibility
Chris@1735 230 * for calling ModelById::release() for it from our own destructor
Chris@1735 231 * (no other class needs to know about the alignment model).
Chris@1735 232
Chris@1735 233 *!!! I don't think the above is a good idea - I think document
Chris@1735 234 should record alignment models and release them
Chris@319 235 */
Chris@1735 236 virtual void setAlignment(ModelId alignmentModel);
Chris@319 237
Chris@319 238 /**
Chris@407 239 * Retrieve the alignment model for this model. This is not a
Chris@407 240 * generally useful function, as the alignment you really want may
Chris@407 241 * be performed by the source model instead. You should normally
Chris@407 242 * use getAlignmentReference, alignToReference and
Chris@407 243 * alignFromReference instead of this. The main intended
Chris@407 244 * application for this function is in streaming out alignments to
Chris@407 245 * the session file.
Chris@407 246 */
Chris@1735 247 virtual const ModelId getAlignment() const;
Chris@407 248
Chris@407 249 /**
Chris@319 250 * Return the reference model for the current alignment timeline,
Chris@319 251 * if any.
Chris@319 252 */
Chris@1735 253 virtual const ModelId getAlignmentReference() const;
Chris@319 254
Chris@319 255 /**
Chris@319 256 * Return the frame number of the reference model that corresponds
Chris@319 257 * to the given frame number in this model.
Chris@319 258 */
Chris@1038 259 virtual sv_frame_t alignToReference(sv_frame_t frame) const;
Chris@319 260
Chris@319 261 /**
Chris@319 262 * Return the frame number in this model that corresponds to the
Chris@319 263 * given frame number of the reference model.
Chris@319 264 */
Chris@1038 265 virtual sv_frame_t alignFromReference(sv_frame_t referenceFrame) const;
Chris@319 266
Chris@319 267 /**
Chris@319 268 * Return the completion percentage for the alignment model: 100
Chris@319 269 * if there is no alignment model or it has been entirely
Chris@319 270 * calculated, or less than 100 if it is still being calculated.
Chris@319 271 */
Chris@319 272 virtual int getAlignmentCompletion() const;
Chris@297 273
Chris@558 274 /**
Chris@558 275 * Set the event, feature, or signal type URI for the features
Chris@558 276 * contained in this model, according to the Audio Features RDF
Chris@558 277 * ontology.
Chris@558 278 */
Chris@558 279 void setRDFTypeURI(QString uri) { m_typeUri = uri; }
Chris@558 280
Chris@558 281 /**
Chris@558 282 * Retrieve the event, feature, or signal type URI for the
Chris@558 283 * features contained in this model, if previously set with
Chris@558 284 * setRDFTypeURI.
Chris@558 285 */
Chris@558 286 QString getRDFTypeURI() const { return m_typeUri; }
Chris@558 287
Chris@1580 288 void toXml(QTextStream &stream,
Chris@1608 289 QString indent = "",
Chris@1608 290 QString extraAttributes = "") const override;
Chris@150 291
Chris@1679 292 virtual QString toDelimitedDataString(QString delimiter,
Chris@1679 293 DataExportOptions options,
Chris@1679 294 sv_frame_t startFrame,
Chris@1679 295 sv_frame_t duration) const = 0;
Chris@150 296
Chris@150 297 signals:
Chris@150 298 /**
Chris@150 299 * Emitted when a model has been edited (or more data retrieved
Chris@150 300 * from cache, in the case of a cached model that generates slowly)
Chris@150 301 */
Chris@1752 302 void modelChanged(ModelId myId);
Chris@150 303
Chris@150 304 /**
Chris@150 305 * Emitted when a model has been edited (or more data retrieved
Chris@150 306 * from cache, in the case of a cached model that generates slowly)
Chris@150 307 */
Chris@1752 308 void modelChangedWithin(ModelId myId, sv_frame_t startFrame, sv_frame_t endFrame);
Chris@150 309
Chris@150 310 /**
Chris@150 311 * Emitted when some internal processing has advanced a stage, but
Chris@150 312 * the model has not changed externally. Views should respond by
Chris@150 313 * updating any progress meters or other monitoring, but not
Chris@150 314 * refreshing the actual view.
Chris@150 315 */
Chris@1752 316 void completionChanged(ModelId myId);
Chris@150 317
Chris@319 318 /**
Chris@411 319 * Emitted when internal processing is complete (i.e. when
Chris@411 320 * isReady() would return true, with completion at 100).
Chris@411 321 */
Chris@1752 322 void ready(ModelId myId);
Chris@411 323
Chris@411 324 /**
Chris@319 325 * Emitted when the completion percentage changes for the
Chris@319 326 * calculation of this model's alignment model.
Chris@319 327 */
Chris@1752 328 void alignmentCompletionChanged(ModelId myId);
Chris@319 329
Chris@150 330 protected:
Chris@1500 331 Model() :
Chris@1735 332 //!!! m_abandoning(false),
Chris@1725 333 m_extendTo(0) { }
Chris@150 334
Chris@150 335 // Not provided.
Chris@1735 336 Model(const Model &) =delete;
Chris@1735 337 Model &operator=(const Model &) =delete;
Chris@297 338
Chris@1735 339 ModelId m_sourceModel;
Chris@1735 340 ModelId m_alignmentModel;
Chris@558 341 QString m_typeUri;
Chris@1735 342 //!!! bool m_abandoning;
Chris@1725 343 sv_frame_t m_extendTo;
Chris@150 344 };
Chris@150 345
Chris@1741 346 typedef Model::Id ModelId;
Chris@1742 347 typedef TypedById<Model, Model::Id> ModelById;
Chris@1731 348
Chris@150 349 #endif