File: AudacityApplicationLogic.cpp

package info (click to toggle)
audacity 3.7.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 134,800 kB
  • sloc: cpp: 366,277; ansic: 198,323; lisp: 7,761; sh: 3,414; python: 1,501; xml: 1,385; perl: 854; makefile: 125
file content (229 lines) | stat: -rw-r--r-- 7,999 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/*  SPDX-License-Identifier: GPL-2.0-or-later */
/*!********************************************************************

  Audacity: A Digital Audio Editor

  AudacityApplicationLogic.cpp

  Matthieu Hodgkinson

**********************************************************************/
#include "AudacityApplicationLogic.h"
#include "BasicUI.h"
#include "CommandManager.h"
#include "Effect.h"
#include "EffectManager.h"
#include "EffectPlugin.h"
#include "PluginManager.h"
#include "Project.h"
#include "ProjectHistory.h"
#include "ProjectRate.h"
#include "TrackFocus.h"
#include "ViewInfo.h"
#include "Viewport.h"
#include "WaveTrack.h"

/// DoEffect() takes a PluginID and executes the associated effect.
///
/// At the moment flags are used only to indicate whether to prompt for
//  parameters, whether to save the state to history and whether to allow
/// 'Repeat Last Effect'.

bool AudacityApplicationLogic::DoEffect(
   const PluginID& ID, AudacityProject& project, unsigned flags,
   ShowEffectHostInterfaceCb showEffectHostInterfaceCb,
   StopPlaybackCb stopPlaybackCb, SelectAllIfNoneCb selectAllIfNoneCb)
{
   auto& tracks = TrackList::Get(project);
   auto& trackFactory = WaveTrackFactory::Get(project);
   auto rate = ProjectRate::Get(project).GetRate();
   auto& selectedRegion = ViewInfo::Get(project).selectedRegion;
   auto& commandManager = CommandManager::Get(project);
   auto& viewport = Viewport::Get(project);

   const PluginDescriptor* plug = PluginManager::Get().GetPlugin(ID);

   if (!plug || !PluginManager::IsPluginAvailable(*plug))
   {
      BasicUI::ShowMessageBox(
         XO("This plugin could not be loaded.\nIt may have been deleted."),
         BasicUI::MessageBoxOptions().Caption(XO("Plugin Error")));

      return false;
   }

   EffectType type = plug->GetEffectType();

   // Make sure there's no activity since the effect is about to be applied
   // to the project's tracks.  Mainly for Apply during RTP, but also used
   // for batch commands
   if (flags & EffectManager::kConfigured)
   {
      stopPlaybackCb();
      // Don't Select All if repeating Generator Effect
      if (!(flags & EffectManager::kConfigured))
         selectAllIfNoneCb();
   }

   auto nTracksOriginally = tracks.Size();
   // wxWindow* focus = wxWindow::FindFocus();
   // wxWindow* parent = nullptr;
   // if (focus != nullptr)
   // {
   //    parent = focus->GetParent();
   // }

   bool success = false;
   auto cleanup = finally([&] {
      if (!success)
      {
         // For now, we're limiting realtime preview to a single effect, so
         // make sure the menus reflect that fact that one may have just been
         // opened.
         CommandManager::Get(project).UpdateMenus(false);
      }
   });

   const auto range = tracks.Selected<const WaveTrack>();
   bool anyTracks = !range.empty();
   bool clean = std::all_of(range.begin(), range.end(), [](const WaveTrack* t) {
      return t->GetEndTime() == 0;
   });

   EffectManager& em = EffectManager::Get();

   em.SetSkipStateFlag(false);
   success = false;
   if (auto effect = dynamic_cast<Effect*>(em.GetEffect(ID)))
   {
      if (const auto pSettings = em.GetDefaultSettings(ID))
      {
         const auto pAccess =
            std::make_shared<SimpleEffectSettingsAccess>(*pSettings);
         const auto finder = [effect, pAccess, flags,
                              cb = std::move(showEffectHostInterfaceCb)](
                                EffectSettings& settings)
            -> std::optional<std::shared_ptr<EffectInstanceEx>> {
            // Prompting will be bypassed when applying an effect that has
            // already been configured, e.g. repeating the last effect on a
            // different selection.  Prompting may call EffectPreview
            std::shared_ptr<EffectInstance> pInstance;
            std::shared_ptr<EffectInstanceEx> pInstanceEx;
            if ((flags & EffectManager::kConfigured) == 0 && pAccess)
            {
               if (!cb(*effect, pInstance, *pAccess))
                  return {};
               else if (!(pInstanceEx =
                             std::dynamic_pointer_cast<EffectInstanceEx>(
                                pInstance)))
                  return {};
               else
                  // Retrieve again after the dialog modified settings
                  settings = pAccess->Get();
            }
            return { pInstanceEx };
         };
         pAccess->ModifySettings([&](EffectSettings& settings) {
            success = effect->DoEffect(
               settings, finder, rate, &tracks, &trackFactory, selectedRegion,
               flags, pAccess);
            return nullptr;
         });
      }
   }

   if (!success)
      return false;

   if (em.GetSkipStateFlag())
      flags = flags | EffectManager::kSkipState;

   if (!(flags & EffectManager::kSkipState))
   {
      auto shortDesc = PluginManager::Get().GetName(ID);
      const auto longDesc = XO("Applied effect: %s").Format(shortDesc);
      ProjectHistory::Get(project).PushState(longDesc, shortDesc);
   }

   if (!(flags & EffectManager::kDontRepeatLast))
   {
      // Remember a successful generator, effect, analyzer, or tool Process
      auto shortDesc = PluginManager::Get().GetName(ID);
      /* i18n-hint: %s will be the name of the effect which will be
       * repeated if this menu item is chosen */
      auto lastEffectDesc = XO("Repeat %s").Format(shortDesc);
      switch (type)
      {
      case EffectTypeGenerate:
         commandManager.Modify(wxT("RepeatLastGenerator"), lastEffectDesc);
         commandManager.mLastGenerator = ID;
         commandManager.mRepeatGeneratorFlags = EffectManager::kConfigured;
         break;
      case EffectTypeProcess:
         commandManager.Modify(wxT("RepeatLastEffect"), lastEffectDesc);
         commandManager.mLastEffect = ID;
         commandManager.mRepeatEffectFlags = EffectManager::kConfigured;
         break;
      case EffectTypeAnalyze:
         commandManager.Modify(wxT("RepeatLastAnalyzer"), lastEffectDesc);
         commandManager.mLastAnalyzer = ID;
         commandManager.mLastAnalyzerRegistration =
            CommandManager::repeattypeplugin;
         commandManager.mRepeatAnalyzerFlags = EffectManager::kConfigured;
         break;
      case EffectTypeTool:
         commandManager.Modify(wxT("RepeatLastTool"), lastEffectDesc);
         commandManager.mLastTool = ID;
         commandManager.mLastToolRegistration =
            CommandManager::repeattypeplugin;
         commandManager.mRepeatToolFlags = EffectManager::kConfigured;
         if (shortDesc == NYQUIST_PROMPT_NAME)
         {
            commandManager.mRepeatToolFlags =
               EffectManager::kRepeatNyquistPrompt; // Nyquist Prompt is not
                                                    // configured
         }
         break;
      }
   }

   // STM:
   // The following automatically re-zooms after sound was generated.
   // IMO, it was disorienting, removing to try out without re-fitting
   // mchinen:12/14/08 reapplying for generate effects
   if (type == EffectTypeGenerate)
   {
      if (!anyTracks || (clean && selectedRegion.t0() == 0.0))
         viewport.ZoomFitHorizontally();
   }

   // PRL:  Redraw explicitly because sometimes history push is skipped
   viewport.Redraw();

   // if (focus != nullptr && focus->GetParent() == parent)
   // {
   //    focus->SetFocus();
   // }

   // A fix for Bug 63
   // New tracks added?  Scroll them into view so that user sees them.
   // Don't care what track type.  An analyser might just have added a
   // Label track and we want to see it.
   if (tracks.Size() > nTracksOriginally)
   {
      viewport.ScrollToBottom();
   }
   else
   {
      auto pTrack = *tracks.Selected().begin();
      if (!pTrack)
         pTrack = *tracks.begin();
      if (pTrack)
      {
         TrackFocus::Get(project).Set(pTrack);
         Viewport::Get(project).ShowTrack(*pTrack);
      }
   }

   return true;
}