Mercurial > hg > svcore
changeset 1673:dfcd05e8bd2f osc-script
Merge from branch single-point
author | Chris Cannam |
---|---|
date | Wed, 27 Mar 2019 14:15:21 +0000 |
parents | 1d1a16968f03 (current diff) b5580d93f28b (diff) |
children | 69ab62d378bf |
files | data/model/IntervalModel.h data/model/Model.cpp data/model/PathModel.h data/model/SparseModel.h data/model/SparseValueModel.h files.pri |
diffstat | 18 files changed, 59 insertions(+), 1371 deletions(-) [+] |
line wrap: on
line diff
--- a/data/model/AggregateWaveModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/AggregateWaveModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -41,6 +41,11 @@ bool isOK() const override; bool isReady(int *) const override; + int getCompletion() const override { + int c = 0; + (void)isReady(&c); + return c; + } QString getTypeName() const override { return tr("Aggregate Wave"); }
--- a/data/model/AlignmentModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/AlignmentModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -41,6 +41,11 @@ sv_frame_t getEndFrame() const override; sv_samplerate_t getSampleRate() const override; bool isReady(int *completion = 0) const override; + int getCompletion() const override { + int c = 0; + (void)isReady(&c); + return c; + } const ZoomConstraint *getZoomConstraint() const override; QString getTypeName() const override { return tr("Alignment"); }
--- a/data/model/IntervalModel.h Tue Mar 26 14:34:21 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006-2008 Chris Cannam and QMUL. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef SV_INTERVAL_MODEL_H -#define SV_INTERVAL_MODEL_H - -#include "SparseValueModel.h" -#include "base/RealTime.h" - -/** - * Model containing sparse data (points with some properties) of which - * the properties include a duration and an arbitrary float value. - * The other properties depend on the point type. - */ - -template <typename PointType> -class IntervalModel : public SparseValueModel<PointType> -{ -public: - IntervalModel(sv_samplerate_t sampleRate, int resolution, - bool notifyOnAdd = true) : - SparseValueModel<PointType>(sampleRate, resolution, notifyOnAdd) - { } - - IntervalModel(sv_samplerate_t sampleRate, int resolution, - float valueMinimum, float valueMaximum, - bool notifyOnAdd = true) : - SparseValueModel<PointType>(sampleRate, resolution, - valueMinimum, valueMaximum, - notifyOnAdd) - { } - - /** - * PointTypes have a duration, so this returns all points that span any - * of the given range (as well as the usual additional few before - * and after). Consequently this can be very slow (optimised data - * structures still to be done!). - */ - typename SparseValueModel<PointType>::PointList getPoints(sv_frame_t start, sv_frame_t end) const override; - - /** - * PointTypes have a duration, so this returns all points that span the - * given frame. Consequently this can be very slow (optimised - * data structures still to be done!). - */ - typename SparseValueModel<PointType>::PointList getPoints(sv_frame_t frame) const override; - - const typename SparseModel<PointType>::PointList &getPoints() const override { - return SparseModel<PointType>::getPoints(); - } - - /** - * TabularModel methods. - */ - - QVariant getData(int row, int column, int role) const override - { - if (column < 2) { - return SparseValueModel<PointType>::getData - (row, column, role); - } - - typename SparseModel<PointType>::PointList::const_iterator i - = SparseModel<PointType>::getPointListIteratorForRow(row); - if (i == SparseModel<PointType>::m_points.end()) return QVariant(); - - switch (column) { - case 2: - if (role == Qt::EditRole || role == TabularModel::SortRole) return i->value; - else return QString("%1 %2").arg(i->value).arg - (IntervalModel<PointType>::getScaleUnits()); - case 3: return int(i->duration); //!!! could be better presented - default: return QVariant(); - } - } - - Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override - { - typedef IntervalModel<PointType> I; - - if (column < 2) { - return SparseValueModel<PointType>::getSetDataCommand - (row, column, value, role); - } - - if (role != Qt::EditRole) return 0; - typename I::PointList::const_iterator i - = I::getPointListIteratorForRow(row); - if (i == I::m_points.end()) return 0; - typename I::EditCommand *command = new typename I::EditCommand - (this, I::tr("Edit Data")); - - PointType point(*i); - command->deletePoint(point); - - switch (column) { - // column cannot be 0 or 1, those cases were handled above - case 2: point.value = float(value.toDouble()); break; - case 3: point.duration = value.toInt(); break; - } - - command->addPoint(point); - return command->finish(); - } - - bool isColumnTimeValue(int column) const override - { - // NB duration is not a "time value" -- that's for columns - // whose sort ordering is exactly that of the frame time - return (column < 2); - } -}; - -template <typename PointType> -typename SparseValueModel<PointType>::PointList -IntervalModel<PointType>::getPoints(sv_frame_t start, sv_frame_t end) const -{ - typedef IntervalModel<PointType> I; - - if (start > end) return typename I::PointList(); - - QMutex &mutex(I::m_mutex); - QMutexLocker locker(&mutex); - - PointType endPoint(end); - - typename I::PointListConstIterator endItr = I::m_points.upper_bound(endPoint); - - if (endItr != I::m_points.end()) ++endItr; - if (endItr != I::m_points.end()) ++endItr; - - typename I::PointList rv; - - for (typename I::PointListConstIterator i = endItr; i != I::m_points.begin(); ) { - --i; - if (i->frame < start) { - if (i->frame + i->duration >= start) { - rv.insert(*i); - } - } else if (i->frame <= end) { - rv.insert(*i); - } - } - - return rv; -} - -template <typename PointType> -typename SparseValueModel<PointType>::PointList -IntervalModel<PointType>::getPoints(sv_frame_t frame) const -{ - typedef IntervalModel<PointType> I; - - QMutex &mutex(I::m_mutex); - QMutexLocker locker(&mutex); - - if (I::m_resolution == 0) return typename I::PointList(); - - sv_frame_t start = (frame / I::m_resolution) * I::m_resolution; - sv_frame_t end = start + I::m_resolution; - - PointType endPoint(end); - - typename I::PointListConstIterator endItr = I::m_points.upper_bound(endPoint); - - typename I::PointList rv; - - for (typename I::PointListConstIterator i = endItr; i != I::m_points.begin(); ) { - --i; - if (i->frame < start) { - if (i->frame + i->duration >= start) { - rv.insert(*i); - } - } else if (i->frame <= end) { - rv.insert(*i); - } - } - - return rv; -} - -#endif
--- a/data/model/Model.cpp Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/Model.cpp Wed Mar 27 14:15:21 2019 +0000 @@ -20,8 +20,6 @@ #include <iostream> -const int Model::COMPLETION_UNKNOWN = -1; - Model::~Model() { SVDEBUG << "Model::~Model(" << this << ")" << endl;
--- a/data/model/Model.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/Model.h Wed Mar 27 14:15:21 2019 +0000 @@ -133,23 +133,42 @@ /** * Return true if the model has finished loading or calculating * all its data, for a model that is capable of calculating in a - * background thread. The default implementation is appropriate - * for a thread that does not background any work but carries out - * all its calculation from the constructor or accessors. + * background thread. * - * If "completion" is non-NULL, this function should return - * through it an estimated percentage value showing how far - * through the background operation it thinks it is (for progress - * reporting). If it has no way to calculate progress, it may - * return the special value COMPLETION_UNKNOWN. See also - * getCompletion(). + * If "completion" is non-NULL, return through it an estimated + * percentage value showing how far through the background + * operation it thinks it is (for progress reporting). This should + * be identical to the value returned by getCompletion(). + * + * A model that carries out all its calculation from the + * constructor or accessor functions would typically return true + * (and completion == 100) as long as isOK() is true. Other models + * may make the return value here depend on the internal + * completion status. + * + * See also getCompletion(). */ - virtual bool isReady(int *completion = 0) const { - bool ok = isOK(); - if (completion) *completion = (ok ? 100 : 0); - return ok; + virtual bool isReady(int *cp = nullptr) const { + int c = getCompletion(); + if (cp) *cp = c; + if (!isOK()) return false; + else return (c == 100); } - static const int COMPLETION_UNKNOWN; + + /** + * Return an estimated percentage value showing how far through + * any background operation used to calculate or load the model + * data the model thinks it is. Must return 100 when the model is + * complete. + * + * A model that carries out all its calculation from the + * constructor or accessor functions might return 0 if isOK() is + * false and 100 if isOK() is true. Other models may make the + * return value here depend on the internal completion status. + * + * See also isReady(). + */ + virtual int getCompletion() const = 0; /** * If this model imposes a zoom constraint, i.e. some limit to the
--- a/data/model/NoteModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/NoteModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -129,7 +129,7 @@ float getValueMinimum() const { return m_valueMinimum; } float getValueMaximum() const { return m_valueMaximum; } - int getCompletion() const { return m_completion; } + int getCompletion() const override { return m_completion; } void setCompletion(int completion, bool update = true) {
--- a/data/model/PathModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/PathModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -115,6 +115,9 @@ /** * Query methods. */ + int getPointCount() const { + return int(m_points.size()); + } const PointList &getPoints() const { return m_points; }
--- a/data/model/ReadOnlyWaveFileModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/ReadOnlyWaveFileModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -54,6 +54,11 @@ bool isOK() const override; bool isReady(int *) const override; + int getCompletion() const override { + int c = 0; + (void)isReady(&c); + return c; + } const ZoomConstraint *getZoomConstraint() const override { return &m_zoomConstraint; }
--- a/data/model/RegionModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/RegionModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -107,7 +107,7 @@ float getValueMinimum() const { return m_valueMinimum; } float getValueMaximum() const { return m_valueMaximum; } - int getCompletion() const { return m_completion; } + int getCompletion() const override { return m_completion; } void setCompletion(int completion, bool update = true) {
--- a/data/model/SparseModel.h Tue Mar 26 14:34:21 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1001 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef SV_SPARSE_MODEL_H -#define SV_SPARSE_MODEL_H - -#include "Model.h" -#include "TabularModel.h" -#include "base/Command.h" -#include "base/RealTime.h" -#include "system/System.h" - -#include <iostream> - -#include <set> -#include <vector> -#include <algorithm> -#include <iterator> - -#include <cmath> - -#include <QMutex> -#include <QTextStream> - -/** - * Model containing sparse data (points with some properties). The - * properties depend on the point type. - */ -template <typename PointType> -class SparseModel : public Model, - public TabularModel -{ - // If we omit the Q_OBJECT macro, lupdate complains. - - // If we include it, moc fails (can't handle template classes). - - // If we omit it, lupdate still seems to emit translatable - // messages for the tr() strings in here. So I guess we omit it. - -public: - SparseModel(sv_samplerate_t sampleRate, int resolution, - bool notifyOnAdd = true); - virtual ~SparseModel() { } - - bool isOK() const override { return true; } - sv_frame_t getStartFrame() const override; - sv_frame_t getEndFrame() const override; - sv_samplerate_t getSampleRate() const override { return m_sampleRate; } - - // Number of frames of the underlying sample rate that this model - // is capable of resolving to. For example, if m_resolution == 10 - // then every point in this model will be at a multiple of 10 - // sample frames and should be considered to cover a window ending - // 10 sample frames later. - virtual int getResolution() const { - return m_resolution ? m_resolution : 1; - } - virtual void setResolution(int resolution); - - // Extend the end of the model. If this is set to something beyond - // the end of the final point in the model, then getEndFrame() - // will return this value. Otherwise getEndFrame() will return the - // end of the final point. (This is used by the Tony application) - virtual void extendEndFrame(sv_frame_t to) { m_extendTo = to; } - - typedef PointType Point; - typedef std::multiset<PointType, - typename PointType::OrderComparator> PointList; - typedef typename PointList::iterator PointListIterator; - typedef typename PointList::const_iterator PointListConstIterator; - - /** - * Return whether the model is empty or not. - */ - virtual bool isEmpty() const; - - /** - * Get the total number of points in the model. - */ - virtual int getPointCount() const; - - /** - * Get all points. - */ - virtual const PointList &getPoints() const; - - /** - * Get all of the points in this model between the given - * boundaries (in frames), as well as up to two points before and - * after the boundaries. If you need exact boundaries, check the - * point coordinates in the returned list. - */ - virtual PointList getPoints(sv_frame_t start, sv_frame_t end) const; - - /** - * Get all points that cover the given frame number, taking the - * resolution of the model into account. - */ - virtual PointList getPoints(sv_frame_t frame) const; - - /** - * Return all points that share the nearest frame number prior to - * the given one at which there are any points. - */ - virtual PointList getPreviousPoints(sv_frame_t frame) const; - - /** - * Return all points that share the nearest frame number - * subsequent to the given one at which there are any points. - */ - virtual PointList getNextPoints(sv_frame_t frame) const; - - /** - * Remove all points. - */ - virtual void clear(); - - /** - * Add a point. - */ - virtual void addPoint(const PointType &point); - - /** - * Remove a point. Points are not necessarily unique, so this - * function will remove the first point that compares equal to the - * supplied one using Point::Comparator. Other identical points - * may remain in the model. - */ - virtual void deletePoint(const PointType &point); - - /** - * Return true if the given point is found in this model, false - * otherwise. - */ - virtual bool containsPoint(const PointType &point); - - bool isReady(int *completion = 0) const override { - bool ready = isOK() && (m_completion == 100); - if (completion) *completion = m_completion; - return ready; - } - - virtual void setCompletion(int completion, bool update = true); - virtual int getCompletion() const { return m_completion; } - - virtual bool hasTextLabels() const { return m_hasTextLabels; } - - bool isSparse() const override { return true; } - - QString getTypeName() const override { return tr("Sparse"); } - - virtual QString getXmlOutputType() const { return "sparse"; } - - void toXml(QTextStream &out, - QString indent = "", - QString extraAttributes = "") const override; - - QString toDelimitedDataString(QString delimiter) const override { - return toDelimitedDataStringWithOptions - (delimiter, DataExportDefaults); - } - - QString toDelimitedDataStringWithOptions(QString delimiter, - DataExportOptions opts) const override { - return toDelimitedDataStringSubsetWithOptions - (delimiter, opts, - std::min(getStartFrame(), sv_frame_t(0)), getEndFrame()); - } - - QString toDelimitedDataStringSubset(QString delimiter, sv_frame_t f0, sv_frame_t f1) const override { - return toDelimitedDataStringSubsetWithOptions - (delimiter, DataExportDefaults, f0, f1); - } - - QString toDelimitedDataStringSubsetWithOptions(QString delimiter, DataExportOptions opts, sv_frame_t f0, sv_frame_t f1) const override { - if (opts & DataExportFillGaps) { - return toDelimitedDataStringSubsetFilled(delimiter, opts, f0, f1); - } else { - QString s; - for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { - if (i->frame >= f0 && i->frame < f1) { - s += i->toDelimitedDataString(delimiter, opts, m_sampleRate) + "\n"; - } - } - return s; - } - } - - /** - * Command to add a point, with undo. - */ - class AddPointCommand : public Command - { - public: - AddPointCommand(SparseModel<PointType> *model, - const PointType &point, - QString name = "") : - m_model(model), m_point(point), m_name(name) { } - - QString getName() const override { - return (m_name == "" ? tr("Add Point") : m_name); - } - - void execute() override { m_model->addPoint(m_point); } - void unexecute() override { m_model->deletePoint(m_point); } - - const PointType &getPoint() const { return m_point; } - - private: - SparseModel<PointType> *m_model; - PointType m_point; - QString m_name; - }; - - - /** - * Command to remove a point, with undo. - */ - class DeletePointCommand : public Command - { - public: - DeletePointCommand(SparseModel<PointType> *model, - const PointType &point) : - m_model(model), m_point(point) { } - - QString getName() const override { return tr("Delete Point"); } - - void execute() override { m_model->deletePoint(m_point); } - void unexecute() override { m_model->addPoint(m_point); } - - const PointType &getPoint() const { return m_point; } - - private: - SparseModel<PointType> *m_model; - PointType m_point; - }; - - - /** - * Command to add or remove a series of points, with undo. - * Consecutive add/remove pairs for the same point are collapsed. - */ - class EditCommand : public MacroCommand - { - public: - EditCommand(SparseModel<PointType> *model, QString commandName); - - virtual void addPoint(const PointType &point); - virtual void deletePoint(const PointType &point); - - /** - * Stack an arbitrary other command in the same sequence. - */ - void addCommand(Command *command) override { addCommand(command, true); } - - /** - * If any points have been added or deleted, return this - * command (so the caller can add it to the command history). - * Otherwise delete the command and return NULL. - */ - virtual EditCommand *finish(); - - protected: - virtual void addCommand(Command *command, bool executeFirst); - - SparseModel<PointType> *m_model; - }; - - - /** - * Command to relabel a point. - */ - class RelabelCommand : public Command - { - public: - RelabelCommand(SparseModel<PointType> *model, - const PointType &point, - QString newLabel) : - m_model(model), m_oldPoint(point), m_newPoint(point) { - m_newPoint.label = newLabel; - } - - QString getName() const override { return tr("Re-Label Point"); } - - void execute() override { - m_model->deletePoint(m_oldPoint); - m_model->addPoint(m_newPoint); - std::swap(m_oldPoint, m_newPoint); - } - - void unexecute() override { execute(); } - - private: - SparseModel<PointType> *m_model; - PointType m_oldPoint; - PointType m_newPoint; - }; - - /** - * TabularModel methods. - */ - - int getRowCount() const override - { - return int(m_points.size()); - } - - sv_frame_t getFrameForRow(int row) const override - { - PointListConstIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) return 0; - return i->frame; - } - - int getRowForFrame(sv_frame_t frame) const override - { - if (m_rows.empty()) rebuildRowVector(); - std::vector<sv_frame_t>::iterator i = - std::lower_bound(m_rows.begin(), m_rows.end(), frame); - ssize_t row = std::distance(m_rows.begin(), i); - if (i != m_rows.begin() && (i == m_rows.end() || *i != frame)) { - --row; - } - return int(row); - } - - int getColumnCount() const override { return 1; } - QVariant getData(int row, int column, int role) const override - { - PointListConstIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) { -// cerr << "no iterator for row " << row << " (have " << getRowCount() << " rows)" << endl; - return QVariant(); - } - -// cerr << "returning data for row " << row << " col " << column << endl; - - switch (column) { - case 0: { - if (role == SortRole) return int(i->frame); - RealTime rt = RealTime::frame2RealTime(i->frame, getSampleRate()); - if (role == Qt::EditRole) return rt.toString().c_str(); - else return rt.toText().c_str(); - } - case 1: return int(i->frame); - } - - return QVariant(); - } - - Command *getSetDataCommand(int row, int column, - const QVariant &value, int role) override - { - if (role != Qt::EditRole) return 0; - PointListIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) return 0; - EditCommand *command = new EditCommand(this, tr("Edit Data")); - - Point point(*i); - command->deletePoint(point); - - switch (column) { - case 0: point.frame = lrint(value.toDouble() * getSampleRate()); break; - case 1: point.frame = value.toInt(); break; - } - - command->addPoint(point); - return command->finish(); - } - - Command *getInsertRowCommand(int row) override - { - EditCommand *command = new EditCommand(this, tr("Insert Data Point")); - Point point(0); - PointListIterator i = getPointListIteratorForRow(row); - if (i == m_points.end() && i != m_points.begin()) --i; - if (i != m_points.end()) point = *i; - command->addPoint(point); - return command->finish(); - } - - Command *getRemoveRowCommand(int row) override - { - PointListIterator i = getPointListIteratorForRow(row); - if (i == m_points.end()) return 0; - EditCommand *command = new EditCommand(this, tr("Delete Data Point")); - command->deletePoint(*i); - return command->finish(); - } - -protected: - sv_samplerate_t m_sampleRate; - int m_resolution; - sv_frame_t m_extendTo; - bool m_notifyOnAdd; - sv_frame_t m_sinceLastNotifyMin; - sv_frame_t m_sinceLastNotifyMax; - bool m_hasTextLabels; - - PointList m_points; - int m_pointCount; - mutable QMutex m_mutex; - int m_completion; - - void getPointIterators(sv_frame_t frame, - PointListIterator &startItr, - PointListIterator &endItr); - void getPointIterators(sv_frame_t frame, - PointListConstIterator &startItr, - PointListConstIterator &endItr) const; - - // This is only used if the model is called on to act in - // TabularModel mode - mutable std::vector<sv_frame_t> m_rows; // map from row number to frame - - void rebuildRowVector() const - { - m_rows.clear(); - for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { -// std::cerr << "rebuildRowVector: row " << m_rows.size() << " -> " << i->frame << std::endl; - m_rows.push_back(i->frame); - } - } - - PointListIterator getPointListIteratorForRow(int row) - { - if (m_rows.empty()) rebuildRowVector(); - if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end(); - - sv_frame_t frame = m_rows[row]; - int indexAtFrame = 0; - int ri = row; - while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; } - int initialIndexAtFrame = indexAtFrame; - - PointListIterator i0, i1; - getPointIterators(frame, i0, i1); - PointListIterator i = i0; - - for (i = i0; i != i1; ++i) { - if (i->frame < (int)frame) { continue; } - if (indexAtFrame > 0) { --indexAtFrame; continue; } - return i; - } - - if (indexAtFrame > 0) { - std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl; - } - return i; - } - - PointListConstIterator getPointListIteratorForRow(int row) const - { - if (m_rows.empty()) rebuildRowVector(); - if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end(); - - sv_frame_t frame = m_rows[row]; - int indexAtFrame = 0; - int ri = row; - while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; } - int initialIndexAtFrame = indexAtFrame; - -// std::cerr << "getPointListIteratorForRow " << row << ": initialIndexAtFrame = " << initialIndexAtFrame << " for frame " << frame << std::endl; - - PointListConstIterator i0, i1; - getPointIterators(frame, i0, i1); - PointListConstIterator i = i0; - - for (i = i0; i != i1; ++i) { -// std::cerr << "i->frame is " << i->frame << ", wanting " << frame << std::endl; - - if (i->frame < (int)frame) { continue; } - if (indexAtFrame > 0) { --indexAtFrame; continue; } - return i; - } -/* - if (i == m_points.end()) { - std::cerr << "returning i at end" << std::endl; - } else { - std::cerr << "returning i with i->frame = " << i->frame << std::endl; - } -*/ - if (indexAtFrame > 0) { - std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl; - } - return i; - } - - QString toDelimitedDataStringSubsetFilled(QString delimiter, - DataExportOptions opts, - sv_frame_t f0, - sv_frame_t f1) const { - - QString s; - opts &= ~DataExportFillGaps; - - // find frame time of first point in range (if any) - sv_frame_t first = f0; - for (auto &p: m_points) { - if (p.frame >= f0) { - first = p.frame; - break; - } - } - - // project back to first frame time in range according to - // resolution. e.g. if f0 = 2, first = 9, resolution = 4 then - // we start at 5 (because 1 is too early and we need to arrive - // at 9 to match the first actual point). This method is - // stupid but easy to understand: - sv_frame_t f = first; - while (f >= f0 + m_resolution) f -= m_resolution; - - // now progress, either writing the next point (if within - // distance) or a default point - PointListConstIterator itr = m_points.begin(); - - while (f < f1) { - if (itr != m_points.end() && itr->frame <= f) { - s += itr->toDelimitedDataString(delimiter, opts, m_sampleRate); - ++itr; - } else { - s += Point(f).toDelimitedDataString(delimiter, opts, m_sampleRate); - } - s += "\n"; - f += m_resolution; - } - - return s; - } -}; - - -template <typename PointType> -SparseModel<PointType>::SparseModel(sv_samplerate_t sampleRate, - int resolution, - bool notifyOnAdd) : - m_sampleRate(sampleRate), - m_resolution(resolution), - m_extendTo(0), - m_notifyOnAdd(notifyOnAdd), - m_sinceLastNotifyMin(-1), - m_sinceLastNotifyMax(-1), - m_hasTextLabels(false), - m_pointCount(0), - m_completion(100) -{ -} - -template <typename PointType> -sv_frame_t -SparseModel<PointType>::getStartFrame() const -{ - QMutexLocker locker(&m_mutex); - sv_frame_t f = 0; - if (!m_points.empty()) { - f = m_points.begin()->frame; - } - return f; -} - -template <typename PointType> -sv_frame_t -SparseModel<PointType>::getEndFrame() const -{ - QMutexLocker locker(&m_mutex); - sv_frame_t f = 0; - if (!m_points.empty()) { - PointListConstIterator i(m_points.end()); - f = (--i)->frame + getResolution(); - } - if (m_extendTo > f) { - return m_extendTo; - } else { - return f; - } -} - -template <typename PointType> -bool -SparseModel<PointType>::isEmpty() const -{ - return m_pointCount == 0; -} - -template <typename PointType> -int -SparseModel<PointType>::getPointCount() const -{ - return m_pointCount; -} - -template <typename PointType> -const typename SparseModel<PointType>::PointList & -SparseModel<PointType>::getPoints() const -{ - return m_points; -} - -template <typename PointType> -typename SparseModel<PointType>::PointList -SparseModel<PointType>::getPoints(sv_frame_t start, sv_frame_t end) const -{ - if (start > end) return PointList(); - QMutexLocker locker(&m_mutex); - - PointType startPoint(start), endPoint(end); - - PointListConstIterator startItr = m_points.lower_bound(startPoint); - PointListConstIterator endItr = m_points.upper_bound(endPoint); - - if (startItr != m_points.begin()) --startItr; - if (startItr != m_points.begin()) --startItr; - if (endItr != m_points.end()) ++endItr; - if (endItr != m_points.end()) ++endItr; - - PointList rv; - - for (PointListConstIterator i = startItr; i != endItr; ++i) { - rv.insert(*i); - } - - return rv; -} - -template <typename PointType> -typename SparseModel<PointType>::PointList -SparseModel<PointType>::getPoints(sv_frame_t frame) const -{ - PointListConstIterator startItr, endItr; - getPointIterators(frame, startItr, endItr); - - PointList rv; - - for (PointListConstIterator i = startItr; i != endItr; ++i) { - rv.insert(*i); - } - - return rv; -} - -template <typename PointType> -void -SparseModel<PointType>::getPointIterators(sv_frame_t frame, - PointListIterator &startItr, - PointListIterator &endItr) -{ - QMutexLocker locker(&m_mutex); - - if (m_resolution == 0) { - startItr = m_points.end(); - endItr = m_points.end(); - return; - } - - sv_frame_t start = (frame / m_resolution) * m_resolution; - sv_frame_t end = start + m_resolution; - - PointType startPoint(start), endPoint(end); - - startItr = m_points.lower_bound(startPoint); - endItr = m_points.upper_bound(endPoint); -} - -template <typename PointType> -void -SparseModel<PointType>::getPointIterators(sv_frame_t frame, - PointListConstIterator &startItr, - PointListConstIterator &endItr) const -{ - QMutexLocker locker(&m_mutex); - - if (m_resolution == 0) { -// std::cerr << "getPointIterators: resolution == 0, returning end()" << std::endl; - startItr = m_points.end(); - endItr = m_points.end(); - return; - } - - sv_frame_t start = (frame / m_resolution) * m_resolution; - sv_frame_t end = start + m_resolution; - - PointType startPoint(start), endPoint(end); - -// std::cerr << "getPointIterators: start frame " << start << ", end frame " << end << ", m_resolution " << m_resolution << std::endl; - - startItr = m_points.lower_bound(startPoint); - endItr = m_points.upper_bound(endPoint); -} - -template <typename PointType> -typename SparseModel<PointType>::PointList -SparseModel<PointType>::getPreviousPoints(sv_frame_t originFrame) const -{ - QMutexLocker locker(&m_mutex); - - PointType lookupPoint(originFrame); - PointList rv; - - PointListConstIterator i = m_points.lower_bound(lookupPoint); - if (i == m_points.begin()) return rv; - - --i; - sv_frame_t frame = i->frame; - while (i->frame == frame) { - rv.insert(*i); - if (i == m_points.begin()) break; - --i; - } - - return rv; -} - -template <typename PointType> -typename SparseModel<PointType>::PointList -SparseModel<PointType>::getNextPoints(sv_frame_t originFrame) const -{ - QMutexLocker locker(&m_mutex); - - PointType lookupPoint(originFrame); - PointList rv; - - PointListConstIterator i = m_points.upper_bound(lookupPoint); - if (i == m_points.end()) return rv; - - sv_frame_t frame = i->frame; - while (i != m_points.end() && i->frame == frame) { - rv.insert(*i); - ++i; - } - - return rv; -} - -template <typename PointType> -void -SparseModel<PointType>::setResolution(int resolution) -{ - { - QMutexLocker locker(&m_mutex); - m_resolution = resolution; - m_rows.clear(); - } - emit modelChanged(); -} - -template <typename PointType> -void -SparseModel<PointType>::clear() -{ - { - QMutexLocker locker(&m_mutex); - m_points.clear(); - m_pointCount = 0; - m_rows.clear(); - } - emit modelChanged(); -} - -template <typename PointType> -void -SparseModel<PointType>::addPoint(const PointType &point) -{ - { - QMutexLocker locker(&m_mutex); - - m_points.insert(point); - m_pointCount++; - if (point.getLabel() != "") m_hasTextLabels = true; - - // Even though this model is nominally sparse, there may still - // be too many signals going on here (especially as they'll - // probably be queued from one thread to another), which is - // why we need the notifyOnAdd as an option rather than a - // necessity (the alternative is to notify on setCompletion). - - if (m_notifyOnAdd) { - m_rows.clear(); //!!! inefficient - } else { - if (m_sinceLastNotifyMin == -1 || - point.frame < m_sinceLastNotifyMin) { - m_sinceLastNotifyMin = point.frame; - } - if (m_sinceLastNotifyMax == -1 || - point.frame > m_sinceLastNotifyMax) { - m_sinceLastNotifyMax = point.frame; - } - } - } - - if (m_notifyOnAdd) { - emit modelChangedWithin(point.frame, point.frame + m_resolution); - } -} - -template <typename PointType> -bool -SparseModel<PointType>::containsPoint(const PointType &point) -{ - QMutexLocker locker(&m_mutex); - - PointListIterator i = m_points.lower_bound(point); - typename PointType::Comparator comparator; - while (i != m_points.end()) { - if (i->frame > point.frame) break; - if (!comparator(*i, point) && !comparator(point, *i)) { - return true; - } - ++i; - } - - return false; -} - -template <typename PointType> -void -SparseModel<PointType>::deletePoint(const PointType &point) -{ - { - QMutexLocker locker(&m_mutex); - - PointListIterator i = m_points.lower_bound(point); - typename PointType::Comparator comparator; - while (i != m_points.end()) { - if (i->frame > point.frame) break; - if (!comparator(*i, point) && !comparator(point, *i)) { - m_points.erase(i); - m_pointCount--; - break; - } - ++i; - } - -// std::cout << "SparseOneDimensionalModel: emit modelChanged(" -// << point.frame << ")" << std::endl; - m_rows.clear(); //!!! inefficient - } - - emit modelChangedWithin(point.frame, point.frame + m_resolution); -} - -template <typename PointType> -void -SparseModel<PointType>::setCompletion(int completion, bool update) -{ -// std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; - bool emitCompletionChanged = true; - bool emitGeneralModelChanged = false; - bool emitRegionChanged = false; - - { - QMutexLocker locker(&m_mutex); - - if (m_completion != completion) { - m_completion = completion; - - if (completion == 100) { - - if (m_notifyOnAdd) { - emitCompletionChanged = false; - } - - m_notifyOnAdd = true; // henceforth - m_rows.clear(); //!!! inefficient - emitGeneralModelChanged = true; - - } else if (!m_notifyOnAdd) { - - if (update && - m_sinceLastNotifyMin >= 0 && - m_sinceLastNotifyMax >= 0) { - m_rows.clear(); //!!! inefficient - emitRegionChanged = true; - } - } - } - } - - if (emitCompletionChanged) { - emit completionChanged(); - } - if (emitGeneralModelChanged) { - emit modelChanged(); - } - if (emitRegionChanged) { - emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax); - m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; - } -} - -template <typename PointType> -void -SparseModel<PointType>::toXml(QTextStream &out, - QString indent, - QString extraAttributes) const -{ -// std::cerr << "SparseModel::toXml: extraAttributes = \"" -// << extraAttributes.toStdString() << std::endl; - - QString type = getXmlOutputType(); - - Model::toXml - (out, - indent, - QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6") - .arg(type) - .arg(PointType(0).getDimensions()) - .arg(m_resolution) - .arg(m_notifyOnAdd ? "true" : "false") - .arg(getObjectExportId(&m_points)) - .arg(extraAttributes)); - - out << indent; - out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n") - .arg(getObjectExportId(&m_points)) - .arg(PointType(0).getDimensions()); - - for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { - i->toXml(out, indent + " "); - } - - out << indent; - out << "</dataset>\n"; -} - -template <typename PointType> -SparseModel<PointType>::EditCommand::EditCommand(SparseModel *model, - QString commandName) : - MacroCommand(commandName), - m_model(model) -{ -} - -template <typename PointType> -void -SparseModel<PointType>::EditCommand::addPoint(const PointType &point) -{ - addCommand(new AddPointCommand(m_model, point), true); -} - -template <typename PointType> -void -SparseModel<PointType>::EditCommand::deletePoint(const PointType &point) -{ - addCommand(new DeletePointCommand(m_model, point), true); -} - -template <typename PointType> -typename SparseModel<PointType>::EditCommand * -SparseModel<PointType>::EditCommand::finish() -{ - if (!m_commands.empty()) { - return this; - } else { - delete this; - return 0; - } -} - -template <typename PointType> -void -SparseModel<PointType>::EditCommand::addCommand(Command *command, - bool executeFirst) -{ - if (executeFirst) command->execute(); - - if (!m_commands.empty()) { - DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command); - if (dpc) { - AddPointCommand *apc = dynamic_cast<AddPointCommand *> - (m_commands[m_commands.size() - 1]); - typename PointType::Comparator comparator; - if (apc) { - if (!comparator(apc->getPoint(), dpc->getPoint()) && - !comparator(dpc->getPoint(), apc->getPoint())) { - deleteCommand(apc); - return; - } - } - } - } - - MacroCommand::addCommand(command); -} - -#endif - - -
--- a/data/model/SparseOneDimensionalModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/SparseOneDimensionalModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -81,8 +81,8 @@ QString getDefaultPlayClipId() const override { return "tap"; } bool hasTextLabels() const { return m_haveTextLabels; } - - int getCompletion() const { return m_completion; } + + int getCompletion() const override { return m_completion; } void setCompletion(int completion, bool update = true) {
--- a/data/model/SparseTimeValueModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/SparseTimeValueModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -111,7 +111,7 @@ float getValueMinimum() const { return m_valueMinimum; } float getValueMaximum() const { return m_valueMaximum; } - int getCompletion() const { return m_completion; } + int getCompletion() const override { return m_completion; } void setCompletion(int completion, bool update = true) {
--- a/data/model/SparseValueModel.h Tue Mar 26 14:34:21 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ - -/* - Sonic Visualiser - An audio file viewer and annotation editor. - Centre for Digital Music, Queen Mary, University of London. - This file copyright 2006 Chris Cannam. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. See the file - COPYING included with this distribution for more information. -*/ - -#ifndef SV_SPARSE_VALUE_MODEL_H -#define SV_SPARSE_VALUE_MODEL_H - -#include "SparseModel.h" -#include "base/UnitDatabase.h" - -#include "system/System.h" - -/** - * Model containing sparse data (points with some properties) of which - * one of the properties is an arbitrary float value. The other - * properties depend on the point type. - */ - -template <typename PointType> -class SparseValueModel : public SparseModel<PointType> -{ -public: - SparseValueModel(sv_samplerate_t sampleRate, int resolution, - bool notifyOnAdd = true) : - SparseModel<PointType>(sampleRate, resolution, notifyOnAdd), - m_valueMinimum(0.f), - m_valueMaximum(0.f), - m_haveExtents(false) - { } - - SparseValueModel(sv_samplerate_t sampleRate, int resolution, - float valueMinimum, float valueMaximum, - bool notifyOnAdd = true) : - SparseModel<PointType>(sampleRate, resolution, notifyOnAdd), - m_valueMinimum(valueMinimum), - m_valueMaximum(valueMaximum), - m_haveExtents(true) - { } - - using SparseModel<PointType>::m_points; - using SparseModel<PointType>::modelChanged; - using SparseModel<PointType>::getPoints; - using SparseModel<PointType>::tr; - - QString getTypeName() const override { return tr("Sparse Value"); } - - virtual float getValueMinimum() const { return m_valueMinimum; } - virtual float getValueMaximum() const { return m_valueMaximum; } - - virtual QString getScaleUnits() const { return m_units; } - virtual void setScaleUnits(QString units) { - m_units = units; - UnitDatabase::getInstance()->registerUnit(units); - } - - void addPoint(const PointType &point) override - { - bool allChange = false; - - if (!ISNAN(point.value) && !ISINF(point.value)) { - if (!m_haveExtents || point.value < m_valueMinimum) { - m_valueMinimum = point.value; allChange = true; -// std::cerr << "addPoint: value min = " << m_valueMinimum << std::endl; - } - if (!m_haveExtents || point.value > m_valueMaximum) { - m_valueMaximum = point.value; allChange = true; -// std::cerr << "addPoint: value max = " << m_valueMaximum << " (min = " << m_valueMinimum << ")" << std::endl; - } - m_haveExtents = true; - } - - SparseModel<PointType>::addPoint(point); - if (allChange) emit modelChanged(); - } - - void deletePoint(const PointType &point) override - { - SparseModel<PointType>::deletePoint(point); - - if (point.value == m_valueMinimum || - point.value == m_valueMaximum) { - - float formerMin = m_valueMinimum, formerMax = m_valueMaximum; - - for (typename SparseModel<PointType>::PointList::const_iterator i - = m_points.begin(); - i != m_points.end(); ++i) { - - if (i == m_points.begin() || i->value < m_valueMinimum) { - m_valueMinimum = i->value; -// std::cerr << "deletePoint: value min = " << m_valueMinimum << std::endl; - } - if (i == m_points.begin() || i->value > m_valueMaximum) { - m_valueMaximum = i->value; -// std::cerr << "deletePoint: value max = " << m_valueMaximum << std::endl; - } - } - - if (formerMin != m_valueMinimum || formerMax != m_valueMaximum) { - emit modelChanged(); - } - } - } - - void toXml(QTextStream &stream, - QString indent = "", - QString extraAttributes = "") const override - { - std::cerr << "SparseValueModel::toXml: extraAttributes = \"" - << extraAttributes.toStdString() << "\"" << std::endl; - - SparseModel<PointType>::toXml - (stream, - indent, - QString("%1 minimum=\"%2\" maximum=\"%3\" units=\"%4\"") - .arg(extraAttributes).arg(m_valueMinimum).arg(m_valueMaximum) - .arg(this->encodeEntities(m_units))); - } - -protected: - float m_valueMinimum; - float m_valueMaximum; - bool m_haveExtents; - QString m_units; -}; - - -#endif -
--- a/data/model/TextModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/TextModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -69,7 +69,7 @@ sv_samplerate_t getSampleRate() const override { return m_sampleRate; } int getResolution() const { return m_resolution; } - int getCompletion() const { return m_completion; } + int getCompletion() const override { return m_completion; } void setCompletion(int completion, bool update = true) {
--- a/data/model/WritableWaveFileModel.cpp Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/WritableWaveFileModel.cpp Wed Mar 27 14:15:21 2019 +0000 @@ -221,15 +221,6 @@ return (m_model && m_model->isOK()); } -bool -WritableWaveFileModel::isReady(int *completion) const -{ - int c = getCompletion(); - if (completion) *completion = c; - if (!isOK()) return false; - return (c == 100); -} - void WritableWaveFileModel::setWriteProportion(int proportion) {
--- a/data/model/WritableWaveFileModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/WritableWaveFileModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -139,7 +139,6 @@ int getWriteProportion() const; bool isOK() const override; - bool isReady(int *) const override; /** * Return the generation completion percentage of this model. This @@ -147,7 +146,7 @@ * -- it just contains varying amounts of data depending on how * much has been written. */ - virtual int getCompletion() const { return 100; } + int getCompletion() const override { return 100; } const ZoomConstraint *getZoomConstraint() const override { static PowerOfSqrtTwoZoomConstraint zc;
--- a/data/model/test/MockWaveModel.h Tue Mar 26 14:34:21 2019 +0000 +++ b/data/model/test/MockWaveModel.h Wed Mar 27 14:15:21 2019 +0000 @@ -51,6 +51,7 @@ sv_frame_t getEndFrame() const override { return m_data[0].size(); } sv_samplerate_t getSampleRate() const override { return 44100; } bool isOK() const override { return true; } + int getCompletion() const override { return 100; } QString getTypeName() const override { return tr("Mock Wave"); }
--- a/files.pri Tue Mar 26 14:34:21 2019 +0000 +++ b/files.pri Wed Mar 27 14:15:21 2019 +0000 @@ -85,7 +85,6 @@ data/model/EventCommands.h \ data/model/FFTModel.h \ data/model/ImageModel.h \ - data/model/IntervalModel.h \ data/model/Labeller.h \ data/model/Model.h \ data/model/ModelDataTableModel.h \ @@ -96,10 +95,8 @@ data/model/RangeSummarisableTimeValueModel.h \ data/model/RegionModel.h \ data/model/RelativelyFineZoomConstraint.h \ - data/model/SparseModel.h \ data/model/SparseOneDimensionalModel.h \ data/model/SparseTimeValueModel.h \ - data/model/SparseValueModel.h \ data/model/TabularModel.h \ data/model/TextModel.h \ data/model/WaveformOversampler.h \