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 EffectOutputTracks outputs { *mTracks, {{ mT0, mT1 }} };
226 bool bGoodResult = true;
227
228 int count = 0;
229 for (auto track : outputs.Get().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 if (bGoodResult)
254 outputs.Commit();
255
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
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
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:190
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:335
#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
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
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:57
#define S(N)
Definition: ToChars.cpp:64
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:56
void reinit(Integral count)
Definition: MemoryX.h:108
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Definition: ClientData.h:317
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:116
double mProjectRate
Definition: EffectBase.h:112
std::shared_ptr< TrackList > mTracks
Definition: EffectBase.h:109
double mT0
Definition: EffectBase.h:115
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
Definition: Effect.cpp:343
int GetNumWaveTracks() const
Definition: Effect.h:139
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
Use this object to copy the input tracks to tentative outputTracks.
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:640
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:227
size_t GetMaxBlockSize() const
Definition: WaveTrack.cpp:2754
size_t GetBestBlockSize(sampleCount t) const
Definition: WaveTrack.cpp:2734
void ClearAndPaste(double t0, double t1, const WaveTrack &src, bool preserve=true, bool merge=true, const TimeWarper *effectWarper=nullptr, bool clearByTrimming=false)
Definition: WaveTrack.cpp:1554
Holder EmptyCopy(const SampleBlockFactoryPtr &pFactory={}, bool keepLink=true) const
Definition: WaveTrack.cpp:1379
virtual bool Flush() noexcept=0
virtual bool Write(const wxString &key, bool value)=0
virtual bool Read(const wxString &key, bool *value) const =0
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.