1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-06-15 23:59:37 +02:00

Steve's changes to 'Truncate Silence' which compile for me, and the result seems sensible, but I have not done any 'code review' so committing this on trust. Very limited risk, one 'effect'.

This commit is contained in:
martynshaw99 2014-03-19 00:50:24 +00:00
parent 332c4ce04c
commit 1ffd419b11
2 changed files with 150 additions and 99 deletions

View File

@ -47,44 +47,41 @@ EffectTruncSilence::EffectTruncSilence()
bool EffectTruncSilence::Init()
{
mTruncInitialAllowedSilentMs = gPrefs->Read(wxT("/Effects/TruncateSilence/InitialAllowedSilentMs"), 200L);
if ((mTruncInitialAllowedSilentMs < 0) || (mTruncInitialAllowedSilentMs >= 9999999)) { // corrupted Prefs?
mTruncInitialAllowedSilentMs = 200L;
gPrefs->Write(wxT("/Effects/TruncateSilence/InitialAllowedSilentMs"), mTruncInitialAllowedSilentMs);
}
mTruncLongestAllowedSilentMs = gPrefs->Read(wxT("/Effects/TruncateSilence/LongestAllowedSilentMs"), 1000L);
if ((mTruncLongestAllowedSilentMs < 0) || (mTruncLongestAllowedSilentMs >= 9999999)) { // corrupted Prefs?
mTruncLongestAllowedSilentMs = 1000L;
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilentMs"), mTruncLongestAllowedSilentMs);
}
mTruncDbChoiceIndex = gPrefs->Read(wxT("/Effects/TruncateSilence/DbChoiceIndex"), 4L);
if ((mTruncDbChoiceIndex < 0) || (mTruncDbChoiceIndex >= Enums::NumDbChoices)) { // corrupted Prefs?
mTruncDbChoiceIndex = Enums::NumDbChoices - 1; // Off-Skip
gPrefs->Write(wxT("/Effects/TruncateSilence/DbChoiceIndex"), mTruncDbChoiceIndex);
mTruncLongestAllowedSilentMs = SKIP_EFFECT_MILLISECOND;
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilentMs"), mTruncLongestAllowedSilentMs);
mTruncDbChoiceIndex = 4L;
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilence"), 4L);
}
mProcessIndex = gPrefs->Read(wxT("/Effects/TruncateSilence/ProcessChoice"), 0L);
if ((mProcessIndex < 0) || (mProcessIndex > 1)) { // corrupted Prefs?
mProcessIndex = 0L;
gPrefs->Write(wxT("/Effects/TruncateSilence/ProcessChoice"), 0L);
}
gPrefs->Read(wxT("/Effects/TruncateSilence/InitialAllowedSilence"), &mInitialAllowedSilence, 0.5);
if ((mInitialAllowedSilence < 0.001) || (mInitialAllowedSilence > 10000.0)) { // corrupted Prefs?
mInitialAllowedSilence = 0.5;
gPrefs->Write(wxT("/Effects/TruncateSilence/InitialAllowedSilence"), 0.5);
}
gPrefs->Read(wxT("/Effects/TruncateSilence/LongestAllowedSilence"), &mTruncLongestAllowedSilence, 0.5);
if ((mTruncLongestAllowedSilence < 0.0) || (mTruncLongestAllowedSilence > 10000.0)) { // corrupted Prefs?
mTruncLongestAllowedSilence = 0.5;
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilence"), 0.5);
}
gPrefs->Read(wxT("/Effects/TruncateSilence/CompressPercent"), &mSilenceCompressPercent, 50.0);
if ((mSilenceCompressPercent < 0.0) || (mSilenceCompressPercent > 100.0)) { // corrupted Prefs?
mSilenceCompressPercent = 50.0;
gPrefs->Write(wxT("/Effects/TruncateSilence/CompressPercent"), 50.0);
}
// mBlendFrameCount is not currently used in dialog.
mBlendFrameCount = gPrefs->Read(wxT("/Effects/TruncateSilence/BlendFrameCount"), 100L);
if ((mBlendFrameCount < 0) || (mBlendFrameCount >= 5000)) { // corrupted Prefs?
mBlendFrameCount = 100;
gPrefs->Write(wxT("/Effects/TruncateSilence/BlendFrameCount"), 100);
}
mSilenceCompressRatio = 0.1*gPrefs->Read(wxT("/Effects/TruncateSilence/CompressRatio"), 40L);
if ((mSilenceCompressRatio < 1.0) || (mSilenceCompressRatio > 20.0)) { // corrupted Prefs?
mSilenceCompressRatio = 4.0;
gPrefs->Write(wxT("/Effects/TruncateSilence/CompressRatio"), 40L);
}
return gPrefs->Flush();
}
bool EffectTruncSilence::CheckWhetherSkipEffect()
{
// FIXME: This misses the final (-80 dB) option.
return ((mTruncDbChoiceIndex >= (Enums::NumDbChoices - 1))
|| (mTruncLongestAllowedSilentMs >= SKIP_EFFECT_MILLISECOND));
}
void EffectTruncSilence::End()
{
}
@ -99,21 +96,22 @@ bool EffectTruncSilence::PromptUser()
if (dlog.GetReturnCode() == wxID_CANCEL)
return false;
gPrefs->Write(wxT("/Effects/TruncateSilence/InitialAllowedSilentMs"), mTruncInitialAllowedSilentMs);
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilentMs"), mTruncLongestAllowedSilentMs);
gPrefs->Write(wxT("/Effects/TruncateSilence/DbChoiceIndex"), mTruncDbChoiceIndex);
gPrefs->Write(wxT("/Effects/TruncateSilence/CompressRatio"), (int)floor(10.0*mSilenceCompressRatio+0.5));
gPrefs->Write(wxT("/Effects/TruncateSilence/ProcessChoice"), mProcessIndex);
gPrefs->Write(wxT("/Effects/TruncateSilence/InitialAllowedSilence"), mInitialAllowedSilence);
gPrefs->Write(wxT("/Effects/TruncateSilence/LongestAllowedSilence"), mTruncLongestAllowedSilence);
gPrefs->Write(wxT("/Effects/TruncateSilence/CompressPercent"), mSilenceCompressPercent);
gPrefs->Flush();
return true;
}
bool EffectTruncSilence::TransferParameters( Shuttle & shuttle )
{
shuttle.TransferEnum(wxT("Db"), mTruncDbChoiceIndex, Enums::NumDbChoices, Enums::GetDbChoices());
shuttle.TransferInt(wxT("Minimum"), mTruncInitialAllowedSilentMs, 200);
shuttle.TransferInt(wxT("Duration"), mTruncLongestAllowedSilentMs, 1000);
shuttle.TransferDouble(wxT("Compress"), mSilenceCompressRatio, 4.0f);
shuttle.TransferInt(wxT("Action"), mProcessIndex, 0);
shuttle.TransferDouble(wxT("Minimum"), mInitialAllowedSilence, 0.5);
shuttle.TransferDouble(wxT("Truncate"), mTruncLongestAllowedSilence, 0.5);
shuttle.TransferDouble(wxT("Compress"), mSilenceCompressPercent, 50.0);
return true;
}
@ -127,7 +125,7 @@ bool EffectTruncSilence::Process()
// Lower bound on the amount of silence to find at a time -- this avoids
// detecting silence repeatedly in low-frequency sounds.
const float minTruncMs = 1.0f;
const double minTruncMs = 0.001;
double truncDbSilenceThreshold = Enums::Db2Signal[mTruncDbChoiceIndex];
// Master list of silent regions; it is responsible for deleting them.
@ -150,8 +148,8 @@ bool EffectTruncSilence::Process()
// Smallest silent region to detect in frames
sampleCount minSilenceFrames =
sampleCount((wxMax( mTruncInitialAllowedSilentMs, minTruncMs) *
wt->GetRate()) / 1000.0);
sampleCount(wxMax( mInitialAllowedSilence, minTruncMs) *
wt->GetRate());
//
// Scan the track for silences
@ -286,14 +284,27 @@ bool EffectTruncSilence::Process()
// Intersection may create regions smaller than allowed; ignore them.
// Allow one nanosecond extra for consistent results with exact milliseconds of allowed silence.
if ((r->end - r->start) < ((mTruncInitialAllowedSilentMs / 1000.0) - 0.000000001))
if ((r->end - r->start) < (mInitialAllowedSilence - 0.000000001))
continue;
// Find new silence length as requested
double inLength = r->end - r->start;
double outLength = wxMin(
mTruncInitialAllowedSilentMs / 1000.0 + (inLength - mTruncInitialAllowedSilentMs / 1000.0) / mSilenceCompressRatio,
mTruncLongestAllowedSilentMs / 1000.0);
double outLength;
switch (mProcessIndex) {
case 0:
outLength = mTruncLongestAllowedSilence;
break;
case 1:
outLength = mInitialAllowedSilence +
(inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0;
break;
default:
outLength = wxMin(mInitialAllowedSilence +
(inLength - mInitialAllowedSilence) * mSilenceCompressPercent / 100.0,
mTruncLongestAllowedSilence);
}
double cutLen = inLength - outLength;
totalCutLen += cutLen;
@ -503,15 +514,19 @@ void EffectTruncSilence::BlendFrames(float* buffer, int blendFrameCount, int lef
// TruncSilenceDialog
//----------------------------------------------------------------------------
#define ID_SHORTEST_SILENCE_TEXT 7000
#define ID_LONGEST_SILENCE_TEXT 7001
#define ID_COMPRESS_FACTOR 7002
enum {
ID_DETECT_SILENCE = 1001,
ID_TRUNCATION_DURATION,
ID_COMPRESS_FACTOR,
ID_PROCESS_CHOICE
};
BEGIN_EVENT_TABLE(TruncSilenceDialog, EffectDialog)
EVT_BUTTON(ID_EFFECT_PREVIEW, TruncSilenceDialog::OnPreview)
EVT_TEXT( ID_SHORTEST_SILENCE_TEXT, TruncSilenceDialog::OnDurationChange )
EVT_TEXT( ID_LONGEST_SILENCE_TEXT, TruncSilenceDialog::OnDurationChange )
EVT_TEXT( ID_COMPRESS_FACTOR, TruncSilenceDialog::OnDurationChange )
EVT_CHOICE(ID_PROCESS_CHOICE, TruncSilenceDialog::OnControlChange)
EVT_TEXT(ID_DETECT_SILENCE, TruncSilenceDialog::OnControlChange)
EVT_TEXT(ID_TRUNCATION_DURATION, TruncSilenceDialog::OnControlChange)
EVT_TEXT(ID_COMPRESS_FACTOR, TruncSilenceDialog::OnControlChange)
END_EVENT_TABLE()
TruncSilenceDialog::TruncSilenceDialog(EffectTruncSilence * effect,
@ -526,52 +541,61 @@ void TruncSilenceDialog::PopulateOrExchange(ShuttleGui & S)
{
S.AddSpace(0, 5);
S.StartStatic(_("Detection"));
S.StartHorizontalLay();
{
S.StartTwoColumn();
// Action choices
wxArrayString processChoices;
processChoices.Add(_("Truncate Detected Silence"));
processChoices.Add(_("Compress Excess Silence"));
S.Id(ID_PROCESS_CHOICE).TieChoice(wxT(""),
mEffect->mProcessIndex,
&processChoices);
S.SetSizeHints(-1, -1);
}
S.EndHorizontalLay();
S.StartStatic(_("Detect Silence"));
{
S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
{
// Threshold
wxArrayString choices(Enums::NumDbChoices, Enums::GetDbChoices());
S.TieChoice(_("Threshold for silence:"),
S.TieChoice(_("Level:"),
mEffect->mTruncDbChoiceIndex,
&choices);
S.SetSizeHints(-1, -1);
S.AddUnits(wxT("dB"));
// Ignored silence
S.Id(ID_DETECT_SILENCE).TieNumericTextBox(_("Duration:"),
mEffect->mInitialAllowedSilence,
12);
S.AddUnits(wxT("seconds"));
}
S.EndTwoColumn();
S.StartThreeColumn();
{
S.Id( ID_SHORTEST_SILENCE_TEXT ).TieNumericTextBox(_("Ignore silence less than:"),
mEffect->mTruncInitialAllowedSilentMs,
10);
S.AddUnits( _("milliseconds") );
}
S.EndThreeColumn();
S.EndMultiColumn();
}
S.EndStatic();
S.StartStatic(_("Truncation"));
S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
{
mTruncationMessage = S.AddVariableText(wxString::Format(_("For silences longer than %d milliseconds:"),
(gPrefs->Read(wxT("/Effects/TruncateSilence/InitialAllowedSilentMs"), 200L))));
// Truncation / Compression factor
S.Id( ID_TRUNCATION_DURATION ).TieNumericTextBox(_("Truncate to:"),
mEffect->mTruncLongestAllowedSilence,
12);
S.AddUnits(wxT("seconds"));
S.StartThreeColumn();
{
S.Id( ID_COMPRESS_FACTOR ).TieNumericTextBox(_("Compress silence by:"),
mEffect->mSilenceCompressRatio,
10);
/* i18n-hint: Leave as is unless your language has a different way to show ratios like 5:1*/
S.AddUnits( _(":1") );
// Truncation.
S.Id( ID_LONGEST_SILENCE_TEXT ).TieNumericTextBox(_("and then truncate to:"),
mEffect->mTruncLongestAllowedSilentMs,
10);
S.AddUnits( _("milliseconds.") );
}
S.EndThreeColumn();
S.Id( ID_COMPRESS_FACTOR ).TieNumericTextBox(_("Compress to:"),
mEffect->mSilenceCompressPercent,
12);
S.AddUnits(wxT("percent"));
}
S.EndStatic();
S.EndMultiColumn();
// Warnings
pWarning = S.AddVariableText( wxT("") );
UpdateUI();
}
void TruncSilenceDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
@ -580,7 +604,27 @@ void TruncSilenceDialog::OnPreview(wxCommandEvent & WXUNUSED(event))
mEffect->Preview();
}
void TruncSilenceDialog::OnDurationChange(wxCommandEvent & WXUNUSED(event))
void TruncSilenceDialog::UpdateUI()
{
wxWindow *pWnd;
switch (mEffect->mProcessIndex)
{
case 0:
pWnd = FindWindowById(ID_TRUNCATION_DURATION, this);
pWnd->Enable(true);
pWnd = FindWindowById(ID_COMPRESS_FACTOR, this);
pWnd->Enable(false);
break;
case 1:
pWnd = FindWindowById(ID_TRUNCATION_DURATION, this);
pWnd->Enable(false);
pWnd = FindWindowById(ID_COMPRESS_FACTOR, this);
pWnd->Enable(true);
}
}
void TruncSilenceDialog::OnControlChange(wxCommandEvent & WXUNUSED(event))
{
// We may even get called during the constructor.
// This test saves us from calling unsafe functions.
@ -588,23 +632,31 @@ void TruncSilenceDialog::OnDurationChange(wxCommandEvent & WXUNUSED(event))
return;
TransferDataFromWindow();
mTruncationMessage->SetLabel(wxString::Format(_("For silence longer than %d milliseconds:"),
(mEffect->mTruncInitialAllowedSilentMs)));
bool bOk = true;
wxString warningText;
if (mEffect->mTruncInitialAllowedSilentMs < 1.0f) {
if (mEffect->mInitialAllowedSilence < 0.001) {
bOk = false;
warningText = _("Ignored silence must be at least 1 millisecond");
warningText = _("Minimum detection duration: 0.001 seconds.");
} else if (mEffect->mInitialAllowedSilence > 10000.0) {
bOk = false;
warningText = _("Maximum detection duration: 10000 seconds.");
}
if (mEffect->mTruncLongestAllowedSilentMs < 1.0f) {
if ((mEffect->mTruncLongestAllowedSilence < 0.0f) && (mEffect->mProcessIndex != 1)) {
bOk = false;
warningText = _("Cannot truncate to less than 1 millisecond");
warningText = _("Cannot truncate to less than 0 seconds.");
} else if ((mEffect->mTruncLongestAllowedSilence > 10000.0) && (mEffect->mProcessIndex != 1)) {
bOk = false;
warningText = _("Maximum truncation length is 10000 seconds.");
}
if (mEffect->mSilenceCompressRatio < 1.0f) {
if ((mEffect->mSilenceCompressPercent < 0.0) && (mEffect->mProcessIndex != 0)) {
bOk = false;
warningText = _("Compression ratio must be at least 1:1");
warningText = _("Compression cannot be less than 0 percent.");
} else if ((mEffect->mSilenceCompressPercent >= 100.0) && (mEffect->mProcessIndex != 0)) {
bOk = false;
warningText = _("Compression must be less than 100 percent");
}
pWarning->SetLabel( bOk ? wxT("") : warningText);
@ -615,4 +667,5 @@ void TruncSilenceDialog::OnDurationChange(wxCommandEvent & WXUNUSED(event))
pWnd = FindWindowById( ID_EFFECT_PREVIEW, this );
pWnd->Enable( bOk );
UpdateUI();
}

View File

@ -52,7 +52,6 @@ public:
}
virtual bool Init();
virtual void End();
virtual bool CheckWhetherSkipEffect();
virtual bool PromptUser();
virtual bool TransferParameters( Shuttle & shuttle );
@ -64,11 +63,12 @@ public:
void Intersect(RegionList &dest, const RegionList &src);
private:
sampleCount mBlendFrameCount;
int mTruncInitialAllowedSilentMs;
int mTruncLongestAllowedSilentMs;
int mTruncDbChoiceIndex;
double mSilenceCompressRatio;
int mProcessIndex;
sampleCount mBlendFrameCount;
double mInitialAllowedSilence;
double mTruncLongestAllowedSilence;
double mSilenceCompressPercent;
friend class TruncSilenceDialog;
};
@ -86,18 +86,16 @@ public:
void PopulateOrExchange(ShuttleGui & S);
void OnPreview(wxCommandEvent & event);
void OnDurationChange(wxCommandEvent & event);
void OnControlChange(wxCommandEvent & event);
void UpdateUI();
private:
EffectTruncSilence *mEffect;
wxStaticText * pWarning;
wxStaticText * mTruncationMessage;
wxStaticText *mRatioLabel;
private:
DECLARE_EVENT_TABLE()
};
#endif