Audacity 3.2.0
NoiseRemoval.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 NoiseRemoval.cpp
6
7 Dominic Mazzoni
8
9*******************************************************************//****************************************************************//*******************************************************************/
40
41
42#include "NoiseRemoval.h"
43
44#if !defined(EXPERIMENTAL_NOISE_REDUCTION)
45
46#include "EffectPreview.h"
47#include "LoadEffects.h"
48
49#include "WaveTrack.h"
50#include "Prefs.h"
51#include "FileNames.h"
52#include "ShuttleGui.h"
53
54#include <math.h>
55
56#if defined(__WXMSW__) && !defined(__CYGWIN__)
57#include <float.h>
58#define finite(x) _finite(x)
59#endif
60
61#include <wx/file.h>
62#include <wx/ffile.h>
63#include <wx/bitmap.h>
64#include <wx/brush.h>
65#include <wx/button.h>
66#include <wx/choice.h>
67#include <wx/radiobut.h>
68#include <wx/statbox.h>
69#include <wx/stattext.h>
70#include <wx/textctrl.h>
71#include <wx/valtext.h>
72
73
75
77{ XO("Noise Removal") };
78
80
82{
83 mWindowSize = 2048;
84 mSpectrumSize = 1 + mWindowSize / 2;
85
86 gPrefs->Read(wxT("/Effects/NoiseRemoval/NoiseSensitivity"),
87 &mSensitivity, 0.0);
88 gPrefs->Read(wxT("/Effects/NoiseRemoval/NoiseGain"),
89 &mNoiseGain, -24.0);
90 gPrefs->Read(wxT("/Effects/NoiseRemoval/NoiseFreqSmoothing"),
91 &mFreqSmoothingHz, 150.0);
92 gPrefs->Read(wxT("/Effects/NoiseRemoval/NoiseAttackDecayTime"),
93 &mAttackDecayTime, 0.15);
94 gPrefs->Read(wxT("/Effects/NoiseRemoval/NoiseLeaveNoise"),
95 &mbLeaveNoise, false);
96// mbLeaveNoise = false;
97
98
99 mMinSignalTime = 0.05f;
100 mHasProfile = false;
101 mDoProfile = true;
102
104
105 Init();
106}
107
109{
110}
111
112// ComponentInterface implementation
113
115{
116 return Symbol;
117}
118
120{
121 return XO("Removes constant background noise such as fans, tape noise, or hums");
122}
123
124// EffectDefinitionInterface implementation
125
127{
128 return EffectTypeProcess;
129}
130
132{
133 return false;
134}
135
136// Effect implementation
137
138#define MAX_NOISE_LEVEL 30
140{
141 mLevel = gPrefs->Read(wxT("/Effects/NoiseRemoval/Noise_Level"), 3L);
142 if ((mLevel < 0) || (mLevel > MAX_NOISE_LEVEL)) { // corrupted Prefs?
143 mLevel = 0; //Off-skip
144 gPrefs->Write(wxT("/Effects/NoiseRemoval/Noise_Level"), mLevel);
145 }
146 return gPrefs->Flush();
147}
148
150{
151 return (mLevel == 0);
152}
153
156
161 wxWindow &parent, const EffectDialogFactory &,
162 std::shared_ptr<EffectInstance> &pInstance, EffectSettingsAccess &access,
163 bool forceModal )
164{
165 // Assign the out parameter
166 pInstance = MakeInstance();
167 if (pInstance && !pInstance->Init())
168 pInstance.reset();
169
170 // to do: use forceModal correctly
171 NoiseRemovalDialog dlog(this, access, &parent);
173 dlog.mGain = -mNoiseGain;
174 dlog.mFreq = mFreqSmoothingHz;
175 dlog.mTime = mAttackDecayTime;
177 dlog.mKeepSignal->SetValue(!mbLeaveNoise);
178 dlog.mKeepNoise->SetValue(mbLeaveNoise);
179
180 // We may want to twiddle the levels if we are setting
181 // from a macro editing dialog
182 bool bAllowTwiddleSettings = forceModal;
183
184 if (mHasProfile || bAllowTwiddleSettings) {
185 dlog.m_pButton_Preview->Enable(GetNumWaveTracks() != 0);
186 dlog.m_pButton_RemoveNoise->SetDefault();
187 } else {
188 dlog.m_pButton_Preview->Enable(false);
189 dlog.m_pButton_RemoveNoise->Enable(false);
190 }
191
193 dlog.mKeepNoise->SetValue(dlog.mbLeaveNoise);
194 dlog.CentreOnParent();
195 dlog.ShowModal();
196
197 const auto returnCode = dlog.GetReturnCode();
198 if (!returnCode)
199 return 0;
200
202 mNoiseGain = -dlog.mGain;
203 mFreqSmoothingHz = dlog.mFreq;
204 mAttackDecayTime = dlog.mTime;
206
207 gPrefs->Write(wxT("/Effects/NoiseRemoval/NoiseSensitivity"), mSensitivity);
208 gPrefs->Write(wxT("/Effects/NoiseRemoval/NoiseGain"), mNoiseGain);
209 gPrefs->Write(wxT("/Effects/NoiseRemoval/NoiseFreqSmoothing"), mFreqSmoothingHz);
210 gPrefs->Write(wxT("/Effects/NoiseRemoval/NoiseAttackDecayTime"), mAttackDecayTime);
211 gPrefs->Write(wxT("/Effects/NoiseRemoval/NoiseLeaveNoise"), mbLeaveNoise);
212
213 mDoProfile = (dlog.GetReturnCode() == 1);
214 if (!gPrefs->Flush())
215 return 0;
216 return returnCode;
217}
218
220{
221 Initialize();
222
223 // This same code will both remove noise and profile it,
224 // depending on 'mDoProfile'
225 this->CopyInputTracks(); // Set up mOutputTracks.
226 bool bGoodResult = true;
227
228 int count = 0;
229 for( auto track : mOutputTracks->Selected< WaveTrack >() ) {
230 double trackStart = track->GetStartTime();
231 double trackEnd = track->GetEndTime();
232 double t0 = mT0 < trackStart? trackStart: mT0;
233 double t1 = mT1 > trackEnd? trackEnd: mT1;
234
235 if (t1 > t0) {
236 auto start = track->TimeToLongSamples(t0);
237 auto end = track->TimeToLongSamples(t1);
238 auto len = end - start;
239
240 if (!ProcessOne(count, track, start, len)) {
241 bGoodResult = false;
242 break;
243 }
244 }
245 count++;
246 }
247
248 if (bGoodResult && mDoProfile) {
249 mHasProfile = true;
250 mDoProfile = false;
251 }
252
253 this->ReplaceProcessedTracks(bGoodResult);
254 return bGoodResult;
255}
256
258{
259 Floats tmp{ mSpectrumSize };
260 int j, j0, j1;
261
262 for(int i = 0; i < mSpectrumSize; i++) {
263 j0 = wxMax(0, i - mFreqSmoothingBins);
264 j1 = wxMin(mSpectrumSize-1, i + mFreqSmoothingBins);
265 tmp[i] = 0.0;
266 for(j = j0; j <= j1; j++) {
267 tmp[i] += spec[j];
268 }
269 tmp[i] /= (j1 - j0 + 1);
270 }
271
272 for(size_t i = 0; i < mSpectrumSize; i++)
273 spec[i] = tmp[i];
274}
275
277{
284 // Applies to power, divide by 10:
285 mSensitivityFactor = pow(10.0, mSensitivity/10.0);
287 (int)(mMinSignalTime * mSampleRate / (mWindowSize / 2));
288 if( mMinSignalBlocks < 1 )
291
294
299
300 // Initialize the FFT
302
307
308 // Create a Hann window function
309 for(size_t i=0; i<mWindowSize; i++)
310 mWindow[i] = 0.5 - 0.5 * cos((2.0*M_PI*i) / mWindowSize);
311
312 if (mDoProfile) {
313 for (size_t i = 0; i < mSpectrumSize; i++)
314 mNoiseThreshold[i] = float(0);
315 }
316}
317
319{
320 hFFT.reset();
321
322 if (mDoProfile) {
324 }
325
326 mSpectrums.reset();
327 mGains.reset();
328 mRealFFTs.reset();
329 mImagFFTs.reset();
330
331 mFFTBuffer.reset();
332 mInWaveBuffer.reset();
333 mWindow.reset();
334 mOutOverlapBuffer.reset();
335
336 mOutputTrack.reset();
337}
338
340{
341 for(size_t i = 0; i < mHistoryLen; i++) {
342 for(size_t j = 0; j < mSpectrumSize; j++) {
343 mSpectrums[i][j] = 0;
345 mRealFFTs[i][j] = 0.0;
346 mImagFFTs[i][j] = 0.0;
347 }
348 }
349
350 for(size_t j = 0; j < mWindowSize; j++)
351 mOutOverlapBuffer[j] = 0.0;
352
353 mInputPos = 0;
354 mInSampleCount = 0;
355 mOutSampleCount = -(int)((mWindowSize / 2) * (mHistoryLen - 1));
356}
357
358void EffectNoiseRemoval::ProcessSamples(size_t len, float *buffer)
359{
360 while(len && mOutSampleCount < mInSampleCount) {
361 size_t avail = wxMin(len, mWindowSize - mInputPos);
362 for(size_t i = 0; i < avail; i++)
363 mInWaveBuffer[mInputPos + i] = buffer[i];
364 buffer += avail;
365 len -= avail;
366 mInputPos += avail;
367
368 if (mInputPos == int(mWindowSize)) {
370 if (mDoProfile)
371 GetProfile();
372 else
373 RemoveNoise();
375
376 // Rotate halfway for overlap-add
377 for(size_t i = 0; i < mWindowSize / 2; i++) {
379 }
381 }
382 }
383}
384
386{
387 for(size_t i = 0; i < mWindowSize; i++)
389 RealFFTf(mFFTBuffer.get(), hFFT.get());
390 for(size_t i = 1; i + 1 < mSpectrumSize; i++) {
391 mRealFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i] ];
392 mImagFFTs[0][i] = mFFTBuffer[hFFT->BitReversed[i]+1];
393 mSpectrums[0][i] = mRealFFTs[0][i]*mRealFFTs[0][i] + mImagFFTs[0][i]*mImagFFTs[0][i];
395 }
396 // DC and Fs/2 bins need to be handled specially
397 mSpectrums[0][0] = mFFTBuffer[0]*mFFTBuffer[0];
401}
402
403namespace {
404 inline void Rotate(ArraysOf<float> &arrays, size_t historyLen)
405 {
406 Floats temp = std::move( arrays[ historyLen - 1 ] );
407
408 for ( size_t nn = historyLen - 1; nn--; )
409 arrays[ nn + 1 ] = std::move( arrays[ nn ] );
410 arrays[0] = std::move( temp );
411 }
412}
413
415{
416 // Remember the last window so we can reuse it
421}
422
424{
425 // Keep flushing empty input buffers through the history
426 // windows until we've output exactly as many samples as
427 // were input.
428 // Well, not exactly, but not more than mWindowSize/2 extra samples at the end.
429 // We'll DELETE them later in ProcessOne.
430
431 Floats empty{ mWindowSize / 2 };
432 for(size_t i = 0; i < mWindowSize / 2; i++)
433 empty[i] = 0.0;
434
436 ProcessSamples(mWindowSize / 2, empty.get());
437 }
438}
439
441{
442 // The noise threshold for each frequency is the maximum
443 // level achieved at that frequency for a minimum of
444 // mMinSignalBlocks blocks in a row - the max of a min.
445
446 int start = mHistoryLen - mMinSignalBlocks;
447 int finish = mHistoryLen;
448 int i;
449
450 for (size_t j = 0; j < mSpectrumSize; j++) {
451 float min = mSpectrums[start][j];
452 for (i = start+1; i < finish; i++) {
453 if (mSpectrums[i][j] < min)
454 min = mSpectrums[i][j];
455 }
456 if (min > mNoiseThreshold[j])
457 mNoiseThreshold[j] = min;
458 }
459
460 mOutSampleCount += mWindowSize / 2; // what is this for? Not used when we are getting the profile?
461}
462
464{
465 size_t center = mHistoryLen / 2;
466 size_t start = center - mMinSignalBlocks/2;
467 size_t finish = start + mMinSignalBlocks;
468
469 // Raise the gain for elements in the center of the sliding history
470 for (size_t j = 0; j < mSpectrumSize; j++) {
471 float min = mSpectrums[start][j];
472 for (size_t i = start+1; i < finish; i++) {
473 if (mSpectrums[i][j] < min)
474 min = mSpectrums[i][j];
475 }
476 if (min > mSensitivityFactor * mNoiseThreshold[j] && mGains[center][j] < 1.0) {
477 if (mbLeaveNoise) mGains[center][j] = 0.0;
478 else mGains[center][j] = 1.0;
479 } else {
480 if (mbLeaveNoise) mGains[center][j] = 1.0;
481 }
482 }
483
484 // Decay the gain in both directions;
485 // note that mOneBlockAttackDecay is less than 1.0
486 // of linear attenuation per block
487 for (size_t j = 0; j < mSpectrumSize; j++) {
488 for (size_t i = center + 1; i < mHistoryLen; i++) {
489 if (mGains[i][j] < mGains[i - 1][j] * mOneBlockAttackDecay)
490 mGains[i][j] = mGains[i - 1][j] * mOneBlockAttackDecay;
491 if (mGains[i][j] < mNoiseAttenFactor)
493 }
494 for (size_t i = center; i--;) {
495 if (mGains[i][j] < mGains[i + 1][j] * mOneBlockAttackDecay)
496 mGains[i][j] = mGains[i + 1][j] * mOneBlockAttackDecay;
497 if (mGains[i][j] < mNoiseAttenFactor)
499 }
500 }
501
502
503 // Apply frequency smoothing to output gain
504 int out = mHistoryLen - 1; // end of the queue
505
506 ApplyFreqSmoothing(mGains[out].get());
507
508 // Apply gain to FFT
509 for (size_t j = 0; j < (mSpectrumSize-1); j++) {
510 mFFTBuffer[j*2 ] = mRealFFTs[out][j] * mGains[out][j];
511 mFFTBuffer[j*2+1] = mImagFFTs[out][j] * mGains[out][j];
512 }
513 // The Fs/2 component is stored as the imaginary part of the DC component
515
516 // Invert the FFT into the output buffer
517 InverseRealFFTf(mFFTBuffer.get(), hFFT.get());
518
519 // Overlap-add
520 for(size_t j = 0; j < (mSpectrumSize-1); j++) {
521 mOutOverlapBuffer[j*2 ] += mFFTBuffer[hFFT->BitReversed[j] ] * mWindow[j*2 ];
522 mOutOverlapBuffer[j*2+1] += mFFTBuffer[hFFT->BitReversed[j]+1] * mWindow[j*2+1];
523 }
524
525 // Output the first half of the overlap buffer, they're done -
526 // and then shift the next half over.
527 if (mOutSampleCount >= 0) { // ...but not if it's the first half-window
529 mWindowSize / 2);
530 }
532 for(size_t j = 0; j < mWindowSize / 2; j++) {
534 mOutOverlapBuffer[j + (mWindowSize / 2)] = 0.0;
535 }
536}
537
539 sampleCount start, sampleCount len)
540{
541 if (track == NULL)
542 return false;
543
545
546 if (!mDoProfile)
547 mOutputTrack = track->EmptyCopy();
548
549 auto bufferSize = track->GetMaxBlockSize();
550 Floats buffer{ bufferSize };
551
552 bool bLoopSuccess = true;
553 auto samplePos = start;
554 while (samplePos < start + len) {
555 //Get a blockSize of samples (smaller than the size of the buffer)
556 //Adjust the block size if it is the final block in the track
557 const auto blockSize = limitSampleBufferSize(
558 track->GetBestBlockSize(samplePos),
559 start + len - samplePos
560 );
561
562 //Get the samples from the track and put them in the buffer
563 track->Get((samplePtr)buffer.get(), floatSample, samplePos, blockSize);
564
565 mInSampleCount += blockSize;
566 ProcessSamples(blockSize, buffer.get());
567
568 samplePos += blockSize;
569
570 // Update the Progress meter
571 if (TrackProgress(count, (samplePos - start).as_double() / len.as_double())) {
572 bLoopSuccess = false;
573 break;
574 }
575 }
576
577 FinishTrack();
578
579 if (!mDoProfile) {
580 // Flush the output WaveTrack (since it's buffered)
581 mOutputTrack->Flush();
582
583 // Take the output track and insert it in place of the original
584 // sample data (as operated on -- this may not match mT0/mT1)
585 if (bLoopSuccess) {
586 double t0 = mOutputTrack->LongSamplesToTime(start);
587 double tLen = mOutputTrack->LongSamplesToTime(len);
588 // Filtering effects always end up with more data than they started with. Delete this 'tail'.
589 mOutputTrack->HandleClear(tLen, mOutputTrack->GetEndTime(), false, false);
590 track->ClearAndPaste(t0, t0 + tLen, mOutputTrack.get(), true, false);
591 }
592 }
593
594 return bLoopSuccess;
595}
596
597// WDR: class implementations
598
599//----------------------------------------------------------------------------
600// NoiseRemovalDialog
601//----------------------------------------------------------------------------
602
603// WDR: event table for NoiseRemovalDialog
604
605enum {
618};
619
620#define SENSITIVITY_MIN 0 // Corresponds to -20 dB
621#define SENSITIVITY_MAX 4000 // Corresponds to 20 dB
622
623#define GAIN_MIN 0
624#define GAIN_MAX 48 // Corresponds to -48 dB
625
626#define FREQ_MIN 0
627#define FREQ_MAX 100 // Corresponds to 1000 Hz
628
629#define TIME_MIN 0
630#define TIME_MAX 100 // Corresponds to 1.000 seconds
631
632
633BEGIN_EVENT_TABLE(NoiseRemovalDialog,wxDialogWrapper)
649
651 EffectNoiseRemoval * effect, EffectSettingsAccess &access, wxWindow *parent)
652 : EffectDialog( parent, XO("Noise Removal"), EffectTypeProcess)
653 , mAccess{ access }
654{
655 m_pEffect = effect;
656
657 // NULL out the control members until the controls are created.
658 m_pButton_GetProfile = NULL;
659 m_pButton_Preview = NULL;
660 m_pButton_RemoveNoise = NULL;
661
662 Init();
663
664 m_pButton_Preview =
665 (wxButton *)wxWindow::FindWindowById(ID_EFFECT_PREVIEW, this);
666 m_pButton_RemoveNoise =
667 (wxButton *)wxWindow::FindWindowById(wxID_OK, this);
668}
669
670void NoiseRemovalDialog::OnGetProfile( wxCommandEvent & WXUNUSED(event))
671{
672 EndModal(1);
673}
674
675void NoiseRemovalDialog::OnKeepNoise( wxCommandEvent & WXUNUSED(event))
676{
677 mbLeaveNoise = mKeepNoise->GetValue();
678}
679
680void NoiseRemovalDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
681{
682 // Save & restore parameters around Preview, because we didn't do OK.
683 bool oldDoProfile = m_pEffect->mDoProfile;
684 bool oldLeaveNoise = m_pEffect->mbLeaveNoise;
685 double oldSensitivity = m_pEffect->mSensitivity;
686 double oldGain = m_pEffect->mNoiseGain;
687 double oldFreq = m_pEffect->mFreqSmoothingHz;
688 double oldTime = m_pEffect->mAttackDecayTime;
689
691
692 m_pEffect->mDoProfile = false;
698
699 auto cleanup = finally( [&] {
700 m_pEffect->mSensitivity = oldSensitivity;
701 m_pEffect->mNoiseGain = oldGain;
702 m_pEffect->mFreqSmoothingHz = oldFreq;
703 m_pEffect->mAttackDecayTime = oldTime;
704 m_pEffect->mbLeaveNoise = oldLeaveNoise;
705 m_pEffect->mDoProfile = oldDoProfile;
706 } );
707
709}
710
711void NoiseRemovalDialog::OnRemoveNoise( wxCommandEvent & WXUNUSED(event))
712{
713 mbLeaveNoise = mKeepNoise->GetValue();
714 EndModal(2);
715}
716
717void NoiseRemovalDialog::OnCancel(wxCommandEvent & WXUNUSED(event))
718{
719 EndModal(0);
720}
721
723{
724 S.StartStatic(XO("Step 1"));
725 {
726 S.AddVariableText(XO(
727"Select a few seconds of just noise so Audacity knows what to filter out,\nthen click Get Noise Profile:"));
728 m_pButton_GetProfile = S.Id(ID_BUTTON_GETPROFILE).AddButton(XXO("&Get Noise Profile"));
729 }
730 S.EndStatic();
731
732 S.StartStatic(XO("Step 2"));
733 {
734 S.AddVariableText(XO(
735"Select all of the audio you want filtered, choose how much noise you want\nfiltered out, and then click 'OK' to remove noise.\n"));
736
737 S.StartMultiColumn(3, wxEXPAND);
738 S.SetStretchyCol(2);
739 {
740 mGainT = S.Id(ID_GAIN_TEXT)
741 .Validator<wxTextValidator>(wxFILTER_NUMERIC)
742 .AddTextBox(XXO("Noise re&duction (dB):"), wxT(""), 0);
743
745 .Name(XO("Noise reduction"))
746 .Style(wxSL_HORIZONTAL)
747 .MinSize( { 150, -1 } )
748 .AddSlider( {}, 0, GAIN_MAX, GAIN_MIN);
749
751 .Validator<wxTextValidator>(wxFILTER_NUMERIC)
752 .AddTextBox(XXO("&Sensitivity (dB):"), wxT(""), 0);
754 .Name(XO("Sensitivity"))
755 .Style(wxSL_HORIZONTAL)
756 .MinSize( { 150, -1 } )
757 .AddSlider( {}, 0, SENSITIVITY_MAX, SENSITIVITY_MIN);
758
759 mFreqT = S.Id(ID_FREQ_TEXT)
760 .Validator<wxTextValidator>(wxFILTER_NUMERIC)
761 .AddTextBox(XXO("Fr&equency smoothing (Hz):"), wxT(""), 0);
763 .Name(XO("Frequency smoothing"))
764 .Style(wxSL_HORIZONTAL)
765 .MinSize( { 150, -1 } )
766 .AddSlider( {}, 0, FREQ_MAX, FREQ_MIN);
767
768 mTimeT = S.Id(ID_TIME_TEXT)
769 .Validator<wxTextValidator>(wxFILTER_NUMERIC)
770 .AddTextBox(XXO("Attac&k/decay time (secs):"), wxT(""), 0);
772 .Name(XO("Attack/decay time"))
773 .Style(wxSL_HORIZONTAL)
774 .MinSize( { 150, -1 } )
775 .AddSlider( {}, 0, TIME_MAX, TIME_MIN);
776
777 S.AddPrompt(XXO("Noise:"));
779 .AddRadioButton(XXO("Re&move"));
781 .AddRadioButtonToGroup(XXO("&Isolate"));
782 }
783 S.EndMultiColumn();
784 }
785 S.EndStatic();
786}
787
789{
790 mSensitivityT->SetValue(wxString::Format(wxT("%.2f"), mSensitivity));
791 mGainT->SetValue(wxString::Format(wxT("%d"), (int)mGain));
792 mFreqT->SetValue(wxString::Format(wxT("%d"), (int)mFreq));
793 mTimeT->SetValue(wxString::Format(wxT("%.2f"), mTime));
794 mKeepNoise->SetValue(mbLeaveNoise);
795 mKeepSignal->SetValue(!mbLeaveNoise);
796
797 mSensitivityS->SetValue(std::clamp<long>(mSensitivity*100.0 + (SENSITIVITY_MAX-SENSITIVITY_MIN+1)/2.0, SENSITIVITY_MIN, SENSITIVITY_MAX));
798 mGainS->SetValue(std::clamp<long>(mGain, GAIN_MIN, GAIN_MAX));
799 mFreqS->SetValue(std::clamp<long>(mFreq / 10, FREQ_MIN, FREQ_MAX));
800 mTimeS->SetValue(std::clamp<long>(mTime * TIME_MAX + 0.5, TIME_MIN, TIME_MAX));
801
802 return true;
803}
804
806{
807 // Nothing to do here
808 return true;
809}
810
811void NoiseRemovalDialog::OnSensitivityText(wxCommandEvent & WXUNUSED(event))
812{
813 mSensitivityT->GetValue().ToDouble(&mSensitivity);
814 mSensitivityS->SetValue(std::clamp<long>(mSensitivity*100.0 + (SENSITIVITY_MAX-SENSITIVITY_MIN+1)/2.0, SENSITIVITY_MIN, SENSITIVITY_MAX));
815}
816
817void NoiseRemovalDialog::OnGainText(wxCommandEvent & WXUNUSED(event))
818{
819 mGainT->GetValue().ToDouble(&mGain);
820 mGainS->SetValue(std::clamp<long>(mGain, GAIN_MIN, GAIN_MAX));
821}
822
823void NoiseRemovalDialog::OnFreqText(wxCommandEvent & WXUNUSED(event))
824{
825 mFreqT->GetValue().ToDouble(&mFreq);
826 mFreqS->SetValue(std::clamp<long>(mFreq / 10, FREQ_MIN, FREQ_MAX));
827}
828
829void NoiseRemovalDialog::OnTimeText(wxCommandEvent & WXUNUSED(event))
830{
831 mTimeT->GetValue().ToDouble(&mTime);
832 mTimeS->SetValue(std::clamp<long>(mTime * TIME_MAX + 0.5, TIME_MIN, TIME_MAX));
833}
834
835void NoiseRemovalDialog::OnSensitivitySlider(wxCommandEvent & WXUNUSED(event))
836{
837 mSensitivity = mSensitivityS->GetValue()/100.0 - 20.0;
838 mSensitivityT->SetValue(wxString::Format(wxT("%.2f"), mSensitivity));
839}
840
841void NoiseRemovalDialog::OnGainSlider(wxCommandEvent & WXUNUSED(event))
842{
843 mGain = mGainS->GetValue();
844 mGainT->SetValue(wxString::Format(wxT("%d"), (int)mGain));
845}
846
847void NoiseRemovalDialog::OnFreqSlider(wxCommandEvent & WXUNUSED(event))
848{
849 mFreq = mFreqS->GetValue() * 10;
850 mFreqT->SetValue(wxString::Format(wxT("%d"), (int)mFreq));
851}
852
853void NoiseRemovalDialog::OnTimeSlider(wxCommandEvent & WXUNUSED(event))
854{
855 mTime = mTimeS->GetValue() / (TIME_MAX*1.0);
856 mTimeT->SetValue(wxString::Format(wxT("%.2f"), mTime));
857}
858
859#endif
wxT("CloseDown"))
END_EVENT_TABLE()
int min(int a, int b)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
#define M_PI
Definition: Distortion.cpp:30
#define ID_EFFECT_PREVIEW
Definition: Effect.h:199
EffectType
@ EffectTypeProcess
void EffectPreview(EffectBase &effect, EffectSettingsAccess &access, std::function< void()> updateUI, bool dryOnly)
Calculate temporary tracks of limited length with effect applied and play.
std::function< DialogFactoryResults(wxWindow &parent, EffectBase &, EffectUIServices &, EffectSettingsAccess &) > EffectDialogFactory
Type of function that creates a dialog for an effect.
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define DB_TO_LINEAR(x)
Definition: MemoryX.h:560
#define TIME_MAX
@ ID_GAIN_TEXT
@ ID_TIME_SLIDER
@ ID_BUTTON_GETPROFILE
@ ID_GAIN_SLIDER
@ ID_FREQ_SLIDER
@ ID_BUTTON_LEAVENOISE
@ ID_SENSITIVITY_TEXT
@ ID_SENSITIVITY_SLIDER
@ ID_RADIOBUTTON_KEEPSIGNAL
@ ID_TIME_TEXT
@ ID_FREQ_TEXT
@ ID_RADIOBUTTON_KEEPNOISE
#define SENSITIVITY_MIN
#define SENSITIVITY_MAX
#define MAX_NOISE_LEVEL
#define FREQ_MAX
#define TIME_MIN
#define GAIN_MIN
#define GAIN_MAX
#define FREQ_MIN
FileConfig * gPrefs
Definition: Prefs.cpp:70
void RealFFTf(fft_type *buffer, const FFTParam *h)
Definition: RealFFTf.cpp:161
void InverseRealFFTf(fft_type *buffer, const FFTParam *h)
Definition: RealFFTf.cpp:263
HFFT GetFFT(size_t fftlen)
Definition: RealFFTf.cpp:104
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22
char * samplePtr
Definition: SampleFormat.h:55
#define S(N)
Definition: ToChars.cpp:64
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:57
void reinit(Integral count)
Definition: MemoryX.h:109
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Base class for many of the effects in Audacity.
Definition: EffectBase.h:28
double mT1
Definition: EffectBase.h:119
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:97
double mProjectRate
Definition: EffectBase.h:115
double mT0
Definition: EffectBase.h:118
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:224
void CopyInputTracks(bool allSyncLockSelected=false)
Definition: Effect.cpp:400
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
Definition: Effect.cpp:350
int GetNumWaveTracks() const
Definition: Effect.h:141
Performs effect computation.
A two-pass effect to remove background noise.
Definition: NoiseRemoval.h:37
static const ComponentInterfaceSymbol Symbol
Definition: NoiseRemoval.h:39
ComponentInterfaceSymbol GetSymbol() override
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
bool Init() override
ArraysOf< float > mImagFFTs
Definition: NoiseRemoval.h:124
void ProcessSamples(size_t len, float *buffer)
std::shared_ptr< WaveTrack > mOutputTrack
Definition: NoiseRemoval.h:103
int ShowHostInterface(EffectBase &plugin, wxWindow &parent, const EffectDialogFactory &factory, std::shared_ptr< EffectInstance > &pInstance, EffectSettingsAccess &access, bool forceModal=false) override
ArraysOf< float > mRealFFTs
Definition: NoiseRemoval.h:123
void ApplyFreqSmoothing(float *spec)
EffectType GetType() const override
Type determines how it behaves.
bool ProcessOne(int count, WaveTrack *track, sampleCount start, sampleCount len)
sampleCount mOutSampleCount
Definition: NoiseRemoval.h:105
TranslatableString GetDescription() override
bool Process(EffectInstance &instance, EffectSettings &settings) override
ArraysOf< float > mSpectrums
Definition: NoiseRemoval.h:121
bool CheckWhetherSkipEffect(const EffectSettings &settings) const override
After Init(), tell whether Process() should be skipped.
virtual ~EffectNoiseRemoval()
ArraysOf< float > mGains
Definition: NoiseRemoval.h:122
void End() override
sampleCount mInSampleCount
Definition: NoiseRemoval.h:104
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
Dialog used with EffectNoiseRemoval.
Definition: NoiseRemoval.h:138
void OnFreqText(wxCommandEvent &event)
wxButton * m_pButton_RemoveNoise
Definition: NoiseRemoval.h:175
void OnPreview(wxCommandEvent &event) override
void OnFreqSlider(wxCommandEvent &event)
void PopulateOrExchange(ShuttleGui &S) override
wxTextCtrl * mTimeT
Definition: NoiseRemoval.h:188
void OnCancel(wxCommandEvent &event)
EffectSettingsAccess & mAccess
Definition: NoiseRemoval.h:171
void OnRemoveNoise(wxCommandEvent &event)
wxTextCtrl * mSensitivityT
Definition: NoiseRemoval.h:185
wxButton * m_pButton_Preview
Definition: NoiseRemoval.h:174
wxRadioButton * mKeepNoise
Definition: NoiseRemoval.h:178
wxButton * m_pButton_GetProfile
Definition: NoiseRemoval.h:173
void OnGainText(wxCommandEvent &event)
bool TransferDataFromWindow() override
void OnTimeSlider(wxCommandEvent &event)
wxTextCtrl * mFreqT
Definition: NoiseRemoval.h:187
void OnGainSlider(wxCommandEvent &event)
EffectNoiseRemoval * m_pEffect
Definition: NoiseRemoval.h:170
wxSlider * mSensitivityS
Definition: NoiseRemoval.h:180
void OnGetProfile(wxCommandEvent &event)
void OnKeepNoise(wxCommandEvent &event)
void OnSensitivityText(wxCommandEvent &event)
void OnSensitivitySlider(wxCommandEvent &event)
void OnTimeText(wxCommandEvent &event)
wxTextCtrl * mGainT
Definition: NoiseRemoval.h:186
wxRadioButton * mKeepSignal
Definition: NoiseRemoval.h:177
bool TransferDataToWindow() override
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:625
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
bool Get(samplePtr buffer, sampleFormat format, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const override
Definition: WaveTrack.cpp:1985
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1672
size_t GetBestBlockSize(sampleCount t) const override
This returns a nonnegative number of samples meant to size a memory buffer.
Definition: WaveTrack.cpp:1654
void ClearAndPaste(double t0, double t1, const Track *src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=NULL)
Definition: WaveTrack.cpp:771
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
Definition: WaveTrack.cpp:635
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
double as_double() const
Definition: SampleCount.h:46
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
void Rotate(ArraysOf< float > &arrays, size_t historyLen)
BuiltinEffectsModule::Registration< EffectNoiseRemoval > reg
Externalized state of a plug-in.