# HG changeset patch # Parent 88c04d1bb5eb8e0e98e4264e92e7d3d1fe4716b2 Adds a simple noise coring filter. diff -r 88c04d1bb5eb src/Makefile.in --- a/src/Makefile.in Fri Sep 16 22:24:41 2011 +0200 +++ b/src/Makefile.in Sun Sep 18 15:42:53 2011 +0200 @@ -166,6 +166,7 @@ effects/Invert.o \ effects/Leveller.o \ effects/Noise.o \ + effects/NoiseCoring.o \ effects/NoiseRemoval.o \ effects/Normalize.o \ effects/Phaser.o \ diff -r 88c04d1bb5eb src/effects/LoadEffects.cpp --- a/src/effects/LoadEffects.cpp Fri Sep 16 22:24:41 2011 +0200 +++ b/src/effects/LoadEffects.cpp Sun Sep 18 15:42:53 2011 +0200 @@ -29,6 +29,7 @@ #include "Invert.h" #include "Leveller.h" #include "Noise.h" +#include "NoiseCoring.h" #include "NoiseRemoval.h" #include "Normalize.h" #include "Phaser.h" @@ -253,6 +254,7 @@ em.RegisterEffect(new EffectFadeOut(), SIMPLE_EFFECT); em.RegisterEffect(new EffectInvert()); em.RegisterEffect(new EffectLeveller(), SIMPLE_EFFECT); + em.RegisterEffect(new EffectNoiseCoring(), SIMPLE_EFFECT); em.RegisterEffect(new EffectNoiseRemoval(), SIMPLE_EFFECT); em.RegisterEffect(new EffectNormalize(), SIMPLE_EFFECT); em.RegisterEffect(new EffectPhaser()); diff -r 88c04d1bb5eb src/effects/NoiseCoring.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/effects/NoiseCoring.cpp Sun Sep 18 15:42:53 2011 +0200 @@ -0,0 +1,662 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + NoiseCoring.cpp + + Jerome M. Berger + +*******************************************************************//** + +\file NoiseCoring.cpp +\brief Implements EffectNoiseCoring and NoiseCoringDialog. + +*//****************************************************************//** + + +\class EffectNoiseCoring +\brief An Effect. + + Performs noise removal through FFT coring. + + The filter is applied using overlap/add of Hanning windows. + +*//****************************************************************//** + +\class NoiseCoringDialog +\brief Dialog used with EffectNoiseCoring + +*//*******************************************************************/ +#include "NoiseCoring.h" + +#include "../Audacity.h" +#include "../FFT.h" +#include "../Prefs.h" +#include "../Project.h" + +#include +#include + +#include +#include + +#define WINDOW_SIZE_MIN 10 +#define WINDOW_SIZE_DEF 2000 +#define WINDOW_SIZE_MAX 4095 + +#define THRESHOLD_MIN -100 +#define THRESHOLD_DEF -50 +#define THRESHOLD_MAX 0 + +#define GAIN_MIN 0 +#define GAIN_DEF 20 +#define GAIN_MAX 50 + +#define SHAPE_MIN 0 +#define SHAPE_DEF 10 +#define SHAPE_MAX 40 + +void EffectNoiseCoring::ReadPrefs() +{ + + gPrefs->Read(wxT("/Effects/EffectNoiseCoring/FilterLength"), + &mM, 2*WINDOW_SIZE_DEF+1); + if ((mM < 2*WINDOW_SIZE_MIN+1) || (mM > 2*WINDOW_SIZE_MAX+1)) { // corrupted Prefs? + mM = 2*WINDOW_SIZE_DEF+1; //default + gPrefs->Write(wxT("/Effects/EffectNoiseCoring/FilterLength"), mM); + } + gPrefs->Read(wxT("/Effects/EffectNoiseCoring/Threshold"), + &mThreshold, THRESHOLD_DEF); + if ((mThreshold < THRESHOLD_MIN) || (mThreshold > THRESHOLD_MAX)) { // corrupted Prefs? + mThreshold = THRESHOLD_DEF; + gPrefs->Write(wxT("/Effects/EffectNoiseCoring/Threshold"), mThreshold); + } + gPrefs->Read(wxT("/Effects/EffectNoiseCoring/Gain"), + &mGain, GAIN_DEF); + if ((mGain < GAIN_MIN) || (mGain > GAIN_MAX)) { // corrupted Prefs? + mGain = GAIN_DEF; + gPrefs->Write(wxT("/Effects/EffectNoiseCoring/Gain"), mGain); + } + gPrefs->Read(wxT("/Effects/EffectNoiseCoring/Shape"), + &mShape, SHAPE_DEF); + if ((mShape < SHAPE_MIN) || (mShape > SHAPE_MAX)) { // corrupted Prefs? + mShape = SHAPE_DEF; + gPrefs->Write(wxT("/Effects/EffectNoiseCoring/Shape"), mShape); + } +} + +EffectNoiseCoring::EffectNoiseCoring() +{ + hFFT = InitializeFFT(windowSize); + mFFTBuffer = new float[windowSize]; + mFilterFuncR = new float[windowSize]; + mFilterFuncI = new float[windowSize]; + ReadPrefs(); +} + + +EffectNoiseCoring::~EffectNoiseCoring() +{ + if(hFFT) + EndFFT(hFFT); + hFFT = NULL; + if(mFFTBuffer) + delete[] mFFTBuffer; + mFFTBuffer = NULL; + if(mFilterFuncR) + delete[] mFilterFuncR; + mFilterFuncR = NULL; + if(mFilterFuncI) + delete[] mFilterFuncI; + mFilterFuncI = NULL; +} + +bool EffectNoiseCoring::Init() +{ + return(true); +} + +bool EffectNoiseCoring::PromptUser() +{ + NoiseCoringDialog dlog(this, mParent); + dlog.mWindowSize = (mM-1)/2; + dlog.mThreshold = mThreshold; + dlog.mGain = mGain; + dlog.mShape = mShape; + + dlog.m_pButton_RemoveNoise->SetDefault(); + + dlog.TransferDataToWindow(); + dlog.CentreOnParent(); + dlog.ShowModal(); + + if (dlog.GetReturnCode() == 0) { + return false; + } + + mM = 2*dlog.mWindowSize+1; + mThreshold = dlog.mThreshold; + mGain = dlog.mGain; + mShape = dlog.mShape; + gPrefs->Write(wxT("/CsPresets/FilterLength"), mM); + gPrefs->Write(wxT("/CsPresets/Threshold"), mThreshold); + gPrefs->Write(wxT("/CsPresets/Gain"), mGain); + gPrefs->Write(wxT("/CsPresets/Shape"), mShape); + + return true; +} + +bool EffectNoiseCoring::TransferParameters( Shuttle & shuttle ) +{ + shuttle.TransferInt(wxT("FilterLength"),mM,2*WINDOW_SIZE_DEF+1); + shuttle.TransferDouble(wxT("Threshold"),mThreshold,THRESHOLD_DEF); + shuttle.TransferDouble(wxT("Gain"),mGain,GAIN_DEF); + shuttle.TransferDouble(wxT("Shape"),mShape,SHAPE_DEF); + return true; +} + +bool EffectNoiseCoring::Process() +{ + const double t = (windowSize*windowSize)/16.0 * exp10 (mThreshold/10.0); + const double g = exp10 (-mGain/20.0); + mStrength = -t / log (1 - g); + + this->CopyInputTracks(); // Set up mOutputTracks. + bool bGoodResult = true; + + SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks); + WaveTrack *track = (WaveTrack *) iter.First(); + int count = 0; + while (track) { + double trackStart = track->GetStartTime(); + double trackEnd = track->GetEndTime(); + double t0 = mT0 < trackStart? trackStart: mT0; + double t1 = mT1 > trackEnd? trackEnd: mT1; + + if (t1 > t0) { + sampleCount start = track->TimeToLongSamples(t0); + sampleCount end = track->TimeToLongSamples(t1); + sampleCount len = (sampleCount)(end - start); + + if (!ProcessOne(count, track, start, len)) + { + bGoodResult = false; + break; + } + } + + track = (WaveTrack *) iter.Next(); + count++; + } + + this->ReplaceProcessedTracks(bGoodResult); + return bGoodResult; +} + + +bool EffectNoiseCoring::ProcessOne(int count, WaveTrack * t, + sampleCount start, sampleCount len) +{ + // create a new WaveTrack to hold all of the output, including 'tails' each end + AudacityProject *p = GetActiveProject(); + WaveTrack *output = p->GetTrackFactory()->NewWaveTrack(floatSample, t->GetRate()); + + int L = windowSize - (mM - 1); //Process L samples at a go + sampleCount s = start; + sampleCount idealBlockLen = t->GetMaxBlockSize() * 4; + if (idealBlockLen % L != 0) + idealBlockLen += (L - (idealBlockLen % L)); + + float *buffer = new float[idealBlockLen]; + + float *window1 = new float[windowSize]; + float *window2 = new float[windowSize]; + float *thisWindow = window1; + float *lastWindow = window2; + + sampleCount originalLen = len; + + int i,j; + for(i=0; i len) + block = len; + + t->Get((samplePtr)buffer, floatSample, s, block); + + for(i=0; i block) //if last lump would exceed block + wcopy = block - i; //shorten it + for(j=0; jAppend((samplePtr)buffer, floatSample, block); + len -= block; + s += block; + + if (TrackProgress(count, (s-start)/(double)originalLen)) + { + bLoopSuccess = false; + break; + } + } + + if(bLoopSuccess) + { + // mM-1 samples of 'tail' left in lastWindow, get them now + if(wcopy < (mM-1)) { + // Still have some overlap left to process + // (note that lastWindow and thisWindow have been exchanged at this point + // so that 'thisWindow' is really the window prior to 'lastWindow') + for(j=0; jAppend((samplePtr)buffer, floatSample, mM-1); + output->Flush(); + + // now move the appropriate bit of the output back to the track + // (this could be enhanced in the future to use the tails) + double offsetT0 = t->LongSamplesToTime((sampleCount)offset); + double lenT = t->LongSamplesToTime(originalLen); + // 'start' is the sample offset in 't', the passed in track + // 'startT' is the equivalent time value + // 'output' starts at zero + double startT = t->LongSamplesToTime(start); + + //output has one waveclip for the total length, even though + //t might have whitespace seperating multiple clips + //we want to maintain the original clip structure, so + //only paste the intersections of the new clip. + + //Find the bits of clips that need replacing + std::vector > clipStartEndTimes; + std::vector > clipRealStartEndTimes; //the above may be truncated due to a clip being partially selected + for (WaveClipList::compatibility_iterator it=t->GetClipIterator(); it; it=it->GetNext()) + { + WaveClip *clip; + double clipStartT; + double clipEndT; + + clip = it->GetData(); + clipStartT = clip->GetStartTime(); + clipEndT = clip->GetEndTime(); + if( clipEndT <= startT ) + continue; // clip is not within selection + if( clipStartT >= startT + lenT ) + continue; // clip is not within selection + + //save the actual clip start/end so that we can rejoin them after we paste. + clipRealStartEndTimes.push_back(std::pair(clipStartT,clipEndT)); + + if( clipStartT < startT ) // does selection cover the whole clip? + clipStartT = startT; // don't copy all the new clip + if( clipEndT > startT + lenT ) // does selection cover the whole clip? + clipEndT = startT + lenT; // don't copy all the new clip + + //save them + clipStartEndTimes.push_back(std::pair(clipStartT,clipEndT)); + } + //now go thru and replace the old clips with new + for(unsigned int i=0;iClear(clipStartEndTimes[i].first,clipStartEndTimes[i].second); + output->Copy(clipStartEndTimes[i].first-startT+offsetT0,clipStartEndTimes[i].second-startT+offsetT0, &toClipOutput); + if(toClipOutput) + { + //put the processed audio in + t->Paste(clipStartEndTimes[i].first,toClipOutput); + //if the clip was only partially selected, the Paste will have created a split line. Join is needed to take care of this + //This is not true when the selection is fully contained within one clip (second half of conditional) + if( (clipRealStartEndTimes[i].first != clipStartEndTimes[i].first || + clipRealStartEndTimes[i].second != clipStartEndTimes[i].second) && + !(clipRealStartEndTimes[i].first <= startT && + clipRealStartEndTimes[i].second >= startT+lenT) ) + t->Join(clipRealStartEndTimes[i].first,clipRealStartEndTimes[i].second); + delete toClipOutput; + } + } + } + + delete[] buffer; + delete[] window1; + delete[] window2; + delete output; + + return bLoopSuccess; +} + +void EffectNoiseCoring::Filter(sampleCount len, + float *buffer) +{ + int i; + // Apply FFT + RealFFTf(buffer, hFFT); + //FFT(len, false, inr, NULL, outr, outi); + MakeFilter (buffer, len); + + // Apply filter + // DC component is purely real + mFFTBuffer[0] = buffer[0] * mFilterFuncR[0]; + for(i=1; i<(len/2); i++) + { + const double re = buffer[hFFT->BitReversed[i] ]; + const double im = buffer[hFFT->BitReversed[i]+1]; + + mFFTBuffer[2*i ] = re*mFilterFuncR[i] - im*mFilterFuncI[i]; + mFFTBuffer[2*i+1] = re*mFilterFuncI[i] + im*mFilterFuncR[i]; + } + // Fs/2 component is purely real + mFFTBuffer[1] = buffer[1] * mFilterFuncR[len/2]; + + // Inverse FFT and normalization + InverseRealFFTf(mFFTBuffer, hFFT); + ReorderToTime(hFFT, mFFTBuffer, buffer); +} + +void EffectNoiseCoring::MakeFilter (const float* buffer, sampleCount len) +{ + // Create the filter + if (len != windowSize) + printf ("EffectNoiseCoring ERROR: invalid filter length (%lld != %d)\n", len, windowSize); + if (mShape > 1e-6) + mFilterFuncR[0] = 0; + else + mFilterFuncR[0] = (1 - exp (-buffer[0] * buffer[0] / mStrength)); + int i; + for(i=1; iBitReversed[i] ]; + const double im = buffer[hFFT->BitReversed[i]+1]; + mFilterFuncR[i] = mFilterFuncR[windowSize-i] = (1 - exp (-((re*re) + (im*im)) / (mStrength * pow (163./i, mShape/10.0)))); + } + mFilterFuncR[windowSize/2] = (1 - exp (-buffer[1] * buffer[1] / (mStrength * pow (163./i, mShape/10.0)))); + + // Dilate the filter to prevent the windowing from attenuating + // isolated frequencies too much. The dilation is not a problem + // as far as noise removal is concerned thanks to the masking + // effect of nearby frequencies. + for (i = 0; i < windowSize/2; ++i) + { + double result = 0.0; + for (int j = i-(3*windowSize)/(2*mM); j <= i+(3*windowSize)/(2*mM); ++j) + if ((j > 0) && (j < windowSize/2) && (mFilterFuncR[windowSize-j] > result)) + result = mFilterFuncR[windowSize-j]; + mFilterFuncR[i] = result; + } + for (i = 1; i < windowSize/2; ++i) + mFilterFuncR[windowSize-i] = mFilterFuncR[i]; + + //transfer to time domain to do the padding and windowing + float *outr = new float[windowSize]; + float *outi = new float[windowSize]; + InverseRealFFT(windowSize, mFilterFuncR, NULL, outr); // To time domain + + for(i=0;i<=(mM-1)/2;i++) + { //Windowing - could give a choice, fixed for now - MJS + // double mult=0.54-0.46*cos(2*M_PI*(i+(M-1)/2.0)/(mM-1)); //Hamming + //Blackman + double mult = 0.42-0.5*cos(2*M_PI*(i+(mM-1)/2.0)/(mM-1))+.08*cos(4*M_PI*(i+(mM-1)/2.0)/(mM-1)); + outr[i]*=mult; + if(i!=0){ + outr[windowSize-i]*=mult; + } + } + for(;i<=windowSize/2;i++) + { //Padding + outr[i]=0; + outr[windowSize-i]=0; + } + float *tempr = new float[mM]; + for(i=0;i<(mM-1)/2;i++) + { //shift so that padding on right + tempr[(mM-1)/2+i]=outr[i]; + tempr[i]=outr[windowSize-(mM-1)/2+i]; + } + tempr[(mM-1)/2+i]=outr[i]; + + for(i=0;iSetValidator(vld); + mThresholdS = S.Id(ID_THRESHOLD_SLIDER).AddSlider(wxT(""), 0, THRESHOLD_MAX, THRESHOLD_MIN); + mThresholdS->SetName(_("Threshold")); + mThresholdS->SetRange(THRESHOLD_MIN, THRESHOLD_MAX); + mThresholdS->SetSizeHints(150, -1); + + mGainT = S.Id(ID_GAIN_TEXT).AddTextBox(_("Noise re&duction (dB):"), + wxT(""), + 0); + S.SetStyle(wxSL_HORIZONTAL); + mGainT->SetValidator(vld); + mGainS = S.Id(ID_GAIN_SLIDER).AddSlider(wxT(""), 0, GAIN_MAX, GAIN_MIN); + mGainS->SetName(_("Noise reduction")); + mGainS->SetRange(GAIN_MIN, GAIN_MAX); + mGainS->SetSizeHints(150, -1); + + mShapeT = S.Id(ID_SHAPE_TEXT).AddTextBox(_("Noise &shape (dB/decade):"), + wxT(""), + 0); + S.SetStyle(wxSL_HORIZONTAL); + mShapeT->SetValidator(vld); + mShapeS = S.Id(ID_SHAPE_SLIDER).AddSlider(wxT(""), 0, SHAPE_MAX, SHAPE_MIN); + mShapeS->SetName(_("Noise shape")); + mShapeS->SetRange(SHAPE_MIN, SHAPE_MAX); + mShapeS->SetSizeHints(150, -1); + + mWindowSizeT = S.Id(ID_WINDOW_SIZE_TEXT).AddTextBox(_("&Filter length:"), + wxT(""), + 0); + S.SetStyle(wxSL_HORIZONTAL); + mWindowSizeT->SetValidator(vld); + mWindowSizeS = S.Id(ID_WINDOW_SIZE_SLIDER).AddSlider(wxT(""), 0, WINDOW_SIZE_MAX, WINDOW_SIZE_MIN); + mWindowSizeS->SetName(_("Filter length")); + mWindowSizeS->SetRange(WINDOW_SIZE_MIN, WINDOW_SIZE_MAX); + mWindowSizeS->SetSizeHints(150, -1); + } + S.EndMultiColumn(); + } + S.EndStatic(); +} + +bool NoiseCoringDialog::TransferDataToWindow() +{ + mWindowSizeT->SetValue(wxString::Format(wxT("%d"), mWindowSize)); + mThresholdT->SetValue(wxString::Format(wxT("%d"), (int)mThreshold)); + mGainT->SetValue(wxString::Format(wxT("%d"), (int)mGain)); + mShapeT->SetValue(wxString::Format(wxT("%d"), (int)mShape)); + + mWindowSizeS->SetValue(TrapLong(mWindowSize, WINDOW_SIZE_MIN, WINDOW_SIZE_MAX)); + mThresholdS->SetValue(TrapLong(mThreshold, THRESHOLD_MIN, THRESHOLD_MAX)); + mGainS->SetValue(TrapLong(mGain, GAIN_MIN, GAIN_MAX)); + mShapeS->SetValue(TrapLong(mShape, SHAPE_MIN, SHAPE_MAX)); + + return true; +} + +bool NoiseCoringDialog::TransferDataFromWindow() +{ + // Nothing to do here + return true; +} + +void NoiseCoringDialog::OnWindowSizeText(wxCommandEvent & event) +{ + mWindowSizeT->GetValue().ToLong(&mWindowSize); + mWindowSizeS->SetValue(TrapLong(mWindowSize, WINDOW_SIZE_MIN, WINDOW_SIZE_MAX)); +} + +void NoiseCoringDialog::OnThresholdText(wxCommandEvent & event) +{ + mThresholdT->GetValue().ToDouble(&mThreshold); + mThresholdS->SetValue(TrapLong(mThreshold, THRESHOLD_MIN, THRESHOLD_MAX)); +} + +void NoiseCoringDialog::OnGainText(wxCommandEvent & event) +{ + mGainT->GetValue().ToDouble(&mGain); + mGainS->SetValue(TrapLong(mGain, GAIN_MIN, GAIN_MAX)); +} + +void NoiseCoringDialog::OnShapeText(wxCommandEvent & event) +{ + mShapeT->GetValue().ToDouble(&mShape); + mShapeS->SetValue(TrapLong(mShape, SHAPE_MIN, SHAPE_MAX)); +} + +void NoiseCoringDialog::OnWindowSizeSlider(wxCommandEvent & event) +{ + mWindowSize = mWindowSizeS->GetValue(); + mWindowSizeT->SetValue(wxString::Format(wxT("%d"), mWindowSize)); +} + +void NoiseCoringDialog::OnThresholdSlider(wxCommandEvent & event) +{ + mThreshold = mThresholdS->GetValue(); + mThresholdT->SetValue(wxString::Format(wxT("%d"), (int)mThreshold)); +} + +void NoiseCoringDialog::OnGainSlider(wxCommandEvent & event) +{ + mGain = mGainS->GetValue(); + mGainT->SetValue(wxString::Format(wxT("%d"), (int)mGain)); +} + +void NoiseCoringDialog::OnShapeSlider(wxCommandEvent & event) +{ + mShape = mShapeS->GetValue(); + mShapeT->SetValue(wxString::Format(wxT("%d"), (int)mShape)); +} + +// Indentation settings for Vim and Emacs and unique identifier for Arch, a +// version control system. Please do not modify past this point. +// +// Local Variables: +// c-basic-offset: 3 +// indent-tabs-mode: nil +// End: +// +// vim: et sts=3 sw=3 +// arch-tag: 65b35bfa-632c-46fe-9170-840a158b3c97 + diff -r 88c04d1bb5eb src/effects/NoiseCoring.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/effects/NoiseCoring.h Sun Sep 18 15:42:53 2011 +0200 @@ -0,0 +1,156 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + NoiseCoring.h + + Jerome M. Berger + +***********************************************************************/ + +#ifndef __AUDACITY_EFFECT_NOISE_CORING__ +#define __AUDACITY_EFFECT_NOISE_CORING__ + +#include "Effect.h" +#include "../RealFFTf.h" +#include "../WaveTrack.h" + +#include +#include + +class NoiseCoringDialog; + +class EffectNoiseCoring: public Effect { + +public: + + EffectNoiseCoring(); + virtual ~EffectNoiseCoring(); + + virtual wxString GetEffectName() { + return wxString(_("Noise Coring...")); + } + + virtual wxString GetEffectIdentifier() { + return wxString(wxT("NoiseCoring")); + } + + virtual std::set GetEffectCategories() { + std::set result; + result.insert(wxT("http://audacityteam.org/namespace#NoiseCoring")); + return result; + } + + virtual wxString GetEffectAction() { + return wxString(_("Performing Noise Coring...")); + } + + virtual bool Init(); + virtual bool PromptUser(); + virtual bool TransferParameters( Shuttle & shuttle ); + + virtual bool Process(); + + // Number of samples in an FFT window + enum {windowSize=16384}; //MJS - work out the optimum for this at run time? Have a dialog box for it? + +private: + bool ProcessOne(int count, WaveTrack * t, + sampleCount start, sampleCount len); + + void MakeFilter (const float* buffer, sampleCount len); + void Filter(sampleCount len, + float *buffer); + void ReadPrefs(); + + HFFT hFFT; + float *mFFTBuffer; + float *mFilterFuncR; + float *mFilterFuncI; + int mM; + double mThreshold; + double mGain; + double mStrength; + double mShape; + +public: + +friend class NoiseCoringDialog; +}; + +// WDR: class declarations + +//---------------------------------------------------------------------------- +// NoiseCoringDialog +//---------------------------------------------------------------------------- + +class NoiseCoringDialog: public EffectDialog +{ +public: + // constructors and destructors + NoiseCoringDialog(EffectNoiseCoring *effect, + wxWindow *parent); + + // WDR: method declarations for EqualizationDialog + wxSizer *MakeNoiseCoringDialog(bool call_fit = true, + bool set_sizer = true); + + void PopulateOrExchange(ShuttleGui & S); + bool TransferDataToWindow(); + bool TransferDataFromWindow(); + +private: + // handlers + void OnRemoveNoise( wxCommandEvent &event ); + void OnCancel( wxCommandEvent &event ); + + void OnWindowSizeText(wxCommandEvent & event); + void OnThresholdText(wxCommandEvent & event); + void OnGainText(wxCommandEvent & event); + void OnShapeText(wxCommandEvent & event); + void OnWindowSizeSlider(wxCommandEvent & event); + void OnThresholdSlider(wxCommandEvent & event); + void OnGainSlider(wxCommandEvent & event); + void OnShapeSlider(wxCommandEvent & event); + +public: + + EffectNoiseCoring *m_pEffect; + + wxButton *m_pButton_Preview; + wxButton *m_pButton_RemoveNoise; + + wxSlider *mWindowSizeS; + wxSlider *mThresholdS; + wxSlider *mGainS; + wxSlider *mShapeS; + + wxTextCtrl *mWindowSizeT; + wxTextCtrl *mThresholdT; + wxTextCtrl *mGainT; + wxTextCtrl *mShapeT; + + long mWindowSize; + double mThreshold; + double mGain; + double mShape; + +private: + DECLARE_EVENT_TABLE() + +}; + +#endif + +// Indentation settings for Vim and Emacs and unique identifier for Arch, a +// version control system. Please do not modify past this point. +// +// Local Variables: +// c-basic-offset: 3 +// indent-tabs-mode: nil +// mode: c++ +// End: +// +// vim: et sts=3 sw=3 +// arch-tag: 309f263d-748c-4dc0-9e68-9e86732890bb +