27#include <wx/checkbox.h>
33#include "../ProjectSettings.h"
34#include "../ShuttleGui.h"
35#include "../SyncLock.h"
36#include "../WaveTrack.h"
37#include "../widgets/valnum.h"
38#include "../widgets/AudacityMessageBox.h"
66static inline double enumToDB(
int val ) {
return -( 5.0 * val + 20.0 ); }
77 {
XO(
"Truncate Detected Silence") },
78 {
XO(
"Compress Excess Silence") }
107{
XO(
"Truncate Silence") };
118 Parameters().Reset(*
this);
120 SetLinearEffectFlag(
false);
146 return XO(
"Automatically reduces the length of passages where the volume is below a specified level");
151 return L
"Truncate_Silence";
169 double myThreshold {};
170 bool newParams = [&] {
207 double inputLength =
mT1 -
mT0;
208 double minInputLength = inputLength;
218 for (
auto wt :
inputTracks()->Selected< const WaveTrack >()) {
221 auto index = wt->TimeToLongSamples(
mT0);
224 Analyze(silences, trackSilences, wt, &silentFrame, &index, whichTrack, &inputLength, &minInputLength);
247 unsigned nGroups = 0;
250 const bool syncLock =
settings.IsSyncLocked();
254 for (
auto track :
inputTracks()->SelectedLeaders< const WaveTrack >() ) {
260 - [&](
const Track *pTrack){
261 return channels.contains(pTrack); };
265"When truncating independently, there may only be one selected audio track in each Sync-Locked Track Group.") );
294 Track *groupFirst, *groupLast;
297 groupFirst = *trackRange.begin();
298 groupLast = *trackRange.rbegin();
304 double totalCutLen = 0.0;
305 if (!
DoRemoval(silences, iGroup, nGroups, groupFirst, groupLast, totalCutLen))
307 newT1 = std::max(newT1,
mT1 - totalCutLen);
331 double totalCutLen = 0.0;
333 *trackRange.begin(), *trackRange.rbegin(), totalCutLen)) {
344 const Track *firstTrack,
const Track *lastTrack)
353 .StartingWith( firstTrack ).EndingAfter( lastTrack ) )
356 auto minSilenceFrames =
364 auto index = wt->TimeToLongSamples(
mT0);
368 bool cancelled = !(
Analyze(silences, trackSilences, wt, &silentFrame, &index, whichTrack));
377 if (silentFrame >= minSilenceFrames)
380 trackSilences.push_back(
Region(
381 wt->LongSamplesToTime(index - silentFrame),
382 wt->LongSamplesToTime(index)
395(
const RegionList &silences,
unsigned iGroup,
unsigned nGroups,
Track *firstTrack,
Track *lastTrack,
405 RegionList::const_reverse_iterator rit;
406 for (rit = silences.rbegin(); rit != silences.rend(); ++rit)
408 const Region ®ion = *rit;
409 const Region *
const r = ®ion;
413 (1 -
detectFrac) * (iGroup + whichReg /
double(silences.size())) / nGroups;
426 double inLength = r->
end - r->
start;
444 const double cutLen = std::max(0.0, inLength - outLength);
449 totalCutLen += cutLen;
451 double cutStart = (r->
start + r->
end - cutLen) / 2;
452 double cutEnd = cutStart + cutLen;
454 .StartingWith(firstTrack).EndingAfter(lastTrack)
456 - [&](
const Track *pTrack) {
return
458 pTrack->GetEndTime() < r->
start;
477 Floats buf1{ blendFrames };
478 Floats buf2{ blendFrames };
482 wt->
GetFloats(buf1.get(), t1, blendFrames);
483 wt->
GetFloats(buf2.get(), t2, blendFrames);
485 for (
decltype(blendFrames) i = 0; i < blendFrames; ++i)
487 buf1[i] = ((blendFrames-i) * buf1[i] + i * buf2[i]) /
492 wt->
Clear(cutStart, cutEnd);
499 t->SyncLockAdjust(cutEnd, cutStart);
514 double* inputLength ,
515 double* minInputLength )
const
526 double previewLength;
527 gPrefs->Read(wxT(
"/AudioIO/EffectsPreviewLen"), &previewLength, 6.0);
532 RegionList::iterator rit(silenceList.begin());
535 Floats buffer{ blockLen };
538 while (*index <
end) {
539 if (inputLength && ((outLength >= previewLen) || (*index - start > wt->
TimeToLongSamples(*minInputLength)))) {
540 *inputLength = std::min<double>(*inputLength, *minInputLength);
541 if (outLength >= previewLen) {
542 *minInputLength = *inputLength;
551 (*index - start).as_double() /
552 (
end - start).as_double()) /
561 for ( ; rit != silenceList.end(); ++rit) {
563 if (rit->end >= curTime) {
568 if (rit == silenceList.end()) {
573 auto requiredTrackSamples = previewLen - outLength;
574 outLength += (remainingTrackSamples > requiredTrackSamples)? requiredTrackSamples : remainingTrackSamples;
579 else if (rit->start > curTime) {
581 if (*silentFrame >= minSilenceFrames) {
582 trackSilences.push_back(
Region(
590 auto requiredTrackSamples = previewLen - outLength;
592 outLength += ((newIndex - *index) > requiredTrackSamples)? requiredTrackSamples : newIndex - *index;
603 wt->
GetFloats((buffer.get()), *index, count);
606 for (
decltype(count) i = 0; i < count; ++i) {
607 if (inputLength && ((outLength >= previewLen) || (outLength > wt->
TimeToLongSamples(*minInputLength)))) {
612 if (fabs(buffer[i]) < truncDbSilenceThreshold) {
617 if (*silentFrame >= minSilenceFrames) {
627 (*silentFrame - allowed).as_double()
636 trackSilences.push_back(
Region(
641 else if (inputLength) {
642 outLength += *silentFrame;
655 *inputLength = std::min<double>(*inputLength, *minInputLength);
656 if (outLength >= previewLen) {
657 *minInputLength = *inputLength;
672 S.StartStatic(
XO(
"Detect Silence"));
674 S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
678 .Validator<FloatingPointValidator<double>>(
679 3, &
mThresholdDB, NumValidatorStyle::NO_TRAILING_ZEROES,
681 .NameSuffix(
XO(
"db"))
682 .AddTextBox(
XXO(
"&Threshold:"), wxT(
""), 0);
683 S.AddUnits(
XO(
"dB"));
688 NumValidatorStyle::NO_TRAILING_ZEROES,
690 .NameSuffix(
XO(
"seconds"))
691 .AddTextBox(
XXO(
"&Duration:"), wxT(
""), 12);
692 S.AddUnits(
XO(
"seconds"));
698 S.StartStatic(
XO(
"Action"));
700 S.StartHorizontalLay();
706 .MinSize( { -1, -1 } )
707 .AddChoice( {}, actionChoices );
709 S.EndHorizontalLay();
710 S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
716 NumValidatorStyle::NO_TRAILING_ZEROES,
718 .NameSuffix(
XO(
"seconds"))
719 .AddTextBox(
XXO(
"Tr&uncate to:"), wxT(
""), 12);
720 S.AddUnits(
XO(
"seconds"));
724 NumValidatorStyle::NO_TRAILING_ZEROES,
727 .AddTextBox(
XXO(
"C&ompress to:"), wxT(
""), 12);
732 S.StartMultiColumn(2, wxALIGN_CENTER_HORIZONTAL);
756 RegionList::iterator destIter;
757 destIter = dest.begin();
759 if (destIter == dest.end())
761 RegionList::iterator curDest = destIter;
764 double nsStart = curDest->start;
766 bool lastRun =
false;
768 RegionList::const_iterator srcIter = src.begin();
772 if (srcIter == src.end())
777 while (srcIter != src.end() || lastRun)
780 RegionList::const_iterator curSrc;
785 nsEnd = std::numeric_limits<double>::max();
790 nsEnd = curSrc->start;
796 while (curDest->end <= nsStart)
799 if (destIter == dest.end())
807 if (nsStart > curDest->start && nsEnd < curDest->
end)
810 Region r(nsEnd, curDest->end);
813 curDest->end = nsStart;
816 RegionList::iterator nextIt(destIter);
823 if (nextIt == dest.end())
826 dest.insert(nextIt, r);
833 if (nsStart > curDest->start && nsStart < curDest->
end &&
834 nsEnd >= curDest->end)
836 curDest->end = nsStart;
839 if (destIter == dest.end())
847 while (nsStart <= curDest->start && nsEnd >= curDest->end)
849 destIter = dest.erase(destIter);
850 if (destIter == dest.end())
858 if (nsStart <= curDest->start &&
859 nsEnd > curDest->start && nsEnd < curDest->
end)
861 curDest->start = nsEnd;
873 nsStart = curSrc->end;
875 if (srcIter == src.end())
auto Visit(Visitor &&vis, Variant &&var)
Mimic some of std::visit, for the case of one visitor only.
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
static Settings & settings()
static CommandParameters::ObsoleteMap kObsoleteActions[]
static const size_t DEF_BlendFrameCount
static const size_t nObsoleteActions
static const double DEF_MinTruncMs
static double enumToDB(int val)
Generates EffectParameterMethods overrides from variadic template arguments.
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
bool ReadAndVerify(const wxString &key, float *val, float defVal, float min, float max) const
std::pair< wxString, size_t > ObsoleteMap
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
std::shared_ptr< TrackList > mOutputTracks
const TrackList * inputTracks() const
void ReplaceProcessedTracks(const bool bGoodResult)
const AudacityProject * FindProject() const
void CopyInputTracks(bool allSyncLockSelected=false)
int MessageBox(const TranslatableString &message, long style=DefaultMessageBoxStyle, const TranslatableString &titleStr={}) const
bool EnableApply(bool enable=true)
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
bool TotalProgress(double frac, const TranslatableString &={}) const
int GetNumWaveTracks() const
Performs effect computation.
Interface for manipulations of an Effect's settings.
Truncate Silence automatically reduces the length of passages where the volume is below a set thresho...
bool Process(EffectInstance &instance, EffectSettings &settings) override
Actually do the effect here.
bool FindSilences(RegionList &silences, const TrackList *list, const Track *firstTrack, const Track *lastTrack)
static constexpr EnumParameter ActIndex
static constexpr EffectParameter Independent
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
wxTextCtrl * mThresholdText
double mInitialAllowedSilence
double CalcPreviewInputLength(const EffectSettings &settings, double previewLength) const override
Default implementation returns previewLength
bool Analyze(RegionList &silenceList, RegionList &trackSilences, const WaveTrack *wt, sampleCount *silentFrame, sampleCount *index, int whichTrack, double *inputLength=NULL, double *minInputLength=NULL) const
void OnControlChange(wxCommandEvent &evt)
static constexpr EffectParameter Minimum
virtual ~EffectTruncSilence()
wxCheckBox * mIndependent
bool TransferDataFromWindow(EffectSettings &settings) override
Update the given settings from controls.
double mSilenceCompressPercent
static constexpr EffectParameter Truncate
std::unique_ptr< EffectUIValidator > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access) override
Add controls to effect panel; always succeeds.
EffectType GetType() const override
Type determines how it behaves.
static const EnumValueSymbol kActionStrings[nActions]
double mTruncLongestAllowedSilence
static constexpr EffectParameter Threshold
bool ProcessIndependently()
wxTextCtrl * mTruncLongestAllowedSilenceT
static const ComponentInterfaceSymbol Symbol
const EffectParameterMethods & Parameters() const override
TranslatableString GetDescription() const override
ComponentInterfaceSymbol GetSymbol() const override
bool DoRemoval(const RegionList &silences, unsigned iGroup, unsigned nGroups, Track *firstTrack, Track *lastTrack, double &totalCutLen)
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
wxTextCtrl * mInitialAllowedSilenceT
wxTextCtrl * mSilenceCompressPercentT
static constexpr EffectParameter Compress
void Intersect(RegionList &dest, const RegionList &src)
Enums is a helper class for Shuttle. It defines enumerations which are used in effects dialogs,...
static const size_t NumDbChoices
static const EnumValueSymbol DbChoices[]
static ProjectSettings & Get(AudacityProject &project)
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
Retrieve samples from a track in floating-point format, regardless of the storage format.
double LongSamplesToTime(sampleCount pos) const
Convert correctly between a number of samples and an (absolute) time in seconds.
sampleCount TimeToLongSamples(double t0) const
Convert correctly between an (absolute) time in seconds and a number of samples.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
static bool IsSelectedOrSyncLockSelected(const Track *pTrack)
static TrackIterRange< Track > Group(Track *pTrack)
Abstract base class for an object holding data associated with points on a time axis.
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
auto Selected() -> TrackIterRange< TrackType >
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
size_t GetMaxBlockSize() const override
This returns a nonnegative number of samples meant to size a memory buffer.
void Clear(double t0, double t1) override
void Set(constSamplePtr buffer, sampleFormat format, sampleCount start, size_t len)
double GetEndTime() const override
Get the time at which the last clip in the track ends, plus recorded stuff.
double GetRate() const override
Positions or offsets within audio files need a wide type.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for, if Traits<Type>::iterated_type is defined.
BuiltinEffectsModule::Registration< EffectTruncSilence > reg
const wxChar *const key
Identifier in configuration file.
const Type def
Default value.
const Type min
Minimum value.
const Type max
Maximum value.
Externalized state of a plug-in.
Structure to hold region of a wavetrack and a comparison function for sortability.