| 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@150 | 16 #ifndef _MODEL_H_ | 
| Chris@150 | 17 #define _MODEL_H_ | 
| Chris@150 | 18 | 
| Chris@150 | 19 #include <vector> | 
| Chris@150 | 20 #include <QObject> | 
| Chris@150 | 21 | 
| Chris@150 | 22 #include "base/XmlExportable.h" | 
| Chris@391 | 23 #include "base/Playable.h" | 
| Chris@150 | 24 | 
| Chris@290 | 25 typedef std::vector<float> SampleBlock; | 
| Chris@290 | 26 | 
| Chris@179 | 27 class ZoomConstraint; | 
| Chris@319 | 28 class AlignmentModel; | 
| Chris@179 | 29 | 
| Chris@150 | 30 /** | 
| Chris@150 | 31  * Model is the base class for all data models that represent any sort | 
| Chris@150 | 32  * of data on a time scale based on an audio frame rate. | 
| Chris@150 | 33  */ | 
| Chris@150 | 34 | 
| Chris@179 | 35 class Model : public QObject, | 
| Chris@391 | 36 	      public XmlExportable, | 
| Chris@391 | 37               public Playable | 
| Chris@150 | 38 { | 
| Chris@150 | 39     Q_OBJECT | 
| Chris@150 | 40 | 
| Chris@150 | 41 public: | 
| Chris@150 | 42     virtual ~Model(); | 
| Chris@150 | 43 | 
| Chris@150 | 44     /** | 
| Chris@150 | 45      * Return true if the model was constructed successfully.  Classes | 
| Chris@150 | 46      * that refer to the model should always test this before use. | 
| Chris@150 | 47      */ | 
| Chris@150 | 48     virtual bool isOK() const = 0; | 
| Chris@150 | 49 | 
| Chris@150 | 50     /** | 
| Chris@150 | 51      * Return the first audio frame spanned by the model. | 
| Chris@150 | 52      */ | 
| Chris@929 | 53     virtual int getStartFrame() const = 0; | 
| Chris@150 | 54 | 
| Chris@150 | 55     /** | 
| Chris@150 | 56      * Return the last audio frame spanned by the model. | 
| Chris@150 | 57      */ | 
| Chris@929 | 58     virtual int getEndFrame() const = 0; | 
| Chris@150 | 59 | 
| Chris@150 | 60     /** | 
| Chris@150 | 61      * Return the frame rate in frames per second. | 
| Chris@150 | 62      */ | 
| Chris@929 | 63     virtual int getSampleRate() const = 0; | 
| Chris@150 | 64 | 
| Chris@150 | 65     /** | 
| Chris@297 | 66      * Return the frame rate of the underlying material, if the model | 
| Chris@297 | 67      * itself has already been resampled. | 
| Chris@297 | 68      */ | 
| Chris@929 | 69     virtual int getNativeRate() const { return getSampleRate(); } | 
| Chris@297 | 70 | 
| Chris@297 | 71     /** | 
| Chris@333 | 72      * Return the "work title" of the model, if known. | 
| Chris@333 | 73      */ | 
| Chris@333 | 74     virtual QString getTitle() const; | 
| Chris@333 | 75 | 
| Chris@333 | 76     /** | 
| Chris@333 | 77      * Return the "artist" or "maker" of the model, if known. | 
| Chris@333 | 78      */ | 
| Chris@333 | 79     virtual QString getMaker() const; | 
| Chris@333 | 80 | 
| Chris@333 | 81     /** | 
| Chris@345 | 82      * Return the location of the data in this model (e.g. source | 
| Chris@345 | 83      * URL).  This should not normally be returned for editable models | 
| Chris@345 | 84      * that have been edited. | 
| Chris@345 | 85      */ | 
| Chris@345 | 86     virtual QString getLocation() const; | 
| Chris@345 | 87 | 
| Chris@345 | 88     /** | 
| Chris@345 | 89      * Return the type of the model.  For display purposes only. | 
| Chris@345 | 90      */ | 
| Chris@345 | 91     virtual QString getTypeName() const = 0; | 
| Chris@345 | 92 | 
| Chris@345 | 93     /** | 
| Chris@150 | 94      * Return a copy of this model. | 
| Chris@150 | 95      * | 
| Chris@150 | 96      * If the model is not editable, this may be effectively a shallow | 
| Chris@150 | 97      * copy.  If the model is editable, however, this operation must | 
| Chris@150 | 98      * properly copy all of the model's editable data. | 
| Chris@150 | 99      * | 
| Chris@150 | 100      * In general this operation is not useful for non-editable dense | 
| Chris@150 | 101      * models such as waveforms, because there may be no efficient | 
| Chris@150 | 102      * copy operation implemented -- for such models it is better not | 
| Chris@150 | 103      * to copy at all. | 
| Chris@150 | 104      * | 
| Chris@150 | 105      * Caller owns the returned value. | 
| Chris@150 | 106      */ | 
| Chris@150 | 107     virtual Model *clone() const = 0; | 
| Chris@923 | 108 | 
| Chris@923 | 109     /** | 
| Chris@923 | 110      * Mark the model as abandoning. This means that the application | 
| Chris@923 | 111      * no longer needs it, so it can stop doing any background | 
| Chris@923 | 112      * calculations it may be involved in. Note that as far as the | 
| Chris@923 | 113      * model API is concerned, this does nothing more than tell the | 
| Chris@923 | 114      * model to return true from isAbandoning().  The actual response | 
| Chris@923 | 115      * to this will depend on the model's context -- it's possible | 
| Chris@923 | 116      * nothing at all will change. | 
| Chris@923 | 117      */ | 
| Chris@923 | 118     virtual void abandon() { | 
| Chris@923 | 119         m_abandoning = true; | 
| Chris@923 | 120     } | 
| Chris@923 | 121 | 
| Chris@923 | 122     /** | 
| Chris@923 | 123      * Query whether the model has been marked as abandoning. | 
| Chris@923 | 124      */ | 
| Chris@923 | 125     virtual bool isAbandoning() const { | 
| Chris@923 | 126         return m_abandoning; | 
| Chris@923 | 127     } | 
| Chris@923 | 128 | 
| Chris@150 | 129     /** | 
| Chris@150 | 130      * Return true if the model has finished loading or calculating | 
| Chris@150 | 131      * all its data, for a model that is capable of calculating in a | 
| Chris@150 | 132      * background thread.  The default implementation is appropriate | 
| Chris@150 | 133      * for a thread that does not background any work but carries out | 
| Chris@150 | 134      * all its calculation from the constructor or accessors. | 
| Chris@150 | 135      * | 
| Chris@150 | 136      * If "completion" is non-NULL, this function should return | 
| Chris@150 | 137      * through it an estimated percentage value showing how far | 
| Chris@150 | 138      * through the background operation it thinks it is (for progress | 
| Chris@150 | 139      * reporting).  If it has no way to calculate progress, it may | 
| Chris@150 | 140      * return the special value COMPLETION_UNKNOWN. | 
| Chris@150 | 141      */ | 
| Chris@150 | 142     virtual bool isReady(int *completion = 0) const { | 
| Chris@150 | 143 	bool ok = isOK(); | 
| Chris@150 | 144 	if (completion) *completion = (ok ? 100 : 0); | 
| Chris@150 | 145 	return ok; | 
| Chris@150 | 146     } | 
| Chris@150 | 147     static const int COMPLETION_UNKNOWN; | 
| Chris@150 | 148 | 
| Chris@179 | 149     /** | 
| Chris@179 | 150      * If this model imposes a zoom constraint, i.e. some limit to the | 
| Chris@179 | 151      * set of resolutions at which its data can meaningfully be | 
| Chris@179 | 152      * displayed, then return it. | 
| Chris@179 | 153      */ | 
| Chris@179 | 154     virtual const ZoomConstraint *getZoomConstraint() const { | 
| Chris@179 | 155         return 0; | 
| Chris@179 | 156     } | 
| Chris@179 | 157 | 
| Chris@297 | 158     /** | 
| Chris@297 | 159      * If this model was derived from another, return the model it was | 
| Chris@297 | 160      * derived from.  The assumption is that the source model's | 
| Chris@297 | 161      * alignment will also apply to this model, unless some other | 
| Chris@319 | 162      * property (such as a specific alignment model set on this model) | 
| Chris@319 | 163      * indicates otherwise. | 
| Chris@297 | 164      */ | 
| Chris@297 | 165     virtual Model *getSourceModel() const { | 
| Chris@297 | 166         return m_sourceModel; | 
| Chris@297 | 167     } | 
| Chris@297 | 168 | 
| Chris@297 | 169     /** | 
| Chris@297 | 170      * Set the source model for this model. | 
| Chris@297 | 171      */ | 
| Chris@319 | 172     virtual void setSourceModel(Model *model); | 
| Chris@319 | 173 | 
| Chris@319 | 174     /** | 
| Chris@319 | 175      * Specify an aligment between this model's timeline and that of a | 
| Chris@319 | 176      * reference model.  The alignment model records both the | 
| Chris@319 | 177      * reference and the alignment.  This model takes ownership of the | 
| Chris@319 | 178      * alignment model. | 
| Chris@319 | 179      */ | 
| Chris@319 | 180     virtual void setAlignment(AlignmentModel *alignment); | 
| Chris@319 | 181 | 
| Chris@319 | 182     /** | 
| Chris@407 | 183      * Retrieve the alignment model for this model.  This is not a | 
| Chris@407 | 184      * generally useful function, as the alignment you really want may | 
| Chris@407 | 185      * be performed by the source model instead.  You should normally | 
| Chris@407 | 186      * use getAlignmentReference, alignToReference and | 
| Chris@407 | 187      * alignFromReference instead of this.  The main intended | 
| Chris@407 | 188      * application for this function is in streaming out alignments to | 
| Chris@407 | 189      * the session file. | 
| Chris@407 | 190      */ | 
| Chris@407 | 191     virtual const AlignmentModel *getAlignment() const; | 
| Chris@407 | 192 | 
| Chris@407 | 193     /** | 
| Chris@319 | 194      * Return the reference model for the current alignment timeline, | 
| Chris@319 | 195      * if any. | 
| Chris@319 | 196      */ | 
| Chris@319 | 197     virtual const Model *getAlignmentReference() const; | 
| Chris@319 | 198 | 
| Chris@319 | 199     /** | 
| Chris@319 | 200      * Return the frame number of the reference model that corresponds | 
| Chris@319 | 201      * to the given frame number in this model. | 
| Chris@319 | 202      */ | 
| Chris@929 | 203     virtual int alignToReference(int frame) const; | 
| Chris@319 | 204 | 
| Chris@319 | 205     /** | 
| Chris@319 | 206      * Return the frame number in this model that corresponds to the | 
| Chris@319 | 207      * given frame number of the reference model. | 
| Chris@319 | 208      */ | 
| Chris@929 | 209     virtual int alignFromReference(int referenceFrame) const; | 
| Chris@319 | 210 | 
| Chris@319 | 211     /** | 
| Chris@319 | 212      * Return the completion percentage for the alignment model: 100 | 
| Chris@319 | 213      * if there is no alignment model or it has been entirely | 
| Chris@319 | 214      * calculated, or less than 100 if it is still being calculated. | 
| Chris@319 | 215      */ | 
| Chris@319 | 216     virtual int getAlignmentCompletion() const; | 
| Chris@297 | 217 | 
| Chris@558 | 218     /** | 
| Chris@558 | 219      * Set the event, feature, or signal type URI for the features | 
| Chris@558 | 220      * contained in this model, according to the Audio Features RDF | 
| Chris@558 | 221      * ontology. | 
| Chris@558 | 222      */ | 
| Chris@558 | 223     void setRDFTypeURI(QString uri) { m_typeUri = uri; } | 
| Chris@558 | 224 | 
| Chris@558 | 225     /** | 
| Chris@558 | 226      * Retrieve the event, feature, or signal type URI for the | 
| Chris@558 | 227      * features contained in this model, if previously set with | 
| Chris@558 | 228      * setRDFTypeURI. | 
| Chris@558 | 229      */ | 
| Chris@558 | 230     QString getRDFTypeURI() const { return m_typeUri; } | 
| Chris@558 | 231 | 
| Chris@150 | 232     virtual void toXml(QTextStream &stream, | 
| Chris@150 | 233                        QString indent = "", | 
| Chris@150 | 234                        QString extraAttributes = "") const; | 
| Chris@150 | 235 | 
| Chris@838 | 236     virtual QString toDelimitedDataString(QString delimiter) const { | 
| Chris@929 | 237         return toDelimitedDataStringSubset(delimiter, getStartFrame(), getEndFrame()); | 
| Chris@838 | 238     } | 
| Chris@929 | 239     virtual QString toDelimitedDataStringSubset(QString, int /* f0 */, int /* f1 */) const { | 
| Chris@838 | 240         return ""; | 
| Chris@838 | 241     } | 
| Chris@150 | 242 | 
| Chris@319 | 243 public slots: | 
| Chris@319 | 244     void aboutToDelete(); | 
| Chris@319 | 245     void sourceModelAboutToBeDeleted(); | 
| Chris@319 | 246 | 
| Chris@150 | 247 signals: | 
| Chris@150 | 248     /** | 
| Chris@150 | 249      * Emitted when a model has been edited (or more data retrieved | 
| Chris@150 | 250      * from cache, in the case of a cached model that generates slowly) | 
| Chris@150 | 251      */ | 
| Chris@150 | 252     void modelChanged(); | 
| Chris@150 | 253 | 
| Chris@150 | 254     /** | 
| Chris@150 | 255      * Emitted when a model has been edited (or more data retrieved | 
| Chris@150 | 256      * from cache, in the case of a cached model that generates slowly) | 
| Chris@150 | 257      */ | 
| Chris@931 | 258     void modelChangedWithin(int startFrame, int endFrame); | 
| Chris@150 | 259 | 
| Chris@150 | 260     /** | 
| Chris@150 | 261      * Emitted when some internal processing has advanced a stage, but | 
| Chris@150 | 262      * the model has not changed externally.  Views should respond by | 
| Chris@150 | 263      * updating any progress meters or other monitoring, but not | 
| Chris@150 | 264      * refreshing the actual view. | 
| Chris@150 | 265      */ | 
| Chris@150 | 266     void completionChanged(); | 
| Chris@150 | 267 | 
| Chris@319 | 268     /** | 
| Chris@411 | 269      * Emitted when internal processing is complete (i.e. when | 
| Chris@411 | 270      * isReady() would return true, with completion at 100). | 
| Chris@411 | 271      */ | 
| Chris@411 | 272     void ready(); | 
| Chris@411 | 273 | 
| Chris@411 | 274     /** | 
| Chris@319 | 275      * Emitted when the completion percentage changes for the | 
| Chris@319 | 276      * calculation of this model's alignment model. | 
| Chris@319 | 277      */ | 
| Chris@319 | 278     void alignmentCompletionChanged(); | 
| Chris@319 | 279 | 
| Chris@319 | 280     /** | 
| Chris@319 | 281      * Emitted when something notifies this model (through calling | 
| Chris@319 | 282      * aboutToDelete() that it is about to delete it.  Note that this | 
| Chris@319 | 283      * depends on an external agent such as a Document object or | 
| Chris@319 | 284      * owning model telling the model that it is about to delete it; | 
| Chris@319 | 285      * there is nothing in the model to guarantee that this signal | 
| Chris@319 | 286      * will be emitted before the actual deletion. | 
| Chris@319 | 287      */ | 
| Chris@319 | 288     void aboutToBeDeleted(); | 
| Chris@319 | 289 | 
| Chris@150 | 290 protected: | 
| Chris@923 | 291     Model() : | 
| Chris@923 | 292         m_sourceModel(0), | 
| Chris@923 | 293         m_alignment(0), | 
| Chris@923 | 294         m_abandoning(false), | 
| Chris@923 | 295         m_aboutToDelete(false) { } | 
| Chris@150 | 296 | 
| Chris@150 | 297     // Not provided. | 
| Chris@150 | 298     Model(const Model &); | 
| Chris@150 | 299     Model &operator=(const Model &); | 
| Chris@297 | 300 | 
| Chris@297 | 301     Model *m_sourceModel; | 
| Chris@319 | 302     AlignmentModel *m_alignment; | 
| Chris@558 | 303     QString m_typeUri; | 
| Chris@923 | 304     bool m_abandoning; | 
| Chris@319 | 305     bool m_aboutToDelete; | 
| Chris@150 | 306 }; | 
| Chris@150 | 307 | 
| Chris@150 | 308 #endif |