Audacity 3.2.0
RealtimeEffectList.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 RealtimeEffectList.cpp
6
7 *********************************************************************/
8
10#include "RealtimeEffectState.h"
11
12#include "Project.h"
13#include "Track.h"
14
16{
17}
18
20{
21}
22
23// Deep copy of states
24std::unique_ptr<ClientData::Cloneable<>> RealtimeEffectList::Clone() const
25{
26 auto result = std::make_unique<RealtimeEffectList>();
27 for (auto &pState : mStates)
28 result->mStates.push_back(pState);
29 result->SetActive(this->IsActive());
30 return result;
31}
32
33// Access for per-project effect list
35{
36 [](AudacityProject &project)
37 {
38 return std::make_shared<RealtimeEffectList>();
39 }
40};
41
43{
44 return project.AttachedObjects::Get<RealtimeEffectList>(masterEffects);
45}
46
48 AudacityProject &project, const std::shared_ptr<RealtimeEffectList> &list)
49{
50 auto &result = *list;
51 project.AttachedObjects::Assign(masterEffects, list);
52 return result;
53}
54
56{
57 return Get(const_cast<AudacityProject &>(project));
58}
59
61{
63 {
64 return std::make_unique<RealtimeEffectList>();
65 }
66};
67
68// Access for per-track effect list
70{
71 return track.GetGroupData()
72 .Track::ChannelGroupAttachments::Get<RealtimeEffectList>(trackEffects);
73}
74
76{
77 return Get(const_cast<Track &>(track));
78}
79
80bool
81RealtimeEffectList::AddState(std::shared_ptr<RealtimeEffectState> pState)
82{
83 const auto &id = pState->GetID();
84 if (pState->GetEffect() != nullptr) {
85 auto shallowCopy = mStates;
86 shallowCopy.emplace_back(pState);
87 // Lock for only a short time
88 (LockGuard{ mLock }, swap(shallowCopy, mStates));
89
92 mStates.size() - 1,
93 { },
94 pState
95 });
96
97 return true;
98 }
99 else
100 // Effect initialization failed for the id
101 return false;
102}
103
104bool
106 std::shared_ptr<RealtimeEffectState> pState)
107{
108 if (index >= mStates.size())
109 return false;
110 const auto &id = pState->GetID();
111 if (pState->GetEffect() != nullptr) {
112 auto shallowCopy = mStates;
113
116 index,
117 { },
118 shallowCopy[index]
119 });
120
121 swap(pState, shallowCopy[index]);
122 // Lock for only a short time
123 (LockGuard{ mLock }, swap(shallowCopy, mStates));
124
127 index,
128 { },
129 pState
130 });
131
132 return true;
133 }
134 else
135 // Effect initialization failed for the id
136 return false;
137}
138
140 const std::shared_ptr<RealtimeEffectState> pState)
141{
142 auto shallowCopy = mStates;
143 auto end = shallowCopy.end(),
144 found = std::find(shallowCopy.begin(), end, pState);
145 if (found != end)
146 {
147 const auto index = std::distance(shallowCopy.begin(), found);
148 shallowCopy.erase(found);
149
150 // Lock for only a short time
151 (LockGuard{ mLock }, swap(shallowCopy, mStates));
152
155 static_cast<size_t>(index),
156 { },
157 pState
158 });
159 }
160}
161
163{
164 decltype(mStates) temp;
165
166 // Swap an empty list in as a whole, not removing one at a time
167 // Lock for only a short time
168 (LockGuard{ mLock }, swap(temp, mStates));
169
170 for (auto index = temp.size(); index--;)
172 { RealtimeEffectListMessage::Type::Remove, index, {}, temp[index] });
173}
174
175std::optional<size_t> RealtimeEffectList::FindState(
176 const std::shared_ptr<RealtimeEffectState> &pState) const
177{
178 const auto begin = mStates.begin()
179 , end = mStates.end()
180 , iter = std::find(begin, end, pState);
181 if (iter == end)
182 return {};
183 return std::distance(begin, iter);
184}
185
187{
188 return mStates.size();
189}
190
191std::shared_ptr<RealtimeEffectState>
192RealtimeEffectList::GetStateAt(size_t index) noexcept
193{
194 if (index < mStates.size())
195 return mStates[index];
196 return nullptr;
197}
198
199std::shared_ptr<const RealtimeEffectState>
200RealtimeEffectList::GetStateAt(size_t index) const noexcept
201{
202 return const_cast<RealtimeEffectList*>(this)->GetStateAt(index);
203}
204
205void RealtimeEffectList::MoveEffect(size_t fromIndex, size_t toIndex)
206{
207 assert(fromIndex < mStates.size());
208 assert(toIndex < mStates.size());
209
210 auto shallowCopy = mStates;
211 if(fromIndex == toIndex)
212 return;
213 if(fromIndex < toIndex)
214 {
215 const auto first = shallowCopy.begin() + fromIndex;
216 const auto last = shallowCopy.begin() + toIndex + 1;
217 std::rotate(first, first + 1, last);
218 }
219 else
220 {
221 const auto first = shallowCopy.rbegin() + (shallowCopy.size() - (fromIndex + 1));
222 const auto last = shallowCopy.rbegin() + (shallowCopy.size() - toIndex);
223 std::rotate(first, first + 1, last);
224 }
225 // Lock for only a short time
226 (LockGuard{ mLock }, swap(shallowCopy, mStates));
227
230 fromIndex,
231 toIndex,
232 mStates[toIndex]
233 });
234}
235
236const std::string &RealtimeEffectList::XMLTag()
237{
238 static const std::string result{"effects"};
239 return result;
240}
241
242static constexpr auto activeAttribute = "active";
243
245 const std::string_view &tag, const AttributesList &attrs)
246{
247 if (tag == XMLTag()) {
248 for (auto &[attr, value] : attrs) {
249 if (attr == activeAttribute)
250 SetActive(value.Get<bool>());
251 }
252 return true;
253 }
254 return false;
255}
256
258{
259 if (tag == RealtimeEffectState::XMLTag()) {
261 return mStates.back().get();
262 }
263 return nullptr;
264}
265
267{
268 xmlFile.StartTag(XMLTag());
270 for (const auto & state : mStates)
271 state->WriteXML(xmlFile);
272 xmlFile.EndTag(XMLTag());
273}
274
276{
277 // Restore per-project states
278 Set(project, shared_from_this());
279}
280
282{
283 return mActive.load(std::memory_order_relaxed);
284}
285
287{
288 (LockGuard{ mLock }, mActive.store(value, std::memory_order_relaxed));
289}
290
292 [](AudacityProject &project) -> std::shared_ptr<UndoStateExtension> {
293 return RealtimeEffectList::Get(project).shared_from_this();
294 }
295};
wxString PluginID
Definition: EffectManager.h:30
static const Track::ChannelGroupAttachments::RegisteredFactory trackEffects
static UndoRedoExtensionRegistry::Entry sEntry
static constexpr auto activeAttribute
static const AttachedProjectObjects::RegisteredFactory masterEffects
declares abstract base class Track, TrackList, and iterators over TrackList
std::vector< Attribute > AttributesList
Definition: XMLTagHandler.h:40
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:266
CallbackReturn Publish(const RealtimeEffectListMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
static RealtimeEffectList & Get(AudacityProject &project)
std::optional< size_t > FindState(const std::shared_ptr< RealtimeEffectState > &pState) const
Report the position of a state in the list.
std::lock_guard< Lock > LockGuard
bool AddState(std::shared_ptr< RealtimeEffectState > pState)
void RestoreUndoRedoState(AudacityProject &project) noexcept override
Modify the project when undoing or redoing to some state in history.
std::unique_ptr< ClientData::Cloneable<> > Clone() const override
size_t GetStatesCount() const noexcept
bool IsActive() const
Non-blocking atomic boolean load.
static const RealtimeEffectList & Get(const Track &track)
void RemoveState(std::shared_ptr< RealtimeEffectState > pState)
void Clear()
Use only in the main thread. Sends Remove messages.
std::atomic< bool > mActive
bool HandleXMLTag(const std::string_view &tag, const AttributesList &attrs) override
void SetActive(bool value)
Done by main thread only, under a lock guard.
static RealtimeEffectList & Set(AudacityProject &project, const std::shared_ptr< RealtimeEffectList > &list)
static const std::string & XMLTag()
XMLTagHandler * HandleXMLChild(const std::string_view &tag) override
Use only in the main thread. May add a state while deserializing.
void WriteXML(XMLWriter &xmlFile) const
Use only in the main thread, to avoid races.
void MoveEffect(size_t fromIndex, size_t toIndex)
Use only in the main thread. Changes effect order in the stack. Does nothing if fromIndex equals toIn...
bool ReplaceState(size_t index, std::shared_ptr< RealtimeEffectState > pState)
std::shared_ptr< RealtimeEffectState > GetStateAt(size_t index) noexcept
static const std::string & XMLTag()
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
ChannelGroupData & GetGroupData()
Definition: Track.cpp:179
This class is an interface which should be implemented by classes which wish to be able to load and s...
Definition: XMLTagHandler.h:42
Base class for XMLFileWriter and XMLStringWriter that provides the general functionality for creating...
Definition: XMLWriter.h:26
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:80
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:37
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:103
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:753
@ Remove
Effect item was removed from the list at srcIndex position. affectedState is removed state.
@ DidReplace
Effect item was replaced with a new item at srcIndex position. affectedState is an old state.
@ Move
Item position has changed, from srcIndex to dstIndex. affectedState is the moved state.
@ Insert
New effect item was added to the list at srcIndex position. affectedState is a new state.
@ WillReplace
Effect item will be replaced with a new item at srcIndex position. affectedState is the state to be r...
static std::shared_ptr< RealtimeEffectState > make_shared(Args &&...args)
Definition: MemoryX.h:505
Typically statically constructed.
Definition: UndoManager.h:107