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 AUDACITY_DLL_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 Track &track, unsigned chans, float rate);
135 void Finalize() noexcept;
136
137 friend RealtimeEffects::ProcessingScope;
140 AllListsLock(RealtimeEffectManager *pManager = nullptr);
141 AllListsLock(AllListsLock &&other);
143 void Reset();
144 ~AllListsLock() { Reset(); }
145 };
146
147 void ProcessStart(bool suspended);
149 size_t Process(bool suspended, Track &track,
150 float *const *buffers, float *const *scratch,
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
174
175 template<typename StateVisitor>
176 void VisitAll(const StateVisitor &func)
177 {
178 // Call the function for each effect on the master list
179 RealtimeEffectList::Get(mProject).Visit(func);
180
181 // And all track lists
182 for (auto leader : mGroupLeaders)
183 RealtimeEffectList::Get(*leader).Visit(func);
184 }
185
187 Latency mLatency{ 0 };
188
189 std::atomic<bool> mSuspended{ true };
190
191 bool mActive{ false };
192
193 // This member is mutated only by Initialize(), AddTrack(), Finalize()
194 // which are to be called only while there is no playback
195 std::vector<Track *> mGroupLeaders;
196
197 std::unordered_map<Track *, unsigned> mChans;
198 std::unordered_map<Track *, double> mRates;
199};
200
201namespace RealtimeEffects {
204public:
207 std::weak_ptr<AudacityProject> wProject, double sampleRate)
208 : mSampleRate{ sampleRate }
209 , mwProject{ move(wProject) }
210 {
211 if (auto pProject = mwProject.lock())
212 RealtimeEffectManager::Get(*pProject).Initialize(*this, sampleRate);
213 }
217 {
218 if (auto pProject = mwProject.lock())
220 }
221
222 void AddTrack(Track &track, unsigned chans, float rate)
223 {
224 if (auto pProject = mwProject.lock())
226 .AddTrack(*this, track, chans, rate);
227 }
228
229 std::vector<std::shared_ptr<EffectInstance>> mInstances;
231
232private:
233 std::weak_ptr<AudacityProject> mwProject;
234};
235
238public:
240 {
241 if (auto pProject = mwProject.lock()) {
242 auto &manager = RealtimeEffectManager::Get(*pProject);
243 mLocks = { &manager };
244 mSuspended = manager.GetSuspended();
245 }
246 }
249 std::weak_ptr<AudacityProject> wProject)
250 : mwProject{ move(wProject) }
251 {
252 if (auto pProject = mwProject.lock())
254 }
255 ProcessingScope( ProcessingScope &&other ) = default;
258 {
259 if (auto pProject = mwProject.lock())
261 }
262
263 size_t Process(Track &track,
264 float *const *buffers,
265 float *const *scratch,
266 unsigned nBuffers,
267 size_t numSamples
268 )
269 {
270 if (auto pProject = mwProject.lock())
271 return RealtimeEffectManager::Get(*pProject)
272 .Process(mSuspended, track, buffers, scratch,
273 nBuffers, numSamples);
274 else
275 return numSamples; // consider them trivially processed
276 }
277
278private:
280 std::weak_ptr<AudacityProject> mwProject;
282};
283}
284
285#endif
Utility ClientData::Site to register hooks into a host class that attach client data.
static TransactionScope::Factory::Scope scope
wxString PluginID
Definition: EffectManager.h:30
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:89
Performs effect computation.
An object that sends messages to an open-ended list of subscribed callbacks.
Definition: Observer.h:108
Publisher & operator=(Publisher &&)=default
void Visit(const StateVisitor &func)
Apply the function to all states sequentially.
static RealtimeEffectList & Get(AudacityProject &project)
std::unordered_map< Track *, double > mRates
std::vector< Track * > mGroupLeaders
all are non-null
void VisitAll(const StateVisitor &func)
Visit the per-project states first, then all tracks from AddTrack.
size_t Process(bool suspended, Track &track, float *const *buffers, float *const *scratch, unsigned nBuffers, size_t numSamples)
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)
void Finalize() noexcept
Main thread cleans up after playback.
std::unordered_map< Track *, unsigned > mChans
RealtimeEffectManager & operator=(const RealtimeEffectManager &)=delete
void ProcessEnd(bool suspended) noexcept
void AddTrack(RealtimeEffects::InitializationScope &scope, Track &track, unsigned chans, float rate)
std::chrono::microseconds Latency
RealtimeEffectManager(const RealtimeEffectManager &)=delete
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.
void AddTrack(Track &track, unsigned chans, float rate)
InitializationScope(std::weak_ptr< AudacityProject > wProject, double sampleRate)
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
RealtimeEffectManager::AllListsLock mLocks
size_t Process(Track &track, float *const *buffers, float *const *scratch, unsigned nBuffers, size_t numSamples)
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:225
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
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