1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-20 14:20:06 +02:00

Apply patch for bug 495, taking proper account of max, min and offsets of both tracks of a stereo pair.

This commit is contained in:
martynshaw99 2012-05-03 21:54:18 +00:00
parent 68e2d00f9b
commit ebf54adaab
2 changed files with 169 additions and 137 deletions

View File

@ -143,16 +143,16 @@ bool EffectNormalize::PromptUser()
bool EffectNormalize::Process() bool EffectNormalize::Process()
{ {
bool wasLinked = false; // set when a track has a linked (stereo) track if (mGain == false && mDC == false)
if (mGain == false &&
mDC == false)
return true; return true;
float ratio = pow(10.0,TrapDouble(mLevel, // same value used for all tracks
NORMALIZE_DB_MIN,
NORMALIZE_DB_MAX)/20.0);
//Iterate over each track //Iterate over each track
this->CopyInputTracks(); // Set up mOutputTracks. this->CopyInputTracks(); // Set up mOutputTracks.
bool bGoodResult = true; bool bGoodResult = true;
SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks); SelectedTrackListOfKindIterator iter(Track::Wave, mOutputTracks);
WaveTrack *track = (WaveTrack *) iter.First(); WaveTrack *track = (WaveTrack *) iter.First();
mCurTrackNum = 0; mCurTrackNum = 0;
@ -168,42 +168,54 @@ bool EffectNormalize::Process()
// Process only if the right marker is to the right of the left marker // Process only if the right marker is to the right of the left marker
if (mCurT1 > mCurT0) { if (mCurT1 > mCurT0) {
AnalyseTrack(track); // sets mOffset and offset-adjusted mMin and mMax
//Transform the marker timepoints to samples if(!track->GetLinked() || mStereoInd) { // mono or 'stereo tracks independently'
sampleCount start = track->TimeToLongSamples(mCurT0); float extent = wxMax(fabs(mMax), fabs(mMin));
sampleCount end = track->TimeToLongSamples(mCurT1); if (extent > 0)
mMult = ratio / extent;
//Get the track rate and samples else
mCurRate = track->GetRate(); mMult = 1.0;
mCurChannel = track->GetChannel(); if (!ProcessOne(track))
{
if(mStereoInd) // do stereo tracks independently (the easy way) bGoodResult = false;
track->GetMinMax(&mMin, &mMax, mCurT0, mCurT1); break;
}
}
else else
{ {
if(!wasLinked) // new mono track or first of a stereo pair // we have a linked stereo track
{ // so we need to find it's min, max and offset
track->GetMinMax(&mMin, &mMax, mCurT0, mCurT1); // as they are needed to calc the multiplier for both tracks
if(track->GetLinked()) float offset1 = mOffset; // remember ones from first track
{ float min1 = mMin;
wasLinked = true; // so we use these values for the next (linked) track float max1 = mMax;
track = (WaveTrack *) iter.Next(); // get the next one for the max/min track = (WaveTrack *) iter.Next(); // get the next one
float min, max; AnalyseTrack(track); // sets mOffset and offset-adjusted mMin and mMax
track->GetMinMax(&min, &max, mCurT0, mCurT1); float offset2 = mOffset; // ones for second track
mMin = min < mMin ? min : mMin; float min2 = mMin;
mMax = max > mMax ? max : mMax; float max2 = mMax;
track = (WaveTrack *) iter.Prev(); // back to the one we are on float extent = wxMax(fabs(min1), fabs(max1));
} extent = wxMax(extent, fabs(min2));
} extent = wxMax(extent, fabs(max2));
if (extent > 0)
mMult = ratio / extent; // we need to use this for both linked tracks
else else
wasLinked = false; // second of the stereo pair, next one is mono or first mMult = 1.0;
} track = (WaveTrack *) iter.Prev(); // go back to the first linked one
mOffset = offset1;
//ProcessOne() (implemented below) processes a single track if (!ProcessOne(track))
if (!ProcessOne(track, start, end)) {
{ bGoodResult = false;
bGoodResult = false; break;
break; }
mCurTrackNum++; // keeps progress bar correct
track = (WaveTrack *) iter.Next(); // go to the second linked one
mOffset = offset2;
if (!ProcessOne(track))
{
bGoodResult = false;
break;
}
} }
} }
@ -216,16 +228,40 @@ bool EffectNormalize::Process()
return bGoodResult; return bGoodResult;
} }
//ProcessOne() takes a track, transforms it to bunch of buffer-blocks, void EffectNormalize::AnalyseTrack(WaveTrack * track)
//and executes AnalyzeData, then ProcessData, on it... {
bool EffectNormalize::ProcessOne(WaveTrack * track, if(mGain)
sampleCount start, sampleCount end) track->GetMinMax(&mMin, &mMax, mCurT0, mCurT1); // set mMin, mMax
else
mMin = -1.0, mMax = 1.0; // sensible defaults?
if(mDC) {
AnalyseDC(track); // sets mOffset
mMin += mOffset;
mMax += mOffset;
}
else
mOffset = 0.0;
}
//AnalyseDC() takes a track, transforms it to bunch of buffer-blocks,
//and executes AnalyzeData on it...
// sets mOffset
bool EffectNormalize::AnalyseDC(WaveTrack * track)
{ {
bool rc = true; bool rc = true;
sampleCount s; sampleCount s;
mOffset = 0.0; // we might just return
if(!mDC) // don't do analysis if not doing dc removal
return(rc);
//Transform the marker timepoints to samples
sampleCount start = track->TimeToLongSamples(mCurT0);
sampleCount end = track->TimeToLongSamples(mCurT1);
//Get the length of the buffer (as double). len is //Get the length of the buffer (as double). len is
//used simple to calculate a progress meter, so it is easier //used simply to calculate a progress meter, so it is easier
//to make it a double now than it is to do it later //to make it a double now than it is to do it later
double len = (double)(end - start); double len = (double)(end - start);
@ -233,53 +269,95 @@ bool EffectNormalize::ProcessOne(WaveTrack * track,
//be shorter than the length of the track being processed. //be shorter than the length of the track being processed.
float *buffer = new float[track->GetMaxBlockSize()]; float *buffer = new float[track->GetMaxBlockSize()];
int pass; mSum = 0.0; // dc offset inits
mCount = 0;
for(pass=0; pass<2; pass++) //Go through the track one buffer at a time. s counts which
{ //sample the current buffer starts at.
if(pass==0 && !mDC) // we don't need an analysis pass if not doing dc removal s = start;
continue; while (s < end) {
if (pass==0) //Get a block of samples (smaller than the size of the buffer)
StartAnalysis(); // dc offset only. Max/min done in Process(). sampleCount block = track->GetBestBlockSize(s);
if (pass==1)
StartProcessing(); //Adjust the block size if it is the final block in the track
if (s + block > end)
block = end - s;
//Get the samples from the track and put them in the buffer
track->Get((samplePtr) buffer, floatSample, s, block);
//Process the buffer.
AnalyzeData(buffer, block);
//Increment s one blockfull of samples
s += block;
//Update the Progress meter
if (TrackProgress(mCurTrackNum,
((double)(s - start) / (len*2)))) {
rc = false; //lda .. break, not return, so that buffer is deleted
break;
}
}
//Go through the track one buffer at a time. s counts which //Clean up the buffer
//sample the current buffer starts at. delete[] buffer;
s = start;
while (s < end) {
//Get a block of samples (smaller than the size of the buffer)
sampleCount block = track->GetBestBlockSize(s);
//Adjust the block size if it is the final block in the track
if (s + block > end)
block = end - s;
//Get the samples from the track and put them in the buffer
track->Get((samplePtr) buffer, floatSample, s, block);
//Process the buffer.
if (pass==0) mOffset = (float)(-mSum / mCount); // calculate actual offset (amount that needs to be added on)
AnalyzeData(buffer, block);
if (pass==1) { //Return true because the effect processing succeeded ... unless cancelled
ProcessData(buffer, block); return rc;
}
//ProcessOne() takes a track, transforms it to bunch of buffer-blocks,
//and executes ProcessData, on it...
// uses mMult and mOffset to normalize a track. Needs to have them set before being called
bool EffectNormalize::ProcessOne(WaveTrack * track)
{
bool rc = true;
sampleCount s;
//Transform the marker timepoints to samples
sampleCount start = track->TimeToLongSamples(mCurT0);
sampleCount end = track->TimeToLongSamples(mCurT1);
//Copy the newly-changed samples back onto the track. //Get the length of the buffer (as double). len is
track->Set((samplePtr) buffer, floatSample, s, block); //used simply to calculate a progress meter, so it is easier
} //to make it a double now than it is to do it later
double len = (double)(end - start);
//Increment s one blockfull of samples
s += block; //Initiate a processing buffer. This buffer will (most likely)
//be shorter than the length of the track being processed.
float *buffer = new float[track->GetMaxBlockSize()];
//Go through the track one buffer at a time. s counts which
//sample the current buffer starts at.
s = start;
while (s < end) {
//Get a block of samples (smaller than the size of the buffer)
sampleCount block = track->GetBestBlockSize(s);
//Adjust the block size if it is the final block in the track
if (s + block > end)
block = end - s;
//Get the samples from the track and put them in the buffer
track->Get((samplePtr) buffer, floatSample, s, block);
//Process the buffer.
ProcessData(buffer, block);
//Copy the newly-changed samples back onto the track.
track->Set((samplePtr) buffer, floatSample, s, block);
//Update the Progress meter //Increment s one blockfull of samples
if (TrackProgress(mCurTrackNum, s += block;
((double)(pass)*0.5) + // Approximate each pass as half.
((double)(s - start) / (len*2)))) { //Update the Progress meter
rc = false; //lda .. break, not return, so that buffer is deleted if (TrackProgress(mCurTrackNum,
break; ((double)(s - start) / (len*2)))) {
} rc = false; //lda .. break, not return, so that buffer is deleted
break;
} }
} }
//Clean up the buffer //Clean up the buffer
@ -289,47 +367,18 @@ bool EffectNormalize::ProcessOne(WaveTrack * track,
return rc; return rc;
} }
void EffectNormalize::StartAnalysis()
{
mSum = 0.0;
mCount = 0;
}
void EffectNormalize::AnalyzeData(float *buffer, sampleCount len) void EffectNormalize::AnalyzeData(float *buffer, sampleCount len)
{ {
int i; sampleCount i;
for(i=0; i<len; i++) for(i=0; i<len; i++)
mSum += (double)buffer[i]; mSum += (double)buffer[i];
mCount += len; mCount += len;
} }
void EffectNormalize::StartProcessing()
{
mMult = 1.0;
mOffset = 0.0;
float ratio = pow(10.0,TrapDouble(mLevel,
NORMALIZE_DB_MIN,
NORMALIZE_DB_MAX)/20.0);
if (mDC) {
mOffset = (float)(-mSum / mCount);
}
if (mGain) {
float extent = fabs(mMax + mOffset);
if (fabs(mMin + mOffset) > extent)
extent = fabs(mMin + mOffset);
if (extent > 0)
mMult = ratio / extent;
}
}
void EffectNormalize::ProcessData(float *buffer, sampleCount len) void EffectNormalize::ProcessData(float *buffer, sampleCount len)
{ {
int i; sampleCount i;
for(i=0; i<len; i++) { for(i=0; i<len; i++) {
float adjFrame = (buffer[i] + mOffset) * mMult; float adjFrame = (buffer[i] + mOffset) * mMult;
@ -499,15 +548,3 @@ void NormalizeDialog::OnPreview(wxCommandEvent &event)
mEffect->mLevel = oldLevel; mEffect->mLevel = oldLevel;
mEffect->mStereoInd = oldStereoInd; mEffect->mStereoInd = oldStereoInd;
} }
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 3
// indent-tabs-mode: nil
// End:
//
// vim: et sts=3 sw=3
// arch-tag: 0e9ab1c7-3cb3-4864-8f30-876218bea476

View File

@ -60,13 +60,10 @@ class EffectNormalize: public Effect
virtual bool Process(); virtual bool Process();
private: private:
bool ProcessOne(WaveTrack * t, bool ProcessOne(WaveTrack * t);
sampleCount start, sampleCount end); virtual void AnalyseTrack(WaveTrack * track);
virtual void StartAnalysis();
virtual void AnalyzeData(float *buffer, sampleCount len); virtual void AnalyzeData(float *buffer, sampleCount len);
bool AnalyseDC(WaveTrack * track);
virtual void StartProcessing();
virtual void ProcessData(float *buffer, sampleCount len); virtual void ProcessData(float *buffer, sampleCount len);
bool mGain; bool mGain;
@ -75,16 +72,14 @@ class EffectNormalize: public Effect
bool mStereoInd; bool mStereoInd;
int mCurTrackNum; int mCurTrackNum;
double mCurRate;
double mCurT0; double mCurT0;
double mCurT1; double mCurT1;
int mCurChannel;
float mMult; float mMult;
float mOffset; float mOffset;
float mMin; float mMin;
float mMax; float mMax;
double mSum; double mSum;
int mCount; sampleCount mCount;
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------