mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-18 09:00:07 +02:00
Use class NumberScale in TrackArtist and spectral selection, abstracting...
... the details of mapping to and from pixel height
This commit is contained in:
parent
045828d744
commit
43b7df701b
@ -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);
|
||||
|
||||
|
@ -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<const WaveTrack*>(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<WaveTrack*>(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<WaveTrack*>(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<const WaveTrack*>(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,
|
||||
|
@ -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 {
|
||||
|
@ -15,6 +15,7 @@ Paul Licameli
|
||||
|
||||
#include "../Audacity.h"
|
||||
#include "SpectrogramSettings.h"
|
||||
#include "../NumberScale.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <wx/msgdlg.h>
|
||||
@ -23,7 +24,6 @@ Paul Licameli
|
||||
#include "../Prefs.h"
|
||||
#include "../RealFFTf.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
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
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user