annotate framework/Document.h @ 771:1d6cca5a5621 pitch-align

Allow use of proper sparse models (i.e. retaining event time info) in alignment; use this to switch to note alignment, which is what we have most recently been doing in the external program. Not currently producing correct results, though
author Chris Cannam
date Fri, 29 May 2020 17:39:02 +0100
parents 6429a164b7e1
children
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@683 98 Layer *createImportedLayer(ModelId);
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@693 161 * handler callback.
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@697 168 * Indicate that the async layer creation task associated with the
Chris@697 169 * given handle should be cancelled. There is no guarantee about
Chris@697 170 * what this will mean, and the handler callback may still be
Chris@697 171 * called.
Chris@697 172 */
Chris@697 173 void cancelAsyncLayerCreation(LayerCreationAsyncHandle handle);
Chris@697 174
Chris@697 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@683 186 * models that were based on the previous main model. The model
Chris@683 187 * must have been added to ModelById already, and Document will
Chris@683 188 * take responsibility for releasing it later.
Chris@45 189 */
Chris@683 190 void setMainModel(ModelId); // a WaveFileModel
Chris@45 191
Chris@45 192 /**
Chris@45 193 * Get the main model (the source for playback sample rate, etc).
Chris@45 194 */
Chris@683 195 ModelId getMainModel() { return m_mainModel; }
Chris@683 196
Chris@683 197 std::vector<ModelId> getTransformInputModels();
Chris@45 198
Chris@693 199 /**
Chris@693 200 * Return true if the model id is known to be the main model or
Chris@693 201 * one of the other existing models that can be shown in a new
Chris@693 202 * layer.
Chris@693 203 */
Chris@683 204 bool isKnownModel(ModelId) const;
Chris@77 205
Chris@45 206 /**
Chris@45 207 * Add a derived model associated with the given transform,
Chris@45 208 * running the transform and returning the resulting model.
Chris@683 209 * The model is added to ModelById before returning.
Chris@45 210 */
Chris@683 211 ModelId addDerivedModel(const Transform &transform,
Chris@683 212 const ModelTransformer::Input &input,
Chris@683 213 QString &returnedMessage);
Chris@45 214
Chris@45 215 /**
Chris@297 216 * Add derived models associated with the given set of related
Chris@297 217 * transforms, running the transforms and returning the resulting
Chris@683 218 * models. The models are added to ModelById before returning.
Chris@297 219 */
Chris@329 220 friend class AdditionalModelConverter;
Chris@683 221 std::vector<ModelId> addDerivedModels(const Transforms &transforms,
Chris@297 222 const ModelTransformer::Input &input,
Chris@329 223 QString &returnedMessage,
Chris@329 224 AdditionalModelConverter *);
Chris@297 225
Chris@297 226 /**
Chris@45 227 * Add a derived model associated with the given transform. This
Chris@45 228 * is necessary to register any derived model that was not created
Chris@683 229 * by the document using createDerivedModel or
Chris@691 230 * createDerivedLayer. Document will take responsibility for
Chris@691 231 * releasing the model later.
Chris@45 232 */
Chris@329 233 void addAlreadyDerivedModel(const Transform &transform,
Chris@329 234 const ModelTransformer::Input &input,
Chris@683 235 ModelId outputModelToAdd);
Chris@45 236
Chris@45 237 /**
Chris@691 238 * Add an imported model, i.e. any model (other than the main
Chris@691 239 * model) that has been created by any means other than as the
Chris@691 240 * output of a transform. This is necessary to register any
Chris@691 241 * imported model that is to be associated with a layer, and also
Chris@691 242 * to make sure that the model is released by the Document
Chris@691 243 * later. Aggregate models, alignment models, and miscellaneous
Chris@691 244 * temporary models should also be added in this way, unless the
Chris@691 245 * temporary models are large enough to need managing in a way
Chris@691 246 * that guarantees the shortest possible lifespan.
Chris@45 247 */
Chris@691 248 void addNonDerivedModel(ModelId);
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@683 255 void setModel(Layer *, ModelId);
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@672 297 * Re-generate alignments for all appropriate models against the
Chris@672 298 * main model. Existing alignments will be re-calculated.
Chris@672 299 */
Chris@672 300 void realignModels();
Chris@672 301
Chris@672 302 /**
Chris@601 303 * Return true if any external files (most obviously audio) failed
Chris@601 304 * to be found on load, so that the document is incomplete
Chris@601 305 * compared to its saved description.
Chris@601 306 */
Chris@601 307 bool isIncomplete() const { return m_isIncomplete; }
Chris@601 308
Chris@601 309 void setIncomplete(bool i) { m_isIncomplete = i; }
Chris@601 310
Chris@634 311 void toXml(QTextStream &, QString indent, QString extraAttributes) const override;
Chris@226 312 void toXmlAsTemplate(QTextStream &, QString indent, QString extraAttributes) const;
Chris@47 313
Chris@45 314 signals:
Chris@45 315 void layerAdded(Layer *);
Chris@45 316 void layerRemoved(Layer *);
Chris@45 317 void layerAboutToBeDeleted(Layer *);
Chris@45 318
Chris@45 319 // Emitted when a layer is first added to a view, or when it is
Chris@45 320 // last removed from a view
Chris@45 321 void layerInAView(Layer *, bool);
Chris@45 322
Chris@683 323 void modelAdded(ModelId);
Chris@683 324 void mainModelChanged(ModelId); // a WaveFileModel; emitted after modelAdded
Chris@45 325
Chris@78 326 void modelGenerationFailed(QString transformName, QString message);
Chris@78 327 void modelGenerationWarning(QString transformName, QString message);
Chris@78 328 void modelRegenerationFailed(QString layerName, QString transformName,
Chris@78 329 QString message);
Chris@78 330 void modelRegenerationWarning(QString layerName, QString transformName,
Chris@78 331 QString message);
Chris@428 332
Chris@683 333 void alignmentComplete(ModelId); // an AlignmentModel
Chris@761 334 void alignmentFailed(ModelId, QString message); // an AlignmentModel
Chris@45 335
Chris@160 336 void activity(QString);
Chris@160 337
Chris@588 338 protected slots:
Chris@687 339 void performDeferredAlignment(ModelId);
Chris@588 340
Chris@45 341 protected:
Chris@683 342 void releaseModel(ModelId model);
Chris@45 343
Chris@45 344 /**
Chris@45 345 * If model is suitable for alignment, align it against the main
Chris@672 346 * model and store the alignment in the model. If the model has an
Chris@672 347 * alignment already for the current main model, leave it
Chris@672 348 * unchanged unless forceRecalculate is true.
Chris@45 349 */
Chris@683 350 void alignModel(ModelId, bool forceRecalculate = false);
Chris@45 351
Chris@45 352 /*
Chris@45 353 * Every model that is in use by a layer in the document must be
Chris@45 354 * found in either m_mainModel or m_models. We own and control
Chris@45 355 * the lifespan of all of these models.
Chris@45 356 */
Chris@45 357
Chris@45 358 /**
Chris@45 359 * The model that provides the underlying sample rate, etc. This
Chris@45 360 * model is not reference counted for layers, and is not freed
Chris@45 361 * unless it is replaced or the document is deleted.
Chris@45 362 */
Chris@683 363 ModelId m_mainModel; // a WaveFileModel
Chris@45 364
Chris@45 365 struct ModelRecord
Chris@45 366 {
Chris@595 367 // Information associated with a non-main model. If this
Chris@683 368 // model is derived from another, then source will be
Chris@683 369 // something other than None and the transform name will be
Chris@683 370 // set appropriately. If the transform is set but source is
Chris@683 371 // None, then there was a transform involved but the (target)
Chris@683 372 // model has been modified since being generated from it.
Chris@72 373
Chris@72 374 // This does not use ModelTransformer::Input, because it would
Chris@683 375 // be confusing to have Input objects hanging around with None
Chris@72 376 // models in them.
Chris@72 377
Chris@683 378 ModelId source; // may be None
Chris@72 379 int channel;
Chris@72 380 Transform transform;
Chris@329 381 bool additional;
Chris@45 382 };
Chris@45 383
Chris@683 384 // These must be stored in increasing order of id (as in the
Chris@683 385 // ordered std::map), to ensure repeatability for automated tests
Chris@683 386 std::map<ModelId, ModelRecord> m_models;
Chris@691 387
Chris@683 388 std::set<ModelId> m_aggregateModels;
Chris@691 389 std::set<ModelId> m_alignmentModels;
Chris@661 390
Chris@329 391 /**
Chris@329 392 * Add an extra derived model (returned at the end of processing a
Chris@329 393 * transform).
Chris@329 394 */
Chris@683 395 void addAdditionalModel(ModelId);
Chris@329 396
Chris@45 397 class AddLayerCommand : public Command
Chris@45 398 {
Chris@45 399 public:
Chris@595 400 AddLayerCommand(Document *d, View *view, Layer *layer);
Chris@595 401 virtual ~AddLayerCommand();
Chris@595 402
Chris@634 403 void execute() override;
Chris@634 404 void unexecute() override;
Chris@634 405 QString getName() const override;
Chris@45 406
Chris@45 407 protected:
Chris@595 408 Document *m_d;
Chris@595 409 View *m_view; // I don't own this
Chris@595 410 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@595 411 QString m_name;
Chris@595 412 bool m_added;
Chris@45 413 };
Chris@45 414
Chris@45 415 class RemoveLayerCommand : public Command
Chris@45 416 {
Chris@45 417 public:
Chris@595 418 RemoveLayerCommand(Document *d, View *view, Layer *layer);
Chris@595 419 virtual ~RemoveLayerCommand();
Chris@595 420
Chris@634 421 void execute() override;
Chris@634 422 void unexecute() override;
Chris@634 423 QString getName() const override;
Chris@45 424
Chris@45 425 protected:
Chris@595 426 Document *m_d;
Chris@595 427 View *m_view; // I don't own this
Chris@595 428 Layer *m_layer; // Document owns this, but I determine its lifespan
Chris@339 429 bool m_wasDormant;
Chris@595 430 QString m_name;
Chris@595 431 bool m_added;
Chris@45 432 };
Chris@45 433
Chris@45 434 typedef std::map<Layer *, std::set<View *> > LayerViewMap;
Chris@45 435 LayerViewMap m_layerViewMap;
Chris@45 436
Chris@45 437 void addToLayerViewMap(Layer *, View *);
Chris@45 438 void removeFromLayerViewMap(Layer *, View *);
Chris@45 439
Chris@45 440 QString getUniqueLayerName(QString candidate);
Chris@683 441 void writeBackwardCompatibleDerivation(QTextStream &, QString, ModelId,
Chris@72 442 const ModelRecord &) const;
Chris@90 443
Chris@226 444 void toXml(QTextStream &, QString, QString, bool asTemplate) const;
Chris@226 445 void writePlaceholderMainModel(QTextStream &, QString) const;
Chris@226 446
Chris@683 447 std::vector<Layer *> createLayersForDerivedModels(std::vector<ModelId>,
Chris@329 448 QStringList names);
Chris@329 449
Chris@45 450 /**
Chris@45 451 * And these are the layers. We also control the lifespans of
Chris@45 452 * these (usually through the commands used to add and remove them).
Chris@45 453 */
Chris@663 454 typedef std::vector<Layer *> LayerList;
Chris@663 455 LayerList m_layers;
Chris@47 456
Chris@47 457 bool m_autoAlignment;
Chris@423 458 Align *m_align;
Chris@601 459
Chris@601 460 bool m_isIncomplete;
Chris@45 461 };
Chris@45 462
Chris@45 463 #endif