📄 noiseremoval.cpp
字号:
/********************************************************************** Audacity: A Digital Audio Editor NoiseRemoval.cpp Dominic Mazzoni The noise is removed using noise gates on each frequency band in the FFT, and the signal is reconstructed using overlap/add of Hanning windows.**********************************************************************/#include "NoiseRemoval.h"#include "../Audacity.h"#include "../Envelope.h"#include "../FFT.h"#include "../WaveTrack.h"#include "../Prefs.h"#include "../Project.h"#include <math.h>#if defined(__WXMSW__) && !defined(__CYGWIN__)#include <float.h>#define finite(x) _finite(x)#endif#ifdef __MACOS9__#include <fp.h>#define finite(x) isfinite(x)#endif#include <wx/file.h>#include <wx/ffile.h>#include <wx/bitmap.h>#include <wx/brush.h>#include <wx/button.h>#include <wx/dcmemory.h>#include <wx/image.h>#include <wx/intl.h>#include <wx/msgdlg.h>#include <wx/sizer.h>#include <wx/statbox.h>#include <wx/stattext.h>#include "../AudacityApp.h"EffectNoiseRemoval::EffectNoiseRemoval(){ windowSize = 2048; int halfWindowSize = windowSize / 2; mNoiseGate = new float[windowSize]; sum = new float[windowSize]; sumsq = new float[windowSize]; profileCount = new int[windowSize]; smoothing = new float[windowSize]; mHasProfile = false; // These two are safe to do, even if not in CleanSpeechMode wxGetApp().SetCleanSpeechNoiseGate(mNoiseGate); wxGetApp().SetCleanSpeechNoiseGateExpectedCount(halfWindowSize * sizeof(float)); CleanSpeechMayReadNoisegate(); Init();}EffectNoiseRemoval::~EffectNoiseRemoval(){ delete [] mNoiseGate; delete [] sum; delete [] sumsq; delete [] profileCount; delete [] smoothing;}void EffectNoiseRemoval::CleanSpeechMayReadNoisegate(){ int halfWindowSize = windowSize / 2;//lda-131a always try to get noisegate.nrp if in CleanSpeechMode and it exists AudacityProject * project = GetActiveProject(); if (project == NULL) { int mode = gPrefs->Read(wxT("/Batch/CleanSpeechMode"), 0L); if (mode == 0) { return; } } // Try to open the file. wxString filename = FILENAME(wxT("noisegate.nrp")); // if file doesn't exist, return quietly. if( !wxFile::Exists( filename )) return; wxFFile noiseGateFile((const wxChar*)filename, (const wxChar*)wxT("rb")); bool flag = noiseGateFile.IsOpened(); if (flag != true) return; // Now get its data. int expectedCount = halfWindowSize * sizeof(float); int count = noiseGateFile.Read(mNoiseGate, expectedCount); noiseGateFile.Close(); if (count == expectedCount) { for (int i = halfWindowSize; i < windowSize; ++i) { mNoiseGate[i] = float(0.0); // only half filled by Read } mHasProfile = true; mDoProfile = false; }}void EffectNoiseRemoval::CleanSpeechMayWriteNoiseGate(){ AudacityProject * project = GetActiveProject(); if( !project || !project->GetCleanSpeechMode() ) return; wxFFile noiseGateFile((const wxChar*)FILENAME(wxT("noisegate.nrp")), (const wxChar*)wxT("wb")); bool flag = noiseGateFile.IsOpened(); if (flag == true) { int expectedCount = (windowSize / 2) * sizeof(float); // FIX-ME: Should we check return value on Write? noiseGateFile.Write(mNoiseGate, expectedCount); noiseGateFile.Close(); }}#define MAX_NOISE_LEVEL 30bool EffectNoiseRemoval::Init(){ mLevel = gPrefs->Read(wxT("/CsPresets/Noise_Level"), 3L); if ((mLevel < 0) || (mLevel > MAX_NOISE_LEVEL)) { // corrupted Prefs? mLevel = 0; //Off-skip gPrefs->Write(wxT("/CsPresets/Noise_Level"), mLevel); } return true;}bool EffectNoiseRemoval::CheckWhetherSkipEffect(){ bool rc = (mLevel == 0); return rc;}bool EffectNoiseRemoval::PromptUser(){ NoiseRemovalDialog dlog(this, mParent, -1, _("Noise Removal")); dlog.m_pSlider->SetValue(mLevel); dlog.mLevel = mLevel; if( !mHasProfile ) { CleanSpeechMayReadNoisegate(); } // We may want to twiddle the levels if we are setting // from an automation dialog, the only case in which we can // get here without any wavetracks. bool bAllowTwiddleSettings = (mWaveTracks==NULL); if (mHasProfile || bAllowTwiddleSettings ) { dlog.m_pButton_Preview->Enable(mWaveTracks != NULL); dlog.m_pButton_RemoveNoise->SetDefault(); dlog.m_pButton_RemoveNoise->SetFocus(); } else { dlog.m_pSlider->Enable(false); dlog.m_pButton_Preview->Enable(false); dlog.m_pButton_RemoveNoise->Enable(false); } dlog.CentreOnParent(); dlog.ShowModal(); if (dlog.GetReturnCode() == 0) { return false; } mLevel = dlog.m_pSlider->GetValue(); gPrefs->Write(wxT("/CsPresets/Noise_Level"), mLevel); //lda-131a make persistent mDoProfile = (dlog.GetReturnCode() == 1); return true;} bool EffectNoiseRemoval::TransferParameters( Shuttle & shuttle ){ shuttle.TransferInt(wxT("Level"),mLevel,1); return true;}bool EffectNoiseRemoval::Process(){ // If we are creating a profile, we don't care whether we have // one already. We just prepare the counters. if (mDoProfile) { for(int i=0; i<windowSize; i++) { sum[i] = float(0.0); sumsq[i] = float(0.0); profileCount[i] = 0; } } else { // We need a profile. if( !mHasProfile ) { CleanSpeechMayReadNoisegate(); } // If we still don't have a profile we have a problem. if( !mHasProfile) { wxMessageBox( _("Attempt to run Noise Removal without a noise profile\n.") ); return false; } } // This same code will both remove noise and // profile it, depending on 'mDoProfile' TrackListIterator iter(mWaveTracks); 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) { longSampleCount start = track->TimeToLongSamples(t0); longSampleCount end = track->TimeToLongSamples(t1); sampleCount len = (sampleCount)(end - start); if (!ProcessOne(count, track, start, len)){ return false; } } track = (WaveTrack *) iter.Next(); count++; } if (mDoProfile) { for(int i=0; i<=windowSize/2; i++) { //float stddev = sqrt(sumsq[i] - (sum[i]*sum[i])/profileCount[i]) // / profileCount[i]; mNoiseGate[i] = sum[i] / profileCount[i]; // average } CleanSpeechMayWriteNoiseGate(); mHasProfile = true; mDoProfile = false; } return true;}bool EffectNoiseRemoval::ProcessOne(int count, WaveTrack * track, longSampleCount start, sampleCount len){ bool retCode = true; sampleCount s = 0; sampleCount idealBlockLen = track->GetMaxBlockSize() * 4; if (idealBlockLen % windowSize != 0) idealBlockLen += (windowSize - (idealBlockLen % windowSize)); float *buffer = new float[idealBlockLen]; float *window1 = new float[windowSize]; float *window2 = new float[windowSize]; float *thisWindow = window1; float *lastWindow = window2; int i; for(i=0; i<windowSize; i++) { lastWindow[i] = 0; smoothing[i] = float(0.0); } while((s < len)&&((len-s)>(windowSize/2))) { sampleCount block = idealBlockLen; if (s + block > len) block = len - s; track->Get((samplePtr) buffer, floatSample, start + s, block); for(i=0; i<(block-windowSize/2); i+=windowSize/2) { int wcopy = windowSize; if (i + wcopy > block) wcopy = block - i; int j; for(j=0; j<wcopy; j++) thisWindow[j] = buffer[i+j]; for(j=wcopy; j<windowSize; j++) thisWindow[j] = 0; if (mDoProfile) GetProfile(windowSize, thisWindow); else { //TIDY-ME: could we just test mLevel=<0 in CheckWhetherSkipEffect? if (mLevel > 0) { // Skip NoiseRemoval if zero ... may apply for CleanChain RemoveNoise(windowSize, thisWindow); for(j=0; j<windowSize/2; j++) { buffer[i+j] = thisWindow[j] + lastWindow[windowSize/2 + j]; } } } float *tempP = thisWindow; thisWindow = lastWindow; lastWindow = tempP; } // Shift by half-a-window less than the block size we loaded // (so that the blocks properly overlap) block -= windowSize/2; if (!mDoProfile)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -