mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-16 08:34:10 +02:00
Remove EXPERIMENTAL_TRUNC_SILENCE #ifdefs since it is no longer experimental.
This commit is contained in:
parent
1af35d4168
commit
1ddee72498
@ -150,7 +150,4 @@
|
|||||||
//#define AUTOMATED_INPUT_LEVEL_ADJUSTMENT
|
//#define AUTOMATED_INPUT_LEVEL_ADJUSTMENT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// AWD: new Truncate Silence code
|
|
||||||
#define EXPERIMENTAL_TRUNC_SILENCE
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -119,342 +119,6 @@ bool EffectTruncSilence::TransferParameters( Shuttle & shuttle )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef EXPERIMENTAL_TRUNC_SILENCE
|
|
||||||
#define QUARTER_SECOND_MS 250
|
|
||||||
bool EffectTruncSilence::Process()
|
|
||||||
{
|
|
||||||
SelectedTrackListOfKindIterator iter(Track::Wave, mTracks);
|
|
||||||
WaveTrack *t;
|
|
||||||
double t0 = mT0;
|
|
||||||
double t1 = mT1;
|
|
||||||
int tndx;
|
|
||||||
int tcount = 0;
|
|
||||||
int fr;
|
|
||||||
|
|
||||||
// Init using first track
|
|
||||||
t = (WaveTrack *) iter.First();
|
|
||||||
double rate = t->GetRate();
|
|
||||||
sampleCount blockLen = t->GetMaxBlockSize();
|
|
||||||
|
|
||||||
// Get the left and right bounds for all tracks
|
|
||||||
while (t) {
|
|
||||||
// Make sure all tracks have the same sample rate
|
|
||||||
if (rate != t->GetRate()) {
|
|
||||||
wxMessageBox(_("All tracks must have the same sample rate"), _("Truncate Silence"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count the tracks
|
|
||||||
tcount++;
|
|
||||||
|
|
||||||
// Set the current bounds to whichever left marker is
|
|
||||||
// greater and whichever right marker is less
|
|
||||||
t0 = wxMax(mT0, t->GetStartTime());
|
|
||||||
t1 = wxMin(mT1, t->GetEndTime());
|
|
||||||
|
|
||||||
// Use the smallest block size of all the tracks
|
|
||||||
blockLen = wxMin(blockLen, t->GetMaxBlockSize());
|
|
||||||
|
|
||||||
// Iterate to the next track
|
|
||||||
t = (WaveTrack*) iter.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just a sanity check, really it should be much higher
|
|
||||||
if(blockLen < 4*mBlendFrameCount)
|
|
||||||
blockLen = 4*mBlendFrameCount;
|
|
||||||
|
|
||||||
// Transform the marker timepoints to samples
|
|
||||||
t = (WaveTrack *) iter.First();
|
|
||||||
sampleCount start = t->TimeToLongSamples(t0);
|
|
||||||
sampleCount end = t->TimeToLongSamples(t1);
|
|
||||||
|
|
||||||
// Bigger buffers reduce 'reset'
|
|
||||||
//blockLen *= 8;
|
|
||||||
// Stress-test the logic for cutting samples through block endpoints
|
|
||||||
//blockLen /= 8;
|
|
||||||
|
|
||||||
// Set thresholds
|
|
||||||
// We have a lower bound on the amount of silence we chop out at a time
|
|
||||||
// to avoid chopping up low frequency sounds. We're good down to 10Hz
|
|
||||||
// if we use 100ms.
|
|
||||||
const float minTruncMs = 1.0f;
|
|
||||||
double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex];
|
|
||||||
int truncInitialAllowedSilentSamples =
|
|
||||||
int((wxMax( mTruncInitialAllowedSilentMs, minTruncMs) * rate) / 1000.0);
|
|
||||||
int truncLongestAllowedSilentSamples =
|
|
||||||
int((wxMax( mTruncLongestAllowedSilentMs, minTruncMs) * rate) / 1000.0);
|
|
||||||
|
|
||||||
// Require at least 4 samples for lengths
|
|
||||||
if(truncInitialAllowedSilentSamples < 4)
|
|
||||||
truncInitialAllowedSilentSamples = 4;
|
|
||||||
if(truncLongestAllowedSilentSamples < 4)
|
|
||||||
truncLongestAllowedSilentSamples = 4;
|
|
||||||
|
|
||||||
// If the cross-fade is longer than the minimum length,
|
|
||||||
// then limit the cross-fade length to the minimum length
|
|
||||||
// This allows us to have reasonable cross-fade by default
|
|
||||||
// and still allow for 1ms minimum lengths
|
|
||||||
if(truncInitialAllowedSilentSamples < mBlendFrameCount)
|
|
||||||
mBlendFrameCount = truncInitialAllowedSilentSamples;
|
|
||||||
if(truncLongestAllowedSilentSamples < mBlendFrameCount)
|
|
||||||
mBlendFrameCount = truncLongestAllowedSilentSamples;
|
|
||||||
|
|
||||||
// For sake of efficiency, don't let blockLen be less than double the longest silent samples
|
|
||||||
// up until a sane limit of 1Meg samples
|
|
||||||
while((blockLen > 0) && (blockLen < truncLongestAllowedSilentSamples*2) && (blockLen < 1048576)) {
|
|
||||||
blockLen *= 2;
|
|
||||||
}
|
|
||||||
// Don't allow either value to be more than half of the block length
|
|
||||||
if(truncLongestAllowedSilentSamples > blockLen/2)
|
|
||||||
truncLongestAllowedSilentSamples = blockLen/2;
|
|
||||||
if(truncInitialAllowedSilentSamples > truncLongestAllowedSilentSamples)
|
|
||||||
truncInitialAllowedSilentSamples = truncLongestAllowedSilentSamples;
|
|
||||||
|
|
||||||
// We use the 'longest' variable as additive to the 'initial' variable
|
|
||||||
truncLongestAllowedSilentSamples -= truncInitialAllowedSilentSamples;
|
|
||||||
|
|
||||||
// Perform the crossfade half-way through the minimum removed silence duration
|
|
||||||
int rampInFrames = (truncInitialAllowedSilentSamples + mBlendFrameCount) / 2;
|
|
||||||
if(rampInFrames > truncInitialAllowedSilentSamples)
|
|
||||||
rampInFrames = truncInitialAllowedSilentSamples;
|
|
||||||
|
|
||||||
// Allocate buffers
|
|
||||||
float **buffer = new float*[tcount];
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
buffer[tndx] = new float[blockLen];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start processing
|
|
||||||
//Track::All is needed because this effect has clear functionality
|
|
||||||
this->CopyInputTracks(Track::All); // Set up mOutputTracks.
|
|
||||||
SelectedTrackListOfKindIterator iterOut(Track::Wave, mOutputTracks);
|
|
||||||
|
|
||||||
sampleCount index = start;
|
|
||||||
sampleCount outTrackOffset = start;
|
|
||||||
bool cancelled = false;
|
|
||||||
// Reset
|
|
||||||
bool ignoringFrames = false;
|
|
||||||
bool truncToMinimum = true; // Ignore the initial samples until we get above the noise floor
|
|
||||||
sampleCount consecutiveSilentFrames = 0;
|
|
||||||
sampleCount truncIndex = 0;
|
|
||||||
sampleCount i = 0;
|
|
||||||
sampleCount keep;
|
|
||||||
|
|
||||||
while (index < end) {
|
|
||||||
|
|
||||||
// Limit size of current block if we've reached the end
|
|
||||||
sampleCount count = blockLen-i;
|
|
||||||
if ((index + count) > end) {
|
|
||||||
count = end - index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill the buffers
|
|
||||||
tndx = 0;
|
|
||||||
t = (WaveTrack *) iter.First();
|
|
||||||
while (t) {
|
|
||||||
t->Get((samplePtr)(buffer[tndx++]+i), floatSample, index, count);
|
|
||||||
t = (WaveTrack *) iter.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shift over to account for samples remaining from prior block
|
|
||||||
sampleCount limit = count+i;
|
|
||||||
|
|
||||||
// Look for silences in current block
|
|
||||||
for ( ; i < limit; i++) {
|
|
||||||
|
|
||||||
// Is current frame in all tracks below threshold
|
|
||||||
bool below = true;
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
if (fabs(buffer[tndx][i]) >= truncDbSilenceThreshold) {
|
|
||||||
below = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make sure we cross-fade and output the last silence
|
|
||||||
// so we get a smooth transition into whatever follows the selected region
|
|
||||||
// Also set the 'truncToMinimum' flag so that the last silence is truncated to the minimum amount
|
|
||||||
if(below && ((index+i+1) == end)) {
|
|
||||||
below = false;
|
|
||||||
truncToMinimum = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count frame if it's below threshold
|
|
||||||
if (below) {
|
|
||||||
consecutiveSilentFrames++;
|
|
||||||
|
|
||||||
// Ignore this frame (equivalent to cutting it)
|
|
||||||
// otherwise, keep sample to be part of allowed silence
|
|
||||||
if (consecutiveSilentFrames > truncInitialAllowedSilentSamples) {
|
|
||||||
ignoringFrames = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (ignoringFrames == true) {
|
|
||||||
// Scale the consectiveSilentFrames so we keep a silence duration
|
|
||||||
// which is proportional to the original silence up to the limit
|
|
||||||
keep = consecutiveSilentFrames - truncInitialAllowedSilentSamples;
|
|
||||||
keep /= mSilenceCompressRatio;
|
|
||||||
|
|
||||||
// The first and last samples always get truncated to the minimum amount
|
|
||||||
if(truncToMinimum == true)
|
|
||||||
keep = 0;
|
|
||||||
if(keep > truncLongestAllowedSilentSamples)
|
|
||||||
keep = truncLongestAllowedSilentSamples;
|
|
||||||
if(keep < 0)
|
|
||||||
keep = 0;
|
|
||||||
|
|
||||||
// Compute the location of the cross-fade to be halfway through the silence
|
|
||||||
// with restriction to the samples we still have available to use
|
|
||||||
rampInFrames = (truncInitialAllowedSilentSamples - keep + mBlendFrameCount) / 2;
|
|
||||||
if(rampInFrames > truncInitialAllowedSilentSamples)
|
|
||||||
rampInFrames = truncInitialAllowedSilentSamples;
|
|
||||||
if(rampInFrames < mBlendFrameCount)
|
|
||||||
rampInFrames = mBlendFrameCount;
|
|
||||||
|
|
||||||
// Include the cross-fade samples in the count to make the loop logic easier
|
|
||||||
keep += rampInFrames;
|
|
||||||
truncIndex -= rampInFrames;
|
|
||||||
if(truncIndex < 0) {
|
|
||||||
// This happens when we have silence overlapping a block boundary
|
|
||||||
keep += truncIndex;
|
|
||||||
if(keep < 0)
|
|
||||||
keep = 0;
|
|
||||||
truncIndex = 0;
|
|
||||||
}
|
|
||||||
// back up for cross-fade
|
|
||||||
sampleCount curOffset = i - keep;
|
|
||||||
|
|
||||||
if(curOffset < 0) {
|
|
||||||
// This should never happen, but just in case...
|
|
||||||
keep += curOffset - rampInFrames;
|
|
||||||
if(keep < mBlendFrameCount)
|
|
||||||
keep = mBlendFrameCount;
|
|
||||||
curOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
// Cross fade the cut point
|
|
||||||
for (fr = 0; fr < mBlendFrameCount; fr++) {
|
|
||||||
buffer[tndx][truncIndex+fr] = ((mBlendFrameCount-fr)*buffer[tndx][truncIndex+fr] + fr*buffer[tndx][curOffset + fr]) / mBlendFrameCount;
|
|
||||||
}
|
|
||||||
// Append the 'keep' samples, if any
|
|
||||||
for ( ; fr < keep; fr++) {
|
|
||||||
buffer[tndx][truncIndex+fr] = buffer[tndx][curOffset + fr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
truncIndex += keep;
|
|
||||||
}
|
|
||||||
consecutiveSilentFrames = 0;
|
|
||||||
ignoringFrames = false;
|
|
||||||
truncToMinimum = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can get here either because > dbThreshold
|
|
||||||
// or silence duration isn't longer than allowed
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
buffer[tndx][truncIndex] = buffer[tndx][i];
|
|
||||||
}
|
|
||||||
truncIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update tracks if any samples were removed, now or before
|
|
||||||
if (outTrackOffset + truncIndex != index + limit) {
|
|
||||||
// Put updated sample back into output tracks.
|
|
||||||
tndx = 0;
|
|
||||||
t = (WaveTrack *) iterOut.First();
|
|
||||||
while (t) {
|
|
||||||
t->Set((samplePtr)buffer[tndx++], floatSample, outTrackOffset, truncIndex);
|
|
||||||
t = (WaveTrack *) iterOut.Next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If currently in a silent section, retain samples for the next pass
|
|
||||||
if(consecutiveSilentFrames > mBlendFrameCount) {
|
|
||||||
if (ignoringFrames == true) {
|
|
||||||
// Retain only what we need for truncating the silence
|
|
||||||
keep = consecutiveSilentFrames-truncInitialAllowedSilentSamples;
|
|
||||||
if(keep > (truncLongestAllowedSilentSamples+mBlendFrameCount))
|
|
||||||
keep = truncLongestAllowedSilentSamples+mBlendFrameCount;
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
// Cross fade the cut point
|
|
||||||
for(fr = 0; fr < mBlendFrameCount; fr++) {
|
|
||||||
buffer[tndx][fr] = ((mBlendFrameCount-fr)*buffer[tndx][truncIndex-mBlendFrameCount+fr]
|
|
||||||
+ fr*buffer[tndx][i-keep+fr]) / mBlendFrameCount;
|
|
||||||
}
|
|
||||||
for( ; fr < keep; fr++) {
|
|
||||||
buffer[tndx][fr] = buffer[tndx][i-keep+fr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update the output index, less what we are retaining for next time
|
|
||||||
outTrackOffset += truncIndex - mBlendFrameCount;
|
|
||||||
// Append the following buffer to the existing data
|
|
||||||
i = keep;
|
|
||||||
truncIndex = mBlendFrameCount;
|
|
||||||
} else {
|
|
||||||
// Retain the silent samples for the next buffer
|
|
||||||
keep = consecutiveSilentFrames;
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
for(fr=0 ; fr < keep; fr++) {
|
|
||||||
buffer[tndx][fr] = buffer[tndx][i-keep+fr];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update the output index, less what we are retaining for next time
|
|
||||||
outTrackOffset += truncIndex - keep;
|
|
||||||
// Append the following buffer to the existing data
|
|
||||||
i = keep;
|
|
||||||
truncIndex = keep;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Maintain output index
|
|
||||||
outTrackOffset += truncIndex;
|
|
||||||
// Reset the buffer pointers to the beginning
|
|
||||||
i = 0;
|
|
||||||
truncIndex = 0;
|
|
||||||
consecutiveSilentFrames = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update progress and bail if user cancelled
|
|
||||||
cancelled = TrackProgress(0, ((double)index / (double)end));
|
|
||||||
if (cancelled) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bump to next block
|
|
||||||
index += count;
|
|
||||||
}
|
|
||||||
|
|
||||||
AudacityProject *p = GetActiveProject();
|
|
||||||
if (!p)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Remove stale data at end of output tracks.
|
|
||||||
if (!cancelled && (outTrackOffset < end)) {
|
|
||||||
t = (WaveTrack *) iterOut.First();
|
|
||||||
while(t) {
|
|
||||||
t->Clear(outTrackOffset / rate, t1);
|
|
||||||
t = (WaveTrack *) iterOut.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
t1 = outTrackOffset / rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free buffers
|
|
||||||
for (tndx = 0; tndx < tcount; tndx++) {
|
|
||||||
delete [] buffer[tndx];
|
|
||||||
}
|
|
||||||
delete [] buffer;
|
|
||||||
|
|
||||||
mT0 = t0;
|
|
||||||
mT1 = t1;
|
|
||||||
|
|
||||||
this->ReplaceProcessedTracks(!cancelled);
|
|
||||||
return !cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // defined(EXPERIMENTAL_TRUNC_SILENCE)
|
|
||||||
|
|
||||||
// AWD: this is the new version!
|
|
||||||
bool EffectTruncSilence::Process()
|
bool EffectTruncSilence::Process()
|
||||||
{
|
{
|
||||||
// Typical fraction of total time taken by detection (better to guess low)
|
// Typical fraction of total time taken by detection (better to guess low)
|
||||||
@ -823,8 +487,6 @@ void EffectTruncSilence::Intersect(RegionList &dest, const RegionList &src)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // EXPERIMENTAL_TRUNC_SILENCE
|
|
||||||
|
|
||||||
void EffectTruncSilence::BlendFrames(float* buffer, int blendFrameCount, int leftIndex, int rightIndex)
|
void EffectTruncSilence::BlendFrames(float* buffer, int blendFrameCount, int leftIndex, int rightIndex)
|
||||||
{
|
{
|
||||||
float* bufOutput = &buffer[leftIndex];
|
float* bufOutput = &buffer[leftIndex];
|
||||||
|
@ -61,9 +61,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
//ToDo ... put BlendFrames in Effects, Project, or other class
|
//ToDo ... put BlendFrames in Effects, Project, or other class
|
||||||
void BlendFrames(float* buffer, int leftIndex, int rightIndex, int blendFrameCount);
|
void BlendFrames(float* buffer, int leftIndex, int rightIndex, int blendFrameCount);
|
||||||
#ifdef EXPERIMENTAL_TRUNC_SILENCE
|
|
||||||
void Intersect(RegionList &dest, const RegionList &src);
|
void Intersect(RegionList &dest, const RegionList &src);
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
sampleCount mBlendFrameCount;
|
sampleCount mBlendFrameCount;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user