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
20
21#include "EffectBase.h"
22
23#include <thread>
24#include "../AudioIO.h"
25#include "ConfigInterface.h"
27#include "../MixAndRender.h"
28#include "PluginManager.h"
29#include "../ProjectAudioManager.h"
30#include "QualitySettings.h"
31#include "TransactionScope.h"
32#include "ViewInfo.h"
33#include "../WaveTrack.h"
34#include "../widgets/ProgressDialog.h"
35#include "../widgets/NumericTextCtrl.h"
36
37// Effect application counter
39
41{
42 // PRL: I think this initialization of mProjectRate doesn't matter
43 // because it is always reassigned in DoEffect before it is used
44 // STF: but can't call AudioIOBase::GetOptimalSupportedSampleRate() here.
45 // (Which is called to compute the default-default value.) (Bug 2280)
47}
48
49EffectBase::~EffectBase() = default;
50
52{
53 return 30.0;
54}
55
56// TODO: Lift the possible user-prompting part out of this function, so that
57// the recursive paths into this function via Effect::Delegate are simplified,
58// and we don't have both EffectSettings and EffectSettingsAccessPtr
59// If pAccess is not null, settings should have come from its Get()
61 TrackList *list,
63 NotifyingSelectedRegion &selectedRegion,
64 unsigned flags,
65 wxWindow *pParent,
66 const EffectDialogFactory &dialogFactory,
67 const EffectSettingsAccessPtr &pAccess)
68{
69 auto cleanup0 = valueRestorer(mUIFlags, flags);
70 wxASSERT(selectedRegion.duration() >= 0.0);
71
72 mOutputTracks.reset();
73
75 mProjectRate = projectRate;
76 mTracks = list;
77
78 // This is for performance purposes only, no additional recovery implied
79 auto &pProject = *const_cast<AudacityProject*>(FindProject()); // how to remove this const_cast?
80 TransactionScope trans(pProject, "Effect");
81
82 // Update track/group counts
84
85 bool isSelection = false;
86
87 auto duration = 0.0;
92
93 WaveTrack *newTrack{};
94 bool success = false;
95 auto oldDuration = duration;
96
97 auto cleanup = finally( [&] {
98 if (!success) {
99 if (newTrack) {
100 mTracks->Remove(newTrack);
101 }
102 // On failure, restore the old duration setting
103 settings.extra.SetDuration(oldDuration);
104 }
105 else
106 trans.Commit();
107
108 ReplaceProcessedTracks( false );
109 mPresetNames.clear();
110 } );
111
112 // We don't yet know the effect type for code in the Nyquist Prompt, so
113 // assume it requires a track and handle errors when the effect runs.
114 if ((GetType() == EffectTypeGenerate || GetPath() == NYQUIST_PROMPT_ID) && (mNumTracks == 0)) {
115 auto track = mFactory->Create();
117 newTrack = mTracks->Add(track);
118 newTrack->SetSelected(true);
119 }
120
121 mT0 = selectedRegion.t0();
122 mT1 = selectedRegion.t1();
123 if (mT1 > mT0)
124 {
125 // there is a selection: let's fit in there...
126 // MJS: note that this is just for the TTC and is independent of the track rate
127 // but we do need to make sure we have the right number of samples at the project rate
128 double quantMT0 = QUANTIZED_TIME(mT0, mProjectRate);
129 double quantMT1 = QUANTIZED_TIME(mT1, mProjectRate);
130 duration = quantMT1 - quantMT0;
131 isSelection = true;
132 mT1 = mT0 + duration;
133 }
134
135 // This is happening inside EffectSettingsAccess::ModifySettings
136 auto newFormat = isSelection
139 auto updater = [&](EffectSettings &settings) {
140 settings.extra.SetDuration(duration);
141 settings.extra.SetDurationFormat( newFormat );
142 };
143 // Update our copy of settings; update the EffectSettingsAccess too,
144 // if we are going to show a dialog
145 updater(settings);
146 if (pAccess)
147 pAccess->ModifySettings(updater);
148
149#ifdef EXPERIMENTAL_SPECTRAL_EDITING
150 mF0 = selectedRegion.f0();
151 mF1 = selectedRegion.f1();
153 mPresetNames.push_back(L"control-f0");
155 mPresetNames.push_back(L"control-f1");
156
157#endif
159
160 // Allow the dialog factory to fill this in, but it might not
161 std::shared_ptr<EffectInstance> pInstance;
162
163 // Prompting will be bypassed when applying an effect that has already
164 // been configured, e.g. repeating the last effect on a different selection.
165 // Prompting may call EffectBase::Preview
166 if ( pParent && dialogFactory && pAccess &&
167 IsInteractive()) {
169 *pParent, dialogFactory, pInstance, *pAccess, true ) )
170 return false;
171 else if (!pInstance)
172 return false;
173 else
174 // Retrieve again after the dialog modified settings
175 settings = pAccess->Get();
176 }
177
178 if (!pInstance) {
179 // Path that skipped the dialog factory -- effect may be non-interactive
180 // or this is batch mode processing or repeat of last effect with stored
181 // settings.
182 pInstance = MakeInstance();
183 // Note: Init may read parameters from preferences
184 if (!pInstance || !pInstance->Init())
185 return false;
186 }
187
188
189 // If the dialog was shown, then it has been closed without errors or
190 // cancellation, and any change of duration has been saved in the config file
191
192 bool returnVal = true;
193 bool skipFlag = CheckWhetherSkipEffect(settings);
194 if (skipFlag == false)
195 {
196 using namespace BasicUI;
197 auto name = GetName();
198 auto progress = MakeProgress(
199 name,
200 XO("Applying %s...").Format( name ),
202 );
203 auto vr = valueRestorer( mProgress, progress.get() );
204
205 assert(pInstance); // null check above
206 returnVal = pInstance->Process(settings);
207 }
208
209 if (returnVal && (mT1 >= mT0 ))
210 {
211 selectedRegion.setTimes(mT0, mT1);
212 }
213
214 success = returnVal;
215 return returnVal;
216}
217
218void EffectBase::SetLinearEffectFlag(bool linearEffectFlag)
219{
220 mIsLinearEffect = linearEffectFlag;
221}
222
223void EffectBase::SetPreviewFullSelectionFlag(bool previewDurationFlag)
224{
225 mPreviewFullSelection = previewDurationFlag;
226}
227
228
230{
231 mPreviewWithNotSelected = includeNotSelected;
232}
233
234// If bGoodResult, replace mTracks tracks with successfully processed mOutputTracks copies.
235// Else clear and DELETE mOutputTracks copies.
236void EffectBase::ReplaceProcessedTracks(const bool bGoodResult)
237{
238 if (!bGoodResult) {
239 // Free resources, unless already freed.
240
241 // Processing failed or was cancelled so throw away the processed tracks.
242 if ( mOutputTracks )
243 mOutputTracks->Clear();
244
245 // Reset map
246 mIMap.clear();
247 mOMap.clear();
248
249 //TODO:undo the non-gui ODTask transfer
250 return;
251 }
252
253 // Assume resources need to be freed.
254 wxASSERT(mOutputTracks); // Make sure we at least did the CopyInputTracks().
255
256 auto iterOut = mOutputTracks->ListOfTracks::begin(),
257 iterEnd = mOutputTracks->ListOfTracks::end();
258
259 size_t cnt = mOMap.size();
260 size_t i = 0;
261
262 for (; iterOut != iterEnd; ++i) {
263 ListOfTracks::value_type o = *iterOut;
264 // If tracks were removed from mOutputTracks, then there will be
265 // tracks in the map that must be removed from mTracks.
266 while (i < cnt && mOMap[i] != o.get()) {
267 const auto t = mIMap[i];
268 if (t) {
269 mTracks->Remove(t);
270 }
271 i++;
272 }
273
274 // This should never happen
275 wxASSERT(i < cnt);
276
277 // Remove the track from the output list...don't DELETE it
278 iterOut = mOutputTracks->erase(iterOut);
279
280 const auto t = mIMap[i];
281 if (t == NULL)
282 {
283 // This track is a NEW addition to output tracks; add it to mTracks
284 mTracks->Add( o );
285 }
286 else
287 {
288 // Replace mTracks entry with the NEW track
289 mTracks->Replace(t, o);
290 }
291 }
292
293 // If tracks were removed from mOutputTracks, then there may be tracks
294 // left at the end of the map that must be removed from mTracks.
295 while (i < cnt) {
296 const auto t = mIMap[i];
297 if (t) {
298 mTracks->Remove(t);
299 }
300 i++;
301 }
302
303 // Reset map
304 mIMap.clear();
305 mOMap.clear();
306
307 // Make sure we processed everything
308 wxASSERT(mOutputTracks->empty());
309
310 // The output list is no longer needed
311 mOutputTracks.reset();
312 nEffectsDone++;
313}
314
316{
317 if (!inputTracks())
318 return nullptr;
319 return inputTracks()->GetOwner();
320}
321
323{
324 mNumTracks = mTracks->Selected< const WaveTrack >().size();
326}
327
328void EffectBase::Preview(EffectSettingsAccess &access, bool dryOnly)
329{
330 if (mNumTracks == 0) { // nothing to preview
331 return;
332 }
333
334 auto gAudioIO = AudioIO::Get();
335 if (gAudioIO->IsBusy()) {
336 return;
337 }
338
339 wxWindow *FocusDialog = wxWindow::FindFocus();
340
341 double previewDuration;
342 bool isNyquist = GetFamily() == NYQUISTEFFECTS_FAMILY;
343 bool isGenerator = GetType() == EffectTypeGenerate;
344
345 // Mix a few seconds of audio from all of the tracks
346 double previewLen;
347 gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen, 6.0);
348
349 const double rate = mProjectRate;
350
351 const auto &settings = access.Get();
352 if (isNyquist && isGenerator)
353 previewDuration = CalcPreviewInputLength(settings, previewLen);
354 else
355 previewDuration = std::min(settings.extra.GetDuration(),
356 CalcPreviewInputLength(settings, previewLen));
357
358 double t1 = mT0 + previewDuration;
359
360 if ((t1 > mT1) && !isGenerator) {
361 t1 = mT1;
362 }
363
364 if (t1 <= mT0)
365 return;
366
367 bool success = true;
368
369 auto cleanup = finally( [&] {
370
371 // Effect is already inited; we will call Process and then Init
372 // again, so the state is exactly the way it was before Preview
373 // was called.
374 if (!dryOnly)
375 // TODO remove this reinitialization of state within the Effect object
376 // It is done indirectly via Effect::Instance
377 if (auto pInstance = MakeInstance())
378 pInstance->Init();
379
380 // In case any dialog control depends on mT1 or mDuration:
381 if ( mUIDialog )
382 mUIDialog->TransferDataToWindow();
383 } );
384
385 auto vr0 = valueRestorer( mT0 );
386 auto vr1 = valueRestorer( mT1 );
387 // Most effects should stop at t1.
389 mT1 = t1;
390
391 // In case any dialog control depends on mT1 or mDuration:
392 if ( mUIDialog ) {
393 mUIDialog->TransferDataToWindow();
394 }
395
396 // Save the original track list
397 TrackList *saveTracks = mTracks;
398
399 auto cleanup2 = finally( [&] {
400 mTracks = saveTracks;
401 if (FocusDialog) {
402 FocusDialog->SetFocus();
403 }
404
405 // In case of failed effect, be sure to free memory.
406 ReplaceProcessedTracks( false );
407 } );
408
409 // Build NEW tracklist from rendering tracks
410 // Set the same owning project, so FindProject() can see it within Process()
411 const auto pProject = saveTracks->GetOwner();
412 auto uTracks = TrackList::Create( pProject );
413 mTracks = uTracks.get();
414
415 // Linear Effect preview optimised by pre-mixing to one track.
416 // Generators need to generate per track.
417 if (mIsLinearEffect && !isGenerator) {
418 WaveTrack::Holder mixLeft, mixRight;
419 MixAndRender(saveTracks->Selected<const WaveTrack>(),
420 Mixer::WarpOptions{ *saveTracks },
421 wxString{}, // Don't care about the name of the temporary tracks
422 mFactory, rate, floatSample, mT0, t1, mixLeft, mixRight);
423 if (!mixLeft)
424 return;
425
426 mixLeft->Offset(-mixLeft->GetStartTime());
427 mixLeft->SetSelected(true);
428 auto pLeft = mTracks->Add( mixLeft );
429 Track *pRight{};
430 if (mixRight) {
431 mixRight->Offset(-mixRight->GetStartTime());
432 mixRight->SetSelected(true);
433 pRight = mTracks->Add( mixRight );
434 mTracks->MakeMultiChannelTrack(*pLeft, 2, true);
435 }
436 }
437 else {
438 for (auto src : saveTracks->Any< const WaveTrack >()) {
439 if (src->GetSelected() || mPreviewWithNotSelected) {
440 auto dest = src->Copy(mT0, t1);
441 dest->SetSelected(src->GetSelected());
442 mTracks->Add( dest );
443 }
444 }
445 }
446
447 // NEW tracks start at time zero.
448 // Adjust mT0 and mT1 to be the times to process, and to
449 // play back in these tracks
450 mT1 -= mT0;
451 mT0 = 0.0;
452
453 // Update track/group counts
455
456 // Apply effect
457 if (!dryOnly) {
458 using namespace BasicUI;
459 auto progress = MakeProgress(
460 GetName(),
461 XO("Preparing preview"),
463 ); // Have only "Stop" button.
464 auto vr = valueRestorer( mProgress, progress.get() );
465
466 auto vr2 = valueRestorer( mIsPreview, true );
467
469 // Preview of non-realtime effect
470 auto pInstance = MakeInstance();
471 success = pInstance && pInstance->Process(settings);
472 });
473 }
474
475 if (success)
476 {
478
479 // Some effects (Paulstretch) may need to generate more
480 // than previewLen, so take the min.
481 t1 = std::min(mT0 + previewLen, mT1);
482
483 // Start audio playing
484 auto options = DefaultPlayOptions(*pProject);
485 int token = gAudioIO->StartStream(tracks, mT0, t1, t1, options);
486
487 if (token) {
488 auto previewing = ProgressResult::Success;
489 // The progress dialog must be deleted before stopping the stream
490 // to allow events to flow to the app during StopStream processing.
491 // The progress dialog blocks these events.
492 {
493 ProgressDialog progress
494 (GetName(), XO("Previewing"), pdlgHideCancelButton);
495
496 while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) {
497 using namespace std::chrono;
498 std::this_thread::sleep_for(100ms);
499 previewing = progress.Update(gAudioIO->GetStreamTime() - mT0, t1 - mT0);
500 }
501 }
502
503 gAudioIO->StopStream();
504
505 while (gAudioIO->IsBusy()) {
506 using namespace std::chrono;
507 std::this_thread::sleep_for(100ms);
508 }
509 }
510 else {
511 using namespace BasicUI;
513 wxWidgetsWindowPlacement{ FocusDialog }, XO("Error"),
514 XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
515 wxT("Error_opening_sound_device"),
516 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
517 }
518 }
519}
wxT("CloseDown"))
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:82
#define NYQUISTEFFECTS_FAMILY
Definition: EffectBase.h:144
const RegistryPath & CurrentSettingsGroup()
Component of a configuration key path, for last-used destructive settings.
@ EffectTypeGenerate
std::function< DialogFactoryResults(wxWindow &parent, EffectPlugin &, EffectUIClientInterface &, EffectSettingsAccess &) > EffectDialogFactory
Type of function that creates a dialog for an effect.
Definition: EffectPlugin.h:41
#define XO(s)
Definition: Internat.h:31
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:234
#define QUANTIZED_TIME(time, rate)
Definition: MemoryX.h:541
void MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime, WaveTrack::Holder &uLeft, WaveTrack::Holder &uRight)
Mixes together all input tracks, applying any envelopes, amplitude gain, panning, and real-time effec...
#define NYQUIST_PROMPT_ID
FileConfig * gPrefs
Definition: Prefs.cpp:71
@ pdlgHideCancelButton
AudioIOStartStreamOptions DefaultPlayOptions(AudacityProject &project, bool newDefault)
@ floatSample
Definition: SampleFormat.h:34
static Settings & settings()
Definition: TrackInfo.cpp:87
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
static AudioIO * Get()
Definition: AudioIO.cpp:133
Abstraction of a progress dialog with well defined time-to-completion estimate.
Definition: BasicUI.h:154
virtual PluginPath GetPath() const =0
TranslatableString GetName() const
int mNumTracks
Definition: EffectBase.h:136
double mT1
Definition: EffectBase.h:107
std::shared_ptr< TrackList > mOutputTracks
Definition: EffectBase.h:105
bool DoEffect(EffectSettings &settings, double projectRate, TrackList *list, WaveTrackFactory *factory, NotifyingSelectedRegion &selectedRegion, unsigned flags, wxWindow *pParent, const EffectDialogFactory &dialogFactory, const EffectSettingsAccessPtr &pAccess) override
Unfortunately complicated dual-use function.
Definition: EffectBase.cpp:60
WaveTrackFactory * mFactory
Definition: EffectBase.h:101
~EffectBase() override
TrackList * mTracks
Definition: EffectBase.h:125
void CountWaveTracks()
Definition: EffectBase.cpp:322
std::vector< Track * > mOMap
Definition: EffectBase.h:134
void SetPreviewFullSelectionFlag(bool previewDurationFlag)
Definition: EffectBase.cpp:223
void SetLinearEffectFlag(bool linearEffectFlag)
Definition: EffectBase.cpp:218
const TrackList * inputTracks() const
Definition: EffectBase.h:102
virtual bool CheckWhetherSkipEffect(const EffectSettings &settings) const =0
After Init(), tell whether Process() should be skipped.
double mProjectRate
Definition: EffectBase.h:99
bool mIsPreview
Definition: EffectBase.h:131
BasicUI::ProgressDialog * mProgress
Definition: EffectBase.h:98
bool mPreviewWithNotSelected
Definition: EffectBase.h:128
int mNumGroups
Definition: EffectBase.h:137
bool mPreviewFullSelection
Definition: EffectBase.h:129
virtual double CalcPreviewInputLength(const EffectSettings &settings, double previewLength) const =0
std::vector< Track * > mIMap
Definition: EffectBase.h:133
wxArrayString mPresetNames
Definition: EffectBase.h:112
double GetDefaultDuration()
Definition: EffectBase.cpp:51
wxWeakRef< wxDialog > mUIDialog
This weak pointer may be the same as mUIParent, or null.
Definition: EffectBase.h:119
double mT0
Definition: EffectBase.h:106
unsigned mUIFlags
Definition: EffectBase.h:113
void IncludeNotSelectedPreviewTracks(bool includeNotSelected)
Definition: EffectBase.cpp:229
void ReplaceProcessedTracks(const bool bGoodResult)
Definition: EffectBase.cpp:236
bool mIsLinearEffect
This weak pointer may be the same as mHostUIDialog, or null.
Definition: EffectBase.h:127
void Preview(EffectSettingsAccess &access, bool dryOnly) override
Definition: EffectBase.cpp:328
static int nEffectsDone
Definition: EffectBase.h:91
const AudacityProject * FindProject() const
Definition: EffectBase.cpp:315
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 EffectFamilySymbol GetFamily() const =0
Report identifier and user-visible name of the effect protocol.
virtual std::shared_ptr< EffectInstance > MakeInstance() const =0
Make an object maintaining short-term state of an Effect.
std::shared_ptr< EffectSettingsAccess > EffectSettingsAccessPtr
Definition: EffectPlugin.h:56
virtual int ShowHostInterface(wxWindow &parent, const EffectDialogFactory &factory, std::shared_ptr< EffectInstance > &pInstance, EffectSettingsAccess &access, bool forceModal=false)=0
Usually applies factory to self and given access.
virtual const EffectSettingsManager & GetDefinition() const =0
void ModifySettings(Function &&function)
Do a correct read-modify-write of settings.
virtual const EffectSettings & Get()=0
static const RegistryPath & DurationKey()
Abstract base class used in importing a file.
double t1() const
Definition: ViewInfo.h:35
double f1() const
Definition: ViewInfo.h:37
double duration() const
Definition: ViewInfo.h:40
bool setTimes(double t0, double t1)
Definition: ViewInfo.cpp:51
double f0() const
Definition: ViewInfo.h:36
double t0() const
Definition: ViewInfo.h:34
static NumericFormatSymbol DefaultSelectionFormat()
static NumericFormatSymbol TimeAndSampleFormat()
static TransportTracks GetAllPlaybackTracks(TrackList &trackList, bool selectedOnly, bool nonWaveToo=false)
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
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
void Offset(double t)
Definition: Track.h:482
A flat linked list of tracks supporting Add, Remove, Clear, and Contains, serialization of the list o...
Definition: Track.h:1338
bool MakeMultiChannelTrack(Track &first, int nChannels, bool aligned)
Converts channels to a multichannel track.
Definition: Track.cpp:762
static std::shared_ptr< TrackList > Create(AudacityProject *pOwner)
Definition: Track.cpp:502
auto SelectedLeaders() -> TrackIterRange< TrackType >
Definition: Track.h:1488
ListOfTracks::value_type Replace(Track *t, const ListOfTracks::value_type &with)
Definition: Track.cpp:724
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:543
TrackKind * Add(const std::shared_ptr< TrackKind > &t)
Definition: Track.h:1564
auto Any() -> TrackIterRange< TrackType >
Definition: Track.h:1437
TrackNodePointer Remove(Track *t)
Remove the Track and return an iterator to what followed it.
Definition: Track.cpp:798
auto Selected() -> TrackIterRange< TrackType >
Definition: Track.h:1454
AudacityProject * GetOwner()
Definition: Track.h:1373
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:613
std::shared_ptr< WaveTrack > Create()
Creates an unnamed empty WaveTrack with default sample format and default rate.
Definition: WaveTrack.cpp:118
A Track that contains audio waveform data.
Definition: WaveTrack.h:57
static wxString GetDefaultAudioTrackNamePreference()
Definition: WaveTrack.cpp:100
std::shared_ptr< WaveTrack > Holder
Definition: WaveTrack.h:106
@ ProgressShowCancel
Definition: BasicUI.h:139
@ ProgressShowStop
Definition: BasicUI.h:138
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:254
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:284
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
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:49
Externalized state of a plug-in.
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:54
Window placement information for wxWidgetsBasicUI can be constructed from a wxWindow pointer.