Audacity 3.2.0
EffectPreview.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 EffectPreview.cpp
6
7 Dominic Mazzoni
8 Vaughan Johnson
9 Martyn Shaw
10
11 Paul Licameli split from EffectBase.cpp
12
13*//*******************************************************************/
14#include "EffectPreview.h"
15#include "EffectBase.h"
16
17#include "AudioIO.h"
18#include "BasicUI.h"
19#include "MixAndRender.h"
20#include "ProjectAudioIO.h"
21#include "TransportUtilities.h"
22#include "WaveTrack.h"
23
25 EffectSettingsAccess &access, std::function<void()> updateUI, bool dryOnly)
26{
27 auto cleanup0 = effect.BeginPreview(access.Get());
28
29 // These are temporary state in the Effect object that are meant be moved to
30 // a new class EffectContext
31 const auto numTracks = effect.mNumTracks;
32 const auto rate = effect.mProjectRate;
33 const auto &factory = effect.mFactory;
34 auto &mT0 = effect.mT0;
35 auto &mT1 = effect.mT1;
36 auto &mTracks = effect.mTracks;
37 auto &mProgress = effect.mProgress;
38 auto &mIsPreview = effect.mIsPreview;
39
40 // Get certain immutable properties of the effect
41 const auto previewFullSelection = effect.PreviewsFullSelection();
42 const auto isLinearEffect = effect.IsLinearEffect();
43
44 if (numTracks == 0) { // nothing to preview
45 return;
46 }
47
48 auto gAudioIO = AudioIO::Get();
49 if (gAudioIO->IsBusy()) {
50 return;
51 }
52
53 const auto FocusDialog = BasicUI::FindFocus();
54 assert(FocusDialog); // postcondition
55
56 double previewDuration;
57 bool isNyquist = effect.GetFamily() == NYQUISTEFFECTS_FAMILY;
58 bool isGenerator = effect.GetType() == EffectTypeGenerate;
59
60 // Mix a few seconds of audio from all of the tracks
61 double previewLen;
62 gPrefs->Read(wxT("/AudioIO/EffectsPreviewLen"), &previewLen, 6.0);
63
64 const auto &settings = access.Get();
65 if (isNyquist && isGenerator)
66 previewDuration = effect.CalcPreviewInputLength(settings, previewLen);
67 else
68 previewDuration = std::min(settings.extra.GetDuration(),
69 effect.CalcPreviewInputLength(settings, previewLen));
70
71 double t1 = mT0 + previewDuration;
72
73 if ((t1 > mT1) && !isGenerator) {
74 t1 = mT1;
75 }
76
77 if (t1 <= mT0)
78 return;
79
80 bool success = true;
81
82 auto cleanup = finally( [&] {
83
84 // Effect is already inited; we will call Process and then Init
85 // again, so the state is exactly the way it was before Preview
86 // was called.
87 if (!dryOnly)
88 // TODO remove this reinitialization of state within the Effect object
89 // It is done indirectly via Effect::Instance
90 if (auto pInstance =
91 std::dynamic_pointer_cast<EffectInstanceEx>(effect.MakeInstance())
92 )
93 pInstance->Init();
94 } );
95
96 auto vr0 = valueRestorer( mT0 );
97 auto vr1 = valueRestorer( mT1 );
98 // Most effects should stop at t1.
99 if (!previewFullSelection)
100 mT1 = t1;
101
102 // In case any dialog control depends on mT1 or mDuration:
103 if (updateUI)
104 updateUI();
105
106 // Save the original track list
107 auto saveTracks = mTracks;
108
109 auto cleanup2 = finally( [&] {
110 mTracks = saveTracks;
111 if (*FocusDialog)
112 BasicUI::SetFocus(*FocusDialog);
113 } );
114
115 // Build NEW tracklist from rendering tracks
116 // Set the same owning project, so FindProject() can see it within Process()
117 const auto pProject = saveTracks->GetOwner();
118 mTracks = TrackList::Create(pProject);
119
120 // Linear Effect preview optimised by pre-mixing to one track.
121 // Generators need to generate per track.
122 if (isLinearEffect && !isGenerator) {
123 auto newTrack = MixAndRender(
124 saveTracks->Selected<const WaveTrack>(),
125 Mixer::WarpOptions{ saveTracks->GetOwner() },
126 wxString{}, // Don't care about the name of the temporary tracks
127 factory, rate, floatSample, mT0, t1);
128 if (!newTrack)
129 return;
130 mTracks->Add(newTrack);
131
132 newTrack->MoveTo(0);
133 newTrack->SetSelected(true);
134 }
135 else {
136 for (auto src : saveTracks->Selected<const WaveTrack>()) {
137 auto dest = src->Copy(mT0, t1);
138 dest->SetSelected(true);
139 mTracks->Add(dest);
140 }
141 }
142
143 // NEW tracks start at time zero.
144 // Adjust mT0 and mT1 to be the times to process, and to
145 // play back in these tracks
146 mT1 -= mT0;
147 mT0 = 0.0;
148
149 // Update track/group counts
150 effect.CountWaveTracks();
151
152 // Apply effect
153 if (!dryOnly) {
154 using namespace BasicUI;
155 auto progress = MakeProgress(
156 effect.GetName(),
157 XO("Preparing preview"),
159 ); // Have only "Stop" button.
160 auto vr = valueRestorer( mProgress, progress.get() );
161
162 auto vr2 = valueRestorer( mIsPreview, true );
163
165 // Preview of non-realtime effect
166 auto pInstance =
167 std::dynamic_pointer_cast<EffectInstanceEx>(effect.MakeInstance());
168 success = pInstance && pInstance->Process(settings);
169 return nullptr;
170 });
171 }
172
173 if (success)
174 {
175 auto tracks = MakeTransportTracks(*mTracks, true);
176
177 // Some effects (Paulstretch) may need to generate more
178 // than previewLen, so take the min.
179 t1 = std::min(mT0 + previewLen, mT1);
180
181 // Start audio playing
182 auto options = ProjectAudioIO::GetDefaultOptions(*pProject);
183 int token = gAudioIO->StartStream(tracks, mT0, t1, t1, options);
184
185 if (token) {
186 using namespace BasicUI;
187 auto previewing = ProgressResult::Success;
188 // The progress dialog must be deleted before stopping the stream
189 // to allow events to flow to the app during StopStream processing.
190 // The progress dialog blocks these events.
191 {
192 auto progress = MakeProgress(effect.GetName(),
193 XO("Previewing"), ProgressShowStop);
194
195 while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) {
196 using namespace std::chrono;
197 std::this_thread::sleep_for(100ms);
198 previewing = progress->Poll(
199 gAudioIO->GetStreamTime() - mT0, t1 - mT0);
200 }
201 }
202
203 gAudioIO->StopStream();
204
205 while (gAudioIO->IsBusy()) {
206 using namespace std::chrono;
207 std::this_thread::sleep_for(100ms);
208 }
209 }
210 else {
211 using namespace BasicUI;
213 *FocusDialog, XO("Error"),
214 XO("Error opening sound device.\nTry changing the audio host, playback device and the project sample rate."),
215 wxT("Error_opening_sound_device"),
216 ErrorDialogOptions{ ErrorDialogType::ModalErrorReport } );
217 }
218 }
219}
wxT("CloseDown"))
static RegisteredToolbarFactory factory
Toolkit-neutral facade for basic user interface services.
int min(int a, int b)
#define NYQUISTEFFECTS_FAMILY
Definition: EffectBase.h:141
@ EffectTypeGenerate
void EffectPreview(EffectBase &effect, EffectSettingsAccess &access, std::function< void()> updateUI, bool dryOnly)
Calculate temporary tracks of limited length with effect applied and play.
XO("Cut/Copy/Paste")
ValueRestorer< T > valueRestorer(T &var)
inline functions provide convenient parameter type deduction
Definition: MemoryX.h:253
Track::Holder MixAndRender(const TrackIterRange< const WaveTrack > &trackRange, const Mixer::WarpOptions &warpOptions, const wxString &newTrackName, WaveTrackFactory *trackFactory, double rate, sampleFormat format, double startTime, double endTime)
Mixes together all input tracks, applying any envelopes, per-track real-time effects,...
audacity::BasicSettings * gPrefs
Definition: Prefs.cpp:68
constexpr sampleFormat floatSample
Definition: SampleFormat.h:45
const auto tracks
static Settings & settings()
Definition: TrackInfo.cpp:51
TransportSequences MakeTransportTracks(TrackList &trackList, bool selectedOnly, bool nonWaveToo)
static AudioIO * Get()
Definition: AudioIO.cpp:126
TranslatableString GetName() const
Base class for many of the effects in Audacity.
Definition: EffectBase.h:33
int mNumTracks
Definition: EffectBase.h:117
double mT1
Definition: EffectBase.h:123
WaveTrackFactory * mFactory
Definition: EffectBase.h:121
void CountWaveTracks()
Definition: EffectBase.cpp:227
bool PreviewsFullSelection() const
Definition: EffectBase.h:39
virtual std::any BeginPreview(const EffectSettings &settings)
Called when Preview() starts, to allow temporary effect state changes.
Definition: EffectBase.cpp:234
double mProjectRate
Definition: EffectBase.h:119
bool mIsPreview
Definition: EffectBase.h:124
bool IsLinearEffect() const
Definition: EffectBase.h:38
BasicUI::ProgressDialog * mProgress
Definition: EffectBase.h:118
std::shared_ptr< TrackList > mTracks
Definition: EffectBase.h:116
virtual double CalcPreviewInputLength(const EffectSettings &settings, double previewLength) const =0
double mT0
Definition: EffectBase.h:122
virtual EffectType GetType() const =0
Type determines how it behaves.
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.
void ModifySettings(Function &&function)
Do a correct read-modify-write of settings.
virtual const EffectSettings & Get()=0
static AudioIOStartStreamOptions GetDefaultOptions(AudacityProject &project, bool newDefaults=false)
Invoke the global hook, supplying a default argument.
static TrackListHolder Create(AudacityProject *pOwner)
Definition: Track.cpp:330
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
virtual bool Read(const wxString &key, bool *value) const =0
void SetFocus(const WindowPlacement &focus)
Set the window that accepts keyboard input.
Definition: BasicUI.h:392
@ ProgressShowStop
Definition: BasicUI.h:141
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:272
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:302
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:383
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:52
Externalized state of a plug-in.
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:56