Chris@1554
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@1554
|
2
|
Chris@1554
|
3 /*
|
Chris@1554
|
4 Sonic Visualiser
|
Chris@1554
|
5 An audio file viewer and annotation editor.
|
Chris@1554
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@1554
|
7
|
Chris@1554
|
8 This program is free software; you can redistribute it and/or
|
Chris@1554
|
9 modify it under the terms of the GNU General Public License as
|
Chris@1554
|
10 published by the Free Software Foundation; either version 2 of the
|
Chris@1554
|
11 License, or (at your option) any later version. See the file
|
Chris@1554
|
12 COPYING included with this distribution for more information.
|
Chris@1554
|
13 */
|
Chris@1554
|
14
|
Chris@1554
|
15 #include "Colour3DPlotExporter.h"
|
Chris@1554
|
16
|
Chris@1554
|
17 #include "data/model/EditableDenseThreeDimensionalModel.h"
|
Chris@1554
|
18 #include "data/model/FFTModel.h"
|
Chris@1554
|
19
|
Chris@1554
|
20 #include "VerticalBinLayer.h"
|
Chris@1554
|
21
|
Chris@1556
|
22 Colour3DPlotExporter::Colour3DPlotExporter(Sources sources, Parameters params) :
|
Chris@1556
|
23 m_sources(sources),
|
Chris@1556
|
24 m_params(params)
|
Chris@1556
|
25 {
|
Chris@1556
|
26 SVCERR << "Colour3DPlotExporter::Colour3DPlotExporter: constructed at "
|
Chris@1556
|
27 << this << endl;
|
Chris@1556
|
28 }
|
Chris@1556
|
29
|
Chris@1556
|
30 Colour3DPlotExporter::~Colour3DPlotExporter()
|
Chris@1556
|
31 {
|
Chris@1556
|
32 SVCERR << "Colour3DPlotExporter[" << this << "]::~Colour3DPlotExporter"
|
Chris@1556
|
33 << endl;
|
Chris@1556
|
34 }
|
Chris@1556
|
35
|
Chris@1556
|
36 void
|
Chris@1556
|
37 Colour3DPlotExporter::discardSources()
|
Chris@1556
|
38 {
|
Chris@1556
|
39 SVCERR << "Colour3DPlotExporter[" << this << "]::discardSources"
|
Chris@1556
|
40 << endl;
|
Chris@1556
|
41 QMutexLocker locker(&m_mutex);
|
Chris@1556
|
42 m_sources.verticalBinLayer = nullptr;
|
Chris@1556
|
43 m_sources.source = {};
|
Chris@1556
|
44 m_sources.fft = {};
|
Chris@1556
|
45 m_sources.provider = nullptr;
|
Chris@1556
|
46 }
|
Chris@1556
|
47
|
Chris@1554
|
48 QString
|
Chris@1554
|
49 Colour3DPlotExporter::toDelimitedDataString(QString delimiter,
|
Chris@1554
|
50 DataExportOptions options,
|
Chris@1554
|
51 sv_frame_t startFrame,
|
Chris@1554
|
52 sv_frame_t duration) const
|
Chris@1554
|
53 {
|
Chris@1554
|
54 QMutexLocker locker(&m_mutex);
|
Chris@1554
|
55
|
Chris@1554
|
56 BinDisplay binDisplay = m_params.binDisplay;
|
Chris@1554
|
57
|
Chris@1556
|
58 (void)options; //!!!
|
Chris@1556
|
59
|
Chris@1554
|
60 auto model =
|
Chris@1554
|
61 ModelById::getAs<DenseThreeDimensionalModel>(m_sources.source);
|
Chris@1554
|
62 auto fftModel =
|
Chris@1554
|
63 ModelById::getAs<FFTModel>(m_sources.fft);
|
Chris@1554
|
64
|
Chris@1554
|
65 auto layer = m_sources.verticalBinLayer;
|
Chris@1554
|
66 auto provider = m_sources.provider;
|
Chris@1554
|
67
|
Chris@1554
|
68 if (!model || !layer) {
|
Chris@1554
|
69 SVCERR << "ERROR: Colour3DPlotExporter::toDelimitedDataString: Source model and layer required" << endl;
|
Chris@1554
|
70 return {};
|
Chris@1554
|
71 }
|
Chris@1556
|
72 if ((binDisplay == BinDisplay::PeakFrequencies) && !fftModel) {
|
Chris@1556
|
73 SVCERR << "ERROR: Colour3DPlotExporter::toDelimitedDataString: FFT model required in peak frequencies mode" << endl;
|
Chris@1556
|
74 return {};
|
Chris@1556
|
75 }
|
Chris@1554
|
76
|
Chris@1554
|
77 int minbin = 0;
|
Chris@1554
|
78 int sh = model->getHeight();
|
Chris@1554
|
79 int nbins = sh;
|
Chris@1554
|
80
|
Chris@1554
|
81 //!!! todo: consider what to do about the actual Colour 3D Plot
|
Chris@1554
|
82 //!!! Layer. In the existing application, this is exported full
|
Chris@1554
|
83 //!!! height. If we switch to using this code, we will be
|
Chris@1554
|
84 //!!! exporting only the displayed height. This is backward
|
Chris@1554
|
85 //!!! incompatible, but also not directly interpretable without
|
Chris@1554
|
86 //!!! any guide in the exported file as to what the bin indices
|
Chris@1554
|
87 //!!! are. Perhaps we should have a flag to export full height,
|
Chris@1554
|
88 //!!! and default to using it.
|
Chris@1554
|
89
|
Chris@1554
|
90 //!!! todo: what about the other export types besides
|
Chris@1554
|
91 //!!! delimited-data-string ?
|
Chris@1556
|
92
|
Chris@1556
|
93 //!!! todo: scripted regression tests for layer exports (of all
|
Chris@1556
|
94 //!!! types)
|
Chris@1556
|
95
|
Chris@1556
|
96 //!!! todo: export selected region only (we have the necessaries
|
Chris@1556
|
97 //!!! here, but it needs support higher up)
|
Chris@1556
|
98
|
Chris@1556
|
99 //!!! todo: option to include timestamps for columns
|
Chris@1554
|
100
|
Chris@1554
|
101 if (provider) {
|
Chris@1554
|
102
|
Chris@1554
|
103 minbin = layer->getIBinForY(provider, provider->getPaintHeight());
|
Chris@1554
|
104 if (minbin >= sh) minbin = sh - 1;
|
Chris@1554
|
105 if (minbin < 0) minbin = 0;
|
Chris@1554
|
106
|
Chris@1554
|
107 nbins = layer->getIBinForY(provider, 0) - minbin + 1;
|
Chris@1554
|
108 if (minbin + nbins > sh) nbins = sh - minbin;
|
Chris@1554
|
109 }
|
Chris@1554
|
110
|
Chris@1554
|
111 int w = model->getWidth();
|
Chris@1554
|
112
|
Chris@1554
|
113 QString s;
|
Chris@1554
|
114
|
Chris@1554
|
115 for (int i = 0; i < w; ++i) {
|
Chris@1556
|
116
|
Chris@1554
|
117 sv_frame_t fr = model->getStartFrame() + i * model->getResolution();
|
Chris@1554
|
118 if (fr < startFrame || fr >= startFrame + duration) {
|
Chris@1554
|
119 continue;
|
Chris@1554
|
120 }
|
Chris@1556
|
121
|
Chris@1556
|
122 // Unlike Colour3DPlotRenderer, we don't want to scale or
|
Chris@1556
|
123 // normalise
|
Chris@1556
|
124
|
Chris@1556
|
125 //!!! (should we be handling phase layer type?)
|
Chris@1556
|
126
|
Chris@1556
|
127 auto column = model->getColumn(i);
|
Chris@1556
|
128 column = ColumnOp::Column(column.data() + minbin,
|
Chris@1556
|
129 column.data() + minbin + nbins);
|
Chris@1556
|
130
|
Chris@1556
|
131 //!!! todo: peaks, frequencies (the things we came here for)
|
Chris@1556
|
132
|
Chris@1554
|
133 QStringList list;
|
Chris@1554
|
134
|
Chris@1556
|
135 if (binDisplay == BinDisplay::PeakFrequencies) {
|
Chris@1556
|
136
|
Chris@1556
|
137 FFTModel::PeakSet peaks = fftModel->getPeakFrequencies
|
Chris@1558
|
138 (FFTModel::AllPeaks, i, minbin, minbin + nbins - 1);
|
Chris@1554
|
139
|
Chris@1556
|
140 for (const auto &p: peaks) {
|
Chris@1556
|
141
|
Chris@1556
|
142 int bin = p.first;
|
Chris@1556
|
143 double freq = p.second;
|
Chris@1556
|
144 float mag = column[bin - minbin];
|
Chris@1556
|
145
|
Chris@1556
|
146 list << QString("%1").arg(freq) << QString("%1").arg(mag);
|
Chris@1556
|
147 }
|
Chris@1556
|
148
|
Chris@1556
|
149 } else {
|
Chris@1556
|
150
|
Chris@1556
|
151 if (binDisplay == BinDisplay::PeakBins) {
|
Chris@1556
|
152 column = ColumnOp::peakPick(column);
|
Chris@1556
|
153 }
|
Chris@1556
|
154
|
Chris@1556
|
155 for (auto value: column) {
|
Chris@1556
|
156 list << QString("%1").arg(value);
|
Chris@1556
|
157 }
|
Chris@1556
|
158 }
|
Chris@1556
|
159
|
Chris@1554
|
160 s += list.join(delimiter) + "\n";
|
Chris@1554
|
161 }
|
Chris@1554
|
162
|
Chris@1554
|
163 return s;
|
Chris@1554
|
164
|
Chris@1554
|
165
|
Chris@1554
|
166 //!!! For reference, this is the body of
|
Chris@1554
|
167 //!!! EditableDenseThreeDimensionalModel::toDelimitedDataString
|
Chris@1554
|
168 /*
|
Chris@1554
|
169 QString s;
|
Chris@1554
|
170 for (int i = 0; in_range_for(m_data, i); ++i) {
|
Chris@1554
|
171 sv_frame_t fr = m_startFrame + i * m_resolution;
|
Chris@1554
|
172 if (fr >= startFrame && fr < startFrame + duration) {
|
Chris@1554
|
173 QStringList list;
|
Chris@1554
|
174 for (int j = 0; in_range_for(m_data.at(i), j); ++j) {
|
Chris@1554
|
175 list << QString("%1").arg(m_data.at(i).at(j));
|
Chris@1554
|
176 }
|
Chris@1554
|
177 s += list.join(delimiter) + "\n";
|
Chris@1554
|
178 }
|
Chris@1554
|
179 }
|
Chris@1554
|
180 return s;
|
Chris@1554
|
181 */
|
Chris@1554
|
182 }
|
Chris@1554
|
183
|