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:
55 static constexpr ChannelGroup* MasterGroup = nullptr;
56
57 using Latency = std::chrono::microseconds;
58
61
63 static const RealtimeEffectManager & Get(const AudacityProject &project);
64
65 // Realtime effect processing
66
68 bool IsActive() const noexcept;
69// Latency GetLatency() const;
70
72
80 std::shared_ptr<RealtimeEffectState> AddState(
81 RealtimeEffects::InitializationScope *pScope,
82 ChannelGroup *pGroup,
83 const PluginID & id);
84
86
95 std::shared_ptr<RealtimeEffectState> ReplaceState(
96 RealtimeEffects::InitializationScope *pScope,
97 ChannelGroup *pGroup,
98 size_t index, const PluginID & id);
99
101
107 void RemoveState(RealtimeEffects::InitializationScope *pScope,
108 ChannelGroup *pGroup,
109 std::shared_ptr<RealtimeEffectState> pState);
110
112 std::optional<size_t> FindState(
113 ChannelGroup *pGroup,
114 const std::shared_ptr<RealtimeEffectState> &pState) const;
115
116 bool GetSuspended() const
117 { return mSuspended.load(std::memory_order_relaxed); }
118
120
126 void SetSuspended(bool value)
127 { mSuspended.store(value, std::memory_order_relaxed); }
128
129private:
131
132 std::shared_ptr<RealtimeEffectState>
133 MakeNewState(RealtimeEffects::InitializationScope *pScope,
134 ChannelGroup *pGroup,
135 const PluginID &id);
136
139 unsigned numPlaybackChannels, double sampleRate);
143 const ChannelGroup &group, unsigned chans, float rate);
145 void Finalize() noexcept;
146
147 friend RealtimeEffects::ProcessingScope;
148
149 void ProcessStart(bool suspended);
150
152 size_t Process(bool suspended,
153 const ChannelGroup *group,
154 float *const *buffers, float *const *scratch, float *dummy,
155 unsigned nBuffers, size_t numSamples);
156 void ProcessEnd(bool suspended) noexcept;
157
159 RealtimeEffectManager &operator=(const RealtimeEffectManager&) = delete;
160
161 // Type that state visitor functions would have for out-of-line definition
162 // of VisitGroup and VisitAll
163 // using StateVisitor =
164 // std::function<void(RealtimeEffectState &state, bool listIsActive)> ;
165
167 template<typename StateVisitor>
168 void VisitGroup(ChannelGroup *group, const StateVisitor &func)
169 {
170 if(group == nullptr)
171 RealtimeEffectList::Get(mProject).Visit(func);
172 else
173 // Call the function for each effect on the group list
174 RealtimeEffectList::Get(*group).Visit(func);
175 }
176
177 template<typename StateVisitor>
178 void VisitGroup(const ChannelGroup *group, const StateVisitor &func)
179 {
180 VisitGroup(const_cast<ChannelGroup*>(group), func);
181 }
182
184
185 template<typename StateVisitor>
186 void VisitAll(const StateVisitor &func)
187 {
188 // Call the function for each effect on the master list
189 RealtimeEffectList::Get(mProject).Visit(func);
190
191 // And all group lists
192 for (auto group : mGroups)
193 RealtimeEffectList::Get(*group).Visit(func);
194 }
195
197 //Latency mLatency{ 0 };
198
199 std::atomic<bool> mSuspended{ true };
200
201 bool mActive{ false };
202
203 // This member is mutated only by Initialize(), AddGroup(), Finalize()
204 // which are to be called only while there is no playback
205 std::vector<const ChannelGroup *> mGroups;
206
207 std::unordered_map<const ChannelGroup *, double> mRates;
208};
209
210namespace RealtimeEffects {
213public:
216 std::weak_ptr<AudacityProject> wProject, double sampleRate,
217 unsigned numPlaybackChannels
219 , mwProject{ move(wProject) }
220 , mNumPlaybackChannels{ numPlaybackChannels }
221 {
222 if (const auto pProject = mwProject.lock())
223 {
225 *this,
226 numPlaybackChannels,
228 );
229 }
230 }
234 {
235 if (auto pProject = mwProject.lock())
237 }
238
239 void AddGroup(const ChannelGroup &group,
240 unsigned chans, float rate)
241 {
242 if (auto pProject = mwProject.lock())
244 .AddGroup(*this, group, chans, rate);
245 }
246
247 std::vector<std::shared_ptr<EffectInstance>> mInstances;
250
251private:
252 std::weak_ptr<AudacityProject> mwProject;
253};
254
257public:
260 std::weak_ptr<AudacityProject> wProject)
261 : mwProject{ move(wProject) }
262 {
263 if (auto pProject = mwProject.lock())
265 }
266 ProcessingScope( ProcessingScope &&other ) = default;
269 {
270 if (auto pProject = mwProject.lock())
272 }
273
275 size_t Process(const ChannelGroup *group,
276 float *const *buffers,
277 float *const *scratch,
278 float *dummy,
279 unsigned nBuffers,
280 size_t numSamples
281 )
282 {
283 if (const auto pProject = mwProject.lock())
284 {
285 return RealtimeEffectManager::Get(*pProject)
286 .Process(mSuspended, group, buffers, scratch, dummy,
287 nBuffers, numSamples);
288 }
289 return 0; // consider them trivially processed
290 }
291
292private:
293 std::weak_ptr<AudacityProject> mwProject;
295};
296}
297
298#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.
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 Initialize(RealtimeEffects::InitializationScope &scope, unsigned numPlaybackChannels, double sampleRate)
Main thread begins to define a set of groups for playback.
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)
size_t Process(bool suspended, const ChannelGroup *group, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
void ProcessStart(bool suspended)
std::unordered_map< const ChannelGroup *, double > mRates
void Finalize() noexcept
Main thread cleans up after playback.
void AddGroup(RealtimeEffects::InitializationScope &scope, const ChannelGroup &group, unsigned chans, float rate)
void ProcessEnd(bool suspended) noexcept
std::chrono::microseconds Latency
std::vector< const ChannelGroup * > mGroups
all are non-null
void VisitGroup(const ChannelGroup *group, const StateVisitor &func)
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.
ProcessingScope & operator=(ProcessingScope &&other)=default
std::weak_ptr< AudacityProject > mwProject
size_t Process(const ChannelGroup *group, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
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:202
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