📄 avccompressor.cpp
字号:
/********************************************************************** Audacity: A Digital Audio Editor AvcCompressor.cpp Vincent A. Busam**********************************************************************//* TODO List: 1. Add graph shows curve specified by grid, keep it up to date, allow setting of grid points by moving points in grid. 2. Better help 3. Radio button selection so Adjustment Settings can be times instead of samples. 4. Radio button selection so Amplification Settings can be db instead of raw values. 5. Save settings by name 6. Remove "help" text in window when Audacity help available.*/#include <math.h>#include <wx/defs.h>#include <wx/msgdlg.h>#include <wx/textdlg.h>#include <wx/dcmemory.h>#include "../WaveTrack.h"#include "../Envelope.h"#include "../widgets/Ruler.h"#include "../Prefs.h"// Including the following cpp file is quite unorthodox, but it gives the opportunity to// use iAVC's capability of generating inline code for the important methods. We// can't trust compilers to generated inline code, even when the inline keyword is// used.#ifdef _WINDOWS // kludge for Audacity since we don't really have MS Windows #define max(a,b) ( (a<b)?b:a )#endif//!!!!!!!!!!!!!!!!!!!!!!!!! I M P O R T A N T !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!// IMPORTANT: This define determines if iAVC generates in line code.//#define IAVC_INLINE // use inline code for get and put of samples#include "AvcCompressor.h"#include "../../lib-src/iAVC/iAVCsamples.h"#include "../../lib-src/iAVC/iAVC.cpp"#define ADJWIN_DEFAULT DEFAULT_ADJUSTER_WINDOW_SIZE#define ADJWIN_MIN 1000#define ADJWIN_MAX 10000#define DELAY_DEFAULT DEFAULT_MINIMUM_SAMPLES_BEFORE_SWITCH#define DELAY_MIN 0#define DELAY_MAX 5000#define CHANGE_DEFAULT DEFAULT_MINIMUM_SAMPLES_BEFORE_SWITCH#define CHANGE_MIN 1000#define CHANGE_MAX 5000#define MINPCT_DEFAULT DEFAULT_MAX_PCT_CHANGE_AT_ONCE#define MINPCT_MIN 5#define MINPCT_MAX 50EffectAvcCompressor::EffectAvcCompressor(): mpBufferList ( NULL ), mpBufferPrevious ( NULL ), mnDelay ( 0 ), mpDialog ( NULL ){}EffectAvcCompressor::~EffectAvcCompressor(){ if ( mpDialog != NULL ) delete mpDialog;}wxString EffectAvcCompressor::GetEffectDescription() { return "Applied effect: AVC"; // XXX: temporary // Note: This is useful only after values have been set. // FIX-ME: Compile error (cannot pass wxString to Format). //return wxString::Format(_("Applied effect: %s"), // this->GetEffectDescription()); //old //return wxString::Format("Applied effect: %s change window = %d samples", //(const char *)(this->GetEffectName()), mnChangeWindow); } inlinevoid EffectAvcCompressor::OutputSample ( IAVCSAMPLETYPE left, IAVCSAMPLETYPE right ){ if ( mpBufferList->mnNext >= mpBufferList->mnLen ) { // have filled up this buffer, move to next iAVCBufferList * pOld = mpBufferList; mpBufferList = mpBufferList->mpNext; delete pOld; } if ( mpBufferList == NULL ) return; // set the output sample values ((IAVCSAMPLETYPE*)mpBufferList->mpLeftBuffer)[mpBufferList->mnNext] = left; if ( mpBufferList->mpRightBuffer ) ((IAVCSAMPLETYPE*)mpBufferList->mpRightBuffer)[mpBufferList->mnNext] = right; ++mpBufferList->mnNext;}bool EffectAvcCompressor::PromptUser(){ if ( mpDialog == NULL ) // reuse dialog so we keep user changes to values mpDialog = new AvcCompressorDialog(mParent, -1, _("Automatic Volume Control")); mpDialog->CentreOnParent(); mpDialog->ShowModal(); if (!mpDialog->GetReturnCode()) return false; mAutoVolCtrl.Reset(); // reset control before setting values // Set parameters for iAVC class unsigned short int *nTransform = new unsigned short int [ MULTIPLY_PCT_ARRAY_SIZE ]; mnChangeWindow=mpDialog->GetChangeWindow(); mpDialog->GetTransformArray(nTransform); if ( mAutoVolCtrl.SetSampleWindowSize(mpDialog->GetAdjusterWindow()+mnChangeWindow, mpDialog->GetAdjusterWindow(), 0) == false || mAutoVolCtrl.SetMinSamplesBeforeSwitch(mnChangeWindow) == false ) { wxMessageBox("Error setting parameters for automatic volume control."); return false; } mAutoVolCtrl.SetMaxPctChangeAtOnce(mpDialog->GetMinimumPercent()); mAutoVolCtrl.SetMultipliers(nTransform); mAutoVolCtrl.SetNumberTracks(mnTracks); mnDelay = mpDialog->GetDelay(); delete [] nTransform; return true;}bool EffectAvcCompressor::TransferParameters( Shuttle & shuttle ){ wxASSERT( false );// Not yet implemented.// shuttle.TransferInt("",,0); return true;}bool EffectAvcCompressor::Init() // invoked before PromptUser{ if ( EffectSimplePairedTwoTrack<IAVCSAMPLETYPE,AVCCOMPSAMPLETYPE>::Init() == false ) return false; return true;}bool EffectAvcCompressor::ProcessSimplePairedTwoTrack(/*IAVCSAMPLETYPE*/ void *bufferLeft, /*IAVCSAMPLETYPE*/ void *bufferRight, // may be 0 sampleCount len){ // build new iAVCBufferList node iAVCBufferList * pBufferNode = new iAVCBufferList; if ( mpBufferPrevious != NULL ) mpBufferPrevious->mpNext = pBufferNode; // link to end of list else mpBufferList = pBufferNode; // have first node in list mpBufferPrevious = pBufferNode; // this node now the last added to list pBufferNode->mpNext = NULL; pBufferNode->mpLeftBuffer = bufferLeft; pBufferNode->mpRightBuffer = bufferRight; pBufferNode->mnLen = len; pBufferNode->mnNext = 0; // process samples in these buffer(s) IAVCSAMPLETYPE* typedBufferLeft = (IAVCSAMPLETYPE*)bufferLeft; IAVCSAMPLETYPE* typedBufferRight = (IAVCSAMPLETYPE*)bufferRight; sampleCount i; IAVCSAMPLETYPE left; IAVCSAMPLETYPE right = 0; for ( i = 0 ; i < len ; ++i ) { left = typedBufferLeft[i]; if ( typedBufferRight ) right = typedBufferRight[i]; #ifdef IAVC_INLINE // use inline SetNextSample() #define IAVC_SETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE // use inline GetNextSample() if ( mnDelay <= 0 ) { // get a value only if past desired delay #define IAVC_GETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE } #else // call SetNextSample() and GetNextSample() mAutoVolCtrl.SetNextSample(left, right); if ( mnDelay <= 0 ) { // get a value only if past desired delay mAutoVolCtrl.GetNextSample(left, right); } #endif if ( mnDelay <= 0 ) { // get a value only if past desired delay OutputSample ( left, right ); typedBufferLeft[i] = left; if ( typedBufferRight ) typedBufferRight[i] = right; } else { // count down the delay amount --mnDelay; } } return true;}void EffectAvcCompressor::End(){ IAVCSAMPLETYPE left; IAVCSAMPLETYPE right = 0; // We now need to output any samples still waiting because while ( mpBufferList != NULL ) { #ifdef IAVC_INLINE // use inline GetNextSample() #define IAVC_GETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE #else // call GetNextSample() mAutoVolCtrl.GetNextSample(left, right); #endif OutputSample ( left, right ); } mpBufferPrevious = NULL; EffectSimplePairedTwoTrack<IAVCSAMPLETYPE,AVCCOMPSAMPLETYPE>::End();}// WDR: class implementations//----------------------------------------------------------------------------// AvcCompressorDialog//----------------------------------------------------------------------------#define PREF_ADJWIN "/Effect/AVC/user1/adjwin"#define PREF_DELAY "/Effect/AVC/user1/delay"#define PREF_CHANGE "/Effect/AVC/user1/change"#define PREF_MINPCT "/Effect/AVC/user1/minpct"#define PREF_ENABLE "/Effect/AVC/user1/%d/enable"#define PREF_HORIZ "/Effect/AVC/user1/%d/horiz"#define PREV_VERT "/Effect/AVC/user1/%d/vert"// WDR: event table for AvcCompressorDialogBEGIN_EVENT_TABLE(AvcCompressorDialog,wxDialog) EVT_BUTTON( wxID_OK, AvcCompressorDialog::OnOK ) EVT_BUTTON( wxID_CANCEL, AvcCompressorDialog::OnCancel ) EVT_BUTTON( ID_RESTORE_DEFAULTS, AvcCompressorDialog::OnRestoreDefaults ) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+1, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+2, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+3, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+4, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+5, AvcCompressorDialog::OnCheckBox)END_EVENT_TABLE()AvcCompressorDialog::AvcCompressorDialog(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style ) : wxDialog( parent, id, title, position, size, style ), mctlAdjWin ( 0 ), mctlDelay ( 0 ), mctlChangeWin ( 0 ), mctlMinPct ( 0 ){ for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mctlCheckBoxes[i] = 0; mctlXAxis[i] = 0; mctlYAxis[i] = 0; } MakeAvcCompressorDialog( this, TRUE ); // First make sure all value initialized, especially horiz and vert first & last values wxCommandEvent event; OnRestoreDefaults(event); // Now read in from registry ReadPrefs();}AvcCompressorDialog::~AvcCompressorDialog(){ // zero out pointers in case reference counts being used mctlAdjWin = 0; mctlDelay = 0; mctlChangeWin = 0; mctlMinPct = 0; for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mctlCheckBoxes[i] = 0; mctlXAxis[i] = 0; mctlYAxis[i] = 0; }}// figure out Y value for each possible X valuevoid AvcCompressorDialog::GetTransformArray( unsigned short int nTransform[MULTIPLY_PCT_ARRAY_SIZE] ){ long iCurPoint = 0; // index to mnXAxis and mnYAxis long iPrevPoint= 0; // index to mnXAxis and mnYAxis long iMultiply = 1; // iMultiply and iDivide used to calculate fractional slopes long iDivide = 1; long iBias = 0; // keeps values from decreasing nTransform [ 0 ] = 0; for ( long i = 0 ; i < MULTIPLY_PCT_ARRAY_SIZE - 1 ; ++i ) { if ( i == mnXAxis [ iCurPoint ] && iCurPoint < NUM_CURVE_POINTS - 1 ) { // time to move to next point iPrevPoint = iCurPoint; // find next checked point while ( mctlCheckBoxes[++iCurPoint]->GetValue() == false) ; // last box guaranteed to be checked // Recalculate bias based on what would be calculated with old values and // what would be calculated with new values. long iOld = i * iMultiply / iDivide + iBias; iMultiply = mnYAxis [ iCurPoint ] - mnYAxis [ iPrevPoint ]; iDivide = mnXAxis [ iCurPoint ] - mnXAxis [ iPrevPoint ]; iBias = iOld - ( i * iMultiply / iDivide ); } nTransform [ i ] = (unsigned short int) ( i * iMultiply / iDivide + iBias ); } // set boundary case for loudest sound nTransform [ MULTIPLY_PCT_ARRAY_SIZE - 1 ] = MULTIPLY_PCT_ARRAY_SIZE - 1;}bool AvcCompressorDialog::LongRangeCheck ( wxWindow *window, const long nValue, const long nMin, const long nMax ){ if ( nValue < nMin || nValue > nMax ) { // value out of range if ( !wxValidator::IsSilent() ) wxBell(); wxString strTemp; strTemp.Printf ( _("Value must be from %d to %d."), nMin, nMax ); wxMessageBox(strTemp, _("Validation error"), wxOK | wxICON_EXCLAMATION, GetParent() ); if ( window ) window->SetFocus(); return false; } return true;}// WDR: handler implementations for AvcCompressorDialog
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -