Audacity 3.2.0
RealtimeEffectManager.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 RealtimeEffectManager.h
6
7 Paul Licameli split from EffectManager.h
8
9 **********************************************************************/
10
11#ifndef __AUDACITY_REALTIME_EFFECT_MANAGER__
12#define __AUDACITY_REALTIME_EFFECT_MANAGER__
13
14#include <atomic>
15#include <chrono>
16#include <memory>
17#include <mutex>
18#include <optional>
19#include <unordered_map>
20#include <vector>
21
22#include "ClientData.h"
23#include "Observer.h"
24#include "PluginProvider.h" // for PluginID
25#include "RealtimeEffectList.h"
26
27class ChannelGroup;
28class EffectInstance;
29
30namespace RealtimeEffects {
31 class InitializationScope;
32 class ProcessingScope;
33}
34
37{
38 enum class Type
39 {
40 EffectAdded,
41 EffectReplaced,
42 EffectRemoved
43 };
46};
47
48class REALTIME_EFFECTS_API RealtimeEffectManager final :
49 public ClientData::Base,
50 public Observer::Publisher<RealtimeEffectManagerMessage>
51{
52public:
53 using Latency = std::chrono::microseconds;
54
57
59 static const RealtimeEffectManager & Get(const AudacityProject &project);
60
61 // Realtime effect processing
62
64 bool IsActive() const noexcept;
65// Latency GetLatency() const;
66
68
76 std::shared_ptr<RealtimeEffectState> AddState(
77 RealtimeEffects::InitializationScope *pScope,
78 ChannelGroup *pGroup,
79 const PluginID & id);
80
82
91 std::shared_ptr<RealtimeEffectState> ReplaceState(
92 RealtimeEffects::InitializationScope *pScope,
93 ChannelGroup *pGroup,
94 size_t index, const PluginID & id);
95
97
103 void RemoveState(RealtimeEffects::InitializationScope *pScope,
104 ChannelGroup *pGroup,
105 std::shared_ptr<RealtimeEffectState> pState);
106
108 std::optional<size_t> FindState(
109 ChannelGroup *pGroup,
110 const std::shared_ptr<RealtimeEffectState> &pState) const;
111
112 bool GetSuspended() const
113 { return mSuspended.load(std::memory_order_relaxed); }
114
116
122 void SetSuspended(bool value)
123 { mSuspended.store(value, std::memory_order_relaxed); }
124
125private:
127
128 std::shared_ptr<RealtimeEffectState>
129 MakeNewState(RealtimeEffects::InitializationScope *pScope,
130 ChannelGroup *pGroup,
131 const PluginID &id);
132
135 double sampleRate);
139 const ChannelGroup &group, unsigned chans, float rate);
141 void Finalize() noexcept;
142
143 friend RealtimeEffects::ProcessingScope;
144 struct REALTIME_EFFECTS_API AllListsLock {
146 AllListsLock(RealtimeEffectManager *pManager = nullptr);
147 AllListsLock(AllListsLock &&other);
148 AllListsLock& operator= (AllListsLock &&other);
149 void Reset();
150 ~AllListsLock() { Reset(); }
151 };
152
153 void ProcessStart(bool suspended);
155 size_t Process(bool suspended,
156 const ChannelGroup &group,
157 float *const *buffers, float *const *scratch, float *dummy,
158 unsigned nBuffers, size_t numSamples);
159 void ProcessEnd(bool suspended) noexcept;
160
163
164 // Type that state visitor functions would have for out-of-line definition
165 // of VisitGroup and VisitAll
166 // using StateVisitor =
167 // std::function<void(RealtimeEffectState &state, bool listIsActive)> ;
168
170 template<typename StateVisitor>
171 void VisitGroup(ChannelGroup &group, const StateVisitor &func)
172 {
173 // Call the function for each effect on the master list
174 RealtimeEffectList::Get(mProject).Visit(func);
175
176 // Call the function for each effect on the group list
177 RealtimeEffectList::Get(group).Visit(func);
178 }
179
180 template<typename StateVisitor>
182 const ChannelGroup &group, const StateVisitor &func)
183 {
184 // Call the function for each effect on the master list
185 RealtimeEffectList::Get(mProject).Visit(func);
186
187 // Call the function for each effect on the group list
188 RealtimeEffectList::Get(group).Visit(func);
189 }
190
192
193 template<typename StateVisitor>
194 void VisitAll(const StateVisitor &func)
195 {
196 // Call the function for each effect on the master list
197 RealtimeEffectList::Get(mProject).Visit(func);
198
199 // And all group lists
200 for (auto group : mGroups)
201 RealtimeEffectList::Get(*group).Visit(func);
202 }
203
205 Latency mLatency{ 0 };
206
207 std::atomic<bool> mSuspended{ true };
208
209 bool mActive{ false };
210
211 // This member is mutated only by Initialize(), AddGroup(), Finalize()
212 // which are to be called only while there is no playback
213 std::vector<const ChannelGroup *> mGroups;
214
215 std::unordered_map<const ChannelGroup *, double> mRates;
216};
217
218namespace RealtimeEffects {
221public:
224 std::weak_ptr<AudacityProject> wProject, double sampleRate,
225 unsigned numPlaybackChannels
227 , mwProject{ move(wProject) }
228 , mNumPlaybackChannels{ numPlaybackChannels }
229 {
230 if (auto pProject = mwProject.lock())
232 }
236 {
237 if (auto pProject = mwProject.lock())
239 }
240
241 void AddGroup(const ChannelGroup &group,
242 unsigned chans, float rate)
243 {
244 if (auto pProject = mwProject.lock())
246 .AddGroup(*this, group, chans, rate);
247 }
248
249 std::vector<std::shared_ptr<EffectInstance>> mInstances;
252
253private:
254 std::weak_ptr<AudacityProject> mwProject;
255};
256
259public:
261 {
262 if (auto pProject = mwProject.lock()) {
263 auto &manager = RealtimeEffectManager::Get(*pProject);
264 mLocks = { &manager };
265 mSuspended = manager.GetSuspended();
266 }
267 }
270 std::weak_ptr<AudacityProject> wProject)
271 : mwProject{ move(wProject) }
272 {
273 if (auto pProject = mwProject.lock())
275 }
276 ProcessingScope( ProcessingScope &&other ) = default;
279 {
280 if (auto pProject = mwProject.lock())
282 }
283
285 size_t Process(const ChannelGroup &group,
286 float *const *buffers,
287 float *const *scratch,
288 float *dummy,
289 unsigned nBuffers,
290 size_t numSamples
291 )
292 {
293 if (auto pProject = mwProject.lock())
294 return RealtimeEffectManager::Get(*pProject)
295 .Process(mSuspended, group, buffers, scratch, dummy,
296 nBuffers, numSamples);
297 else
298 return 0; // consider them trivially processed
299 }
300
301private:
303 std::weak_ptr<AudacityProject> mwProject;
305};
306}
307
308#endif
Utility ClientData::Site to register hooks into a host class that attach client data.
wxString PluginID
Generalized interface for discovery of plug-ins for one protocol.
static const AttachedProjectObjects::RegisteredFactory manager
const auto project
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Performs effect computation.
An object that sends messages to an open-ended list of subscribed callbacks.
Definition: Observer.h:108
void Visit(const StateVisitor &func)
Apply the function to all states sequentially.
static RealtimeEffectList & Get(AudacityProject &project)
void VisitGroup(ChannelGroup &group, const StateVisitor &func)
Visit the per-project states first, then states for group.
void VisitAll(const StateVisitor &func)
Visit the per-project states first, then all groups from AddGroup.
void SetSuspended(bool value)
To be called only from main thread.
static RealtimeEffectManager & Get(AudacityProject &project)
void Initialize(RealtimeEffects::InitializationScope &scope, double sampleRate)
Main thread begins to define a set of groups for playback.
void ProcessStart(bool suspended)
std::unordered_map< const ChannelGroup *, double > mRates
void Finalize() noexcept
Main thread cleans up after playback.
size_t Process(bool suspended, const ChannelGroup &group, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
RealtimeEffectManager & operator=(const RealtimeEffectManager &)=delete
void AddGroup(RealtimeEffects::InitializationScope &scope, const ChannelGroup &group, unsigned chans, float rate)
void ProcessEnd(bool suspended) noexcept
std::chrono::microseconds Latency
void VisitGroup(const ChannelGroup &group, const StateVisitor &func)
std::vector< const ChannelGroup * > mGroups
all are non-null
RealtimeEffectManager(const RealtimeEffectManager &)=delete
Brackets processing setup and cleanup in the main thread.
void AddGroup(const ChannelGroup &group, unsigned chans, float rate)
InitializationScope(std::weak_ptr< AudacityProject > wProject, double sampleRate, unsigned numPlaybackChannels)
InitializationScope(InitializationScope &&other)=default
std::vector< std::shared_ptr< EffectInstance > > mInstances
std::weak_ptr< AudacityProject > mwProject
InitializationScope & operator=(InitializationScope &&other)=default
Brackets one block of processing in one thread.
size_t Process(const ChannelGroup &group, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
ProcessingScope & operator=(ProcessingScope &&other)=default
std::weak_ptr< AudacityProject > mwProject
RealtimeEffectManager::AllListsLock mLocks
ProcessingScope(ProcessingScope &&other)=default
ProcessingScope(InitializationScope &, std::weak_ptr< AudacityProject > wProject)
Require a prior InializationScope to ensure correct nesting.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:201
static CommandContext::TargetFactory::SubstituteInUnique< InteractiveOutputTargets > scope
STL namespace.
A convenient default parameter for class template Site.
Definition: ClientData.h:29
Posted when effect is being added or removed to/from channel group or project.
ChannelGroup * group
null, if changes happened in the project scope