28#include <wx/checkbox.h>
37#include "../widgets/valnum.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,
225 &inputLength, &minInputLength);
227 whichTrack += wt->NChannels();
245 unsigned nGroups = 0;
251 for (
auto track :
inputTracks()->Selected<const WaveTrack>()) {
256 - [&](
const Track *pTrack){
return pTrack == track; };
260"When truncating independently, there may only be one selected audio track in each Sync-Locked Track Group.") );
281 for (
auto track : outputs.Get().Selected<
WaveTrack>()) {
287 Track *groupFirst, *groupLast;
288 auto range = syncLock
290 : TrackList::SingletonRange<Track>(track);
291 double totalCutLen = 0.0;
292 if (!
DoRemoval(silences, range, iGroup, nGroups, totalCutLen))
294 newT1 = std::max(newT1,
mT1 - totalCutLen);
318 auto trackRange = outputs.Get().Any();
319 double totalCutLen = 0.0;
320 if (
DoRemoval(silences, trackRange, 0, 1, totalCutLen)) {
338 for (
auto wt : range) {
339 assert(wt->IsLeader());
341 auto minSilenceFrames =
350 auto index = wt->TimeToLongSamples(
mT0);
355 silences, trackSilences, *wt, &silentFrame, &index, whichTrack));
361 if (silentFrame >= minSilenceFrames)
364 trackSilences.push_back(
Region(
365 wt->LongSamplesToTime(index - silentFrame),
366 wt->LongSamplesToTime(index)
380 unsigned iGroup,
unsigned nGroups,
390 RegionList::const_reverse_iterator rit;
391 for (rit = silences.rbegin(); rit != silences.rend(); ++rit)
393 const Region ®ion = *rit;
394 const Region *
const r = ®ion;
398 (1 -
detectFrac) * (iGroup + whichReg /
double(silences.size())) / nGroups;
408 double inLength = r->
end - r->
start;
426 const double cutLen = std::max(0.0, inLength - outLength);
431 totalCutLen += cutLen;
434 double cutStart = (r->
start + r->
end - cutLen) / 2;
435 double cutEnd = cutStart + cutLen;
438 - [&](
const Track *pTrack) {
return
440 pTrack->GetEndTime() < r->
start;
442 ).VisitWhile(success,
464 Buffers buffers[2]{ blendFrames, blendFrames };
469 for (
const auto pChannel : wt.
Channels()) {
471 pChannel->GetFloats(buffer.buf1.get(), t1, blendFrames);
472 pChannel->GetFloats(buffer.buf2.get(), t2, blendFrames);
474 for (
decltype(blendFrames) i = 0; i < blendFrames; ++i) {
476 ((blendFrames - i) * buffer.buf1[i] + i * buffer.buf2[i]) /
483 wt.
Clear(cutStart, cutEnd);
486 for (
const auto pChannel : wt.
Channels()) {
501 assert(t.IsLeader());
503 t.SyncLockAdjust(cutEnd, cutStart);
516 sampleCount* index,
int whichTrack,
double* inputLength,
517 double* minInputLength)
const
520 const auto rate = wt.
GetRate();
523 auto minSilenceFrames =
532 double previewLength;
533 gPrefs->
Read(
wxT(
"/AudioIO/EffectsPreviewLen"), &previewLength, 6.0);
535 const sampleCount previewLen(previewLength * rate);
538 RegionList::iterator rit(silenceList.begin());
547 while (*index <
end) {
548 if (inputLength && ((outLength >= previewLen) ||
551 *inputLength = std::min<double>(*inputLength, *minInputLength);
552 if (outLength >= previewLen) {
553 *minInputLength = *inputLength;
562 (*index - start).as_double() /
563 (
end - start).as_double()) /
572 for ( ; rit != silenceList.end(); ++rit) {
574 if (rit->end >= curTime) {
579 if (rit == silenceList.end()) {
583 auto remainingTrackSamples =
585 auto requiredTrackSamples = previewLen - outLength;
586 outLength += (remainingTrackSamples > requiredTrackSamples)
587 ? requiredTrackSamples
588 : remainingTrackSamples;
593 else if (rit->start > curTime) {
595 if (*silentFrame >= minSilenceFrames) {
596 trackSilences.push_back(
Region(
604 auto requiredTrackSamples = previewLen - outLength;
606 outLength += ((newIndex - *index) > requiredTrackSamples)
607 ? requiredTrackSamples
620 for (
const auto pChannel : wt.
Channels())
621 pChannel->GetFloats(buffers[
iChannel++].get(), *index, count);
624 for (
decltype(count) i = 0; i < count; ++i) {
625 if (inputLength && ((outLength >= previewLen) ||
633 const bool silent = std::all_of(buffers, buffers +
iChannel,
634 [&](
const Floats &buffer){
635 return fabs(buffer[i]) < truncDbSilenceThreshold;
641 if (*silentFrame >= minSilenceFrames) {
653 (*silentFrame - allowed).as_double()
662 trackSilences.push_back(
Region(
667 else if (inputLength) {
668 outLength += *silentFrame;
681 *inputLength = std::min<double>(*inputLength, *minInputLength);
682 if (outLength >= previewLen) {
683 *minInputLength = *inputLength;
700 S.StartStatic(
XO(
"Detect Silence"));
702 S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
706 .Validator<FloatingPointValidator<double>>(
707 3, &
mThresholdDB, NumValidatorStyle::NO_TRAILING_ZEROES,
709 .NameSuffix(
XO(
"db"))
710 .AddTextBox(
XXO(
"&Threshold:"),
wxT(
""), 0);
711 S.AddUnits(
XO(
"dB"));
716 NumValidatorStyle::NO_TRAILING_ZEROES,
718 .NameSuffix(
XO(
"seconds"))
719 .AddTextBox(
XXO(
"&Duration:"),
wxT(
""), 12);
720 S.AddUnits(
XO(
"seconds"));
726 S.StartStatic(
XO(
"Action"));
728 S.StartHorizontalLay();
734 .MinSize( { -1, -1 } )
735 .AddChoice( {}, actionChoices );
737 S.EndHorizontalLay();
738 S.StartMultiColumn(3, wxALIGN_CENTER_HORIZONTAL);
744 NumValidatorStyle::NO_TRAILING_ZEROES,
746 .NameSuffix(
XO(
"seconds"))
747 .AddTextBox(
XXO(
"Tr&uncate to:"),
wxT(
""), 12);
748 S.AddUnits(
XO(
"seconds"));
752 NumValidatorStyle::NO_TRAILING_ZEROES,
755 .AddTextBox(
XXO(
"C&ompress to:"),
wxT(
""), 12);
760 S.StartMultiColumn(2, wxALIGN_CENTER_HORIZONTAL);
800 RegionList::iterator destIter;
801 destIter = dest.begin();
803 if (destIter == dest.end())
805 RegionList::iterator curDest = destIter;
808 double nsStart = curDest->start;
810 bool lastRun =
false;
812 RegionList::const_iterator srcIter = src.begin();
816 if (srcIter == src.end())
821 while (srcIter != src.end() || lastRun)
824 RegionList::const_iterator curSrc;
829 nsEnd = std::numeric_limits<double>::max();
834 nsEnd = curSrc->start;
840 while (curDest->end <= nsStart)
843 if (destIter == dest.end())
851 if (nsStart > curDest->start && nsEnd < curDest->
end)
854 Region r(nsEnd, curDest->end);
857 curDest->end = nsStart;
860 RegionList::iterator nextIt(destIter);
867 if (nextIt == dest.end())
870 dest.insert(nextIt, r);
877 if (nsStart > curDest->start && nsStart < curDest->
end &&
878 nsEnd >= curDest->end)
880 curDest->end = nsStart;
883 if (destIter == dest.end())
891 while (nsStart <= curDest->start && nsEnd >= curDest->end)
893 destIter = dest.erase(destIter);
894 if (destIter == dest.end())
902 if (nsStart <= curDest->start &&
903 nsEnd > curDest->start && nsEnd < curDest->
end)
905 curDest->start = nsEnd;
917 nsStart = curSrc->end;
919 if (srcIter == src.end())
Toolkit-neutral facade for basic user interface services.
XXO("&Cut/Copy/Paste Toolbar")
audacity::BasicSettings * gPrefs
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,...
const TrackList * inputTracks() const
std::shared_ptr< TrackList > mTracks
const AudacityProject * FindProject() const
static bool EnableApply(wxWindow *parent, bool enable=true)
Enable or disable the Apply button of the dialog that contains parent.
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.
Use this object to copy the input tracks to tentative outputTracks.
Hold values to send to effect output meters.
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 TransferDataToWindow(const EffectSettings &settings) override
std::unique_ptr< EffectEditor > PopulateOrExchange(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Add controls to effect panel; always succeeds.
bool Process(EffectInstance &instance, EffectSettings &settings) override
static constexpr EnumParameter ActIndex
static constexpr EffectParameter Independent
wxWeakRef< wxWindow > mUIParent
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
wxTextCtrl * mThresholdText
double mInitialAllowedSilence
bool NeedsDither() const override
double CalcPreviewInputLength(const EffectSettings &settings, double previewLength) const override
void OnControlChange(wxCommandEvent &evt)
static constexpr EffectParameter Minimum
bool FindSilences(RegionList &silences, const TrackIterRange< const WaveTrack > &range)
bool Analyze(RegionList &silenceList, RegionList &trackSilences, const WaveTrack &wt, sampleCount *silentFrame, sampleCount *index, int whichTrack, double *inputLength=nullptr, double *minInputLength=nullptr) const
virtual ~EffectTruncSilence()
wxCheckBox * mIndependent
bool TransferDataFromWindow(EffectSettings &settings) override
double mSilenceCompressPercent
static constexpr EffectParameter Truncate
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 LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
wxTextCtrl * mInitialAllowedSilenceT
wxTextCtrl * mSilenceCompressPercentT
static constexpr EffectParameter Compress
bool DoRemoval(const RegionList &silences, const TrackIterRange< Track > &range, unsigned iGroup, unsigned nGroups, double &totalCutLen)
void Intersect(RegionList &dest, const RegionList &src)
static int DoMessageBox(const EffectPlugin &plugin, const TranslatableString &message, long style=DefaultMessageBoxStyle, const TranslatableString &titleStr={})
static const size_t NumDbChoices
static const EnumValueSymbol DbChoices[]
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)
bool IsSyncLocked() const
static SyncLockState & Get(AudacityProject &project)
Abstract base class for an object holding data associated with points on a time axis.
static auto SingletonRange(TrackType *pTrack) -> TrackIterRange< TrackType >
Holds a msgid for the translation catalog; may also bind format arguments.
A Track that contains audio waveform data.
void Clear(double t0, double t1) override
bool IsLeader() const override
double GetEndTime() const override
Implement WideSampleSequence.
double GetRate() const override
size_t GetMaxBlockSize() const
double LongSamplesToTime(sampleCount pos) const
sampleCount TimeToLongSamples(double t0) const
double SnapToSample(double t) const
virtual bool Read(const wxString &key, bool *value) const =0
Positions or offsets within audio files need a wide type.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
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.
Range between two TrackIters, usable in range-for statements, and with Visit member functions.
Structure to hold region of a wavetrack and a comparison function for sortability.