changeset 1611:b2f32c554199 single-point

Pull out the Point class, plus start testing NoteModel, plus actually add the tests...
author Chris Cannam
date Tue, 05 Mar 2019 15:15:11 +0000
parents 7db29268cf4c
children 23a29e5dc0e9
files base/Clipboard.cpp base/Clipboard.h base/Point.h data/model/Model.h data/model/NoteModel.h data/model/test/TestSparseModels.h files.pri
diffstat 7 files changed, 371 insertions(+), 253 deletions(-) [+]
line wrap: on
line diff
--- 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() { }
 
--- 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 <QString>
 #include <vector>
 
-#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();
 
--- /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 <QString>
+
+#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
--- 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.
      */
--- 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));
+    }
 };
 
 
--- /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 <QObject>
+#include <QtTest>
+
+#include <iostream>
+
+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 =
+            "<model id='1' name='This &quot;&amp;&quot; that' sampleRate='100' start='20' end='60' type='sparse' dimensions='1' resolution='10' notifyOnAdd='false' dataset='0' />\n"
+            "<dataset id='0' dimensions='1'>\n"
+            "  <point frame='20' label='' />\n"
+            "  <point frame='20' label='Label &amp;&apos;&quot;&gt;' />\n"
+            "  <point frame='50' label='' />\n"
+            "</dataset>\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 =
+            "<model id='3' name='' sampleRate='100' start='20' end='60' type='sparse' dimensions='3' resolution='10' notifyOnAdd='false' dataset='2'  subtype='note' valueQuantization='0' minimum='123.4' maximum='126.3' units='Hz'/>\n"
+            "<dataset id='2' dimensions='3'>\n"
+            "  <point frame='20' value='123.4' duration='20' level='0.8' label='note 1' />\n"
+            "  <point frame='20' value='124.3' duration='10' level='0.9' label='note 2' />\n"
+            "  <point frame='50' value='126.3' duration='30' level='0.9' label='note 3' />\n"
+            "</dataset>\n";
+        expected.replace("\'", "\"");
+        if (xml != expected) {
+            cerr << "Obtained xml:\n" << xml
+                 << "\nExpected:\n" << expected << endl;
+        }
+        QCOMPARE(xml, expected);
+    }
+    
+        
+};
+
+#endif
--- 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 \