changeset 1676:3b51df7695a4 single-point

Merge from branch osc-script
author Chris Cannam
date Thu, 28 Mar 2019 10:39:24 +0000
parents b5580d93f28b (current diff) 6804af71b7be (diff)
children f97d64b8674f
files
diffstat 14 files changed, 155 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/base/Event.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/base/Event.h	Thu Mar 28 10:39:24 2019 +0000
@@ -256,21 +256,44 @@
         return m_uri < p.m_uri;
     }
 
+    struct ExportNameOptions {
+
+        ExportNameOptions() :
+            valueAtttributeName("value"),
+            uriAttributeName("uri") { }
+
+        QString valueAtttributeName;
+        QString uriAttributeName;
+    };
+    
     void toXml(QTextStream &stream,
                QString indent = "",
-               QString extraAttributes = "") const {
+               QString extraAttributes = "",
+               ExportNameOptions opts = ExportNameOptions()) const {
 
         // For I/O purposes these are points, not events
         stream << indent << QString("<point frame=\"%1\" ").arg(m_frame);
-        if (m_haveValue) stream << QString("value=\"%1\" ").arg(m_value);
-        if (m_haveDuration) stream << QString("duration=\"%1\" ").arg(m_duration);
-        if (m_haveLevel) stream << QString("level=\"%1\" ").arg(m_level);
-        if (m_haveReferenceFrame) stream << QString("referenceFrame=\"%1\" ")
-                                      .arg(m_referenceFrame);
-        stream << QString("label=\"%1\" ")
-            .arg(XmlExportable::encodeEntities(m_label));
+        if (m_haveValue) {
+            stream << QString("%1=\"%2\" ")
+                .arg(opts.valueAtttributeName).arg(m_value);
+        }
+        if (m_haveDuration) {
+            stream << QString("duration=\"%1\" ").arg(m_duration);
+        }
+        if (m_haveLevel) {
+            stream << QString("level=\"%1\" ").arg(m_level);
+        }
+        if (m_haveReferenceFrame) {
+            stream << QString("referenceFrame=\"%1\" ")
+                .arg(m_referenceFrame);
+        }
+        if (m_label != "") {
+            stream << QString("label=\"%1\" ")
+                .arg(XmlExportable::encodeEntities(m_label));
+        }
         if (m_uri != QString()) {
-            stream << QString("uri=\"%1\" ")
+            stream << QString("%1=\"%2\" ")
+                .arg(opts.uriAttributeName)
                 .arg(XmlExportable::encodeEntities(m_uri));
         }
         stream << extraAttributes << "/>\n";
--- a/base/EventSeries.cpp	Wed Mar 27 14:13:32 2019 +0000
+++ b/base/EventSeries.cpp	Thu Mar 28 10:39:24 2019 +0000
@@ -485,12 +485,21 @@
                    QString indent,
                    QString extraAttributes) const
 {
+    toXml(out, indent, extraAttributes, Event::ExportNameOptions());
+}
+
+void
+EventSeries::toXml(QTextStream &out,
+                   QString indent,
+                   QString extraAttributes,
+                   Event::ExportNameOptions options) const
+{
     out << indent << QString("<dataset id=\"%1\" %2>\n")
         .arg(getObjectExportId(this))
         .arg(extraAttributes);
     
     for (const auto &p: m_events) {
-        p.toXml(out, indent + "  ");
+        p.toXml(out, indent + "  ", "", options);
     }
     
     out << indent << "</dataset>\n";
--- a/base/EventSeries.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/base/EventSeries.h	Thu Mar 28 10:39:24 2019 +0000
@@ -205,6 +205,14 @@
     void toXml(QTextStream &out,
                QString indent,
                QString extraAttributes) const override;
+
+    /**
+     * Emit to XML as a dataset element.
+     */
+    void toXml(QTextStream &out,
+               QString indent,
+               QString extraAttributes,
+               Event::ExportNameOptions) const;
     
 private:
     /**
--- a/data/model/AlignmentModel.cpp	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/AlignmentModel.cpp	Thu Mar 28 10:39:24 2019 +0000
@@ -54,6 +54,8 @@
 
 AlignmentModel::~AlignmentModel()
 {
+    SVDEBUG << "AlignmentModel(" << this << ")::~AlignmentModel()" << endl;
+    
     if (m_inputModel) m_inputModel->aboutToDelete();
     delete m_inputModel;
 
@@ -201,8 +203,8 @@
         m_rawPath->isReady(&completion);
 
 #ifdef DEBUG_ALIGNMENT_MODEL
-        cerr << "AlignmentModel::pathCompletionChanged: completion = "
-                  << completion << endl;
+        SVCERR << "AlignmentModel::pathCompletionChanged: completion = "
+               << completion << endl;
 #endif
 
         m_pathComplete = (completion == 100);
@@ -211,7 +213,8 @@
 
             constructPath();
             constructReversePath();
-            
+
+            SVDEBUG << "AlignmentModel: path complete, deleting input" << endl;
             if (m_inputModel) m_inputModel->aboutToDelete();
             delete m_inputModel;
             m_inputModel = nullptr;
--- a/data/model/ImageModel.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/ImageModel.h	Thu Mar 28 10:39:24 2019 +0000
@@ -142,7 +142,7 @@
     void add(Event e) override {
 
         {   QMutexLocker locker(&m_mutex);
-            m_events.add(e.withoutDuration());
+            m_events.add(e.withoutDuration().withoutValue().withoutLevel());
         }
         
         m_notifier.update(e.getFrame(), m_resolution);
@@ -255,8 +255,11 @@
                           // subsequent events are always notified
              .arg(getObjectExportId(&m_events))
              .arg(extraAttributes));
+
+        Event::ExportNameOptions options;
+        options.uriAttributeName = "image";
         
-        m_events.toXml(out, indent, QString("dimensions=\"1\""));
+        m_events.toXml(out, indent, QString("dimensions=\"1\""), options);
     }
   
 protected:
--- a/data/model/Model.cpp	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/Model.cpp	Thu Mar 28 10:39:24 2019 +0000
@@ -22,7 +22,7 @@
 
 Model::~Model()
 {
-//    SVDEBUG << "Model::~Model(" << this << ")" << endl;
+    SVDEBUG << "Model::~Model(" << this << ")" << endl;
 
     if (!m_aboutToDelete) {
         SVDEBUG << "NOTE: Model(" << this << ", \""
@@ -73,9 +73,10 @@
 void
 Model::aboutToDelete()
 {
-//    SVDEBUG << "Model(" << this << ", \""
-//            << objectName() << "\", type uri <"
-//            << m_typeUri << ">)::aboutToDelete()" << endl;
+    SVDEBUG << "Model(" << this << ", \""
+            << objectName() << "\", type name \""
+            << getTypeName() << "\", type uri <"
+            << m_typeUri << ">)::aboutToDelete()" << endl;
 
     if (m_aboutToDelete) {
         SVDEBUG << "WARNING: Model(" << this << ", \""
@@ -98,6 +99,9 @@
 void
 Model::setAlignment(AlignmentModel *alignment)
 {
+    SVDEBUG << "Model(" << this << "): accepting alignment model "
+            << alignment << endl;
+    
     if (m_alignment) {
         m_alignment->aboutToDelete();
         delete m_alignment;
--- a/data/model/PathModel.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/PathModel.h	Thu Mar 28 10:39:24 2019 +0000
@@ -76,7 +76,7 @@
         m_end(0) {
     }
 
-    QString getTypeName() const override { return tr("Text"); }
+    QString getTypeName() const override { return tr("Path"); }
     bool isSparse() const { return true; }
     bool isOK() const override { return true; }
 
@@ -179,7 +179,14 @@
              .arg(getObjectExportId(&m_points))
              .arg(extraAttributes));
 
+        out << indent << QString("<dataset id=\"%1\" dimensions=\"2\">\n")
+            .arg(getObjectExportId(&m_points));
         
+        for (PathPoint p: m_points) {
+            p.toXml(out, indent + "  ", "");
+        }
+
+        out << indent << "</dataset>\n";
     }
     
 protected:
--- a/data/model/TextModel.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/TextModel.h	Thu Mar 28 10:39:24 2019 +0000
@@ -137,7 +137,7 @@
     void add(Event e) override {
 
         {   QMutexLocker locker(&m_mutex);
-            m_events.add(e.withoutDuration());
+            m_events.add(e.withoutDuration().withoutLevel());
         }
         
         m_notifier.update(e.getFrame(), m_resolution);
@@ -250,8 +250,11 @@
                           // subsequent events are always notified
              .arg(getObjectExportId(&m_events))
              .arg(extraAttributes));
+
+        Event::ExportNameOptions options;
+        options.valueAtttributeName = "height";
         
-        m_events.toXml(out, indent, QString("dimensions=\"2\""));
+        m_events.toXml(out, indent, QString("dimensions=\"2\""), options);
     }
   
 protected:
--- a/data/model/test/TestSparseModels.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/model/test/TestSparseModels.h	Thu Mar 28 10:39:24 2019 +0000
@@ -19,6 +19,7 @@
 #include "../NoteModel.h"
 #include "../TextModel.h"
 #include "../PathModel.h"
+#include "../ImageModel.h"
 
 #include <QObject>
 #include <QtTest>
@@ -106,8 +107,9 @@
     void s1d_xml() {
         SparseOneDimensionalModel m(100, 10, false);
         m.setObjectName("This \"&\" that");
-        Event p1(20), p2(20), p3(50);
-        p2 = p2.withLabel("Label &'\">");
+        Event p1(20);
+        Event p2(20, "Label &'\">");
+        Event p3(50, 12.4f, 16, ""); // value + duration should not be saved
         m.add(p1);
         m.add(p2);
         m.add(p3);
@@ -118,9 +120,9 @@
         QString expected =
             "<model id='1' name='This &quot;&amp;&quot; that' sampleRate='100' start='20' end='60' type='sparse' dimensions='1' resolution='10' notifyOnAdd='true' dataset='0' />\n"
             "<dataset id='0' dimensions='1'>\n"
-            "  <point frame='20' label='' />\n"
+            "  <point frame='20' />\n"
             "  <point frame='20' label='Label &amp;&apos;&quot;&gt;' />\n"
-            "  <point frame='50' label='' />\n"
+            "  <point frame='50' />\n"
             "</dataset>\n";
         expected.replace("\'", "\"");
         if (xml != expected) {
@@ -226,7 +228,7 @@
         Event p2(20, 0.0f, "text 2");
         Event p3(50, 0.3f, "text 3");
         m.add(p1);
-        m.add(p2);
+        m.add(p2.withLevel(0.8f));
         m.add(p3);
         QString xml;
         QTextStream str(&xml, QIODevice::WriteOnly);
@@ -276,6 +278,28 @@
         QCOMPARE(xml, expected);
     }
 
+    void image_xml() {
+        ImageModel m(100, 10, false);
+        Event p1(20, 30, 40, "a label"); // value + duration should not be saved
+        m.add(p1.withURI("/path/to/thing.png").withLevel(0.8f));
+        QString xml;
+        QTextStream str(&xml, QIODevice::WriteOnly);
+        m.toXml(str);
+        str.flush();
+
+        QString expected =
+            "<model id='4' name='' sampleRate='100' start='20' end='30' type='sparse' dimensions='1' resolution='10' notifyOnAdd='true' dataset='2' subtype='image' />\n"
+            "<dataset id='2' dimensions='1'>\n"
+            "  <point frame='20' label='a label' image='/path/to/thing.png' />\n"
+            "</dataset>\n";
+        expected.replace("\'", "\"");
+        if (xml != expected) {
+            cerr << "Obtained xml:\n" << xml
+                 << "\nExpected:\n" << expected << endl;
+        }
+        QCOMPARE(xml, expected);
+    }
+
 };
 
 #endif
--- a/data/osc/OSCMessage.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/osc/OSCMessage.h	Thu Mar 28 10:39:24 2019 +0000
@@ -50,6 +50,18 @@
     int getArgCount() const;
     const QVariant &getArg(int i) const;
 
+    // For debugging purposes, not for interchange
+    QString toString() const {
+        QString s = QString("[%1][%2] %3")
+            .arg(m_target)
+            .arg(m_targetData)
+            .arg(m_method);
+        for (auto a: m_args) {
+            s.push_back(" \"" + a.toString() + "\"");
+        }
+        return s;
+    }
+
 private:
     int m_target;
     int m_targetData;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/osc/OSCMessageCallback.h	Thu Mar 28 10:39:24 2019 +0000
@@ -0,0 +1,25 @@
+/* -*- 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 SV_OSC_MESSAGE_CALLBACK_H
+#define SV_OSC_MESSAGE_CALLBACK_H
+
+class OSCMessage;
+
+class OSCMessageCallback {
+public:
+    virtual void handleOSCMessage(const OSCMessage &) = 0;
+};
+
+#endif
--- a/data/osc/OSCQueue.cpp	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/osc/OSCQueue.cpp	Thu Mar 28 10:39:24 2019 +0000
@@ -30,6 +30,8 @@
 
 #include <unistd.h>
 
+#include <QThread>
+
 void
 OSCQueue::oscError(int num, const char *msg, const char *path)
 {
@@ -155,6 +157,9 @@
     OSCMessage *message = m_buffer.readOne();
     OSCMessage rmessage = *message;
     delete message;
+    SVDEBUG << "OSCQueue::readMessage: In thread "
+            << QThread::currentThreadId() << ": message follows:\n"
+            << rmessage.toString() << endl;
     return rmessage;
 }
 
--- a/data/osc/OSCQueue.h	Wed Mar 27 14:13:32 2019 +0000
+++ b/data/osc/OSCQueue.h	Thu Mar 28 10:39:24 2019 +0000
@@ -43,6 +43,7 @@
 
     bool isEmpty() const { return getMessagesAvailable() == 0; }
     int getMessagesAvailable() const;
+    void postMessage(OSCMessage);
     OSCMessage readMessage();
 
     QString getOSCURL() const;
@@ -59,7 +60,6 @@
                                  int, lo_message, void *);
 #endif
 
-    void postMessage(OSCMessage);
     bool parseOSCPath(QString path, int &target, int &targetData, QString &method);
 
     RingBuffer<OSCMessage *> m_buffer;
--- a/files.pri	Wed Mar 27 14:13:32 2019 +0000
+++ b/files.pri	Thu Mar 28 10:39:24 2019 +0000
@@ -104,6 +104,7 @@
            data/model/ReadOnlyWaveFileModel.h \
            data/model/WritableWaveFileModel.h \
            data/osc/OSCMessage.h \
+           data/osc/OSCMessageCallback.h \
            data/osc/OSCQueue.h \
 	   plugin/PluginScan.h \
            plugin/DSSIPluginFactory.h \