Chris@45: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@45: Chris@45: /* Chris@45: Sonic Visualiser Chris@45: An audio file viewer and annotation editor. Chris@45: Centre for Digital Music, Queen Mary, University of London. Chris@45: This file copyright 2006 Chris Cannam and QMUL. Chris@45: Chris@45: This program is free software; you can redistribute it and/or Chris@45: modify it under the terms of the GNU General Public License as Chris@45: published by the Free Software Foundation; either version 2 of the Chris@45: License, or (at your option) any later version. See the file Chris@45: COPYING included with this distribution for more information. Chris@45: */ Chris@45: Chris@635: #ifndef SV_FILE_READER_H Chris@635: #define SV_FILE_READER_H Chris@45: Chris@45: #include "layer/LayerFactory.h" Chris@106: #include "transform/Transform.h" Chris@45: Chris@45: #include Chris@45: Chris@45: #include Chris@45: Chris@45: class Pane; Chris@45: class Model; Chris@685: class Path; Chris@45: class Document; Chris@45: class PlayParameters; Chris@45: Chris@45: class SVFileReaderPaneCallback Chris@45: { Chris@45: public: Chris@45: virtual ~SVFileReaderPaneCallback(); Chris@45: virtual Pane *addPane() = 0; Chris@45: virtual void setWindowSize(int width, int height) = 0; Chris@435: virtual void addSelection(sv_frame_t start, sv_frame_t end) = 0; Chris@45: }; Chris@45: Chris@45: /** Chris@45: SVFileReader loads Sonic Visualiser XML files. (The SV file Chris@45: format is bzipped XML.) Chris@45: Chris@45: Some notes about the SV XML format follow. We're very lazy with Chris@45: our XML: there's no schema or DTD, and we depend heavily on Chris@45: elements being in a particular order. Chris@45: Chris@45: \verbatim Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@72: Chris@72: Chris@72: Chris@72: Chris@72: Chris@72: Chris@72: Chris@72: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@587: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: Chris@45: \endverbatim Chris@45: */ Chris@45: Chris@45: Chris@79: class SVFileReader : public QObject, QXmlDefaultHandler Chris@45: { Chris@79: Q_OBJECT Chris@79: Chris@45: public: Chris@45: SVFileReader(Document *document, Chris@595: SVFileReaderPaneCallback &callback, Chris@45: QString location = ""); // for audio file locate mechanism Chris@45: virtual ~SVFileReader(); Chris@45: Chris@45: void parse(const QString &xmlData); Chris@45: void parse(QXmlInputSource &source); Chris@45: Chris@45: bool isOK(); Chris@45: QString getErrorString() const { return m_errorString; } Chris@45: Chris@45: // For loading a single layer onto an existing pane Chris@45: void setCurrentPane(Pane *pane) { m_currentPane = pane; } Chris@45: Chris@634: bool startElement(const QString &namespaceURI, Chris@685: const QString &localName, Chris@685: const QString &qName, Chris@685: const QXmlAttributes& atts) override; Chris@685: Chris@634: bool characters(const QString &) override; Chris@45: Chris@634: bool endElement(const QString &namespaceURI, Chris@685: const QString &localName, Chris@685: const QString &qName) override; Chris@45: Chris@634: bool error(const QXmlParseException &exception) override; Chris@634: bool fatalError(const QXmlParseException &exception) override; Chris@45: Chris@140: enum FileType Chris@140: { Chris@140: SVSessionFile, Chris@140: SVLayerFile, Chris@140: UnknownFileType Chris@140: }; Chris@140: Chris@140: static FileType identifyXmlFile(QString path); Chris@140: Chris@79: signals: Chris@79: void modelRegenerationFailed(QString layerName, QString transformName, Chris@79: QString message); Chris@79: void modelRegenerationWarning(QString layerName, QString transformName, Chris@79: QString message); Chris@79: Chris@45: protected: Chris@45: bool readWindow(const QXmlAttributes &); Chris@45: bool readModel(const QXmlAttributes &); Chris@45: bool readView(const QXmlAttributes &); Chris@45: bool readLayer(const QXmlAttributes &); Chris@45: bool readDatasetStart(const QXmlAttributes &); Chris@45: bool addBinToDataset(const QXmlAttributes &); Chris@45: bool addPointToDataset(const QXmlAttributes &); Chris@45: bool addRowToDataset(const QXmlAttributes &); Chris@45: bool readRowData(const QString &); Chris@45: bool readDerivation(const QXmlAttributes &); Chris@45: bool readPlayParameters(const QXmlAttributes &); Chris@45: bool readPlugin(const QXmlAttributes &); Chris@308: bool readPluginForTransform(const QXmlAttributes &); Chris@308: bool readPluginForPlayback(const QXmlAttributes &); Chris@72: bool readTransform(const QXmlAttributes &); Chris@72: bool readParameter(const QXmlAttributes &); Chris@45: bool readSelection(const QXmlAttributes &); Chris@45: bool readMeasurement(const QXmlAttributes &); Chris@629: Chris@629: void makeAggregateModels(); Chris@45: void addUnaddedModels(); Chris@45: Chris@685: // We use the term "pending" of things that have been referred to Chris@685: // but not yet constructed because their definitions are Chris@685: // incomplete. They are just referred to with an ExportId. Models Chris@685: // that have been constructed are always added straight away to Chris@685: // ById and are referred to with a ModelId (everywhere where Chris@685: // previously we would have used a Model *). m_models maps from Chris@685: // ExportId (as read from the file) to complete Models, or to a Chris@685: // ModelId of None for any model that could not be constructed for Chris@685: // some reason. Chris@685: Chris@685: typedef XmlExportable::ExportId ExportId; Chris@685: Chris@685: bool haveModel(ExportId id) { Chris@685: return (m_models.find(id) != m_models.end()) && !m_models[id].isNone(); Chris@45: } Chris@685: Chris@629: struct PendingAggregateRec { Chris@629: QString name; Chris@629: sv_samplerate_t sampleRate; Chris@685: std::vector components; Chris@629: }; Chris@629: Chris@45: Document *m_document; Chris@45: SVFileReaderPaneCallback &m_paneCallback; Chris@45: QString m_location; Chris@45: Pane *m_currentPane; Chris@685: std::map m_layers; Chris@685: std::map m_models; Chris@685: std::map m_paths; Chris@685: std::set m_addedModels; // i.e. added to Document, not just ById Chris@685: std::map m_pendingAggregates; Chris@685: Chris@685: // A model element often contains a dataset id, and the dataset Chris@685: // then follows it. When the model is read, an entry in this map Chris@685: // is added, mapping from the dataset's export id (the actual Chris@685: // dataset has not been read yet) back to the export id of the Chris@685: // object that needs it. We map to export id rather than model id, Chris@685: // because the object might be a path rather than a model. Chris@685: std::map m_awaitingDatasets; Chris@685: Chris@685: // And then this is the model or path that a dataset element is Chris@685: // currently being read into, i.e. the value looked up from Chris@685: // m_awaitingDatasets at the point where the dataset is found. Chris@685: ExportId m_currentDataset; Chris@685: Chris@45: Layer *m_currentLayer; Chris@685: ModelId m_currentDerivedModel; Chris@685: ExportId m_pendingDerivedModel; Chris@45: PlayParameters *m_currentPlayParameters; Chris@72: Transform m_currentTransform; Chris@685: ModelId m_currentTransformSource; Chris@72: int m_currentTransformChannel; Chris@72: bool m_currentTransformIsNewStyle; Chris@45: QString m_datasetSeparator; Chris@45: bool m_inRow; Chris@45: bool m_inLayer; Chris@45: bool m_inView; Chris@45: bool m_inData; Chris@45: bool m_inSelections; Chris@45: int m_rowNumber; Chris@45: QString m_errorString; Chris@45: bool m_ok; Chris@45: }; Chris@45: Chris@45: #endif