Mercurial > hg > svapp
diff framework/Document.cpp @ 101:89a689720ee9 spectrogram-cache-rejig
* Merge from trunk
author | Chris Cannam |
---|---|
date | Wed, 27 Feb 2008 11:59:42 +0000 |
parents | 621c2edd1693 |
children |
line wrap: on
line diff
--- a/framework/Document.cpp Sun Nov 11 20:34:41 2007 +0000 +++ b/framework/Document.cpp Wed Feb 27 11:59:42 2008 +0000 @@ -29,6 +29,7 @@ #include "plugin/transform/ModelTransformerFactory.h" #include <QApplication> #include <QTextStream> +#include <QSettings> #include <iostream> // For alignment: @@ -36,6 +37,8 @@ #include "data/model/SparseTimeValueModel.h" #include "data/model/AlignmentModel.h" +//#define DEBUG_DOCUMENT 1 + //!!! still need to handle command history, documentRestored/documentModified Document::Document() : @@ -53,10 +56,14 @@ //still refer to it in various places that don't have access to //the document, be nice to fix that -// std::cerr << "\n\nDocument::~Document: about to clear command history" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "\n\nDocument::~Document: about to clear command history" << std::endl; +#endif CommandHistory::getInstance()->clear(); +#ifdef DEBUG_DOCUMENT std::cerr << "Document::~Document: about to delete layers" << std::endl; +#endif while (!m_layers.empty()) { deleteLayer(*m_layers.begin(), true); } @@ -73,19 +80,21 @@ std::cerr << "Document::~Document: WARNING: Main model is also" << " in models list!" << std::endl; } else if (model) { + model->aboutToDelete(); emit modelAboutToBeDeleted(model); - model->aboutToDelete(); delete model; } m_models.erase(m_models.begin()); } } -// std::cerr << "Document::~Document: About to get rid of main model" -// << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::~Document: About to get rid of main model" + << std::endl; +#endif if (m_mainModel) { + m_mainModel->aboutToDelete(); emit modelAboutToBeDeleted(m_mainModel); - m_mainModel->aboutToDelete(); } emit mainModelChanged(0); @@ -103,8 +112,10 @@ m_layers.insert(newLayer); +#ifdef DEBUG_DOCUMENT std::cerr << "Document::createLayer: Added layer of type " << type << ", now have " << m_layers.size() << " layers" << std::endl; +#endif emit layerAdded(newLayer); @@ -147,8 +158,10 @@ m_layers.insert(newLayer); +#ifdef DEBUG_DOCUMENT std::cerr << "Document::createImportedLayer: Added layer of type " << type << ", now have " << m_layers.size() << " layers" << std::endl; +#endif emit layerAdded(newLayer); return newLayer; @@ -157,6 +170,8 @@ Layer * Document::createEmptyLayer(LayerFactory::LayerType type) { + if (!m_mainModel) return 0; + Model *newModel = LayerFactory::getInstance()->createEmptyModel(type, m_mainModel); if (!newModel) return 0; @@ -188,24 +203,23 @@ } Layer * -Document::createDerivedLayer(TransformId transform, - Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml) +Document::createDerivedLayer(const Transform &transform, + const ModelTransformer::Input &input) { - Model *newModel = addDerivedModel(transform, inputModel, - context, configurationXml); + QString message; + Model *newModel = addDerivedModel(transform, input, message); if (!newModel) { - // error already printed to stderr by addDerivedModel - emit modelGenerationFailed(transform); + emit modelGenerationFailed(transform.getIdentifier(), message); return 0; + } else if (message != "") { + emit modelGenerationWarning(transform.getIdentifier(), message); } LayerFactory::LayerTypeSet types = LayerFactory::getInstance()->getValidLayerTypes(newModel); if (types.empty()) { - std::cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << transform.toStdString() << std::endl; + std::cerr << "WARNING: Document::createLayerForTransformer: no valid display layer for output of transform " << transform.getIdentifier().toStdString() << std::endl; delete newModel; return 0; } @@ -233,7 +247,8 @@ if (newLayer) { newLayer->setObjectName(getUniqueLayerName (TransformFactory::getInstance()-> - getTransformFriendlyName(transform))); + getTransformFriendlyName + (transform.getIdentifier()))); } emit layerAdded(newLayer); @@ -257,25 +272,31 @@ // using one of these. Carry out this replacement before we // delete any of the models. +#ifdef DEBUG_DOCUMENT std::cerr << "Document::setMainModel: Have " << m_layers.size() << " layers" << std::endl; +#endif for (LayerSet::iterator i = m_layers.begin(); i != m_layers.end(); ++i) { Layer *layer = *i; Model *model = layer->getModel(); -// std::cerr << "Document::setMainModel: inspecting model " -// << (model ? model->objectName().toStdString() : "(null)") << " in layer " -// << layer->objectName().toStdString() << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::setMainModel: inspecting model " + << (model ? model->objectName().toStdString() : "(null)") << " in layer " + << layer->objectName().toStdString() << std::endl; +#endif if (model == oldMainModel) { -// std::cerr << "... it uses the old main model, replacing" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "... it uses the old main model, replacing" << std::endl; +#endif LayerFactory::getInstance()->setModel(layer, m_mainModel); continue; } - if (m_models.find(model) == m_models.end()) { + if (model && (m_models.find(model) == m_models.end())) { std::cerr << "WARNING: Document::setMainModel: Unknown model " << model << " in layer " << layer << std::endl; // get rid of this hideous degenerate @@ -283,45 +304,63 @@ continue; } - if (m_models[model].source == oldMainModel) { + if (m_models[model].source && + (m_models[model].source == oldMainModel)) { -// std::cerr << "... it uses a model derived from the old main model, regenerating" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "... it uses a model derived from the old main model, regenerating" << std::endl; +#endif // This model was derived from the previous main // model: regenerate it. - TransformId transform = m_models[model].transform; - PluginTransformer::ExecutionContext context = m_models[model].context; + const Transform &transform = m_models[model].transform; + QString transformId = transform.getIdentifier(); + //!!! We have a problem here if the number of channels in + //the main model has changed. + + QString message; Model *replacementModel = addDerivedModel(transform, - m_mainModel, - context, - m_models[model].configurationXml); + ModelTransformer::Input + (m_mainModel, m_models[model].channel), + message); if (!replacementModel) { std::cerr << "WARNING: Document::setMainModel: Failed to regenerate model for transform \"" - << transform.toStdString() << "\"" << " in layer " << layer << std::endl; - if (failedTransformers.find(transform) == failedTransformers.end()) { + << transformId.toStdString() << "\"" << " in layer " << layer << std::endl; + if (failedTransformers.find(transformId) + == failedTransformers.end()) { emit modelRegenerationFailed(layer->objectName(), - transform); - failedTransformers.insert(transform); + transformId, + message); + failedTransformers.insert(transformId); } obsoleteLayers.push_back(layer); } else { + if (message != "") { + emit modelRegenerationWarning(layer->objectName(), + transformId, + message); + } +#ifdef DEBUG_DOCUMENT std::cerr << "Replacing model " << model << " (type " << typeid(*model).name() << ") with model " << replacementModel << " (type " << typeid(*replacementModel).name() << ") in layer " << layer << " (name " << layer->objectName().toStdString() << ")" << std::endl; +#endif RangeSummarisableTimeValueModel *rm = dynamic_cast<RangeSummarisableTimeValueModel *>(replacementModel); +#ifdef DEBUG_DOCUMENT if (rm) { std::cerr << "new model has " << rm->getChannelCount() << " channels " << std::endl; } else { std::cerr << "new model is not a RangeSummarisableTimeValueModel!" << std::endl; } +#endif setModel(layer, replacementModel); } } @@ -332,23 +371,36 @@ } for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { - if (i->first->getAlignmentReference() == oldMainModel) { + + if (m_autoAlignment) { + + alignModel(i->first); + + } else if (oldMainModel && + (i->first->getAlignmentReference() == oldMainModel)) { + alignModel(i->first); } } + if (oldMainModel) { + oldMainModel->aboutToDelete(); + emit modelAboutToBeDeleted(oldMainModel); + } + + if (m_autoAlignment) { + alignModel(m_mainModel); + } + emit mainModelChanged(m_mainModel); - // we already emitted modelAboutToBeDeleted for this delete oldMainModel; } void -Document::addDerivedModel(TransformId transform, - Model *inputModel, - const PluginTransformer::ExecutionContext &context, - Model *outputModelToAdd, - QString configurationXml) +Document::addDerivedModel(const Transform &transform, + const ModelTransformer::Input &input, + Model *outputModelToAdd) { if (m_models.find(outputModelToAdd) != m_models.end()) { std::cerr << "WARNING: Document::addDerivedModel: Model already added" @@ -356,16 +408,17 @@ return; } -// std::cerr << "Document::addDerivedModel: source is " << inputModel << " \"" << inputModel->objectName().toStdString() << "\"" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::addDerivedModel: source is " << input.getModel() << " \"" << input.getModel()->objectName().toStdString() << "\"" << std::endl; +#endif ModelRecord rec; - rec.source = inputModel; + rec.source = input.getModel(); + rec.channel = input.getChannel(); rec.transform = transform; - rec.context = context; - rec.configurationXml = configurationXml; rec.refcount = 0; - outputModelToAdd->setSourceModel(inputModel); + outputModelToAdd->setSourceModel(input.getModel()); m_models[outputModelToAdd] = rec; @@ -384,7 +437,6 @@ ModelRecord rec; rec.source = 0; - rec.transform = ""; rec.refcount = 0; m_models[model] = rec; @@ -395,29 +447,41 @@ } Model * -Document::addDerivedModel(TransformId transform, - Model *inputModel, - const PluginTransformer::ExecutionContext &context, - QString configurationXml) +Document::addDerivedModel(const Transform &transform, + const ModelTransformer::Input &input, + QString &message) { Model *model = 0; for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { if (i->second.transform == transform && - i->second.source == inputModel && - i->second.context == context && - i->second.configurationXml == configurationXml) { + i->second.source == input.getModel() && + i->second.channel == input.getChannel()) { return i->first; } } model = ModelTransformerFactory::getInstance()->transform - (transform, inputModel, context, configurationXml); + (transform, input, message); + + // The transform we actually used was presumably identical to the + // one asked for, except that the version of the plugin may + // differ. It's possible that the returned message contains a + // warning about this; that doesn't concern us here, but we do + // need to ensure that the transform we remember is correct for + // what was actually applied, with the current plugin version. + + Transform applied = transform; + applied.setPluginVersion + (TransformFactory::getInstance()-> + getDefaultTransformFor(transform.getIdentifier(), + lrintf(transform.getSampleRate())) + .getPluginVersion()); if (!model) { - std::cerr << "WARNING: Document::addDerivedModel: no output model for transform " << transform.toStdString() << std::endl; + std::cerr << "WARNING: Document::addDerivedModel: no output model for transform " << transform.getIdentifier().toStdString() << std::endl; } else { - addDerivedModel(transform, inputModel, context, model, configurationXml); + addDerivedModel(applied, input, model); } return model; @@ -470,8 +534,8 @@ << "their source fields appropriately" << std::endl; } + model->aboutToDelete(); emit modelAboutToBeDeleted(model); - model->aboutToDelete(); m_models.erase(model); delete model; } @@ -490,7 +554,9 @@ if (force) { +#ifdef DEBUG_DOCUMENT std::cerr << "(force flag set -- deleting from all views)" << std::endl; +#endif for (std::set<View *>::iterator j = m_layerViewMap[layer].begin(); j != m_layerViewMap[layer].end(); ++j) { @@ -577,10 +643,12 @@ { Model *model = layer->getModel(); if (!model) { -// std::cerr << "Document::addLayerToView: Layer (\"" -// << layer->objectName().toStdString() -// << "\") with no model being added to view: " -// << "normally you want to set the model first" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::addLayerToView: Layer (\"" + << layer->objectName().toStdString() + << "\") with no model being added to view: " + << "normally you want to set the model first" << std::endl; +#endif } else { if (model != m_mainModel && m_models.find(model) == m_models.end()) { @@ -661,7 +729,7 @@ } std::vector<Model *> -Document::getTransformerInputModels() +Document::getTransformInputModels() { std::vector<Model *> models; @@ -686,9 +754,28 @@ } bool +Document::isKnownModel(const Model *model) const +{ + if (model == m_mainModel) return true; + return (m_models.find(const_cast<Model *>(model)) != m_models.end()); +} + +TransformId +Document::getAlignmentTransformName() +{ + QSettings settings; + settings.beginGroup("Alignment"); + TransformId id = + settings.value("transform-id", + "vamp:match-vamp-plugin:match:path").toString(); + settings.endGroup(); + return id; +} + +bool Document::canAlign() { - TransformId id = "vamp:match-vamp-plugin:match:path"; + TransformId id = getAlignmentTransformName(); TransformFactory *factory = TransformFactory::getInstance(); return factory->haveTransform(id); } @@ -696,14 +783,27 @@ void Document::alignModel(Model *model) { - if (!m_mainModel || model == m_mainModel) return; + if (!m_mainModel) return; RangeSummarisableTimeValueModel *rm = dynamic_cast<RangeSummarisableTimeValueModel *>(model); if (!rm) return; - if (rm->getAlignmentReference() == m_mainModel) return; + if (rm->getAlignmentReference() == m_mainModel) { + std::cerr << "Document::alignModel: model " << rm << " is already aligned to main model " << m_mainModel << std::endl; + return; + } + if (model == m_mainModel) { + // The reference has an empty alignment to itself. This makes + // it possible to distinguish between the reference and any + // unaligned model just by looking at the model itself, + // without also knowing what the main model is + std::cerr << "Document::alignModel(" << model << "): is main model, setting appropriately" << std::endl; + rm->setAlignment(new AlignmentModel(model, model, 0, 0)); + return; + } + // This involves creating three new models: // 1. an AggregateWaveModel to provide the mixdowns of the main @@ -733,22 +833,34 @@ Model *aggregate = new AggregateWaveModel(components); - TransformId id = "vamp:match-vamp-plugin:match:path"; + TransformId id = "vamp:match-vamp-plugin:match:path"; //!!! configure - ModelTransformerFactory *factory = ModelTransformerFactory::getInstance(); + TransformFactory *tf = TransformFactory::getInstance(); - PluginTransformer::ExecutionContext context = - factory->getDefaultContextForTransformer(id, aggregate); - context.stepSize = context.blockSize/2; + Transform transform = tf->getDefaultTransformFor + (id, aggregate->getSampleRate()); - Model *transformOutput = factory->transform - (id, aggregate, context, "<plugin param-serialise=\"1\"/>"); + transform.setStepSize(transform.getBlockSize()/2); + transform.setParameter("serialise", 1); + + std::cerr << "Document::alignModel: Alignment transform step size " << transform.getStepSize() << ", block size " << transform.getBlockSize() << std::endl; + + ModelTransformerFactory *mtf = ModelTransformerFactory::getInstance(); + + QString message; + Model *transformOutput = mtf->transform(transform, aggregate, message); + + if (!transformOutput) { + transform.setStepSize(0); + transformOutput = mtf->transform(transform, aggregate, message); + } SparseTimeValueModel *path = dynamic_cast<SparseTimeValueModel *> (transformOutput); if (!path) { std::cerr << "Document::alignModel: ERROR: Failed to create alignment path (no MATCH plugin?)" << std::endl; + emit alignmentFailed(id, message); delete transformOutput; delete aggregate; return; @@ -766,6 +878,7 @@ for (ModelMap::iterator i = m_models.begin(); i != m_models.end(); ++i) { alignModel(i->first); } + alignModel(m_mainModel); } Document::AddLayerCommand::AddLayerCommand(Document *d, @@ -781,7 +894,9 @@ Document::AddLayerCommand::~AddLayerCommand() { -// std::cerr << "Document::AddLayerCommand::~AddLayerCommand" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::AddLayerCommand::~AddLayerCommand" << std::endl; +#endif if (!m_added) { m_d->deleteLayer(m_layer); } @@ -829,7 +944,9 @@ Document::RemoveLayerCommand::~RemoveLayerCommand() { -// std::cerr << "Document::RemoveLayerCommand::~RemoveLayerCommand" << std::endl; +#ifdef DEBUG_DOCUMENT + std::cerr << "Document::RemoveLayerCommand::~RemoveLayerCommand" << std::endl; +#endif if (!m_added) { m_d->deleteLayer(m_layer); } @@ -916,7 +1033,7 @@ bool writeModel = true; bool haveDerivation = false; - if (rec.source && rec.transform != "") { + if (rec.source && rec.transform.getIdentifier() != "") { haveDerivation = true; } @@ -933,33 +1050,8 @@ } if (haveDerivation) { - - QString extentsAttributes; - if (rec.context.startFrame != 0 || - rec.context.duration != 0) { - extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") - .arg(rec.context.startFrame) - .arg(rec.context.duration); - } - - out << indent; - out << QString(" <derivation source=\"%1\" model=\"%2\" channel=\"%3\" domain=\"%4\" stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" transform=\"%9\"") - .arg(XmlExportable::getObjectExportId(rec.source)) - .arg(XmlExportable::getObjectExportId(i->first)) - .arg(rec.context.channel) - .arg(rec.context.domain) - .arg(rec.context.stepSize) - .arg(rec.context.blockSize) - .arg(extentsAttributes) - .arg(int(rec.context.windowType)) - .arg(XmlExportable::encodeEntities(rec.transform)); - - if (rec.configurationXml != "") { - out << ">\n " + indent + rec.configurationXml - + "\n" + indent + " </derivation>\n"; - } else { - out << "/>\n"; - } + writeBackwardCompatibleDerivation(out, indent + " ", + i->first, rec); } //!!! We should probably own the PlayParameterRepository @@ -982,4 +1074,82 @@ out << indent + "</data>\n"; } +void +Document::writeBackwardCompatibleDerivation(QTextStream &out, QString indent, + Model *targetModel, + const ModelRecord &rec) const +{ + // There is a lot of redundancy in the XML we output here, because + // we want it to work with older SV session file reading code as + // well. + // + // Formerly, a transform was described using a derivation element + // which set out the source and target models, execution context + // (step size, input channel etc) and transform id, containing a + // plugin element which set out the transform parameters and so + // on. (The plugin element came from a "configurationXml" string + // obtained from PluginXml.) + // + // This has been replaced by a derivation element setting out the + // source and target models and input channel, containing a + // transform element which sets out everything in the Transform. + // + // In order to retain compatibility with older SV code, however, + // we have to write out the same stuff into the derivation as + // before, and manufacture an appropriate plugin element as well + // as the transform element. In order that newer code knows it's + // dealing with a newer format, we will also write an attribute + // 'type="transform"' in the derivation element. + const Transform &transform = rec.transform; + + // Just for reference, this is what we would write if we didn't + // have to be backward compatible: + // + // out << indent + // << QString("<derivation type=\"transform\" source=\"%1\" " + // "model=\"%2\" channel=\"%3\">\n") + // .arg(XmlExportable::getObjectExportId(rec.source)) + // .arg(XmlExportable::getObjectExportId(targetModel)) + // .arg(rec.channel); + // + // transform.toXml(out, indent + " "); + // + // out << indent << "</derivation>\n"; + // + // Unfortunately, we can't just do that. So we do this... + + QString extentsAttributes; + if (transform.getStartTime() != RealTime::zeroTime || + transform.getDuration() != RealTime::zeroTime) { + extentsAttributes = QString("startFrame=\"%1\" duration=\"%2\" ") + .arg(RealTime::realTime2Frame(transform.getStartTime(), + targetModel->getSampleRate())) + .arg(RealTime::realTime2Frame(transform.getDuration(), + targetModel->getSampleRate())); + } + + out << indent; + out << QString("<derivation type=\"transform\" source=\"%1\" " + "model=\"%2\" channel=\"%3\" domain=\"%4\" " + "stepSize=\"%5\" blockSize=\"%6\" %7windowType=\"%8\" " + "transform=\"%9\">\n") + .arg(XmlExportable::getObjectExportId(rec.source)) + .arg(XmlExportable::getObjectExportId(targetModel)) + .arg(rec.channel) + .arg(TransformFactory::getInstance()->getTransformInputDomain + (transform.getIdentifier())) + .arg(transform.getStepSize()) + .arg(transform.getBlockSize()) + .arg(extentsAttributes) + .arg(int(transform.getWindowType())) + .arg(XmlExportable::encodeEntities(transform.getIdentifier())); + + transform.toXml(out, indent + " "); + + out << indent << " " + << TransformFactory::getInstance()->getPluginConfigurationXml(transform); + + out << indent << "</derivation>\n"; +} +