Audacity 3.2.0
EffectBase.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 EffectBase.cpp
6
7 Dominic Mazzoni
8 Vaughan Johnson
9 Martyn Shaw
10
11 Paul Licameli split from Effect.cpp
12
13*******************************************************************//*******************************************************************/
19#include "EffectBase.h"
20
21#include <thread>
22#include "BasicUI.h"
23#include "ConfigInterface.h"
24#include "PluginManager.h"
25#include "QualitySettings.h"
26#include "TransactionScope.h"
27#include "ViewInfo.h"
28#include "WaveTrack.h"
30
31// Effect application counter
33
35{
36 // PRL: I think this initialization of mProjectRate doesn't matter
37 // because it is always reassigned in DoEffect before it is used
38 // STF: but can't call AudioIOBase::GetOptimalSupportedSampleRate() here.
39 // (Which is called to compute the default-default value.) (Bug 2280)
41}
42
43EffectBase::~EffectBase() = default;
44
46{
47 return 30.0;
48}
49
50// TODO: Lift the possible user-prompting part out of this function, so that
51// the recursive paths into this function via Effect::Delegate are simplified,
52// and we don't have both EffectSettings and EffectSettingsAccessPtr
53// If pAccess is not null, settings should have come from its Get()
55 const InstanceFinder &finder,
56 double projectRate,
57 TrackList *list,
59 NotifyingSelectedRegion &selectedRegion,
60 unsigned flags,
61 const EffectSettingsAccessPtr &pAccess)
62{
63 auto cleanup0 = valueRestorer(mUIFlags, flags);
64 wxASSERT(selectedRegion.duration() >= 0.0);
65
66 mOutputTracks.reset();
67
69 mProjectRate = projectRate;
70
71 SetTracks(list);
72 // Don't hold a dangling pointer when done
73 Finally Do([&]{ SetTracks(nullptr); });
74
75 // This is for performance purposes only, no additional recovery implied
76 auto &pProject = *const_cast<AudacityProject*>(FindProject()); // how to remove this const_cast?
77 TransactionScope trans(pProject, "Effect");
78
79 // Update track/group counts
81
82 bool isSelection = false;
83
84 auto duration = 0.0;
89
90 WaveTrack *newTrack{};
91 bool success = false;
92 auto oldDuration = duration;
93
94 auto cleanup = finally( [&] {
95 if (!success) {
96 if (newTrack) {
97 mTracks->Remove(newTrack);
98 }
99 // On failure, restore the old duration setting
100 settings.extra.SetDuration(oldDuration);
101 }
102 else
103 trans.Commit();
104
105 ReplaceProcessedTracks( false );
106 mPresetNames.clear();
107 } );
108
109 // We don't yet know the effect type for code in the Nyquist Prompt, so
110 // assume it requires a track and handle errors when the effect runs.
111 if ((GetType() == EffectTypeGenerate || GetPath() == NYQUIST_PROMPT_ID) && (mNumTracks == 0)) {
112 auto track = mFactory->Create();
114 newTrack = mTracks->Add(track);
115 newTrack->SetSelected(true);
116 }
117
118 mT0 = selectedRegion.t0();
119 mT1 = selectedRegion.t1();
120 if (mT1 > mT0)
121 {
122 // there is a selection: let's fit in there...
123 // MJS: note that this is just for the TTC and is independent of the track rate
124 // but we do need to make sure we have the right number of samples at the project rate
125 double quantMT0 = QUANTIZED_TIME(mT0, mProjectRate);
126 double quantMT1 = QUANTIZED_TIME(mT1, mProjectRate);
127 duration = quantMT1 - quantMT0;
128 isSelection = true;
129 mT1 = mT0 + duration;
130 }
131
132 // This is happening inside EffectSettingsAccess::ModifySettings
133 auto newFormat = isSelection
136 auto updater = [&](EffectSettings &settings) {
137 settings.extra.SetDuration(duration);
138 settings.extra.SetDurationFormat( newFormat );
139 return nullptr;
140 };
141 // Update our copy of settings; update the EffectSettingsAccess too,
142 // if we are going to show a dialog
144 if (pAccess)
145 pAccess->ModifySettings(updater);
146
147#ifdef EXPERIMENTAL_SPECTRAL_EDITING
148 mF0 = selectedRegion.f0();
149 mF1 = selectedRegion.f1();
151 mPresetNames.push_back(L"control-f0");
153 mPresetNames.push_back(L"control-f1");
154
155#endif
157
158 // Allow the dialog factory to fill this in, but it might not
159 std::shared_ptr<EffectInstance> pInstance;
160
161 if (IsInteractive()) {
162 if (!finder)
163 return false;
164 else if (auto result = finder(settings))
165 pInstance = *result;
166 else
167 return false;
168 }
169
170 auto pInstanceEx = std::dynamic_pointer_cast<EffectInstanceEx>(pInstance);
171 if (!pInstanceEx) {
172 // Path that skipped the dialog factory -- effect may be non-interactive
173 // or this is batch mode processing or repeat of last effect with stored
174 // settings.
175 pInstanceEx = std::dynamic_pointer_cast<EffectInstanceEx>(MakeInstance());
176 // Note: Init may read parameters from preferences
177 if (!pInstanceEx || !pInstanceEx->Init())
178 return false;
179 }
180
181
182 // If the dialog was shown, then it has been closed without errors or
183 // cancellation, and any change of duration has been saved in the config file
184
185 bool returnVal = true;
186 bool skipFlag = CheckWhetherSkipEffect(settings);
187 if (skipFlag == false)
188 {
189 using namespace BasicUI;
190 auto name = GetName();
191 auto progress = MakeProgress(
192 name,
193 XO("Applying %s...").Format( name ),
195 );
196 auto vr = valueRestorer( mProgress, progress.get() );
197
198 assert(pInstanceEx); // null check above
199 returnVal = pInstanceEx->Process(settings);
200 }
201
202 if (returnVal && (mT1 >= mT0 ))
203 {
204 selectedRegion.setTimes(mT0, mT1);
205 }
206
207 success = returnVal;
208 return returnVal;
209}
210
211void EffectBase::SetLinearEffectFlag(bool linearEffectFlag)
212{
213 mIsLinearEffect = linearEffectFlag;
214}
215
216void EffectBase::SetPreviewFullSelectionFlag(bool previewDurationFlag)
217{
218 mPreviewFullSelection = previewDurationFlag;
219}
220
221
222// If bGoodResult, replace mTracks tracks with successfully processed mOutputTracks copies.
223// Else clear and DELETE mOutputTracks copies.
224void EffectBase::ReplaceProcessedTracks(const bool bGoodResult)
225{
226 if (!bGoodResult) {
227 // Free resources, unless already freed.
228
229 // Processing failed or was cancelled so throw away the processed tracks.
230 if ( mOutputTracks )
231 mOutputTracks->Clear();
232
233 // Reset map
234 mIMap.clear();
235 mOMap.clear();
236
237 //TODO:undo the non-gui ODTask transfer
238 return;
239 }
240
241 // Assume resources need to be freed.
242 wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks().
243
244 auto iterOut = mOutputTracks->ListOfTracks::begin(),
245 iterEnd = mOutputTracks->ListOfTracks::end();
246
247 size_t cnt = mOMap.size();
248 size_t i = 0;
249
250 for (; iterOut != iterEnd; ++i) {
251 ListOfTracks::value_type o = *iterOut;
252 // If tracks were removed from mOutputTracks, then there will be
253 // tracks in the map that must be removed from mTracks.
254 while (i < cnt && mOMap[i] != o.get()) {
255 const auto t = mIMap[i];
256 if (t) {
257 mTracks->Remove(t);
258 }
259 i++;
260 }
261
262 // This should never happen
263 wxASSERT(i < cnt);
264
265 // Remove the track from the output list...don't DELETE it
266 iterOut = mOutputTracks->erase(iterOut);
267
268 const auto t = mIMap[i];
269 if (t == NULL)
270 {
271 // This track is a NEW addition to output tracks; add it to mTracks
272 mTracks->Add( o );
273 }
274 else
275 {
276 // Replace mTracks entry with the NEW track
277 mTracks->Replace(t, o);
278 }
279 }
280
281 // If tracks were removed from mOutputTracks, then there may be tracks
282 // left at the end of the map that must be removed from mTracks.
283 while (i < cnt) {
284 const auto t = mIMap[i];
285 if (t) {
286 mTracks->Remove(t);
287 }
288 i++;
289 }
290
291 // Reset map
292 mIMap.clear();
293 mOMap.clear();
294
295 // Make sure we processed everything
296 wxASSERT(mOutputTracks->empty());
297
298 // The output list is no longer needed
299 mOutputTracks.reset();
300 nEffectsDone++;
301}
302
304{
305 if (!inputTracks())
306 return nullptr;
307 return inputTracks()->GetOwner();
308}
309
311{
312 mNumTracks = mTracks->Selected< const WaveTrack >().size();
314}
315
317{
318 return {};
319}
320
322 -> std::optional<InstancePointer>
323{
324 auto result = plugin.MakeInstance();
325 if (auto pInstanceEx = std::dynamic_pointer_cast<EffectInstanceEx>(result)
326 ; pInstanceEx && pInstanceEx->Init())
327 return { pInstanceEx };
328 return {};
329}
330
332{
333 return [&plugin](auto&) { return FindInstance(plugin); };
334}
Toolkit-neutral facade for basic user interface services.
const TranslatableString name
Definition: Distortion.cpp:76
const RegistryPath & CurrentSettingsGroup()
Component of a configuration key path, for last-used destructive settings.
@ EffectTypeGenerate
XO("Cut/Copy/Paste")
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:251
#define QUANTIZED_TIME(time, rate)
Definition: MemoryX.h:559
#define NYQUIST_PROMPT_ID
static Settings & settings()
Definition: TrackInfo.cpp:83
static CustomUpdaterValue updater
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
virtual PluginPath GetPath() const =0
TranslatableString GetName() const
int mNumTracks
Definition: EffectBase.h:113
double mT1
Definition: EffectBase.h:119
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:97
WaveTrackFactory * mFactory
Definition: EffectBase.h:117
~EffectBase() override
TrackList * mTracks
Definition: EffectBase.h:112
void CountWaveTracks()
Definition: EffectBase.cpp:310
std::vector< Track * > mOMap
Definition: EffectBase.h:136
void SetPreviewFullSelectionFlag(bool previewDurationFlag)
Definition: EffectBase.cpp:216
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:211
const TrackList * inputTracks() const
Definition: EffectBase.h:94
virtual std::any BeginPreview(const EffectSettings &settings)
Called when Preview() starts, to allow temporary effect state changes.
Definition: EffectBase.cpp:316
virtual bool CheckWhetherSkipEffect(const EffectSettings &settings) const =0
After Init(), tell whether Process() should be skipped.
double mProjectRate
Definition: EffectBase.h:115
BasicUI::ProgressDialog * mProgress
Definition: EffectBase.h:114
int mNumGroups
Definition: EffectBase.h:138
bool DoEffect(EffectSettings &settings, const InstanceFinder &finder, double projectRate, TrackList *list, WaveTrackFactory *factory, NotifyingSelectedRegion &selectedRegion, unsigned flags, const EffectSettingsAccessPtr &pAccess) override
Definition: EffectBase.cpp:54
bool mPreviewFullSelection
Definition: EffectBase.h:133
std::vector< Track * > mIMap
Definition: EffectBase.h:135
static std::optional< InstancePointer > FindInstance(EffectPlugin &plugin)
Definition: EffectBase.cpp:321
wxArrayString mPresetNames
Definition: EffectBase.h:102
double GetDefaultDuration()
Definition: EffectBase.cpp:45
static InstanceFinder DefaultInstanceFinder(EffectPlugin &plugin)
Definition: EffectBase.cpp:331
double mT0
Definition: EffectBase.h:118
unsigned mUIFlags
Definition: EffectBase.h:103
void SetTracks(TrackList *pTracks)
Definition: EffectBase.h:36
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:224
bool mIsLinearEffect
Definition: EffectBase.h:132
static int nEffectsDone
Definition: EffectBase.h:92
const AudacityProject * FindProject() const
Definition: EffectBase.cpp:303
virtual EffectType GetType() const =0
Type determines how it behaves.
virtual bool IsInteractive() const =0
Whether the effect needs a dialog for entry of settings.
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
Factory of instances of an effect.
Definition: EffectPlugin.h:36
std::function< std::optional< InstancePointer >(EffectSettings &settings) > InstanceFinder
Definition: EffectPlugin.h:72
std::shared_ptr< EffectSettingsAccess > EffectSettingsAccessPtr
Definition: EffectPlugin.h:38
virtual const EffectSettingsManager & GetDefinition() const =0
static const RegistryPath & DurationKey()
Abstract base class used in importing a file.
double t1() const
Definition: ViewInfo.h:36
double f1() const
Definition: ViewInfo.h:38
double duration() const
Definition: ViewInfo.h:41
bool setTimes(double t0, double t1)
Definition: ViewInfo.cpp:51
double f0() const
Definition: ViewInfo.h:37
double t0() const
Definition: ViewInfo.h:35
static const int UndefinedFrequency
bool ReadWithDefault(T *pVar, const T &defaultValue) const
overload of ReadWithDefault returning a boolean that is true if the value was previously defined *‍/
Definition: Prefs.h:206
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1201
auto SelectedLeaders() -> TrackIterRange< TrackType >
Definition: Track.h:1353
ListOfTracks::value_type Replace(Track *t, const ListOfTracks::value_type &with)
Definition: Track.cpp:605
wxString MakeUniqueTrackName(const wxString &baseTrackName) const
Returns string that contains baseTrackName, but is guaranteed to be unique among other tracks in that...
Definition: Track.cpp:417
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
Definition: Track.h:1435
TrackNodePointer Remove(Track *t)
Remove the Track and return an iterator to what followed it.
Definition: Track.cpp:673
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1319
AudacityProject * GetOwner()
Definition: Track.h:1238
RAII for a database transaction, possibly nested.
bool Commit()
Commit the transaction.
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:558
std::shared_ptr< WaveTrack > Create()
Creates an unnamed empty WaveTrack with default sample format and default rate.
Definition: WaveTrack.cpp:182
A Track that contains audio waveform data.
Definition: WaveTrack.h:51
static wxString GetDefaultAudioTrackNamePreference()
Definition: WaveTrack.cpp:164
@ ProgressShowCancel
Definition: BasicUI.h:141
std::unique_ptr< ProgressDialog > MakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags=(ProgressShowStop|ProgressShowCancel), const TranslatableString &remainingLabelText={})
Create and display a progress dialog.
Definition: BasicUI.h:289
NUMERIC_FORMATS_API NumericFormatSymbol DefaultSelectionFormat()
NUMERIC_FORMATS_API NumericFormatSymbol TimeAndSampleFormat()
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
PROJECT_RATE_API IntSetting DefaultSampleRate
static RegisteredToolbarFactory factory
Externalized state of a plug-in.
"finally" as in The C++ Programming Language, 4th ed., p. 358 Useful for defining ad-hoc RAII actions...
Definition: MemoryX.h:173