# HG changeset patch # User Chris Cannam # Date 1578321985 0 # Node ID a0b2f3b4dd2f6d07a4ce8b0ea3a89fc8e98d85a5 # Parent 76e4302a3fc2e6d822113265cd3876c79f75b896 Start work on spectrogram export code diff -r 76e4302a3fc2 -r a0b2f3b4dd2f files.pri --- 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 \ diff -r 76e4302a3fc2 -r a0b2f3b4dd2f layer/Colour3DPlotExporter.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(m_sources.source); + auto fftModel = + ModelById::getAs(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; + */ +} + diff -r 76e4302a3fc2 -r a0b2f3b4dd2f layer/Colour3DPlotExporter.h --- /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 diff -r 76e4302a3fc2 -r a0b2f3b4dd2f layer/Layer.h --- 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 diff -r 76e4302a3fc2 -r a0b2f3b4dd2f layer/SpectrogramLayer.h --- 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 &extents) const override; + std::vector &extents) const override; void paintCrosshairs(LayerGeometryProvider *, QPainter &, QPoint) const override; QString getFeatureDescription(LayerGeometryProvider *v, QPoint &) const override; diff -r 76e4302a3fc2 -r a0b2f3b4dd2f view/Overview.cpp --- 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(); } } diff -r 76e4302a3fc2 -r a0b2f3b4dd2f view/Overview.h --- 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 -#include +#include 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 ViewSet;