mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-06 15:37:44 +02:00
Paul Licameli's Spectral Editing Patch.
This relies on three new nyquist scripts to actually do the editing. The peak-snapping code in FrequencyWindow has been extracted into a new class, SpectrumAnalyst, to provide peak-snapping in spectrogram too.
This commit is contained in:
parent
b84fdb82e1
commit
37608c2290
plug-ins
src
33
plug-ins/SpectralEditMulti.ny
Normal file
33
plug-ins/SpectralEditMulti.ny
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
;nyquist plug-in
|
||||||
|
;version 3
|
||||||
|
;type process
|
||||||
|
;name "Spectral edit multi tool"
|
||||||
|
;action "Calculating..."
|
||||||
|
|
||||||
|
(defun wet (sig)
|
||||||
|
(cond
|
||||||
|
((not (or *f0* *f1*)) (throw 'error-message "Please select frequencies"))
|
||||||
|
((not *f0*) (highpass2 sig *f1*))
|
||||||
|
((not *f1*) (lowpass2 sig *f0*))
|
||||||
|
(t (if (= *f0* *f1*)
|
||||||
|
(throw 'error-message "Band width is undefined")
|
||||||
|
(let*
|
||||||
|
((fc (sqrt (* *f0* *f1*)))
|
||||||
|
(width (abs (- *f1* *f0*)))
|
||||||
|
(q (/ fc width)))
|
||||||
|
(notch2 sig fc q))))))
|
||||||
|
|
||||||
|
(defun result (sig)
|
||||||
|
(let*
|
||||||
|
((tn (truncate len))
|
||||||
|
(rate (snd-srate sig))
|
||||||
|
(transition (truncate (* 0.01 rate)))
|
||||||
|
(t1 (min transition (/ tn 2)))
|
||||||
|
(t2 (max (- tn transition) (/ tn 2)))
|
||||||
|
(breakpoints (list t1 1.0 t2 1.0 tn))
|
||||||
|
(env (snd-pwl 0.0 rate breakpoints)))
|
||||||
|
(sum (prod env (wet sig)) (prod (diff 1.0 env) sig))))
|
||||||
|
|
||||||
|
(catch 'error-message
|
||||||
|
(multichan-expand #'result s))
|
||||||
|
|
32
plug-ins/SpectralEditParametricEQ.ny
Normal file
32
plug-ins/SpectralEditParametricEQ.ny
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
;nyquist plug-in
|
||||||
|
;version 3
|
||||||
|
;type process
|
||||||
|
;name "Spectral edit parametric EQ"
|
||||||
|
;action "Calculating..."
|
||||||
|
|
||||||
|
;control control-gain "Gain (dB)" real "" 0 -24 24
|
||||||
|
|
||||||
|
|
||||||
|
(defun wet (sig gain)
|
||||||
|
(cond
|
||||||
|
((not (or *f0* *f1*)) (throw 'debug-message "Please select frequencies"))
|
||||||
|
((not *f0*) (throw 'debug-message "Bottom frequency is undefined"))
|
||||||
|
((not *f1*) (throw 'debug-message "Top frequency is undefined"))
|
||||||
|
(t (let*
|
||||||
|
((fc (sqrt (* *f0* *f1*)))
|
||||||
|
(width-octaves (/ (s-log (/ *f1* *f0*)) (s-log 2.0))))
|
||||||
|
(eq-band sig fc gain (/ width-octaves 2))))))
|
||||||
|
|
||||||
|
(defun result (sig)
|
||||||
|
(let*
|
||||||
|
((tn (truncate len))
|
||||||
|
(rate (snd-srate sig))
|
||||||
|
(transition (truncate (* 0.01 rate)))
|
||||||
|
(t1 (min transition (/ tn 2)))
|
||||||
|
(t2 (max (- tn transition) (/ tn 2)))
|
||||||
|
(breakpoints (list t1 1.0 t2 1.0 tn))
|
||||||
|
(env (snd-pwl 0.0 rate breakpoints)))
|
||||||
|
(sum (prod env (wet sig control-gain)) (prod (diff 1.0 env) sig))))
|
||||||
|
|
||||||
|
(catch 'debug-message
|
||||||
|
(multichan-expand #'result s))
|
36
plug-ins/SpectralEditShelves.ny
Normal file
36
plug-ins/SpectralEditShelves.ny
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
;nyquist plug-in
|
||||||
|
;version 3
|
||||||
|
;type process
|
||||||
|
;name "Spectral edit shelves"
|
||||||
|
;action "Calculating..."
|
||||||
|
|
||||||
|
;control control-gain "Gain (dB)" real "" 0 -24 24
|
||||||
|
|
||||||
|
(defun mid-shelf (sig lf hf gain)
|
||||||
|
"Combines high shelf and low shelf filters"
|
||||||
|
(let* ((invg (- gain)))
|
||||||
|
(scale (db-to-linear gain)
|
||||||
|
(eq-highshelf (eq-lowshelf sig lf invg)
|
||||||
|
hf invg))))
|
||||||
|
|
||||||
|
(defun wet (sig gain)
|
||||||
|
(cond
|
||||||
|
((not (or *f0* *f1*)) (throw 'debug-message "Please select frequencies"))
|
||||||
|
((not *f0*) (eq-lowshelf sig *f1* gain))
|
||||||
|
((not *f1*) (eq-highshelf sig *f0* gain))
|
||||||
|
(t (mid-shelf sig *f0* *f1* gain))))
|
||||||
|
|
||||||
|
(defun result (sig)
|
||||||
|
(let*
|
||||||
|
((tn (truncate len))
|
||||||
|
(rate (snd-srate sig))
|
||||||
|
(transition (truncate (* 0.01 rate)))
|
||||||
|
(t1 (min transition (/ tn 2)))
|
||||||
|
(t2 (max (- tn transition) (/ tn 2)))
|
||||||
|
(breakpoints (list t1 1.0 t2 1.0 tn))
|
||||||
|
(env (snd-pwl 0.0 rate breakpoints)))
|
||||||
|
(sum (prod env (wet sig control-gain)) (prod (diff 1.0 env) sig))))
|
||||||
|
|
||||||
|
(catch 'debug-message
|
||||||
|
(multichan-expand #'result s))
|
||||||
|
|
@ -570,14 +570,14 @@ void AColor::DarkMIDIChannel(wxDC * dc, int channel /* 1 - 16 */ )
|
|||||||
|
|
||||||
bool AColor::gradient_inited = 0;
|
bool AColor::gradient_inited = 0;
|
||||||
|
|
||||||
unsigned char AColor::gradient_pre[2][2][gradientSteps][3];
|
unsigned char AColor::gradient_pre[ColorGradientTotal][2][gradientSteps][3];
|
||||||
|
|
||||||
void AColor::PreComputeGradient() {
|
void AColor::PreComputeGradient() {
|
||||||
{
|
{
|
||||||
if (!gradient_inited) {
|
if (!gradient_inited) {
|
||||||
gradient_inited = 1;
|
gradient_inited = 1;
|
||||||
|
|
||||||
for (int selected = 0; selected <= 1; selected++)
|
for (int selected = 0; selected < ColorGradientTotal; selected++)
|
||||||
for (int grayscale = 0; grayscale <= 1; grayscale++) {
|
for (int grayscale = 0; grayscale <= 1; grayscale++) {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
|
|
||||||
@ -608,10 +608,24 @@ void AColor::PreComputeGradient() {
|
|||||||
b = (gradient[left][2] * lweight) + (gradient[right][2] * rweight);
|
b = (gradient[left][2] * lweight) + (gradient[right][2] * rweight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected) {
|
switch (selected) {
|
||||||
|
case ColorGradientUnselected:
|
||||||
|
// not dimmed
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ColorGradientTimeSelected:
|
||||||
|
// partly dimmed
|
||||||
|
r *= 0.88f;
|
||||||
|
g *= 0.88f;
|
||||||
|
b *= 0.992f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ColorGradientTimeAndFrequencySelected:
|
||||||
|
// fully dimmed
|
||||||
r *= 0.77f;
|
r *= 0.77f;
|
||||||
g *= 0.77f;
|
g *= 0.77f;
|
||||||
b *= 0.885f;
|
b *= 0.885f;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
gradient_pre[selected][grayscale][i][0] = (unsigned char) (255 * r);
|
gradient_pre[selected][grayscale][i][0] = (unsigned char) (255 * r);
|
||||||
gradient_pre[selected][grayscale][i][1] = (unsigned char) (255 * g);
|
gradient_pre[selected][grayscale][i][1] = (unsigned char) (255 * g);
|
||||||
|
13
src/AColor.h
13
src/AColor.h
@ -22,6 +22,15 @@ class wxRect;
|
|||||||
|
|
||||||
class AColor {
|
class AColor {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum ColorGradientChoice {
|
||||||
|
ColorGradientUnselected = 0,
|
||||||
|
ColorGradientTimeSelected,
|
||||||
|
ColorGradientTimeAndFrequencySelected,
|
||||||
|
|
||||||
|
ColorGradientTotal // keep me last
|
||||||
|
};
|
||||||
|
|
||||||
static void Init();
|
static void Init();
|
||||||
static void ReInit();
|
static void ReInit();
|
||||||
|
|
||||||
@ -97,7 +106,7 @@ class AColor {
|
|||||||
|
|
||||||
static bool gradient_inited;
|
static bool gradient_inited;
|
||||||
static const int gradientSteps = 512;
|
static const int gradientSteps = 512;
|
||||||
static unsigned char gradient_pre[2][2][gradientSteps][3];
|
static unsigned char gradient_pre[ColorGradientTotal][2][gradientSteps][3];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static wxPen sparePen;
|
static wxPen sparePen;
|
||||||
@ -107,7 +116,7 @@ class AColor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline void GetColorGradient(float value,
|
inline void GetColorGradient(float value,
|
||||||
bool selected,
|
AColor::ColorGradientChoice selected,
|
||||||
bool grayscale,
|
bool grayscale,
|
||||||
unsigned char *red,
|
unsigned char *red,
|
||||||
unsigned char *green, unsigned char *blue) {
|
unsigned char *green, unsigned char *blue) {
|
||||||
|
@ -102,6 +102,9 @@
|
|||||||
// Won't build on Fedora 17 or Windows VC++, per http://bugzilla.audacityteam.org/show_bug.cgi?id=539.
|
// Won't build on Fedora 17 or Windows VC++, per http://bugzilla.audacityteam.org/show_bug.cgi?id=539.
|
||||||
//#define EXPERIMENTAL_OD_FFMPEG 1
|
//#define EXPERIMENTAL_OD_FFMPEG 1
|
||||||
|
|
||||||
|
// Paul Licameli (PRL) 5 Oct 2014
|
||||||
|
#define EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
|
||||||
// Philip Van Baren 01 July 2009
|
// Philip Van Baren 01 July 2009
|
||||||
// Replace RealFFT() and PowerSpectrum function to use (faster) RealFFTf function
|
// Replace RealFFT() and PowerSpectrum function to use (faster) RealFFTf function
|
||||||
#define EXPERIMENTAL_USE_REALFFTF
|
#define EXPERIMENTAL_USE_REALFFTF
|
||||||
|
@ -107,12 +107,23 @@ BEGIN_EVENT_TABLE(FreqWindow, wxDialog)
|
|||||||
EVT_CHECKBOX(GridOnOffID, FreqWindow::OnGridOnOff)
|
EVT_CHECKBOX(GridOnOffID, FreqWindow::OnGridOnOff)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
SpectrumAnalyst::SpectrumAnalyst()
|
||||||
|
: mAlg(Spectrum)
|
||||||
|
, mRate(0.0)
|
||||||
|
, mWindowSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SpectrumAnalyst::~SpectrumAnalyst()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
|
FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
|
||||||
const wxString & title,
|
const wxString & title,
|
||||||
const wxPoint & pos):
|
const wxPoint & pos):
|
||||||
wxDialog(parent, id, title, pos, wxDefaultSize,
|
wxDialog(parent, id, title, pos, wxDefaultSize,
|
||||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX),
|
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX),
|
||||||
mData(NULL), mProcessed(NULL), mBitmap(NULL)
|
mData(NULL), mBitmap(NULL), mAnalyst(new SpectrumAnalyst())
|
||||||
{
|
{
|
||||||
mMouseX = 0;
|
mMouseX = 0;
|
||||||
mMouseY = 0;
|
mMouseY = 0;
|
||||||
@ -132,7 +143,11 @@ FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
|
|||||||
|
|
||||||
gPrefs->Read(wxT("/FreqWindow/DrawGrid"), &mDrawGrid, true);
|
gPrefs->Read(wxT("/FreqWindow/DrawGrid"), &mDrawGrid, true);
|
||||||
gPrefs->Read(wxT("/FreqWindow/SizeChoice"), &mSize, 2);
|
gPrefs->Read(wxT("/FreqWindow/SizeChoice"), &mSize, 2);
|
||||||
gPrefs->Read(wxT("/FreqWindow/AlgChoice"), &mAlg, 0);
|
|
||||||
|
int alg;
|
||||||
|
gPrefs->Read(wxT("/FreqWindow/AlgChoice"), (&alg), 0);
|
||||||
|
mAlg = static_cast<SpectrumAnalyst::Algorithm>(alg);
|
||||||
|
|
||||||
gPrefs->Read(wxT("/FreqWindow/FuncChoice"), &mFunc, 3);
|
gPrefs->Read(wxT("/FreqWindow/FuncChoice"), &mFunc, 3);
|
||||||
gPrefs->Read(wxT("/FreqWindow/AxisChoice"), &mAxis, 0);
|
gPrefs->Read(wxT("/FreqWindow/AxisChoice"), &mAxis, 0);
|
||||||
gPrefs->Read(wxT("/GUI/EnvdBRange"), &dBRange, ENV_DB_RANGE);
|
gPrefs->Read(wxT("/GUI/EnvdBRange"), &dBRange, ENV_DB_RANGE);
|
||||||
@ -214,7 +229,7 @@ FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
|
|||||||
|
|
||||||
mAxisChoice->SetSelection(mAxis);
|
mAxisChoice->SetSelection(mAxis);
|
||||||
// Log-frequency axis works for spectrum plots only.
|
// Log-frequency axis works for spectrum plots only.
|
||||||
if (mAlg != 0) {
|
if (mAlg != SpectrumAnalyst::Spectrum) {
|
||||||
mAxis = 0;
|
mAxis = 0;
|
||||||
mAxisChoice->Disable();
|
mAxisChoice->Disable();
|
||||||
}
|
}
|
||||||
@ -381,8 +396,6 @@ FreqWindow::~FreqWindow()
|
|||||||
delete[] mData;
|
delete[] mData;
|
||||||
if (mBuffer)
|
if (mBuffer)
|
||||||
delete[] mBuffer;
|
delete[] mBuffer;
|
||||||
if (mProcessed)
|
|
||||||
delete[] mProcessed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqWindow::GetAudio()
|
void FreqWindow::GetAudio()
|
||||||
@ -489,7 +502,7 @@ void FreqWindow::DrawPlot()
|
|||||||
memDC.SetBrush(*wxWHITE_BRUSH);
|
memDC.SetBrush(*wxWHITE_BRUSH);
|
||||||
memDC.DrawRectangle(r);
|
memDC.DrawRectangle(r);
|
||||||
|
|
||||||
if (!mProcessed) {
|
if (0 == mAnalyst->GetProcessedSize()) {
|
||||||
if (mData && mDataLen < mWindowSize)
|
if (mData && mDataLen < mWindowSize)
|
||||||
memDC.DrawText(_("Not enough data selected."), r.x + 5, r.y + 5);
|
memDC.DrawText(_("Not enough data selected."), r.x + 5, r.y + 5);
|
||||||
|
|
||||||
@ -498,7 +511,8 @@ void FreqWindow::DrawPlot()
|
|||||||
|
|
||||||
float yTotal = (mYMax - mYMin);
|
float yTotal = (mYMax - mYMin);
|
||||||
|
|
||||||
int alg = mAlgChoice->GetSelection();
|
SpectrumAnalyst::Algorithm alg =
|
||||||
|
SpectrumAnalyst::Algorithm(mAlgChoice->GetSelection());
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -506,7 +520,7 @@ void FreqWindow::DrawPlot()
|
|||||||
|
|
||||||
// Set up y axis ruler
|
// Set up y axis ruler
|
||||||
|
|
||||||
if (alg == 0) {
|
if (alg == SpectrumAnalyst::Spectrum) {
|
||||||
vRuler->ruler.SetUnits(_("dB"));
|
vRuler->ruler.SetUnits(_("dB"));
|
||||||
vRuler->ruler.SetFormat(Ruler::LinearDBFormat);
|
vRuler->ruler.SetFormat(Ruler::LinearDBFormat);
|
||||||
} else {
|
} else {
|
||||||
@ -531,7 +545,7 @@ void FreqWindow::DrawPlot()
|
|||||||
|
|
||||||
float xMin, xMax, xRatio, xStep;
|
float xMin, xMax, xRatio, xStep;
|
||||||
|
|
||||||
if (alg == 0) {
|
if (alg == SpectrumAnalyst::Spectrum) {
|
||||||
xMin = mRate / mWindowSize;
|
xMin = mRate / mWindowSize;
|
||||||
xMax = mRate / 2;
|
xMax = mRate / 2;
|
||||||
xRatio = xMax / xMin;
|
xRatio = xMax / xMin;
|
||||||
@ -548,7 +562,7 @@ void FreqWindow::DrawPlot()
|
|||||||
hRuler->ruler.SetUnits(_("Hz"));
|
hRuler->ruler.SetUnits(_("Hz"));
|
||||||
} else {
|
} else {
|
||||||
xMin = 0;
|
xMin = 0;
|
||||||
xMax = mProcessedSize / mRate;
|
xMax = mAnalyst->GetProcessedSize() / mRate;
|
||||||
xStep = (xMax - xMin) / width;
|
xStep = (xMax - xMin) / width;
|
||||||
hRuler->ruler.SetLog(false);
|
hRuler->ruler.SetLog(false);
|
||||||
hRuler->ruler.SetUnits(_("s"));
|
hRuler->ruler.SetUnits(_("s"));
|
||||||
@ -557,7 +571,7 @@ void FreqWindow::DrawPlot()
|
|||||||
hRuler->Refresh(false);
|
hRuler->Refresh(false);
|
||||||
|
|
||||||
// Draw the plot
|
// Draw the plot
|
||||||
if (alg == 0)
|
if (alg == SpectrumAnalyst::Spectrum)
|
||||||
memDC.SetPen(wxPen(theTheme.Colour( clrHzPlot ), 1, wxSOLID));
|
memDC.SetPen(wxPen(theTheme.Colour( clrHzPlot ), 1, wxSOLID));
|
||||||
else
|
else
|
||||||
memDC.SetPen(wxPen(theTheme.Colour( clrWavelengthPlot), 1, wxSOLID));
|
memDC.SetPen(wxPen(theTheme.Colour( clrWavelengthPlot), 1, wxSOLID));
|
||||||
@ -568,9 +582,9 @@ void FreqWindow::DrawPlot()
|
|||||||
float y;
|
float y;
|
||||||
|
|
||||||
if (mLogAxis)
|
if (mLogAxis)
|
||||||
y = GetProcessedValue(xPos, xPos * xStep);
|
y = mAnalyst->GetProcessedValue(xPos, xPos * xStep);
|
||||||
else
|
else
|
||||||
y = GetProcessedValue(xPos, xPos + xStep);
|
y = mAnalyst->GetProcessedValue(xPos, xPos + xStep);
|
||||||
|
|
||||||
float ynorm = (y - mYMin) / yTotal;
|
float ynorm = (y - mYMin) / yTotal;
|
||||||
|
|
||||||
@ -725,13 +739,11 @@ float CubicMaximize(float y0, float y1, float y2, float y3, float * max)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float FreqWindow::GetProcessedValue(float freq0, float freq1)
|
float SpectrumAnalyst::GetProcessedValue(float freq0, float freq1) const
|
||||||
{
|
{
|
||||||
int alg = mAlgChoice->GetSelection();
|
|
||||||
|
|
||||||
float bin0, bin1, binwidth;
|
float bin0, bin1, binwidth;
|
||||||
|
|
||||||
if (alg == 0) {
|
if (mAlg == Spectrum) {
|
||||||
bin0 = freq0 * mWindowSize / mRate;
|
bin0 = freq0 * mWindowSize / mRate;
|
||||||
bin1 = freq1 * mWindowSize / mRate;
|
bin1 = freq1 * mWindowSize / mRate;
|
||||||
} else {
|
} else {
|
||||||
@ -747,8 +759,8 @@ float FreqWindow::GetProcessedValue(float freq0, float freq1)
|
|||||||
int ibin = int (binmid) - 1;
|
int ibin = int (binmid) - 1;
|
||||||
if (ibin < 1)
|
if (ibin < 1)
|
||||||
ibin = 1;
|
ibin = 1;
|
||||||
if (ibin >= mProcessedSize - 3)
|
if (ibin >= GetProcessedSize() - 3)
|
||||||
ibin = mProcessedSize - 4;
|
ibin = std::max(0, GetProcessedSize() - 4);
|
||||||
|
|
||||||
value = CubicInterpolate(mProcessed[ibin],
|
value = CubicInterpolate(mProcessed[ibin],
|
||||||
mProcessed[ibin + 1],
|
mProcessed[ibin + 1],
|
||||||
@ -756,6 +768,11 @@ float FreqWindow::GetProcessedValue(float freq0, float freq1)
|
|||||||
mProcessed[ibin + 3], binmid - ibin);
|
mProcessed[ibin + 3], binmid - ibin);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
if (bin0 < 0)
|
||||||
|
bin0 = 0;
|
||||||
|
if (bin1 >= GetProcessedSize())
|
||||||
|
bin1 = GetProcessedSize() - 1;
|
||||||
|
|
||||||
if (int (bin1) > int (bin0))
|
if (int (bin1) > int (bin0))
|
||||||
value += mProcessed[int (bin0)] * (int (bin0) + 1 - bin0);
|
value += mProcessed[int (bin0)] * (int (bin0) + 1 - bin0);
|
||||||
bin0 = 1 + int (bin0);
|
bin0 = 1 + int (bin0);
|
||||||
@ -771,15 +788,63 @@ float FreqWindow::GetProcessedValue(float freq0, float freq1)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SpectrumAnalyst::FindPeak(float xPos, float *pY) const
|
||||||
|
{
|
||||||
|
float bestpeak = 0.0f;
|
||||||
|
float bestValue = 0.0;
|
||||||
|
if (GetProcessedSize() > 1) {
|
||||||
|
bool up = (mProcessed[1] > mProcessed[0]);
|
||||||
|
float bestdist = 1000000;
|
||||||
|
for (int bin = 3; bin < GetProcessedSize() - 1; bin++) {
|
||||||
|
bool nowUp = mProcessed[bin] > mProcessed[bin - 1];
|
||||||
|
if (!nowUp && up) {
|
||||||
|
// Local maximum. Find actual value by cubic interpolation
|
||||||
|
int leftbin = bin - 2;
|
||||||
|
/*
|
||||||
|
if (leftbin < 1)
|
||||||
|
leftbin = 1;
|
||||||
|
*/
|
||||||
|
float valueAtMax = 0.0;
|
||||||
|
float max = leftbin + CubicMaximize(mProcessed[leftbin],
|
||||||
|
mProcessed[leftbin + 1],
|
||||||
|
mProcessed[leftbin + 2],
|
||||||
|
mProcessed[leftbin + 3],
|
||||||
|
&valueAtMax);
|
||||||
|
|
||||||
|
float thispeak;
|
||||||
|
if (mAlg == Spectrum)
|
||||||
|
thispeak = max * mRate / mWindowSize;
|
||||||
|
else
|
||||||
|
thispeak = max / mRate;
|
||||||
|
|
||||||
|
if (fabs(thispeak - xPos) < bestdist) {
|
||||||
|
bestpeak = thispeak;
|
||||||
|
bestdist = fabs(thispeak - xPos);
|
||||||
|
bestValue = valueAtMax;
|
||||||
|
// Should this test come after the enclosing if?
|
||||||
|
if (thispeak > xPos)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
up = nowUp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pY)
|
||||||
|
*pY = bestValue;
|
||||||
|
return bestpeak;
|
||||||
|
}
|
||||||
|
|
||||||
void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
||||||
{
|
{
|
||||||
wxPaintDC dc( (wxWindow *) evt.GetEventObject() );
|
wxPaintDC dc( (wxWindow *) evt.GetEventObject() );
|
||||||
|
|
||||||
dc.DrawBitmap( *mBitmap, 0, 0, true );
|
dc.DrawBitmap( *mBitmap, 0, 0, true );
|
||||||
if( mProcessed == NULL )
|
if( 0 == mAnalyst->GetProcessedSize() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int alg = mAlgChoice->GetSelection();
|
SpectrumAnalyst::Algorithm alg =
|
||||||
|
SpectrumAnalyst::Algorithm(mAlgChoice->GetSelection());
|
||||||
|
|
||||||
dc.SetFont(mFreqFont);
|
dc.SetFont(mFreqFont);
|
||||||
|
|
||||||
@ -789,7 +854,7 @@ void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
|||||||
|
|
||||||
float xMin, xMax, xRatio, xStep;
|
float xMin, xMax, xRatio, xStep;
|
||||||
|
|
||||||
if (alg == 0) {
|
if (alg == SpectrumAnalyst::Spectrum) {
|
||||||
xMin = mRate / mWindowSize;
|
xMin = mRate / mWindowSize;
|
||||||
xMax = mRate / 2;
|
xMax = mRate / 2;
|
||||||
xRatio = xMax / xMin;
|
xRatio = xMax / xMin;
|
||||||
@ -799,52 +864,21 @@ void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
|||||||
xStep = (xMax - xMin) / width;
|
xStep = (xMax - xMin) / width;
|
||||||
} else {
|
} else {
|
||||||
xMin = 0;
|
xMin = 0;
|
||||||
xMax = mProcessedSize / mRate;
|
xMax = mAnalyst->GetProcessedSize() / mRate;
|
||||||
xStep = (xMax - xMin) / width;
|
xStep = (xMax - xMin) / width;
|
||||||
}
|
}
|
||||||
|
|
||||||
float xPos = xMin;
|
float xPos = xMin;
|
||||||
|
|
||||||
// Find the peak nearest the cursor and plot it
|
// Find the peak nearest the cursor and plot it
|
||||||
float bestpeak = float(0.0);
|
|
||||||
if ( r.Contains(mMouseX, mMouseY) & (mMouseX!=0) & (mMouseX!=r.width-1) ) {
|
if ( r.Contains(mMouseX, mMouseY) & (mMouseX!=0) & (mMouseX!=r.width-1) ) {
|
||||||
if (mLogAxis)
|
if (mLogAxis)
|
||||||
xPos = xMin * pow(xStep, mMouseX - (r.x + 1));
|
xPos = xMin * pow(xStep, mMouseX - (r.x + 1));
|
||||||
else
|
else
|
||||||
xPos = xMin + xStep * (mMouseX - (r.x + 1));
|
xPos = xMin + xStep * (mMouseX - (r.x + 1));
|
||||||
|
|
||||||
bool up = (mProcessed[1] > mProcessed[0]);
|
float bestValue = 0;
|
||||||
float bestdist = 1000000;
|
float bestpeak = mAnalyst->FindPeak(xPos, &bestValue);
|
||||||
float bestValue = 0.0;
|
|
||||||
for (int bin = 2; bin < mProcessedSize; bin++) {
|
|
||||||
bool nowUp = mProcessed[bin] > mProcessed[bin - 1];
|
|
||||||
if (!nowUp && up) {
|
|
||||||
// Local maximum. Find actual value by cubic interpolation
|
|
||||||
int leftbin = bin - 2;
|
|
||||||
if (leftbin < 1)
|
|
||||||
leftbin = 1;
|
|
||||||
float valueAtMax = 0.0;
|
|
||||||
float max = leftbin + CubicMaximize(mProcessed[leftbin],
|
|
||||||
mProcessed[leftbin + 1],
|
|
||||||
mProcessed[leftbin + 2],
|
|
||||||
mProcessed[leftbin + 3], &valueAtMax);
|
|
||||||
|
|
||||||
float thispeak;
|
|
||||||
if (alg == 0)
|
|
||||||
thispeak = max * mRate / mWindowSize;
|
|
||||||
else
|
|
||||||
thispeak = max / mRate;
|
|
||||||
|
|
||||||
if (fabs(thispeak - xPos) < bestdist) {
|
|
||||||
bestpeak = thispeak;
|
|
||||||
bestdist = fabs(thispeak - xPos);
|
|
||||||
bestValue = valueAtMax;
|
|
||||||
if (thispeak > xPos)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
up = nowUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
int px;
|
int px;
|
||||||
if (mLogAxis)
|
if (mLogAxis)
|
||||||
@ -861,10 +895,10 @@ void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
|||||||
|
|
||||||
if (mLogAxis) {
|
if (mLogAxis) {
|
||||||
xPos = xMin * pow(xStep, mMouseX - (r.x + 1));
|
xPos = xMin * pow(xStep, mMouseX - (r.x + 1));
|
||||||
value = GetProcessedValue(xPos, xPos * xStep);
|
value = mAnalyst->GetProcessedValue(xPos, xPos * xStep);
|
||||||
} else {
|
} else {
|
||||||
xPos = xMin + xStep * (mMouseX - (r.x + 1));
|
xPos = xMin + xStep * (mMouseX - (r.x + 1));
|
||||||
value = GetProcessedValue(xPos, xPos + xStep);
|
value = mAnalyst->GetProcessedValue(xPos, xPos + xStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString info;
|
wxString info;
|
||||||
@ -873,7 +907,7 @@ void FreqWindow::PlotPaint(wxPaintEvent & evt)
|
|||||||
const wxChar *xp;
|
const wxChar *xp;
|
||||||
const wxChar *pp;
|
const wxChar *pp;
|
||||||
|
|
||||||
if (alg == 0) {
|
if (alg == SpectrumAnalyst::Spectrum) {
|
||||||
xpitch = PitchName_Absolute(FreqToMIDInote(xPos));
|
xpitch = PitchName_Absolute(FreqToMIDInote(xPos));
|
||||||
peakpitch = PitchName_Absolute(FreqToMIDInote(bestpeak));
|
peakpitch = PitchName_Absolute(FreqToMIDInote(bestpeak));
|
||||||
xp = xpitch.c_str();
|
xp = xpitch.c_str();
|
||||||
@ -946,41 +980,80 @@ void FreqWindow::Plot()
|
|||||||
void FreqWindow::Recalc()
|
void FreqWindow::Recalc()
|
||||||
{
|
{
|
||||||
//wxLogDebug(wxT("Starting FreqWindow::Recalc()"));
|
//wxLogDebug(wxT("Starting FreqWindow::Recalc()"));
|
||||||
if (mProcessed)
|
|
||||||
delete[] mProcessed;
|
|
||||||
mProcessed = NULL;
|
|
||||||
|
|
||||||
if (!mData) {
|
if (!mData) {
|
||||||
mFreqPlot->Refresh(true);
|
mFreqPlot->Refresh(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int alg = mAlgChoice->GetSelection();
|
SpectrumAnalyst::Algorithm alg =
|
||||||
|
SpectrumAnalyst::Algorithm(mAlgChoice->GetSelection());
|
||||||
int windowFunc = mFuncChoice->GetSelection();
|
int windowFunc = mFuncChoice->GetSelection();
|
||||||
long windowSize = 0;
|
long windowSize = 0;
|
||||||
(mSizeChoice->GetStringSelection()).ToLong(&windowSize);
|
(mSizeChoice->GetStringSelection()).ToLong(&windowSize);
|
||||||
|
mWindowSize = windowSize;
|
||||||
|
|
||||||
|
//Progress dialog over FFT operation
|
||||||
|
std::auto_ptr<ProgressDialog> progress
|
||||||
|
(new ProgressDialog(_("Plot Spectrum"),_("Drawing Spectrum")));
|
||||||
|
|
||||||
|
if(!mAnalyst->Calculate(alg, windowFunc, mWindowSize, mRate,
|
||||||
|
mData, mDataLen,
|
||||||
|
&mYMin, &mYMax, progress.get())) {
|
||||||
|
mFreqPlot->Refresh(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alg == SpectrumAnalyst::Spectrum) {
|
||||||
|
if(mYMin < -dBRange)
|
||||||
|
mYMin = -dBRange;
|
||||||
|
if(mYMax <= -dBRange)
|
||||||
|
mYMax = -dBRange + 10.; // it's all out of range, but show a scale.
|
||||||
|
else
|
||||||
|
mYMax += .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wxLogDebug(wxT("About to draw plot in FreqWindow::Recalc()"));
|
||||||
|
DrawPlot();
|
||||||
|
mFreqPlot->Refresh(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpectrumAnalyst::Calculate(Algorithm alg, int windowFunc,
|
||||||
|
int windowSize, double rate,
|
||||||
|
const float *data, int dataLen,
|
||||||
|
float *pYMin, float *pYMax,
|
||||||
|
ProgressDialog *progress)
|
||||||
|
{
|
||||||
|
// Wipe old data
|
||||||
|
mProcessed.resize(0);
|
||||||
|
mRate = 0.0;
|
||||||
|
mWindowSize = 0;
|
||||||
|
|
||||||
|
// Validate inputs
|
||||||
int f = NumWindowFuncs();
|
int f = NumWindowFuncs();
|
||||||
|
|
||||||
if (!(windowSize >= 32 && windowSize <= 65536 &&
|
if (!(windowSize >= 32 && windowSize <= 65536 &&
|
||||||
alg >= 0 && alg <= 4 && windowFunc >= 0 && windowFunc < f)) {
|
alg >= SpectrumAnalyst::Spectrum &&
|
||||||
mFreqPlot->Refresh(true);
|
alg < SpectrumAnalyst::NumAlgorithms &&
|
||||||
return;
|
windowFunc >= 0 && windowFunc < f)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dataLen < windowSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now repopulate
|
||||||
|
mRate = rate;
|
||||||
mWindowSize = windowSize;
|
mWindowSize = windowSize;
|
||||||
|
mAlg = alg;
|
||||||
|
|
||||||
if (mDataLen < mWindowSize) {
|
int half = mWindowSize / 2;
|
||||||
mFreqPlot->Refresh(true);
|
mProcessed.resize(mWindowSize);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mProcessed = new float[mWindowSize];
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < mWindowSize; i++)
|
for (i = 0; i < mWindowSize; i++)
|
||||||
mProcessed[i] = float(0.0);
|
mProcessed[i] = float(0.0);
|
||||||
int half = mWindowSize / 2;
|
|
||||||
|
|
||||||
float *in = new float[mWindowSize];
|
float *in = new float[mWindowSize];
|
||||||
float *in2 = new float[mWindowSize];
|
float *in2 = new float[mWindowSize];
|
||||||
@ -1002,26 +1075,23 @@ void FreqWindow::Recalc()
|
|||||||
else
|
else
|
||||||
wss = 1.0;
|
wss = 1.0;
|
||||||
|
|
||||||
//Progress dialog over FFT operation
|
|
||||||
ProgressDialog *mProgress = new ProgressDialog(_("Plot Spectrum"),_("Drawing Spectrum"));
|
|
||||||
|
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int windows = 0;
|
int windows = 0;
|
||||||
while (start + mWindowSize <= mDataLen) {
|
while (start + mWindowSize <= dataLen) {
|
||||||
for (i = 0; i < mWindowSize; i++)
|
for (i = 0; i < mWindowSize; i++)
|
||||||
in[i] = win[i] * mData[start + i];
|
in[i] = win[i] * data[start + i];
|
||||||
|
|
||||||
switch (alg) {
|
switch (alg) {
|
||||||
case 0: // Spectrum
|
case Spectrum:
|
||||||
PowerSpectrum(mWindowSize, in, out);
|
PowerSpectrum(mWindowSize, in, out);
|
||||||
|
|
||||||
for (i = 0; i < half; i++)
|
for (i = 0; i < half; i++)
|
||||||
mProcessed[i] += out[i];
|
mProcessed[i] += out[i];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case Autocorrelation:
|
||||||
case 2:
|
case CubeRootAutocorrelation:
|
||||||
case 3: // Autocorrelation, Cuberoot AC or Enhanced AC
|
case EnhancedAutocorrelation:
|
||||||
|
|
||||||
// Take FFT
|
// Take FFT
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
@ -1033,11 +1103,12 @@ void FreqWindow::Recalc()
|
|||||||
for (i = 0; i < mWindowSize; i++)
|
for (i = 0; i < mWindowSize; i++)
|
||||||
in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);
|
in[i] = (out[i] * out[i]) + (out2[i] * out2[i]);
|
||||||
|
|
||||||
if (alg == 1) {
|
if (alg == Autocorrelation) {
|
||||||
for (i = 0; i < mWindowSize; i++)
|
for (i = 0; i < mWindowSize; i++)
|
||||||
in[i] = sqrt(in[i]);
|
in[i] = sqrt(in[i]);
|
||||||
}
|
}
|
||||||
if (alg == 2 || alg == 3) {
|
if (alg == CubeRootAutocorrelation ||
|
||||||
|
alg == EnhancedAutocorrelation) {
|
||||||
// Tolonen and Karjalainen recommend taking the cube root
|
// Tolonen and Karjalainen recommend taking the cube root
|
||||||
// of the power, instead of the square root
|
// of the power, instead of the square root
|
||||||
|
|
||||||
@ -1056,7 +1127,7 @@ void FreqWindow::Recalc()
|
|||||||
mProcessed[i] += out[i];
|
mProcessed[i] += out[i];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // Cepstrum
|
case Cepstrum:
|
||||||
#ifdef EXPERIMENTAL_USE_REALFFTF
|
#ifdef EXPERIMENTAL_USE_REALFFTF
|
||||||
RealFFT(mWindowSize, in, out, out2);
|
RealFFT(mWindowSize, in, out, out2);
|
||||||
#else
|
#else
|
||||||
@ -1065,6 +1136,7 @@ void FreqWindow::Recalc()
|
|||||||
|
|
||||||
// Compute log power
|
// Compute log power
|
||||||
// Set a sane lower limit assuming maximum time amplitude of 1.0
|
// Set a sane lower limit assuming maximum time amplitude of 1.0
|
||||||
|
{
|
||||||
float power;
|
float power;
|
||||||
float minpower = 1e-20*mWindowSize*mWindowSize;
|
float minpower = 1e-20*mWindowSize*mWindowSize;
|
||||||
for (i = 0; i < mWindowSize; i++)
|
for (i = 0; i < mWindowSize; i++)
|
||||||
@ -1085,24 +1157,30 @@ void FreqWindow::Recalc()
|
|||||||
// Take real part of result
|
// Take real part of result
|
||||||
for (i = 0; i < half; i++)
|
for (i = 0; i < half; i++)
|
||||||
mProcessed[i] += out[i];
|
mProcessed[i] += out[i];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wxASSERT(false);
|
||||||
|
break;
|
||||||
} //switch
|
} //switch
|
||||||
|
|
||||||
start += half;
|
start += half;
|
||||||
windows++;
|
windows++;
|
||||||
// only update the progress dialogue infrequently to reduce it's overhead
|
// only update the progress dialogue infrequently to reduce its overhead
|
||||||
// If we do it every time, it spends as much time updating X11 as doing
|
// If we do it every time, it spends as much time updating X11 as doing
|
||||||
// the calculations. 10 seems a reasonable compromise on Linux that
|
// the calculations. 10 seems a reasonable compromise on Linux that
|
||||||
// doesn't make it unresponsive, but avoids the slowdown.
|
// doesn't make it unresponsive, but avoids the slowdown.
|
||||||
if ((windows % 10) == 0)
|
if (progress && (windows % 10) == 0)
|
||||||
mProgress->Update(1 - static_cast<float>(mDataLen - start) / mDataLen);
|
progress->Update(1 - static_cast<float>(dataLen - start) / dataLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
//wxLogDebug(wxT("Finished updating progress dialogue in FreqWindow::Recalc()"));
|
//wxLogDebug(wxT("Finished updating progress dialogue in SpectrumAnalyst::Recalc()"));
|
||||||
|
float mYMin = 1000000, mYMax = -1000000;
|
||||||
switch (alg) {
|
switch (alg) {
|
||||||
double scale;
|
double scale;
|
||||||
case 0: // Spectrum
|
case Spectrum:
|
||||||
// Convert to decibels
|
// Convert to decibels
|
||||||
mYMin = 1000000.;
|
mYMin = 1000000.;
|
||||||
mYMax = -1000000.;
|
mYMax = -1000000.;
|
||||||
@ -1115,19 +1193,10 @@ void FreqWindow::Recalc()
|
|||||||
else if(mProcessed[i] < mYMin)
|
else if(mProcessed[i] < mYMin)
|
||||||
mYMin = mProcessed[i];
|
mYMin = mProcessed[i];
|
||||||
}
|
}
|
||||||
if(mYMin < -dBRange)
|
|
||||||
mYMin = -dBRange;
|
|
||||||
if(mYMax <= -dBRange)
|
|
||||||
mYMax = -dBRange + 10.; // it's all out of range, but show a scale.
|
|
||||||
else
|
|
||||||
mYMax += .5;
|
|
||||||
|
|
||||||
mProcessedSize = half;
|
|
||||||
mYStep = 10;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // Standard Autocorrelation
|
case Autocorrelation:
|
||||||
case 2: // Cuberoot Autocorrelation
|
case CubeRootAutocorrelation:
|
||||||
for (i = 0; i < half; i++)
|
for (i = 0; i < half; i++)
|
||||||
mProcessed[i] = mProcessed[i] / windows;
|
mProcessed[i] = mProcessed[i] / windows;
|
||||||
|
|
||||||
@ -1139,13 +1208,9 @@ void FreqWindow::Recalc()
|
|||||||
mYMax = mProcessed[i];
|
mYMax = mProcessed[i];
|
||||||
else if (mProcessed[i] < mYMin)
|
else if (mProcessed[i] < mYMin)
|
||||||
mYMin = mProcessed[i];
|
mYMin = mProcessed[i];
|
||||||
|
|
||||||
mYStep = 1;
|
|
||||||
|
|
||||||
mProcessedSize = half;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // Enhanced Autocorrelation
|
case EnhancedAutocorrelation:
|
||||||
for (i = 0; i < half; i++)
|
for (i = 0; i < half; i++)
|
||||||
mProcessed[i] = mProcessed[i] / windows;
|
mProcessed[i] = mProcessed[i] / windows;
|
||||||
|
|
||||||
@ -1179,17 +1244,14 @@ void FreqWindow::Recalc()
|
|||||||
mYMax = mProcessed[i];
|
mYMax = mProcessed[i];
|
||||||
else if (mProcessed[i] < mYMin)
|
else if (mProcessed[i] < mYMin)
|
||||||
mYMin = mProcessed[i];
|
mYMin = mProcessed[i];
|
||||||
|
|
||||||
mYStep = 1;
|
|
||||||
|
|
||||||
mProcessedSize = half;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4: // Cepstrum
|
case Cepstrum:
|
||||||
for (i = 0; i < half; i++)
|
for (i = 0; i < half; i++)
|
||||||
mProcessed[i] = mProcessed[i] / windows;
|
mProcessed[i] = mProcessed[i] / windows;
|
||||||
|
|
||||||
// Find min/max, ignoring first and last few values
|
// Find min/max, ignoring first and last few values
|
||||||
|
{
|
||||||
int ignore = 4;
|
int ignore = 4;
|
||||||
mYMin = mProcessed[ignore];
|
mYMin = mProcessed[ignore];
|
||||||
mYMax = mProcessed[ignore];
|
mYMax = mProcessed[ignore];
|
||||||
@ -1198,10 +1260,11 @@ void FreqWindow::Recalc()
|
|||||||
mYMax = mProcessed[i];
|
mYMax = mProcessed[i];
|
||||||
else if (mProcessed[i] < mYMin)
|
else if (mProcessed[i] < mYMin)
|
||||||
mYMin = mProcessed[i];
|
mYMin = mProcessed[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
mYStep = 1;
|
default:
|
||||||
|
wxASSERT(false);
|
||||||
mProcessedSize = half;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1211,10 +1274,12 @@ void FreqWindow::Recalc()
|
|||||||
delete[]out2;
|
delete[]out2;
|
||||||
delete[]win;
|
delete[]win;
|
||||||
|
|
||||||
//wxLogDebug(wxT("About to draw plot in FreqWindow::Recalc()"));
|
if (pYMin)
|
||||||
DrawPlot();
|
*pYMin = mYMin;
|
||||||
mFreqPlot->Refresh(true);
|
if (pYMax)
|
||||||
delete mProgress;
|
*pYMax = mYMax;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreqWindow::OnExport(wxCommandEvent & WXUNUSED(event))
|
void FreqWindow::OnExport(wxCommandEvent & WXUNUSED(event))
|
||||||
@ -1241,17 +1306,19 @@ void FreqWindow::OnExport(wxCommandEvent & WXUNUSED(event))
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const int processedSize = mAnalyst->GetProcessedSize();
|
||||||
|
const float *const processed = mAnalyst->GetProcessed();
|
||||||
if (mAlgChoice->GetSelection() == 0) {
|
if (mAlgChoice->GetSelection() == 0) {
|
||||||
f.AddLine(_("Frequency (Hz)\tLevel (dB)"));
|
f.AddLine(_("Frequency (Hz)\tLevel (dB)"));
|
||||||
for (int i = 1; i < mProcessedSize; i++)
|
for (int i = 1; i < processedSize; i++)
|
||||||
f.AddLine(wxString::
|
f.AddLine(wxString::
|
||||||
Format(wxT("%f\t%f"), i * mRate / mWindowSize,
|
Format(wxT("%f\t%f"), i * mRate / mWindowSize,
|
||||||
mProcessed[i]));
|
processed[i]));
|
||||||
} else {
|
} else {
|
||||||
f.AddLine(_("Lag (seconds)\tFrequency (Hz)\tLevel"));
|
f.AddLine(_("Lag (seconds)\tFrequency (Hz)\tLevel"));
|
||||||
for (int i = 1; i < mProcessedSize; i++)
|
for (int i = 1; i < processedSize; i++)
|
||||||
f.AddLine(wxString::Format(wxT("%f\t%f\t%f"),
|
f.AddLine(wxString::Format(wxT("%f\t%f\t%f"),
|
||||||
i / mRate, mRate / i, mProcessed[i]));
|
i / mRate, mRate / i, processed[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __WXMAC__
|
#ifdef __WXMAC__
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#ifndef __AUDACITY_FREQ_WINDOW__
|
#ifndef __AUDACITY_FREQ_WINDOW__
|
||||||
#define __AUDACITY_FREQ_WINDOW__
|
#define __AUDACITY_FREQ_WINDOW__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
#include <wx/brush.h>
|
#include <wx/brush.h>
|
||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
@ -32,7 +34,7 @@ class FreqWindow;
|
|||||||
|
|
||||||
class TrackList;
|
class TrackList;
|
||||||
|
|
||||||
class FreqWindow;
|
class ProgressDialog;
|
||||||
|
|
||||||
class FreqPlot:public wxWindow {
|
class FreqPlot:public wxWindow {
|
||||||
public:
|
public:
|
||||||
@ -50,6 +52,45 @@ class FreqPlot:public wxWindow {
|
|||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SpectrumAnalyst
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Algorithm {
|
||||||
|
Spectrum,
|
||||||
|
Autocorrelation,
|
||||||
|
CubeRootAutocorrelation,
|
||||||
|
EnhancedAutocorrelation,
|
||||||
|
Cepstrum,
|
||||||
|
|
||||||
|
NumAlgorithms
|
||||||
|
};
|
||||||
|
|
||||||
|
SpectrumAnalyst();
|
||||||
|
~SpectrumAnalyst();
|
||||||
|
|
||||||
|
// Return true iff successful
|
||||||
|
bool Calculate(Algorithm alg,
|
||||||
|
int windowFunc, // see FFT.h for values
|
||||||
|
int windowSize, double rate,
|
||||||
|
const float *data, int dataLen,
|
||||||
|
float *pYMin = 0, float *pYMax = 0, // outputs
|
||||||
|
ProgressDialog *progress = 0);
|
||||||
|
|
||||||
|
const float *GetProcessed() const { return &mProcessed[0]; }
|
||||||
|
int GetProcessedSize() const { return mProcessed.size() / 2; }
|
||||||
|
|
||||||
|
float GetProcessedValue(float freq0, float freq1) const;
|
||||||
|
float FindPeak(float xPos, float *pY) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Algorithm mAlg;
|
||||||
|
double mRate;
|
||||||
|
int mWindowSize;
|
||||||
|
std::vector<float> mProcessed;
|
||||||
|
};
|
||||||
|
|
||||||
class FreqWindow:public wxDialog {
|
class FreqWindow:public wxDialog {
|
||||||
public:
|
public:
|
||||||
FreqWindow(wxWindow * parent, wxWindowID id,
|
FreqWindow(wxWindow * parent, wxWindowID id,
|
||||||
@ -81,7 +122,7 @@ class FreqWindow:public wxDialog {
|
|||||||
float *mBuffer;
|
float *mBuffer;
|
||||||
bool mDrawGrid;
|
bool mDrawGrid;
|
||||||
int mSize;
|
int mSize;
|
||||||
int mAlg;
|
SpectrumAnalyst::Algorithm mAlg;
|
||||||
int mFunc;
|
int mFunc;
|
||||||
int mAxis;
|
int mAxis;
|
||||||
int dBRange;
|
int dBRange;
|
||||||
@ -126,8 +167,6 @@ class FreqWindow:public wxDialog {
|
|||||||
int mDataLen;
|
int mDataLen;
|
||||||
float *mData;
|
float *mData;
|
||||||
int mWindowSize;
|
int mWindowSize;
|
||||||
float *mProcessed;
|
|
||||||
int mProcessedSize;
|
|
||||||
|
|
||||||
bool mLogAxis;
|
bool mLogAxis;
|
||||||
float mYMin;
|
float mYMin;
|
||||||
@ -139,7 +178,7 @@ class FreqWindow:public wxDialog {
|
|||||||
int mMouseX;
|
int mMouseX;
|
||||||
int mMouseY;
|
int mMouseY;
|
||||||
|
|
||||||
float GetProcessedValue(float freq0, float freq1);
|
std::auto_ptr<SpectrumAnalyst> mAnalyst;
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
@ -48,6 +48,9 @@ simplifies construction of menu items.
|
|||||||
#include <wx/statusbr.h>
|
#include <wx/statusbr.h>
|
||||||
#include <wx/utils.h>
|
#include <wx/utils.h>
|
||||||
|
|
||||||
|
#include "FreqWindow.h"
|
||||||
|
#include "TrackPanel.h"
|
||||||
|
|
||||||
#include "Project.h"
|
#include "Project.h"
|
||||||
#include "effects/EffectManager.h"
|
#include "effects/EffectManager.h"
|
||||||
|
|
||||||
|
@ -92,6 +92,7 @@ scroll information. It also has some status flags.
|
|||||||
|
|
||||||
#include "Project.h"
|
#include "Project.h"
|
||||||
|
|
||||||
|
#include "FreqWindow.h"
|
||||||
#include "AutoRecovery.h"
|
#include "AutoRecovery.h"
|
||||||
#include "AudacityApp.h"
|
#include "AudacityApp.h"
|
||||||
#include "AColor.h"
|
#include "AColor.h"
|
||||||
|
@ -23,13 +23,12 @@
|
|||||||
#include "DirManager.h"
|
#include "DirManager.h"
|
||||||
#include "UndoManager.h"
|
#include "UndoManager.h"
|
||||||
#include "ViewInfo.h"
|
#include "ViewInfo.h"
|
||||||
#include "TrackPanel.h"
|
#include "TrackPanelListener.h"
|
||||||
#include "AudioIO.h"
|
#include "AudioIO.h"
|
||||||
#include "commands/CommandManager.h"
|
#include "commands/CommandManager.h"
|
||||||
#include "effects/EffectManager.h"
|
#include "effects/EffectManager.h"
|
||||||
#include "xml/XMLTagHandler.h"
|
#include "xml/XMLTagHandler.h"
|
||||||
#include "toolbars/SelectionBar.h"
|
#include "toolbars/SelectionBarListener.h"
|
||||||
#include "FreqWindow.h"
|
|
||||||
|
|
||||||
#include <wx/defs.h>
|
#include <wx/defs.h>
|
||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
@ -56,13 +55,16 @@ class RecordingRecoveryHandler;
|
|||||||
class TrackList;
|
class TrackList;
|
||||||
class Tags;
|
class Tags;
|
||||||
|
|
||||||
|
class TrackPanel;
|
||||||
|
class FreqWindow;
|
||||||
|
|
||||||
// toolbar classes
|
// toolbar classes
|
||||||
class ControlToolBar;
|
class ControlToolBar;
|
||||||
class DeviceToolBar;
|
class DeviceToolBar;
|
||||||
class EditToolBar;
|
class EditToolBar;
|
||||||
class MeterToolBar;
|
class MeterToolBar;
|
||||||
class MixerToolBar;
|
class MixerToolBar;
|
||||||
class SelectionToolBar;
|
class SelectionBar;
|
||||||
class Toolbar;
|
class Toolbar;
|
||||||
class ToolManager;
|
class ToolManager;
|
||||||
class ToolsToolBar;
|
class ToolsToolBar;
|
||||||
@ -365,7 +367,7 @@ class AUDACITY_DLL_API AudacityProject: public wxFrame,
|
|||||||
LyricsWindow* GetLyricsWindow() { return mLyricsWindow; };
|
LyricsWindow* GetLyricsWindow() { return mLyricsWindow; };
|
||||||
MixerBoard* GetMixerBoard() { return mMixerBoard; };
|
MixerBoard* GetMixerBoard() { return mMixerBoard; };
|
||||||
|
|
||||||
// SelectionBar callback methods
|
// SelectionBarListener callback methods
|
||||||
|
|
||||||
virtual double AS_GetRate();
|
virtual double AS_GetRate();
|
||||||
virtual void AS_SetRate(double rate);
|
virtual void AS_SetRate(double rate);
|
||||||
|
@ -6,26 +6,52 @@
|
|||||||
|
|
||||||
Dominic Mazzoni
|
Dominic Mazzoni
|
||||||
|
|
||||||
|
*******************************************************************//**
|
||||||
|
|
||||||
|
\class SelectedRegion
|
||||||
|
\brief Defines a selected portion of a project
|
||||||
|
|
||||||
|
This includes starting and ending times, and other optional information
|
||||||
|
such as a frequency range, but not the set of selected tracks.
|
||||||
|
|
||||||
|
Maintains the invariants that ending time is not less than starting time
|
||||||
|
and that starting and ending frequencies, when both defined, are also
|
||||||
|
correctly ordered.
|
||||||
|
|
||||||
|
*//****************************************************************//**
|
||||||
|
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#ifndef __AUDACITY_SELECTEDREGION__
|
#ifndef __AUDACITY_SELECTEDREGION__
|
||||||
#define __AUDACITY_SELECTEDREGION__
|
#define __AUDACITY_SELECTEDREGION__
|
||||||
|
|
||||||
#include "Audacity.h"
|
#include "Audacity.h"
|
||||||
|
#include "Experimental.h"
|
||||||
|
|
||||||
class AUDACITY_DLL_API SelectedRegion {
|
class AUDACITY_DLL_API SelectedRegion {
|
||||||
|
|
||||||
// Maintains the invariant: t1() >= t0()
|
// Maintains the invariant: t1() >= t0()
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
static const int UndefinedFrequency = -1;
|
||||||
|
|
||||||
SelectedRegion()
|
SelectedRegion()
|
||||||
: mT0(0.0)
|
: mT0(0.0)
|
||||||
, mT1(0.0)
|
, mT1(0.0)
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
, mF0(UndefinedFrequency)
|
||||||
|
, mF1(UndefinedFrequency)
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SelectedRegion(double t0, double t1)
|
SelectedRegion(double t0, double t1)
|
||||||
: mT0(t0)
|
: mT0(t0)
|
||||||
, mT1(t1)
|
, mT1(t1)
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
, mF0(UndefinedFrequency)
|
||||||
|
, mF1(UndefinedFrequency)
|
||||||
|
#endif
|
||||||
{ ensureOrdering(); }
|
{ ensureOrdering(); }
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +63,10 @@ public:
|
|||||||
SelectedRegion(const SelectedRegion &x)
|
SelectedRegion(const SelectedRegion &x)
|
||||||
: mT0(x.mT0)
|
: mT0(x.mT0)
|
||||||
, mT1(x.mT1)
|
, mT1(x.mT1)
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
, mF0(x.mF0)
|
||||||
|
, mF1(x.mF1)
|
||||||
|
#endif
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SelectedRegion& operator=(const SelectedRegion& x)
|
SelectedRegion& operator=(const SelectedRegion& x)
|
||||||
@ -44,15 +74,34 @@ public:
|
|||||||
if (this != &x) {
|
if (this != &x) {
|
||||||
mT0 = x.mT0;
|
mT0 = x.mT0;
|
||||||
mT1 = x.mT1;
|
mT1 = x.mT1;
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
mF0 = x.mF0;
|
||||||
|
mF1 = x.mF1;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
|
||||||
double t0() const { return mT0; }
|
double t0() const { return mT0; }
|
||||||
double t1() const { return mT1; }
|
double t1() const { return mT1; }
|
||||||
double duration() const { return mT1 - mT0; }
|
double duration() const { return mT1 - mT0; }
|
||||||
bool isPoint() const { return mT1 <= mT0; }
|
bool isPoint() const { return mT1 <= mT0; }
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
double f0() const { return mF0; }
|
||||||
|
double f1() const { return mF1; }
|
||||||
|
double fc() const {
|
||||||
|
if (mF0 == UndefinedFrequency ||
|
||||||
|
mF1 == UndefinedFrequency)
|
||||||
|
return UndefinedFrequency;
|
||||||
|
else
|
||||||
|
return sqrt(mF0 * mF1);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Mutators
|
||||||
// PRL: to do: more integrity checks
|
// PRL: to do: more integrity checks
|
||||||
|
|
||||||
// Returns true iff the bounds got swapped
|
// Returns true iff the bounds got swapped
|
||||||
@ -105,6 +154,28 @@ public:
|
|||||||
|
|
||||||
void collapseToT1() { mT0 = mT1; }
|
void collapseToT1() { mT0 = mT1; }
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Returns true iff the bounds got swapped
|
||||||
|
bool setF0(double f) {
|
||||||
|
mF0 = f;
|
||||||
|
return ensureFrequencyOrdering();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true iff the bounds got swapped
|
||||||
|
bool setF1(double f) {
|
||||||
|
mF1 = f;
|
||||||
|
return ensureFrequencyOrdering();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true iff the bounds got swapped
|
||||||
|
bool setFrequencies(double f0, double f1)
|
||||||
|
{
|
||||||
|
mF0 = f0;
|
||||||
|
mF1 = f1;
|
||||||
|
return ensureFrequencyOrdering();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ensureOrdering()
|
bool ensureOrdering()
|
||||||
{
|
{
|
||||||
@ -118,8 +189,33 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
bool ensureFrequencyOrdering()
|
||||||
|
{
|
||||||
|
if (mF1 < 0)
|
||||||
|
mF1 = UndefinedFrequency;
|
||||||
|
if (mF0 < 0)
|
||||||
|
mF0 = UndefinedFrequency;
|
||||||
|
|
||||||
|
if (mF0 != UndefinedFrequency &&
|
||||||
|
mF1 != UndefinedFrequency &&
|
||||||
|
mF1 < mF0) {
|
||||||
|
const double t = mF1;
|
||||||
|
mF1 = mF0;
|
||||||
|
mF0 = t;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
double mT0;
|
double mT0;
|
||||||
double mT1;
|
double mT1;
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
double mF0; // low frequency
|
||||||
|
double mF1; // high frequency
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1780,6 +1780,8 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
bool autocorrelation,
|
bool autocorrelation,
|
||||||
bool logF)
|
bool logF)
|
||||||
{
|
{
|
||||||
|
enum { MONOCHROME_LINE = 230, COLORED_LINE = 0 };
|
||||||
|
|
||||||
#if PROFILE_WAVEFORM
|
#if PROFILE_WAVEFORM
|
||||||
# ifdef __WXMSW__
|
# ifdef __WXMSW__
|
||||||
__time64_t tv0, tv1;
|
__time64_t tv0, tv1;
|
||||||
@ -1794,6 +1796,13 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
double sel0 = viewInfo->selectedRegion.t0();
|
double sel0 = viewInfo->selectedRegion.t0();
|
||||||
double sel1 = viewInfo->selectedRegion.t1();
|
double sel1 = viewInfo->selectedRegion.t1();
|
||||||
|
|
||||||
|
double freqLo = SelectedRegion::UndefinedFrequency;
|
||||||
|
double freqHi = SelectedRegion::UndefinedFrequency;
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
freqLo = viewInfo->selectedRegion.f0();
|
||||||
|
freqHi = viewInfo->selectedRegion.f1();
|
||||||
|
#endif
|
||||||
|
|
||||||
double tOffset = clip->GetOffset();
|
double tOffset = clip->GetOffset();
|
||||||
double rate = clip->GetRate();
|
double rate = clip->GetRate();
|
||||||
double sps = 1./rate;
|
double sps = 1./rate;
|
||||||
@ -1922,7 +1931,7 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
minFreq = GetSpectrumLogMinFreq(ifreq/1000.0);
|
minFreq = GetSpectrumLogMinFreq(ifreq/1000.0);
|
||||||
if(minFreq < 1)
|
if(minFreq < 1)
|
||||||
// Paul L: I suspect this line is now unreachable
|
// Paul L: I suspect this line is now unreachable
|
||||||
minFreq = ifreq/1000.0;
|
minFreq = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool usePxCache = false;
|
bool usePxCache = false;
|
||||||
@ -1953,9 +1962,15 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PRL: Must the following two be integers?
|
||||||
int minSamples = int ((double)minFreq * (double)windowSize / rate + 0.5); // units are fft bins
|
int minSamples = int ((double)minFreq * (double)windowSize / rate + 0.5); // units are fft bins
|
||||||
int maxSamples = int ((double)maxFreq * (double)windowSize / rate + 0.5);
|
int maxSamples = int ((double)maxFreq * (double)windowSize / rate + 0.5);
|
||||||
float binPerPx = float(maxSamples - minSamples) / float(mid.height);
|
float binPerPx = float(maxSamples - minSamples) / float(mid.height);
|
||||||
|
float selBinLo = freqLo * (double)windowSize / rate;
|
||||||
|
float selBinHi = freqHi * (double)windowSize / rate;
|
||||||
|
float selBinCenter =
|
||||||
|
((freqLo < 0 || freqHi < 0) ? -1 : sqrt(freqLo * freqHi))
|
||||||
|
* (double)windowSize / rate;
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
sampleCount w1 = (sampleCount) ((t0*rate + x *rate *tstep) + .5);
|
sampleCount w1 = (sampleCount) ((t0*rate + x *rate *tstep) + .5);
|
||||||
@ -2024,15 +2039,31 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
if (!logF)
|
if (!logF)
|
||||||
{
|
{
|
||||||
for (int yy = 0; yy < mid.height; yy++) {
|
for (int yy = 0; yy < mid.height; yy++) {
|
||||||
bool selflag = (ssel0 <= w0 && w1 < ssel1);
|
float bin0 = float (yy) * binPerPx + minSamples;
|
||||||
|
float bin1 = float (yy + 1) * binPerPx + minSamples;
|
||||||
|
|
||||||
|
bool centerLine = false;
|
||||||
|
AColor::ColorGradientChoice selected =
|
||||||
|
AColor::ColorGradientUnselected;
|
||||||
|
if (ssel0 <= w0 && w1 < ssel1)
|
||||||
|
{
|
||||||
|
if (selBinCenter >= 0 &&
|
||||||
|
bin0 <= selBinCenter &&
|
||||||
|
selBinCenter < bin1)
|
||||||
|
centerLine = true;
|
||||||
|
else if((selBinLo < 0 || selBinLo < bin1) &&
|
||||||
|
(selBinHi < 0 || selBinHi > bin0))
|
||||||
|
selected =
|
||||||
|
AColor::ColorGradientTimeAndFrequencySelected;
|
||||||
|
else
|
||||||
|
selected =
|
||||||
|
AColor::ColorGradientTimeSelected;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char rv, gv, bv;
|
unsigned char rv, gv, bv;
|
||||||
float value;
|
float value;
|
||||||
|
|
||||||
if(!usePxCache) {
|
if(!usePxCache) {
|
||||||
float bin0 = float (yy) * binPerPx + minSamples;
|
|
||||||
float bin1 = float (yy + 1) * binPerPx + minSamples;
|
|
||||||
|
|
||||||
|
|
||||||
if (int (bin1) == int (bin0))
|
if (int (bin1) == int (bin0))
|
||||||
value = freq[half * x + int (bin0)];
|
value = freq[half * x + int (bin0)];
|
||||||
else {
|
else {
|
||||||
@ -2069,7 +2100,11 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
else
|
else
|
||||||
value = clip->mSpecPxCache->values[x * mid.height + yy];
|
value = clip->mSpecPxCache->values[x * mid.height + yy];
|
||||||
|
|
||||||
GetColorGradient(value, selflag, mIsGrayscale, &rv, &gv, &bv);
|
if(centerLine)
|
||||||
|
// Draw center frequency line
|
||||||
|
rv = gv = bv = (mIsGrayscale ? MONOCHROME_LINE : COLORED_LINE);
|
||||||
|
else
|
||||||
|
GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv);
|
||||||
|
|
||||||
int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
|
int px = ((mid.height - 1 - yy) * mid.width + x) * 3;
|
||||||
data[px++] = rv;
|
data[px++] = rv;
|
||||||
@ -2079,7 +2114,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
}
|
}
|
||||||
else //logF
|
else //logF
|
||||||
{
|
{
|
||||||
bool selflag = (ssel0 <= w0 && w1 < ssel1);
|
|
||||||
unsigned char rv, gv, bv;
|
unsigned char rv, gv, bv;
|
||||||
float value;
|
float value;
|
||||||
int x0=x*half;
|
int x0=x*half;
|
||||||
@ -2151,7 +2185,6 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
float yy2 = yy2_base;
|
float yy2 = yy2_base;
|
||||||
double exp_scale_per_height = exp(scale/mid.height);
|
double exp_scale_per_height = exp(scale/mid.height);
|
||||||
for (int yy = 0; yy < mid.height; yy++) {
|
for (int yy = 0; yy < mid.height; yy++) {
|
||||||
if(!usePxCache) {
|
|
||||||
if (int(yy2)>=half)
|
if (int(yy2)>=half)
|
||||||
yy2=half-1;
|
yy2=half-1;
|
||||||
if (yy2<0)
|
if (yy2<0)
|
||||||
@ -2165,6 +2198,26 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
yy3=0;
|
yy3=0;
|
||||||
float bin1 = float(yy3);
|
float bin1 = float(yy3);
|
||||||
|
|
||||||
|
bool centerLine = false;
|
||||||
|
AColor::ColorGradientChoice selected =
|
||||||
|
AColor::ColorGradientUnselected;
|
||||||
|
if (ssel0 <= w0 && w1 < ssel1)
|
||||||
|
{
|
||||||
|
if (selBinCenter >= 0 &&
|
||||||
|
bin0 <= selBinCenter &&
|
||||||
|
selBinCenter < bin1)
|
||||||
|
centerLine = true;
|
||||||
|
else if((selBinLo < 0 || selBinLo < bin1) &&
|
||||||
|
(selBinHi < 0 || selBinHi > bin0))
|
||||||
|
selected =
|
||||||
|
AColor::ColorGradientTimeAndFrequencySelected;
|
||||||
|
else
|
||||||
|
selected =
|
||||||
|
AColor::ColorGradientTimeSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!usePxCache) {
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_FIND_NOTES
|
#ifdef EXPERIMENTAL_FIND_NOTES
|
||||||
if (mFftFindNotes) {
|
if (mFftFindNotes) {
|
||||||
if (it < maximas) {
|
if (it < maximas) {
|
||||||
@ -2204,12 +2257,16 @@ void TrackArtist::DrawClipSpectrum(WaveTrack *track,
|
|||||||
if (value < 0.0)
|
if (value < 0.0)
|
||||||
value = float(0.0);
|
value = float(0.0);
|
||||||
clip->mSpecPxCache->values[x * mid.height + yy] = value;
|
clip->mSpecPxCache->values[x * mid.height + yy] = value;
|
||||||
yy2 = yy2_base;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
value = clip->mSpecPxCache->values[x * mid.height + yy];
|
value = clip->mSpecPxCache->values[x * mid.height + yy];
|
||||||
|
yy2 = yy2_base;
|
||||||
|
|
||||||
GetColorGradient(value, selflag, mIsGrayscale, &rv, &gv, &bv);
|
if(centerLine)
|
||||||
|
// Draw center frequency line
|
||||||
|
rv = gv = bv = (mIsGrayscale ? MONOCHROME_LINE : COLORED_LINE);
|
||||||
|
else
|
||||||
|
GetColorGradient(value, selected, mIsGrayscale, &rv, &gv, &bv);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
#ifdef EXPERIMENTAL_FFT_Y_GRID
|
||||||
if (mFftYGrid && yGrid[yy]) {
|
if (mFftYGrid && yGrid[yy]) {
|
||||||
|
@ -184,6 +184,8 @@ is time to refresh some aspect of the screen.
|
|||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
#include <wx/image.h>
|
#include <wx/image.h>
|
||||||
|
|
||||||
|
#include "FreqWindow.h" // for SpectrumAnalyst
|
||||||
|
|
||||||
#include "AColor.h"
|
#include "AColor.h"
|
||||||
#include "AllThemeResources.h"
|
#include "AllThemeResources.h"
|
||||||
#include "AudacityApp.h"
|
#include "AudacityApp.h"
|
||||||
@ -459,6 +461,7 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
|||||||
mTrackArtist(NULL),
|
mTrackArtist(NULL),
|
||||||
mBacking(NULL),
|
mBacking(NULL),
|
||||||
mRefreshBacking(false),
|
mRefreshBacking(false),
|
||||||
|
mConverter(),
|
||||||
mAutoScrolling(false),
|
mAutoScrolling(false),
|
||||||
mVertScrollRemainder(0),
|
mVertScrollRemainder(0),
|
||||||
vrulerSize(36,0)
|
vrulerSize(36,0)
|
||||||
@ -561,6 +564,11 @@ TrackPanel::TrackPanel(wxWindow * parent, wxWindowID id,
|
|||||||
wxCommandEventHandler(TrackPanel::OnTrackListUpdated),
|
wxCommandEventHandler(TrackPanel::OnTrackListUpdated),
|
||||||
NULL,
|
NULL,
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
mFrequencySnapper.reset(new SpectrumAnalyst());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackPanel::~TrackPanel()
|
TrackPanel::~TrackPanel()
|
||||||
@ -1509,6 +1517,7 @@ bool TrackPanel::SetCursorByActivity( )
|
|||||||
#endif
|
#endif
|
||||||
case IsOverCutLine:
|
case IsOverCutLine:
|
||||||
SetCursor( unsafe ? *mDisabledCursor : *mArrowCursor);
|
SetCursor( unsafe ? *mDisabledCursor : *mArrowCursor);
|
||||||
|
// what, no return true here? -- PRL
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1595,6 +1604,11 @@ void TrackPanel::SetCursorAndTipWhenInLabelTrack( LabelTrack * pLT,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Seems 4 is too small to work at the top. Why?
|
||||||
|
enum { FREQ_SNAP_DISTANCE = 10 };
|
||||||
|
#endif
|
||||||
|
|
||||||
// The select tool can have different cursors and prompts depending on what
|
// The select tool can have different cursors and prompts depending on what
|
||||||
// we hover over, most notably when hovering over the selction boundaries.
|
// we hover over, most notably when hovering over the selction boundaries.
|
||||||
// Determine and set the cursor and tip accordingly.
|
// Determine and set the cursor and tip accordingly.
|
||||||
@ -1678,6 +1692,97 @@ void TrackPanel::SetCursorAndTipWhenSelectTool( Track * t,
|
|||||||
*ppTip = _("Click and drag to move right selection boundary.");
|
*ppTip = _("Click and drag to move right selection boundary.");
|
||||||
SetCursor(*mAdjustRightSelectionCursor);
|
SetCursor(*mAdjustRightSelectionCursor);
|
||||||
}
|
}
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
else if (mAdjustSelectionEdges &&
|
||||||
|
!mViewInfo->selectedRegion.isPoint() &&
|
||||||
|
t->GetKind() == Track::Wave)
|
||||||
|
{
|
||||||
|
const WaveTrack *wt = static_cast<WaveTrack*>(t);
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
if(logF || display == WaveTrack::SpectrumDisplay) {
|
||||||
|
double centerFrequency = mViewInfo->selectedRegion.fc();
|
||||||
|
|
||||||
|
if (event.AltDown()) {
|
||||||
|
if (event.ShiftDown()) {
|
||||||
|
// Even if top or bottom is not defined, it un-snaps
|
||||||
|
*ppTip = _("Click and drag to adjust boundaries of selected frequency band.");
|
||||||
|
return; // default cursor
|
||||||
|
}
|
||||||
|
else if (mFreqSelMode == FREQ_SEL_SNAPPING_CENTER) {
|
||||||
|
*ppTip = _("Move to snap center to peak frequencies, then click and drag to adjust band width.");
|
||||||
|
return; // default cursor
|
||||||
|
}
|
||||||
|
else if (centerFrequency >= 0) {
|
||||||
|
// PRL: Todo: fix message for Mac, say "Command" ?
|
||||||
|
*ppTip =
|
||||||
|
_("Click and drag to adjust band width about a fixed center, or hit Control to move the center.");
|
||||||
|
return; // default cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Is the cursor over the geometric mean frequency?
|
||||||
|
bool adjustCenter = false;
|
||||||
|
if (centerFrequency >= 0) {
|
||||||
|
const wxInt64 centerSel =
|
||||||
|
FrequencyToPosition(centerFrequency, r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjustCenter =
|
||||||
|
within(event.m_y, centerSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjustCenter) {
|
||||||
|
*ppTip =
|
||||||
|
_("Click and drag to adjust center selection frequency.");
|
||||||
|
SetCursor(*mEnvelopeCursor); // For want of a better...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the cursor over the bottom selection boundary?
|
||||||
|
bool adjust_bottom = false;
|
||||||
|
if (mViewInfo->selectedRegion.f0() < 0)
|
||||||
|
// Should we un-snap the bottom from "all"?
|
||||||
|
adjust_bottom =
|
||||||
|
within(event.m_y, r.y + r.height, FREQ_SNAP_DISTANCE);
|
||||||
|
else {
|
||||||
|
const wxInt64 bottomSel =
|
||||||
|
FrequencyToPosition(mViewInfo->selectedRegion.f0(),
|
||||||
|
r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjust_bottom =
|
||||||
|
within(event.m_y, bottomSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjust_bottom) {
|
||||||
|
*ppTip =
|
||||||
|
_("Click and drag to adjust bottom selection frequency.");
|
||||||
|
SetCursor(*mEnvelopeCursor); // For want of a better...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the cursor over the top selection boundary?
|
||||||
|
bool adjust_top = false;
|
||||||
|
if (mViewInfo->selectedRegion.f1() < 0)
|
||||||
|
// Should we un-snap the top from "all"?
|
||||||
|
adjust_top =
|
||||||
|
within(event.m_y, r.y, FREQ_SNAP_DISTANCE);
|
||||||
|
else {
|
||||||
|
const wxInt64 topSel =
|
||||||
|
FrequencyToPosition(mViewInfo->selectedRegion.f1(),
|
||||||
|
r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjust_top =
|
||||||
|
within(event.m_y, topSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjust_top) {
|
||||||
|
*ppTip =
|
||||||
|
_("Click and drag to adjust top selection frequency.");
|
||||||
|
SetCursor(*mEnvelopeCursor); // For want of a better...
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
else if (HitTestStretch(t, r, event)) {
|
else if (HitTestStretch(t, r, event)) {
|
||||||
*ppTip = _("Click and drag to stretch within selected region.");
|
*ppTip = _("Click and drag to stretch within selected region.");
|
||||||
@ -1856,6 +1961,11 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
|
|||||||
//Send the new selection state to the undo/redo stack:
|
//Send the new selection state to the undo/redo stack:
|
||||||
MakeParentModifyState(false);
|
MakeParentModifyState(false);
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// This stops center snapping with mouse movement
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if (event.LeftDClick() && !event.ShiftDown()) {
|
} else if (event.LeftDClick() && !event.ShiftDown()) {
|
||||||
if (!mCapturedTrack) {
|
if (!mCapturedTrack) {
|
||||||
wxRect r;
|
wxRect r;
|
||||||
@ -1896,6 +2006,21 @@ void TrackPanel::HandleSelect(wxMouseEvent & event)
|
|||||||
SetCapturedTrack( NULL );
|
SetCapturedTrack( NULL );
|
||||||
MakeParentModifyState(false);
|
MakeParentModifyState(false);
|
||||||
}
|
}
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
else if (!event.IsButton() && event.AltDown()) {
|
||||||
|
// Enter center-snapping mode,
|
||||||
|
// or readjust if there already
|
||||||
|
if ((mFreqSelMode == FREQ_SEL_SNAPPING_CENTER
|
||||||
|
// Already in this selection mode
|
||||||
|
||
|
||||||
|
mFreqSelCenter < 0
|
||||||
|
// No defined center
|
||||||
|
)
|
||||||
|
&&
|
||||||
|
!mViewInfo->selectedRegion.isPoint())
|
||||||
|
MoveSnappingFreqSelection(event.m_y, r.y, r.height, t);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
done:
|
done:
|
||||||
SelectionHandleDrag(event, t);
|
SelectionHandleDrag(event, t);
|
||||||
|
|
||||||
@ -1940,6 +2065,63 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
bool stretch = HitTestStretch(pTrack, r, event);
|
bool stretch = HitTestStretch(pTrack, r, event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
if (event.AltDown() && pTrack &&
|
||||||
|
pTrack->GetKind() == Track::Wave) {
|
||||||
|
const WaveTrack* wt = static_cast<WaveTrack*>(pTrack);
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
if (logF || display == WaveTrack::SpectrumDisplay) {
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
const double rate = wt->GetRate();
|
||||||
|
|
||||||
|
// If the Alt button is down, modify the current frequency selection.
|
||||||
|
|
||||||
|
// If not shift-alt, and center is defined, drag the width;
|
||||||
|
// otherwise edit the selection boundary nearest the mouse click.
|
||||||
|
|
||||||
|
bool dragWidth = false;
|
||||||
|
mFreqSelCenter = mViewInfo->selectedRegion.fc();
|
||||||
|
|
||||||
|
if (!event.ShiftDown() && mFreqSelCenter >= 0)
|
||||||
|
dragWidth = true;
|
||||||
|
|
||||||
|
double selend =
|
||||||
|
PositionToFrequency(false, event.m_y, r.y, r.height, rate, logF);
|
||||||
|
double high =
|
||||||
|
mViewInfo->selectedRegion.f1() < 0
|
||||||
|
? rate / 2 : mViewInfo->selectedRegion.f1();
|
||||||
|
double low =
|
||||||
|
mViewInfo->selectedRegion.f0() < 0
|
||||||
|
? 0 : mViewInfo->selectedRegion.f0();
|
||||||
|
if (logF)
|
||||||
|
selend = log(std::max(1.0, selend)),
|
||||||
|
high = log(std::max(1.0, high)),
|
||||||
|
low = log(std::max(1.0, low));
|
||||||
|
const bool adjustLow = (fabs (selend - low) < fabs (selend - high));
|
||||||
|
if (adjustLow) {
|
||||||
|
mFreqSelMode = FREQ_SEL_BOTTOM_FREE;
|
||||||
|
mFreqSelStart = mViewInfo->selectedRegion.f1();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mFreqSelMode = FREQ_SEL_TOP_FREE;
|
||||||
|
mFreqSelStart = mViewInfo->selectedRegion.f0();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not adjust time boundaries
|
||||||
|
mSelStart = -1;
|
||||||
|
|
||||||
|
ExtendFreqSelection(event.m_y, r.y, r.height, dragWidth);
|
||||||
|
UpdateSelectionDisplay();
|
||||||
|
// Frequency selection doesn't persist (yet?), so skip this:
|
||||||
|
// MakeParentModifyState(false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
#endif
|
||||||
if (event.ShiftDown()
|
if (event.ShiftDown()
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
&& !stretch
|
&& !stretch
|
||||||
@ -1978,8 +2160,14 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
else
|
else
|
||||||
mSelStart = mViewInfo->selectedRegion.t0();
|
mSelStart = mViewInfo->selectedRegion.t0();
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// If drag starts, change time selection only
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
#endif
|
||||||
|
|
||||||
// If the shift button is down, extend the current selection.
|
// If the shift button is down, extend the current selection.
|
||||||
ExtendSelection(event.m_x, r.x, pTrack);
|
ExtendSelection(event.m_x, r.x, pTrack);
|
||||||
|
UpdateSelectionDisplay();
|
||||||
MakeParentModifyState(false);
|
MakeParentModifyState(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2030,26 +2218,130 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
}
|
}
|
||||||
//Make sure you are within the selected track
|
//Make sure you are within the selected track
|
||||||
if (pTrack && pTrack->GetSelected()) {
|
if (pTrack && pTrack->GetSelected()) {
|
||||||
|
// Adjusting selection edges can be turned off in the
|
||||||
|
// preferences now
|
||||||
|
if (mAdjustSelectionEdges) {
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Check for dragging of top, bottom, or center
|
||||||
|
if (!mViewInfo->selectedRegion.isPoint() &&
|
||||||
|
pTrack->GetKind() == Track::Wave) {
|
||||||
|
const WaveTrack *wt = static_cast<WaveTrack*>(pTrack);
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
if (logF || display == WaveTrack::SpectrumDisplay) {
|
||||||
|
// Adjust frequency selection, no modifier keys
|
||||||
|
|
||||||
|
// Is the cursor over the geometric mean frequency?
|
||||||
|
bool adjustCenter = false;
|
||||||
|
mFreqSelCenter = mViewInfo->selectedRegion.fc();
|
||||||
|
if (mFreqSelCenter >= 0) {
|
||||||
|
const wxInt64 centerSel =
|
||||||
|
FrequencyToPosition(mFreqSelCenter, r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjustCenter =
|
||||||
|
within(event.m_y, centerSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjustCenter) {
|
||||||
|
// Keep width constant
|
||||||
|
|
||||||
|
// Disable extension of time selection, unless also near
|
||||||
|
// left or right boundary as tested later
|
||||||
|
mSelStart = -1;
|
||||||
|
mFreqSelMode = FREQ_SEL_DRAG_CENTER;
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
// High (and low) must be defined if center is
|
||||||
|
// Use this to remember the starting ratio:
|
||||||
|
mFreqSelStart = mViewInfo->selectedRegion.f1() / mFreqSelCenter;
|
||||||
|
startNewSelection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startNewSelection) {
|
||||||
|
// Is the cursor over the bottom selection boundary?
|
||||||
|
bool adjust_bottom = false;
|
||||||
|
if (mViewInfo->selectedRegion.f0() < 0)
|
||||||
|
// Should we un-snap the bottom from "all"?
|
||||||
|
adjust_bottom =
|
||||||
|
within(event.m_y, r.y + r.height, FREQ_SNAP_DISTANCE);
|
||||||
|
else {
|
||||||
|
const wxInt64 bottomSel =
|
||||||
|
FrequencyToPosition(mViewInfo->selectedRegion.f0(),
|
||||||
|
r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjust_bottom =
|
||||||
|
within(event.m_y, bottomSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjust_bottom) {
|
||||||
|
// Pin top edge
|
||||||
|
// Disable extension of time selection, unless also near
|
||||||
|
// left or right boundary as tested later
|
||||||
|
mSelStart = -1;
|
||||||
|
mFreqSelMode = FREQ_SEL_BOTTOM_FREE;
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
mFreqSelStart = mViewInfo->selectedRegion.f1();
|
||||||
|
startNewSelection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startNewSelection) {
|
||||||
|
// Is the cursor over the bottom selection boundary?
|
||||||
|
bool adjust_top = false;
|
||||||
|
if (mViewInfo->selectedRegion.f1() < 0)
|
||||||
|
// Should we un-snap the top from "all"?
|
||||||
|
adjust_top =
|
||||||
|
within(event.m_y, r.y, FREQ_SNAP_DISTANCE);
|
||||||
|
else {
|
||||||
|
const wxInt64 topSel =
|
||||||
|
FrequencyToPosition(mViewInfo->selectedRegion.f1(),
|
||||||
|
r.y, r.height,
|
||||||
|
wt->GetRate(), logF);
|
||||||
|
adjust_top =
|
||||||
|
within(event.m_y, topSel, SELECTION_RESIZE_REGION);
|
||||||
|
}
|
||||||
|
if (adjust_top) {
|
||||||
|
// Pin bottom edge
|
||||||
|
// Disable extension of time selection, unless also near
|
||||||
|
// left or right boundary as tested later
|
||||||
|
mSelStart = -1;
|
||||||
|
mFreqSelMode = FREQ_SEL_TOP_FREE;
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
mFreqSelStart = mViewInfo->selectedRegion.f0();
|
||||||
|
startNewSelection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // spectrum type
|
||||||
|
} // wave track
|
||||||
|
#endif
|
||||||
|
|
||||||
wxInt64 leftSel = TimeToPosition(mViewInfo->selectedRegion.t0(), r.x);
|
wxInt64 leftSel = TimeToPosition(mViewInfo->selectedRegion.t0(), r.x);
|
||||||
wxInt64 rightSel = TimeToPosition(mViewInfo->selectedRegion.t1(), r.x);
|
wxInt64 rightSel = TimeToPosition(mViewInfo->selectedRegion.t1(), r.x);
|
||||||
wxASSERT(leftSel <= rightSel);
|
wxASSERT(leftSel <= rightSel);
|
||||||
// Adjusting selection edges can be turned off in the
|
|
||||||
// preferences now
|
|
||||||
if (!mAdjustSelectionEdges) {
|
|
||||||
}
|
|
||||||
// Is the cursor over the left selection boundary?
|
// Is the cursor over the left selection boundary?
|
||||||
else if (within(event.m_x, leftSel, SELECTION_RESIZE_REGION)) {
|
if (within(event.m_x, leftSel, SELECTION_RESIZE_REGION)) {
|
||||||
// Pin the right selection boundary
|
// Pin the right selection boundary
|
||||||
mSelStart = mViewInfo->selectedRegion.t1();
|
mSelStart = mViewInfo->selectedRegion.t1();
|
||||||
|
if (startNewSelection) {
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Enable time extension only
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
#endif
|
||||||
startNewSelection = false;
|
startNewSelection = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Is the cursor over the right selection boundary?
|
// Is the cursor over the right selection boundary?
|
||||||
else if (within(event.m_x, rightSel, SELECTION_RESIZE_REGION)) {
|
else if (within(event.m_x, rightSel, SELECTION_RESIZE_REGION)) {
|
||||||
// Pin the left selection boundary
|
// Pin the left selection boundary
|
||||||
mSelStart = mViewInfo->selectedRegion.t0();
|
mSelStart = mViewInfo->selectedRegion.t0();
|
||||||
|
if (startNewSelection) {
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Enable time extension only
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
#endif
|
||||||
startNewSelection = false;
|
startNewSelection = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Determine if user clicked on a label track.
|
//Determine if user clicked on a label track.
|
||||||
if (pTrack && (pTrack->GetKind() == Track::Label))
|
if (pTrack && (pTrack->GetKind() == Track::Label))
|
||||||
@ -2160,6 +2452,9 @@ void TrackPanel::SelectionHandleClick(wxMouseEvent & event,
|
|||||||
if (startNewSelection) {
|
if (startNewSelection) {
|
||||||
// If we didn't move a selection boundary, start a new selection
|
// If we didn't move a selection boundary, start a new selection
|
||||||
SelectNone();
|
SelectNone();
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
StartFreqSelection (event.m_y, r.y, r.height, pTrack);
|
||||||
|
#endif
|
||||||
StartSelection(event.m_x, r.x);
|
StartSelection(event.m_x, r.x);
|
||||||
mTracks->Select(pTrack);
|
mTracks->Select(pTrack);
|
||||||
SetFocusedTrack(pTrack);
|
SetFocusedTrack(pTrack);
|
||||||
@ -2203,6 +2498,10 @@ void TrackPanel::StartSelection(int mouseXCoordinate, int trackLeftEdge)
|
|||||||
void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
||||||
Track *pTrack)
|
Track *pTrack)
|
||||||
{
|
{
|
||||||
|
if (mSelStart < 0)
|
||||||
|
// Must be dragging frequency bounds only.
|
||||||
|
return;
|
||||||
|
|
||||||
double selend = PositionToTime(mouseXCoordinate, trackLeftEdge);
|
double selend = PositionToTime(mouseXCoordinate, trackLeftEdge);
|
||||||
clip_bottom(selend, 0.0);
|
clip_bottom(selend, 0.0);
|
||||||
|
|
||||||
@ -2255,7 +2554,10 @@ void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
|||||||
//On-Demand: check to see if there is an OD thing associated with this track. If so we want to update the focal point for the task.
|
//On-Demand: check to see if there is an OD thing associated with this track. If so we want to update the focal point for the task.
|
||||||
if (pTrack && (pTrack->GetKind() == Track::Wave) && ODManager::IsInstanceCreated())
|
if (pTrack && (pTrack->GetKind() == Track::Wave) && ODManager::IsInstanceCreated())
|
||||||
ODManager::Instance()->DemandTrackUpdate((WaveTrack*)pTrack,sel0); //sel0 is sometimes less than mSelStart
|
ODManager::Instance()->DemandTrackUpdate((WaveTrack*)pTrack,sel0); //sel0 is sometimes less than mSelStart
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::UpdateSelectionDisplay()
|
||||||
|
{
|
||||||
// Full refresh since the label area may need to indicate
|
// Full refresh since the label area may need to indicate
|
||||||
// newly selected tracks.
|
// newly selected tracks.
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
@ -2267,6 +2569,210 @@ void TrackPanel::ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
|||||||
DisplaySelection();
|
DisplaySelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline double findMaxRatio(double center, double rate)
|
||||||
|
{
|
||||||
|
const double minFrequency = 1.0;
|
||||||
|
const double maxFrequency = (rate / 2.0);
|
||||||
|
const double frequency =
|
||||||
|
std::min(maxFrequency,
|
||||||
|
std::max(minFrequency, center));
|
||||||
|
return
|
||||||
|
std::min(frequency / minFrequency, maxFrequency / frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::StartSnappingFreqSelection (WaveTrack *pTrack)
|
||||||
|
{
|
||||||
|
static const sampleCount minLength = 8;
|
||||||
|
|
||||||
|
mFreqSelMode = FREQ_SEL_SNAPPING_CENTER;
|
||||||
|
const double rate = pTrack->GetRate();
|
||||||
|
|
||||||
|
// Grab samples, just for this track, at these times
|
||||||
|
std::vector<float> frequencySnappingData;
|
||||||
|
const sampleCount start =
|
||||||
|
pTrack->TimeToLongSamples(mViewInfo->selectedRegion.t0());
|
||||||
|
const sampleCount end =
|
||||||
|
pTrack->TimeToLongSamples(mViewInfo->selectedRegion.t1());
|
||||||
|
const sampleCount length =
|
||||||
|
std::min(sampleCount(frequencySnappingData.max_size()),
|
||||||
|
std::min(sampleCount(10485760), // as in FreqWindow.cpp
|
||||||
|
end - start));
|
||||||
|
const sampleCount effectiveLength = std::max(minLength, length);
|
||||||
|
frequencySnappingData.resize(effectiveLength, 0.0f);
|
||||||
|
pTrack->Get(
|
||||||
|
reinterpret_cast<samplePtr>(&frequencySnappingData[0]),
|
||||||
|
floatSample, start, length);
|
||||||
|
|
||||||
|
// Use same settings as are now used for spectrogram display,
|
||||||
|
// except, shrink the window as needed so we get some answers
|
||||||
|
int windowSize = mTrackArtist->GetSpectrumWindowSize();
|
||||||
|
while(windowSize > effectiveLength)
|
||||||
|
windowSize >>= 1;
|
||||||
|
int windowType;
|
||||||
|
gPrefs->Read(wxT("/Spectrum/WindowType"), &windowType, 3);
|
||||||
|
mFrequencySnapper->Calculate(
|
||||||
|
SpectrumAnalyst::Spectrum, windowType, windowSize, rate,
|
||||||
|
&frequencySnappingData[0], length);
|
||||||
|
|
||||||
|
// We can now throw away the sample data but we keep the spectrum.
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::MoveSnappingFreqSelection (int mouseYCoordinate,
|
||||||
|
int trackTopEdge,
|
||||||
|
int trackHeight, Track *pTrack)
|
||||||
|
{
|
||||||
|
if (pTrack &&
|
||||||
|
pTrack->GetSelected() &&
|
||||||
|
pTrack->GetKind() == Track::Wave)
|
||||||
|
{
|
||||||
|
WaveTrack* wt = static_cast<WaveTrack*>(pTrack);
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
if (logF || display== WaveTrack::SpectrumDisplay)
|
||||||
|
{
|
||||||
|
const double rate = wt->GetRate();
|
||||||
|
|
||||||
|
if (mFreqSelMode != FREQ_SEL_SNAPPING_CENTER)
|
||||||
|
StartSnappingFreqSelection(wt);
|
||||||
|
|
||||||
|
const double frequency =
|
||||||
|
PositionToFrequency(false, mouseYCoordinate,
|
||||||
|
trackTopEdge, trackHeight, rate, logF);
|
||||||
|
const double snappedFrequency =
|
||||||
|
mFrequencySnapper->FindPeak(frequency, NULL);
|
||||||
|
const double maxRatio = findMaxRatio(snappedFrequency, rate);
|
||||||
|
double ratio = 2.0; // An arbitrary octave on each side, at most
|
||||||
|
if (mViewInfo->selectedRegion.f1() >= mViewInfo->selectedRegion.f0() &&
|
||||||
|
mViewInfo->selectedRegion.f0() >= 0)
|
||||||
|
// Preserve already chosen ratio instead
|
||||||
|
ratio = sqrt(mViewInfo->selectedRegion.f1() /
|
||||||
|
mViewInfo->selectedRegion.f0());
|
||||||
|
ratio = std::min(ratio, maxRatio);
|
||||||
|
|
||||||
|
// Set up what the alt-click code expects to find
|
||||||
|
mFreqSelCenter = snappedFrequency;
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(
|
||||||
|
snappedFrequency / ratio, snappedFrequency * ratio);
|
||||||
|
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
// SelectNone();
|
||||||
|
// mTracks->Select(pTrack);
|
||||||
|
SetFocusedTrack(pTrack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::StartFreqSelection (int mouseYCoordinate, int trackTopEdge,
|
||||||
|
int trackHeight, Track *pTrack)
|
||||||
|
{
|
||||||
|
mFreqSelTrack = 0;
|
||||||
|
mFreqSelMode = FREQ_SEL_INVALID;
|
||||||
|
mFreqSelStart = mFreqSelCenter = SelectedRegion::UndefinedFrequency;
|
||||||
|
|
||||||
|
if (pTrack &&
|
||||||
|
pTrack->GetKind() == Track::Wave)
|
||||||
|
{
|
||||||
|
const WaveTrack* wt = static_cast<WaveTrack*>(pTrack);
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
if (logF || display == WaveTrack::SpectrumDisplay)
|
||||||
|
{
|
||||||
|
mFreqSelTrack = wt;
|
||||||
|
mFreqSelMode = FREQ_SEL_FREE;
|
||||||
|
const double rate = wt->GetRate();
|
||||||
|
mFreqSelStart =
|
||||||
|
PositionToFrequency(false, mouseYCoordinate,
|
||||||
|
trackTopEdge, trackHeight, rate, logF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(mFreqSelStart, mFreqSelStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrackPanel::ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge,
|
||||||
|
int trackHeight, bool dragWidth)
|
||||||
|
{
|
||||||
|
// When dragWidth is true, and not dragging the center,
|
||||||
|
// adjust both top and bottom about geometric mean.
|
||||||
|
|
||||||
|
if (mFreqSelMode == FREQ_SEL_INVALID ||
|
||||||
|
mFreqSelMode == FREQ_SEL_SNAPPING_CENTER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Extension happens only when dragging in the same track in which we
|
||||||
|
// started, and that is of a spectrogram display type.
|
||||||
|
|
||||||
|
const WaveTrack* wt = mFreqSelTrack;
|
||||||
|
const int display = wt->GetDisplay();
|
||||||
|
const bool logF = display == WaveTrack::SpectrumLogDisplay;
|
||||||
|
const double rate = wt->GetRate();
|
||||||
|
const double frequency =
|
||||||
|
PositionToFrequency(true, mouseYCoordinate,
|
||||||
|
trackTopEdge, trackHeight, rate, logF);
|
||||||
|
if (mFreqSelMode == FREQ_SEL_DRAG_CENTER) {
|
||||||
|
if (frequency == rate || frequency < 1.0)
|
||||||
|
// snapped to top or bottom
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(
|
||||||
|
SelectedRegion::UndefinedFrequency,
|
||||||
|
SelectedRegion::UndefinedFrequency);
|
||||||
|
else {
|
||||||
|
// mFreqSelStart holds the ratio of top to center
|
||||||
|
const double maxRatio = findMaxRatio(frequency, rate);
|
||||||
|
const double ratio = std::min(maxRatio, mFreqSelStart);
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(
|
||||||
|
frequency / ratio, frequency * ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dragWidth && mFreqSelCenter >= 0) {
|
||||||
|
if (frequency == rate || frequency < 1.0)
|
||||||
|
// snapped to top or bottom
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(
|
||||||
|
SelectedRegion::UndefinedFrequency,
|
||||||
|
SelectedRegion::UndefinedFrequency);
|
||||||
|
else {
|
||||||
|
const double maxRatio = findMaxRatio(mFreqSelCenter, rate);
|
||||||
|
double ratio = frequency / mFreqSelCenter;
|
||||||
|
if (ratio < 1.0)
|
||||||
|
ratio = 1.0 / ratio;
|
||||||
|
ratio = std::min(maxRatio, ratio);
|
||||||
|
mViewInfo->selectedRegion.setFrequencies(
|
||||||
|
mFreqSelCenter / ratio, mFreqSelCenter * ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const bool bottomDefined =
|
||||||
|
!(mFreqSelMode == FREQ_SEL_TOP_FREE && mFreqSelStart < 0);
|
||||||
|
const bool topDefined =
|
||||||
|
!(mFreqSelMode == FREQ_SEL_BOTTOM_FREE && mFreqSelStart < 0);
|
||||||
|
if (!bottomDefined || (topDefined && mFreqSelStart < frequency)) {
|
||||||
|
// Adjust top
|
||||||
|
if (frequency == rate)
|
||||||
|
// snapped high; upper frequency is undefined
|
||||||
|
mViewInfo->selectedRegion.setF1(SelectedRegion::UndefinedFrequency);
|
||||||
|
else
|
||||||
|
mViewInfo->selectedRegion.setF1(std::max(1.0, frequency));
|
||||||
|
|
||||||
|
mViewInfo->selectedRegion.setF0(mFreqSelStart);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Adjust bottom
|
||||||
|
if (frequency < 1.0)
|
||||||
|
// snapped low; lower frequency is undefined
|
||||||
|
mViewInfo->selectedRegion.setF0(SelectedRegion::UndefinedFrequency);
|
||||||
|
else
|
||||||
|
mViewInfo->selectedRegion.setF0(std::min(rate / 2.0, frequency));
|
||||||
|
|
||||||
|
mViewInfo->selectedRegion.setF1(mFreqSelStart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
|
void TrackPanel::Stretch(int mouseXCoordinate, int trackLeftEdge,
|
||||||
Track *pTrack)
|
Track *pTrack)
|
||||||
@ -2404,6 +2910,9 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
|
|||||||
// Can someone make this value of '5' configurable in
|
// Can someone make this value of '5' configurable in
|
||||||
// preferences?
|
// preferences?
|
||||||
const int minimumSizedSelection = 5; //measured in pixels
|
const int minimumSizedSelection = 5; //measured in pixels
|
||||||
|
|
||||||
|
// Might be dragging frequency bounds only, test
|
||||||
|
if (mSelStart >= 0) {
|
||||||
wxInt64 SelStart=TimeToPosition( mSelStart, r.x); //cvt time to pixels.
|
wxInt64 SelStart=TimeToPosition( mSelStart, r.x); //cvt time to pixels.
|
||||||
// Abandon this drag if selecting < 5 pixels.
|
// Abandon this drag if selecting < 5 pixels.
|
||||||
if (wxLongLong(SelStart-x).Abs() < minimumSizedSelection
|
if (wxLongLong(SelStart-x).Abs() < minimumSizedSelection
|
||||||
@ -2412,26 +2921,28 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
|
|||||||
#endif // once stretching starts, it's ok to move even 1 pixel
|
#endif // once stretching starts, it's ok to move even 1 pixel
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle which tracks are selected
|
// Handle which tracks are selected
|
||||||
|
Track *sTrack = pTrack;
|
||||||
if (Track *eTrack = FindTrack(x, y, false, false, NULL)) {
|
if (Track *eTrack = FindTrack(x, y, false, false, NULL)) {
|
||||||
// Swap the track pointers if needed
|
// Swap the track pointers if needed
|
||||||
if (eTrack->GetIndex() < pTrack->GetIndex()) {
|
if (eTrack->GetIndex() < sTrack->GetIndex()) {
|
||||||
Track *t = eTrack;
|
Track *t = eTrack;
|
||||||
eTrack = pTrack;
|
eTrack = sTrack;
|
||||||
pTrack = t;
|
sTrack = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
TrackListIterator iter(mTracks);
|
TrackListIterator iter(mTracks);
|
||||||
pTrack = iter.StartWith(pTrack);
|
sTrack = iter.StartWith(sTrack);
|
||||||
do {
|
do {
|
||||||
mTracks->Select(pTrack);
|
mTracks->Select(sTrack);
|
||||||
if (pTrack == eTrack) {
|
if (sTrack == eTrack) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pTrack = iter.Next();
|
sTrack = iter.Next();
|
||||||
} while (pTrack);
|
} while (sTrack);
|
||||||
}
|
}
|
||||||
#ifdef USE_MIDI
|
#ifdef USE_MIDI
|
||||||
if (mStretching) {
|
if (mStretching) {
|
||||||
@ -2443,7 +2954,15 @@ void TrackPanel::SelectionHandleDrag(wxMouseEvent & event, Track *clickedTrack)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
if (mFreqSelTrack == pTrack)
|
||||||
|
ExtendFreqSelection(y, r.y, r.height,
|
||||||
|
(event.AltDown() && !event.ShiftDown()));
|
||||||
|
#endif
|
||||||
|
|
||||||
ExtendSelection(x, r.x, clickedTrack);
|
ExtendSelection(x, r.x, clickedTrack);
|
||||||
|
UpdateSelectionDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a position (mouse X coordinate) to
|
/// Converts a position (mouse X coordinate) to
|
||||||
@ -2466,6 +2985,84 @@ wxInt64 TrackPanel::TimeToPosition(double projectTime,
|
|||||||
trackLeftEdge);
|
trackLeftEdge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
/// Converts a position (mouse Y coordinate) to
|
||||||
|
/// frequency, in Hz.
|
||||||
|
double TrackPanel::PositionToFrequency(bool maySnap,
|
||||||
|
wxInt64 mouseYCoordinate,
|
||||||
|
wxInt64 trackTopEdge,
|
||||||
|
int trackHeight,
|
||||||
|
double rate,
|
||||||
|
bool logF) const
|
||||||
|
{
|
||||||
|
// Handle snapping
|
||||||
|
if (maySnap &&
|
||||||
|
mouseYCoordinate - trackTopEdge < FREQ_SNAP_DISTANCE)
|
||||||
|
return rate;
|
||||||
|
if (maySnap &&
|
||||||
|
trackTopEdge + trackHeight - mouseYCoordinate < FREQ_SNAP_DISTANCE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const double p = double(mouseYCoordinate - trackTopEdge) / trackHeight;
|
||||||
|
const int freq = lrint(rate/2.);
|
||||||
|
|
||||||
|
if (logF)
|
||||||
|
{
|
||||||
|
const double maxFreq =
|
||||||
|
std::min(freq, mTrackArtist->GetSpectrumLogMaxFreq(freq));
|
||||||
|
const double minFreq =
|
||||||
|
std::max(1, mTrackArtist->GetSpectrumLogMinFreq(1));
|
||||||
|
return exp(p * log(minFreq) + (1.0 - p) * log(maxFreq));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double maxFreq =
|
||||||
|
std::min(freq, mTrackArtist->GetSpectrumMaxFreq(freq));
|
||||||
|
const double minFreq =
|
||||||
|
std::max(0, mTrackArtist->GetSpectrumMinFreq(0));
|
||||||
|
return p * minFreq + (1.0 - p) * maxFreq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a frequency to screen y position.
|
||||||
|
wxInt64 TrackPanel::FrequencyToPosition(double frequency,
|
||||||
|
wxInt64 trackTopEdge,
|
||||||
|
int trackHeight,
|
||||||
|
double rate,
|
||||||
|
bool logF) const
|
||||||
|
{
|
||||||
|
const int freq = lrint(rate/2.);
|
||||||
|
double p = 0;
|
||||||
|
|
||||||
|
if (logF)
|
||||||
|
{
|
||||||
|
const double maxFreq =
|
||||||
|
std::min(freq, mTrackArtist->GetSpectrumLogMaxFreq(freq));
|
||||||
|
const double minFreq =
|
||||||
|
std::max(1, mTrackArtist->GetSpectrumLogMinFreq(1));
|
||||||
|
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 double maxFreq =
|
||||||
|
std::min(freq, mTrackArtist->GetSpectrumMaxFreq(freq));
|
||||||
|
const double minFreq =
|
||||||
|
std::max(0, mTrackArtist->GetSpectrumMinFreq(0));
|
||||||
|
if (maxFreq > minFreq)
|
||||||
|
p = (frequency - minFreq) / (maxFreq - minFreq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return trackTopEdge + wxInt64((1.0 - p) * trackHeight);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// HandleEnvelope gets called when the user is changing the
|
/// HandleEnvelope gets called when the user is changing the
|
||||||
/// amplitude envelope on a track.
|
/// amplitude envelope on a track.
|
||||||
void TrackPanel::HandleEnvelope(wxMouseEvent & event)
|
void TrackPanel::HandleEnvelope(wxMouseEvent & event)
|
||||||
@ -5025,8 +5622,21 @@ void TrackPanel::OnCaptureKey(wxCommandEvent & event)
|
|||||||
/// Allow typing into LabelTracks.
|
/// Allow typing into LabelTracks.
|
||||||
void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
// Only deal with LabelTracks
|
|
||||||
Track *t = GetFocusedTrack();
|
Track *t = GetFocusedTrack();
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Test very special conditions for freeing up the frequency selection
|
||||||
|
// for renewed center snapping
|
||||||
|
if (t &&
|
||||||
|
t->GetKind() == Track::Wave &&
|
||||||
|
event.GetKeyCode() == WXK_CONTROL &&
|
||||||
|
event.AltDown()) {
|
||||||
|
StartSnappingFreqSelection(static_cast<WaveTrack*>(t));
|
||||||
|
// And don't skip event, yet
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Only deal with LabelTracks
|
||||||
if (!t || t->GetKind() != Track::Label) {
|
if (!t || t->GetKind() != Track::Label) {
|
||||||
event.Skip();
|
event.Skip();
|
||||||
return;
|
return;
|
||||||
|
@ -11,12 +11,15 @@
|
|||||||
#ifndef __AUDACITY_TRACK_PANEL__
|
#ifndef __AUDACITY_TRACK_PANEL__
|
||||||
#define __AUDACITY_TRACK_PANEL__
|
#define __AUDACITY_TRACK_PANEL__
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <wx/dcmemory.h>
|
#include <wx/dcmemory.h>
|
||||||
#include <wx/dynarray.h>
|
#include <wx/dynarray.h>
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#include <wx/window.h>
|
#include <wx/window.h>
|
||||||
|
|
||||||
|
#include "Experimental.h"
|
||||||
#include "Sequence.h" //Stm: included for the sampleCount declaration
|
#include "Sequence.h" //Stm: included for the sampleCount declaration
|
||||||
#include "WaveClip.h"
|
#include "WaveClip.h"
|
||||||
#include "WaveTrack.h"
|
#include "WaveTrack.h"
|
||||||
@ -27,6 +30,7 @@ class wxMenu;
|
|||||||
class wxRect;
|
class wxRect;
|
||||||
|
|
||||||
class LabelTrack;
|
class LabelTrack;
|
||||||
|
class SpectrumAnalyst;
|
||||||
class TrackPanel;
|
class TrackPanel;
|
||||||
class TrackArtist;
|
class TrackArtist;
|
||||||
class Ruler;
|
class Ruler;
|
||||||
@ -54,31 +58,8 @@ class AUDACITY_DLL_API TrackClip
|
|||||||
|
|
||||||
WX_DECLARE_OBJARRAY(TrackClip, TrackClipArray);
|
WX_DECLARE_OBJARRAY(TrackClip, TrackClipArray);
|
||||||
|
|
||||||
class AUDACITY_DLL_API TrackPanelListener {
|
// Declared elsewhere, to reduce compilation dependencies
|
||||||
|
class TrackPanelListener;
|
||||||
public:
|
|
||||||
TrackPanelListener(){};
|
|
||||||
virtual ~TrackPanelListener(){};
|
|
||||||
|
|
||||||
virtual void TP_DisplaySelection() = 0;
|
|
||||||
virtual void TP_DisplayStatusMessage(wxString msg) = 0;
|
|
||||||
|
|
||||||
virtual int TP_GetCurrentTool() = 0;
|
|
||||||
virtual ToolsToolBar * TP_GetToolsToolBar() = 0;
|
|
||||||
virtual ControlToolBar * TP_GetControlToolBar() = 0;
|
|
||||||
|
|
||||||
virtual void TP_OnPlayKey() = 0;
|
|
||||||
virtual void TP_PushState(wxString shortDesc, wxString longDesc,
|
|
||||||
int flags = PUSH_AUTOSAVE | PUSH_CALC_SPACE) = 0;
|
|
||||||
virtual void TP_ModifyState(bool bWantsAutoSave) = 0; // if true, writes auto-save file. Should set only if you really want the state change restored after
|
|
||||||
// a crash, as it can take many seconds for large (eg. 10 track-hours) projects
|
|
||||||
virtual void TP_RedrawScrollbars() = 0;
|
|
||||||
virtual void TP_ScrollLeft() = 0;
|
|
||||||
virtual void TP_ScrollRight() = 0;
|
|
||||||
virtual void TP_ScrollWindow(double scrollto) = 0;
|
|
||||||
virtual void TP_ScrollUpDown(int delta) = 0;
|
|
||||||
virtual void TP_HandleResize() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// TrackInfo sliders: we keep a pool of sliders, and attach them to tracks as
|
// TrackInfo sliders: we keep a pool of sliders, and attach them to tracks as
|
||||||
@ -334,6 +315,19 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
|
|||||||
virtual void StartSelection (int mouseXCoordinate, int trackLeftEdge);
|
virtual void StartSelection (int mouseXCoordinate, int trackLeftEdge);
|
||||||
virtual void ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
virtual void ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
|
||||||
Track *pTrack);
|
Track *pTrack);
|
||||||
|
virtual void UpdateSelectionDisplay();
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
virtual void StartSnappingFreqSelection (WaveTrack *pTrack);
|
||||||
|
virtual void MoveSnappingFreqSelection (int mouseYCoordinate,
|
||||||
|
int trackTopEdge,
|
||||||
|
int trackHeight, Track *pTrack);
|
||||||
|
virtual void StartFreqSelection (int mouseYCoordinate, int trackTopEdge,
|
||||||
|
int trackHeight, Track *pTrack);
|
||||||
|
virtual void ExtendFreqSelection(int mouseYCoordinate, int trackTopEdge,
|
||||||
|
int trackHeight, bool dragWidth);
|
||||||
|
#endif
|
||||||
|
|
||||||
virtual void SelectTracksByLabel( LabelTrack *t );
|
virtual void SelectTracksByLabel( LabelTrack *t );
|
||||||
virtual void SelectTrackLength(Track *t);
|
virtual void SelectTrackLength(Track *t);
|
||||||
|
|
||||||
@ -563,6 +557,21 @@ protected:
|
|||||||
|
|
||||||
double mSelStart;
|
double mSelStart;
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
enum {
|
||||||
|
FREQ_SEL_INVALID,
|
||||||
|
FREQ_SEL_SNAPPING_CENTER,
|
||||||
|
FREQ_SEL_TOP_FREE,
|
||||||
|
FREQ_SEL_BOTTOM_FREE,
|
||||||
|
FREQ_SEL_DRAG_CENTER,
|
||||||
|
FREQ_SEL_FREE
|
||||||
|
} mFreqSelMode;
|
||||||
|
double mFreqSelStart;
|
||||||
|
double mFreqSelCenter; // Used when dragging the width about fixed center
|
||||||
|
const WaveTrack *mFreqSelTrack;
|
||||||
|
std::auto_ptr<SpectrumAnalyst> mFrequencySnapper;
|
||||||
|
#endif
|
||||||
|
|
||||||
Track *mCapturedTrack;
|
Track *mCapturedTrack;
|
||||||
Envelope *mCapturedEnvelope;
|
Envelope *mCapturedEnvelope;
|
||||||
WaveClip *mCapturedClip;
|
WaveClip *mCapturedClip;
|
||||||
@ -628,6 +637,20 @@ protected:
|
|||||||
wxInt64 TimeToPosition(double time,
|
wxInt64 TimeToPosition(double time,
|
||||||
wxInt64 trackLeftEdge) const;
|
wxInt64 trackLeftEdge) const;
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
double PositionToFrequency(bool maySnap,
|
||||||
|
wxInt64 mouseYCoordinate,
|
||||||
|
wxInt64 trackTopEdge,
|
||||||
|
int trackHeight,
|
||||||
|
double rate,
|
||||||
|
bool logF) const;
|
||||||
|
wxInt64 FrequencyToPosition(double frequency,
|
||||||
|
wxInt64 trackTopEdge,
|
||||||
|
int trackHeight,
|
||||||
|
double rate,
|
||||||
|
bool logF) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
int mInitialTrackHeight;
|
int mInitialTrackHeight;
|
||||||
int mInitialUpperTrackHeight;
|
int mInitialUpperTrackHeight;
|
||||||
bool mAutoScrolling;
|
bool mAutoScrolling;
|
||||||
@ -734,6 +757,8 @@ protected:
|
|||||||
|
|
||||||
//This constant determines the size of the horizontal region (in pixels) around
|
//This constant determines the size of the horizontal region (in pixels) around
|
||||||
//the right and left selection bounds that can be used for horizontal selection adjusting
|
//the right and left selection bounds that can be used for horizontal selection adjusting
|
||||||
|
//(or, vertical distance around top and bottom bounds in spectrograms,
|
||||||
|
// for vertical selection adjusting)
|
||||||
#define SELECTION_RESIZE_REGION 3
|
#define SELECTION_RESIZE_REGION 3
|
||||||
|
|
||||||
#define SMOOTHING_KERNEL_RADIUS 3
|
#define SMOOTHING_KERNEL_RADIUS 3
|
||||||
|
@ -401,7 +401,7 @@ class AUDACITY_DLL_API WaveTrack: public Track {
|
|||||||
mLastDisplay=mDisplay; // remember last display mode for wave and wavedb so they can remap
|
mLastDisplay=mDisplay; // remember last display mode for wave and wavedb so they can remap
|
||||||
mDisplay = display;
|
mDisplay = display;
|
||||||
}
|
}
|
||||||
int GetDisplay() {return mDisplay;}
|
int GetDisplay() const {return mDisplay;}
|
||||||
int GetLastDisplay() {return mLastDisplay;}
|
int GetLastDisplay() {return mLastDisplay;}
|
||||||
|
|
||||||
void GetDisplayBounds(float *min, float *max);
|
void GetDisplayBounds(float *min, float *max);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*//*******************************************************************/
|
*//*******************************************************************/
|
||||||
|
|
||||||
#include "GetProjectInfoCommand.h"
|
#include "GetProjectInfoCommand.h"
|
||||||
|
#include "../TrackPanel.h"
|
||||||
#include "../Project.h"
|
#include "../Project.h"
|
||||||
#include "../Track.h"
|
#include "../Track.h"
|
||||||
#include "../WaveTrack.h"
|
#include "../WaveTrack.h"
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
*//*******************************************************************/
|
*//*******************************************************************/
|
||||||
|
|
||||||
#include "GetTrackInfoCommand.h"
|
#include "GetTrackInfoCommand.h"
|
||||||
|
#include "../TrackPanel.h"
|
||||||
#include "../Project.h"
|
#include "../Project.h"
|
||||||
#include "../Track.h"
|
#include "../Track.h"
|
||||||
#include "../WaveTrack.h"
|
#include "../WaveTrack.h"
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <wx/valtext.h>
|
#include <wx/valtext.h>
|
||||||
|
|
||||||
#include "../Audacity.h"
|
#include "../Audacity.h"
|
||||||
|
#include "../LabelTrack.h"
|
||||||
#include "../Envelope.h"
|
#include "../Envelope.h"
|
||||||
#include "../LabelTrack.h"
|
#include "../LabelTrack.h"
|
||||||
#include "../Prefs.h"
|
#include "../Prefs.h"
|
||||||
|
@ -104,6 +104,10 @@ bool Effect::DoEffect(wxWindow *parent, int flags,
|
|||||||
mTracks = list;
|
mTracks = list;
|
||||||
mT0 = t0;
|
mT0 = t0;
|
||||||
mT1 = t1;
|
mT1 = t1;
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
mF0 = selectedRegion->f0();
|
||||||
|
mF1 = selectedRegion->f1();
|
||||||
|
#endif
|
||||||
CountWaveTracks();
|
CountWaveTracks();
|
||||||
|
|
||||||
// Note: Init may read parameters from preferences
|
// Note: Init may read parameters from preferences
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
class wxDialog;
|
class wxDialog;
|
||||||
class wxWindow;
|
class wxWindow;
|
||||||
|
|
||||||
|
#include "../Experimental.h"
|
||||||
#include "../WaveTrack.h"
|
#include "../WaveTrack.h"
|
||||||
#include "../Shuttle.h"
|
#include "../Shuttle.h"
|
||||||
#include "../ShuttleGui.h"
|
#include "../ShuttleGui.h"
|
||||||
@ -215,6 +216,10 @@ class AUDACITY_DLL_API Effect {
|
|||||||
TrackList *mOutputTracks; // used only if CopyInputTracks() is called.
|
TrackList *mOutputTracks; // used only if CopyInputTracks() is called.
|
||||||
double mT0;
|
double mT0;
|
||||||
double mT1;
|
double mT1;
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
double mF0;
|
||||||
|
double mF1;
|
||||||
|
#endif
|
||||||
TimeWarper *mWarper;
|
TimeWarper *mWarper;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -778,6 +778,24 @@ bool EffectNyquist::ProcessOne()
|
|||||||
|
|
||||||
wxString cmd;
|
wxString cmd;
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
{
|
||||||
|
static const wxString varName(wxT("*F0*"));
|
||||||
|
if (mF0 < 0)
|
||||||
|
cmd += wxString::Format(wxT("(setf %s nil)\n"), varName);
|
||||||
|
else
|
||||||
|
cmd += wxString::Format(wxT("(setf %s (float %g))\n"), varName, mF0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
static const wxString varName(wxT("*F1*"));
|
||||||
|
if (mF1 < 0)
|
||||||
|
cmd += wxString::Format(wxT("(setf %s nil)\n"), varName);
|
||||||
|
else
|
||||||
|
cmd += wxString::Format(wxT("(setf %s (float %g))\n"), varName, mF1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mDebug) {
|
if (mDebug) {
|
||||||
cmd += wxT("(setf *tracenable* T)\n");
|
cmd += wxT("(setf *tracenable* T)\n");
|
||||||
if (mExternal) {
|
if (mExternal) {
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <wx/combobox.h>
|
#include <wx/combobox.h>
|
||||||
#include <wx/log.h>
|
#include <wx/log.h>
|
||||||
#include <wx/process.h>
|
#include <wx/process.h>
|
||||||
|
#include <wx/sizer.h>
|
||||||
#include <wx/textctrl.h>
|
#include <wx/textctrl.h>
|
||||||
#include <FileDialog.h>
|
#include <FileDialog.h>
|
||||||
#include "Export.h"
|
#include "Export.h"
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
*//********************************************************************/
|
*//********************************************************************/
|
||||||
|
|
||||||
#include "../Audacity.h"
|
#include "../Audacity.h"
|
||||||
|
#include "../Experimental.h"
|
||||||
|
|
||||||
#include <wx/defs.h>
|
#include <wx/defs.h>
|
||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
@ -105,6 +106,14 @@ void MousePrefs::CreateList()
|
|||||||
AddItem(_("Left-Double-Click"), _("Select"), _("Select Clip or Entire Track"));
|
AddItem(_("Left-Double-Click"), _("Select"), _("Select Clip or Entire Track"));
|
||||||
AddItem(_("Ctrl-Left-Click"), _("Select"), _("Set Selection Point and Play"));
|
AddItem(_("Ctrl-Left-Click"), _("Select"), _("Set Selection Point and Play"));
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Spectral selection
|
||||||
|
AddItem(_("Alt-Shift-Left-Click"), _("Select"), _("Adjust high or low frequency"));
|
||||||
|
AddItem(_("Alt-Left-Drag"), _("Select"), _("Adjust bandwidth"));
|
||||||
|
AddItem(_("Alt-Ctrl"), _("Select"), _("Unpin center frequency"));
|
||||||
|
AddItem(_("Alt-Move"), _("Select"), _("Snap center frequency to peaks"));
|
||||||
|
#endif
|
||||||
|
|
||||||
AddItem(_("Left-Click"), _("Zoom"), _("Zoom in on Point"));
|
AddItem(_("Left-Click"), _("Zoom"), _("Zoom in on Point"));
|
||||||
AddItem(_("Left-Drag"), _("Zoom"), _("Zoom in on a Range"), _("same as right-drag"));
|
AddItem(_("Left-Drag"), _("Zoom"), _("Zoom in on a Range"), _("same as right-drag"));
|
||||||
AddItem(_("Right-Click"), _("Zoom"), _("Zoom out one step"));
|
AddItem(_("Right-Click"), _("Zoom"), _("Zoom out one step"));
|
||||||
@ -131,6 +140,14 @@ void MousePrefs::CreateList()
|
|||||||
AddItem(_("Right-Click"), _("Multi"), _("Zoom out one step"), _("same as zoom tool"));
|
AddItem(_("Right-Click"), _("Multi"), _("Zoom out one step"), _("same as zoom tool"));
|
||||||
AddItem(_("Right-Drag"), _("Multi"), _("Zoom in on a Range"), _("same as zoom tool"));
|
AddItem(_("Right-Drag"), _("Multi"), _("Zoom in on a Range"), _("same as zoom tool"));
|
||||||
|
|
||||||
|
#ifdef EXPERIMENTAL_SPECTRAL_EDITING
|
||||||
|
// Spectral selection
|
||||||
|
AddItem(_("Alt-Shift-Left-Click"), _("Multi"), _("Adjust high or low frequency"), _("same as select tool"));
|
||||||
|
AddItem(_("Alt-Left-Drag"), _("Multi"), _("Adjust bandwidth"), _("same as select tool"));
|
||||||
|
AddItem(_("Alt-Ctrl"), _("Multi"), _("Unpin center frequency"), _("same as select tool"));
|
||||||
|
AddItem(_("Alt-Move"), _("Multi"), _("Snap center frequency to peaks"), _("same as select tool"));
|
||||||
|
#endif
|
||||||
|
|
||||||
AddItem(_("Wheel-Rotate"), _("Any"), _("Scroll up or down"));
|
AddItem(_("Wheel-Rotate"), _("Any"), _("Scroll up or down"));
|
||||||
AddItem(_("Shift-Wheel-Rotate"),_("Any"), _("Scroll left or right"));
|
AddItem(_("Shift-Wheel-Rotate"),_("Any"), _("Scroll left or right"));
|
||||||
AddItem(_("Ctrl-Wheel-Rotate"), _("Any"), _("Zoom in or out on Mouse Pointer"));
|
AddItem(_("Ctrl-Wheel-Rotate"), _("Any"), _("Zoom in or out on Mouse Pointer"));
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "DeviceToolBar.h"
|
#include "DeviceToolBar.h"
|
||||||
#include "ToolDock.h"
|
#include "ToolDock.h"
|
||||||
|
#include "../TrackPanel.h"
|
||||||
|
|
||||||
#include "../AColor.h"
|
#include "../AColor.h"
|
||||||
#include "../AllThemeResources.h"
|
#include "../AllThemeResources.h"
|
||||||
|
@ -43,6 +43,7 @@ with changes in the SelectionBar.
|
|||||||
#endif
|
#endif
|
||||||
#include <wx/statline.h>
|
#include <wx/statline.h>
|
||||||
|
|
||||||
|
#include "SelectionBarListener.h"
|
||||||
#include "SelectionBar.h"
|
#include "SelectionBar.h"
|
||||||
|
|
||||||
#include "../AudacityApp.h"
|
#include "../AudacityApp.h"
|
||||||
|
@ -24,24 +24,9 @@ class wxDC;
|
|||||||
class wxRadioButton;
|
class wxRadioButton;
|
||||||
class wxSizeEvent;
|
class wxSizeEvent;
|
||||||
|
|
||||||
|
class SelectionBarListener;
|
||||||
class TimeTextCtrl;
|
class TimeTextCtrl;
|
||||||
|
|
||||||
class AUDACITY_DLL_API SelectionBarListener {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SelectionBarListener(){};
|
|
||||||
virtual ~SelectionBarListener(){};
|
|
||||||
|
|
||||||
virtual double AS_GetRate() = 0;
|
|
||||||
virtual void AS_SetRate(double rate) = 0;
|
|
||||||
virtual int AS_GetSnapTo() = 0;
|
|
||||||
virtual void AS_SetSnapTo(int snap) = 0;
|
|
||||||
virtual const wxString & AS_GetSelectionFormat() = 0;
|
|
||||||
virtual void AS_SetSelectionFormat(const wxString & format) = 0;
|
|
||||||
virtual void AS_ModifySelection(double &start, double &end, bool done) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SelectionBar:public ToolBar {
|
class SelectionBar:public ToolBar {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <wx/intl.h>
|
#include <wx/intl.h>
|
||||||
#endif // WX_PRECOMP
|
#endif // WX_PRECOMP
|
||||||
|
|
||||||
|
#include "../Envelope.h"
|
||||||
#include "TranscriptionToolBar.h"
|
#include "TranscriptionToolBar.h"
|
||||||
|
|
||||||
#include "ControlToolBar.h"
|
#include "ControlToolBar.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user