📄 equalization.cpp
字号:
/********************************************************************** Audacity: A Digital Audio Editor EffectEqualization.cpp Mitch Golden Vaughan Johnson (Preview) Applies an FFT of certain specific equalization curves, suitable for old recordings. Clone of the FFT Filter effect, see documentation there.**********************************************************************/#include "Equalization.h"#include "../Envelope.h"#include "../FFT.h"#include "../WaveTrack.h"#include "../widgets/Ruler.h"#include <wx/bitmap.h>#include <wx/button.h>#include <wx/msgdlg.h>#include <wx/brush.h>#include <wx/dcmemory.h>#include <wx/image.h>#include <wx/intl.h>#include <wx/radiobox.h>#include <wx/sizer.h>#include <wx/stattext.h>#include <wx/string.h>#include <wx/textdlg.h>#include <math.h>#define ID_BUTTON_PREVIEW 10004const float EffectEqualization::curvex[] = { 30., 31., 50., 63., 70., 100., 125., 200., 250., 300., 400., 500., 600., 700., 800., 900., 1000., 2000., 3000., 4000., 5000., 6000., 7000., 8000., 9000., 10000., 15000., 16000. };// Don't want to be warned about double->float precision loss here// when compiling with MSVC.#pragma warning( disable: 4305 )const float EffectEqualization::curvey[][nCurvePoints] = { { // flat 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }, { // amradio// 30 31 50 63 70 100 125 200 250 300 400 500 600 700 800 900 1000 2000 3000 4000 5000 6000 7000 8000 9000 10000 15000 16000. -20.,-20.,-20.,-20.,-20.,-20.,-16.,-12., -8., -4., 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -4., -8.,-12.,-16.,-20.0,-20.,-20.,-20.,-20., -20., -20.0 }, { // acoustic (see p 52) -20.0, -20.0, -20.0, 5.0, 4.4, 3.3, 2.5, 1.7, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.5, -2.5, -3.3, -4.0, -4.5, -5.0, -10.0, -15.0, -20.0, -20.0 }, { // NAB 20.0, 20.0, 16.0, 15.6, 15.5, 13.8, 12.0, 8.0, 6.2, 5.0, 3.0, 1.7, 1.0, 0.0, -0.5, -1.0, -1.3, -4.2, -6.5, -8.5, -10.2, -12.0, -13.0, -14.0, -15.0, -16.0, -20.0, -20.0 }, { // LP 13.5, 13.2, 13.0, 12.8, 12.5, 11.0, 10.5, 8.0, 7.0, 6.0, 3.5, 2.5, 1.5, 1.0, 0.5, -0.5, -1.0, -3.5, -6.0, -8.0, -10.0, -11.5, -12.5, -13.5, -14.5, -16.0, -21.2, -22.0 }, { // AES 22.5, 22.5, 18.0, 16.0, 15.0, 12.0, 10.0, 6.5, 5.2, 4.5, 3.0, 2.0, 1.5, 1.0, 0.5, 0.0, 0.0, -2.2, -4.0, -5.5, -6.7, -8.0, -9.0, -10.0, -11.0, -12.0, -15.5, -16.0 }, { // Decca FFRR Micro 14.0, 14.0, 14.0, 13.8, 13.5, 12.5, 11.5, 8.5, 7.2, 6.0, 4.0, 2.5, 1.5, 1.0, 0.5, 0.0, 0.0, -1.5, -3.0, -4.5, -6.0, -7.0, -8.0, -8.5, -9.0, -10.0, -12.6, -13.0 }, { // Decca FFRR 78 22.0, 21.5, 14.0, 11.2, 9.8, 6.0, 2,0, 1.5, 1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 -0.5, -1.0, -2.0, -2.5, -3.5, -4.0, -4.5, -7.0, -7.5 }, { // RIAA 18.6, 18.5, 17.0, 16.0, 15.3, 13.1, 11.8, 8.2, 7.9, 5.5, 3.8, 2.7, 2.0, 1.2, 1.0, 0.5, 0.0, -2.6, -4.8, -6.6, -8.2, -9.6, -10.9, -11.9, -12.9, -13.6, -17.2, -18.0 }, { // Col 78 16.0, 16.0, 16.0, 14.0, 12.5, 10.0, 8.5, 5.0, 4.0, 3.0, 2.0, 1.0, 0.5, 0.2, 0.0, -0.5, -1.0, -3.5, -6.0, -8.0, -10.0, -11.5, -12.5, -13.5, -14.5, -16.0, -21.2, -22.0 }, { // Decca FFRR LP 17.5, 17.2, 14.0, 12.0, 11.5, 9.0, 7.5, 5.0, 4.0, 3.0, 2.0, 1.5, 1.0, 0.7, 0.2, 0.0, 0.0, -4.0, -6.7, -8.5, -10.0, -11.0, -12.0, -13.0, -13.2, -14.0, -16.0, -16.0 }, { // EMI 78 14.0, 14.0, 14.0, 12.0, 11.0, 8.0, 7.0, 4.0, 3.0, 2.0, 1.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -5.0, -5.0 }, { // RCA Victor 1938 24.0, 24.0, 24.0, 21.8, 20.0, 16.0, 13.0, 9.0, 7.5, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0, 0.5, 0.0, -2.5, -5.0, -6.5, -7.5, -8.0, -7.7, -7.5, -7.5, -7.5, -7.5, -7.5 }, { // RCA Victor 1947 24.0, 24.0, 24.0, 21.8, 20.0, 16.0, 13.0, 9.0, 7.5, 6.0, 4.0, 3.0, 2.0, 1.5, 1.0, 0.5, 0.0, -2.5, -5.0, -6.5, -8.0, -10.0, -11.5, -12.0, -12.5, -12.5, -12.5, -12.5 } };#pragma warning( default: 4305 )const wxChar * EffectEqualization::curveNames[] = { wxT("flat"), wxT("amradio"), wxT("acoustic"), wxT("NAB"), wxT("Columbia LP"), wxT("AES"), wxT("Decca FFRR Micro"), wxT("Decca FFRR 78"), wxT("RIAA"), wxT("Columbia 78"), wxT("Decca FFRR LP"), wxT("EMI 78"), wxT("RCA Victor 1938"), wxT("RCA Victor 1947") };EffectEqualization::EffectEqualization(){ mFilterFunc = new float[windowSize];}EffectEqualization::~EffectEqualization(){ if(mFilterFunc) delete[] mFilterFunc; mFilterFunc = NULL;}bool EffectEqualization::PromptUser(){ TrackListIterator iter(mWaveTracks); WaveTrack *t = (WaveTrack *) iter.First(); float hiFreq = ((float)(t->GetRate())/2.); EqualizationDialog dlog(this, ((double)loFreqI), hiFreq, mFilterFunc, windowSize, mParent, -1, _("Equalization")); dlog.CentreOnParent(); dlog.ShowModal(); if (!dlog.GetReturnCode()) return false; return true;}bool EffectEqualization::TransferParameters( Shuttle & shuttle ){ //TODO: Lots of parameters...// shuttle.TransferInt("",,0); return true;}bool EffectEqualization::Process(){ 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++; } return true;}bool EffectEqualization::ProcessOne(int count, WaveTrack * t, sampleCount start, sampleCount len){ sampleCount s = start; sampleCount idealBlockLen = t->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; sampleCount originalLen = len; int i; for(i=0; i<windowSize; i++) lastWindow[i] = 0; TrackProgress(count, 0.); while(len) { sampleCount block = idealBlockLen; if (block > len) block = len; t->Get((samplePtr)buffer, floatSample, s, block); int j;/* Martyn Shaw set this code back like Filter.cppas the 'lastWindow' was not getting set correctly and one morewindow was being taken from the current block than it should have been */ for(i=0; i<(block-windowSize/2); i+=windowSize/2) { int wcopy = windowSize; if (i + wcopy > block) wcopy = block - i; for(j=0; j<wcopy; j++) thisWindow[j] = buffer[i+j]; for(j=wcopy; j<windowSize; j++) thisWindow[j] = 0.; Filter(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; } if (len > block && len > windowSize/2) block -= windowSize/2; t->Set((samplePtr)buffer, floatSample, s, block); len -= block; s += block; TrackProgress(count, (s-start)/(double)originalLen); } delete[] buffer; delete[] window1; delete[] window2; return true;}void EffectEqualization::Filter(sampleCount len, float *buffer){ float *inr = new float[len]; float *ini = new float[len]; float *outr = new float[len]; float *outi = new float[len]; int i; for(i=0; i<len; i++) inr[i] = buffer[i]; // Apply window and FFT WindowFunc(3, len, inr); // Hanning window FFT(len, false, inr, NULL, outr, outi); // Apply filter int half = len/2; for(i=0; i<=half; i++) { int j = len - i; outr[i] = outr[i]*mFilterFunc[i]; outi[i] = outi[i]*mFilterFunc[i]; if (i!=0 && i!=len/2) { outr[j] = outr[j]*mFilterFunc[i]; outi[j] = outi[j]*mFilterFunc[i]; } } // Inverse FFT and normalization FFT(len, true, outr, outi, inr, ini); for(i=0; i<len; i++) buffer[i] = float(inr[i]); delete[] inr; delete[] ini; delete[] outr; delete[] outi;}//----------------------------------------------------------------------------// EqualizationPanel//----------------------------------------------------------------------------BEGIN_EVENT_TABLE(EqualizationPanel, wxPanel) EVT_PAINT(EqualizationPanel::OnPaint) EVT_MOUSE_EVENTS(EqualizationPanel::OnMouseEvent)END_EVENT_TABLE()EqualizationPanel::EqualizationPanel( double loFreq, double hiFreq, Envelope *env, wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size): wxPanel(parent, id, pos, size){ mBitmap = NULL; mWidth = 0; mHeight = 0; mLoFreq = loFreq; mHiFreq = hiFreq; mEnvelope = env; mEnvelope->Flatten(0.5); mEnvelope->Mirror(false); mEnvelope->SetTrackLen(1.0); SetSizeHints(100, 80);}EqualizationPanel::~EqualizationPanel(){ if(mBitmap) delete mBitmap; mBitmap = NULL;}void EqualizationPanel::OnPaint(wxPaintEvent & evt){ wxPaintDC dc(this); int width, height; GetSize(&width, &height); if (!mBitmap || mWidth!=width || mHeight!=height) { if (mBitmap) delete mBitmap; mWidth = width; mHeight = height; mBitmap = new wxBitmap(mWidth, mHeight); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -