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 EffectInstance;
28
29namespace RealtimeEffects {
30 class InitializationScope;
31 class ProcessingScope;
32}
33
36{
37 enum class Type
38 {
39 EffectAdded,
40 EffectReplaced,
41 EffectRemoved
42 };
44 std::shared_ptr<Track> track;
45};
46
47class REALTIME_EFFECTS_API RealtimeEffectManager final :
48 public ClientData::Base,
49 public Observer::Publisher<RealtimeEffectManagerMessage>
50{
51public:
52 using Latency = std::chrono::microseconds;
53
56
57 static RealtimeEffectManager & Get(AudacityProject &project);
58 static const RealtimeEffectManager & Get(const AudacityProject &project);
59
60 // Realtime effect processing
61
63 bool IsActive() const noexcept;
64// Latency GetLatency() const;
65
67
75 std::shared_ptr<RealtimeEffectState> AddState(
76 RealtimeEffects::InitializationScope *pScope, Track *pTrack,
77 const PluginID & id);
78
80
89 std::shared_ptr<RealtimeEffectState> ReplaceState(
90 RealtimeEffects::InitializationScope *pScope, Track *pTrack,
91 size_t index, const PluginID & id);
92
94
100 void RemoveState(RealtimeEffects::InitializationScope *pScope,
101 Track *pTrack, std::shared_ptr<RealtimeEffectState> pState);
102
104 std::optional<size_t> FindState(
105 Track *pTrack, const std::shared_ptr<RealtimeEffectState> &pState) const;
106
107 bool GetSuspended() const
108 { return mSuspended.load(std::memory_order_relaxed); }
109
111
117 void SetSuspended(bool value)
118 { mSuspended.store(value, std::memory_order_relaxed); }
119
120private:
122
123 std::shared_ptr<RealtimeEffectState>
124 MakeNewState(RealtimeEffects::InitializationScope *pScope,
125 Track *pLeader, const PluginID &id);
126
129 double sampleRate);
133 const Track &track, unsigned chans, float rate);
135 void Finalize() noexcept;
136
137 friend RealtimeEffects::ProcessingScope;
138 struct REALTIME_EFFECTS_API AllListsLock {
140 AllListsLock(RealtimeEffectManager *pManager = nullptr);
141 AllListsLock(AllListsLock &&other);
142 AllListsLock& operator= (AllListsLock &&other);
143 void Reset();
144 ~AllListsLock() { Reset(); }
145 };
146
147 void ProcessStart(bool suspended);
149 size_t Process(bool suspended, const Track &track,
150 float *const *buffers, float *const *scratch, float *dummy,
151 unsigned nBuffers, size_t numSamples);
152 void ProcessEnd(bool suspended) noexcept;
153
156
157 // Type that state visitor functions would have for out-of-line definition
158 // of VisitGroup and VisitAll
159 // using StateVisitor =
160 // std::function<void(RealtimeEffectState &state, bool listIsActive)> ;
161
163 template<typename StateVisitor>
164 void VisitGroup(Track &leader, const StateVisitor &func)
165 {
166 // Call the function for each effect on the master list
167 RealtimeEffectList::Get(mProject).Visit(func);
168
169 // Call the function for each effect on the track list
170 RealtimeEffectList::Get(leader).Visit(func);
171 }
172
173 template<typename StateVisitor>
174 void VisitGroup(const Track &leader, const StateVisitor &func)
175 {
176 // Call the function for each effect on the master list
177 RealtimeEffectList::Get(mProject).Visit(func);
178
179 // Call the function for each effect on the track list
180 RealtimeEffectList::Get(leader).Visit(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 track lists
192 for (auto leader : mGroupLeaders)
193 RealtimeEffectList::Get(*leader).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(), AddTrack(), Finalize()
204 // which are to be called only while there is no playback
205 std::vector<const Track *> mGroupLeaders;
206
207 std::unordered_map<const Track *, double> mRates;
208};
209
210namespace RealtimeEffects {
213public:
216 std::weak_ptr<AudacityProject> wProject, double sampleRate,
217 unsigned numPlaybackChannels
218 ) : mSampleRate{ sampleRate }
219 , mwProject{ move(wProject) }
220 , mNumPlaybackChannels{ numPlaybackChannels }
221 {
222 if (auto pProject = mwProject.lock())
223 RealtimeEffectManager::Get(*pProject).Initialize(*this, sampleRate);
224 }
228 {
229 if (auto pProject = mwProject.lock())
231 }
232
233 void AddTrack(const Track &track, unsigned chans, float rate)
234 {
235 if (auto pProject = mwProject.lock())
237 .AddTrack(*this, track, chans, rate);
238 }
239
240 std::vector<std::shared_ptr<EffectInstance>> mInstances;
243
244private:
245 std::weak_ptr<AudacityProject> mwProject;
246};
247
250public:
252 {
253 if (auto pProject = mwProject.lock()) {
254 auto &manager = RealtimeEffectManager::Get(*pProject);
255 mLocks = { &manager };
256 mSuspended = manager.GetSuspended();
257 }
258 }
261 std::weak_ptr<AudacityProject> wProject)
262 : mwProject{ move(wProject) }
263 {
264 if (auto pProject = mwProject.lock())
266 }
267 ProcessingScope( ProcessingScope &&other ) = default;
270 {
271 if (auto pProject = mwProject.lock())
273 }
274
276 size_t Process(const Track &track,
277 float *const *buffers,
278 float *const *scratch,
279 float *dummy,
280 unsigned nBuffers,
281 size_t numSamples
282 )
283 {
284 if (auto pProject = mwProject.lock())
285 return RealtimeEffectManager::Get(*pProject)
286 .Process(mSuspended, track, buffers, scratch, dummy,
287 nBuffers, numSamples);
288 else
289 return 0; // consider them trivially processed
290 }
291
292private:
294 std::weak_ptr<AudacityProject> mwProject;
296};
297}
298
299#endif
Utility ClientData::Site to register hooks into a host class that attach client data.
wxString PluginID
Definition: EffectManager.h:30
static RealtimeEffectState::EffectFactory::Scope scope
Inject a factory for realtime effects.
Definition: EffectUI.cpp:1560
Generalized interface for discovery of plug-ins for one protocol.
static const AttachedProjectObjects::RegisteredFactory manager
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(const Track &leader, const StateVisitor &func)
std::unordered_map< const Track *, double > mRates
void VisitAll(const StateVisitor &func)
Visit the per-project states first, then all tracks from AddTrack.
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 tracks for playback.
void ProcessStart(bool suspended)
size_t Process(bool suspended, const Track &track, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
void Finalize() noexcept
Main thread cleans up after playback.
RealtimeEffectManager & operator=(const RealtimeEffectManager &)=delete
void ProcessEnd(bool suspended) noexcept
std::vector< const Track * > mGroupLeaders
all are non-null
std::chrono::microseconds Latency
RealtimeEffectManager(const RealtimeEffectManager &)=delete
void AddTrack(RealtimeEffects::InitializationScope &scope, const Track &track, unsigned chans, float rate)
void VisitGroup(Track &leader, const StateVisitor &func)
Visit the per-project states first, then states for leader if not null.
Brackets processing setup and cleanup in the main thread.
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
void AddTrack(const Track &track, unsigned chans, float rate)
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 Track &track, float *const *buffers, float *const *scratch, float *dummy, unsigned nBuffers, size_t numSamples)
RealtimeEffectManager::AllListsLock mLocks
ProcessingScope(ProcessingScope &&other)=default
ProcessingScope(InitializationScope &, std::weak_ptr< AudacityProject > wProject)
Require a prior InializationScope to ensure correct nesting.
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:226
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:196
STL namespace.
A convenient default parameter for class template Site.
Definition: ClientData.h:28
Posted when effect is being added or removed to/from track or project.
std::shared_ptr< Track > track
null, if changes happened in the project scope