annotate framework/Document.h @ 562:3c846b06c518 3.0-integration

When returning the frame that we have filled to, avoid accidentally reducing the frame number (making it appear we are less filled than we really are) when we had intended to round it up to the full requested amount. Fixes some unexpected double-playback in non-looping play-selection mode.
author Chris Cannam
date Wed, 14 Dec 2016 11:55:47 +0000
parents b23db4cef02f
children d122d3595a32
rev   line source
Chris@45 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@45 2
Chris@45 3 /*
Chris@45 4 Sonic Visualiser
Chris@45 5 An audio file viewer and annotation editor.
Chris@45 6 Centre for Digital Music, Queen Mary, University of London.
Chris@45 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@45 8
Chris@45 9 This program is free software; you can redistribute it and/or
Chris@45 10 modify it under the terms of the GNU General Public License as
Chris@45 11 published by the Free Software Foundation; either version 2 of the
Chris@45 12 License, or (at your option) any later version. See the file
Chris@45 13 COPYING included with this distribution for more information.
Chris@45 14 */
Chris@45 15
Chris@45 16 #ifndef _DOCUMENT_H_
Chris@45 17 #define _DOCUMENT_H_
Chris@45 18
Chris@45 19 #include "layer/LayerFactory.h"
Chris@106 20 #include "transform/Transform.h"
Chris@106 21 #include "transform/ModelTransformer.h"
gyorgyf@270 22 #include "transform/FeatureExtractionModelTransformer.h"
Chris@45 23 #include "base/Command.h"
Chris@45 24
Chris@45 25 #include <map>
Chris@45 26 #include <set>
Chris@45 27
Chris@45 28 class Model;
Chris@45 29 class Layer;
Chris@45 30 class View;
Chris@45 31 class WaveFileModel;
Chris@45 32
Chris@329 33 class AdditionalModelConverter;
Chris@329 34
Chris@423 35 class Align;
Chris@423 36
Chris@45 37 /**
Chris@45 38 * A Sonic Visualiser document consists of a set of data models, and
Chris@45 39 * also the visualisation layers used to display them. Changes to the
Chris@45 40 * layers and their layout need to be stored and managed in much the
Chris@45 41 * same way as changes to the underlying data.
Chris@45 42 *
Chris@45 43 * The document manages:
Chris@45 44 *
Chris@45 45 * - A main data Model, which provides the underlying sample rate and
Chris@45 46 * such like. This must be a WaveFileModel.
Chris@45 47 *
Chris@45 48 * - Any number of imported Model objects, which contain data without any
Chris@45 49 * requirement to remember where the data came from or how to
Chris@45 50 * regenerate it.
Chris@45 51 *
Chris@53 52 * - Any number of Model objects that were generated by a Transformer
Chris@54 53 * such as FeatureExtractionModelTransformer. For these, we also
Chris@45 54 * record the source model and the name of the transform used to
Chris@45 55 * generate the model so that we can regenerate it (potentially
Chris@45 56 * from a different source) on demand.
Chris@45 57 *
Chris@45 58 * - A flat list of Layer objects. Elsewhere, the GUI may distribute these
Chris@45 59 * across any number of View widgets. A layer may be viewable on more
Chris@45 60 * than one view at once, in principle. A layer refers to one model,
Chris@45 61 * but the same model can be in use in more than one layer.
Chris@45 62 *
Chris@45 63 * The document does *not* manage the existence or structure of Pane
Chris@45 64 * and other view widgets. However, it does provide convenience
Chris@45 65 * methods for reference-counted command-based management of the
Chris@45 66 * association between layers and views (addLayerToView,
Chris@45 67 * removeLayerFromView).
Chris@45 68 */
Chris@45 69
Chris@45 70 class Document : public QObject,
Chris@45 71 public XmlExportable
Chris@45 72 {
Chris@45 73 Q_OBJECT
Chris@45 74
Chris@45 75 public:
Chris@45 76 Document();
Chris@45 77 virtual ~Document();
Chris@45 78
Chris@45 79 /**
Chris@45 80 * Create and return a new layer of the given type, associated
Chris@45 81 * with no model. The caller may set any model on this layer, but
Chris@45 82 * the model must also be registered with the document via the
Chris@45 83 * add-model methods below.
Chris@45 84 */
Chris@45 85 Layer *createLayer(LayerFactory::LayerType);
Chris@45 86
Chris@45 87 /**
Chris@45 88 * Create and return a new layer of the given type, associated
Chris@45 89 * with the current main model (if appropriate to the layer type).
Chris@45 90 */
Chris@45 91 Layer *createMainModelLayer(LayerFactory::LayerType);
Chris@45 92
Chris@45 93 /**
Chris@45 94 * Create and return a new layer associated with the given model,
Chris@45 95 * and register the model as an imported model.
Chris@45 96 */
Chris@45 97 Layer *createImportedLayer(Model *);
Chris@45 98
Chris@45 99 /**
Chris@45 100 * Create and return a new layer of the given type, with an
Chris@45 101 * appropriate empty model. If the given type is not one for
Chris@45 102 * which an empty model can meaningfully be created, return 0.
Chris@45 103 */
Chris@45 104 Layer *createEmptyLayer(LayerFactory::LayerType);
Chris@45 105
Chris@45 106 /**
Chris@45 107 * Create and return a new layer of the given type, associated
Chris@45 108 * with the given transform name. This method does not run the
Chris@45 109 * transform itself, nor create a model. The caller can safely
Chris@45 110 * add a model to the layer later, but note that all models used
Chris@45 111 * by a transform layer _must_ be registered with the document
Chris@45 112 * using addDerivedModel below.
Chris@45 113 */
Chris@54 114 Layer *createDerivedLayer(LayerFactory::LayerType, TransformId);
Chris@45 115
Chris@45 116 /**
Chris@45 117 * Create and return a suitable layer for the given transform,
Chris@45 118 * running the transform and associating the resulting model with
Chris@45 119 * the new layer.
Chris@45 120 */
Chris@72 121 Layer *createDerivedLayer(const Transform &,
Chris@72 122 const ModelTransformer::Input &);
Chris@45 123
Chris@45 124 /**
Chris@297 125 * Create and return suitable layers for the given transforms,
Chris@297 126 * which must be identical apart from the output (i.e. must use
Chris@297 127 * the same plugin and configuration). The layers are returned in
Chris@329 128 * the same order as the transforms are supplied.
matthiasm@269 129 */
Chris@297 130 std::vector<Layer *> createDerivedLayers(const Transforms &,
Chris@297 131 const ModelTransformer::Input &);
matthiasm@269 132
Chris@363 133 typedef void *LayerCreationAsyncHandle;
Chris@363 134
Chris@329 135 class LayerCreationHandler {
Chris@329 136 public:
Chris@329 137 virtual ~LayerCreationHandler() { }
Chris@329 138
Chris@329 139 /**
Chris@329 140 * The primary layers are those corresponding 1-1 to the input
Chris@329 141 * models, listed in the same order as the input models. The
Chris@329 142 * additional layers vector contains any layers (from all
Chris@329 143 * models) that were returned separately at the end of
Chris@363 144 * processing. The handle indicates which async process this
Chris@363 145 * callback was initiated by. It must not be used again after
Chris@363 146 * this function returns.
Chris@329 147 */
Chris@363 148 virtual void layersCreated(LayerCreationAsyncHandle handle,
Chris@363 149 std::vector<Layer *> primary,
Chris@329 150 std::vector<Layer *> additional) = 0;
Chris@329 151 };
Chris@329 152
Chris@329 153 /**
Chris@329 154 * Create suitable layers for the given transforms, which must be
Chris@329 155 * identical apart from the output (i.e. must use the same plugin
Chris@329 156 * and configuration). This method returns after initialising the
Chris@329 157 * transformer process, and the layers are returned through a
Chris@363 158 * subsequent call to the provided handler (which must be
Chris@363 159 * non-null). The handle returned will be passed through to the
Chris@363 160 * handler callback, and may be also used for cancelling the task.
Chris@329 161 */
Chris@363 162 LayerCreationAsyncHandle createDerivedLayersAsync(const Transforms &,
Chris@363 163 const ModelTransformer::Input &,
Chris@363 164 LayerCreationHandler *handler);
Chris@363 165
Chris@363 166 /**
Chris@363 167 * Indicate that the async layer creation task associated with the
Chris@363 168 * given handle should be cancelled. There is no guarantee about
Chris@363 169 * what this will mean, and the handler callback may still be
Chris@363 170 * called.
Chris@363 171 */
Chris@363 172 void cancelAsyncLayerCreation(LayerCreationAsyncHandle handle);
Chris@329 173
matthiasm@269 174 /**
Chris@52 175 * Delete the given layer, and also its associated model if no
Chris@52 176 * longer used by any other layer. In general, this should be the
Chris@52 177 * only method used to delete layers -- doing so directly is a bit
Chris@52 178 * of a social gaffe.
Chris@52 179 */
Chris@52 180 void deleteLayer(Layer *, bool force = false);
Chris@52 181
Chris@52 182 /**
Chris@45 183 * Set the main model (the source for playback sample rate, etc)
Chris@45 184 * to the given wave file model. This will regenerate any derived
Chris@45 185 * models that were based on the previous main model.
Chris@45 186 */
Chris@45 187 void setMainModel(WaveFileModel *);
Chris@45 188
Chris@45 189 /**
Chris@45 190 * Get the main model (the source for playback sample rate, etc).
Chris@45 191 */
Chris@45 192 WaveFileModel *getMainModel() { return m_mainModel; }
Chris@45 193
Chris@45 194 /**
Chris@45 195 * Get the main model (the source for playback sample rate, etc).
Chris@45 196 */
Chris@45 197 const WaveFileModel *getMainModel() const { return m_mainModel; }
Chris@45 198
Chris@72 199 std::vector<Model *> getTransformInputModels();
Chris@45 200
Chris@77 201 bool isKnownModel(const Model *) const;
Chris@77 202
Chris@45 203 /**
Chris@45 204 * Add a derived model associated with the given transform,
Chris@45 205 * running the transform and returning the resulting model.
Chris@45 206 */
Chris@72 207 Model *addDerivedModel(const Transform &transform,
Chris@78 208 const ModelTransformer::Input &input,
Chris@296 209 QString &returnedMessage);
Chris@45 210
Chris@45 211 /**
Chris@297 212 * Add derived models associated with the given set of related
Chris@297 213 * transforms, running the transforms and returning the resulting
Chris@297 214 * models.
Chris@297 215 */
Chris@329 216 friend class AdditionalModelConverter;
Chris@297 217 std::vector<Model *> addDerivedModels(const Transforms &transforms,
Chris@297 218 const ModelTransformer::Input &input,
Chris@329 219 QString &returnedMessage,
Chris@329 220 AdditionalModelConverter *);
Chris@297 221
Chris@297 222 /**
Chris@45 223 * Add a derived model associated with the given transform. This
Chris@45 224 * is necessary to register any derived model that was not created
Chris@45 225 * by the document using createDerivedModel or createDerivedLayer.
Chris@45 226 */
Chris@329 227 void addAlreadyDerivedModel(const Transform &transform,
Chris@329 228 const ModelTransformer::Input &input,
Chris@329 229 Model *outputModelToAdd);
Chris@45 230
Chris@45 231 /**
Chris@45 232 * Add an imported (non-derived, non-main) model. This is
Chris@45 233 * necessary to register any imported model that is associated
Chris@45 234 * with a layer.
Chris@45 235 */
Chris@45 236 void addImportedModel(Model *);
Chris@45 237
Chris@45 238 /**
Chris@45 239 * Associate the given model with the given layer. The model must
Chris@45 240 * have already been registered using one of the addXXModel
Chris@45 241 * methods above.
Chris@45 242 */
Chris@45 243 void setModel(Layer *, Model *);
Chris@45 244
Chris@45 245 /**
Chris@45 246 * Set the given layer to use the given channel of its model (-1
Chris@45 247 * means all available channels).
Chris@45 248 */
Chris@45 249 void setChannel(Layer *, int);
Chris@45 250
Chris@45 251 /**
Chris@45 252 * Add the given layer to the given view. If the layer is
Chris@45 253 * intended to show a particular model, the model should normally
Chris@45 254 * be set using setModel before this method is called.
Chris@45 255 */
Chris@45 256 void addLayerToView(View *, Layer *);
Chris@45 257
Chris@45 258 /**
Chris@333 259 * Remove the given layer from the given view. Ownership of the
Chris@333 260 * layer is transferred to a command object on the undo stack, and
Chris@333 261 * the layer will be deleted when the undo stack is pruned.
Chris@45 262 */
Chris@45 263 void removeLayerFromView(View *, Layer *);
Chris@45 264
Chris@48 265 /**
Chris@50 266 * Return true if alignment is supported (i.e. if the necessary
Chris@50 267 * plugin is found).
Chris@50 268 */
Chris@51 269 static bool canAlign();
Chris@50 270
Chris@50 271 /**
Chris@48 272 * Specify whether models added via addImportedModel should be
Chris@48 273 * automatically aligned against the main model if appropriate.
Chris@48 274 */
Chris@48 275 void setAutoAlignment(bool on) { m_autoAlignment = on; }
Chris@48 276
Chris@48 277 /**
Chris@48 278 * Generate alignments for all appropriate models against the main
Chris@48 279 * model. Existing alignments will not be re-calculated unless
Chris@48 280 * the main model has changed since they were calculated.
Chris@48 281 */
Chris@48 282 void alignModels();
Chris@48 283
Chris@45 284 void toXml(QTextStream &, QString indent, QString extraAttributes) const;
Chris@226 285 void toXmlAsTemplate(QTextStream &, QString indent, QString extraAttributes) const;
Chris@47 286
Chris@45 287 signals:
Chris@45 288 void layerAdded(Layer *);
Chris@45 289 void layerRemoved(Layer *);
Chris@45 290 void layerAboutToBeDeleted(Layer *);
Chris@45 291
Chris@45 292 // Emitted when a layer is first added to a view, or when it is
Chris@45 293 // last removed from a view
Chris@45 294 void layerInAView(Layer *, bool);
Chris@45 295
Chris@45 296 void modelAdded(Model *);
Chris@45 297 void mainModelChanged(WaveFileModel *); // emitted after modelAdded
Chris@45 298 void modelAboutToBeDeleted(Model *);
Chris@45 299
Chris@78 300 void modelGenerationFailed(QString transformName, QString message);
Chris@78 301 void modelGenerationWarning(QString transformName, QString message);
Chris@78 302 void modelRegenerationFailed(QString layerName, QString transformName,
Chris@78 303 QString message);
Chris@78 304 void modelRegenerationWarning(QString layerName, QString transformName,
Chris@78 305 QString message);
Chris@428 306
Chris@428 307 void alignmentComplete(AlignmentModel *);
Chris@420 308 void alignmentFailed(QString message);
Chris@45 309
Chris@160 310 void activity(QString);
Chris@160 311
Chris@45 312 protected:
Chris@45 313 void releaseModel(Model *model);
Chris@45 314
Chris@45 315 /**
Chris@45 316 * If model is suitable for alignment, align it against the main
Chris@48 317 * model and store the alignment in the model. (If the model has
Chris@48 318 * an alignment already for the current main model, leave it
Chris@48 319 * unchanged.)
Chris@45 320 */
Chris@45 321 void alignModel(Model *);
Chris@45 322
Chris@45 323 /*
Chris@45 324 * Every model that is in use by a layer in the document must be
Chris@45 325 * found in either m_mainModel or m_models. We own and control
Chris@45 326 * the lifespan of all of these models.
Chris@45 327 */
Chris@45 328
Chris@45 329 /**
Chris@45 330 * The model that provides the underlying sample rate, etc. This
Chris@45 331 * model is not reference counted for layers, and is not freed
Chris@45 332 * unless it is replaced or the document is deleted.
Chris@45 333 */
Chris@45 334 WaveFileModel *m_mainModel;
Chris@45 335
Chris@45 336 struct ModelRecord
Chris@45 337 {
Chris@45 338 // Information associated with a non-main model. If this
Chris@45 339 // model is derived from another, then source will be non-NULL
Chris@45 340 // and the transform name will be set appropriately. If the
Chris@45 341 // transform name is set but source is NULL, then there was a
Chris@45 342 // transform involved but the (target) model has been modified
Chris@45 343 // since being generated from it.
Chris@72 344
Chris@72 345 // This does not use ModelTransformer::Input, because it would
Chris@72 346 // be confusing to have Input objects hanging around with NULL
Chris@72 347 // models in them.
Chris@72 348
Chris@45 349 const Model *source;
Chris@72 350 int channel;
Chris@72 351 Transform transform;
Chris@329 352 bool additional;
Chris@45 353
Chris@45 354 // Count of the number of layers using this model.
Chris@45 355 int refcount;
Chris@45 356 };
Chris@45 357
Chris@45 358 typedef std::map<Model *, ModelRecord> ModelMap;
Chris@45 359 ModelMap m_models;
Chris@45 360
Chris@329 361 /**
Chris@329 362 * Add an extra derived model (returned at the end of processing a
Chris@329 363 * transform).
Chris@329 364 */
Chris@329 365 void addAdditionalModel(Model *);
Chris@329 366
Chris@45 367 class AddLayerCommand : public Command
Chris@45 368 {
Chris@45 369 public:
Chris@45 370 AddLayerCommand(Document *d, View *view, Layer *layer);
Chris@45 371 virtual ~AddLayerCommand();
Chris@45 372
Chris@45 373 virtual void execute();
Chris@45 374 virtual void unexecute();
Chris@159 375 virtual QString getName() const;
Chris@45 376
Chris@45 377 protected:
Chris@45 378 Document *m_d;
Chris@45 379 View *m_view; // I don't own this
Chris@83 380 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@45 381 QString m_name;
Chris@45 382 bool m_added;
Chris@45 383 };
Chris@45 384
Chris@45 385 class RemoveLayerCommand : public Command
Chris@45 386 {
Chris@45 387 public:
Chris@45 388 RemoveLayerCommand(Document *d, View *view, Layer *layer);
Chris@45 389 virtual ~RemoveLayerCommand();
Chris@45 390
Chris@45 391 virtual void execute();
Chris@45 392 virtual void unexecute();
Chris@159 393 virtual QString getName() const;
Chris@45 394
Chris@45 395 protected:
Chris@45 396 Document *m_d;
Chris@45 397 View *m_view; // I don't own this
Chris@45 398 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@339 399 bool m_wasDormant;
Chris@45 400 QString m_name;
Chris@45 401 bool m_added;
Chris@45 402 };
Chris@45 403
Chris@45 404 typedef std::map<Layer *, std::set<View *> > LayerViewMap;
Chris@45 405 LayerViewMap m_layerViewMap;
Chris@45 406
Chris@45 407 void addToLayerViewMap(Layer *, View *);
Chris@45 408 void removeFromLayerViewMap(Layer *, View *);
Chris@45 409
Chris@45 410 QString getUniqueLayerName(QString candidate);
Chris@72 411 void writeBackwardCompatibleDerivation(QTextStream &, QString, Model *,
Chris@72 412 const ModelRecord &) const;
Chris@90 413
Chris@226 414 void toXml(QTextStream &, QString, QString, bool asTemplate) const;
Chris@226 415 void writePlaceholderMainModel(QTextStream &, QString) const;
Chris@226 416
Chris@329 417 std::vector<Layer *> createLayersForDerivedModels(std::vector<Model *>,
Chris@329 418 QStringList names);
Chris@329 419
Chris@45 420 /**
Chris@45 421 * And these are the layers. We also control the lifespans of
Chris@45 422 * these (usually through the commands used to add and remove them).
Chris@45 423 */
Chris@45 424 typedef std::set<Layer *> LayerSet;
Chris@45 425 LayerSet m_layers;
Chris@47 426
Chris@47 427 bool m_autoAlignment;
Chris@423 428 Align *m_align;
Chris@45 429 };
Chris@45 430
Chris@45 431 #endif