From 43b7df701bf5a80c177c2cd5dec467a905ebdb1c Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Tue, 16 Jun 2015 12:46:55 -0400 Subject: [PATCH] Use class NumberScale in TrackArtist and spectral selection, abstracting... ... the details of mapping to and from pixel height --- src/TrackArtist.cpp | 278 ++++++++++++------------------ src/TrackPanel.cpp | 90 +++------- src/TrackPanel.h | 6 +- src/prefs/SpectrogramSettings.cpp | 38 +++- src/prefs/SpectrogramSettings.h | 5 + 5 files changed, 173 insertions(+), 244 deletions(-) diff --git a/src/TrackArtist.cpp b/src/TrackArtist.cpp index b23940050..af76192d8 100644 --- a/src/TrackArtist.cpp +++ b/src/TrackArtist.cpp @@ -168,6 +168,7 @@ audio tracks. #include "AColor.h" #include "BlockFile.h" #include "Envelope.h" +#include "NumberScale.h" #include "Track.h" #include "WaveTrack.h" #include "LabelTrack.h" @@ -2036,7 +2037,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache, const int display = track->GetDisplay(); const bool autocorrelation = (WaveTrack::PitchDisplay == display); - const bool logF = settings.scaleType == SpectrogramSettings::stLogarithmic; enum { DASH_LENGTH = 10 /* pixels */ }; @@ -2115,15 +2115,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache, scaleType == SpectrogramSettings::stLinear ? settings.GetMaxFreq(rate) : settings.GetLogMaxFreq(rate); - float minBin = ((double)minFreq / binUnit); - float maxBin = ((double)maxFreq / binUnit); - float binPerPx = float(maxBin - minBin) / float(mid.height); - - const float - // e=exp(1.0f), - lmin = logf(float(minFreq)), - lmax = logf(float(maxFreq)), - scale = lmax - lmin; + const NumberScale numberScale(settings.GetScale(rate, true, autocorrelation)); #ifdef EXPERIMENTAL_FFT_Y_GRID const float @@ -2204,135 +2196,124 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache, int *indexes = new int[maxTableSize]; #endif //EXPERIMENTAL_FIND_NOTES - for (int xx = 0; xx < hiddenMid.width; ++xx) - { - if (!logF) { - for (int yy = 0; yy < hiddenMid.height; ++yy) { - float bin0 = float(yy) * binPerPx + minBin; - float bin1 = float(yy + 1) * binPerPx + minBin; + for (int xx = 0; xx < hiddenMid.width; ++xx) { + NumberScale::Iterator it = numberScale.begin(mid.height); + float nextBin = std::max(0.0f, std::min(float(half - 1), *it)); + for (int yy = 0; yy < hiddenMid.height; ++yy) { + const float bin = nextBin; + nextBin = std::max(0.0f, std::min(float(half - 1), *++it)); + + if (settings.scaleType != SpectrogramSettings::stLogarithmic) { const float value = findValue - (freq + half * xx, bin0, bin1, half, autocorrelation, gain, range); + (freq + half * xx, bin, nextBin, half, autocorrelation, gain, range); clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value; } - } - else { + else { + // Do we need this legacy experiment still? #ifdef EXPERIMENTAL_FIND_NOTES - int maximas=0; - const int x0 = half * xx; - if (fftFindNotes) { - for (int i = maxTableSize-1; i >= 0; i--) - indexes[i]=-1; + int maximas = 0; + const int x0 = half * x; + if (fftFindNotes) { + for (int i = maxTableSize - 1; i >= 0; i--) + indexes[i] = -1; - // Build a table of (most) values, put the index in it. - for (int i = int(i0); i < int(i1); i++) { - float freqi=freq[x0 + int(i)]; - int value=int((freqi+gain+range)/range*(maxTableSize-1)); - if (value < 0) - value=0; - if (value >= maxTableSize) - value=maxTableSize-1; - indexes[value]=i; - } - // Build from the indices an array of maxima. - for (int i = maxTableSize - 1; i >= 0; i--) { - int index = indexes[i]; - if (index >= 0) { - float freqi = freq[x0 + index]; - if (freqi < findNotesMinA) - break; - - bool ok = true; - for (int m = 0; m < maximas; m++) { - // Avoid to store very close maxima. - float maxm = maxima[m]; - if (maxm / index < minDistance && index / maxm < minDistance) { - ok = false; + // Build a table of (most) values, put the index in it. + for (int i = int(i0); i < int(i1); i++) { + float freqi = freq[x0 + int(i)]; + int value = int((freqi + gain + range) / range*(maxTableSize - 1)); + if (value < 0) + value = 0; + if (value >= maxTableSize) + value = maxTableSize - 1; + indexes[value] = i; + } + // Build from the indices an array of maxima. + for (int i = maxTableSize - 1; i >= 0; i--) { + int index = indexes[i]; + if (index >= 0) { + float freqi = freq[x0 + index]; + if (freqi < findNotesMinA) break; + + bool ok = true; + for (int m = 0; m < maximas; m++) { + // Avoid to store very close maxima. + float maxm = maxima[m]; + if (maxm / index < minDistance && index / maxm < minDistance) { + ok = false; + break; + } + } + if (ok) { + maxima[maximas++] = index; + if (maximas >= numberOfMaxima) + break; } } - if (ok) { - maxima[maximas++] = index; - if (maximas >= numberOfMaxima) - break; - } } - } // The f2pix helper macro converts a frequency into a pixel coordinate. #define f2pix(f) (logf(f)-lmins)/(lmaxs-lmins)*hiddenMid.height - // Possibly quantize the maxima frequencies and create the pixel block limits. - for (int i=0; i < maximas; i++) { - int index=maxima[i]; - float f = float(index)*bin2f; - if (findNotesQuantize) - { f = expf(int(log(f/440)/log2*12-0.5)/12.0f*log2)*440; - maxima[i] = f*f2bin; + // Possibly quantize the maxima frequencies and create the pixel block limits. + for (int i = 0; i < maximas; i++) { + int index = maxima[i]; + float f = float(index)*bin2f; + if (findNotesQuantize) + { + f = expf(int(log(f / 440) / log2 * 12 - 0.5) / 12.0f*log2) * 440; + maxima[i] = f*f2bin; + } + float f0 = expf((log(f / 440) / log2 * 24 - 1) / 24.0f*log2) * 440; + maxima0[i] = f2pix(f0); + float f1 = expf((log(f / 440) / log2 * 24 + 1) / 24.0f*log2) * 440; + maxima1[i] = f2pix(f1); } - float f0 = expf((log(f/440)/log2*24-1)/24.0f*log2)*440; - maxima0[i] = f2pix(f0); - float f1 = expf((log(f/440)/log2*24+1)/24.0f*log2)*440; - maxima1[i] = f2pix(f1); } - } - int it=0; - int oldBin0=-1; - bool inMaximum = false; + int it = 0; + int oldBin0 = -1; + bool inMaximum = false; #endif //EXPERIMENTAL_FIND_NOTES - double yy2_base = exp(lmin) / binUnit; - float yy2 = yy2_base; - double exp_scale_per_height = exp(scale / hiddenMid.height); - for (int yy = 0; yy < hiddenMid.height; ++yy) { - if (int(yy2) >= half) - yy2=half-1; - if (yy2<0) - yy2=0; - float bin0 = float(yy2); - yy2_base *= exp_scale_per_height; - float yy3 = yy2_base; - if (int(yy3)>=half) - yy3=half-1; - if (yy3<0) - yy3=0; - float bin1 = float(yy3); float value; #ifdef EXPERIMENTAL_FIND_NOTES if (fftFindNotes) { if (it < maximas) { - float i0=maxima0[it]; + float i0 = maxima0[it]; if (yy >= i0) inMaximum = true; if (inMaximum) { - float i1=maxima1[it]; - if (yy+1 <= i1) { - value=findValue(freq + x0, bin0, bin1, half, autocorrelation, gain, range); + float i1 = maxima1[it]; + if (yy + 1 <= i1) { + value = findValue(freq + x0, bin, nextBin, half, autocorrelation, gain, range); if (value < findNotesMinA) value = minColor; - } else { + } + else { it++; inMaximum = false; value = minColor; } - } else { + } + else { value = minColor; } - } else + } + else value = minColor; - } else + } + else #endif //EXPERIMENTAL_FIND_NOTES { value = findValue - (freq + half * xx, bin0, bin1, half, autocorrelation, gain, range); + (freq + half * xx, bin, nextBin, half, autocorrelation, gain, range); } clip->mSpecPxCache->values[xx * hiddenMid.height + yy] = value; - yy2 = yy2_base; - } // each yy - } // is logF + } // logF + } // each yy } // each xx - } // updating cache float selBinLo = freqLo / binUnit; @@ -2384,85 +2365,42 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache, (zoomInfo.PositionToTime(xx + 1, -leftOffset) - tOffset) ); - // TODO: The logF and non-logF case are very similar. - // They should be merged and simplified. - if (!logF) - { - for (int yy = 0; yy < hiddenMid.height; ++yy) { - float bin0 = float(yy) * binPerPx + minBin; - float bin1 = float(yy + 1) * binPerPx + minBin; + NumberScale::Iterator it = numberScale.begin(mid.height); + float nextBin = std::max(0.0f, std::min(float(half - 1), *it)); + for (int yy = 0; yy < hiddenMid.height; ++yy) { + const float bin = nextBin; + nextBin = std::max(0.0f, std::min(float(half - 1), *++it)); - // For spectral selection, determine what colour - // set to use. We use a darker selection if - // in both spectral range and time range. + // For spectral selection, determine what colour + // set to use. We use a darker selection if + // in both spectral range and time range. - AColor::ColorGradientChoice selected = - AColor::ColorGradientUnselected; - // If we are in the time selected range, then we may use a different color set. - if (ssel0 <= w0 && w1 < ssel1) - selected = ChooseColorSet(bin0, bin1, selBinLo, selBinCenter, selBinHi, + AColor::ColorGradientChoice selected = AColor::ColorGradientUnselected; + // If we are in the time selected range, then we may use a different color set. + if (ssel0 <= w0 && w1 < ssel1) + selected = + ChooseColorSet(bin, nextBin, selBinLo, selBinCenter, selBinHi, (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral); - - unsigned char rv, gv, bv; - const float value = uncached - ? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range) - : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy]; - GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); - int px = ((mid.height - 1 - yy) * mid.width + xx) * 3; - data[px++] = rv; - data[px++] = gv; - data[px] = bv; - } - } - else //logF - { - double yy2_base=exp(lmin)/binUnit; - float yy2 = yy2_base; - double exp_scale_per_height = exp(scale / hiddenMid.height); - for (int yy = 0; yy < hiddenMid.height; ++yy) { - if (int(yy2)>=half) - yy2=half-1; - if (yy2<0) - yy2=0; - float bin0 = float(yy2); - yy2_base *= exp_scale_per_height; - float yy3 = yy2_base; - if (int(yy3)>=half) - yy3=half-1; - if (yy3<0) - yy3=0; - float bin1 = float(yy3); - - AColor::ColorGradientChoice selected = AColor::ColorGradientUnselected; - // If we are in the time selected range, then we may use a different color set. - if (ssel0 <= w0 && w1 < ssel1) - selected = ChooseColorSet( - bin0, bin1, selBinLo, selBinCenter, selBinHi, - (xx + leftOffset - hiddenLeftOffset) / DASH_LENGTH, isSpectral); - - unsigned char rv, gv, bv; - const float value = uncached - ? findValue(uncached, bin0, bin1, half, autocorrelation, gain, range) - : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy]; - GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); + const float value = uncached + ? findValue(uncached, bin, nextBin, half, autocorrelation, gain, range) + : clip->mSpecPxCache->values[correctedX * hiddenMid.height + yy]; + unsigned char rv, gv, bv; + GetColorGradient(value, selected, isGrayscale, &rv, &gv, &bv); #ifdef EXPERIMENTAL_FFT_Y_GRID - if (fftYGrid && yGrid[yy]) { - rv /= 1.1f; - gv /= 1.1f; - bv /= 1.1f; - } + if (fftYGrid && yGrid[yy]) { + rv /= 1.1f; + gv /= 1.1f; + bv /= 1.1f; + } #endif //EXPERIMENTAL_FFT_Y_GRID - int px = ((mid.height - 1 - yy) * mid.width + xx) * 3; - data[px++] = rv; - data[px++] = gv; - data[px] = bv; - - yy2 = yy2_base; - } - } - } + int px = ((mid.height - 1 - yy) * mid.width + xx) * 3; + data[px++] = rv; + data[px++] = gv; + data[px] = bv; + } // each yy + } // each xx wxBitmap converted = wxBitmap(*image); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index ea113b475..382fbb40f 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -201,6 +201,7 @@ is time to refresh some aspect of the screen. #include "MixerBoard.h" #include "NoteTrack.h" +#include "NumberScale.h" #include "Prefs.h" #include "Project.h" #include "Snap.h" @@ -1802,22 +1803,15 @@ void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT, namespace { // This returns true if we're a spectral editing track. -inline bool isSpectralSelectionTrack(const Track *pTrack, bool *pLogf = NULL) { +inline bool isSpectralSelectionTrack(const Track *pTrack) { if (pTrack && pTrack->GetKind() == Track::Wave) { const WaveTrack *const wt = static_cast(pTrack); const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); const int display = wt->GetDisplay(); - if (pLogf) { - const bool logF = - settings.scaleType == SpectrogramSettings::stLogarithmic; - *pLogf = logF; - } return (display == WaveTrack::Spectrum) && settings.SpectralSelectionEnabled(); } else { - if (pLogf) - *pLogf = false; return false; } } @@ -1941,9 +1935,8 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t, const bool bShiftDown = event.ShiftDown(); #ifdef EXPERIMENTAL_SPECTRAL_EDITING - bool logF; if ( (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) && - isSpectralSelectionTrack(t, &logF)) { + isSpectralSelectionTrack(t)) { // Not shift-down, but center frequency snapping toggle is on *ppTip = _("Click and drag to set frequency bandwidth."); *ppCursor = mEnvelopeCursor; @@ -2679,9 +2672,8 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event, // preferences now if (mAdjustSelectionEdges) { #ifdef EXPERIMENTAL_SPECTRAL_EDITING - bool logF; if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER && - isSpectralSelectionTrack(pTrack, &logF)) { + isSpectralSelectionTrack(pTrack)) { // Ignore whether we are inside the time selection. // Exit center-snapping, start dragging the width. mFreqSelMode = FREQ_SEL_PINNED_CENTER; @@ -3072,10 +3064,9 @@ void TrackPanel::MoveSnappingFreqSelection (int mouseYCoordinate, int trackTopEdge, int trackHeight, Track *pTrack) { - bool logF; if (pTrack && pTrack->GetSelected() && - isSpectralSelectionTrack(pTrack, &logF)) { + isSpectralSelectionTrack(pTrack)) { WaveTrack *const wt = static_cast(pTrack); // PRL: // What happens if center snapping selection began in one spectrogram track, @@ -3086,7 +3077,7 @@ void TrackPanel::MoveSnappingFreqSelection (int mouseYCoordinate, const double rate = wt->GetRate(); const double frequency = PositionToFrequency(wt, false, mouseYCoordinate, - trackTopEdge, trackHeight, logF); + trackTopEdge, trackHeight); const double snappedFrequency = mFrequencySnapper->FindPeak(frequency, NULL); const double maxRatio = findMaxRatio(snappedFrequency, rate); @@ -3118,13 +3109,12 @@ void TrackPanel::StartFreqSelection (int mouseYCoordinate, int trackTopEdge, mFreqSelMode = FREQ_SEL_INVALID; mFreqSelPin = SelectedRegion::UndefinedFrequency; - bool logF; - if (isSpectralSelectionTrack(pTrack, &logF)) { + if (isSpectralSelectionTrack(pTrack)) { mFreqSelTrack = static_cast(pTrack); mFreqSelMode = FREQ_SEL_FREE; mFreqSelPin = PositionToFrequency(mFreqSelTrack, false, mouseYCoordinate, - trackTopEdge, trackHeight, logF); + trackTopEdge, trackHeight); mViewInfo->selectedRegion.setFrequencies(mFreqSelPin, mFreqSelPin); } } @@ -3143,12 +3133,10 @@ void TrackPanel::ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge, // started, and that is of a spectrogram display type. const WaveTrack* wt = mFreqSelTrack; - const bool logF = - wt->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLogarithmic; const double rate = wt->GetRate(); const double frequency = PositionToFrequency(wt, true, mouseYCoordinate, - trackTopEdge, trackHeight, logF); + trackTopEdge, trackHeight); // Dragging center? if (mFreqSelMode == FREQ_SEL_DRAG_CENTER) { @@ -3527,8 +3515,7 @@ double TrackPanel::PositionToFrequency(const WaveTrack *wt, bool maySnap, wxInt64 mouseYCoordinate, wxInt64 trackTopEdge, - int trackHeight, - bool logF) const + int trackHeight) const { const double rate = wt->GetRate(); @@ -3540,57 +3527,23 @@ double TrackPanel::PositionToFrequency(const WaveTrack *wt, trackTopEdge + trackHeight - mouseYCoordinate < FREQ_SNAP_DISTANCE) return -1; + const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); + const NumberScale numberScale(settings.GetScale(rate, false, false)); const double p = double(mouseYCoordinate - trackTopEdge) / trackHeight; - - if (logF) - { - const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); - const double maxFreq = settings.GetLogMaxFreq(rate); - const double minFreq = settings.GetLogMinFreq(rate); - return exp(p * log(minFreq) + (1.0 - p) * log(maxFreq)); - } - else - { - const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); - const double maxFreq = settings.GetMaxFreq(rate); - const double minFreq = settings.GetMinFreq(rate); - return p * minFreq + (1.0 - p) * maxFreq; - } + return numberScale.PositionToValue(1.0 - p); } /// Converts a frequency to screen y position. wxInt64 TrackPanel::FrequencyToPosition(const WaveTrack *wt, double frequency, wxInt64 trackTopEdge, - int trackHeight, - bool logF) const + int trackHeight) const { const double rate = wt->GetRate(); - double p = 0; - - if (logF) - { - const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); - const double maxFreq = settings.GetLogMaxFreq(rate); - const double minFreq = settings.GetLogMinFreq(rate); - if (maxFreq > minFreq) - { - const double - logFrequency = log(frequency < 1.0 ? 1.0 : frequency), - logMinFreq = log(minFreq), - logMaxFreq = log(maxFreq); - p = (logFrequency - logMinFreq) / (logMaxFreq - logMinFreq); - } - } - else - { - const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); - const double maxFreq = settings.GetMaxFreq(rate); - const double minFreq = settings.GetMinFreq(rate); - if (maxFreq > minFreq) - p = (frequency - minFreq) / (maxFreq - minFreq); - } + const SpectrogramSettings &settings = wt->GetSpectrogramSettings(); + const NumberScale numberScale(settings.GetScale(rate, false, false)); + const float p = numberScale.ValueToPosition(frequency); return trackTopEdge + wxInt64((1.0 - p) * trackHeight); } #endif @@ -3671,18 +3624,17 @@ bool mayDragWidth, bool onlyWithinSnapDistance, bool chooseTime = true; bool chooseBottom = true; bool chooseCenter = false; - bool logF; // Consider adjustment of frequencies only if mouse is // within the time boundaries if (!mViewInfo->selectedRegion.isPoint() && t0 <= selend && selend < t1 && - isSpectralSelectionTrack(pTrack, &logF)) { + isSpectralSelectionTrack(pTrack)) { const WaveTrack *const wt = static_cast(pTrack); const wxInt64 bottomSel = (f0 >= 0) - ? FrequencyToPosition(wt, f0, rect.y, rect.height, logF) + ? FrequencyToPosition(wt, f0, rect.y, rect.height) : rect.y + rect.height; const wxInt64 topSel = (f1 >= 0) - ? FrequencyToPosition(wt, f1, rect.y, rect.height, logF) + ? FrequencyToPosition(wt, f1, rect.y, rect.height) : rect.y; wxInt64 signedBottomDist = int(event.m_y - bottomSel); wxInt64 verticalDist = abs(signedBottomDist); @@ -3700,7 +3652,7 @@ bool mayDragWidth, bool onlyWithinSnapDistance, #endif ) { const wxInt64 centerSel = - FrequencyToPosition(wt, fc, rect.y, rect.height, logF); + FrequencyToPosition(wt, fc, rect.y, rect.height); const wxInt64 centerDist = abs(int(event.m_y - centerSel)); if (centerDist < verticalDist) chooseCenter = true, verticalDist = centerDist, diff --git a/src/TrackPanel.h b/src/TrackPanel.h index c93eaab3c..d5cdc578c 100644 --- a/src/TrackPanel.h +++ b/src/TrackPanel.h @@ -698,13 +698,11 @@ protected: bool maySnap, wxInt64 mouseYCoordinate, wxInt64 trackTopEdge, - int trackHeight, - bool logF) const; + int trackHeight) const; wxInt64 FrequencyToPosition(const WaveTrack *wt, double frequency, wxInt64 trackTopEdge, - int trackHeight, - bool logF) const; + int trackHeight) const; #endif enum SelectionBoundary { diff --git a/src/prefs/SpectrogramSettings.cpp b/src/prefs/SpectrogramSettings.cpp index 173d2f58a..e6e126dd2 100644 --- a/src/prefs/SpectrogramSettings.cpp +++ b/src/prefs/SpectrogramSettings.cpp @@ -15,6 +15,7 @@ Paul Licameli #include "../Audacity.h" #include "SpectrogramSettings.h" +#include "../NumberScale.h" #include #include @@ -23,7 +24,6 @@ Paul Licameli #include "../Prefs.h" #include "../RealFFTf.h" -#include #include SpectrogramSettings::Globals::Globals() @@ -524,6 +524,42 @@ int SpectrogramSettings::GetFFTLength(bool autocorrelation) const ; } +NumberScale SpectrogramSettings::GetScale +(double rate, bool bins, bool autocorrelation) const +{ + int minFreq, maxFreq; + NumberScaleType type = nstLinear; + + // Don't assume the correspondence of the enums will remain direct in the future. + // Do this switch. + switch (scaleType) { + default: + wxASSERT(false); + case stLinear: + type = nstLinear; break; + case stLogarithmic: + type = nstLogarithmic; break; + } + + switch (scaleType) { + default: + wxASSERT(false); + case stLinear: + minFreq = GetMinFreq(rate); + maxFreq = GetMaxFreq(rate); + break; + case stLogarithmic: + minFreq = GetLogMinFreq(rate); + maxFreq = GetLogMaxFreq(rate); + break; + } + + const int half = GetFFTLength(autocorrelation) / 2; + + return NumberScale(type, minFreq, maxFreq, + bins ? rate / (2 * half) : 1.0f); +} + bool SpectrogramSettings::SpectralSelectionEnabled() const { #ifdef SPECTRAL_SELECTION_GLOBAL_SWITCH diff --git a/src/prefs/SpectrogramSettings.h b/src/prefs/SpectrogramSettings.h index 3f4a34dca..a3af7d08c 100644 --- a/src/prefs/SpectrogramSettings.h +++ b/src/prefs/SpectrogramSettings.h @@ -16,6 +16,7 @@ Paul Licameli #undef SPECTRAL_SELECTION_GLOBAL_SWITCH struct FFTParam; +class NumberScale; class SpectrumPrefs; class wxArrayString; @@ -80,6 +81,10 @@ public: void ConvertToEnumeratedWindowSizes(); void ConvertToActualWindowSizes(); + // If "bins" is false, units are Hz + NumberScale SpectrogramSettings::GetScale + (double rate, bool bins, bool autocorrelation) const; + private: int minFreq; int maxFreq;