changeset 500:83eae5239db6

* Permit viewing (though not editing) colour 3d plot layer data in the spreadsheet data viewer dialog * Add somewhat simplistic RDF export for layers * Fix display of peak frequencies in spectrum layer * Fix (I hope) sizing of plugin parameter dialog
author Chris Cannam
date Tue, 02 Dec 2008 17:17:25 +0000
parents b71116d3c180
children ca208281238b
files data/fft/FFTDataServer.cpp data/model/DenseThreeDimensionalModel.h data/model/FFTModel.cpp rdf/RDFExporter.cpp rdf/RDFExporter.h rdf/RDFFeatureWriter.cpp rdf/RDFImporter.cpp rdf/rdf.pro
diffstat 8 files changed, 347 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/data/fft/FFTDataServer.cpp	Fri Nov 28 15:45:20 2008 +0000
+++ b/data/fft/FFTDataServer.cpp	Tue Dec 02 17:17:25 2008 +0000
@@ -916,10 +916,14 @@
         fillColumn(x, true);
     }
 
+    float mean = 0.f;
     for (size_t i = 0; i < count; ++i) {
         values[i] = cache->getMagnitudeAt(col, i * step + minbin);
+        mean += values[i];
     }
+    if (count > 0) mean /= count;
 
+//    std::cerr << "FFTDataServer::getMagnitudeAt: returning " << count << " values of mean " << mean << std::endl;
     return true;
 }
 
--- a/data/model/DenseThreeDimensionalModel.h	Fri Nov 28 15:45:20 2008 +0000
+++ b/data/model/DenseThreeDimensionalModel.h	Tue Dec 02 17:17:25 2008 +0000
@@ -17,12 +17,15 @@
 #define _DENSE_THREE_DIMENSIONAL_MODEL_H_
 
 #include "Model.h"
+#include "TabularModel.h"
 #include "base/ZoomConstraint.h"
+#include "base/RealTime.h"
 
 #include <QMutex>
 #include <vector>
 
-class DenseThreeDimensionalModel : public Model
+class DenseThreeDimensionalModel : public Model,
+                                   public TabularModel
 {
     Q_OBJECT
 
@@ -108,6 +111,54 @@
 
     virtual int getCompletion() const = 0;
 
+    /*
+       TabularModel methods.
+       This class is non-editable -- subclasses may be editable.
+       Row and column are transposed for the tabular view (which is
+       "on its side").
+     */
+    
+    virtual int getRowCount() const { return getWidth(); }
+    virtual int getColumnCount() const { return getHeight() + 2; }
+
+    virtual QString getHeading(int column) const
+    {
+        switch (column) {
+        case 0: return tr("Time");
+        case 1: return tr("Frame");
+        default: return getBinName(column - 2);
+        }
+    }
+
+    virtual QVariant getData(int row, int column, int role) const 
+    {
+        switch (column) {
+        case 0: {
+            RealTime rt = RealTime::frame2RealTime(row * getResolution(),
+                                                   getSampleRate());
+            return rt.toText().c_str();
+        }
+        case 1:
+            return int(row * getResolution());
+        default:
+            return getValueAt(row, column - 2);
+        }
+    }
+
+    virtual bool isColumnTimeValue(int col) const {
+        return col < 2;
+    }
+    virtual SortType getSortType(int col) const {
+        return SortNumeric;
+    }
+
+    virtual long getFrameForRow(int row) const {
+        return row * getSampleRate();
+    }
+    virtual int getRowForFrame(long frame) const {
+        return frame / getSampleRate();
+    }
+
 protected:
     DenseThreeDimensionalModel() { }
 };
--- a/data/model/FFTModel.cpp	Fri Nov 28 15:45:20 2008 +0000
+++ b/data/model/FFTModel.cpp	Tue Dec 02 17:17:25 2008 +0000
@@ -170,10 +170,13 @@
     size_t h = getHeight();
 
     float magnitudes[h];
+
     if (m_server->getMagnitudesAt(x << m_xshift, magnitudes)) {
+
         for (size_t y = 0; y < h; ++y) {
-            result.push_back(magnitudes[h]);
+            result.push_back(magnitudes[y]);
         }
+
     } else {
         for (size_t i = 0; i < h; ++i) result.push_back(0.f);
     }
@@ -259,6 +262,10 @@
 
     getColumn(x, values);
 
+    float mean = 0.f;
+    for (int i =0; i < values.size(); ++i) mean += values[i];
+    if (values.size() >0) mean /= values.size();
+
     // For peak picking we use a moving median window, picking the
     // highest value within each continuous region of values that
     // exceed the median.  For pitch adaptivity, we adjust the window
@@ -269,6 +276,7 @@
     std::deque<float> window;
     std::vector<size_t> inrange;
     float dist = 0.5;
+
     size_t medianWinSize = getPeakPickWindowSize(type, sampleRate, ymin, dist);
     size_t halfWin = medianWinSize/2;
 
@@ -280,6 +288,8 @@
     if (ymax + halfWin < values.size()) binmax = ymax + halfWin;
     else binmax = values.size()-1;
 
+    size_t prevcentre = 0;
+
     for (size_t bin = binmin; bin <= binmax; ++bin) {
 
         float value = values[bin];
@@ -290,7 +300,11 @@
         medianWinSize = getPeakPickWindowSize(type, sampleRate, bin, dist);
         halfWin = medianWinSize/2;
 
-        while (window.size() > medianWinSize) window.pop_front();
+        while (window.size() > medianWinSize) {
+            window.pop_front();
+        }
+
+        size_t actualSize = window.size();
 
         if (type == MajorPitchAdaptivePeaks) {
             if (ymax + halfWin < values.size()) binmax = ymax + halfWin;
@@ -301,25 +315,37 @@
         std::sort(sorted.begin(), sorted.end());
         float median = sorted[int(sorted.size() * dist)];
 
-        if (value > median) {
-            inrange.push_back(bin);
-        }
+        size_t centrebin = 0;
+        if (bin > actualSize/2) centrebin = bin - actualSize/2;
+        
+        while (centrebin > prevcentre || bin == binmin) {
 
-        if (value <= median || bin+1 == values.size()) {
-            size_t peakbin = 0;
-            float peakval = 0.f;
-            if (!inrange.empty()) {
-                for (size_t i = 0; i < inrange.size(); ++i) {
-                    if (i == 0 || values[inrange[i]] > peakval) {
-                        peakval = values[inrange[i]];
-                        peakbin = inrange[i];
+            if (centrebin > prevcentre) ++prevcentre;
+
+            float centre = values[prevcentre];
+
+            if (centre > median) {
+                inrange.push_back(centrebin);
+            }
+
+            if (centre <= median || centrebin+1 == values.size()) {
+                if (!inrange.empty()) {
+                    size_t peakbin = 0;
+                    float peakval = 0.f;
+                    for (size_t i = 0; i < inrange.size(); ++i) {
+                        if (i == 0 || values[inrange[i]] > peakval) {
+                            peakval = values[inrange[i]];
+                            peakbin = inrange[i];
+                        }
+                    }
+                    inrange.clear();
+                    if (peakbin >= ymin && peakbin <= ymax) {
+                        peaks.insert(peakbin);
                     }
                 }
-                inrange.clear();
-                if (peakbin >= ymin && peakbin <= ymax) {
-                    peaks.insert(peakbin);
-                }
             }
+
+            if (bin == binmin) break;
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rdf/RDFExporter.cpp	Tue Dec 02 17:17:25 2008 +0000
@@ -0,0 +1,176 @@
+/* -*- 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 2008 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.
+*/
+
+#include "RDFExporter.h"
+#include "RDFFeatureWriter.h"
+
+#include <vamp-hostsdk/Plugin.h>
+
+#include "data/model/Model.h"
+#include "data/model/RegionModel.h"
+#include "data/model/NoteModel.h"
+#include "data/model/SparseOneDimensionalModel.h"
+#include "data/model/SparseTimeValueModel.h"
+#include "data/model/TextModel.h"
+#include "data/model/EditableDenseThreeDimensionalModel.h"
+
+bool
+RDFExporter::canExportModel(Model *m)
+{
+    if (dynamic_cast<RegionModel *>(m)) return true;
+    if (dynamic_cast<NoteModel *>(m)) return true;
+    if (dynamic_cast<SparseTimeValueModel *>(m)) return true;
+    if (dynamic_cast<SparseOneDimensionalModel *>(m)) return true;
+    if (dynamic_cast<TextModel *>(m)) return true;
+    if (dynamic_cast<EditableDenseThreeDimensionalModel *>(m)) return true;
+    return false;
+}
+
+RDFExporter::RDFExporter(QString path, Model *m) :
+    m_path(path),
+    m_model(m),
+    m_fw(new RDFFeatureWriter())
+{
+    map<string, string> params;
+    params["one-file"] = path.toStdString();
+    params["force"] = "true";
+    m_fw->setParameters(params);
+}
+
+RDFExporter::~RDFExporter()
+{
+    delete m_fw;
+}
+
+bool
+RDFExporter::isOK() const
+{
+    return true;
+}
+
+QString
+RDFExporter::getError() const
+{
+    return "";
+}
+
+void
+RDFExporter::write()
+{
+    QString trackId; // nil
+    Transform transform; // nil
+    Vamp::Plugin::OutputDescriptor output; // nil
+    std::string summaryType; // nil
+
+    Vamp::Plugin::FeatureList features;
+    features.push_back(Vamp::Plugin::Feature());
+    Vamp::Plugin::Feature &f = features[0];
+    int sr = m_model->getSampleRate();
+
+    {
+        RegionModel *m = dynamic_cast<RegionModel *>(m_model);
+        if (m) {
+            f.hasTimestamp = true;
+            f.hasDuration = true;
+            const RegionModel::PointList &pl(m->getPoints());
+            for (RegionModel::PointList::const_iterator i = pl.begin(); 
+                 i != pl.end(); ++i) {
+                f.timestamp = Vamp::RealTime::frame2RealTime(i->frame, sr);
+                f.duration = Vamp::RealTime::frame2RealTime(i->duration, sr);
+                f.values.clear();
+                f.values.push_back(i->value);
+                f.label = i->label.toStdString();
+                m_fw->write(trackId, transform, output, features, summaryType);
+            }
+            return;
+        }
+    }
+    {
+        NoteModel *m = dynamic_cast<NoteModel *>(m_model);
+        if (m) {
+            f.hasTimestamp = true;
+            f.hasDuration = true;
+            const NoteModel::PointList &pl(m->getPoints());
+            for (NoteModel::PointList::const_iterator i = pl.begin(); 
+                 i != pl.end(); ++i) {
+                f.timestamp = Vamp::RealTime::frame2RealTime(i->frame, sr);
+                f.duration = Vamp::RealTime::frame2RealTime(i->duration, sr);
+                f.values.clear();
+                f.values.push_back(i->value);
+                f.values.push_back(i->level);
+                f.label = i->label.toStdString();
+                m_fw->write(trackId, transform, output, features, summaryType);
+            }
+            return;
+        }
+    }
+    {     
+        SparseOneDimensionalModel *m = dynamic_cast<SparseOneDimensionalModel *>(m_model);
+        if (m) {
+            f.hasTimestamp = true;
+            f.hasDuration = false;
+            const SparseOneDimensionalModel::PointList &pl(m->getPoints());
+            for (SparseOneDimensionalModel::PointList::const_iterator i = pl.begin(); 
+                 i != pl.end(); ++i) {
+                f.timestamp = Vamp::RealTime::frame2RealTime(i->frame, sr);
+                f.values.clear();
+                f.label = i->label.toStdString();
+                m_fw->write(trackId, transform, output, features, summaryType);
+            }
+            return;
+        }
+    }
+    {            
+        SparseTimeValueModel *m = dynamic_cast<SparseTimeValueModel *>(m_model);
+        if (m) {
+            f.hasTimestamp = true;
+            f.hasDuration = false;
+            const SparseTimeValueModel::PointList &pl(m->getPoints());
+            for (SparseTimeValueModel::PointList::const_iterator i = pl.begin(); 
+                 i != pl.end(); ++i) {
+                f.timestamp = Vamp::RealTime::frame2RealTime(i->frame, sr);
+                f.values.clear();
+                f.values.push_back(i->value);
+                f.label = i->label.toStdString();
+                m_fw->write(trackId, transform, output, features, summaryType);
+            }
+            return;
+        }
+    }
+    {     
+        TextModel *m = dynamic_cast<TextModel *>(m_model);
+        if (m) {
+            f.hasTimestamp = true;
+            f.hasDuration = false;
+            const TextModel::PointList &pl(m->getPoints());
+            for (TextModel::PointList::const_iterator i = pl.begin(); 
+                 i != pl.end(); ++i) {
+                f.timestamp = Vamp::RealTime::frame2RealTime(i->frame, sr);
+                f.values.clear();
+                f.values.push_back(i->height);
+                f.label = i->label.toStdString();
+                m_fw->write(trackId, transform, output, features, summaryType);
+            }
+            return;
+        }
+    }
+}
+
+QString
+RDFExporter::getSupportedExtensions()
+{
+    return "*.n3 *.ttl";
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rdf/RDFExporter.h	Tue Dec 02 17:17:25 2008 +0000
@@ -0,0 +1,49 @@
+/* -*- 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 2008 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 _RDF_EXPORTER_H_
+#define _RDF_EXPORTER_H_
+
+#include <QString>
+
+class Model;
+class RDFFeatureWriter;
+
+class RDFExporter
+{
+public:
+    /**
+     * Return the file extensions that we can write, in a format
+     * suitable for use with QFileDialog.  For example, "*.ttl *.n3".
+     */
+    static QString getSupportedExtensions();
+
+    RDFExporter(QString path, Model *model);
+    virtual ~RDFExporter();
+
+    static bool canExportModel(Model *);
+
+    virtual bool isOK() const;
+    virtual QString getError() const;
+
+    virtual void write();
+
+protected:
+    QString m_path;
+    Model *m_model;
+    RDFFeatureWriter *m_fw;
+};
+
+#endif
--- a/rdf/RDFFeatureWriter.cpp	Fri Nov 28 15:45:20 2008 +0000
+++ b/rdf/RDFFeatureWriter.cpp	Tue Dec 02 17:17:25 2008 +0000
@@ -221,11 +221,18 @@
     }
     QString timelineURI = m_trackTimelineURIs[trackId];
 
-    stream << "\n<" << url.toEncoded().data() << "> a mo:AudioFile .\n\n"
-           << signalURI << " a mo:Signal ;\n"
-           << "    mo:available_as <" << url.toEncoded().data()
-           << "> ;\n"
-           << "    mo:time [\n"
+    if (trackId != "") {
+        stream << "\n<" << url.toEncoded().data() << "> a mo:AudioFile .\n\n";
+    }
+
+    stream << signalURI << " a mo:Signal ;\n";
+
+    if (trackId != "") {
+        stream << "    mo:available_as <" << url.toEncoded().data()
+               << "> ;\n";
+    }
+
+    stream << "    mo:time [\n"
            << "        a tl:Interval ;\n"
            << "        tl:onTimeLine "
            << timelineURI << "\n    ] .\n\n";
@@ -284,8 +291,10 @@
         m_transformURIs[transform] = transformUri;
     }
 
-    stream << RDFTransformFactory::writeTransformToRDF(transform, transformUri)
-           << endl;
+    if (transform.getIdentifier() != "") {
+        stream << RDFTransformFactory::writeTransformToRDF(transform, transformUri)
+               << endl;
+    }
 
     if (needEventType) {
 
@@ -388,8 +397,10 @@
                    << "S\"^^xsd:duration ;\n    ] ";
         }
 
-        stream << ";\n";
-        stream << "    vamp:computed_by " << m_transformURIs[transform] << " ";
+        if (transform.getIdentifier() != "") {
+            stream << ";\n";
+            stream << "    vamp:computed_by " << m_transformURIs[transform] << " ";
+        }
 
         if (feature.label.length() > 0) {
             stream << ";\n";
--- a/rdf/RDFImporter.cpp	Fri Nov 28 15:45:20 2008 +0000
+++ b/rdf/RDFImporter.cpp	Tue Dec 02 17:17:25 2008 +0000
@@ -563,7 +563,7 @@
     SimpleSPARQLQuery query(s, queryString);
     query.setProgressReporter(reporter);
 
-    cerr << "Query will be: " << queryString.toStdString() << endl;
+//    cerr << "Query will be: " << queryString.toStdString() << endl;
 
     SimpleSPARQLQuery::ResultList results = query.execute();
 
--- a/rdf/rdf.pro	Fri Nov 28 15:45:20 2008 +0000
+++ b/rdf/rdf.pro	Tue Dec 02 17:17:25 2008 +0000
@@ -15,12 +15,14 @@
 # Input
 HEADERS += PluginRDFDescription.h \
            PluginRDFIndexer.h \
+           RDFExporter.h \
            RDFFeatureWriter.h \
            RDFImporter.h \
 	   RDFTransformFactory.h \
            SimpleSPARQLQuery.h
 SOURCES += PluginRDFDescription.cpp \
            PluginRDFIndexer.cpp \
+           RDFExporter.cpp \
            RDFFeatureWriter.cpp \
            RDFImporter.cpp \
            RDFTransformFactory.cpp \