Audacity 3.2.0
AudacityApplicationLogic.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 AudacityApplicationLogic.cpp
7
8 Matthieu Hodgkinson
9
10**********************************************************************/
12#include "BasicUI.h"
13#include "CommandManager.h"
14#include "Effect.h"
15#include "EffectManager.h"
16#include "EffectPlugin.h"
17#include "PluginManager.h"
18#include "Project.h"
19#include "ProjectHistory.h"
20#include "ProjectRate.h"
21#include "TrackFocus.h"
22#include "ViewInfo.h"
23#include "Viewport.h"
24#include "WaveTrack.h"
25
29// parameters, whether to save the state to history and whether to allow
31
33 const PluginID& ID, AudacityProject& project, unsigned flags,
34 ShowEffectHostInterfaceCb showEffectHostInterfaceCb,
35 StopPlaybackCb stopPlaybackCb, SelectAllIfNoneCb selectAllIfNoneCb)
36{
38 auto& trackFactory = WaveTrackFactory::Get(project);
39 auto rate = ProjectRate::Get(project).GetRate();
40 auto& selectedRegion = ViewInfo::Get(project).selectedRegion;
41 auto& commandManager = CommandManager::Get(project);
42 auto& viewport = Viewport::Get(project);
43
45
46 if (!plug || !PluginManager::IsPluginAvailable(*plug))
47 {
49 XO("This plugin could not be loaded.\nIt may have been deleted."),
50 BasicUI::MessageBoxOptions().Caption(XO("Plugin Error")));
51
52 return false;
53 }
54
55 EffectType type = plug->GetEffectType();
56
57 // Make sure there's no activity since the effect is about to be applied
58 // to the project's tracks. Mainly for Apply during RTP, but also used
59 // for batch commands
61 {
62 stopPlaybackCb();
63 // Don't Select All if repeating Generator Effect
64 if (!(flags & EffectManager::kConfigured))
65 selectAllIfNoneCb();
66 }
67
68 auto nTracksOriginally = tracks.Size();
69 // wxWindow* focus = wxWindow::FindFocus();
70 // wxWindow* parent = nullptr;
71 // if (focus != nullptr)
72 // {
73 // parent = focus->GetParent();
74 // }
75
76 bool success = false;
77 auto cleanup = finally([&] {
78 if (!success)
79 {
80 // For now, we're limiting realtime preview to a single effect, so
81 // make sure the menus reflect that fact that one may have just been
82 // opened.
84 }
85 });
86
87 const auto range = tracks.Selected<const WaveTrack>();
88 bool anyTracks = !range.empty();
89 bool clean = std::all_of(range.begin(), range.end(), [](const WaveTrack* t) {
90 return t->GetEndTime() == 0;
91 });
92
94
95 em.SetSkipStateFlag(false);
96 success = false;
97 if (auto effect = dynamic_cast<Effect*>(em.GetEffect(ID)))
98 {
99 if (const auto pSettings = em.GetDefaultSettings(ID))
100 {
101 const auto pAccess =
102 std::make_shared<SimpleEffectSettingsAccess>(*pSettings);
103 const auto finder = [effect, pAccess, flags,
104 cb = std::move(showEffectHostInterfaceCb)](
106 -> std::optional<std::shared_ptr<EffectInstanceEx>> {
107 // Prompting will be bypassed when applying an effect that has
108 // already been configured, e.g. repeating the last effect on a
109 // different selection. Prompting may call EffectPreview
110 std::shared_ptr<EffectInstance> pInstance;
111 std::shared_ptr<EffectInstanceEx> pInstanceEx;
112 if ((flags & EffectManager::kConfigured) == 0 && pAccess)
113 {
114 if (!cb(*effect, pInstance, *pAccess))
115 return {};
116 else if (!(pInstanceEx =
117 std::dynamic_pointer_cast<EffectInstanceEx>(
118 pInstance)))
119 return {};
120 else
121 // Retrieve again after the dialog modified settings
122 settings = pAccess->Get();
123 }
124 return { pInstanceEx };
125 };
126 pAccess->ModifySettings([&](EffectSettings& settings) {
127 success = effect->DoEffect(
128 settings, finder, rate, &tracks, &trackFactory, selectedRegion,
129 flags, pAccess);
130 return nullptr;
131 });
132 }
133 }
134
135 if (!success)
136 return false;
137
138 if (em.GetSkipStateFlag())
139 flags = flags | EffectManager::kSkipState;
140
141 if (!(flags & EffectManager::kSkipState))
142 {
143 auto shortDesc = PluginManager::Get().GetName(ID);
144 const auto longDesc = XO("Applied effect: %s").Format(shortDesc);
145 ProjectHistory::Get(project).PushState(longDesc, shortDesc);
146 }
147
148 if (!(flags & EffectManager::kDontRepeatLast))
149 {
150 // Remember a successful generator, effect, analyzer, or tool Process
151 auto shortDesc = PluginManager::Get().GetName(ID);
152 /* i18n-hint: %s will be the name of the effect which will be
153 * repeated if this menu item is chosen */
154 auto lastEffectDesc = XO("Repeat %s").Format(shortDesc);
155 switch (type)
156 {
158 commandManager.Modify(wxT("RepeatLastGenerator"), lastEffectDesc);
159 commandManager.mLastGenerator = ID;
160 commandManager.mRepeatGeneratorFlags = EffectManager::kConfigured;
161 break;
163 commandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
164 commandManager.mLastEffect = ID;
165 commandManager.mRepeatEffectFlags = EffectManager::kConfigured;
166 break;
168 commandManager.Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc);
169 commandManager.mLastAnalyzer = ID;
170 commandManager.mLastAnalyzerRegistration =
172 commandManager.mRepeatAnalyzerFlags = EffectManager::kConfigured;
173 break;
174 case EffectTypeTool:
175 commandManager.Modify(wxT("RepeatLastTool"), lastEffectDesc);
176 commandManager.mLastTool = ID;
177 commandManager.mLastToolRegistration =
179 commandManager.mRepeatToolFlags = EffectManager::kConfigured;
180 if (shortDesc == NYQUIST_PROMPT_NAME)
181 {
182 commandManager.mRepeatToolFlags =
183 EffectManager::kRepeatNyquistPrompt; // Nyquist Prompt is not
184 // configured
185 }
186 break;
187 }
188 }
189
190 // STM:
191 // The following automatically re-zooms after sound was generated.
192 // IMO, it was disorienting, removing to try out without re-fitting
193 // mchinen:12/14/08 reapplying for generate effects
194 if (type == EffectTypeGenerate)
195 {
196 if (!anyTracks || (clean && selectedRegion.t0() == 0.0))
197 viewport.ZoomFitHorizontally();
198 }
199
200 // PRL: Redraw explicitly because sometimes history push is skipped
201 viewport.Redraw();
202
203 // if (focus != nullptr && focus->GetParent() == parent)
204 // {
205 // focus->SetFocus();
206 // }
207
208 // A fix for Bug 63
209 // New tracks added? Scroll them into view so that user sees them.
210 // Don't care what track type. An analyser might just have added a
211 // Label track and we want to see it.
212 if (tracks.Size() > nTracksOriginally)
213 {
214 viewport.ScrollToBottom();
215 }
216 else
217 {
218 auto pTrack = *tracks.Selected().begin();
219 if (!pTrack)
220 pTrack = *tracks.begin();
221 if (pTrack)
222 {
223 TrackFocus::Get(project).Set(pTrack);
225 }
226 }
227
228 return true;
229}
wxT("CloseDown"))
Toolkit-neutral facade for basic user interface services.
wxString PluginID
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
XO("Cut/Copy/Paste")
#define NYQUIST_PROMPT_NAME
an object holding per-project preferred sample rate
const auto tracks
const auto project
static Settings & settings()
Definition: TrackInfo.cpp:51
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
static CommandManager & Get(AudacityProject &project)
void UpdateMenus(bool checkActive=true)
Base class for many of the effects in Audacity.
Definition: Effect.h:26
EffectManager is the class that handles effects and effect categories.
Definition: EffectManager.h:52
bool GetSkipStateFlag()
void SetSkipStateFlag(bool flag)
EffectPlugin * GetEffect(const PluginID &ID)
static EffectManager & Get()
EffectSettings * GetDefaultSettings(const PluginID &ID)
EffectType GetEffectType() const
TranslatableString GetName(const PluginID &ID) const
static bool IsPluginAvailable(const PluginDescriptor &plug)
const PluginDescriptor * GetPlugin(const PluginID &ID) const
static PluginManager & Get()
void PushState(const TranslatableString &desc, const TranslatableString &shortDesc)
static ProjectHistory & Get(AudacityProject &project)
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
double GetRate() const
Definition: ProjectRate.cpp:53
Track * Get()
Definition: TrackFocus.cpp:156
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
NotifyingSelectedRegion selectedRegion
Definition: ViewInfo.h:216
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
void ShowTrack(const Track &track)
Definition: Viewport.cpp:460
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:33
static WaveTrackFactory & Get(AudacityProject &project)
Definition: WaveTrack.cpp:3376
A Track that contains audio waveform data.
Definition: WaveTrack.h:203
std::function< void()> SelectAllIfNoneCb
AUDACITY_APPLICATION_LOGIC_API bool DoEffect(const PluginID &ID, AudacityProject &project, unsigned flags, ShowEffectHostInterfaceCb, StopPlaybackCb, SelectAllIfNoneCb)
'Repeat Last Effect'.
std::function< bool(Effect &, std::shared_ptr< EffectInstance > &, SimpleEffectSettingsAccess &)> ShowEffectHostInterfaceCb
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:287
Externalized state of a plug-in.