Audacity  3.0.3
SpectrumView.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 SpectrumView.cpp
6 
7 Paul Licameli split from WaveTrackView.cpp
8 
9 **********************************************************************/
10 
11 
12 #include "SpectrumView.h"
13 
14 #include "SpectralDataManager.h" // Cycle :-(
15 #include "SpectrumVRulerControls.h"
16 #include "WaveTrackView.h"
17 #include "WaveTrackViewConstants.h"
18 
19 #include "../../../ui/BrushHandle.h"
20 
21 #include "AColor.h"
22 #include "Prefs.h"
23 #include "NumberScale.h"
24 #include "../../../../TrackArtist.h"
25 #include "../../../../TrackPanelDrawingContext.h"
26 #include "ViewInfo.h"
27 #include "../../../../WaveClip.h"
28 #include "../../../../WaveTrack.h"
29 #include "../../../../prefs/SpectrogramSettings.h"
30 #include "../../../../ProjectSettings.h"
31 
32 #include <wx/dcmemory.h>
33 #include <wx/graphics.h>
34 
35 class BrushHandle;
36 class SpectralData;
37 
40  { wxT("Spectrogram"), XXO("&Spectrogram") }
41 };
42 
44 
45 SpectrumView::SpectrumView(WaveTrackView &waveTrackView) : WaveTrackSubView(waveTrackView) {
46  auto wt = static_cast<WaveTrack*>( FindTrack().get() );
47  mpSpectralData = std::make_shared<SpectralData>(wt->GetRate());
48  mOnBrushTool = false;
49 }
50 
51 SpectrumView::~SpectrumView() = default;
52 
54 {
55  return true;
56 }
57 
59 public:
60  explicit SpectralDataSaver( SpectrumView &view )
61  : mView{ view }
62  {}
63 
64  void Init( AudacityProject &project, bool clearAll ) override
65  {
66  mpProject = &project;
67  ForAll( project, [this, clearAll](SpectrumView &view){
68  auto pOldData = view.mpSpectralData;
69  if (clearAll) {
70  auto &pNewData = view.mpBackupSpectralData =
71  std::make_shared<SpectralData>(pOldData->GetSR());
72  pNewData->CopyFrom(*pOldData);
73  pOldData->clearAllData();
74  }
75  else {
76  // Back up one view only
77  if (&mView == &view) {
78  auto &pNewData = view.mpBackupSpectralData =
79  std::make_shared<SpectralData>(pOldData->GetSR());
80  pNewData->CopyFrom( *pOldData );
81  }
82  else
83  view.mpBackupSpectralData = {};
84  }
85  });
86  }
87 
88  ~SpectralDataSaver() override
89  {
90  if (mpProject)
91  ForAll( *mpProject, [this](SpectrumView &view){
92  if (mCommitted) {
93  // Discard all backups
94  view.mpBackupSpectralData = {};
95  }
96  else {
97  // Restore all
98  if (auto &pBackupData = view.mpBackupSpectralData) {
99  view.mpSpectralData->CopyFrom(*pBackupData);
100  pBackupData.reset();
101  }
102  }
103  });
104  }
105 
106 private:
109 };
110 
111 // This always hits, but details of the hit vary with mouse position and
112 // key state.
114  std::weak_ptr<BrushHandle> &holder,
115  const TrackPanelMouseState &st, const AudacityProject *pProject,
116  const std::shared_ptr<SpectrumView> &pTrackView,
117  const std::shared_ptr<SpectralData> &mpData)
118 {
119  const auto &viewInfo = ViewInfo::Get( *pProject );
120  auto &projectSettings = ProjectSettings::Get( *pProject );
121  auto result = std::make_shared<BrushHandle>(
122  std::make_shared<SpectrumView::SpectralDataSaver>(*pTrackView),
123  pTrackView, TrackList::Get( *pProject ),
124  st, viewInfo, mpData, projectSettings);
125 
126  result = AssignUIHandlePtr(holder, result);
127 
128  //Make sure we are within the selected track
129  // Adjusting the selection edges can be turned off in
130  // the preferences...
131  auto pTrack = pTrackView->FindTrack();
132  if (!pTrack->GetSelected() || !viewInfo.bAdjustSelectionEdges)
133  {
134  return result;
135  }
136 
137  return result;
138 }
139 
141  std::function<void(SpectrumView &view)> fn )
142 {
143  if (!fn)
144  return;
145  for ( const auto wt : TrackList::Get(project).Any< WaveTrack >() ) {
146  if (auto pWaveTrackView =
147  dynamic_cast<WaveTrackView*>( &TrackView::Get(*wt)) ) {
148  for (const auto &pSubView : pWaveTrackView->GetAllSubViews()) {
149  if (const auto sView = dynamic_cast<SpectrumView*>(pSubView.get()))
150  fn( *sView );
151  }
152  }
153  }
154 }
155 
156 std::vector<UIHandlePtr> SpectrumView::DetailedHitTest(
157  const TrackPanelMouseState &state,
158  const AudacityProject *pProject, int currentTool, bool bMultiTool )
159 {
160  const auto wt = std::static_pointer_cast< WaveTrack >( FindTrack() );
161  std::vector<UIHandlePtr> results;
162 
163 #ifdef EXPERIMENTAL_BRUSH_TOOL
164  mOnBrushTool = (currentTool == ToolCodes::brushTool);
165  if(mOnBrushTool){
166  const auto result = BrushHandleHitTest(
167  mBrushHandle, state,
168  pProject, std::static_pointer_cast<SpectrumView>(shared_from_this()),
170  results.push_back(result);
171  return results;
172  }
173 #endif
174 
176  state, pProject, currentTool, bMultiTool, wt
177  ).second;
178 }
179 
180 void SpectrumView::DoSetMinimized( bool minimized )
181 {
182  auto wt = static_cast<WaveTrack*>( FindTrack().get() );
183 
184 #ifdef EXPERIMENTAL_HALF_WAVE
185  bool bHalfWave;
186  gPrefs->Read(wxT("/GUI/CollapseToHalfWave"), &bHalfWave, false);
187  if( bHalfWave && minimized)
188  {
189  // It is all right to set the top of scale to a huge number,
190  // not knowing the track rate here -- because when retrieving the
191  // value, then we pass in a sample rate and clamp it above to the
192  // Nyquist frequency.
193  constexpr auto max = std::numeric_limits<float>::max();
194  const bool spectrumLinear =
195  (wt->GetSpectrogramSettings().scaleType ==
197  // Zoom out full
198  wt->SetSpectrumBounds( spectrumLinear ? 0.0f : 1.0f, max );
199  }
200 #endif
201 
202  TrackView::DoSetMinimized( minimized );
203 }
204 
205 auto SpectrumView::SubViewType() const -> const Type &
206 {
207  return sType;
208 }
209 
210 std::shared_ptr<TrackVRulerControls> SpectrumView::DoGetVRulerControls()
211 {
212  return std::make_shared<SpectrumVRulerControls>( shared_from_this() );
213 }
214 
215 std::shared_ptr<SpectralData> SpectrumView::GetSpectralData(){
216  return mpSpectralData;
217 }
218 
220  if ( const auto pDest = dynamic_cast< SpectrumView* >( destSubView ) ) {
221  pDest->mpSpectralData = std::make_shared<SpectralData>(mpSpectralData->GetSR());
222  pDest->mpSpectralData->CopyFrom(*mpSpectralData);
223  }
224 }
225 
226 namespace
227 {
228 
229 static inline float findValue
230 (const float *spectrum, float bin0, float bin1, unsigned nBins,
231  bool autocorrelation, int gain, int range)
232 {
233  float value;
234 
235 
236 #if 0
237  // Averaging method
238  if ((int)(bin1) == (int)(bin0)) {
239  value = spectrum[(int)(bin0)];
240  } else {
241  float binwidth= bin1 - bin0;
242  value = spectrum[(int)(bin0)] * (1.f - bin0 + (int)bin0);
243 
244  bin0 = 1 + (int)(bin0);
245  while (bin0 < (int)(bin1)) {
246  value += spectrum[(int)(bin0)];
247  bin0 += 1.0;
248  }
249  // Do not reference past end of freq array.
250  if ((int)(bin1) >= (int)nBins) {
251  bin1 -= 1.0;
252  }
253 
254  value += spectrum[(int)(bin1)] * (bin1 - (int)(bin1));
255  value /= binwidth;
256  }
257 #else
258  // Maximum method, and no apportionment of any single bins over multiple pixel rows
259  // See Bug971
260  int index, limitIndex;
261  if (autocorrelation) {
262  // bin = 2 * nBins / (nBins - 1 - array_index);
263  // Solve for index
264  index = std::max(0.0f, std::min(float(nBins - 1),
265  (nBins - 1) - (2 * nBins) / (std::max(1.0f, bin0))
266  ));
267  limitIndex = std::max(0.0f, std::min(float(nBins - 1),
268  (nBins - 1) - (2 * nBins) / (std::max(1.0f, bin1))
269  ));
270  }
271  else {
272  index = std::min<int>(nBins - 1, (int)(floor(0.5 + bin0)));
273  limitIndex = std::min<int>(nBins, (int)(floor(0.5 + bin1)));
274  }
275  value = spectrum[index];
276  while (++index < limitIndex)
277  value = std::max(value, spectrum[index]);
278 #endif
279  if (!autocorrelation) {
280  // Last step converts dB to a 0.0-1.0 range
281  value = (value + range + gain) / (double)range;
282  }
283  value = std::min(1.0f, std::max(0.0f, value));
284  return value;
285 }
286 
287 // dashCount counts both dashes and the spaces between them.
289 ChooseColorSet( float bin0, float bin1, float selBinLo,
290  float selBinCenter, float selBinHi, int dashCount, bool isSpectral )
291 {
292  if (!isSpectral)
294  if ((selBinCenter >= 0) && (bin0 <= selBinCenter) &&
295  (selBinCenter < bin1))
297  if ((0 == dashCount % 2) &&
298  (((selBinLo >= 0) && (bin0 <= selBinLo) && ( selBinLo < bin1)) ||
299  ((selBinHi >= 0) && (bin0 <= selBinHi) && ( selBinHi < bin1))))
301  if ((selBinLo < 0 || selBinLo < bin1) && (selBinHi < 0 || selBinHi > bin0))
303 
305 }
306 
307 
309  WaveTrackCache &waveTrackCache,
310  const WaveClip *clip,
311  const wxRect &rect,
312  const std::shared_ptr<SpectralData> &mpSpectralData,
313  bool selected)
314 {
315  auto &dc = context.dc;
316  const auto artist = TrackArtist::Get( context );
317  bool onBrushTool = artist->onBrushTool;
318  const auto &selectedRegion = *artist->pSelectedRegion;
319  const auto &zoomInfo = *artist->pZoomInfo;
320 
321 #ifdef PROFILE_WAVEFORM
322  Profiler profiler;
323 #endif
324 
325  const WaveTrack *const track = waveTrackCache.GetTrack().get();
327  const bool autocorrelation = (settings.algorithm == SpectrogramSettings::algPitchEAC);
328 
329  enum { DASH_LENGTH = 10 /* pixels */ };
330 
331  const ClipParameters params{
332  true, track, clip, rect, selectedRegion, zoomInfo };
333  const wxRect &hiddenMid = params.hiddenMid;
334  // The "hiddenMid" rect contains the part of the display actually
335  // containing the waveform, as it appears without the fisheye. If it's empty, we're done.
336  if (hiddenMid.width <= 0) {
337  return;
338  }
339 
340  const double &t0 = params.t0;
341  const double &tOffset = params.tOffset;
342  const auto &ssel0 = params.ssel0;
343  const auto &ssel1 = params.ssel1;
344  const double &averagePixelsPerSample = params.averagePixelsPerSample;
345  const double &rate = params.rate;
346  const double &hiddenLeftOffset = params.hiddenLeftOffset;
347  const double &leftOffset = params.leftOffset;
348  const wxRect &mid = params.mid;
349 
350  double freqLo = SelectedRegion::UndefinedFrequency;
351  double freqHi = SelectedRegion::UndefinedFrequency;
352 #ifdef EXPERIMENTAL_SPECTRAL_EDITING
353  freqLo = selectedRegion.f0();
354  freqHi = selectedRegion.f1();
355 #endif
356 
357  const int &colorScheme = settings.colorScheme;
358  const int &range = settings.range;
359  const int &gain = settings.gain;
360 
361 #ifdef EXPERIMENTAL_FIND_NOTES
362  const bool &fftFindNotes = settings.fftFindNotes;
363  const double &findNotesMinA = settings.findNotesMinA;
364  const int &numberOfMaxima = settings.numberOfMaxima;
365  const bool &findNotesQuantize = settings.findNotesQuantize;
366 #endif
367 #ifdef EXPERIMENTAL_FFT_Y_GRID
368  const bool &fftYGrid = settings.fftYGrid;
369 #endif
370 
371  dc.SetPen(*wxTRANSPARENT_PEN);
372 
373  // We draw directly to a bit image in memory,
374  // and then paint this directly to our offscreen
375  // bitmap. Note that this could be optimized even
376  // more, but for now this is not bad. -dmazzoni
377  wxImage image((int)mid.width, (int)mid.height);
378  if (!image.IsOk())
379  return;
380 #ifdef EXPERIMENTAL_SPECTROGRAM_OVERLAY
381  image.SetAlpha();
382  unsigned char *alpha = image.GetAlpha();
383 #endif
384  unsigned char *data = image.GetData();
385 
386  const auto half = settings.GetFFTLength() / 2;
387  const double binUnit = rate / (2 * half);
388  const float *freq = 0;
389  const sampleCount *where = 0;
390  bool updated;
391  {
392  const double pps = averagePixelsPerSample * rate;
393  updated = clip->GetSpectrogram(waveTrackCache, freq, where,
394  (size_t)hiddenMid.width,
395  t0, pps);
396  }
397  auto nBins = settings.NBins();
398 
399  float minFreq, maxFreq;
400  track->GetSpectrumBounds(&minFreq, &maxFreq);
401 
402  const SpectrogramSettings::ScaleType scaleType = settings.scaleType;
403 
404  // nearest frequency to each pixel row from number scale, for selecting
405  // the desired fft bin(s) for display on that row
406  float *bins = (float*)alloca(sizeof(*bins)*(hiddenMid.height + 1));
407  {
408  const NumberScale numberScale( settings.GetScale( minFreq, maxFreq ) );
409 
410  NumberScale::Iterator it = numberScale.begin(mid.height);
411  float nextBin = std::max( 0.0f, std::min( float(nBins - 1),
412  settings.findBin( *it, binUnit ) ) );
413 
414  int yy;
415  for (yy = 0; yy < hiddenMid.height; ++yy) {
416  bins[yy] = nextBin;
417  nextBin = std::max( 0.0f, std::min( float(nBins - 1),
418  settings.findBin( *++it, binUnit ) ) );
419  }
420  bins[yy] = nextBin;
421  }
422 
423 #ifdef EXPERIMENTAL_FFT_Y_GRID
424  const float
425  log2 = logf(2.0f),
426  scale2 = (lmax - lmin) / log2,
427  lmin2 = lmin / log2;
428 
429  ArrayOf<bool> yGrid{size_t(mid.height)};
430  for (int yy = 0; yy < mid.height; ++yy) {
431  float n = (float(yy) / mid.height*scale2 - lmin2) * 12;
432  float n2 = (float(yy + 1) / mid.height*scale2 - lmin2) * 12;
433  float f = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n / 12.0f + lmin2);
434  float f2 = float(minFreq) / (fftSkipPoints + 1)*powf(2.0f, n2 / 12.0f + lmin2);
435  n = logf(f / 440) / log2 * 12;
436  n2 = logf(f2 / 440) / log2 * 12;
437  if (floor(n) < floor(n2))
438  yGrid[yy] = true;
439  else
440  yGrid[yy] = false;
441  }
442 #endif //EXPERIMENTAL_FFT_Y_GRID
443 
444  if (!updated && clip->mSpecPxCache->valid &&
445  ((int)clip->mSpecPxCache->len == hiddenMid.height * hiddenMid.width)
446  && scaleType == clip->mSpecPxCache->scaleType
447  && gain == clip->mSpecPxCache->gain
448  && range == clip->mSpecPxCache->range
449  && minFreq == clip->mSpecPxCache->minFreq
450  && maxFreq == clip->mSpecPxCache->maxFreq
451 #ifdef EXPERIMENTAL_FFT_Y_GRID
452  && fftYGrid==fftYGridOld
453 #endif //EXPERIMENTAL_FFT_Y_GRID
454 #ifdef EXPERIMENTAL_FIND_NOTES
455  && fftFindNotes == artist->fftFindNotesOld
456  && findNotesMinA == artist->findNotesMinAOld
457  && numberOfMaxima == artist->findNotesNOld
458  && findNotesQuantize == artist->findNotesQuantizeOld
459 #endif
460  ) {
461  // Wave clip's spectrum cache is up to date,
462  // and so is the spectrum pixel cache
463  }
464  else {
465  // Update the spectrum pixel cache
466  clip->mSpecPxCache = std::make_unique<SpecPxCache>(hiddenMid.width * hiddenMid.height);
467  clip->mSpecPxCache->valid = true;
468  clip->mSpecPxCache->scaleType = scaleType;
469  clip->mSpecPxCache->gain = gain;
470  clip->mSpecPxCache->range = range;
471  clip->mSpecPxCache->minFreq = minFreq;
472  clip->mSpecPxCache->maxFreq = maxFreq;
473 #ifdef EXPERIMENTAL_FIND_NOTES
474  artist->fftFindNotesOld = fftFindNotes;
475  artist->findNotesMinAOld = findNotesMinA;
476  artist->findNotesNOld = numberOfMaxima;
477  artist->findNotesQuantizeOld = findNotesQuantize;
478 #endif
479 
480 #ifdef EXPERIMENTAL_FIND_NOTES
481  float log2 = logf( 2.0f ),
482  lmin = logf( minFreq ), lmax = logf( maxFreq ), scale = lmax - lmin,
483  lmins = lmin,
484  lmaxs = lmax
485  ;
486 #endif //EXPERIMENTAL_FIND_NOTES
487 
488 #ifdef EXPERIMENTAL_FIND_NOTES
489  int maxima[128];
490  float maxima0[128], maxima1[128];
491  const float
492  f2bin = half / (rate / 2.0f),
493  bin2f = 1.0f / f2bin,
494  minDistance = powf(2.0f, 2.0f / 12.0f),
495  i0 = expf(lmin) / binUnit,
496  i1 = expf(scale + lmin) / binUnit,
497  minColor = 0.0f;
498  const size_t maxTableSize = 1024;
499  ArrayOf<int> indexes{ maxTableSize };
500 #endif //EXPERIMENTAL_FIND_NOTES
501 
502 #ifdef _OPENMP
503 #pragma omp parallel for
504 #endif
505  for (int xx = 0; xx < hiddenMid.width; ++xx) {
506 #ifdef EXPERIMENTAL_FIND_NOTES
507  int maximas = 0;
508  const int x0 = nBins * xx;
509  if (fftFindNotes) {
510  for (int i = maxTableSize - 1; i >= 0; i--)
511  indexes[i] = -1;
512 
513  // Build a table of (most) values, put the index in it.
514  for (int i = (int)(i0); i < (int)(i1); i++) {
515  float freqi = freq[x0 + (int)(i)];
516  int value = (int)((freqi + gain + range) / range*(maxTableSize - 1));
517  if (value < 0)
518  value = 0;
519  if (value >= maxTableSize)
520  value = maxTableSize - 1;
521  indexes[value] = i;
522  }
523  // Build from the indices an array of maxima.
524  for (int i = maxTableSize - 1; i >= 0; i--) {
525  int index = indexes[i];
526  if (index >= 0) {
527  float freqi = freq[x0 + index];
528  if (freqi < findNotesMinA)
529  break;
530 
531  bool ok = true;
532  for (int m = 0; m < maximas; m++) {
533  // Avoid to store very close maxima.
534  float maxm = maxima[m];
535  if (maxm / index < minDistance && index / maxm < minDistance) {
536  ok = false;
537  break;
538  }
539  }
540  if (ok) {
541  maxima[maximas++] = index;
542  if (maximas >= numberOfMaxima)
543  break;
544  }
545  }
546  }
547 
548 // The f2pix helper macro converts a frequency into a pixel coordinate.
549 #define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*hiddenMid.height
550 
551  // Possibly quantize the maxima frequencies and create the pixel block limits.
552  for (int i = 0; i < maximas; i++) {
553  int index = maxima[i];
554  float f = float(index)*bin2f;
555  if (findNotesQuantize)
556  {
557  f = expf((int)(log(f / 440) / log2 * 12 - 0.5) / 12.0f*log2) * 440;
558  maxima[i] = f*f2bin;
559  }
560  float f0 = expf((log(f / 440) / log2 * 24 - 1) / 24.0f*log2) * 440;
561  maxima0[i] = f2pix(f0);
562  float f1 = expf((log(f / 440) / log2 * 24 + 1) / 24.0f*log2) * 440;
563  maxima1[i] = f2pix(f1);
564  }
565  }
566 
567  int it = 0;
568  bool inMaximum = false;
569 #endif //EXPERIMENTAL_FIND_NOTES
570 
571  for (int yy = 0; yy < hiddenMid.height; ++yy) {
572  const float bin = bins[yy];
573  const float nextBin = bins[yy+1];
574 
575  if (settings.scaleType != SpectrogramSettings::stLogarithmic) {
576  const float value = findValue
577  (freq + nBins * xx, bin, nextBin, nBins, autocorrelation, gain, range);
578  clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
579  }
580  else {
581  float value;
582 
583 #ifdef EXPERIMENTAL_FIND_NOTES
584  if (fftFindNotes) {
585  if (it < maximas) {
586  float i0 = maxima0[it];
587  if (yy >= i0)
588  inMaximum = true;
589 
590  if (inMaximum) {
591  float i1 = maxima1[it];
592  if (yy + 1 <= i1) {
593  value = findValue(freq + x0, bin, nextBin, nBins, autocorrelation, gain, range);
594  if (value < findNotesMinA)
595  value = minColor;
596  }
597  else {
598  it++;
599  inMaximum = false;
600  value = minColor;
601  }
602  }
603  else {
604  value = minColor;
605  }
606  }
607  else
608  value = minColor;
609  }
610  else
611 #endif //EXPERIMENTAL_FIND_NOTES
612  {
613  value = findValue
614  (freq + nBins * xx, bin, nextBin, nBins, autocorrelation, gain, range);
615  }
616  clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value;
617  } // logF
618  } // each yy
619  } // each xx
620  } // updating cache
621 
622  float selBinLo = settings.findBin( freqLo, binUnit);
623  float selBinHi = settings.findBin( freqHi, binUnit);
624  float selBinCenter = (freqLo < 0 || freqHi < 0)
625  ? -1
626  : settings.findBin( sqrt(freqLo * freqHi), binUnit );
627 
628  const bool isSpectral = settings.SpectralSelectionEnabled();
629  const bool hidden = (ZoomInfo::HIDDEN == zoomInfo.GetFisheyeState());
630  const int begin = hidden
631  ? 0
632  : std::max(0, (int)(zoomInfo.GetFisheyeLeftBoundary(-leftOffset)));
633  const int end = hidden
634  ? 0
635  : std::min(mid.width, (int)(zoomInfo.GetFisheyeRightBoundary(-leftOffset)));
636  const size_t numPixels = std::max(0, end - begin);
637 
638  SpecCache specCache;
639 
640  // need explicit resize since specCache.where[] accessed before Populate()
641  specCache.Grow(numPixels, settings, -1, t0);
642 
643  if (numPixels > 0) {
644  for (int ii = begin; ii < end; ++ii) {
645  const double time = zoomInfo.PositionToTime(ii, -leftOffset) - tOffset;
646  specCache.where[ii - begin] = sampleCount(0.5 + rate * time);
647  }
648  specCache.Populate
649  (settings, waveTrackCache,
650  0, 0, numPixels,
651  clip->GetPlaySamplesCount(),
652  tOffset, rate,
653  0 // FIXME: PRL -- make reassignment work with fisheye
654  );
655  }
656 
657  // build color gradient tables (not thread safe)
660 
661  // left pixel column of the fisheye
662  int fisheyeLeft = zoomInfo.GetFisheyeLeftBoundary(-leftOffset);
663 
664  // Bug 2389 - always draw at least one pixel of selection.
665  int selectedX = zoomInfo.TimeToPosition(selectedRegion.t0(), -leftOffset);
666 
667 #ifdef _OPENMP
668 #pragma omp parallel for
669 #endif
670 
671  const NumberScale numberScale(settings.GetScale(minFreq, maxFreq));
672  int windowSize = mpSpectralData->GetWindowSize();
673  int hopSize = mpSpectralData->GetHopSize();
674  double sr = mpSpectralData->GetSR();
675  auto &dataHistory = mpSpectralData->dataHistory;
676 
677  // Lazy way to add all hops and bins required for rendering
678  dataHistory.push_back(mpSpectralData->dataBuffer);
679 
680  // Generate combined hops and bins map for rendering
681  std::map<long long, std::set<int>> hopBinMap;
682  for(auto vecIter = dataHistory.begin(); vecIter != dataHistory.end(); ++vecIter){
683  for(const auto &hopMap: *vecIter){
684  for(const auto &binNum: hopMap.second)
685  hopBinMap[hopMap.first].insert(binNum);
686  }
687  }
688 
689  // Lambda for converting yy (not mouse coord!) to respective freq. bins
690  auto yyToFreqBin = [&](int yy){
691  const double p = double(yy) / hiddenMid.height;
692  float convertedFreq = numberScale.PositionToValue(p);
693  float convertedFreqBinNum = convertedFreq / (sr / windowSize);
694  return static_cast<int>(std::round(convertedFreqBinNum));
695  };
696 
697  for (int xx = 0; xx < mid.width; ++xx) {
698  int correctedX = xx + leftOffset - hiddenLeftOffset;
699 
700  // in fisheye mode the time scale has changed, so the row values aren't cached
701  // in the loop above, and must be fetched from fft cache
702  float* uncached;
703  if (!zoomInfo.InFisheye(xx, -leftOffset)) {
704  uncached = 0;
705  }
706  else {
707  int specIndex = (xx - fisheyeLeft) * nBins;
708  wxASSERT(specIndex >= 0 && specIndex < (int)specCache.freq.size());
709  uncached = &specCache.freq[specIndex];
710  }
711 
712  // zoomInfo must be queried for each column since with fisheye enabled
713  // time between columns is variable
714  auto w0 = sampleCount(0.5 + rate *
715  (zoomInfo.PositionToTime(xx, -leftOffset) - tOffset));
716 
717  auto w1 = sampleCount(0.5 + rate *
718  (zoomInfo.PositionToTime(xx+1, -leftOffset) - tOffset));
719 
720  bool maybeSelected = ssel0 <= w0 && w1 < ssel1;
721  maybeSelected = maybeSelected || (xx == selectedX);
722 
723  // In case the xx matches the hop number, it will be used as iterator for frequency bins
724  std::set<int> *pSelectedBins = nullptr;
725  std::set<int>::iterator freqBinIter;
726  auto advanceFreqBinIter = [&](int nextBinRounded){
727  while (freqBinIter != pSelectedBins->end() &&
728  *freqBinIter < nextBinRounded)
729  ++freqBinIter;
730  };
731 
732  bool hitHopNum = false;
733  if (onBrushTool) {
734  int convertedHopNum = (w0.as_long_long() + hopSize / 2) / hopSize;
735  hitHopNum = (hopBinMap.find(convertedHopNum) != hopBinMap.end());
736  if(hitHopNum) {
737  pSelectedBins = &hopBinMap[convertedHopNum];
738  freqBinIter = pSelectedBins->begin();
739  advanceFreqBinIter(std::round(yyToFreqBin(0)));
740  }
741  }
742 
743  for (int yy = 0; yy < hiddenMid.height; ++yy) {
744  if(onBrushTool)
745  maybeSelected = false;
746  const float bin = bins[yy];
747  const float nextBin = bins[yy+1];
748  auto binRounded = std::round(yyToFreqBin(yy));
749  auto nextBinRounded = std::round(yyToFreqBin(yy + 1));
750 
751  if(hitHopNum
752  && freqBinIter != pSelectedBins->end()
753  && binRounded == *freqBinIter)
754  maybeSelected = true;
755 
756  if (hitHopNum)
757  advanceFreqBinIter(nextBinRounded);
758 
759  // For spectral selection, determine what colour
760  // set to use. We use a darker selection if
761  // in both spectral range and time range.
762 
764 
765  // If we are in the time selected range, then we may use a different color set.
766  if (maybeSelected) {
767  selected =
768  ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi,
769  (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral);
770  if ( onBrushTool && selected != AColor::ColorGradientUnselected )
771  // use only two sets of colors
773  }
774 
775  const float value = uncached
776  ? findValue(uncached, bin, nextBin, nBins, autocorrelation, gain, range)
777  : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy];
778 
779  unsigned char rv, gv, bv;
780  GetColorGradient(value, selected, colorScheme, &rv, &gv, &bv);
781 
782 #ifdef EXPERIMENTAL_FFT_Y_GRID
783  if (fftYGrid && yGrid[yy]) {
784  rv /= 1.1f;
785  gv /= 1.1f;
786  bv /= 1.1f;
787  }
788 #endif //EXPERIMENTAL_FFT_Y_GRID
789  int px = ((mid.height - 1 - yy) * mid.width + xx);
790 #ifdef EXPERIMENTAL_SPECTROGRAM_OVERLAY
791  // More transparent the closer to zero intensity.
792  alpha[px]= wxMin( 200, (value+0.3) * 500) ;
793 #endif
794  px *=3;
795  data[px++] = rv;
796  data[px++] = gv;
797  data[px] = bv;
798  } // each yy
799  } // each xx
800 
801  dataHistory.pop_back();
802  wxBitmap converted = wxBitmap(image);
803 
804  wxMemoryDC memDC;
805 
806  memDC.SelectObject(converted);
807 
808  dc.Blit(mid.x, mid.y, mid.width, mid.height, &memDC, 0, 0, wxCOPY, FALSE);
809 
810  // Draw clip edges, as also in waveform view, which improves the appearance
811  // of split views
812  {
813  auto clipRect = ClipParameters::GetClipRect(*clip, zoomInfo, rect);
814  if (!clipRect.IsEmpty())
815  TrackArt::DrawClipEdges(dc, clipRect, selected);
816  }
817 }
818 
819 }
820 
822  const WaveTrack* track,
823  const WaveClip* selectedClip,
824  const wxRect & rect )
825 {
826  const auto artist = TrackArtist::Get( context );
827  const auto &blankSelectedBrush = artist->blankSelectedBrush;
828  const auto &blankBrush = artist->blankBrush;
830  context, rect, track, blankSelectedBrush, blankBrush );
831 
832  WaveTrackCache cache(track->SharedPointer<const WaveTrack>());
833  for (const auto &clip: track->GetClips()){
834  DrawClipSpectrum( context, cache, clip.get(), rect,
835  mpSpectralData, clip.get() == selectedClip);
836  }
837 
838  DrawBoldBoundaries( context, track, rect );
839 }
840 
842  TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass )
843 {
844  if ( iPass == TrackArtist::PassTracks ) {
845  auto &dc = context.dc;
846  // Update cache for locations, e.g. cutlines and merge points
847  // Bug2588: do this for both channels, even if one is not drawn, so that
848  // cut-line editing (which depends on the locations cache) works properly.
849  // If both channels are visible, we will duplicate this effort, but that
850  // matters little.
851  for( auto channel:
852  TrackList::Channels(static_cast<WaveTrack*>(FindTrack().get())) )
853  channel->UpdateLocationsCache();
854 
855  const auto wt = std::static_pointer_cast<const WaveTrack>(
856  FindTrack()->SubstitutePendingChangedTrack());
857 
858  const auto artist = TrackArtist::Get( context );
859 
860 #if defined(__WXMAC__)
861  wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
862  dc.GetGraphicsContext()->SetAntialiasMode(wxANTIALIAS_NONE);
863 #endif
864 
865  auto waveTrackView = GetWaveTrackView().lock();
866  wxASSERT(waveTrackView.use_count());
867 
868  auto seletedClip = waveTrackView->GetSelectedClip().lock();
869  DoDraw( context, wt.get(), seletedClip.get(), rect );
870 
871 #if defined(__WXMAC__)
872  dc.GetGraphicsContext()->SetAntialiasMode(aamode);
873 #endif
874  }
875  WaveTrackSubView::Draw( context, rect, iPass );
876 }
877 
879  []( WaveTrackView &view ){
880  return std::make_shared< SpectrumView >( view );
881  }
882 };
883 
884 // The following attaches the spectrogram settings item to the wave track popup
885 // menu. It is appropriate only to spectrum view and so is kept in this
886 // source file with the rest of the spectrum view implementation.
887 #include "WaveTrackControls.h"
888 #include "AudioIOBase.h"
889 #include "../../../../Menus.h"
890 #include "../../../../ProjectHistory.h"
891 #include "../../../../RefreshCode.h"
892 #include "../../../../prefs/PrefsDialog.h"
893 #include "../../../../prefs/SpectrumPrefs.h"
894 #include "../../../../widgets/AudacityMessageBox.h"
895 #include "../../../../widgets/PopupMenuTable.h"
896 
897 namespace {
899 
902  {
903  static SpectrogramSettingsHandler instance;
904  return instance;
905  }
906 
907  void OnSpectrogramSettings(wxCommandEvent &);
908 
909  void InitUserData(void *pUserData) override
910  {
911  mpData = static_cast< PlayableTrackControls::InitMenuData* >(pUserData);
912  }
913 };
914 
915 void SpectrogramSettingsHandler::OnSpectrogramSettings(wxCommandEvent &)
916 {
917  class ViewSettingsDialog final : public PrefsDialog
918  {
919  public:
920  ViewSettingsDialog(wxWindow *parent, AudacityProject &project,
922  int page)
923  : PrefsDialog(parent, &project, title, factories)
924  , mPage(page)
925  {
926  }
927 
928  long GetPreferredPage() override
929  {
930  return mPage;
931  }
932 
933  void SavePreferredPage() override
934  {
935  }
936 
937  private:
938  const int mPage;
939  };
940 
941  auto gAudioIO = AudioIOBase::Get();
942  if (gAudioIO->IsBusy()){
944  XO(
945 "To change Spectrogram Settings, stop any\n playing or recording first."),
946  XO("Stop the Audio First"),
947  wxOK | wxICON_EXCLAMATION | wxCENTRE);
948  return;
949  }
950 
951  WaveTrack *const pTrack = static_cast<WaveTrack*>(mpData->pTrack);
952 
953  PrefsPanel::Factories factories;
954  // factories.push_back(WaveformPrefsFactory( pTrack ));
955  factories.push_back(SpectrumPrefsFactory( pTrack ));
956  const int page =
957  // (pTrack->GetDisplay() == WaveTrackViewConstants::Spectrum) ? 1 :
958  0;
959 
960  auto title = XO("%s:").Format( pTrack->GetName() );
961  ViewSettingsDialog dialog(
962  mpData->pParent, mpData->project, title, factories, page);
963 
964  if (0 != dialog.ShowModal()) {
965  // Redraw
966  AudacityProject *const project = &mpData->project;
967  ProjectHistory::Get( *project ).ModifyState(true);
968  //Bug 1725 Toolbar was left greyed out.
969  //This solution is overkill, but does fix the problem and is what the
970  //prefs dialog normally does.
972  mpData->result = RefreshCode::RefreshAll;
973  }
974 }
975 
978  { "SubViews/Extra" },
979  std::make_unique<PopupMenuSection>( "SpectrogramSettings",
980  // Conditionally add menu item for settings, if showing spectrum
981  PopupMenuTable::Computed< WaveTrackPopupMenuTable >(
984  static const int OnSpectrogramSettingsID =
986 
987  const auto pTrack = &table.FindWaveTrack();
988  const auto &view = WaveTrackView::Get( *pTrack );
989  const auto displays = view.GetDisplays();
990  bool hasSpectrum = (displays.end() != std::find(
991  displays.begin(), displays.end(),
992  WaveTrackSubView::Type{ WaveTrackViewConstants::Spectrum, {} }
993  ) );
994  if( hasSpectrum )
995  // In future, we might move this to the context menu of the
996  // Spectrum vertical ruler.
997  // (But the latter won't be satisfactory without a means to
998  // open that other context menu with keystrokes only, and that
999  // would require some notion of a focused sub-view.)
1000  return std::make_unique<Entry>( "SpectrogramSettings",
1001  Entry::Item,
1002  OnSpectrogramSettingsID,
1003  XXO("S&pectrogram Settings..."),
1004  (wxCommandEventFunction)
1005  (&SpectrogramSettingsHandler::OnSpectrogramSettings),
1006  SpectrogramSettingsHandler::Instance(),
1007  []( PopupMenuHandler &handler, wxMenu &menu, int id ){
1008  // Bug 1253. Shouldn't open preferences if audio is busy.
1009  // We can't change them on the fly yet anyway.
1010  auto gAudioIO = AudioIOBase::Get();
1011  menu.Enable(id, !gAudioIO->IsBusy());
1012  } );
1013  else
1014  return nullptr;
1015  } ) )
1016 };
1017 }
1018 
1019 static bool ShouldCaptureEvent(wxKeyEvent& event, SpectralData *pData)
1020 {
1021  const auto keyCode = event.GetKeyCode();
1022  return
1023  (keyCode == WXK_BACK || keyCode == WXK_DELETE ||
1024  keyCode == WXK_NUMPAD_DELETE)
1025  && pData && !pData->dataHistory.empty();
1026 }
1027 
1029  wxKeyEvent& event, ViewInfo&, wxWindow*, AudacityProject*)
1030 {
1031  bool capture = ShouldCaptureEvent(event, mpSpectralData.get());
1032  event.Skip(!capture);
1033  return RefreshCode::RefreshNone;
1034 }
1035 
1036 unsigned SpectrumView::KeyDown(wxKeyEvent& event, ViewInfo& viewInfo, wxWindow*, AudacityProject* project)
1037 {
1038  bool capture = ShouldCaptureEvent(event, mpSpectralData.get());
1039  event.Skip(!capture);
1040  if (capture && SpectralDataManager::ProcessTracks(*project))
1041  // Not RefreshCell, because there might be effects in multiple tracks
1042  return RefreshCode::RefreshAll;
1043  return RefreshCode::RefreshNone;
1044 }
1045 
1047  wxKeyEvent &event, ViewInfo&, wxWindow*, AudacityProject* )
1048 {
1049  bool capture = ShouldCaptureEvent(event, mpSpectralData.get());
1050  event.Skip(!capture);
1051  return RefreshCode::RefreshNone;
1052 }
WaveTrackCache
A short-lived object, during whose lifetime, the contents of the WaveTrack are assumed not to change.
Definition: WaveTrack.h:636
ProjectHistory::ModifyState
void ModifyState(bool bWantsAutoSave)
Definition: ProjectHistory.cpp:124
TranslatableString
Holds a msgid for the translation catalog; may also bind format arguments.
Definition: TranslatableString.h:32
AudioIOBase.h
ViewInfo::Get
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:241
BrushHandle
Definition: BrushHandle.h:31
SpectrumView::CaptureKey
unsigned CaptureKey(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent, AudacityProject *project) override
Definition: SpectrumView.cpp:1028
SpectrogramSettings
Spectrogram settings, either for one track or as defaults.
Definition: SpectrogramSettings.h:27
WaveTrack
A Track that contains audio waveform data.
Definition: WaveTrack.h:69
SpectrumView::~SpectrumView
~SpectrumView() override
WaveTrackView
Definition: WaveTrackView.h:97
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
SpectrumView::mpBackupSpectralData
std::shared_ptr< SpectralData > mpBackupSpectralData
Definition: SpectrumView.h:137
fn
static const auto fn
Definition: WaveformView.cpp:1108
RefreshCode::RefreshAll
@ RefreshAll
Definition: RefreshCode.h:26
PrefsDialog::GetPreferredPage
virtual long GetPreferredPage()=0
NumberScale.h
TrackView::Get
static TrackView & Get(Track &)
Definition: TrackView.cpp:63
RefreshCode::RefreshNone
@ RefreshNone
Definition: RefreshCode.h:21
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
SpectrumView::Char
unsigned Char(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent, AudacityProject *project) override
Definition: SpectrumView.cpp:1046
key
static const WaveTrackSubViews::RegisteredFactory key
Definition: SpectrumView.cpp:878
Profiler
A simple profiler to measure the average time lengths that a particular task/function takes....
Definition: Profiler.h:40
SpectralData::dataBuffer
HopsAndBinsMap dataBuffer
Definition: SpectrumView.h:43
Track::GetName
wxString GetName() const
Definition: Track.h:426
AColor::ColorGradientTimeSelected
@ ColorGradientTimeSelected
Definition: AColor.h:30
WaveClip::GetPlaySamplesCount
sampleCount GetPlaySamplesCount() const
Definition: WaveClip.cpp:1821
CommonTrackPanelCell::FindTrack
std::shared_ptr< Track > FindTrack()
Definition: CommonTrackPanelCell.h:46
TrackPanelDrawingContext
Definition: TrackPanelDrawingContext.h:22
TrackList::Channels
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1484
ViewInfo
Definition: ViewInfo.h:202
WaveTrackSubView::DrawBoldBoundaries
static void DrawBoldBoundaries(TrackPanelDrawingContext &context, const WaveTrack *track, const wxRect &rect)
Definition: WaveTrackView.cpp:773
SpectrumVRulerControls.h
Track::SharedPointer
std::shared_ptr< Subclass > SharedPointer()
Definition: Track.h:291
GetColorGradient
void GetColorGradient(float value, AColor::ColorGradientChoice selected, int colorScheme, unsigned char *__restrict red, unsigned char *__restrict green, unsigned char *__restrict blue)
Definition: AColor.h:140
SpectrumView::Draw
void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass) override
Definition: SpectrumView.cpp:841
SpectralData::GetHopSize
int GetHopSize() const
Definition: SpectrumView.h:59
anonymous_namespace{SpectrumView.cpp}::sAttachment
PopupMenuTable::AttachedItem sAttachment
Definition: SpectrumView.cpp:976
anonymous_namespace{SpectrumView.cpp}::ChooseColorSet
AColor::ColorGradientChoice ChooseColorSet(float bin0, float bin1, float selBinLo, float selBinCenter, float selBinHi, int dashCount, bool isSpectral)
Definition: SpectrumView.cpp:289
XO
#define XO(s)
Definition: Internat.h:31
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:44
SpectrumView::SpectralDataSaver
Definition: SpectrumView.cpp:58
TrackPanelDrawingContext::dc
wxDC & dc
Definition: TrackPanelDrawingContext.h:23
SelectedRegion::UndefinedFrequency
static const int UndefinedFrequency
Definition: SelectedRegion.h:41
WaveTrack::GetSpectrogramSettings
const SpectrogramSettings & GetSpectrogramSettings() const
Definition: WaveTrack.cpp:763
ClientData::Site::RegisteredFactory
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
GetWaveTrackMenuTable
WaveTrackPopupMenuTable & GetWaveTrackMenuTable()
Definition: WaveTrackControls.cpp:960
WaveTrackSubView
Definition: WaveTrackView.h:39
MenuCreator::RebuildAllMenuBars
static void RebuildAllMenuBars()
Definition: Menus.cpp:679
AColor::PreComputeGradient
static void PreComputeGradient()
Definition: AColor.cpp:629
SpectrumView::mBrushHandle
std::weak_ptr< BrushHandle > mBrushHandle
Definition: SpectrumView.h:133
Entry
Definition: EditToolBar.cpp:225
WaveTrackSubView::DoDetailedHitTest
std::pair< bool, std::vector< UIHandlePtr > > DoDetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool, const std::shared_ptr< WaveTrack > &wt)
SpectrumView::DoGetVRulerControls
std::shared_ptr< TrackVRulerControls > DoGetVRulerControls() override
Definition: SpectrumView.cpp:210
WaveTrackView.h
SpectrumView::SpectralDataSaver::SpectralDataSaver
SpectralDataSaver(SpectrumView &view)
Definition: SpectrumView.cpp:60
SpectrumView
Definition: SpectrumView.h:114
SpectralDataManager.h
SpecCache::Grow
void Grow(size_t len_, const SpectrogramSettings &settings, double pixelsPerSecond, double start_)
Definition: WaveClip.cpp:789
ClipParameters::GetClipRect
static wxRect GetClipRect(const WaveClip &clip, const ZoomInfo &zoomInfo, const wxRect &viewRect)
Definition: WaveTrackView.cpp:1448
SpectrumView::mpSpectralData
std::shared_ptr< SpectralData > mpSpectralData
Definition: SpectrumView.h:137
WaveClip
This allows multiple clips to be a part of one WaveTrack.
Definition: WaveClip.h:175
TrackArtist::Get
static TrackArtist * Get(TrackPanelDrawingContext &)
Definition: TrackArtist.cpp:79
XXO
#define XXO(s)
Definition: Internat.h:44
Registry::BaseItemPtr
std::unique_ptr< BaseItem > BaseItemPtr
Definition: Registry.h:71
WaveTrackSubViewType
Definition: WaveTrackViewConstants.h:91
SpecCache
Definition: WaveClip.h:38
anonymous_namespace{SpectrumView.cpp}::SpectrogramSettingsHandler::Instance
static SpectrogramSettingsHandler & Instance()
Definition: SpectrumView.cpp:901
anonymous_namespace{SpectrumView.cpp}::findValue
static float findValue(const float *spectrum, float bin0, float bin1, unsigned nBins, bool autocorrelation, int gain, int range)
Definition: SpectrumView.cpp:230
SpectrumView::SubViewType
const Type & SubViewType() const override
Definition: SpectrumView.cpp:205
WaveTrack::GetSpectrumBounds
void GetSpectrumBounds(float *min, float *max) const
Definition: WaveTrack.cpp:332
SpectrumView::SpectralDataSaver::mView
SpectrumView & mView
Definition: SpectrumView.cpp:107
WaveTrack::GetClips
WaveClipHolders & GetClips()
Definition: WaveTrack.h:371
reg
static WaveTrackSubViewType::RegisteredType reg
Definition: SpectrumView.cpp:43
sType
static WaveTrackSubView::Type sType
Definition: SpectrumView.cpp:38
UIHandlePtr
std::shared_ptr< UIHandle > UIHandlePtr
Definition: CellularPanel.h:28
ClipParameters
Definition: WaveTrackView.h:221
AudioIOBase::Get
static AudioIOBase * Get()
Definition: AudioIOBase.cpp:89
SpectrumView::DoDraw
void DoDraw(TrackPanelDrawingContext &context, const WaveTrack *track, const WaveClip *selectedClip, const wxRect &rect)
Definition: SpectrumView.cpp:821
SpectralDataManager::ProcessTracks
static bool ProcessTracks(AudacityProject &project)
Definition: SpectralDataManager.cpp:36
ZoomInfo::HIDDEN
@ HIDDEN
Definition: ZoomInfo.h:159
CommonTrackControls::InitMenuData
Definition: CommonTrackControls.h:34
TrackView::DoSetMinimized
virtual void DoSetMinimized(bool isMinimized)
Definition: TrackView.cpp:126
SpectrogramSettings::ScaleType
int ScaleType
Definition: SpectrogramSettings.h:57
anonymous_namespace{SpectrumView.cpp}::SpectrogramSettingsHandler
Definition: SpectrumView.cpp:898
SpectrogramSettings::stLinear
@ stLinear
Definition: SpectrogramSettings.h:59
ViewInfo.h
BrushHandle::StateSaver::mCommitted
bool mCommitted
Definition: BrushHandle.h:48
SpectrumView::CopyToSubView
void CopyToSubView(WaveTrackSubView *destSubView) const override
Definition: SpectrumView.cpp:219
SpectrumView::ForAll
static void ForAll(AudacityProject &project, std::function< void(SpectrumView &view)> fn)
Definition: SpectrumView.cpp:140
SpectrumPrefsFactory
PrefsPanel::Factory SpectrumPrefsFactory(WaveTrack *wt)
Definition: SpectrumPrefs.cpp:587
SpectrogramSettings::stLogarithmic
@ stLogarithmic
Definition: SpectrogramSettings.h:60
AColor::ColorGradientUnselected
@ ColorGradientUnselected
Definition: AColor.h:29
SpectralData::GetSR
double GetSR() const
Definition: SpectrumView.h:67
min
int min(int a, int b)
Definition: CompareAudioCommand.cpp:106
SpectrumView::SpectrumView
SpectrumView(WaveTrackView &waveTrackView, const SpectrumView &src)=delete
WaveClip::GetSpectrogram
bool GetSpectrogram(WaveTrackCache &cache, const float *&spectrogram, const sampleCount *&where, size_t numPixels, double t0, double pixelsPerSecond) const
Definition: WaveClip.cpp:937
WaveTrackCache::GetTrack
const std::shared_ptr< const WaveTrack > & GetTrack() const
Definition: WaveTrack.h:654
title
static const auto title
Definition: NoUpdatesAvailableDialog.cpp:22
TrackArt::DrawBackgroundWithSelection
AUDACITY_DLL_API void DrawBackgroundWithSelection(TrackPanelDrawingContext &context, const wxRect &rect, const Track *track, const wxBrush &selBrush, const wxBrush &unselBrush, bool useSelection=true)
Definition: TrackArtist.cpp:528
WaveTrackSubViewType::RegisteredType
Definition: WaveTrackViewConstants.h:108
NumberScale::PositionToValue
float PositionToValue(float pp) const
Definition: NumberScale.h:154
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
PopupMenuHandler
Definition: PopupMenuTable.h:85
SpectralData::GetWindowSize
int GetWindowSize() const
Definition: SpectrumView.h:63
sampleCount
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:18
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
WaveTrackViewConstants.h
SpectrogramSettings::algPitchEAC
@ algPitchEAC
Definition: SpectrogramSettings.h:157
TrackArt::DrawClipEdges
AUDACITY_DLL_API void DrawClipEdges(wxDC &dc, const wxRect &clipRect, bool selected=false)
Definition: TrackArtist.cpp:368
WaveTrackView::Get
static WaveTrackView & Get(WaveTrack &track)
Definition: WaveTrackView.cpp:851
SpectrumView::SpectralDataSaver::Init
void Init(AudacityProject &project, bool clearAll) override
Definition: SpectrumView.cpp:64
TrackPanelMouseState
Definition: TrackPanelMouseEvent.h:28
SpectrumView::SpectralDataSaver::~SpectralDataSaver
~SpectralDataSaver() override
Definition: SpectrumView.cpp:88
SpectrumView::GetSpectralData
std::shared_ptr< SpectralData > GetSpectralData()
Definition: SpectrumView.cpp:215
SpecCache::Populate
void Populate(const SpectrogramSettings &settings, WaveTrackCache &waveTrackCache, int copyBegin, int copyEnd, size_t numPixels, sampleCount numSamples, double offset, double rate, double pixelsPerSecond)
Definition: WaveClip.cpp:813
SpectralData
Definition: SpectrumView.h:24
SpectrumView::KeyDown
unsigned KeyDown(wxKeyEvent &event, ViewInfo &viewInfo, wxWindow *pParent, AudacityProject *project) override
Definition: SpectrumView.cpp:1036
PrefsDialog
Dialog that shows the current PrefsPanel in a tabbed divider.
Definition: PrefsDialog.h:34
BrushHandleHitTest
static UIHandlePtr BrushHandleHitTest(std::weak_ptr< BrushHandle > &holder, const TrackPanelMouseState &st, const AudacityProject *pProject, const std::shared_ptr< SpectrumView > &pTrackView, const std::shared_ptr< SpectralData > &mpData)
Definition: SpectrumView.cpp:113
WaveClip::mSpecPxCache
std::unique_ptr< SpecPxCache > mSpecPxCache
Definition: WaveClip.h:402
WaveTrackViewConstants::Spectrum
@ Spectrum
Definition: WaveTrackViewConstants.h:29
WaveTrackSubView::GetWaveTrackView
std::weak_ptr< WaveTrackView > GetWaveTrackView() const
Definition: WaveTrackView.cpp:814
NumberScale::begin
Iterator begin(float nPositions) const
Definition: NumberScale.h:231
SpecCache::freq
std::vector< float > freq
Definition: WaveClip.h:91
WaveTrackPopupMenuTable::FindWaveTrack
WaveTrack & FindWaveTrack() const
Definition: WaveTrackControls.cpp:89
SpectrumView::SpectralDataSaver::mpProject
AudacityProject * mpProject
Definition: SpectrumView.cpp:108
TrackArtist::PassTracks
@ PassTracks
Definition: TrackArtist.h:81
PopupMenuTable::AttachedItem
Definition: PopupMenuTable.h:136
AColor::ColorGradientTimeAndFrequencySelected
@ ColorGradientTimeAndFrequencySelected
Definition: AColor.h:31
SpecCache::where
std::vector< sampleCount > where
Definition: WaveClip.h:92
SpectrumView::DetailedHitTest
std::vector< UIHandlePtr > DetailedHitTest(const TrackPanelMouseState &state, const AudacityProject *pProject, int currentTool, bool bMultiTool) override
Definition: SpectrumView.cpp:156
NumberScale
Definition: NumberScale.h:31
WaveTrackControls.h
Prefs.h
params
EffectDistortion::Params params
Definition: Distortion.cpp:99
AssignUIHandlePtr
std::shared_ptr< Subclass > AssignUIHandlePtr(std::weak_ptr< Subclass > &holder, const std::shared_ptr< Subclass > &pNew)
Definition: UIHandle.h:151
SpectralData::dataHistory
std::vector< HopsAndBinsMap > dataHistory
Definition: SpectrumView.h:44
SpectrumView::mOnBrushTool
bool mOnBrushTool
Definition: SpectrumView.h:138
anonymous_namespace{SpectrumView.cpp}::SpectrogramSettingsHandler::InitUserData
void InitUserData(void *pUserData) override
Called before the menu items are appended.
Definition: SpectrumView.cpp:909
SpectrumView::DoSetMinimized
void DoSetMinimized(bool minimized) override
Definition: SpectrumView.cpp:180
WaveTrackPopupMenuTable
Definition: WaveTrackControls.h:74
settings
static Settings & settings()
Definition: TrackInfo.cpp:86
SpectrumView::IsSpectral
bool IsSpectral() const override
Definition: SpectrumView.cpp:53
AColor::gradient_inited
static bool gradient_inited
Definition: AColor.h:124
PopupMenuTable::Entry
PopupMenuTableEntry Entry
Definition: PopupMenuTable.h:117
AColor.h
ArrayOf< bool >
PrefsDialog::SavePreferredPage
virtual void SavePreferredPage()=0
ShouldCaptureEvent
static bool ShouldCaptureEvent(wxKeyEvent &event, SpectralData *pData)
Definition: SpectrumView.cpp:1019
PrefsPanel::Factories
std::vector< PrefsPanel::PrefsNode > Factories
Definition: PrefsPanel.h:69
WaveTrackPopupMenuTable::ReserveId
int ReserveId()
Definition: WaveTrackControls.h:78
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
AColor::ColorGradientChoice
ColorGradientChoice
Definition: AColor.h:28
PrefsDialog::PrefsDialog
PrefsDialog(wxWindow *parent, AudacityProject *pProject, const TranslatableString &titlePrefix=XO("Preferences:"), PrefsPanel::Factories &factories=PrefsPanel::DefaultFactories())
Definition: PrefsDialog.cpp:446
anonymous_namespace{SpectrumView.cpp}::DrawClipSpectrum
void DrawClipSpectrum(TrackPanelDrawingContext &context, WaveTrackCache &waveTrackCache, const WaveClip *clip, const wxRect &rect, const std::shared_ptr< SpectralData > &mpSpectralData, bool selected)
Definition: SpectrumView.cpp:308
BrushHandle::StateSaver
Definition: BrushHandle.h:37
NumberScale::Iterator
Definition: NumberScale.h:178
SpectrumView.h
AColor::ColorGradientEdge
@ ColorGradientEdge
Definition: AColor.h:32
TrackPanelDrawable::Draw
virtual void Draw(TrackPanelDrawingContext &context, const wxRect &rect, unsigned iPass)
Definition: TrackPanelDrawable.cpp:17