mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-25 16:48:44 +02:00
Other spectrogram scales, easily defined!! -- and include bug fixes 1038, 1039
This commit is contained in:
commit
981acf0bd2
@ -171,6 +171,7 @@ audacity_SOURCES = \
|
||||
MixerBoard.h \
|
||||
ModuleManager.cpp \
|
||||
ModuleManager.h \
|
||||
NumberScale.h \
|
||||
PitchName.cpp \
|
||||
PitchName.h \
|
||||
PlatformCompatibility.cpp \
|
||||
|
279
src/NumberScale.h
Normal file
279
src/NumberScale.h
Normal file
@ -0,0 +1,279 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
NumberScale.h
|
||||
|
||||
Paul Licameli
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef __AUDACITY_NUMBER_SCALE__
|
||||
#define __AUDACITY_NUMBER_SCALE__
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <wx/defs.h>
|
||||
#include <wx/debug.h>
|
||||
|
||||
enum NumberScaleType {
|
||||
nstLinear,
|
||||
nstLogarithmic,
|
||||
nstMel,
|
||||
nstBark,
|
||||
nstErb,
|
||||
nstUndertone,
|
||||
|
||||
nstNumScaleTypes,
|
||||
};
|
||||
|
||||
|
||||
class NumberScale
|
||||
{
|
||||
public:
|
||||
NumberScale(NumberScaleType type,
|
||||
float value0, float value1, float unit)
|
||||
: mType(type)
|
||||
{
|
||||
switch (mType) {
|
||||
case nstLinear:
|
||||
{
|
||||
mValue0 = value0 / unit;
|
||||
mValue1 = value1 / unit;
|
||||
mUnit = 1.0;
|
||||
}
|
||||
break;
|
||||
case nstLogarithmic:
|
||||
{
|
||||
mValue0 = logf(value0 / unit);
|
||||
mValue1 = logf(value1 / unit);
|
||||
mUnit = 1.0;
|
||||
}
|
||||
break;
|
||||
case nstMel:
|
||||
{
|
||||
mValue0 = hzToMel(value0);
|
||||
mValue1 = hzToMel(value1);
|
||||
mUnit = unit;
|
||||
}
|
||||
break;
|
||||
case nstBark:
|
||||
{
|
||||
mValue0 = hzToBark(value0);
|
||||
mValue1 = hzToBark(value1);
|
||||
mUnit = unit;
|
||||
}
|
||||
break;
|
||||
case nstErb:
|
||||
{
|
||||
mValue0 = hzToErb(value0);
|
||||
mValue1 = hzToErb(value1);
|
||||
mUnit = unit;
|
||||
}
|
||||
break;
|
||||
case nstUndertone:
|
||||
{
|
||||
mValue0 = hzToUndertone(value0);
|
||||
mValue1 = hzToUndertone(value1);
|
||||
mUnit = unit;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wxASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
NumberScale Reversal() const
|
||||
{
|
||||
NumberScale result(*this);
|
||||
std::swap(result.mValue0, result.mValue1);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator == (const NumberScale& other) const
|
||||
{
|
||||
return mType == other.mType
|
||||
&& mValue0 == other.mValue0
|
||||
&& mValue1 == other.mValue1
|
||||
&& mUnit == other.mUnit;
|
||||
}
|
||||
|
||||
bool operator != (const NumberScale &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static inline float hzToMel(float hz)
|
||||
{
|
||||
return 1127 * log(1 + hz / 700);
|
||||
}
|
||||
|
||||
static inline float melToHz(float mel)
|
||||
{
|
||||
return 700 * (exp(mel / 1127) - 1);
|
||||
}
|
||||
|
||||
static inline float hzToBark(float hz)
|
||||
{
|
||||
// Traunmueller's formula
|
||||
const float z1 = 26.81 * hz / (1960 + hz) - 0.53;
|
||||
if (z1 < 2.0)
|
||||
return z1 + 0.15 * (2.0 - z1);
|
||||
else if (z1 > 20.1)
|
||||
return z1 + 0.22 * (z1 - 20.1);
|
||||
else
|
||||
return z1;
|
||||
}
|
||||
|
||||
static inline float barkToHz(float z1)
|
||||
{
|
||||
if (z1 < 2.0)
|
||||
z1 = 2.0 + (z1 - 2.0) / 0.85;
|
||||
else if (z1 > 20.1)
|
||||
z1 = 20.1 + (z1 - 20.1) / 1.22;
|
||||
return 1960 * (z1 + 0.53) / (26.28 - z1);
|
||||
}
|
||||
|
||||
static inline float hzToErb(float hz)
|
||||
{
|
||||
return 11.17268 * log(1 + (46.06538 * hz) / (hz + 14678.49));
|
||||
}
|
||||
|
||||
static inline float erbToHz(float erb)
|
||||
{
|
||||
return 676170.4 / (47.06538 - exp(0.08950404 * erb)) - 14678.49;
|
||||
}
|
||||
|
||||
static inline float hzToUndertone(float hz)
|
||||
{
|
||||
return -1.0 / std::max (1.0f, hz);
|
||||
}
|
||||
|
||||
static inline float undertoneToHz(float u)
|
||||
{
|
||||
return -1.0 / u;
|
||||
}
|
||||
|
||||
// Random access
|
||||
float PositionToValue(float pp) const
|
||||
{
|
||||
switch (mType) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
return mValue0 + pp * (mValue1 - mValue0);
|
||||
case nstLogarithmic:
|
||||
return exp(mValue0 + pp * (mValue1 - mValue0));
|
||||
case nstMel:
|
||||
return melToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
|
||||
case nstBark:
|
||||
return barkToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
|
||||
case nstErb:
|
||||
return erbToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
|
||||
case nstUndertone:
|
||||
return undertoneToHz(mValue0 + pp * (mValue1 - mValue0)) / mUnit;
|
||||
}
|
||||
}
|
||||
|
||||
// STL-idiom iteration
|
||||
|
||||
class Iterator
|
||||
{
|
||||
public:
|
||||
Iterator(NumberScaleType type, float step, float value, float unit)
|
||||
: mType(type), mStep(step), mValue(value), mUnit(unit)
|
||||
{
|
||||
}
|
||||
|
||||
float operator * () const
|
||||
{
|
||||
switch (mType) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstLogarithmic:
|
||||
return mValue;
|
||||
case nstMel:
|
||||
return melToHz(mValue) / mUnit;
|
||||
case nstBark:
|
||||
return barkToHz(mValue) / mUnit;
|
||||
case nstErb:
|
||||
return erbToHz(mValue) / mUnit;
|
||||
case nstUndertone:
|
||||
return undertoneToHz(mValue) / mUnit;
|
||||
}
|
||||
}
|
||||
|
||||
Iterator &operator ++()
|
||||
{
|
||||
switch (mType) {
|
||||
case nstLinear:
|
||||
case nstMel:
|
||||
case nstBark:
|
||||
case nstErb:
|
||||
case nstUndertone:
|
||||
mValue += mStep;
|
||||
break;
|
||||
case nstLogarithmic:
|
||||
mValue *= mStep;
|
||||
break;
|
||||
default:
|
||||
wxASSERT(false);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const NumberScaleType mType;
|
||||
const float mStep;
|
||||
float mValue;
|
||||
float mUnit;
|
||||
};
|
||||
|
||||
Iterator begin(float nPositions) const
|
||||
{
|
||||
switch (mType) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
case nstMel:
|
||||
case nstBark:
|
||||
case nstErb:
|
||||
case nstUndertone:
|
||||
return Iterator
|
||||
(mType, (mValue1 - mValue0) / nPositions, mValue0, mUnit);
|
||||
case nstLogarithmic:
|
||||
return Iterator
|
||||
(mType, exp((mValue1 - mValue0) / nPositions), exp(mValue0), mUnit);
|
||||
}
|
||||
}
|
||||
|
||||
// Inverse
|
||||
float ValueToPosition(float val) const
|
||||
{
|
||||
switch (mType) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case nstLinear:
|
||||
return ((val - mValue0) / (mValue1 - mValue0));
|
||||
case nstLogarithmic:
|
||||
return ((log(val) - mValue0) / (mValue1 - mValue0));
|
||||
case nstMel:
|
||||
return ((hzToMel(val * mUnit) - mValue0) / (mValue1 - mValue0));
|
||||
case nstBark:
|
||||
return ((hzToBark(val * mUnit) - mValue0) / (mValue1 - mValue0));
|
||||
case nstErb:
|
||||
return ((hzToErb(val * mUnit) - mValue0) / (mValue1 - mValue0));
|
||||
case nstUndertone:
|
||||
return ((hzToUndertone(val * mUnit) - mValue0) / (mValue1 - mValue0));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const NumberScaleType mType;
|
||||
float mValue0;
|
||||
float mValue1;
|
||||
float mUnit;
|
||||
};
|
||||
|
||||
#endif
|
@ -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"
|
||||
@ -829,6 +830,10 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect)
|
||||
}
|
||||
break;
|
||||
case SpectrogramSettings::stLogarithmic:
|
||||
case SpectrogramSettings::stMel:
|
||||
case SpectrogramSettings::stBark:
|
||||
case SpectrogramSettings::stErb:
|
||||
case SpectrogramSettings::stUndertone:
|
||||
{
|
||||
// SpectrumLog
|
||||
|
||||
@ -852,6 +857,9 @@ void TrackArtist::UpdateVRuler(Track *t, wxRect & rect)
|
||||
vruler->SetRange(maxFreq, minFreq);
|
||||
vruler->SetUnits(wxT(""));
|
||||
vruler->SetLog(true);
|
||||
NumberScale scale
|
||||
(wt->GetSpectrogramSettings().GetScale(wt->GetRate(), false, false).Reversal());
|
||||
vruler->SetNumberScale(&scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2036,7 +2044,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 +2122,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,21 +2203,23 @@ 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 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) {
|
||||
float bin0 = float(yy) * binPerPx + minBin;
|
||||
float bin1 = float(yy + 1) * binPerPx + minBin;
|
||||
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 {
|
||||
// Do we need this legacy experiment still?
|
||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||
int maximas = 0;
|
||||
const int x0 = half * xx;
|
||||
const int x0 = half * x;
|
||||
if (fftFindNotes) {
|
||||
for (int i = maxTableSize - 1; i >= 0; i--)
|
||||
indexes[i] = -1;
|
||||
@ -2266,7 +2267,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
|
||||
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;
|
||||
{
|
||||
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;
|
||||
@ -2280,22 +2282,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
|
||||
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
|
||||
@ -2308,31 +2294,33 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
|
||||
if (inMaximum) {
|
||||
float i1 = maxima1[it];
|
||||
if (yy + 1 <= i1) {
|
||||
value=findValue(freq + x0, bin0, bin1, half, autocorrelation, gain, range);
|
||||
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;
|
||||
} // logF
|
||||
} // each yy
|
||||
} // is logF
|
||||
} // each xx
|
||||
|
||||
} // updating cache
|
||||
|
||||
float selBinLo = freqLo / binUnit;
|
||||
@ -2384,66 +2372,26 @@ 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)
|
||||
{
|
||||
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) {
|
||||
float bin0 = float(yy) * binPerPx + minBin;
|
||||
float bin1 = float(yy + 1) * binPerPx + minBin;
|
||||
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.
|
||||
|
||||
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);
|
||||
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,
|
||||
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)
|
||||
? 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
|
||||
@ -2458,11 +2406,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrackCache &waveTrackCache,
|
||||
data[px++] = rv;
|
||||
data[px++] = gv;
|
||||
data[px] = bv;
|
||||
|
||||
yy2 = yy2_base;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // 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 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,
|
||||
@ -4641,7 +4593,6 @@ void TrackPanel::HandleVZoomDrag( wxMouseEvent & event )
|
||||
/// - Zoom in; ensure we don't go too large.
|
||||
void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
{
|
||||
int minBins = 0;
|
||||
if (!mCapturedTrack)
|
||||
return;
|
||||
|
||||
@ -4671,6 +4622,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
// don't do anything if track is not wave
|
||||
if (mCapturedTrack->GetKind() != Track::Wave)
|
||||
return;
|
||||
|
||||
WaveTrack *track = static_cast<WaveTrack*>(mCapturedTrack);
|
||||
WaveTrack *partner = static_cast<WaveTrack *>(mTracks->GetLink(track));
|
||||
int height = track->GetHeight();
|
||||
@ -4683,71 +4635,58 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
mZoomStart = temp;
|
||||
}
|
||||
|
||||
float min, max, c, l, binSize = 0.0;
|
||||
float min, max, c, l, minBand = 0;
|
||||
const double rate = track->GetRate();
|
||||
const float halfrate = rate / 2;
|
||||
const SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
NumberScale scale(track->GetSpectrogramSettings().GetScale(rate, false, false));
|
||||
const bool spectral = (track->GetDisplay() == WaveTrack::Spectrum);
|
||||
const bool spectrumLinear = spectral &&
|
||||
(track->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLinear);
|
||||
const bool spectrumLog = spectral &&
|
||||
(track->GetSpectrogramSettings().scaleType == SpectrogramSettings::stLogarithmic);
|
||||
|
||||
if (spectral) {
|
||||
if (spectrumLinear) {
|
||||
const SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
min = settings.GetMinFreq(rate);
|
||||
max = settings.GetMaxFreq(rate);
|
||||
const int fftLength = settings.GetFFTLength(false);
|
||||
binSize = rate / fftLength;
|
||||
minBins = std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
|
||||
}
|
||||
else if (spectrumLog) {
|
||||
const SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
else {
|
||||
min = settings.GetLogMinFreq(rate);
|
||||
max = settings.GetLogMaxFreq(rate);
|
||||
}
|
||||
const int fftLength = settings.GetFFTLength(false);
|
||||
binSize = rate / fftLength;
|
||||
minBins = std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
|
||||
const float binSize = rate / fftLength;
|
||||
const int minBins =
|
||||
std::min(10, fftLength / 2); //minimum 10 freq bins, unless there are less
|
||||
minBand = minBins * binSize;
|
||||
}
|
||||
else
|
||||
track->GetDisplayBounds(&min, &max);
|
||||
|
||||
if (IsDragZooming()) {
|
||||
// Drag Zoom
|
||||
float p1, p2, tmin, tmax;
|
||||
tmin=min;
|
||||
tmax=max;
|
||||
const float tmin = min, tmax = max;
|
||||
|
||||
if(spectrumLog) {
|
||||
if (spectral) {
|
||||
double xmin = 1 - (mZoomEnd - ypos) / (float)height;
|
||||
double xmax = 1 - (mZoomStart - ypos) / (float)height;
|
||||
double lmin=log10(tmin), lmax=log10(tmax);
|
||||
double d=lmax-lmin;
|
||||
min=std::max(1.0, pow(10, xmin*d+lmin));
|
||||
max=std::min(rate/2.0, pow(10, xmax*d+lmin));
|
||||
// Enforce vertical zoom limits
|
||||
// done in the linear freq domain for now, but not too far out
|
||||
if(max < min + minBins * binSize)
|
||||
max = min + minBins * binSize;
|
||||
if(max > rate/2.) {
|
||||
max = rate/2.;
|
||||
min = max - minBins * binSize;
|
||||
}
|
||||
const float middle = (xmin + xmax) / 2;
|
||||
const float middleValue = scale.PositionToValue(middle);
|
||||
|
||||
min = std::max(spectrumLinear ? 0.0f : 1.0f,
|
||||
std::min(middleValue - minBand / 2,
|
||||
scale.PositionToValue(xmin)
|
||||
));
|
||||
max = std::min(halfrate,
|
||||
std::max(middleValue + minBand / 2,
|
||||
scale.PositionToValue(xmax)
|
||||
));
|
||||
}
|
||||
else {
|
||||
p1 = (mZoomStart - ypos) / (float)height;
|
||||
p2 = (mZoomEnd - ypos) / (float)height;
|
||||
const float p1 = (mZoomStart - ypos) / (float)height;
|
||||
const float p2 = (mZoomEnd - ypos) / (float)height;
|
||||
max = (tmax * (1.0-p1) + tmin * p1);
|
||||
min = (tmax * (1.0-p2) + tmin * p2);
|
||||
|
||||
// Enforce vertical zoom limits
|
||||
if(spectrumLinear) {
|
||||
if(min < 0.)
|
||||
min = 0.;
|
||||
if(max < min + minBins * binSize)
|
||||
max = min + minBins * binSize;
|
||||
if(max > rate/2.) {
|
||||
max = rate/2.;
|
||||
min = max - minBins * binSize;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Waveform view - allow zooming down to a range of ZOOMLIMIT
|
||||
if (max - min < ZOOMLIMIT) { // if user attempts to go smaller...
|
||||
c = (min+max)/2; // ...set centre of view to centre of dragged area and top/bottom to ZOOMLIMIT/2 above/below
|
||||
@ -4756,53 +4695,31 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (event.ShiftDown() || event.RightUp()) {
|
||||
// Zoom OUT
|
||||
if (spectral) {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out full
|
||||
min = spectrumLinear ? 0.0f : 1.0f;
|
||||
max = halfrate;
|
||||
}
|
||||
else {
|
||||
// Zoom out
|
||||
|
||||
// (Used to zoom out centered at midline, ignoring the click, if linear view.
|
||||
// I think it is better to be consistent. PRL)
|
||||
// Center zoom-out at the midline
|
||||
const float middle = // spectrumLinear ? 0.5f :
|
||||
1.0f - (mZoomStart - ypos) / (float)height;
|
||||
|
||||
min = std::max(spectrumLinear ? 0.0f : 1.0f, scale.PositionToValue(middle - 1.0f));
|
||||
max = std::min(halfrate, scale.PositionToValue(middle + 1.0f));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom out to -1.0...1.0 first, then, and only
|
||||
// then, if they click again, allow one more
|
||||
// zoom out.
|
||||
if (spectrumLinear) {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out full
|
||||
min = 0.0;
|
||||
max = rate/2.;
|
||||
}
|
||||
else {
|
||||
// Zoom out
|
||||
c = 0.5*(min+max);
|
||||
l = (c - min);
|
||||
if(c - 2*l <= 0) {
|
||||
min = 0.0;
|
||||
max = std::min( rate/2., 2. * max);
|
||||
}
|
||||
else {
|
||||
min = std::max( 0.0f, c - 2*l);
|
||||
max = std::min( float(rate)/2, c + 2*l);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(spectrumLog) {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out full
|
||||
min = 1.0;
|
||||
max = rate/2.;
|
||||
}
|
||||
else {
|
||||
// Zoom out
|
||||
float p1;
|
||||
p1 = (mZoomStart - ypos) / (float)height;
|
||||
c = 1.0-p1;
|
||||
double xmin = c - 1.;
|
||||
double xmax = c + 1.;
|
||||
double lmin = log10(min), lmax = log10(max);
|
||||
double d = lmax-lmin;
|
||||
min = std::max(1.0f,float(pow(10, xmin*d+lmin)));
|
||||
max = std::min(rate/2., pow(10, xmax*d+lmin));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (event.ShiftDown() && event.RightUp()) {
|
||||
// Zoom out full
|
||||
min = -1.0;
|
||||
@ -4827,41 +4744,25 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Zoom IN
|
||||
float p1;
|
||||
if (spectrumLinear) {
|
||||
c = 0.5*(min+max);
|
||||
// Enforce maximum vertical zoom
|
||||
l = std::max( minBins * binSize, (c - min));
|
||||
if (spectral) {
|
||||
// Center the zoom-in at the click
|
||||
const float middle = 1.0f - (mZoomStart - ypos) / (float)height;
|
||||
const float middleValue = scale.PositionToValue(middle);
|
||||
|
||||
p1 = (mZoomStart - ypos) / (float)height;
|
||||
c = (max * (1.0-p1) + min * p1);
|
||||
min = std::max( 0.0, c - 0.5*l);
|
||||
max = std::min( float(rate)/2, min + l);
|
||||
}
|
||||
else {
|
||||
if(spectrumLog) {
|
||||
p1 = (mZoomStart - ypos) / (float)height;
|
||||
c = 1.0-p1;
|
||||
double xmin = c - 0.25;
|
||||
double xmax = c + 0.25;
|
||||
double lmin = log10(min), lmax = log10(max);
|
||||
double d = lmax-lmin;
|
||||
min = std::max(1.0f, float(pow(10, xmin*d+lmin)));
|
||||
max = std::min(rate/2., pow(10, xmax*d+lmin));
|
||||
// Enforce vertical zoom limits
|
||||
// done in the linear freq domain for now, but not too far out
|
||||
if(max < min + minBins * binSize)
|
||||
max = min + minBins * binSize;
|
||||
if(max > rate/2.) {
|
||||
max = rate/2.;
|
||||
min = max - minBins * binSize;
|
||||
}
|
||||
min = std::max(spectrumLinear ? 0.0f : 1.0f,
|
||||
std::min(middleValue - minBand / 2,
|
||||
scale.PositionToValue(middle - 0.25f)
|
||||
));
|
||||
max = std::min(halfrate,
|
||||
std::max(middleValue + minBand / 2,
|
||||
scale.PositionToValue(middle + 0.25f)
|
||||
));
|
||||
}
|
||||
else {
|
||||
// Zoom in centered on cursor
|
||||
float p1;
|
||||
if (min < -1.0 || max > 1.0) {
|
||||
min = -1.0;
|
||||
max = 1.0;
|
||||
@ -4878,8 +4779,8 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spectral) {
|
||||
if (spectrumLinear) {
|
||||
SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
settings.SetMinFreq(min);
|
||||
@ -4891,7 +4792,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
settings.SetMaxFreq(max);
|
||||
}
|
||||
}
|
||||
else if(spectrumLog) {
|
||||
else {
|
||||
SpectrogramSettings &settings = track->GetSpectrogramSettings();
|
||||
settings.SetLogMinFreq(min);
|
||||
settings.SetLogMaxFreq(max);
|
||||
@ -4902,6 +4803,7 @@ void TrackPanel::HandleVZoomButtonUp( wxMouseEvent & event )
|
||||
settings.SetLogMaxFreq(max);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
track->SetDisplayBounds(min, max);
|
||||
if (partner)
|
||||
|
@ -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()
|
||||
@ -161,6 +161,10 @@ const wxArrayString &SpectrogramSettings::GetScaleNames()
|
||||
// Keep in correspondence with enum SpectrogramSettings::ScaleType:
|
||||
theArray.Add(_("Linear"));
|
||||
theArray.Add(_("Logarithmic"));
|
||||
theArray.Add(_("Mel"));
|
||||
theArray.Add(_("Bark"));
|
||||
theArray.Add(_("Erb"));
|
||||
theArray.Add(_("Undertone"));
|
||||
}
|
||||
|
||||
return theArray;
|
||||
@ -524,6 +528,59 @@ int SpectrogramSettings::GetFFTLength(bool autocorrelation) const
|
||||
;
|
||||
}
|
||||
|
||||
NumberScale SpectrogramSettings::GetScale
|
||||
(double rate, bool bins, bool autocorrelation) const
|
||||
{
|
||||
int minFreq, maxFreq;
|
||||
NumberScaleType type = nstLinear;
|
||||
const int half = GetFFTLength(autocorrelation) / 2;
|
||||
|
||||
// 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;
|
||||
case stMel:
|
||||
type = nstMel; break;
|
||||
case stBark:
|
||||
type = nstBark; break;
|
||||
case stErb:
|
||||
type = nstErb; break;
|
||||
case stUndertone:
|
||||
type = nstUndertone; break;
|
||||
}
|
||||
|
||||
switch (scaleType) {
|
||||
default:
|
||||
wxASSERT(false);
|
||||
case stLinear:
|
||||
minFreq = GetMinFreq(rate);
|
||||
maxFreq = GetMaxFreq(rate);
|
||||
break;
|
||||
case stLogarithmic:
|
||||
case stMel:
|
||||
case stBark:
|
||||
case stErb:
|
||||
minFreq = GetLogMinFreq(rate);
|
||||
maxFreq = GetLogMaxFreq(rate);
|
||||
break;
|
||||
case stUndertone:
|
||||
{
|
||||
const float bin2 = rate / half;
|
||||
minFreq = std::max(int(0.5 + bin2), GetLogMinFreq(rate));
|
||||
maxFreq = GetLogMaxFreq(rate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -53,6 +54,10 @@ public:
|
||||
enum ScaleType {
|
||||
stLinear,
|
||||
stLogarithmic,
|
||||
stMel,
|
||||
stBark,
|
||||
stErb,
|
||||
stUndertone,
|
||||
|
||||
stNumScaleTypes,
|
||||
};
|
||||
@ -80,6 +85,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;
|
||||
|
@ -76,6 +76,7 @@ array of Ruler::Label.
|
||||
#include "../TimeTrack.h"
|
||||
#include "../TrackPanel.h"
|
||||
#include "../Menus.h"
|
||||
#include "../NumberScale.h"
|
||||
#include "../Prefs.h"
|
||||
#include "../Snap.h"
|
||||
|
||||
@ -97,6 +98,7 @@ using std::max;
|
||||
//
|
||||
|
||||
Ruler::Ruler()
|
||||
: mpNumberScale(0)
|
||||
{
|
||||
mMin = mHiddenMin = 0.0;
|
||||
mMax = mHiddenMax = 100.0;
|
||||
@ -177,6 +179,8 @@ Ruler::~Ruler()
|
||||
delete[] mMinorLabels;
|
||||
if (mMinorMinorLabels)
|
||||
delete[] mMinorMinorLabels;
|
||||
|
||||
delete mpNumberScale;
|
||||
}
|
||||
|
||||
void Ruler::SetTwoTone(bool twoTone)
|
||||
@ -319,6 +323,23 @@ void Ruler::SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxF
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
void Ruler::SetNumberScale(const NumberScale *pScale)
|
||||
{
|
||||
if (!pScale) {
|
||||
if (mpNumberScale) {
|
||||
delete mpNumberScale;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!mpNumberScale || *mpNumberScale != *pScale) {
|
||||
delete mpNumberScale;
|
||||
mpNumberScale = new NumberScale(*pScale);
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Ruler::OfflimitsPixels(int start, int end)
|
||||
{
|
||||
int i;
|
||||
@ -1165,13 +1186,17 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
|
||||
}
|
||||
else {
|
||||
// log case
|
||||
|
||||
NumberScale numberScale(mpNumberScale
|
||||
? *mpNumberScale
|
||||
: NumberScale(nstLogarithmic, mMin, mMax, 1.0f)
|
||||
);
|
||||
|
||||
mDigits=2; //TODO: implement dynamic digit computation
|
||||
double loLog = log10(mMin);
|
||||
double hiLog = log10(mMax);
|
||||
double scale = mLength/(hiLog - loLog);
|
||||
int loDecade = (int) floor(loLog);
|
||||
|
||||
int pos;
|
||||
double val;
|
||||
double startDecade = pow(10., (double)loDecade);
|
||||
|
||||
@ -1179,12 +1204,12 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
|
||||
double decade = startDecade;
|
||||
double delta=hiLog-loLog, steps=fabs(delta);
|
||||
double step = delta>=0 ? 10 : 0.1;
|
||||
double rMin=wxMin(mMin, mMax), rMax=wxMax(mMin, mMax);
|
||||
double rMin=std::min(mMin, mMax), rMax=std::max(mMin, mMax);
|
||||
for(i=0; i<=steps; i++)
|
||||
{ // if(i!=0)
|
||||
{ val = decade;
|
||||
if(val > rMin && val < rMax) {
|
||||
pos = (int)(((log10(val) - loLog)*scale)+0.5);
|
||||
if(val >= rMin && val < rMax) {
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
Tick(pos, val, true, false);
|
||||
}
|
||||
}
|
||||
@ -1204,7 +1229,7 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
|
||||
for(j=start; j!=end; j+=mstep) {
|
||||
val = decade * j;
|
||||
if(val >= rMin && val < rMax) {
|
||||
pos = (int)(((log10(val) - loLog)*scale)+0.5);
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
Tick(pos, val, false, true);
|
||||
}
|
||||
}
|
||||
@ -1220,15 +1245,18 @@ void Ruler::Update(TimeTrack* timetrack)// Envelope *speedEnv, long minSpeed, lo
|
||||
}
|
||||
steps++;
|
||||
for (i = 0; i <= steps; i++) {
|
||||
// PRL: Bug1038. Don't label 1.6, rounded, as a duplicate tick for "2"
|
||||
if (!(mFormat == IntFormat && decade < 10.0)) {
|
||||
for (int f = start; f != int(end); f += mstep) {
|
||||
if (int(f / 10) != f / 10.0f) {
|
||||
val = decade * f / 10;
|
||||
if (val >= rMin && val < rMax) {
|
||||
pos = (int)(((log10(val) - loLog)*scale)+0.5);
|
||||
const int pos(0.5 + mLength * numberScale.ValueToPosition(val));
|
||||
Tick(pos, val, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
decade *= step;
|
||||
}
|
||||
}
|
||||
@ -1904,8 +1932,8 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
||||
TrackPanel *tp = mProject->GetTrackPanel();
|
||||
int mousePosX, width, height;
|
||||
tp->GetTracksUsableArea(&width, &height);
|
||||
mousePosX = wxMax(evt.GetX(), tp->GetLeftOffset());
|
||||
mousePosX = wxMin(mousePosX, tp->GetLeftOffset() + width - 1);
|
||||
mousePosX = std::max(evt.GetX(), tp->GetLeftOffset());
|
||||
mousePosX = std::min(mousePosX, tp->GetLeftOffset() + width - 1);
|
||||
|
||||
bool isWithinStart = IsWithinMarker(mousePosX, mOldPlayRegionStart);
|
||||
bool isWithinEnd = IsWithinMarker(mousePosX, mOldPlayRegionEnd);
|
||||
@ -1920,7 +1948,7 @@ void AdornedRulerPanel::OnMouseEvents(wxMouseEvent &evt)
|
||||
mLastMouseX = mousePosX;
|
||||
mQuickPlayPos = Pos2Time(mousePosX);
|
||||
// If not looping, restrict selection to end of project
|
||||
if (!evt.ShiftDown()) mQuickPlayPos = wxMin(t1, mQuickPlayPos);
|
||||
if (!evt.ShiftDown()) mQuickPlayPos = std::min(t1, mQuickPlayPos);
|
||||
|
||||
|
||||
if (evt.Leaving()) {
|
||||
@ -2487,7 +2515,7 @@ void AdornedRulerPanel::DrawQuickPlayIndicator(wxDC * dc, bool clear)
|
||||
TrackPanel *tp = mProject->GetTrackPanel();
|
||||
wxClientDC cdc(tp);
|
||||
|
||||
double latestEnd = wxMax(mProject->GetTracks()->GetEndTime(), mProject->GetSel1());
|
||||
double latestEnd = std::max(mProject->GetTracks()->GetEndTime(), mProject->GetSel1());
|
||||
if (clear || (mQuickPlayPos >= latestEnd)) {
|
||||
tp->TrackPanel::DrawQuickPlayIndicator(cdc, -1);
|
||||
return;
|
||||
|
@ -23,6 +23,7 @@ class ViewInfo;
|
||||
class AudacityProject;
|
||||
class TimeTrack;
|
||||
class SnapManager;
|
||||
class NumberScale;
|
||||
|
||||
class AUDACITY_DLL_API Ruler {
|
||||
public:
|
||||
@ -98,6 +99,9 @@ class AUDACITY_DLL_API Ruler {
|
||||
// Good defaults are provided, but you can override here
|
||||
void SetFonts(const wxFont &minorFont, const wxFont &majorFont, const wxFont &minorMinorFont);
|
||||
|
||||
// Copies *pScale if it is not NULL
|
||||
void SetNumberScale(const NumberScale *pScale);
|
||||
|
||||
// The ruler will not draw text within this (pixel) range.
|
||||
// Use this if you have another graphic object obscuring part
|
||||
// of the ruler's area. The values start and end are interpreted
|
||||
@ -227,6 +231,8 @@ private:
|
||||
bool mTwoTone;
|
||||
bool mUseZoomInfo;
|
||||
int mLeftOffset;
|
||||
|
||||
NumberScale *mpNumberScale;
|
||||
};
|
||||
|
||||
class AUDACITY_DLL_API RulerPanel : public wxPanel {
|
||||
|
@ -533,6 +533,7 @@
|
||||
<ClInclude Include="..\..\..\src\import\MultiFormatReader.h" />
|
||||
<ClInclude Include="..\..\..\src\import\SpecPowerMeter.h" />
|
||||
<ClInclude Include="..\..\..\src\ModuleManager.h" />
|
||||
<ClInclude Include="..\..\..\src\NumberScale.h" />
|
||||
<ClInclude Include="..\..\..\src\prefs\SpectrogramSettings.h" />
|
||||
<ClInclude Include="..\..\..\src\RevisionIdent.h" />
|
||||
<ClInclude Include="..\..\..\src\SelectedRegion.h" />
|
||||
|
@ -1685,6 +1685,9 @@
|
||||
<ClInclude Include="..\..\..\src\prefs\SpectrogramSettings.h">
|
||||
<Filter>src/prefs</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\src\NumberScale.h">
|
||||
<Filter>src</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\audacity.ico">
|
||||
|
Loading…
x
Reference in New Issue
Block a user