annotate framework/Document.h @ 626:51ecc3e2d71c

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