Chris@58: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@0: Chris@0: /* Chris@59: Sonic Visualiser Chris@59: An audio file viewer and annotation editor. Chris@59: Centre for Digital Music, Queen Mary, University of London. Chris@59: This file copyright 2006 Chris Cannam. Chris@0: Chris@59: This program is free software; you can redistribute it and/or Chris@59: modify it under the terms of the GNU General Public License as Chris@59: published by the Free Software Foundation; either version 2 of the Chris@59: License, or (at your option) any later version. See the file Chris@59: COPYING included with this distribution for more information. Chris@0: */ Chris@0: Chris@0: #include "LayerFactory.h" Chris@0: Chris@0: #include "WaveformLayer.h" Chris@0: #include "SpectrogramLayer.h" Chris@0: #include "TimeRulerLayer.h" Chris@0: #include "TimeInstantLayer.h" Chris@0: #include "TimeValueLayer.h" Chris@30: #include "NoteLayer.h" matthiasm@621: #include "FlexiNoteLayer.h" Chris@411: #include "RegionLayer.h" Chris@35: #include "TextLayer.h" Chris@303: #include "ImageLayer.h" Chris@0: #include "Colour3DPlotLayer.h" Chris@133: #include "SpectrumLayer.h" Chris@193: #include "SliceLayer.h" Chris@193: #include "SliceableLayer.h" Chris@0: Chris@360: #include "base/Clipboard.h" Chris@360: Chris@128: #include "data/model/RangeSummarisableTimeValueModel.h" Chris@128: #include "data/model/DenseTimeValueModel.h" Chris@128: #include "data/model/SparseOneDimensionalModel.h" Chris@128: #include "data/model/SparseTimeValueModel.h" Chris@128: #include "data/model/NoteModel.h" matthiasm@621: #include "data/model/FlexiNoteModel.h" Chris@411: #include "data/model/RegionModel.h" Chris@128: #include "data/model/TextModel.h" Chris@303: #include "data/model/ImageModel.h" Chris@128: #include "data/model/DenseThreeDimensionalModel.h" Chris@156: #include "data/model/WaveFileModel.h" Chris@156: #include "data/model/WritableWaveFileModel.h" Chris@0: Chris@326: #include Chris@326: #include Chris@326: #include Chris@326: #include Chris@326: Chris@326: #include Chris@326: Chris@0: LayerFactory * Chris@0: LayerFactory::m_instance = new LayerFactory; Chris@0: Chris@0: LayerFactory * Chris@125: LayerFactory::getInstance() Chris@0: { Chris@0: return m_instance; Chris@0: } Chris@0: Chris@0: LayerFactory::~LayerFactory() Chris@0: { Chris@0: } Chris@0: Chris@0: QString Chris@0: LayerFactory::getLayerPresentationName(LayerType type) Chris@0: { Chris@0: switch (type) { Chris@0: case Waveform: return Layer::tr("Waveform"); Chris@0: case Spectrogram: return Layer::tr("Spectrogram"); Chris@0: case TimeRuler: return Layer::tr("Ruler"); Chris@0: case TimeInstants: return Layer::tr("Time Instants"); Chris@0: case TimeValues: return Layer::tr("Time Values"); Chris@30: case Notes: return Layer::tr("Notes"); gyorgyf@625: case FlexiNotes: return Layer::tr("Flexible Notes"); Chris@411: case Regions: return Layer::tr("Regions"); Chris@35: case Text: return Layer::tr("Text"); Chris@303: case Image: return Layer::tr("Images"); Chris@0: case Colour3DPlot: return Layer::tr("Colour 3D Plot"); Chris@133: case Spectrum: return Layer::tr("Spectrum"); Chris@193: case Slice: return Layer::tr("Time Slice"); Chris@0: Chris@0: case MelodicRangeSpectrogram: Chris@0: // The user can change all the parameters of this after the Chris@0: // fact -- there's nothing permanently melodic-range about it Chris@0: // that should be encoded in its name Chris@0: return Layer::tr("Spectrogram"); Chris@11: Chris@37: case PeakFrequencySpectrogram: Chris@37: // likewise Chris@37: return Layer::tr("Spectrogram"); Chris@37: Chris@11: default: break; Chris@0: } Chris@0: Chris@0: return Layer::tr("Layer"); Chris@0: } Chris@0: Chris@193: bool Chris@193: LayerFactory::isLayerSliceable(const Layer *layer) Chris@193: { Chris@193: if (dynamic_cast(layer)) { Chris@193: if (dynamic_cast(layer)) { Chris@193: Chris@193: //!!! We can create slices of spectrograms, but there's a Chris@193: // problem managing the models. The source model for the Chris@193: // slice layer has to be one of the spectrogram's FFT Chris@193: // models -- that's fine, except that we can't store & Chris@193: // recall the slice layer with a reference to that model Chris@193: // because the model is internal to the spectrogram layer Chris@193: // and the document has no record of it. We would need Chris@193: // some other way of managing models that are used in this Chris@193: // way. For the moment we just don't allow slices of Chris@193: // spectrograms -- and provide a spectrum layer for this Chris@193: // instead. Chris@193: // Chris@193: // This business needs a bit more thought -- either come Chris@193: // up with a sensible way to deal with that stuff, or Chris@193: // simplify the existing slice layer logic so that it Chris@193: // doesn't have to deal with models disappearing on it at Chris@193: // all (and use the normal Document setModel mechanism to Chris@193: // set its sliceable model instead of the fancy pants Chris@193: // nonsense it's doing at the moment). Chris@193: Chris@193: return false; Chris@193: } Chris@193: return true; Chris@193: } Chris@193: return false; Chris@193: } Chris@193: Chris@0: LayerFactory::LayerTypeSet Chris@0: LayerFactory::getValidLayerTypes(Model *model) Chris@0: { Chris@0: LayerTypeSet types; Chris@0: Chris@0: if (dynamic_cast(model)) { Chris@0: types.insert(Colour3DPlot); Chris@193: types.insert(Slice); Chris@193: } Chris@193: Chris@193: if (dynamic_cast(model)) { Chris@193: types.insert(Waveform); Chris@0: } Chris@0: Chris@0: if (dynamic_cast(model)) { Chris@0: types.insert(Spectrogram); Chris@0: types.insert(MelodicRangeSpectrogram); Chris@37: types.insert(PeakFrequencySpectrogram); Chris@0: } Chris@0: Chris@0: if (dynamic_cast(model)) { Chris@0: types.insert(TimeInstants); Chris@0: } Chris@0: Chris@0: if (dynamic_cast(model)) { Chris@0: types.insert(TimeValues); Chris@411: } Chris@411: Chris@35: if (dynamic_cast(model)) { Chris@35: types.insert(Notes); Chris@0: } Chris@0: Chris@782: // NOTE: GF: types is a set, so order of insertion does not matter matthiasm@621: if (dynamic_cast(model)) { matthiasm@621: types.insert(FlexiNotes); matthiasm@621: } matthiasm@621: Chris@411: if (dynamic_cast(model)) { Chris@411: types.insert(Regions); Chris@411: } Chris@411: Chris@35: if (dynamic_cast(model)) { Chris@35: types.insert(Text); Chris@30: } Chris@30: Chris@303: if (dynamic_cast(model)) { Chris@303: types.insert(Image); Chris@303: } Chris@303: Chris@133: if (dynamic_cast(model)) { Chris@133: types.insert(Spectrum); Chris@133: } Chris@133: Chris@0: // We don't count TimeRuler here as it doesn't actually display Chris@0: // the data, although it can be backed by any model Chris@0: Chris@0: return types; Chris@0: } Chris@0: Chris@17: LayerFactory::LayerTypeSet Chris@17: LayerFactory::getValidEmptyLayerTypes() Chris@17: { Chris@17: LayerTypeSet types; Chris@17: types.insert(TimeInstants); Chris@17: types.insert(TimeValues); Chris@782: types.insert(FlexiNotes); Chris@30: types.insert(Notes); Chris@411: types.insert(Regions); Chris@35: types.insert(Text); Chris@303: types.insert(Image); Chris@17: //!!! and in principle Colour3DPlot -- now that's a challenge Chris@17: return types; Chris@17: } Chris@17: Chris@0: LayerFactory::LayerType Chris@6: LayerFactory::getLayerType(const Layer *layer) Chris@0: { Chris@6: if (dynamic_cast(layer)) return Waveform; Chris@6: if (dynamic_cast(layer)) return Spectrogram; Chris@6: if (dynamic_cast(layer)) return TimeRuler; Chris@6: if (dynamic_cast(layer)) return TimeInstants; Chris@6: if (dynamic_cast(layer)) return TimeValues; Chris@782: if (dynamic_cast(layer)) return FlexiNotes; Chris@30: if (dynamic_cast(layer)) return Notes; Chris@411: if (dynamic_cast(layer)) return Regions; Chris@35: if (dynamic_cast(layer)) return Text; Chris@303: if (dynamic_cast(layer)) return Image; Chris@6: if (dynamic_cast(layer)) return Colour3DPlot; Chris@133: if (dynamic_cast(layer)) return Spectrum; Chris@193: if (dynamic_cast(layer)) return Slice; Chris@6: return UnknownLayer; Chris@6: } Chris@6: Chris@6: QString Chris@17: LayerFactory::getLayerIconName(LayerType type) Chris@17: { Chris@17: switch (type) { Chris@17: case Waveform: return "waveform"; Chris@17: case Spectrogram: return "spectrogram"; Chris@17: case TimeRuler: return "timeruler"; Chris@17: case TimeInstants: return "instants"; Chris@17: case TimeValues: return "values"; Chris@30: case Notes: return "notes"; Chris@782: case FlexiNotes: return "flexinotes"; Chris@411: case Regions: return "regions"; Chris@35: case Text: return "text"; Chris@303: case Image: return "image"; Chris@17: case Colour3DPlot: return "colour3d"; Chris@133: case Spectrum: return "spectrum"; Chris@193: case Slice: return "spectrum"; Chris@326: case MelodicRangeSpectrogram: return "spectrogram"; Chris@326: case PeakFrequencySpectrogram: return "spectrogram"; Chris@17: default: return "unknown"; Chris@17: } Chris@17: } Chris@17: Chris@17: QString Chris@6: LayerFactory::getLayerTypeName(LayerType type) Chris@6: { Chris@6: switch (type) { Chris@6: case Waveform: return "waveform"; Chris@6: case Spectrogram: return "spectrogram"; Chris@6: case TimeRuler: return "timeruler"; Chris@6: case TimeInstants: return "timeinstants"; Chris@6: case TimeValues: return "timevalues"; Chris@30: case Notes: return "notes"; matthiasm@623: case FlexiNotes: return "flexinotes"; Chris@411: case Regions: return "regions"; Chris@35: case Text: return "text"; Chris@303: case Image: return "image"; Chris@6: case Colour3DPlot: return "colour3dplot"; Chris@133: case Spectrum: return "spectrum"; Chris@193: case Slice: return "slice"; Chris@326: case MelodicRangeSpectrogram: return "melodicrange"; Chris@326: case PeakFrequencySpectrogram: return "peakfrequency"; Chris@6: default: return "unknown"; Chris@6: } Chris@6: } Chris@6: Chris@6: LayerFactory::LayerType Chris@6: LayerFactory::getLayerTypeForName(QString name) Chris@6: { Chris@6: if (name == "waveform") return Waveform; Chris@6: if (name == "spectrogram") return Spectrogram; Chris@6: if (name == "timeruler") return TimeRuler; Chris@6: if (name == "timeinstants") return TimeInstants; Chris@6: if (name == "timevalues") return TimeValues; matthiasm@623: if (name == "flexinotes") return FlexiNotes; Chris@411: if (name == "regions") return Regions; Chris@35: if (name == "text") return Text; Chris@303: if (name == "image") return Image; Chris@6: if (name == "colour3dplot") return Colour3DPlot; Chris@133: if (name == "spectrum") return Spectrum; Chris@193: if (name == "slice") return Slice; Chris@0: return UnknownLayer; Chris@0: } Chris@0: Chris@0: void Chris@0: LayerFactory::setModel(Layer *layer, Model *model) Chris@0: { Chris@156: // if (trySetModel(layer, model)) Chris@156: // return; gyorgyf@625: Chris@156: if (trySetModel(layer, model)) Chris@156: return; Chris@156: Chris@156: if (trySetModel(layer, model)) Chris@0: return; Chris@0: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@0: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@0: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@0: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@0: gyorgyf@626: if (trySetModel(layer, model)) gyorgyf@626: return; Chris@30: Chris@782: // GF: added FlexiNoteLayer gyorgyf@626: if (trySetModel(layer, model)) gyorgyf@626: return; gyorgyf@625: Chris@411: if (trySetModel(layer, model)) Chris@411: return; Chris@411: Chris@35: if (trySetModel(layer, model)) Chris@35: return; Chris@35: Chris@303: if (trySetModel(layer, model)) Chris@303: return; Chris@303: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@0: Chris@0: if (trySetModel(layer, model)) Chris@0: return; Chris@133: Chris@133: if (trySetModel(layer, model)) Chris@133: return; Chris@193: Chris@193: // if (trySetModel(layer, model)) Chris@193: // return; Chris@0: } Chris@0: Chris@17: Model * Chris@17: LayerFactory::createEmptyModel(LayerType layerType, Model *baseModel) Chris@17: { Chris@17: if (layerType == TimeInstants) { Chris@17: return new SparseOneDimensionalModel(baseModel->getSampleRate(), 1); Chris@17: } else if (layerType == TimeValues) { Chris@245: return new SparseTimeValueModel(baseModel->getSampleRate(), 1, true); Chris@782: } else if (layerType == FlexiNotes) { matthiasm@623: return new FlexiNoteModel(baseModel->getSampleRate(), 1, true); Chris@30: } else if (layerType == Notes) { Chris@245: return new NoteModel(baseModel->getSampleRate(), 1, true); Chris@411: } else if (layerType == Regions) { Chris@411: return new RegionModel(baseModel->getSampleRate(), 1, true); Chris@35: } else if (layerType == Text) { Chris@35: return new TextModel(baseModel->getSampleRate(), 1, true); Chris@303: } else if (layerType == Image) { Chris@303: return new ImageModel(baseModel->getSampleRate(), 1, true); Chris@17: } else { Chris@17: return 0; Chris@17: } Chris@17: } Chris@17: Chris@53: int Chris@53: LayerFactory::getChannel(Layer *layer) Chris@53: { Chris@53: if (dynamic_cast(layer)) { Chris@53: return dynamic_cast(layer)->getChannel(); Chris@53: } Chris@53: if (dynamic_cast(layer)) { Chris@53: return dynamic_cast(layer)->getChannel(); Chris@53: } Chris@53: return -1; Chris@53: } Chris@53: Chris@53: void Chris@53: LayerFactory::setChannel(Layer *layer, int channel) Chris@53: { Chris@53: if (dynamic_cast(layer)) { Chris@53: dynamic_cast(layer)->setChannel(channel); Chris@53: return; Chris@53: } Chris@53: if (dynamic_cast(layer)) { Chris@53: dynamic_cast(layer)->setChannel(channel); Chris@53: return; Chris@53: } Chris@349: if (dynamic_cast(layer)) { Chris@349: dynamic_cast(layer)->setChannel(channel); Chris@349: return; Chris@349: } Chris@53: } Chris@53: Chris@0: Layer * Chris@53: LayerFactory::createLayer(LayerType type) Chris@0: { Chris@0: Layer *layer = 0; Chris@0: Chris@0: switch (type) { Chris@0: Chris@0: case Waveform: Chris@44: layer = new WaveformLayer; Chris@0: break; Chris@0: Chris@0: case Spectrogram: Chris@44: layer = new SpectrogramLayer; Chris@0: break; Chris@0: Chris@0: case TimeRuler: Chris@44: layer = new TimeRulerLayer; Chris@0: break; Chris@0: Chris@0: case TimeInstants: Chris@44: layer = new TimeInstantLayer; Chris@0: break; Chris@0: Chris@0: case TimeValues: Chris@44: layer = new TimeValueLayer; Chris@0: break; Chris@0: matthiasm@623: case FlexiNotes: matthiasm@623: layer = new FlexiNoteLayer; matthiasm@623: break; matthiasm@623: Chris@30: case Notes: Chris@44: layer = new NoteLayer; Chris@30: break; Chris@30: Chris@411: case Regions: Chris@411: layer = new RegionLayer; Chris@411: break; Chris@411: Chris@35: case Text: Chris@44: layer = new TextLayer; Chris@35: break; Chris@35: Chris@303: case Image: Chris@303: layer = new ImageLayer; Chris@303: break; Chris@303: Chris@0: case Colour3DPlot: Chris@44: layer = new Colour3DPlotLayer; Chris@0: break; Chris@0: Chris@133: case Spectrum: Chris@133: layer = new SpectrumLayer; Chris@133: break; Chris@133: Chris@193: case Slice: Chris@193: layer = new SliceLayer; Chris@193: break; Chris@193: Chris@0: case MelodicRangeSpectrogram: Chris@44: layer = new SpectrogramLayer(SpectrogramLayer::MelodicRange); Chris@0: break; Chris@11: Chris@37: case PeakFrequencySpectrogram: Chris@44: layer = new SpectrogramLayer(SpectrogramLayer::MelodicPeaks); Chris@37: break; Chris@37: Chris@11: default: break; Chris@0: } Chris@0: Chris@0: if (!layer) { Chris@587: SVDEBUG << "LayerFactory::createLayer: Unknown layer type " Chris@585: << type << endl; Chris@0: } else { Chris@587: // SVDEBUG << "LayerFactory::createLayer: Setting object name " Chris@585: // << getLayerPresentationName(type) << " on " << layer << endl; Chris@0: layer->setObjectName(getLayerPresentationName(type)); Chris@326: setLayerDefaultProperties(type, layer); Chris@0: } Chris@0: Chris@0: return layer; Chris@0: } Chris@0: Chris@326: void Chris@326: LayerFactory::setLayerDefaultProperties(LayerType type, Layer *layer) Chris@326: { Chris@587: // SVDEBUG << "LayerFactory::setLayerDefaultProperties: type " << type << " (name \"" << getLayerTypeName(type) << "\")" << endl; Chris@327: Chris@326: QSettings settings; Chris@326: settings.beginGroup("LayerDefaults"); Chris@326: QString defaults = settings.value(getLayerTypeName(type), "").toString(); Chris@326: if (defaults == "") return; Chris@326: Chris@682: // cerr << "defaults=\"" << defaults << "\"" << endl; Chris@327: Chris@326: QString xml = layer->toXmlString(); Chris@326: QDomDocument docOld, docNew; Chris@326: Chris@326: if (docOld.setContent(xml, false) && Chris@326: docNew.setContent(defaults, false)) { Chris@326: Chris@326: QXmlAttributes attrs; Chris@326: Chris@326: QDomElement layerElt = docNew.firstChildElement("layer"); Chris@326: QDomNamedNodeMap attrNodes = layerElt.attributes(); Chris@326: Chris@326: for (unsigned int i = 0; i < attrNodes.length(); ++i) { Chris@326: QDomAttr attr = attrNodes.item(i).toAttr(); Chris@326: if (attr.isNull()) continue; Chris@683: // cerr << "append \"" << attr.name() Chris@584: // << "\" -> \"" << attr.value() << "\"" Chris@682: // << endl; Chris@326: attrs.append(attr.name(), "", "", attr.value()); Chris@326: } Chris@326: Chris@326: layerElt = docOld.firstChildElement("layer"); Chris@326: attrNodes = layerElt.attributes(); Chris@326: for (unsigned int i = 0; i < attrNodes.length(); ++i) { Chris@326: QDomAttr attr = attrNodes.item(i).toAttr(); Chris@326: if (attr.isNull()) continue; Chris@326: if (attrs.value(attr.name()) == "") { Chris@683: // cerr << "append \"" << attr.name() Chris@584: // << "\" -> \"" << attr.value() << "\"" Chris@682: // << endl; Chris@326: attrs.append(attr.name(), "", "", attr.value()); Chris@326: } Chris@326: } Chris@326: Chris@326: layer->setProperties(attrs); Chris@326: } Chris@326: Chris@326: settings.endGroup(); Chris@326: } Chris@326: Chris@360: LayerFactory::LayerType Chris@360: LayerFactory::getLayerTypeForClipboardContents(const Clipboard &clip) Chris@360: { Chris@360: const Clipboard::PointList &contents = clip.getPoints(); Chris@360: Chris@360: bool haveFrame = false; Chris@360: bool haveValue = false; Chris@360: bool haveDuration = false; Chris@411: bool haveLevel = false; Chris@360: Chris@360: for (Clipboard::PointList::const_iterator i = contents.begin(); Chris@360: i != contents.end(); ++i) { Chris@360: if (i->haveFrame()) haveFrame = true; Chris@360: if (i->haveValue()) haveValue = true; Chris@360: if (i->haveDuration()) haveDuration = true; Chris@411: if (i->haveLevel()) haveLevel = true; Chris@360: } Chris@360: Chris@411: if (haveFrame && haveValue && haveDuration && haveLevel) return Notes; Chris@411: if (haveFrame && haveValue && haveDuration) return Regions; Chris@360: if (haveFrame && haveValue) return TimeValues; Chris@360: return TimeInstants; Chris@360: } Chris@360: