# HG changeset patch # User Chris Cannam # Date 1551798911 0 # Node ID b2f32c5541993d857b55053243ecf83a41ff924e # Parent 7db29268cf4c90d437401a9d765bf83508f65cf1 Pull out the Point class, plus start testing NoteModel, plus actually add the tests... diff -r 7db29268cf4c -r b2f32c554199 base/Clipboard.cpp --- a/base/Clipboard.cpp Tue Mar 05 14:18:37 2019 +0000 +++ b/base/Clipboard.cpp Tue Mar 05 15:15:11 2019 +0000 @@ -15,200 +15,6 @@ #include "Clipboard.h" -Clipboard::Point::Point(sv_frame_t frame, QString label) : - m_haveValue(false), - m_haveLevel(false), - m_haveFrame(true), - m_haveDuration(false), - m_haveReferenceFrame(false), - m_haveLabel(true), - m_value(0), - m_level(0.f), - m_frame(frame), - m_duration(0), - m_referenceFrame(frame), - m_label(label) -{ -} - -Clipboard::Point::Point(sv_frame_t frame, float value, QString label) : - m_haveValue(true), - m_haveLevel(false), - m_haveFrame(true), - m_haveDuration(false), - m_haveReferenceFrame(false), - m_haveLabel(true), - m_value(value), - m_level(0.f), - m_frame(frame), - m_duration(0), - m_referenceFrame(frame), - m_label(label) -{ -} - -Clipboard::Point::Point(sv_frame_t frame, float value, sv_frame_t duration, QString label) : - m_haveValue(true), - m_haveLevel(false), - m_haveFrame(true), - m_haveDuration(true), - m_haveReferenceFrame(false), - m_haveLabel(true), - m_value(value), - m_level(0.f), - m_frame(frame), - m_duration(duration), - m_referenceFrame(frame), - m_label(label) -{ -} - -Clipboard::Point::Point(sv_frame_t frame, float value, sv_frame_t duration, float level, QString label) : - m_haveValue(true), - m_haveLevel(true), - m_haveFrame(true), - m_haveDuration(true), - m_haveReferenceFrame(false), - m_haveLabel(true), - m_value(value), - m_level(level), - m_frame(frame), - m_duration(duration), - m_referenceFrame(frame), - m_label(label) -{ -} - -bool -Clipboard::Point::haveFrame() const -{ - return m_haveFrame; -} - -sv_frame_t -Clipboard::Point::getFrame() const -{ - return m_frame; -} - -Clipboard::Point -Clipboard::Point::withFrame(sv_frame_t frame) const -{ - Point p(*this); - p.m_haveFrame = true; - p.m_frame = frame; - return p; -} - -bool -Clipboard::Point::haveValue() const -{ - return m_haveValue; -} - -float -Clipboard::Point::getValue() const -{ - return m_value; -} - -Clipboard::Point -Clipboard::Point::withValue(float value) const -{ - Point p(*this); - p.m_haveValue = true; - p.m_value = value; - return p; -} - -bool -Clipboard::Point::haveDuration() const -{ - return m_haveDuration; -} - -sv_frame_t -Clipboard::Point::getDuration() const -{ - return m_duration; -} - -Clipboard::Point -Clipboard::Point::withDuration(sv_frame_t duration) const -{ - Point p(*this); - p.m_haveDuration = true; - p.m_duration = duration; - return p; -} - -bool -Clipboard::Point::haveLabel() const -{ - return m_haveLabel; -} - -QString -Clipboard::Point::getLabel() const -{ - return m_label; -} - -Clipboard::Point -Clipboard::Point::withLabel(QString label) const -{ - Point p(*this); - p.m_haveLabel = true; - p.m_label = label; - return p; -} - -bool -Clipboard::Point::haveLevel() const -{ - return m_haveLevel; -} - -float -Clipboard::Point::getLevel() const -{ - return m_level; -} - -Clipboard::Point -Clipboard::Point::withLevel(float level) const -{ - Point p(*this); - p.m_haveLevel = true; - p.m_level = level; - return p; -} - -bool -Clipboard::Point::haveReferenceFrame() const -{ - return m_haveReferenceFrame; -} - -bool -Clipboard::Point::referenceFrameDiffers() const -{ - return m_haveReferenceFrame && (m_referenceFrame != m_frame); -} - -sv_frame_t -Clipboard::Point::getReferenceFrame() const -{ - return m_referenceFrame; -} - -void -Clipboard::Point::setReferenceFrame(sv_frame_t f) -{ - m_haveReferenceFrame = true; - m_referenceFrame = f; -} - Clipboard::Clipboard() { } Clipboard::~Clipboard() { } diff -r 7db29268cf4c -r b2f32c554199 base/Clipboard.h --- a/base/Clipboard.h Tue Mar 05 14:18:37 2019 +0000 +++ b/base/Clipboard.h Tue Mar 05 15:15:11 2019 +0000 @@ -16,68 +16,13 @@ #ifndef SV_CLIPBOARD_H #define SV_CLIPBOARD_H -#include #include -#include "BaseTypes.h" +#include "Point.h" class Clipboard { public: - class Point - { - public: - Point(sv_frame_t frame, QString label); - Point(sv_frame_t frame, float value, QString label); - Point(sv_frame_t frame, float value, sv_frame_t duration, QString label); - Point(sv_frame_t frame, float value, sv_frame_t duration, float level, QString label); - - Point(const Point &point) =default; - Point &operator=(const Point &point) =default; - - bool haveFrame() const; - sv_frame_t getFrame() const; - Point withFrame(sv_frame_t frame) const; - - bool haveValue() const; - float getValue() const; - Point withValue(float value) const; - - bool haveDuration() const; - sv_frame_t getDuration() const; - Point withDuration(sv_frame_t duration) const; - - bool haveLabel() const; - QString getLabel() const; - Point withLabel(QString label) const; - - bool haveLevel() const; - float getLevel() const; - Point withLevel(float level) const; - - bool haveReferenceFrame() const; - bool referenceFrameDiffers() const; // from point frame - - sv_frame_t getReferenceFrame() const; - void setReferenceFrame(sv_frame_t); - - private: - // Order of fields here is chosen to minimise overall size of struct. - // If you change something, check what difference it makes to packing. - bool m_haveValue : 1; - bool m_haveLevel : 1; - bool m_haveFrame : 1; - bool m_haveDuration : 1; - bool m_haveReferenceFrame : 1; - bool m_haveLabel : 1; - float m_value; - float m_level; - sv_frame_t m_frame; - sv_frame_t m_duration; - sv_frame_t m_referenceFrame; - QString m_label; - }; - Clipboard(); ~Clipboard(); diff -r 7db29268cf4c -r b2f32c554199 base/Point.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/base/Point.h Tue Mar 05 15:15:11 2019 +0000 @@ -0,0 +1,134 @@ +/* -*- 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_POINT_H +#define SV_POINT_H + +#include + +#include "BaseTypes.h" + +class Point +{ +public: + Point(sv_frame_t frame, QString label) : + m_haveValue(false), m_haveLevel(false), m_haveFrame(true), + m_haveDuration(false), m_haveReferenceFrame(false), m_haveLabel(true), + m_value(0.f), m_level(0.f), m_frame(frame), + m_duration(0), m_referenceFrame(0), m_label(label) { } + + Point(sv_frame_t frame, float value, QString label) : + m_haveValue(true), m_haveLevel(false), m_haveFrame(true), + m_haveDuration(false), m_haveReferenceFrame(false), m_haveLabel(true), + m_value(value), m_level(0.f), m_frame(frame), + m_duration(0), m_referenceFrame(0), m_label(label) { } + + Point(sv_frame_t frame, float value, sv_frame_t duration, QString label) : + m_haveValue(true), m_haveLevel(false), m_haveFrame(true), + m_haveDuration(true), m_haveReferenceFrame(false), m_haveLabel(true), + m_value(value), m_level(0.f), m_frame(frame), + m_duration(duration), m_referenceFrame(0), m_label(label) { } + + Point(sv_frame_t frame, float value, sv_frame_t duration, float level, QString label) : + m_haveValue(true), m_haveLevel(true), m_haveFrame(true), + m_haveDuration(true), m_haveReferenceFrame(false), m_haveLabel(true), + m_value(value), m_level(level), m_frame(frame), + m_duration(duration), m_referenceFrame(0), m_label(label) { } + + Point(const Point &point) =default; + Point &operator=(const Point &point) =default; + Point &operator=(Point &&point) =default; + + bool haveFrame() const { return m_haveFrame; } + sv_frame_t getFrame() const { return m_frame; } + + Point withFrame(sv_frame_t frame) const { + Point p(*this); + p.m_haveFrame = true; + p.m_frame = frame; + return p; + } + + bool haveValue() const { return m_haveValue; } + float getValue() const { return m_value; } + + Point withValue(float value) const { + Point p(*this); + p.m_haveValue = true; + p.m_value = value; + return p; + } + + bool haveDuration() const { return m_haveDuration; } + sv_frame_t getDuration() const { return m_duration; } + + Point withDuration(sv_frame_t duration) const { + Point p(*this); + p.m_haveDuration = true; + p.m_duration = duration; + return p; + } + + bool haveLabel() const { return m_haveLabel; } + QString getLabel() const { return m_label; } + + Point withLabel(QString label) const { + Point p(*this); + p.m_haveLabel = true; + p.m_label = label; + return p; + } + + bool haveLevel() const { return m_haveLevel; } + float getLevel() const { return m_level; } + Point withLevel(float level) const { + Point p(*this); + p.m_haveLevel = true; + p.m_level = level; + return p; + } + + bool haveReferenceFrame() const { return m_haveReferenceFrame; } + sv_frame_t getReferenceFrame() const { return m_referenceFrame; } + + bool referenceFrameDiffers() const { // from point frame + return m_haveReferenceFrame && (m_referenceFrame != m_frame); + } + + Point withReferenceFrame(sv_frame_t frame) const { + Point p(*this); + p.m_haveReferenceFrame = true; + p.m_referenceFrame = frame; + return p; + } + +private: + // The order of fields here is chosen to minimise overall size of struct. + // If you change something, check what difference it makes to packing. + bool m_haveValue : 1; + bool m_haveLevel : 1; + bool m_haveFrame : 1; + bool m_haveDuration : 1; + bool m_haveReferenceFrame : 1; + bool m_haveLabel : 1; + float m_value; + float m_level; + sv_frame_t m_frame; + sv_frame_t m_duration; + sv_frame_t m_referenceFrame; + QString m_label; +}; + +#endif diff -r 7db29268cf4c -r b2f32c554199 data/model/Model.h --- a/data/model/Model.h Tue Mar 05 14:18:37 2019 +0000 +++ b/data/model/Model.h Tue Mar 05 15:15:11 2019 +0000 @@ -55,9 +55,10 @@ virtual sv_frame_t getStartFrame() const = 0; /** - * Return the audio frame at the end of the model, i.e. 1 more - * than the final frame contained within the model. The end frame - * minus the start frame should yield the total duration in frames + * Return the audio frame at the end of the model, i.e. the final + * frame contained within the model plus 1 (or plus the model's + * "resolution" granularity, if more than 1). The end frame minus + * the start frame should yield the total duration in frames * spanned by the model. This is consistent with the definition of * the end frame of a Selection object. */ diff -r 7db29268cf4c -r b2f32c554199 data/model/NoteModel.h --- a/data/model/NoteModel.h Tue Mar 05 14:18:37 2019 +0000 +++ b/data/model/NoteModel.h Tue Mar 05 15:15:11 2019 +0000 @@ -91,6 +91,12 @@ return p1.frame < p2.frame; } }; + + bool operator==(const Note &other) const { + // ew + Comparator c; + return !(c(*this, other) || c(other, *this)); + } }; diff -r 7db29268cf4c -r b2f32c554199 data/model/test/TestSparseModels.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/data/model/test/TestSparseModels.h Tue Mar 05 15:15:11 2019 +0000 @@ -0,0 +1,225 @@ +/* -*- 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 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 TEST_SPARSE_MODELS_H +#define TEST_SPARSE_MODELS_H + +#include "../SparseOneDimensionalModel.h" +#include "../NoteModel.h" + +#include +#include + +#include + +using namespace std; + +class TestSparseModels : public QObject +{ + Q_OBJECT + +private slots: + void s1d_empty() { + SparseOneDimensionalModel m(100, 10, false); + QCOMPARE(m.isEmpty(), true); + QCOMPARE(m.getPointCount(), 0); + QCOMPARE(m.getPoints().begin(), m.getPoints().end()); + QCOMPARE(m.getStartFrame(), 0); + QCOMPARE(m.getEndFrame(), 0); + QCOMPARE(m.getSampleRate(), 100); + QCOMPARE(m.getResolution(), 10); + QCOMPARE(m.isSparse(), true); + + SparseOneDimensionalModel::Point p(10); + m.addPoint(p); + m.clear(); + QCOMPARE(m.isEmpty(), true); + QCOMPARE(m.getPointCount(), 0); + QCOMPARE(m.getPoints().begin(), m.getPoints().end()); + QCOMPARE(m.getStartFrame(), 0); + QCOMPARE(m.getEndFrame(), 0); + + m.addPoint(p); + m.deletePoint(p); + QCOMPARE(m.isEmpty(), true); + QCOMPARE(m.getPointCount(), 0); + QCOMPARE(m.getPoints().begin(), m.getPoints().end()); + QCOMPARE(m.getStartFrame(), 0); + QCOMPARE(m.getEndFrame(), 0); + } + + void s1d_extents() { + SparseOneDimensionalModel m(100, 10, false); + SparseOneDimensionalModel::Point p1(20); + m.addPoint(p1); + QCOMPARE(m.isEmpty(), false); + QCOMPARE(m.getPointCount(), 1); + SparseOneDimensionalModel::Point p2(50); + m.addPoint(p2); + QCOMPARE(m.isEmpty(), false); + QCOMPARE(m.getPointCount(), 2); + QCOMPARE(m.getPoints().size(), 2); + QCOMPARE(*m.getPoints().begin(), p1); + QCOMPARE(*m.getPoints().rbegin(), p2); + QCOMPARE(m.getStartFrame(), 20); + QCOMPARE(m.getEndFrame(), 60); + QCOMPARE(m.containsPoint(p1), true); + m.deletePoint(p1); + QCOMPARE(m.getPointCount(), 1); + QCOMPARE(m.getPoints().size(), 1); + QCOMPARE(*m.getPoints().begin(), p2); + QCOMPARE(m.getStartFrame(), 50); + QCOMPARE(m.getEndFrame(), 60); + QCOMPARE(m.containsPoint(p1), false); + } + + void s1d_sample() { + SparseOneDimensionalModel m(100, 10, false); + SparseOneDimensionalModel::Point p1(20), p2(20), p3(50); + m.addPoint(p1); + m.addPoint(p2); + m.addPoint(p3); + QCOMPARE(m.getPoints().size(), 3); + QCOMPARE(*m.getPoints().begin(), p1); + QCOMPARE(*m.getPoints().rbegin(), p3); + + auto pp = m.getPoints(20, 30); + QCOMPARE(pp.size(), 2); + QCOMPARE(*pp.begin(), p1); + QCOMPARE(*pp.rbegin(), p2); + + pp = m.getPoints(40, 50); + QCOMPARE(pp.size(), 0); + + pp = m.getPoints(50, 50); + QCOMPARE(pp.size(), 1); + QCOMPARE(*pp.begin(), p3); + } + + void s1d_xml() { + SparseOneDimensionalModel m(100, 10, false); + m.setObjectName("This \"&\" that"); + SparseOneDimensionalModel::Point p1(20), p2(20), p3(50); + p2.label = "Label &'\">"; + m.addPoint(p1); + m.addPoint(p2); + m.addPoint(p3); + QString xml; + QTextStream str(&xml, QIODevice::WriteOnly); + m.toXml(str); + str.flush(); + QString expected = + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; + expected.replace("\'", "\""); + if (xml != expected) { + cerr << "Obtained xml:\n" << xml + << "\nExpected:\n" << expected << endl; + } + QCOMPARE(xml, expected); + } + + void note_extents() { + NoteModel m(100, 10, false); + NoteModel::Point p1(20, 123.4, 40, 0.8, "note 1"); + m.addPoint(p1); + QCOMPARE(m.isEmpty(), false); + QCOMPARE(m.getPointCount(), 1); + NoteModel::Point p2(50, 124.3, 30, 0.9, "note 2"); + m.addPoint(p2); + QCOMPARE(m.isEmpty(), false); + QCOMPARE(m.getPointCount(), 2); + QCOMPARE(m.getPoints().size(), 2); + QCOMPARE(*m.getPoints().begin(), p1); + QCOMPARE(*m.getPoints().rbegin(), p2); + QCOMPARE(m.getStartFrame(), 20); + QCOMPARE(m.getEndFrame(), 80); + QCOMPARE(m.containsPoint(p1), true); + QCOMPARE(m.getValueMinimum(), 123.4); + QCOMPARE(m.getValueMaximum(), 124.3); + m.deletePoint(p1); + QCOMPARE(m.getPointCount(), 1); + QCOMPARE(m.getPoints().size(), 1); + QCOMPARE(*m.getPoints().begin(), p2); + QCOMPARE(m.getStartFrame(), 50); + QCOMPARE(m.getEndFrame(), 80); + QCOMPARE(m.containsPoint(p1), false); + } + + void note_sample() { + NoteModel m(100, 10, false); + NoteModel::Point p1(20, 123.4, 20, 0.8, "note 1"); + NoteModel::Point p2(20, 124.3, 10, 0.9, "note 2"); + NoteModel::Point p3(50, 126.3, 30, 0.9, "note 3"); + m.addPoint(p1); + m.addPoint(p2); + m.addPoint(p3); + + QCOMPARE(m.getPoints().size(), 3); + QCOMPARE(*m.getPoints().begin(), p1); + QCOMPARE(*m.getPoints().rbegin(), p3); + + auto pp = m.getPoints(20, 30); + QCOMPARE(pp.size(), 2); + QCOMPARE(*pp.begin(), p1); + QCOMPARE(*pp.rbegin(), p2); + + pp = m.getPoints(30, 50); + QCOMPARE(pp.size(), 1); + QCOMPARE(*pp.begin(), p1); + + pp = m.getPoints(40, 50); + QCOMPARE(pp.size(), 0); + + pp = m.getPoints(50, 50); + QCOMPARE(pp.size(), 1); + QCOMPARE(*pp.begin(), p3); + } + + void note_xml() { + NoteModel m(100, 10, false); + NoteModel::Point p1(20, 123.4, 20, 0.8, "note 1"); + NoteModel::Point p2(20, 124.3, 10, 0.9, "note 2"); + NoteModel::Point p3(50, 126.3, 30, 0.9, "note 3"); + m.setScaleUnits("Hz"); + m.addPoint(p1); + m.addPoint(p2); + m.addPoint(p3); + QString xml; + QTextStream str(&xml, QIODevice::WriteOnly); + m.toXml(str); + str.flush(); + QString expected = + "\n" + "\n" + " \n" + " \n" + " \n" + "\n"; + expected.replace("\'", "\""); + if (xml != expected) { + cerr << "Obtained xml:\n" << xml + << "\nExpected:\n" << expected << endl; + } + QCOMPARE(xml, expected); + } + + +}; + +#endif diff -r 7db29268cf4c -r b2f32c554199 files.pri --- a/files.pri Tue Mar 05 14:18:37 2019 +0000 +++ b/files.pri Tue Mar 05 15:15:11 2019 +0000 @@ -16,6 +16,7 @@ base/Playable.h \ base/PlayParameterRepository.h \ base/PlayParameters.h \ + base/Point.h \ base/Preferences.h \ base/Profiler.h \ base/ProgressPrinter.h \