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:
parent
68e2d00f9b
commit
ebf54adaab
@ -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
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user