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 "Channel.h"
14
16{
17}
18
20{
21}
22
23// Deep copy of states
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{
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
57{
58 return Get(const_cast<AudacityProject &>(project));
59}
60
63{
65 {
66 return std::make_unique<RealtimeEffectList>();
67 }
68};
69
70// Access for per-group effect list
72{
73 return group.GetGroupData()
74 .Attachments::Get<RealtimeEffectList>(channelGroupEffects);
75}
76
78 const ChannelGroup &group)
79{
80 return Get(const_cast<ChannelGroup &>(group));
81}
82
83bool
84RealtimeEffectList::AddState(std::shared_ptr<RealtimeEffectState> pState)
85{
86 const auto &id = pState->GetID();
87 if (pState->GetEffect() != nullptr) {
88 auto shallowCopy = mStates;
89 shallowCopy.emplace_back(pState);
90 // Lock for only a short time
91 (LockGuard{ mLock }, swap(shallowCopy, mStates));
92
95 mStates.size() - 1,
96 { },
97 pState
98 });
99
100 return true;
101 }
102 else
103 // Effect initialization failed for the id
104 return false;
105}
106
107bool
109 std::shared_ptr<RealtimeEffectState> pState)
110{
111 if (index >= mStates.size())
112 return false;
113 const auto &id = pState->GetID();
114 if (pState->GetEffect() != nullptr) {
115 auto shallowCopy = mStates;
116
119 index,
120 { },
121 shallowCopy[index]
122 });
123
124 swap(pState, shallowCopy[index]);
125 // Lock for only a short time
126 (LockGuard{ mLock }, swap(shallowCopy, mStates));
127
130 index,
131 { },
132 pState
133 });
134
135 return true;
136 }
137 else
138 // Effect initialization failed for the id
139 return false;
140}
141
143 const std::shared_ptr<RealtimeEffectState> pState)
144{
145 auto shallowCopy = mStates;
146 auto end = shallowCopy.end(),
147 found = std::find(shallowCopy.begin(), end, pState);
148 if (found != end)
149 {
150 const auto index = std::distance(shallowCopy.begin(), found);
151 shallowCopy.erase(found);
152
153 // Lock for only a short time
154 (LockGuard{ mLock }, swap(shallowCopy, mStates));
155
158 static_cast<size_t>(index),
159 { },
160 pState
161 });
162 }
163}
164
166{
167 decltype(mStates) temp;
168
169 // Swap an empty list in as a whole, not removing one at a time
170 // Lock for only a short time
171 (LockGuard{ mLock }, swap(temp, mStates));
172
173 for (auto index = temp.size(); index--;)
175 { RealtimeEffectListMessage::Type::Remove, index, {}, temp[index] });
176}
177
178std::optional<size_t> RealtimeEffectList::FindState(
179 const std::shared_ptr<RealtimeEffectState> &pState) const
180{
181 const auto begin = mStates.begin()
182 , end = mStates.end()
183 , iter = std::find(begin, end, pState);
184 if (iter == end)
185 return {};
186 return std::distance(begin, iter);
187}
188
190{
191 return mStates.size();
192}
193
194std::shared_ptr<RealtimeEffectState>
195RealtimeEffectList::GetStateAt(size_t index) noexcept
196{
197 if (index < mStates.size())
198 return mStates[index];
199 return nullptr;
200}
201
202std::shared_ptr<const RealtimeEffectState>
203RealtimeEffectList::GetStateAt(size_t index) const noexcept
204{
205 return const_cast<RealtimeEffectList*>(this)->GetStateAt(index);
206}
207
208void RealtimeEffectList::MoveEffect(size_t fromIndex, size_t toIndex)
209{
210 assert(fromIndex < mStates.size());
211 assert(toIndex < mStates.size());
212
213 auto shallowCopy = mStates;
214 if(fromIndex == toIndex)
215 return;
216 if(fromIndex < toIndex)
217 {
218 const auto first = shallowCopy.begin() + fromIndex;
219 const auto last = shallowCopy.begin() + toIndex + 1;
220 std::rotate(first, first + 1, last);
221 }
222 else
223 {
224 const auto first =
225 shallowCopy.rbegin() + (shallowCopy.size() - (fromIndex + 1));
226 const auto last = shallowCopy.rbegin() + (shallowCopy.size() - toIndex);
227 std::rotate(first, first + 1, last);
228 }
229 // Lock for only a short time
230 (LockGuard{ mLock }, swap(shallowCopy, mStates));
231
234 fromIndex,
235 toIndex,
236 mStates[toIndex]
237 });
238}
239
240const std::string &RealtimeEffectList::XMLTag()
241{
242 static const std::string result{"effects"};
243 return result;
244}
245
246static constexpr auto activeAttribute = "active";
247
249 const std::string_view &tag, const AttributesList &attrs)
250{
251 if (tag == XMLTag()) {
252 for (auto &[attr, value] : attrs) {
253 if (attr == activeAttribute)
254 SetActive(value.Get<bool>());
255 }
256 return true;
257 }
258 return false;
259}
260
262{
263 if (tag == RealtimeEffectState::XMLTag()) {
265 return mStates.back().get();
266 }
267 return nullptr;
268}
269
271{
272 xmlFile.StartTag(XMLTag());
274 for (const auto & state : mStates)
275 state->WriteXML(xmlFile);
276 xmlFile.EndTag(XMLTag());
277}
278
280{
281 // Restore per-project states
282 Set(project, shared_from_this());
283}
284
286{
287 return mActive.load(std::memory_order_relaxed);
288}
289
291{
292 (LockGuard{ mLock }, mActive.store(value, std::memory_order_relaxed));
293}
294
296 [](AudacityProject &project) -> std::shared_ptr<UndoStateExtension> {
297 return RealtimeEffectList::Get(project).shared_from_this();
298 }
299};
Abstract class ChannelGroup with two discrete iterable dimensions, channels and intervals; subclasses...
wxString PluginID
static const ChannelGroup::Attachments::RegisteredFactory channelGroupEffects
static UndoRedoExtensionRegistry::Entry sEntry
static constexpr auto activeAttribute
static const AttachedProjectObjects::RegisteredFactory masterEffects
const auto project
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:90
ChannelGroupData & GetGroupData()
Make attachment site on demand as needed.
Definition: Channel.cpp:111
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:274
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.
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()
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:25
virtual void StartTag(const wxString &name)
Definition: XMLWriter.cpp:79
void WriteAttr(const wxString &name, const Identifier &value)
Definition: XMLWriter.h:36
virtual void EndTag(const wxString &name)
Definition: XMLWriter.cpp:102
template struct REGISTRIES_API Cloneable<>
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:645
void rotate(const float *oldPhase, const float *newPhase, std::complex< float > *dst, int32_t n)
Definition: VectorOps.h:140
@ 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:523
Typically statically constructed.
Definition: UndoManager.h:102