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