EditableDenseThreeDimensionalModel.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
17 
18 #include "base/LogRange.h"
19 
20 #include <QTextStream>
21 #include <QStringList>
22 #include <QMutexLocker>
23 
24 #include <iostream>
25 
26 #include <cmath>
27 #include <cassert>
28 
29 using std::vector;
30 
31 #include "system/System.h"
32 
34  int resolution,
35  int yBinCount,
36  bool notifyOnAdd) :
37  m_startFrame(0),
38  m_sampleRate(sampleRate),
39  m_resolution(resolution),
40  m_yBinCount(yBinCount),
41  m_minimum(0.0),
42  m_maximum(0.0),
43  m_haveExtents(false),
44  m_notifyOnAdd(notifyOnAdd),
45  m_sinceLastNotifyMin(-1),
46  m_sinceLastNotifyMax(-1),
47  m_completion(100)
48 {
49 }
50 
51 bool
53 {
54  return true;
55 }
56 
57 bool
59 {
60  if (completion) *completion = getCompletion();
61  return true;
62 }
63 
66 {
67  return m_sampleRate;
68 }
69 
72 {
73  return m_startFrame;
74 }
75 
76 void
78 {
79  m_startFrame = f;
80 }
81 
84 {
85  return m_resolution * m_data.size() + (m_resolution - 1);
86 }
87 
88 int
90 {
91  return m_resolution;
92 }
93 
94 void
96 {
97  m_resolution = sz;
98 }
99 
100 int
102 {
103  return int(m_data.size());
104 }
105 
106 int
108 {
109  return m_yBinCount;
110 }
111 
112 void
114 {
115  m_yBinCount = sz;
116 }
117 
118 float
120 {
121  return m_minimum;
122 }
123 
124 void
126 {
127  m_minimum = level;
128 }
129 
130 float
132 {
133  return m_maximum;
134 }
135 
136 void
138 {
139  m_maximum = level;
140 }
141 
144 {
145  QMutexLocker locker(&m_mutex);
146  if (!in_range_for(m_data, index)) {
147  return {};
148  }
149  Column c = m_data.at(index);
150  if (int(c.size()) == m_yBinCount) {
151  return c;
152  } else {
153  Column cc(c);
154  cc.resize(m_yBinCount, 0.0);
155  return cc;
156  }
157 }
158 
159 float
161 {
162  QMutexLocker locker(&m_mutex);
163  if (!in_range_for(m_data, index)) {
164  return m_minimum;
165  }
166  const Column &c = m_data.at(index);
167  if (!in_range_for(c, n)) {
168  return m_minimum;
169  }
170  return c.at(n);
171 }
172 
173 void
175  const Column &values)
176 {
177  bool allChange = false;
178  sv_frame_t windowStart = index;
179  windowStart *= m_resolution;
180 
181  {
182  QMutexLocker locker(&m_mutex);
183 
184  while (index >= int(m_data.size())) {
185  m_data.push_back(Column());
186  }
187 
188  for (int i = 0; in_range_for(values, i); ++i) {
189  float value = values[i];
190  if (ISNAN(value) || ISINF(value)) {
191  continue;
192  }
193  if (!m_haveExtents || value < m_minimum) {
194  m_minimum = value;
195  allChange = true;
196  }
197  if (!m_haveExtents || value > m_maximum) {
198  m_maximum = value;
199  allChange = true;
200  }
201  m_haveExtents = true;
202  }
203 
204  m_data[index] = values;
205 
206  if (allChange) {
209  } else {
210  if (m_sinceLastNotifyMin == -1 ||
211  windowStart < m_sinceLastNotifyMin) {
212  m_sinceLastNotifyMin = windowStart;
213  }
214  if (m_sinceLastNotifyMax == -1 ||
215  windowStart > m_sinceLastNotifyMax) {
216  m_sinceLastNotifyMax = windowStart;
217  }
218  }
219  }
220 
221  if (m_notifyOnAdd) {
222  if (allChange) {
223  emit modelChanged(getId());
224  } else {
225  emit modelChangedWithin(getId(),
226  windowStart, windowStart + m_resolution);
227  }
228  } else {
229  if (allChange) {
230  emit modelChanged(getId());
231  }
232  }
233 }
234 
235 QString
237 {
238  if (n >= 0 && (int)m_binNames.size() > n) return m_binNames[n];
239  else return "";
240 }
241 
242 void
244 {
245  while ((int)m_binNames.size() <= n) m_binNames.push_back("");
246  m_binNames[n] = name;
247  emit modelChanged(getId());
248 }
249 
250 void
252 {
253  m_binNames = names;
254  emit modelChanged(getId());
255 }
256 
257 bool
259 {
260  return !m_binValues.empty();
261 }
262 
263 float
265 {
266  if (n < (int)m_binValues.size()) return m_binValues[n];
267  else return 0.f;
268 }
269 
270 void
272 {
273  m_binValues = values;
274 }
275 
276 QString
278 {
279  return m_binValueUnit;
280 }
281 
282 void
284 {
285  m_binValueUnit = unit;
286 }
287 
288 bool
290 {
291  QMutexLocker locker(&m_mutex);
292 
293  vector<double> sample;
294  vector<int> n;
295 
296  for (int i = 0; i < 10; ++i) {
297  int index = i * 10;
298  if (in_range_for(m_data, index)) {
299  const Column &c = m_data.at(index);
300  while (c.size() > sample.size()) {
301  sample.push_back(0.0);
302  n.push_back(0);
303  }
304  for (int j = 0; in_range_for(c, j); ++j) {
305  sample[j] += c.at(j);
306  ++n[j];
307  }
308  }
309  }
310 
311  if (sample.empty()) return false;
312  for (decltype(sample)::size_type j = 0; j < sample.size(); ++j) {
313  if (n[j]) sample[j] /= n[j];
314  }
315 
316  return LogRange::shouldUseLogScale(sample);
317 }
318 
319 void
321 {
322  if (m_completion != completion) {
323  m_completion = completion;
324 
325  if (completion == 100) {
326 
327  m_notifyOnAdd = true; // henceforth
328  emit modelChanged(getId());
329 
330  } else if (!m_notifyOnAdd) {
331 
332  if (update &&
333  m_sinceLastNotifyMin >= 0 &&
334  m_sinceLastNotifyMax >= 0) {
335  emit modelChangedWithin(getId(),
339  } else {
340  emit completionChanged(getId());
341  }
342  } else {
343  emit completionChanged(getId());
344  }
345  }
346 }
347 
348 int
350 {
351  return m_completion;
352 }
353 
354 QVector<QString>
356  const
357 {
358  QVector<QString> sv;
359  for (int i = 0; i < m_yBinCount; ++i) {
360  sv.push_back(QString("Bin%1").arg(i+1));
361  }
362  return sv;
363 }
364 
365 QVector<QVector<QString>>
367  sv_frame_t startFrame,
368  sv_frame_t duration)
369  const
370 {
371  QMutexLocker locker(&m_mutex);
372 
373  QVector<QVector<QString>> rows;
374 
375  for (int i = 0; in_range_for(m_data, i); ++i) {
377  if (fr >= startFrame && fr < startFrame + duration) {
378  QVector<QString> row;
379  for (int j = 0; in_range_for(m_data.at(i), j); ++j) {
380  row.push_back(QString("%1").arg(m_data.at(i).at(j)));
381  }
382  rows.push_back(row);
383  }
384  }
385  return rows;
386 }
387 
388 void
390  QString indent,
391  QString extraAttributes) const
392 {
393  QMutexLocker locker(&m_mutex);
394 
395  // For historical reasons we read and write "resolution" as "windowSize".
396 
397  // Our dataset doesn't have its own export ID, we just use
398  // ours. Actually any model could do that, since datasets aren't
399  // in the same id-space as models when re-read
400 
401  SVDEBUG << "EditableDenseThreeDimensionalModel::toXml" << endl;
402 
404  (out, indent,
405  QString("type=\"dense\" dimensions=\"3\" windowSize=\"%1\" yBinCount=\"%2\" minimum=\"%3\" maximum=\"%4\" dataset=\"%5\" startFrame=\"%6\" %7")
406  .arg(m_resolution)
407  .arg(m_yBinCount)
408  .arg(m_minimum)
409  .arg(m_maximum)
410  .arg(getExportId())
411  .arg(m_startFrame)
412  .arg(extraAttributes));
413 
414  out << indent;
415  out << QString("<dataset id=\"%1\" dimensions=\"3\" separator=\" \">\n")
416  .arg(getExportId());
417 
418  for (int i = 0; in_range_for(m_binNames, i); ++i) {
419  if (m_binNames[i] != "") {
420  out << indent + " ";
421  out << QString("<bin number=\"%1\" name=\"%2\"/>\n")
422  .arg(i).arg(m_binNames[i]);
423  }
424  }
425 
426  for (int i = 0; in_range_for(m_data, i); ++i) {
427  Column c = getColumn(i);
428  out << indent + " ";
429  out << QString("<row n=\"%1\">").arg(i);
430  for (int j = 0; in_range_for(c, j); ++j) {
431  if (j > 0) out << " ";
432  out << c.at(j);
433  }
434  out << QString("</row>\n");
435  out.flush();
436  }
437 
438  out << indent + "</dataset>\n";
439 }
440 
441 
float getMinimumLevel() const override
Return the minimum value of the value in each bin.
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
virtual void setMinimumLevel(float sz)
Set the minimum value of the value in a bin.
void toXml(QTextStream &stream, QString indent="", QString extraAttributes="") const override
Stream this exportable object out to XML on a text stream.
Definition: Model.cpp:204
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
virtual void setBinName(int n, QString)
Set the name of bin n.
QString getBinName(int n) const override
Return the name of bin n.
#define ISNAN
Definition: System.h:103
sv_frame_t getStartFrame() const override
Return the first audio frame spanned by the model.
void setCompletion(int completion, bool update=true)
int getWidth() const override
Return the number of columns.
Id getId() const
Return an id for this object.
Definition: ById.h:193
float getBinValue(int n) const override
Return the value of bin n, if any.
EditableDenseThreeDimensionalModel(sv_samplerate_t sampleRate, int resolution, int height, bool notifyOnAdd=true)
int getCompletion() const override
Return an estimated percentage value showing how far through any background operation used to calcula...
virtual void setBinValueUnit(QString unit)
Set the name of the unit of the values return from getBinValue() if any.
QString getBinValueUnit() const override
Obtain the name of the unit of the values returned from getBinValue(), if any.
float getValueAt(int x, int n) const override
Get a single value, from the n&#39;th bin of the given column.
bool isReady(int *completion=0) const override
Return true if the model has finished loading or calculating all its data, for a model that is capabl...
virtual void setBinNames(std::vector< QString > names)
Set the names of all bins.
virtual void setMaximumLevel(float sz)
Set the maximum value of the value in a bin.
void completionChanged(ModelId myId)
Emitted when some internal processing has advanced a stage, but the model has not changed externally...
static bool shouldUseLogScale(std::vector< double > values)
Estimate whether a set of values would be more properly shown using a logarithmic than a linear scale...
Definition: LogRange.cpp:93
ExportId getExportId() const
Return the numerical export identifier for this object.
sv_frame_t getTrueEndFrame() const override
Return the audio frame at the end of the model.
bool in_range_for(const C &container, T i)
Check whether an integer index is in range for a container, avoiding overflows and signed/unsigned co...
Definition: BaseTypes.h:37
void modelChangedWithin(ModelId myId, sv_frame_t startFrame, sv_frame_t endFrame)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
#define SVDEBUG
Definition: Debug.h:106
bool shouldUseLogValueScale() const override
Return true if the distribution of values in the bins is such as to suggest a log scale (mapping to c...
#define ISINF
Definition: System.h:104
sv_samplerate_t getSampleRate() const override
Return the frame rate in frames per second.
QVector< QString > getStringExportHeaders(DataExportOptions options) const override
Return a label for each column that would be written by toStringExportRows.
virtual void setStartFrame(sv_frame_t)
Set the frame offset of the first column.
QVector< QVector< QString > > toStringExportRows(DataExportOptions options, sv_frame_t startFrame, sv_frame_t duration) const override
Emit events starting within the given range as string rows ready for conversion to an e...
virtual void setResolution(int sz)
Set the number of sample frames covered by each set of bins.
virtual void setBinValues(std::vector< float > values)
Set the values of all bins (separate from their labels).
virtual void setHeight(int sz)
Set the number of bins in each column.
void toXml(QTextStream &out, QString indent="", QString extraAttributes="") const override
Stream this exportable object out to XML on a text stream.
bool isOK() const override
Return true if the model was constructed successfully.
float getMaximumLevel() const override
Return the maximum value of the value in each bin.
virtual void setColumn(int x, const Column &values)
Set the entire set of bin values at the given column.
void modelChanged(ModelId myId)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
bool hasBinValues() const override
Return true if the bins have values as well as names.
int getHeight() const override
Return the number of bins in each column.
Column getColumn(int x) const override
Get the set of bin values at the given column.
int getResolution() const override
Return the number of sample frames covered by each set of bins.
int DataExportOptions