| 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@150 | 136      * Return true if the model has finished loading or calculating | 
| Chris@150 | 137      * all its data, for a model that is capable of calculating in a | 
| Chris@1671 | 138      * background thread. | 
| Chris@150 | 139      * | 
| Chris@1671 | 140      * If "completion" is non-NULL, return through it an estimated | 
| Chris@1671 | 141      * percentage value showing how far through the background | 
| Chris@1671 | 142      * operation it thinks it is (for progress reporting). This should | 
| Chris@1671 | 143      * be identical to the value returned by getCompletion(). | 
| Chris@1671 | 144      * | 
| Chris@1671 | 145      * A model that carries out all its calculation from the | 
| Chris@1671 | 146      * constructor or accessor functions would typically return true | 
| Chris@1671 | 147      * (and completion == 100) as long as isOK() is true. Other models | 
| Chris@1671 | 148      * may make the return value here depend on the internal | 
| Chris@1671 | 149      * completion status. | 
| Chris@1669 | 150      * | 
| Chris@1669 | 151      * See also getCompletion(). | 
| Chris@150 | 152      */ | 
| Chris@1671 | 153     virtual bool isReady(int *cp = nullptr) const { | 
| Chris@1671 | 154         int c = getCompletion(); | 
| Chris@1671 | 155         if (cp) *cp = c; | 
| Chris@1671 | 156         if (!isOK()) return false; | 
| Chris@1671 | 157         else return (c == 100); | 
| Chris@150 | 158     } | 
| Chris@1671 | 159 | 
| Chris@1671 | 160     /** | 
| Chris@1671 | 161      * Return an estimated percentage value showing how far through | 
| Chris@1671 | 162      * any background operation used to calculate or load the model | 
| Chris@1671 | 163      * data the model thinks it is. Must return 100 when the model is | 
| Chris@1671 | 164      * complete. | 
| Chris@1671 | 165      * | 
| Chris@1671 | 166      * A model that carries out all its calculation from the | 
| Chris@1671 | 167      * constructor or accessor functions might return 0 if isOK() is | 
| Chris@1671 | 168      * false and 100 if isOK() is true. Other models may make the | 
| Chris@1671 | 169      * return value here depend on the internal completion status. | 
| Chris@1671 | 170      * | 
| Chris@1671 | 171      * See also isReady(). | 
| Chris@1671 | 172      */ | 
| Chris@1671 | 173     virtual int getCompletion() const = 0; | 
| Chris@150 | 174 | 
| Chris@179 | 175     /** | 
| Chris@179 | 176      * If this model imposes a zoom constraint, i.e. some limit to the | 
| Chris@179 | 177      * set of resolutions at which its data can meaningfully be | 
| Chris@179 | 178      * displayed, then return it. | 
| Chris@179 | 179      */ | 
| Chris@179 | 180     virtual const ZoomConstraint *getZoomConstraint() const { | 
| Chris@179 | 181         return 0; | 
| Chris@179 | 182     } | 
| Chris@179 | 183 | 
| Chris@297 | 184     /** | 
| Chris@1735 | 185      * If this model was derived from another, return the id of the | 
| Chris@1735 | 186      * model it was derived from.  The assumption is that the source | 
| Chris@1735 | 187      * model's alignment will also apply to this model, unless some | 
| Chris@1735 | 188      * other property (such as a specific alignment model set on this | 
| Chris@1735 | 189      * model) indicates otherwise. | 
| Chris@297 | 190      */ | 
| Chris@1735 | 191     virtual ModelId getSourceModel() const { | 
| Chris@297 | 192         return m_sourceModel; | 
| Chris@297 | 193     } | 
| Chris@297 | 194 | 
| Chris@297 | 195     /** | 
| Chris@297 | 196      * Set the source model for this model. | 
| Chris@297 | 197      */ | 
| Chris@1735 | 198     virtual void setSourceModel(ModelId model); | 
| Chris@319 | 199 | 
| Chris@319 | 200     /** | 
| Chris@1735 | 201      * Specify an alignment between this model's timeline and that of | 
| Chris@1735 | 202      * a reference model. The alignment model, of type AlignmentModel, | 
| Chris@1761 | 203      * records both the reference and the alignment. | 
| Chris@319 | 204      */ | 
| Chris@1735 | 205     virtual void setAlignment(ModelId alignmentModel); | 
| Chris@319 | 206 | 
| Chris@319 | 207     /** | 
| Chris@407 | 208      * Retrieve the alignment model for this model.  This is not a | 
| Chris@407 | 209      * generally useful function, as the alignment you really want may | 
| Chris@407 | 210      * be performed by the source model instead.  You should normally | 
| Chris@407 | 211      * use getAlignmentReference, alignToReference and | 
| Chris@407 | 212      * alignFromReference instead of this.  The main intended | 
| Chris@407 | 213      * application for this function is in streaming out alignments to | 
| Chris@407 | 214      * the session file. | 
| Chris@407 | 215      */ | 
| Chris@1735 | 216     virtual const ModelId getAlignment() const; | 
| Chris@407 | 217 | 
| Chris@407 | 218     /** | 
| Chris@319 | 219      * Return the reference model for the current alignment timeline, | 
| Chris@319 | 220      * if any. | 
| Chris@319 | 221      */ | 
| Chris@1735 | 222     virtual const ModelId getAlignmentReference() const; | 
| Chris@319 | 223 | 
| Chris@319 | 224     /** | 
| Chris@319 | 225      * Return the frame number of the reference model that corresponds | 
| Chris@319 | 226      * to the given frame number in this model. | 
| Chris@319 | 227      */ | 
| Chris@1038 | 228     virtual sv_frame_t alignToReference(sv_frame_t frame) const; | 
| Chris@319 | 229 | 
| Chris@319 | 230     /** | 
| Chris@319 | 231      * Return the frame number in this model that corresponds to the | 
| Chris@319 | 232      * given frame number of the reference model. | 
| Chris@319 | 233      */ | 
| Chris@1038 | 234     virtual sv_frame_t alignFromReference(sv_frame_t referenceFrame) const; | 
| Chris@319 | 235 | 
| Chris@319 | 236     /** | 
| Chris@319 | 237      * Return the completion percentage for the alignment model: 100 | 
| Chris@319 | 238      * if there is no alignment model or it has been entirely | 
| Chris@319 | 239      * calculated, or less than 100 if it is still being calculated. | 
| Chris@319 | 240      */ | 
| Chris@319 | 241     virtual int getAlignmentCompletion() const; | 
| Chris@297 | 242 | 
| Chris@558 | 243     /** | 
| Chris@558 | 244      * Set the event, feature, or signal type URI for the features | 
| Chris@558 | 245      * contained in this model, according to the Audio Features RDF | 
| Chris@558 | 246      * ontology. | 
| Chris@558 | 247      */ | 
| Chris@558 | 248     void setRDFTypeURI(QString uri) { m_typeUri = uri; } | 
| Chris@558 | 249 | 
| Chris@558 | 250     /** | 
| Chris@558 | 251      * Retrieve the event, feature, or signal type URI for the | 
| Chris@558 | 252      * features contained in this model, if previously set with | 
| Chris@558 | 253      * setRDFTypeURI. | 
| Chris@558 | 254      */ | 
| Chris@558 | 255     QString getRDFTypeURI() const { return m_typeUri; } | 
| Chris@558 | 256 | 
| Chris@1580 | 257     void toXml(QTextStream &stream, | 
| Chris@1608 | 258                QString indent = "", | 
| Chris@1608 | 259                QString extraAttributes = "") const override; | 
| Chris@150 | 260 | 
| Chris@1679 | 261     virtual QString toDelimitedDataString(QString delimiter, | 
| Chris@1679 | 262                                           DataExportOptions options, | 
| Chris@1679 | 263                                           sv_frame_t startFrame, | 
| Chris@1679 | 264                                           sv_frame_t duration) const = 0; | 
| Chris@150 | 265 | 
| Chris@150 | 266 signals: | 
| Chris@150 | 267     /** | 
| Chris@150 | 268      * Emitted when a model has been edited (or more data retrieved | 
| Chris@150 | 269      * from cache, in the case of a cached model that generates slowly) | 
| Chris@150 | 270      */ | 
| Chris@1752 | 271     void modelChanged(ModelId myId); | 
| Chris@150 | 272 | 
| Chris@150 | 273     /** | 
| Chris@150 | 274      * Emitted when a model has been edited (or more data retrieved | 
| Chris@150 | 275      * from cache, in the case of a cached model that generates slowly) | 
| Chris@150 | 276      */ | 
| Chris@1752 | 277     void modelChangedWithin(ModelId myId, sv_frame_t startFrame, sv_frame_t endFrame); | 
| Chris@150 | 278 | 
| Chris@150 | 279     /** | 
| Chris@150 | 280      * Emitted when some internal processing has advanced a stage, but | 
| Chris@150 | 281      * the model has not changed externally.  Views should respond by | 
| Chris@150 | 282      * updating any progress meters or other monitoring, but not | 
| Chris@150 | 283      * refreshing the actual view. | 
| Chris@150 | 284      */ | 
| Chris@1752 | 285     void completionChanged(ModelId myId); | 
| Chris@150 | 286 | 
| Chris@319 | 287     /** | 
| Chris@411 | 288      * Emitted when internal processing is complete (i.e. when | 
| Chris@411 | 289      * isReady() would return true, with completion at 100). | 
| Chris@411 | 290      */ | 
| Chris@1752 | 291     void ready(ModelId myId); | 
| Chris@411 | 292 | 
| Chris@411 | 293     /** | 
| Chris@319 | 294      * Emitted when the completion percentage changes for the | 
| Chris@1767 | 295      * calculation of this model's alignment model. (The ModelId | 
| Chris@1767 | 296      * provided is that of this model, not the alignment model.) | 
| Chris@319 | 297      */ | 
| Chris@1752 | 298     void alignmentCompletionChanged(ModelId myId); | 
| Chris@319 | 299 | 
| Chris@1767 | 300 private slots: | 
| Chris@1767 | 301     void alignmentModelCompletionChanged(ModelId); | 
| Chris@1767 | 302 | 
| Chris@150 | 303 protected: | 
| Chris@1500 | 304     Model() : | 
| Chris@1725 | 305         m_extendTo(0) { } | 
| Chris@150 | 306 | 
| Chris@150 | 307     // Not provided. | 
| Chris@1735 | 308     Model(const Model &) =delete; | 
| Chris@1735 | 309     Model &operator=(const Model &) =delete; | 
| Chris@297 | 310 | 
| Chris@1735 | 311     ModelId m_sourceModel; | 
| Chris@1735 | 312     ModelId m_alignmentModel; | 
| Chris@558 | 313     QString m_typeUri; | 
| Chris@1725 | 314     sv_frame_t m_extendTo; | 
| Chris@150 | 315 }; | 
| Chris@150 | 316 | 
| Chris@1741 | 317 typedef Model::Id ModelId; | 
| Chris@1742 | 318 typedef TypedById<Model, Model::Id> ModelById; | 
| Chris@1731 | 319 | 
| Chris@150 | 320 #endif |