FFTModel.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.
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 
16 #include "FFTModel.h"
17 #include "DenseTimeValueModel.h"
18 
19 #include "base/Profiler.h"
20 #include "base/Pitch.h"
21 #include "base/HitCount.h"
22 #include "base/Debug.h"
23 #include "base/MovingMedian.h"
24 
25 #include <algorithm>
26 
27 #include <cassert>
28 #include <deque>
29 
30 using namespace std;
31 
32 static HitCount inSmallCache("FFTModel: Small FFT cache");
33 static HitCount inSourceCache("FFTModel: Source data cache");
34 
36  int channel,
37  WindowType windowType,
38  int windowSize,
39  int windowIncrement,
40  int fftSize) :
41  m_model(modelId),
42  m_sampleRate(0),
43  m_channel(channel),
44  m_windowType(windowType),
45  m_windowSize(windowSize),
46  m_windowIncrement(windowIncrement),
47  m_fftSize(fftSize),
48  m_windower(windowType, windowSize),
49  m_fft(fftSize),
50  m_maximumFrequency(0.0),
51  m_cacheWriteIndex(0),
52  m_cacheSize(3)
53 {
54  clearCaches();
55 
56  if (m_windowSize > m_fftSize) {
57  SVCERR << "ERROR: FFTModel::FFTModel: window size (" << m_windowSize
58  << ") may not exceed FFT size (" << m_fftSize << ")" << endl;
59  throw invalid_argument("FFTModel window size may not exceed FFT size");
60  }
61 
62  m_fft.initFloat();
63 
64  auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
65  if (model) {
66  m_sampleRate = model->getSampleRate();
67 
68  connect(model.get(), SIGNAL(modelChanged(ModelId)),
69  this, SIGNAL(modelChanged(ModelId)));
70  connect(model.get(), SIGNAL(modelChangedWithin(ModelId, sv_frame_t, sv_frame_t)),
72  } else {
73  m_error = QString("Model #%1 is not available").arg(m_model.untyped);
74  }
75 }
76 
78 {
79 }
80 
81 void
83 {
84  m_cached.clear();
85  while (m_cached.size() < m_cacheSize) {
86  m_cached.push_back({ -1, complexvec_t(m_fftSize / 2 + 1) });
87  }
89  m_savedData.range = { 0, 0 };
90 }
91 
92 bool
94 {
95  auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
96  if (!model) {
97  m_error = QString("Model #%1 is not available").arg(m_model.untyped);
98  return false;
99  }
100  if (!model->isOK()) {
101  m_error = QString("Model #%1 is not OK").arg(m_model.untyped);
102  return false;
103  }
104  return true;
105 }
106 
107 int
109 {
110  int c = 100;
111  auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
112  if (model) {
113  if (model->isReady(&c)) return 100;
114  }
115  return c;
116 }
117 
118 void
120 {
121  m_maximumFrequency = freq;
122  clearCaches();
123 }
124 
125 int
127 {
128  auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
129  if (!model) return 0;
130  return int((model->getEndFrame() - model->getStartFrame())
131  / m_windowIncrement) + 1;
132 }
133 
134 int
136 {
137  int height = m_fftSize / 2 + 1;
138  if (m_maximumFrequency != 0.0) {
139  int maxBin = int(ceil(m_maximumFrequency * m_fftSize) / m_sampleRate);
140  if (maxBin >= 0 && maxBin < height) {
141  return maxBin + 1;
142  }
143  }
144  return height;
145 }
146 
147 QString
149 {
150  return tr("%1 Hz").arg(getBinValue(n));
151 }
152 
153 float
155 {
156  return float((m_sampleRate * n) / m_fftSize);
157 }
158 
161 {
162  auto cplx = getFFTColumn(x);
163  Column col;
164  col.reserve(cplx.size());
165  for (auto c: cplx) col.push_back(abs(c));
166  return col;
167 }
168 
171 {
172  auto cplx = getFFTColumn(x);
173  Column col;
174  col.reserve(cplx.size());
175  for (auto c: cplx) {
176  col.push_back(arg(c));
177  }
178  return col;
179 }
180 
181 float
182 FFTModel::getMagnitudeAt(int x, int y) const
183 {
184  if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
185  return 0.f;
186  }
187  auto col = getFFTColumn(x);
188  return abs(col[y]);
189 }
190 
191 float
193 {
194  Column col(getColumn(x));
195  float max = 0.f;
196  int n = int(col.size());
197  for (int i = 0; i < n; ++i) {
198  if (col[i] > max) max = col[i];
199  }
200  return max;
201 }
202 
203 float
204 FFTModel::getPhaseAt(int x, int y) const
205 {
206  if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) return 0.f;
207  return arg(getFFTColumn(x)[y]);
208 }
209 
210 void
211 FFTModel::getValuesAt(int x, int y, float &re, float &im) const
212 {
213  if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
214  re = 0.f;
215  im = 0.f;
216  return;
217  }
218  auto col = getFFTColumn(x);
219  re = col[y].real();
220  im = col[y].imag();
221 }
222 
223 bool
224 FFTModel::getMagnitudesAt(int x, float *values, int minbin, int count) const
225 {
226  if (count == 0) {
227  count = getHeight() - minbin;
228  }
229  auto col = getFFTColumn(x);
230  for (int i = 0; i < count; ++i) {
231  values[i] = abs(col[minbin + i]);
232  }
233  return true;
234 }
235 
236 bool
237 FFTModel::getPhasesAt(int x, float *values, int minbin, int count) const
238 {
239  if (count == 0) count = getHeight();
240  auto col = getFFTColumn(x);
241  for (int i = 0; i < count; ++i) {
242  values[i] = arg(col[minbin + i]);
243  }
244  return true;
245 }
246 
247 bool
248 FFTModel::getValuesAt(int x, float *reals, float *imags, int minbin, int count) const
249 {
250  if (count == 0) count = getHeight();
251  auto col = getFFTColumn(x);
252  for (int i = 0; i < count; ++i) {
253  reals[i] = col[minbin + i].real();
254  }
255  for (int i = 0; i < count; ++i) {
256  imags[i] = col[minbin + i].imag();
257  }
258  return true;
259 }
260 
262 FFTModel::getSourceSamples(int column) const
263 {
264  // m_fftSize may be greater than m_windowSize, but not the reverse
265 
266 // cerr << "getSourceSamples(" << column << ")" << endl;
267 
268  auto range = getSourceSampleRange(column);
269  auto data = getSourceData(range);
270 
271  int off = (m_fftSize - m_windowSize) / 2;
272 
273  if (off == 0) {
274  return data;
275  } else {
276  vector<float> pad(off, 0.f);
277  floatvec_t padded;
278  padded.reserve(m_fftSize);
279  padded.insert(padded.end(), pad.begin(), pad.end());
280  padded.insert(padded.end(), data.begin(), data.end());
281  padded.insert(padded.end(), pad.begin(), pad.end());
282  return padded;
283  }
284 }
285 
287 FFTModel::getSourceData(pair<sv_frame_t, sv_frame_t> range) const
288 {
289 // cerr << "getSourceData(" << range.first << "," << range.second
290 // << "): saved range is (" << m_savedData.range.first
291 // << "," << m_savedData.range.second << ")" << endl;
292 
293  if (m_savedData.range == range) {
294  inSourceCache.hit();
295  return m_savedData.data;
296  }
297 
298  Profiler profiler("FFTModel::getSourceData (cache miss)");
299 
300  if (range.first < m_savedData.range.second &&
301  range.first >= m_savedData.range.first &&
302  range.second > m_savedData.range.second) {
303 
305 
306  sv_frame_t discard = range.first - m_savedData.range.first;
307 
308  floatvec_t data;
309  data.reserve(range.second - range.first);
310 
311  data.insert(data.end(),
312  m_savedData.data.begin() + discard,
313  m_savedData.data.end());
314 
316  ({ m_savedData.range.second, range.second });
317 
318  data.insert(data.end(), rest.begin(), rest.end());
319 
320  m_savedData = { range, data };
321  return data;
322 
323  } else {
324 
326 
327  auto data = getSourceDataUncached(range);
328  m_savedData = { range, data };
329  return data;
330  }
331 }
332 
334 FFTModel::getSourceDataUncached(pair<sv_frame_t, sv_frame_t> range) const
335 {
336  Profiler profiler("FFTModel::getSourceDataUncached");
337 
338  auto model = ModelById::getAs<DenseTimeValueModel>(m_model);
339  if (!model) return {};
340 
341  decltype(range.first) pfx = 0;
342  if (range.first < 0) {
343  pfx = -range.first;
344  range = { 0, range.second };
345  }
346 
347  auto data = model->getData(m_channel,
348  range.first,
349  range.second - range.first);
350 /*
351  if (data.empty()) {
352  SVDEBUG << "NOTE: empty source data for range (" << range.first << ","
353  << range.second << ") (model end frame "
354  << model->getEndFrame() << ")" << endl;
355  }
356 */
357 
358  // don't return a partial frame
359  data.resize(range.second - range.first, 0.f);
360 
361  if (pfx > 0) {
362  vector<float> pad(pfx, 0.f);
363  data.insert(data.begin(), pad.begin(), pad.end());
364  }
365 
366  if (m_channel == -1) {
367  int channels = model->getChannelCount();
368  if (channels > 1) {
369  int n = int(data.size());
370  float factor = 1.f / float(channels);
371  // use mean instead of sum for fft model input
372  for (int i = 0; i < n; ++i) {
373  data[i] *= factor;
374  }
375  }
376  }
377 
378  return data;
379 }
380 
381 const complexvec_t &
383 {
384  // The small cache (i.e. the m_cached deque) is for cases where
385  // values are looked up individually, and for e.g. peak-frequency
386  // spectrograms where values from two consecutive columns are
387  // needed at once. This cache gets essentially no hits when
388  // scrolling through a magnitude spectrogram, but 95%+ hits with a
389  // peak-frequency spectrogram or spectrum.
390  for (const auto &incache : m_cached) {
391  if (incache.n == n) {
392  inSmallCache.hit();
393  return incache.col;
394  }
395  }
396  inSmallCache.miss();
397 
398  Profiler profiler("FFTModel::getFFTColumn (cache miss)");
399 
400  auto samples = getSourceSamples(n);
401  m_windower.cut(samples.data() + (m_fftSize - m_windowSize) / 2);
402  breakfastquay::v_fftshift(samples.data(), m_fftSize);
403 
404  complexvec_t &col = m_cached[m_cacheWriteIndex].col;
405 
406  // expand to large enough for fft destination, if truncated previously
407  col.resize(m_fftSize / 2 + 1);
408 
409  m_fft.forwardInterleaved(samples.data(),
410  reinterpret_cast<float *>(col.data()));
411 
412  // keep only the number of elements we need - so that we can
413  // return a const ref without having to resize on a cache hit
414  col.resize(getHeight());
415 
416  m_cached[m_cacheWriteIndex].n = n;
417 
419 
420  return col;
421 }
422 
423 bool
424 FFTModel::estimateStableFrequency(int x, int y, double &frequency)
425 {
426  if (!isOK()) return false;
427 
428  frequency = double(y * getSampleRate()) / m_fftSize;
429 
430  if (x+1 >= getWidth()) return false;
431 
432  // At frequency f, a phase shift of 2pi (one cycle) happens in 1/f sec.
433  // At hopsize h and sample rate sr, one hop happens in h/sr sec.
434  // At window size w, for bin b, f is b*sr/w.
435  // thus 2pi phase shift happens in w/(b*sr) sec.
436  // We need to know what phase shift we expect from h/sr sec.
437  // -> 2pi * ((h/sr) / (w/(b*sr)))
438  // = 2pi * ((h * b * sr) / (w * sr))
439  // = 2pi * (h * b) / w.
440 
441  double oldPhase = getPhaseAt(x, y);
442  double newPhase = getPhaseAt(x+1, y);
443 
444  int incr = getResolution();
445 
446  double expectedPhase = oldPhase + (2.0 * M_PI * y * incr) / m_fftSize;
447 
448  double phaseError = princarg(newPhase - expectedPhase);
449 
450  // The new frequency estimate based on the phase error resulting
451  // from assuming the "native" frequency of this bin
452 
453  frequency =
454  (getSampleRate() * (expectedPhase + phaseError - oldPhase)) /
455  (2.0 * M_PI * incr);
456 
457  return true;
458 }
459 
461 FFTModel::getPeaks(PeakPickType type, int x, int ymin, int ymax) const
462 {
463  Profiler profiler("FFTModel::getPeaks");
464 
466  if (!isOK()) return peaks;
467 
468  if (ymax == 0 || ymax > getHeight() - 1) {
469  ymax = getHeight() - 1;
470  }
471 
472  if (type == AllPeaks) {
473  int minbin = ymin;
474  if (minbin > 0) minbin = minbin - 1;
475  int maxbin = ymax;
476  if (maxbin < getHeight() - 1) maxbin = maxbin + 1;
477  const int n = maxbin - minbin + 1;
478  float *values = new float[n];
479  getMagnitudesAt(x, values, minbin, maxbin - minbin + 1);
480  for (int bin = ymin; bin <= ymax; ++bin) {
481  if (bin == minbin || bin == maxbin) continue;
482  if (values[bin - minbin] > values[bin - minbin - 1] &&
483  values[bin - minbin] > values[bin - minbin + 1]) {
484  peaks.insert(bin);
485  }
486  }
487  delete[] values;
488  return peaks;
489  }
490 
491  Column values = getColumn(x);
492  int nv = int(values.size());
493 
494  float mean = 0.f;
495  for (int i = 0; i < nv; ++i) mean += values[i];
496  if (nv > 0) mean = mean / float(values.size());
497 
498  // For peak picking we use a moving median window, picking the
499  // highest value within each continuous region of values that
500  // exceed the median. For pitch adaptivity, we adjust the window
501  // size to a roughly constant pitch range (about four tones).
502 
503  sv_samplerate_t sampleRate = getSampleRate();
504 
505  vector<int> inrange;
506  double dist = 0.5;
507 
508  int medianWinSize = getPeakPickWindowSize(type, sampleRate, ymin, dist);
509  int halfWin = medianWinSize/2;
510 
511  MovingMedian<float> window(medianWinSize);
512 
513  int binmin;
514  if (ymin > halfWin) binmin = ymin - halfWin;
515  else binmin = 0;
516 
517  int binmax;
518  if (ymax + halfWin < nv) binmax = ymax + halfWin;
519  else binmax = nv - 1;
520 
521  int prevcentre = 0;
522 
523  for (int bin = binmin; bin <= binmax; ++bin) {
524 
525  float value = values[bin];
526 
527  // so-called median will actually be the dist*100'th percentile
528  medianWinSize = getPeakPickWindowSize(type, sampleRate, bin, dist);
529  halfWin = medianWinSize/2;
530 
531  int actualSize = std::min(medianWinSize, bin - binmin + 1);
532  window.resize(actualSize);
533  window.setPercentile(dist * 100.0);
534  window.push(value);
535 
536  if (type == MajorPitchAdaptivePeaks) {
537  if (ymax + halfWin < nv) binmax = ymax + halfWin;
538  else binmax = nv - 1;
539  }
540 
541  float median = window.get();
542 
543  int centrebin = 0;
544  if (bin > actualSize/2) centrebin = bin - actualSize/2;
545 
546  while (centrebin > prevcentre || bin == binmin) {
547 
548  if (centrebin > prevcentre) ++prevcentre;
549 
550  float centre = values[prevcentre];
551 
552  if (centre > median) {
553  inrange.push_back(centrebin);
554  }
555 
556  if (centre <= median || centrebin+1 == nv) {
557  if (!inrange.empty()) {
558  int peakbin = 0;
559  float peakval = 0.f;
560  for (int i = 0; i < (int)inrange.size(); ++i) {
561  if (i == 0 || values[inrange[i]] > peakval) {
562  peakval = values[inrange[i]];
563  peakbin = inrange[i];
564  }
565  }
566  inrange.clear();
567  if (peakbin >= ymin && peakbin <= ymax) {
568  peaks.insert(peakbin);
569  }
570  }
571  }
572 
573  if (bin == binmin) break;
574  }
575  }
576 
577  return peaks;
578 }
579 
580 int
582  int bin, double &dist) const
583 {
584  dist = 0.5; // dist is percentile / 100.0
585  if (type == MajorPeaks) return 10;
586  if (bin == 0) return 3;
587 
588  double binfreq = (sampleRate * bin) / m_fftSize;
589  double hifreq = Pitch::getFrequencyForPitch(73, 0, binfreq);
590 
591  int hibin = int(lrint((hifreq * m_fftSize) / sampleRate));
592  int medianWinSize = hibin - bin;
593 
594  if (medianWinSize < 3) {
595  medianWinSize = 3;
596  }
597 
598  // We want to avoid the median window size changing too often, as
599  // it requires a reallocation. So snap to a nearby round number.
600 
601  if (medianWinSize > 20) {
602  medianWinSize = (1 + medianWinSize / 10) * 10;
603  }
604  if (medianWinSize > 200) {
605  medianWinSize = (1 + medianWinSize / 100) * 100;
606  }
607  if (medianWinSize > 2000) {
608  medianWinSize = (1 + medianWinSize / 1000) * 1000;
609  }
610  if (medianWinSize > 20000) {
611  medianWinSize = 20000;
612  }
613 
614  if (medianWinSize < 100) {
615  dist = 1.0 - (4.0 / medianWinSize);
616  } else {
617  dist = 1.0 - (8.0 / medianWinSize);
618  }
619  if (dist < 0.5) dist = 0.5;
620 
621  return medianWinSize;
622 }
623 
626  int ymin, int ymax) const
627 {
628  Profiler profiler("FFTModel::getPeakFrequencies");
629 
630  PeakSet peaks;
631  if (!isOK()) return peaks;
632  PeakLocationSet locations = getPeaks(type, x, ymin, ymax);
633 
634  sv_samplerate_t sampleRate = getSampleRate();
635  int incr = getResolution();
636 
637  // This duplicates some of the work of estimateStableFrequency to
638  // allow us to retrieve the phases in two separate vertical
639  // columns, instead of jumping back and forth between columns x and
640  // x+1, which may be significantly slower if re-seeking is needed
641 
642  vector<float> phases;
643  for (PeakLocationSet::iterator i = locations.begin();
644  i != locations.end(); ++i) {
645  phases.push_back(getPhaseAt(x, *i));
646  }
647 
648  int phaseIndex = 0;
649  for (PeakLocationSet::iterator i = locations.begin();
650  i != locations.end(); ++i) {
651  double oldPhase = phases[phaseIndex];
652  double newPhase = getPhaseAt(x+1, *i);
653  double expectedPhase = oldPhase + (2.0 * M_PI * *i * incr) / m_fftSize;
654  double phaseError = princarg(newPhase - expectedPhase);
655  double frequency =
656  (sampleRate * (expectedPhase + phaseError - oldPhase))
657  / (2 * M_PI * incr);
658  peaks[*i] = frequency;
659  ++phaseIndex;
660  }
661 
662  return peaks;
663 }
664 
Column getPhases(int x) const
Definition: FFTModel.cpp:170
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
sv_samplerate_t getSampleRate() const override
Return the frame rate in frames per second.
Definition: FFTModel.h:78
void clearCaches()
Definition: FFTModel.cpp:82
void resize(int target)
Definition: MovingMedian.h:90
bool isOK() const override
Return true if the model was constructed successfully.
Definition: FFTModel.cpp:93
static HitCount inSmallCache("FFTModel: Small FFT cache")
size_t m_cacheWriteIndex
Definition: FFTModel.h:212
static double getFrequencyForPitch(int midiPitch, double centsOffset=0, double concertA=0.0)
Return the frequency at the given MIDI pitch plus centsOffset cents (1/100ths of a semitone)...
Definition: Pitch.cpp:23
void setMaximumFrequency(double freq)
Definition: FFTModel.cpp:119
static HitCount inSourceCache("FFTModel: Source data cache")
#define M_PI
Definition: System.h:187
std::pair< sv_frame_t, sv_frame_t > getSourceSampleRange(int column) const
Definition: FFTModel.h:187
void getValuesAt(int x, int y, float &real, float &imaginary) const
Definition: FFTModel.cpp:211
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
float getMagnitudeAt(int x, int y) const
!! review which of these are ever actually called
Definition: FFTModel.cpp:182
int m_windowIncrement
Definition: FFTModel.h:177
floatvec_t getSourceData(std::pair< sv_frame_t, sv_frame_t >) const
Definition: FFTModel.cpp:287
int getResolution() const override
Return the number of sample frames covered by each column of bins.
Definition: FFTModel.h:81
void cut(T *const BQ_R__ block) const
Definition: Window.h:70
virtual bool estimateStableFrequency(int x, int y, double &frequency)
Calculate an estimated frequency for a stable signal in this bin, using phase unwrapping.
Definition: FFTModel.cpp:424
int untyped
Definition: ById.h:117
virtual PeakLocationSet getPeaks(PeakPickType type, int x, int ymin=0, int ymax=0) const
Return locations of peak bins in the range [ymin,ymax].
Definition: FFTModel.cpp:461
breakfastquay::FFT m_fft
Definition: FFTModel.h:180
const complexvec_t & getFFTColumn(int column) const
Definition: FFTModel.cpp:382
Any bin exceeding its immediate neighbours.
Definition: FFTModel.h:146
WindowType
Definition: Window.h:30
double m_maximumFrequency
Definition: FFTModel.h:181
Obtain the median (or other percentile) of a moving window across a time series.
Definition: MovingMedian.h:41
std::vector< float, breakfastquay::StlAllocator< float > > floatvec_t
Definition: BaseTypes.h:53
void partial()
Definition: HitCount.h:60
PeakPickType
Definition: FFTModel.h:143
bool getMagnitudesAt(int x, float *values, int minbin=0, int count=0) const
Definition: FFTModel.cpp:224
Profile class for counting cache hits and the like.
Definition: HitCount.h:26
double princarg(double a)
Definition: System.cpp:340
Window< float > m_windower
Definition: FFTModel.h:179
int getCompletion() const override
Return an estimated percentage value showing how far through any background operation used to calcula...
Definition: FFTModel.cpp:108
std::pair< sv_frame_t, sv_frame_t > range
Definition: FFTModel.h:202
virtual PeakSet getPeakFrequencies(PeakPickType type, int x, int ymin=0, int ymax=0) const
Return locations and estimated stable frequencies of peak bins.
Definition: FFTModel.cpp:625
QString getBinName(int n) const override
Get the name of a given bin (i.e.
Definition: FFTModel.cpp:148
QString m_error
Definition: FFTModel.h:182
size_t m_cacheSize
Definition: FFTModel.h:213
std::map< int, double > PeakSet
Definition: FFTModel.h:151
T get() const
Definition: MovingMedian.h:77
void setPercentile(double p)
Definition: MovingMedian.h:61
sv_samplerate_t m_sampleRate
Definition: FFTModel.h:173
float getMaximumMagnitudeAt(int x) const
Definition: FFTModel.cpp:192
void push(T value)
Definition: MovingMedian.h:66
int m_windowSize
Definition: FFTModel.h:176
int getHeight() const override
Return the number of bins in each column.
Definition: FFTModel.cpp:135
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...
void miss()
Definition: HitCount.h:61
~FFTModel()
Definition: FFTModel.cpp:77
Peaks picked using sliding median window.
Definition: FFTModel.h:147
FFTModel(ModelId model, int channel, WindowType windowType, int windowSize, int windowIncrement, int fftSize)
!! threading requirements? !! doubles? since we&#39;re not caching much
Definition: FFTModel.cpp:35
floatvec_t getSourceDataUncached(std::pair< sv_frame_t, sv_frame_t >) const
Definition: FFTModel.cpp:334
bool getPhasesAt(int x, float *values, int minbin=0, int count=0) const
Definition: FFTModel.cpp:237
Column getColumn(int x) const override
Get data from the given column of bin values.
Definition: FFTModel.cpp:160
float getPhaseAt(int x, int y) const
Definition: FFTModel.cpp:204
#define SVCERR
Definition: Debug.h:109
const ModelId m_model
Definition: FFTModel.h:172
int m_channel
Definition: FFTModel.h:174
std::vector< SavedColumn > m_cached
Definition: FFTModel.h:211
std::vector< std::complex< float >, breakfastquay::StlAllocator< std::complex< float > > > complexvec_t
Definition: BaseTypes.h:56
SavedSourceData m_savedData
Definition: FFTModel.h:205
int getPeakPickWindowSize(PeakPickType type, sv_samplerate_t sampleRate, int bin, double &dist) const
Definition: FFTModel.cpp:581
int getWidth() const override
Return the number of columns of bins in the model.
Definition: FFTModel.cpp:126
Definition: ById.h:115
float getBinValue(int n) const override
Return the value of bin n, if any.
Definition: FFTModel.cpp:154
floatvec_t getSourceSamples(int column) const
Definition: FFTModel.cpp:262
int m_fftSize
Definition: FFTModel.h:178
void hit()
Definition: HitCount.h:59
void modelChanged(ModelId myId)
Emitted when a model has been edited (or more data retrieved from cache, in the case of a cached mode...
std::set< int > PeakLocationSet
Definition: FFTModel.h:150
Profile point instance class.
Definition: Profiler.h:93