# HG changeset patch # User Chris Cannam # Date 1154016392 0 # Node ID 999ae0f7d10c85f24c14b644cc4a6156e86d3236 # Parent bd6e85b3d88b7f1255b7403c08c8c6de5f8b8087 * Change preferences dialog to ok/apply/cancel model * Make preferences persist in a config file * Change instance() to getInstance() for all singleton types * Make pasting to time-value layer with no values in clipboard ask you how to generate the values * Fix bad behaviour caused by importing "data"-type (i.e. 3d dense) model from annotation file without a fixed window size available diff -r bd6e85b3d88b -r 999ae0f7d10c layer/Colour3DPlotLayer.cpp --- a/layer/Colour3DPlotLayer.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/Colour3DPlotLayer.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -26,6 +26,8 @@ #include +//#define DEBUG_COLOUR_3D_PLOT_LAYER_PAINT 1 + Colour3DPlotLayer::Colour3DPlotLayer() : Layer(), @@ -170,7 +172,9 @@ Colour3DPlotLayer::paint(View *v, QPainter &paint, QRect rect) const { // Profiler profiler("Colour3DPlotLayer::paint"); -// std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl; +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT + std::cerr << "Colour3DPlotLayer::paint(): m_model is " << m_model << ", zoom level is " << v->getZoomLevel() << std::endl; +#endif //!!! This doesn't yet accommodate the fact that the model may //have a different sample rate from an underlying model. At the @@ -272,10 +276,10 @@ int sw = sx1 - sx0; int sh = m_model->getYBinCount(); -/* +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT std::cerr << "Colour3DPlotLayer::paint: w " << w << ", h " << h << ", sx0 " << sx0 << ", sx1 " << sx1 << ", sw " << sw << ", sh " << sh << std::endl; std::cerr << "Colour3DPlotLayer: sample rate is " << m_model->getSampleRate() << ", window size " << m_model->getWindowSize() << std::endl; -*/ +#endif QPoint illuminatePos; bool illuminate = v->shouldIlluminateLocalFeatures(this, illuminatePos); @@ -321,8 +325,10 @@ } } -// std::cout << "rect " << rx0 << "," << (ry0 - h / sh - 1) << " " -// << w << "x" << (h / sh + 1) << std::endl; +#ifdef DEBUG_COLOUR_3D_PLOT_LAYER_PAINT + std::cerr << "rect " << rx0 << "," << (ry0 - h / sh - 1) << " " + << w << "x" << (h / sh + 1) << std::endl; +#endif paint.drawRect(r); diff -r bd6e85b3d88b -r 999ae0f7d10c layer/Colour3DPlotLayer.h --- a/layer/Colour3DPlotLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/Colour3DPlotLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -77,7 +77,7 @@ virtual void setProperty(const PropertyName &, int value); */ - void setProperties(const QXmlAttributes &attributes) { } + void setProperties(const QXmlAttributes &) { } protected slots: void cacheInvalid(); diff -r bd6e85b3d88b -r 999ae0f7d10c layer/LayerFactory.cpp --- a/layer/LayerFactory.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/LayerFactory.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -36,7 +36,7 @@ LayerFactory::m_instance = new LayerFactory; LayerFactory * -LayerFactory::instance() +LayerFactory::getInstance() { return m_instance; } diff -r bd6e85b3d88b -r 999ae0f7d10c layer/LayerFactory.h --- a/layer/LayerFactory.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/LayerFactory.h Thu Jul 27 16:06:32 2006 +0000 @@ -45,7 +45,7 @@ UnknownLayer = 255 }; - static LayerFactory *instance(); + static LayerFactory *getInstance(); virtual ~LayerFactory(); diff -r bd6e85b3d88b -r 999ae0f7d10c layer/NoteLayer.cpp --- a/layer/NoteLayer.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/NoteLayer.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -924,10 +924,10 @@ } } -void -NoteLayer::paste(const Clipboard &from, int frameOffset) +bool +NoteLayer::paste(const Clipboard &from, int frameOffset, bool interactive) { - if (!m_model) return; + if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); @@ -949,12 +949,28 @@ else newPoint.value = (m_model->getValueMinimum() + m_model->getValueMaximum()) / 2; if (i->haveDuration()) newPoint.duration = i->getDuration(); - else newPoint.duration = m_model->getResolution(); //!!! + else { + size_t nextFrame = frame; + Clipboard::PointList::const_iterator j = i; + for (; j != points.end(); ++j) { + if (!j->haveFrame()) continue; + if (j != i) break; + } + if (j != points.end()) { + nextFrame = j->getFrame(); + } + if (nextFrame == frame) { + newPoint.duration = m_model->getResolution(); + } else { + newPoint.duration = nextFrame - frame; + } + } command->addPoint(newPoint); } command->finish(); + return true; } QString diff -r bd6e85b3d88b -r 999ae0f7d10c layer/NoteLayer.h --- a/layer/NoteLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/NoteLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -55,7 +55,8 @@ virtual void deleteSelection(Selection s); virtual void copy(Selection s, Clipboard &to); - virtual void paste(const Clipboard &from, int frameOffset); + virtual bool paste(const Clipboard &from, int frameOffset, + bool interactive); virtual const Model *getModel() const { return m_model; } void setModel(NoteModel *model); diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TextLayer.cpp --- a/layer/TextLayer.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TextLayer.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -705,16 +705,26 @@ } } -void -TextLayer::paste(const Clipboard &from, int frameOffset) +bool +TextLayer::paste(const Clipboard &from, int frameOffset, bool interactive) { - if (!m_model) return; + if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); TextModel::EditCommand *command = new TextModel::EditCommand(m_model, tr("Paste")); + float valueMin = 0.0, valueMax = 1.0; + for (Clipboard::PointList::const_iterator i = points.begin(); + i != points.end(); ++i) { + if (i->haveValue()) { + if (i->getValue() < valueMin) valueMin = i->getValue(); + if (i->getValue() > valueMax) valueMax = i->getValue(); + } + } + if (valueMax < valueMin + 1.0) valueMax = valueMin + 1.0; + for (Clipboard::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { @@ -724,14 +734,26 @@ frame = i->getFrame() + frameOffset; } TextModel::Point newPoint(frame); - if (i->haveValue()) newPoint.height = i->haveValue(); - if (i->haveLabel()) newPoint.label = i->getLabel(); - else newPoint.label = tr("New Point"); + + if (i->haveValue()) { + newPoint.height = (i->getValue() - valueMin) / (valueMax - valueMin); + } else { + newPoint.height = 0.5; + } + + if (i->haveLabel()) { + newPoint.label = i->getLabel(); + } else if (i->haveValue()) { + newPoint.label = QString("%1").arg(i->getValue()); + } else { + newPoint.label = tr("New Point"); + } command->addPoint(newPoint); } command->finish(); + return true; } QString diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TextLayer.h --- a/layer/TextLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TextLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -53,7 +53,8 @@ virtual void deleteSelection(Selection s); virtual void copy(Selection s, Clipboard &to); - virtual void paste(const Clipboard &from, int frameOffset); + virtual bool paste(const Clipboard &from, int frameOffset, + bool interactive); virtual void editOpen(View *, QMouseEvent *); // on double-click diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TimeInstantLayer.cpp --- a/layer/TimeInstantLayer.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TimeInstantLayer.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -721,10 +721,10 @@ } } -void -TimeInstantLayer::paste(const Clipboard &from, int frameOffset) +bool +TimeInstantLayer::paste(const Clipboard &from, int frameOffset, bool interactive) { - if (!m_model) return; + if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); @@ -740,12 +740,17 @@ frame = i->getFrame() + frameOffset; } SparseOneDimensionalModel::Point newPoint(frame); - if (i->haveLabel()) newPoint.label = i->getLabel(); + if (i->haveLabel()) { + newPoint.label = i->getLabel(); + } else if (i->haveValue()) { + newPoint.label = QString("%1").arg(i->getValue()); + } command->addPoint(newPoint); } command->finish(); + return true; } QString diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TimeInstantLayer.h --- a/layer/TimeInstantLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TimeInstantLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -55,7 +55,8 @@ virtual void deleteSelection(Selection s); virtual void copy(Selection s, Clipboard &to); - virtual void paste(const Clipboard &from, int frameOffset); + virtual bool paste(const Clipboard &from, int frameOffset, + bool interactive); virtual const Model *getModel() const { return m_model; } void setModel(SparseOneDimensionalModel *model); @@ -88,8 +89,7 @@ virtual bool needsTextLabelHeight() const { return m_model->hasTextLabels(); } - virtual bool getValueExtents(float &min, float &max, - bool &log, QString &unit) const { + virtual bool getValueExtents(float &, float &, bool &, QString &) const { return false; } diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TimeRulerLayer.h --- a/layer/TimeRulerLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TimeRulerLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -53,8 +53,7 @@ int value) const; virtual void setProperty(const PropertyName &, int value); - virtual bool getValueExtents(float &min, float &max, - bool &log, QString &unit) const { + virtual bool getValueExtents(float &, float &, bool &, QString &) const { return false; } diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TimeValueLayer.cpp --- a/layer/TimeValueLayer.cpp Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TimeValueLayer.cpp Thu Jul 27 16:06:32 2006 +0000 @@ -23,12 +23,14 @@ #include "model/SparseTimeValueModel.h" #include "widgets/ItemEditDialog.h" +#include "widgets/ListInputDialog.h" #include "SpectrogramLayer.h" // for optional frequency alignment #include #include #include +#include #include #include @@ -1131,16 +1133,143 @@ } } -void -TimeValueLayer::paste(const Clipboard &from, int frameOffset) +bool +TimeValueLayer::paste(const Clipboard &from, int frameOffset, + bool interactive) { - if (!m_model) return; + if (!m_model) return false; const Clipboard::PointList &points = from.getPoints(); SparseTimeValueModel::EditCommand *command = new SparseTimeValueModel::EditCommand(m_model, tr("Paste")); + enum ValueAvailability { + UnknownAvailability, + NoValues, + SomeValues, + AllValues + }; + enum ValueGeneration { + GenerateNone, + GenerateFromCounter, + GenerateFromFrameNumber, + GenerateFromRealTime, + GenerateFromRealTimeDifference, + GenerateFromTempo, + GenerateFromExistingNeighbour, + GenerateFromLabels + }; + + ValueGeneration generation = GenerateNone; + + bool haveUsableLabels = false; + bool haveExistingItems = !(m_model->isEmpty()); + + if (interactive) { + + ValueAvailability availability = UnknownAvailability; + + for (Clipboard::PointList::const_iterator i = points.begin(); + i != points.end(); ++i) { + + if (!i->haveFrame()) continue; + + if (availability == UnknownAvailability) { + if (i->haveValue()) availability = AllValues; + else availability = NoValues; + continue; + } + + if (i->haveValue()) { + if (availability == NoValues) { + availability = SomeValues; + } + } else { + if (availability == AllValues) { + availability = SomeValues; + } + } + + if (!haveUsableLabels) { + if (i->haveLabel()) { + if (i->getLabel().contains(QRegExp("[0-9]"))) { + haveUsableLabels = true; + } + } + } + + if (availability == SomeValues && haveUsableLabels) break; + } + + if (availability == NoValues || availability == SomeValues) { + + QString text; + if (availability == NoValues) { + text = tr("The items you are pasting do not have values.\nWhat values do you want to use for these items?"); + } else { + text = tr("Some of the items you are pasting do not have values.\nWhat values do you want to use for these items?"); + } + + QStringList options; + std::vector genopts; + + options << tr("Zero for all items"); + genopts.push_back(int(GenerateNone)); + + options << tr("Whole numbers counting from 1"); + genopts.push_back(int(GenerateFromCounter)); + + options << tr("Item's audio sample frame number"); + genopts.push_back(int(GenerateFromFrameNumber)); + + options << tr("Item's time in seconds"); + genopts.push_back(int(GenerateFromRealTime)); + + options << tr("Duration from the item to the following item"); + genopts.push_back(int(GenerateFromRealTimeDifference)); + + options << tr("Tempo in bpm derived from the duration"); + genopts.push_back(int(GenerateFromTempo)); + + if (haveExistingItems) { + options << tr("Value of the nearest existing item"); + genopts.push_back(int(GenerateFromExistingNeighbour)); + } + + if (haveUsableLabels) { + options << tr("Value extracted from the item's label (where possible)"); + genopts.push_back(int(GenerateFromLabels)); + } + + + static int prevSelection = 0; + + bool ok = false; + QString selected = ListInputDialog::getItem + (0, tr("Choose value calculation"), + text, options, prevSelection, &ok); + + if (!ok) return false; + int selection = 0; + generation = GenerateNone; + + for (QStringList::const_iterator i = options.begin(); + i != options.end(); ++i) { + if (selected == *i) { + generation = ValueGeneration(genopts[selection]); + break; + } + ++selection; + } + + prevSelection = selection; + } + } + + int counter = 1; + float prevBpm = 120.f; + for (Clipboard::PointList::const_iterator i = points.begin(); i != points.end(); ++i) { @@ -1151,15 +1280,91 @@ } SparseTimeValueModel::Point newPoint(frame); - if (i->haveLabel()) newPoint.label = i->getLabel(); - if (i->haveValue()) newPoint.value = i->getValue(); - else newPoint.value = (m_model->getValueMinimum() + - m_model->getValueMaximum()) / 2; + if (i->haveLabel()) { + newPoint.label = i->getLabel(); + } else if (i->haveValue()) { + newPoint.label = QString("%1").arg(i->getValue()); + } + + if (i->haveValue()) { + newPoint.value = i->getValue(); + } else { + + switch (generation) { + + case GenerateNone: + newPoint.value = 0; + break; + + case GenerateFromCounter: + newPoint.value = counter; + break; + + case GenerateFromFrameNumber: + newPoint.value = frame; + break; + + case GenerateFromRealTime: + newPoint.value = float(frame) / float(m_model->getSampleRate()); + break; + + case GenerateFromRealTimeDifference: + case GenerateFromTempo: + { + size_t nextFrame = frame; + Clipboard::PointList::const_iterator j = i; + for (; j != points.end(); ++j) { + if (!j->haveFrame()) continue; + if (j != i) break; + } + if (j != points.end()) { + nextFrame = j->getFrame(); + } + if (generation == GenerateFromRealTimeDifference) { + newPoint.value = float(nextFrame - frame) / + float(m_model->getSampleRate()); + } else { + float bpm = prevBpm; + if (nextFrame > frame) { + bpm = (60.f * m_model->getSampleRate()) / + (nextFrame - frame); + } + newPoint.value = bpm; + prevBpm = bpm; + } + break; + } + + case GenerateFromExistingNeighbour: + { + SparseTimeValueModel::PointList points = + m_model->getPoints(frame); + if (points.empty()) points = m_model->getPreviousPoints(frame); + if (points.empty()) points = m_model->getNextPoints(frame); + if (points.empty()) { + newPoint.value = 0.f; + } else { + newPoint.value = points.begin()->value; + } + } + + case GenerateFromLabels: + if (i->haveLabel()) { + // more forgiving than QString::toFloat() + newPoint.value = atof(i->getLabel().toLocal8Bit()); + } else { + newPoint.value = 0.f; + } + } + } command->addPoint(newPoint); + + ++counter; } command->finish(); + return true; } QString diff -r bd6e85b3d88b -r 999ae0f7d10c layer/TimeValueLayer.h --- a/layer/TimeValueLayer.h Wed Jul 26 16:48:07 2006 +0000 +++ b/layer/TimeValueLayer.h Thu Jul 27 16:06:32 2006 +0000 @@ -58,7 +58,8 @@ virtual void deleteSelection(Selection s); virtual void copy(Selection s, Clipboard &to); - virtual void paste(const Clipboard &from, int frameOffset); + virtual bool paste(const Clipboard &from, int frameOffset, + bool interactive); virtual const Model *getModel() const { return m_model; } void setModel(SparseTimeValueModel *model);