lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam and QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _DOCUMENT_H_ lbajardsilogic@0: #define _DOCUMENT_H_ lbajardsilogic@0: lbajardsilogic@0: #include "layer/LayerFactory.h" lbajardsilogic@0: #include "transform/Transform.h" lbajardsilogic@0: #include "transform/PluginTransform.h" lbajardsilogic@0: #include "base/Command.h" lbajardsilogic@19: #include "data/model/AudioSourceInfoModel.h" lbajardsilogic@79: #include "filter/RealTimeFilterFactory.h" lbajardsilogic@79: #include "filter/FilterStack.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: class Model; lbajardsilogic@0: class Layer; lbajardsilogic@0: class View; lbajardsilogic@0: class WaveFileModel; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * A Sonic Visualiser document consists of a set of data models, and lbajardsilogic@0: * also the visualisation layers used to display them. Changes to the lbajardsilogic@0: * layers and their layout need to be stored and managed in much the lbajardsilogic@0: * same way as changes to the underlying data. lbajardsilogic@0: * lbajardsilogic@0: * The document manages: lbajardsilogic@0: * lbajardsilogic@0: * - A main data Model, which provides the underlying sample rate and lbajardsilogic@0: * such like. This must be a WaveFileModel. lbajardsilogic@0: * lbajardsilogic@0: * - Any number of imported Model objects, which contain data without any lbajardsilogic@0: * requirement to remember where the data came from or how to lbajardsilogic@0: * regenerate it. lbajardsilogic@0: * lbajardsilogic@0: * - Any number of Model objects that were generated by a Transform lbajardsilogic@0: * such as FeatureExtractionPluginTransform. For these, we also lbajardsilogic@0: * record the source model and the name of the transform used to lbajardsilogic@0: * generate the model so that we can regenerate it (potentially lbajardsilogic@0: * from a different source) on demand. lbajardsilogic@0: * lbajardsilogic@0: * - A flat list of Layer objects. Elsewhere, the GUI may distribute these lbajardsilogic@0: * across any number of View widgets. A layer may be viewable on more lbajardsilogic@0: * than one view at once, in principle. A layer refers to one model, lbajardsilogic@0: * but the same model can be in use in more than one layer. lbajardsilogic@0: * lbajardsilogic@0: * The document does *not* manage the existence or structure of Pane lbajardsilogic@0: * and other view widgets. However, it does provide convenience lbajardsilogic@0: * methods for reference-counted command-based management of the lbajardsilogic@0: * association between layers and views (addLayerToView, lbajardsilogic@0: * removeLayerFromView). lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: class Document : public QObject, lbajardsilogic@0: public XmlExportable lbajardsilogic@0: { lbajardsilogic@0: Q_OBJECT lbajardsilogic@0: lbajardsilogic@0: public: lbajardsilogic@0: Document(); lbajardsilogic@0: virtual ~Document(); lbajardsilogic@0: lbajardsilogic@175: void reset(); lbajardsilogic@175: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a new layer of the given type, associated lbajardsilogic@0: * with no model. The caller may set any model on this layer, but lbajardsilogic@0: * the model must also be registered with the document via the lbajardsilogic@0: * add-model methods below. lbajardsilogic@0: */ lbajardsilogic@0: Layer *createLayer(LayerFactory::LayerType); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a new layer of the given type, associated lbajardsilogic@0: * with the current main model (if appropriate to the layer type). lbajardsilogic@0: */ lbajardsilogic@0: Layer *createMainModelLayer(LayerFactory::LayerType); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a new layer associated with the given model, lbajardsilogic@0: * and register the model as an imported model. lbajardsilogic@0: */ lbajardsilogic@0: Layer *createImportedLayer(Model *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a new layer of the given type, with an lbajardsilogic@0: * appropriate empty model. If the given type is not one for lbajardsilogic@0: * which an empty model can meaningfully be created, return 0. lbajardsilogic@0: */ lbajardsilogic@0: Layer *createEmptyLayer(LayerFactory::LayerType); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a new layer of the given type, associated lbajardsilogic@0: * with the given transform name. This method does not run the lbajardsilogic@0: * transform itself, nor create a model. The caller can safely lbajardsilogic@0: * add a model to the layer later, but note that all models used lbajardsilogic@0: * by a transform layer _must_ be registered with the document lbajardsilogic@0: * using addDerivedModel below. lbajardsilogic@0: */ lbajardsilogic@0: Layer *createDerivedLayer(LayerFactory::LayerType, TransformId); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Create and return a suitable layer for the given transform, lbajardsilogic@0: * running the transform and associating the resulting model with lbajardsilogic@0: * the new layer. lbajardsilogic@0: */ lbajardsilogic@0: Layer *createDerivedLayer(TransformId, lbajardsilogic@0: Model *inputModel, lbajardsilogic@0: const PluginTransform::ExecutionContext &context, lbajardsilogic@0: QString configurationXml); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the main model (the source for playback sample rate, etc) lbajardsilogic@0: * to the given wave file model. This will regenerate any derived lbajardsilogic@0: * models that were based on the previous main model. lbajardsilogic@0: */ lbajardsilogic@0: void setMainModel(WaveFileModel *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get the main model (the source for playback sample rate, etc). lbajardsilogic@0: */ lbajardsilogic@0: WaveFileModel *getMainModel() { return m_mainModel; } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get the main model (the source for playback sample rate, etc). lbajardsilogic@0: */ lbajardsilogic@0: const WaveFileModel *getMainModel() const { return m_mainModel; } lbajardsilogic@0: lbajardsilogic@0: std::vector getTransformInputModels(); lbajardsilogic@0: lbajardsilogic@19: inline void setAudioSourceInfoFileName(const QString& name){m_audioSourceInfoFileName = name;} lbajardsilogic@19: inline QString getAudioSourceInfoFileName() const { return m_audioSourceInfoFileName;} lbajardsilogic@19: lbajardsilogic@19: void setAudioSourceInfoModel(AudioSourceInfoModel *infoModel); lbajardsilogic@19: lbajardsilogic@0: /** lbajardsilogic@0: * Add a derived model associated with the given transform, lbajardsilogic@0: * running the transform and returning the resulting model. lbajardsilogic@0: */ lbajardsilogic@0: Model *addDerivedModel(TransformId transform, lbajardsilogic@0: Model *inputModel, lbajardsilogic@0: const PluginTransform::ExecutionContext &context, lbajardsilogic@0: QString configurationXml); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a derived model associated with the given transform. This lbajardsilogic@0: * is necessary to register any derived model that was not created lbajardsilogic@0: * by the document using createDerivedModel or createDerivedLayer. lbajardsilogic@0: */ lbajardsilogic@0: void addDerivedModel(TransformId, lbajardsilogic@0: Model *inputModel, lbajardsilogic@0: const PluginTransform::ExecutionContext &context, lbajardsilogic@0: Model *outputModelToAdd, lbajardsilogic@0: QString configurationXml); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add an imported (non-derived, non-main) model. This is lbajardsilogic@0: * necessary to register any imported model that is associated lbajardsilogic@0: * with a layer. lbajardsilogic@0: */ lbajardsilogic@0: void addImportedModel(Model *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Associate the given model with the given layer. The model must lbajardsilogic@0: * have already been registered using one of the addXXModel lbajardsilogic@0: * methods above. lbajardsilogic@0: */ lbajardsilogic@0: void setModel(Layer *, Model *); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Set the given layer to use the given channel of its model (-1 lbajardsilogic@0: * means all available channels). lbajardsilogic@0: */ lbajardsilogic@0: void setChannel(Layer *, int); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add the given layer to the given view. If the layer is lbajardsilogic@0: * intended to show a particular model, the model should normally lbajardsilogic@0: * be set using setModel before this method is called. lbajardsilogic@0: */ lbajardsilogic@0: void addLayerToView(View *, Layer *); lbajardsilogic@0: lbajardsilogic@254: void addLayerToViewWithoutCommand(View *, Layer *); lbajardsilogic@254: lbajardsilogic@254: /** lbajardsilogic@0: * Remove the given layer from the given view. lbajardsilogic@0: */ lbajardsilogic@0: void removeLayerFromView(View *, Layer *); lbajardsilogic@254: void removeLayerFromViewWithoutCommand(View *, Layer *); lbajardsilogic@0: lbajardsilogic@19: inline std::set& getLayers(){return m_layers;} lbajardsilogic@19: lbajardsilogic@0: void toXml(QTextStream &, QString indent, QString extraAttributes) const; lbajardsilogic@0: QString toXmlString(QString indent, QString extraAttributes) const; lbajardsilogic@0: lbajardsilogic@19: QString toEasaierXmlString(QString indent, QString extraAttributes) const; lbajardsilogic@19: lbajardsilogic@79: Filter *createFilter(RealTimeFilterFactory::FilterType); lbajardsilogic@79: lbajardsilogic@79: FilterStack *getRealTimeFilterStack(){return m_filterStack;} lbajardsilogic@79: lbajardsilogic@79: void removeFilter(QString &name); lbajardsilogic@79: void removeAllFilters(); lbajardsilogic@79: lbajardsilogic@0: signals: lbajardsilogic@0: void layerAdded(Layer *); lbajardsilogic@0: void layerRemoved(Layer *); lbajardsilogic@0: void layerAboutToBeDeleted(Layer *); lbajardsilogic@0: lbajardsilogic@0: // Emitted when a layer is first added to a view, or when it is lbajardsilogic@0: // last removed from a view lbajardsilogic@0: void layerInAView(Layer *, bool); lbajardsilogic@0: lbajardsilogic@0: void modelAdded(Model *); lbajardsilogic@0: void mainModelChanged(WaveFileModel *); // emitted after modelAdded lbajardsilogic@0: void modelAboutToBeDeleted(Model *); lbajardsilogic@0: lbajardsilogic@0: void modelGenerationFailed(QString transformName); lbajardsilogic@0: void modelRegenerationFailed(QString layerName, QString transformName); lbajardsilogic@0: lbajardsilogic@19: void audioSourceInfoAdded(AudioSourceInfoModel *); lbajardsilogic@19: lbajardsilogic@223: void newFilterAdded(PropertyContainer *); lbajardsilogic@79: void filterRemoved(QString); lbajardsilogic@79: lbajardsilogic@0: protected: lbajardsilogic@0: void releaseModel(Model *model); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Delete the given layer, and also its associated model if no lbajardsilogic@0: * longer used by any other layer. In general, this should be the lbajardsilogic@0: * only method used to delete layers -- doing so directly is a bit lbajardsilogic@0: * of a social gaffe. lbajardsilogic@0: */ lbajardsilogic@0: void deleteLayer(Layer *, bool force = false); lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: * Every model that is in use by a layer in the document must be lbajardsilogic@0: * found in either m_mainModel, m_derivedModels or lbajardsilogic@0: * m_importedModels. We own and control the lifespan of all of lbajardsilogic@0: * these models. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * The model that provides the underlying sample rate, etc. This lbajardsilogic@0: * model is not reference counted for layers, and is not freed lbajardsilogic@0: * unless it is replaced or the document is deleted. lbajardsilogic@0: */ lbajardsilogic@0: WaveFileModel *m_mainModel; lbajardsilogic@0: lbajardsilogic@19: /** lbajardsilogic@19: * The name of the file on the easaier server that provides info on title, author...etc lbajardsilogic@19: */ lbajardsilogic@19: QString m_audioSourceInfoFileName; lbajardsilogic@19: lbajardsilogic@19: /** lbajardsilogic@19: * The model that provides info on title, author...etc lbajardsilogic@19: */ lbajardsilogic@19: AudioSourceInfoModel *m_audioSourceInfoModel; lbajardsilogic@19: lbajardsilogic@0: struct ModelRecord lbajardsilogic@0: { lbajardsilogic@0: // Information associated with a non-main model. If this lbajardsilogic@0: // model is derived from another, then source will be non-NULL lbajardsilogic@0: // and the transform name will be set appropriately. If the lbajardsilogic@0: // transform name is set but source is NULL, then there was a lbajardsilogic@0: // transform involved but the (target) model has been modified lbajardsilogic@0: // since being generated from it. lbajardsilogic@0: const Model *source; lbajardsilogic@0: TransformId transform; lbajardsilogic@0: PluginTransform::ExecutionContext context; lbajardsilogic@0: QString configurationXml; lbajardsilogic@0: lbajardsilogic@0: // Count of the number of layers using this model. lbajardsilogic@0: int refcount; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: typedef std::map ModelMap; lbajardsilogic@0: ModelMap m_models; lbajardsilogic@0: lbajardsilogic@0: class AddLayerCommand : public Command lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: AddLayerCommand(Document *d, View *view, Layer *layer); lbajardsilogic@0: virtual ~AddLayerCommand(); lbajardsilogic@0: lbajardsilogic@0: virtual void execute(); lbajardsilogic@0: virtual void unexecute(); lbajardsilogic@0: virtual QString getName() const { return m_name; } lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: Document *m_d; lbajardsilogic@0: View *m_view; // I don't own this lbajardsilogic@0: Layer *m_layer; // Document owns this, but I determine its lifespans lbajardsilogic@0: QString m_name; lbajardsilogic@0: bool m_added; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: class RemoveLayerCommand : public Command lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: RemoveLayerCommand(Document *d, View *view, Layer *layer); lbajardsilogic@0: virtual ~RemoveLayerCommand(); lbajardsilogic@0: lbajardsilogic@0: virtual void execute(); lbajardsilogic@0: virtual void unexecute(); lbajardsilogic@0: virtual QString getName() const { return m_name; } lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: Document *m_d; lbajardsilogic@0: View *m_view; // I don't own this lbajardsilogic@0: Layer *m_layer; // Document owns this, but I determine its lifespan lbajardsilogic@0: QString m_name; lbajardsilogic@0: bool m_added; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: typedef std::map > LayerViewMap; lbajardsilogic@0: LayerViewMap m_layerViewMap; lbajardsilogic@0: lbajardsilogic@0: void addToLayerViewMap(Layer *, View *); lbajardsilogic@0: void removeFromLayerViewMap(Layer *, View *); lbajardsilogic@0: lbajardsilogic@0: QString getUniqueLayerName(QString candidate); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * And these are the layers. We also control the lifespans of lbajardsilogic@0: * these (usually through the commands used to add and remove them). lbajardsilogic@0: */ lbajardsilogic@0: typedef std::set LayerSet; lbajardsilogic@0: LayerSet m_layers; lbajardsilogic@79: lbajardsilogic@79: FilterStack *m_filterStack; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: #endif