changeset 1554:a0b2f3b4dd2f spectrogram-export

Start work on spectrogram export code
author Chris Cannam
date Mon, 06 Jan 2020 14:46:25 +0000
parents 76e4302a3fc2
children 745be36202aa
files files.pri layer/Colour3DPlotExporter.cpp layer/Colour3DPlotExporter.h layer/Layer.h layer/SpectrogramLayer.h view/Overview.cpp view/Overview.h
diffstat 7 files changed, 205 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/files.pri	Fri Nov 22 14:12:50 2019 +0000
+++ b/files.pri	Mon Jan 06 14:46:25 2020 +0000
@@ -1,5 +1,6 @@
 
 SVGUI_HEADERS += \
+           layer/Colour3DPlotExporter.h \
            layer/Colour3DPlotLayer.h \
            layer/Colour3DPlotRenderer.h \
            layer/ColourDatabase.h \
@@ -95,6 +96,7 @@
            widgets/WindowTypeSelector.h
 
 SVGUI_SOURCES += \
+           layer/Colour3DPlotExporter.cpp \
            layer/Colour3DPlotLayer.cpp \
            layer/Colour3DPlotRenderer.cpp \
            layer/ColourDatabase.cpp \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/Colour3DPlotExporter.cpp	Mon Jan 06 14:46:25 2020 +0000
@@ -0,0 +1,107 @@
+/* -*- 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.
+*/
+
+#include "Colour3DPlotExporter.h"
+
+#include "data/model/EditableDenseThreeDimensionalModel.h"
+#include "data/model/FFTModel.h"
+
+#include "VerticalBinLayer.h"
+
+QString
+Colour3DPlotExporter::toDelimitedDataString(QString delimiter,
+                                            DataExportOptions options,
+                                            sv_frame_t startFrame,
+                                            sv_frame_t duration) const
+{
+    QMutexLocker locker(&m_mutex);
+
+    BinDisplay binDisplay = m_params.binDisplay;
+
+    auto model =
+        ModelById::getAs<DenseThreeDimensionalModel>(m_sources.source);
+    auto fftModel =
+        ModelById::getAs<FFTModel>(m_sources.fft);
+
+    auto layer = m_sources.verticalBinLayer;
+    auto provider = m_sources.provider;
+
+    if (!model || !layer) {
+        SVCERR << "ERROR: Colour3DPlotExporter::toDelimitedDataString: Source model and layer required" << endl;
+        return {};
+    }
+
+    int minbin = 0;
+    int sh = model->getHeight();
+    int nbins = sh;
+
+    //!!! todo: consider what to do about the actual Colour 3D Plot
+    //!!! Layer. In the existing application, this is exported full
+    //!!! height. If we switch to using this code, we will be
+    //!!! exporting only the displayed height. This is backward
+    //!!! incompatible, but also not directly interpretable without
+    //!!! any guide in the exported file as to what the bin indices
+    //!!! are. Perhaps we should have a flag to export full height,
+    //!!! and default to using it.
+
+    //!!! todo: what about the other export types besides
+    //!!! delimited-data-string ?
+    
+    if (provider) {
+
+        minbin = layer->getIBinForY(provider, provider->getPaintHeight());
+        if (minbin >= sh) minbin = sh - 1;
+        if (minbin < 0) minbin = 0;
+    
+        nbins = layer->getIBinForY(provider, 0) - minbin + 1;
+        if (minbin + nbins > sh) nbins = sh - minbin;
+    }
+
+    int w = model->getWidth();
+
+    QString s;
+    
+    for (int i = 0; i < w; ++i) {
+        sv_frame_t fr = model->getStartFrame() + i * model->getResolution();
+        if (fr < startFrame || fr >= startFrame + duration) {
+            continue;
+        }
+        QStringList list;
+
+        //...
+
+        s += list.join(delimiter) + "\n";
+    }
+
+    return s;
+    
+
+    //!!! For reference, this is the body of
+    //!!! EditableDenseThreeDimensionalModel::toDelimitedDataString
+    /*
+    QString s;
+    for (int i = 0; in_range_for(m_data, i); ++i) {
+        sv_frame_t fr = m_startFrame + i * m_resolution;
+        if (fr >= startFrame && fr < startFrame + duration) {
+            QStringList list;
+            for (int j = 0; in_range_for(m_data.at(i), j); ++j) {
+                list << QString("%1").arg(m_data.at(i).at(j));
+            }
+            s += list.join(delimiter) + "\n";
+        }
+    }
+    return s;
+    */    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/layer/Colour3DPlotExporter.h	Mon Jan 06 14:46:25 2020 +0000
@@ -0,0 +1,63 @@
+/* -*- 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 COLOUR_3D_PLOT_EXPORTER_H
+#define COLOUR_3D_PLOT_EXPORTER_H
+
+#include "Colour3DPlotRenderer.h"
+
+class Colour3DPlotExporter : public Model
+{
+    Q_OBJECT
+    
+public:
+    struct Sources {
+        // These must all outlive this class, or else discardSources()
+        // must be called
+        const VerticalBinLayer *verticalBinLayer; // always
+        ModelId source; // always; a DenseThreeDimensionalModel
+        ModelId fft; // optionally; an FFTModel; used for phase/peak-freq modes
+        const LayerGeometryProvider *provider; // optionally
+    };
+
+    struct Parameters {
+        Parameters() :
+            binDisplay(BinDisplay::AllBins) { }
+
+        /** Selection of bins to include in the export. */
+        BinDisplay binDisplay;
+    };
+    
+    Colour3DPlotExporter(Sources sources, Parameters parameters) :
+        m_sources(sources),
+        m_params(parameters)
+    { }
+
+    void discardSources() {
+        QMutexLocker locker(&m_mutex);
+        m_sources.verticalBinLayer = nullptr;
+        m_sources.source = {};
+        m_sources.fft = {};
+        m_sources.provider = nullptr;
+    }
+
+    QString toDelimitedDataString(QString, DataExportOptions,
+                                  sv_frame_t, sv_frame_t) const override;
+
+private:
+    Sources m_sources;
+    Parameters m_params;
+};
+
+#endif
--- a/layer/Layer.h	Fri Nov 22 14:12:50 2019 +0000
+++ b/layer/Layer.h	Mon Jan 06 14:46:25 2020 +0000
@@ -71,6 +71,30 @@
      * model here, return None.
      */
     ModelId getSourceModel() const;
+
+    /**
+     * Return the ID of a model representing the contents of this
+     * layer in a form suitable for export to a tabular file format
+     * such as CSV.
+     *
+     * In most cases this will be the same as returned by
+     * getModel(). The exceptions are those layers such as
+     * SpectrogramLayer, that are "only" alternative views of
+     * time-domain sample data. For such layers, getModel() will
+     * return the backing time-domain data, for example as a
+     * ReadOnlyWaveFileModel; but getExportModel() will return a
+     * model, possibly "local to" the layer, which adapts this into
+     * the form shown in the layer for a given view so that the export
+     * matches the layer's visible contents.
+     *
+     * Because this is supposed to match the contents of the view
+     * rather than the backing model, it's necessary to pass in a view
+     * (or LayerGeometryProvider) so that the layer can retrieve its
+     * vertical extents for export.
+     */
+    virtual ModelId getExportModel(LayerGeometryProvider *) const {
+        return getModel();
+    }
     
     /**
      * Return a zoom constraint object defining the supported zoom
--- a/layer/SpectrogramLayer.h	Fri Nov 22 14:12:50 2019 +0000
+++ b/layer/SpectrogramLayer.h	Mon Jan 06 14:46:25 2020 +0000
@@ -65,6 +65,9 @@
     
     const ZoomConstraint *getZoomConstraint() const override { return this; }
     ModelId getModel() const override { return m_model; }
+
+    ModelId getExportModel(LayerGeometryProvider *) const override;
+
     void paint(LayerGeometryProvider *v, QPainter &paint, QRect rect) const override;
     void setSynchronousPainting(bool synchronous) override;
 
@@ -72,7 +75,7 @@
     void paintVerticalScale(LayerGeometryProvider *v, bool detailed, QPainter &paint, QRect rect) const override;
 
     bool getCrosshairExtents(LayerGeometryProvider *, QPainter &, QPoint cursorPos,
-                                     std::vector<QRect> &extents) const override;
+                             std::vector<QRect> &extents) const override;
     void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const override;
 
     QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override;
--- a/view/Overview.cpp	Fri Nov 22 14:12:50 2019 +0000
+++ b/view/Overview.cpp	Mon Jan 06 14:46:25 2020 +0000
@@ -34,7 +34,7 @@
     m_followPan = false;
     m_followZoom = false;
     setPlaybackFollow(PlaybackIgnore);
-    m_modelTestTime.start();
+    m_modelTestTimer.start();
 
     bool light = hasLightBackground();
     if (light) m_boxColour = Qt::darkGray;
@@ -57,7 +57,7 @@
     }
 
     if (!zoomChanged) {
-        if (m_modelTestTime.elapsed() < 1000) {
+        if (m_modelTestTimer.elapsed() < 1000) {
             for (LayerList::const_iterator i = m_layerStack.begin();
                  i != m_layerStack.end(); ++i) {
                 auto model = ModelById::get((*i)->getModel());
@@ -66,7 +66,7 @@
                 }
             }
         } else {
-            m_modelTestTime.restart();
+            m_modelTestTimer.restart();
         }
     }
 
--- a/view/Overview.h	Fri Nov 22 14:12:50 2019 +0000
+++ b/view/Overview.h	Mon Jan 06 14:46:25 2020 +0000
@@ -19,7 +19,7 @@
 #include "View.h"
 
 #include <QPoint>
-#include <QTime>
+#include <QElapsedTimer>
 
 class QWidget;
 class QPaintEvent;
@@ -68,7 +68,7 @@
     QPoint m_mousePos;
     bool m_clickedInRange;
     sv_frame_t m_dragCentreFrame;
-    QTime m_modelTestTime;
+    QElapsedTimer m_modelTestTimer;
     QColor m_boxColour;
     
     typedef std::set<View *> ViewSet;