Audacity 3.2.0
FindClipping.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 FindClipping.cpp
6
7 Leland Lucius
8
9*******************************************************************//****************************************************************//*******************************************************************/
20#include "FindClipping.h"
21#include "AnalysisTracks.h"
22#include "EffectEditor.h"
23#include "EffectOutputTracks.h"
24#include "LoadEffects.h"
25
26#include <math.h>
27
28
29#include "ShuttleGui.h"
30#include "../widgets/valnum.h"
31#include "AudacityMessageBox.h"
32
33#include "../LabelTrack.h"
34#include "WaveTrack.h"
35
37{
39 Start, Stop
40 > parameters;
41 return parameters;
42}
43
45{ XO("Find Clipping") };
46
48
50{
51 Parameters().Reset(*this);
52}
53
55{
56}
57
58// ComponentInterface implementation
59
61{
62 return Symbol;
63}
64
66{
67 return XO("Creates labels where clipping is detected");
68}
69
71{
72 return L"Find_Clipping";
73}
74
75// EffectDefinitionInterface implementation
76
78{
79 return EffectTypeAnalyze;
80}
81
82// Effect implementation
83
85{
86 std::shared_ptr<AddedAnalysisTrack> addedTrack;
87 std::optional<ModifiedAnalysisTrack> modifiedTrack;
88 const wxString name{ _("Clipping") };
89
90 auto clt = *inputTracks()->Any<const LabelTrack>().find_if(
91 [&](const Track *track){ return track->GetName() == name; });
92
93 LabelTrack *lt{};
94 if (!clt)
95 addedTrack = (AddAnalysisTrack(*this, name)), lt = addedTrack->get();
96 else
97 modifiedTrack.emplace(ModifyAnalysisTrack(*this, *clt, name)),
98 lt = modifiedTrack->get();
99
100 int count = 0;
101
102 // JC: Only process selected tracks.
103 // PRL: Compute the strech into temporary tracks. Don't commit the stretch.
104 EffectOutputTracks temp { *mTracks, GetType(), { { mT0, mT1 } } };
105 for (auto t : temp.Get().Selected<const WaveTrack>()) {
106 double trackStart = t->GetStartTime();
107 double trackEnd = t->GetEndTime();
108 double t0 = std::max(trackStart, mT0);
109 double t1 = std::min(trackEnd, mT1);
110 if (t1 > t0) {
111 auto start = t->TimeToLongSamples(t0);
112 auto end = t->TimeToLongSamples(t1);
113 auto len = end - start;
114
115 for (const auto pChannel : t->Channels())
116 if (!ProcessOne(*lt, count++, *pChannel, start, len))
117 return false;
118 }
119 }
120
121 // No cancellation, so commit the addition of the track.
122 if (addedTrack)
123 addedTrack->Commit();
124 if (modifiedTrack)
125 modifiedTrack->Commit();
126 return true;
127}
128
130 int count, const WaveChannel &wt, sampleCount start, sampleCount len)
131{
132 bool bGoodResult = true;
133 size_t blockSize = (mStart * 1000);
134
135 if (len < mStart)
136 return true;
137
138 Floats buffer;
139 try {
140 // mStart should be positive.
141 // if we are throwing bad_alloc and mStart is negative, find out why.
142 if (mStart < 0 || (int)blockSize < mStart)
143 // overflow
144 throw std::bad_alloc{};
145 buffer.reinit(blockSize);
146 }
147 catch( const std::bad_alloc & ) {
149 XO("Requested value exceeds memory capacity."));
150 return false;
151 }
152
153 float *ptr = buffer.get();
154
155 decltype(len) s = 0, startrun = 0, stoprun = 0, samps = 0;
156 decltype(blockSize) block = 0;
157 double startTime = -1.0;
158
159 while (s < len) {
160 if (block == 0) {
161 if (TrackProgress(count, s.as_double() / len.as_double() )) {
162 bGoodResult = false;
163 break;
164 }
165 block = limitSampleBufferSize( blockSize, len - s );
166 wt.GetFloats(buffer.get(), start + s, block);
167 ptr = buffer.get();
168 }
169
170 float v = fabs(*ptr++);
171 if (v >= MAX_AUDIO) {
172 if (startrun == 0) {
173 startTime = wt.LongSamplesToTime(start + s);
174 samps = 0;
175 }
176 else
177 stoprun = 0;
178 startrun++;
179 samps++;
180 }
181 else {
182 if (startrun >= mStart) {
183 stoprun++;
184 samps++;
185 if (stoprun >= mStop) {
186 lt.AddLabel(
187 SelectedRegion(startTime,
188 wt.LongSamplesToTime(start + s - mStop)),
195 XC("%lld of %lld", "find clipping")
196 .Format(startrun.as_long_long(),
197 (samps - mStop).as_long_long())
198 .Translation());
199 startrun = 0;
200 stoprun = 0;
201 samps = 0;
202 }
203 }
204 else
205 startrun = 0;
206 }
207 s++;
208 block--;
209 }
210 return bGoodResult;
211}
212
213std::unique_ptr<EffectEditor> EffectFindClipping::PopulateOrExchange(
215 const EffectOutputs *)
216{
217 mUIParent = S.GetParent();
218 DoPopulateOrExchange(S, access);
219 return nullptr;
220}
221
224{
225 mpAccess = access.shared_from_this();
226 S.StartMultiColumn(2, wxALIGN_CENTER);
227 {
228 S
229 .Validator<IntegerValidator<int>>(
230 &mStart, NumValidatorStyle::DEFAULT, Start.min)
231 .TieTextBox(XXO("&Start threshold (samples):"), mStart, 10);
232
233 S
234 .Validator<IntegerValidator<int>>(
235 &mStop, NumValidatorStyle::DEFAULT, Stop.min)
236 .TieTextBox(XXO("St&op threshold (samples):"), mStop, 10);
237 }
238 S.EndMultiColumn();
239}
240
242{
244 // To do: eliminate this and just use validators for controls
246
247 return true;
248}
249
251{
252 if (!mUIParent->Validate())
253 {
254 return false;
255 }
256
258 // To do: eliminate this and just use validators for controls
260
261 return true;
262}
std::shared_ptr< AddedAnalysisTrack > AddAnalysisTrack(Effect &effect, const wxString &name)
ModifiedAnalysisTrack ModifyAnalysisTrack(Effect &effect, const LabelTrack &origTrack, const wxString &name)
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:76
EffectType
@ EffectTypeAnalyze
XO("Cut/Copy/Paste")
XXO("&Cut/Copy/Paste Toolbar")
#define XC(s, c)
Definition: Internat.h:37
#define _(s)
Definition: Internat.h:73
#define MAX_AUDIO
Definition: MemoryX.h:341
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
Definition: SampleCount.cpp:22
@ eIsSettingToDialog
Definition: ShuttleGui.h:39
@ eIsGettingFromDialog
Definition: ShuttleGui.h:38
#define S(N)
Definition: ToChars.cpp:64
void reinit(Integral count, bool initialize=false)
Definition: MemoryX.h:59
Generates EffectParameterMethods overrides from variadic template arguments.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
double mT1
Definition: EffectBase.h:114
const TrackList * inputTracks() const
Definition: EffectBase.h:91
std::shared_ptr< TrackList > mTracks
Definition: EffectBase.h:107
double mT0
Definition: EffectBase.h:113
static constexpr EffectParameter Start
Definition: FindClipping.h:70
static const ComponentInterfaceSymbol Symbol
Definition: FindClipping.h:29
int mStop
Using int rather than sampleCount because values are only ever small numbers.
Definition: FindClipping.h:64
bool TransferDataToWindow(const EffectSettings &settings) override
void DoPopulateOrExchange(ShuttleGui &S, EffectSettingsAccess &access)
EffectSettingsAccessPtr mpAccess
Definition: FindClipping.h:66
ManualPageID ManualPage() const override
Name of a page in the Audacity alpha manual, default is empty.
wxWeakRef< wxWindow > mUIParent
Definition: FindClipping.h:61
bool Process(EffectInstance &instance, 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.
static constexpr EffectParameter Stop
Definition: FindClipping.h:72
bool TransferDataFromWindow(EffectSettings &settings) override
const EffectParameterMethods & Parameters() const override
EffectType GetType() const override
Type determines how it behaves.
int mStart
Using int rather than sampleCount because values are only ever small numbers.
Definition: FindClipping.h:63
TranslatableString GetDescription() const override
bool ProcessOne(LabelTrack &lt, int count, const WaveChannel &wt, sampleCount start, sampleCount len)
virtual ~EffectFindClipping()
ComponentInterfaceSymbol GetSymbol() const override
bool TrackProgress(int whichTrack, double frac, const TranslatableString &={}) const
Definition: Effect.cpp:343
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.
virtual void Reset(Effect &effect) const =0
static int DoMessageBox(const EffectPlugin &plugin, const TranslatableString &message, long style=DefaultMessageBoxStyle, const TranslatableString &titleStr={})
Abstract base class used in importing a file.
A LabelTrack is a Track that holds labels (LabelStruct).
Definition: LabelTrack.h:95
int AddLabel(const SelectedRegion &region, const wxString &title)
Defines a selected portion of a project.
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:640
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:110
const wxString & GetName() const
Name is always the same for all channels of a group.
Definition: Track.cpp:64
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:950
Holds a msgid for the translation catalog; may also bind format arguments.
bool GetFloats(float *buffer, sampleCount start, size_t len, fillFormat fill=FillFormat::fillZero, bool mayThrow=true, sampleCount *pNumWithinClips=nullptr) const
"narrow" overload fetches from the unique channel
Definition: WaveTrack.h:129
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
double LongSamplesToTime(sampleCount pos) const
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
double as_double() const
Definition: SampleCount.h:46
BuiltinEffectsModule::Registration< EffectFindClipping > reg
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const Type min
Minimum value.
Externalized state of a plug-in.