tracktion-engine 3.0-10-g034fdde4aa5
Tracktion Engine — High level data model for audio applications

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_PluginList.cpp
Go to the documentation of this file.
1 /*
2 ,--. ,--. ,--. ,--.
3 ,-' '-.,--.--.,--,--.,---.| |,-.,-' '-.`--' ,---. ,--,--, Copyright 2024
4 '-. .-'| .--' ,-. | .--'| /'-. .-',--.| .-. || \ Tracktion Software
5 | | | | \ '-' \ `--.| \ \ | | | |' '-' '| || | Corporation
6 `---' `--' `--`--'`---'`--'`--' `---' `--' `---' `--''--' www.tracktion.com
7
8 Tracktion Engine uses a GPL/commercial licence - see LICENCE.md for details.
9*/
10
11namespace tracktion { inline namespace engine
12{
13
14namespace
15{
16 bool isMasterList (PluginList& pl)
17 {
18 return pl.getOwnerTrack() == nullptr
19 || pl.getOwnerTrack() == pl.getEdit().getMasterTrack();
20 }
21}
22
24{
25 ObjectList (PluginList& l, const juce::ValueTree& parentTree)
26 : ValueTreeObjectList<Plugin> (parentTree), list (l)
27 {
28 // NB: rebuildObjects() is called after construction so that the edit has a valid
29 // list while they're being created
30 }
31
32 ~ObjectList() override
33 {
34 freeObjects();
35 }
36
37 bool isSuitableType (const juce::ValueTree& v) const override
38 {
39 return v.hasType (IDs::PLUGIN);
40 }
41
42 Plugin* createNewObject (const juce::ValueTree& v) override
43 {
44 if (auto p = list.edit.getPluginCache().getOrCreatePluginFor (v))
45 {
46 p->incReferenceCount();
47 p->trackPropertiesChanged();
48 return p.get();
49 }
50
51 return {};
52 }
53
54 void deleteObject (Plugin* p) override
55 {
56 jassert (p != nullptr);
57
58 if (! p->state.getParent().isValid())
59 p->deselect();
60
61 p->decReferenceCount();
62 }
63
64 void newObjectAdded (Plugin*) override {}
65 void objectRemoved (Plugin*) override {}
66 void objectOrderChanged() override {}
67 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override {}
68
69 PluginList& list;
70
72};
73
74//==============================================================================
75PluginList::PluginList (Edit& ed) : edit (ed)
76{
77}
78
79PluginList::~PluginList()
80{
81}
82
83void PluginList::initialise (const juce::ValueTree& v)
84{
85 jassert (v.hasType (IDs::MASTERPLUGINS)
86 || v.hasType (IDs::MASTERTRACK)
87 || v.hasType (IDs::TRACK)
88 || v.hasType (IDs::FOLDERTRACK)
89 || v.hasType (IDs::AUDIOCLIP)
90 || v.hasType (IDs::MIDICLIP)
91 || v.hasType (IDs::STEPCLIP)
92 || v.hasType (IDs::EDITCLIP)
93 || v.hasType (IDs::CONTAINERCLIP));
94
95 state = v;
96 list = std::make_unique<ObjectList> (*this, state);
97 callBlocking ([this] { list->rebuildObjects(); });
98}
99
100void PluginList::releaseObjects()
101{
102 list.reset();
103}
104
105juce::UndoManager* PluginList::getUndoManager() const
106{
107 return &edit.getUndoManager();
108}
109
110Plugin::Array PluginList::getPlugins() const
111{
112 Plugin::Array plugins;
113
114 if (list != nullptr)
115 for (auto p : list->objects)
116 plugins.add (p);
117
118 return plugins;
119}
120
121Plugin** PluginList::begin() const { return list == nullptr ? nullptr : list->objects.begin(); }
122Plugin** PluginList::end() const { return list == nullptr ? nullptr : list->objects.end(); }
123
124int PluginList::size() const
125{
126 if (list != nullptr)
127 return list->objects.size();
128
129 return 0;
130}
131
132Plugin* PluginList::operator[] (int index) const
133{
134 if (list != nullptr)
135 return list->objects[index];
136
137 return {};
138}
139
140bool PluginList::contains (const Plugin* plugin) const
141{
142 return indexOf (plugin) >= 0;
143}
144
145int PluginList::indexOf (const Plugin* plugin) const
146{
147 int i = 0;
148
149 for (auto p : *this)
150 {
151 if (p == plugin)
152 return i;
153
154 ++i;
155 }
156
157 return -1;
158}
159
160void PluginList::setTrackAndClip (Track* track, Clip* clip)
161{
162 ownerTrack = track;
163 ownerClip = clip;
164}
165
166void PluginList::updateTrackProperties()
167{
168 for (auto p : *this)
169 p->trackPropertiesChanged();
170}
171
172void PluginList::sendMirrorUpdateToAllPlugins (Plugin& plugin) const
173{
174 if (list != nullptr)
175 for (auto p : list->objects)
176 p->updateFromMirroredPluginIfNeeded (plugin);
177}
178
179bool PluginList::needsConstantBufferSize()
180{
181 if (list != nullptr)
182 for (auto f : list->objects)
183 if (f->needsConstantBufferSize())
184 return true;
185
186 return false;
187}
188
189bool PluginList::canInsertPlugin()
190{
191 const auto limits = edit.engine.getEngineBehaviour().getEditLimits();
192 return ! ((ownerClip != nullptr && size() >= limits.maxPluginsOnClip)
193 || (ownerTrack != nullptr && size() >= limits.maxPluginsOnTrack)
194 || (isMasterList (*this) && size() >= limits.maxNumMasterPlugins));
195}
196
197void PluginList::insertPlugin (const Plugin::Ptr& plugin, int index, SelectionManager* sm)
198{
199 if (plugin != nullptr)
200 {
201 jassert (plugin->state.isValid());
202
203 if (list == nullptr)
204 {
206 return;
207 }
208
209 if (auto newPlugin = insertPlugin (plugin->state, index))
210 {
211 jassert (plugin == newPlugin); // maybe caused by adding a plugin that wasn't created by this edit's pluginCache?
212 // Should use PluginCache::createNewPlugin to create the ones you add here
213
214 if (sm != nullptr)
215 sm->selectOnly (*newPlugin);
216 }
217 }
218}
219
220Plugin::Ptr PluginList::insertPlugin (const juce::ValueTree& v, int index)
221{
223
224 if (auto newPlugin = edit.getPluginCache().getOrCreatePluginFor (v))
225 {
226 if (list == nullptr)
227 {
229 return {};
230 }
231
232 if (auto ft = dynamic_cast<FolderTrack*> (ownerTrack))
233 {
234 if (! ft->willAcceptPlugin (*newPlugin))
235 {
236 edit.engine.getUIBehaviour().showWarningMessage (TRANS("Can't add this kind of plugin to a folder track"));
237 return {};
238 }
239 }
240
241 if ((ownerTrack == nullptr && ! newPlugin->canBeAddedToMaster()) ||
242 (ownerTrack != nullptr && ! ownerTrack->canContainPlugin (newPlugin.get())))
243 {
244 edit.engine.getUIBehaviour().showWarningMessage (TRANS("Can't add this kind of plugin to the master list"));
245 return {};
246 }
247
248 auto numPlugins = size();
249 const auto limits = edit.engine.getEngineBehaviour().getEditLimits();
250
251 if ((ownerClip != nullptr && numPlugins >= limits.maxPluginsOnClip)
252 || (ownerTrack != nullptr && numPlugins >= limits.maxPluginsOnTrack)
253 || (isMasterList (*this) && numPlugins >= limits.maxNumMasterPlugins))
254 {
256 return {};
257 }
258
259 int treeIndex = -1;
260
261 if (index < 0 || index >= numPlugins)
262 {
263 if (auto sibling = list->objects.getLast())
264 {
265 jassert (sibling->state.isAChildOf (state));
266 treeIndex = state.indexOf (sibling->state) + 1;
267 }
268 }
269 else
270 {
271 if (auto sibling = list->objects[index])
272 {
273 jassert (sibling->state.isAChildOf (state));
274 treeIndex = state.indexOf (sibling->state);
275 }
276 }
277
278 newPlugin->removeFromParent();
279
280 state.addChild (newPlugin->state, treeIndex, getUndoManager());
281 jassert (list->objects.contains (newPlugin.get()));
282
283 return newPlugin;
284 }
285
286 return {};
287}
288
289void PluginList::clear()
290{
291 for (int i = state.getNumChildren(); --i >= 0;)
292 if (state.getChild(i).hasType (IDs::PLUGIN))
293 state.removeChild (i, getUndoManager());
294}
295
296void PluginList::addPluginsFrom (const juce::ValueTree& v, bool clearFirst, bool atStart)
297{
298 if (clearFirst)
299 clear();
300
301 if (! v.isValid())
302 return;
303
304 int index = atStart ? 0 : -1;
305
306 for (int i = 0; i < v.getNumChildren(); ++i)
307 {
308 insertPlugin (v.getChild (i).createCopy(), index);
309 index += atStart ? 1 : 0;
310 }
311}
312
313void PluginList::addDefaultTrackPlugins (bool useVCA)
314{
315 jassert (list != nullptr);
316
317 if (useVCA)
318 {
319 insertPlugin (VCAPlugin::create(), -1);
320 }
321 else
322 {
323 insertPlugin (VolumeAndPanPlugin::create(), -1);
324 insertPlugin (LevelMeterPlugin::create(), -1);
325 }
326
327 if (edit.engine.getEngineBehaviour().arePluginsRemappedWhenTempoChanges())
328 {
329 if (auto vca = findFirstPluginOfType<VCAPlugin>())
330 vca->remapOnTempoChange = true;
331
332 if (auto vp = findFirstPluginOfType<VolumeAndPanPlugin>())
333 vp->remapOnTempoChange = true;
334 }
335}
336
337}} // namespace tracktion { inline namespace engine
bool isValid() const noexcept
bool hasType(const Identifier &typeName) const noexcept
void removeChild(const ValueTree &child, UndoManager *undoManager)
ValueTree getChild(int index) const
int getNumChildren() const noexcept
int indexOf(const ValueTree &child) const noexcept
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
The Tracktion Edit class!
PluginCache & getPluginCache() noexcept
Returns the PluginCache which manages all active Plugin[s] for this Edit.
juce::UndoManager & getUndoManager() noexcept
Returns the juce::UndoManager used for this Edit.
Engine & engine
A reference to the Engine.
virtual EditLimits getEditLimits()
Should return the maximum number of elements that can be added to an Edit.
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
EngineBehaviour & getEngineBehaviour() const
Returns the EngineBehaviour instance.
Holds a sequence of plugins.
virtual bool canContainPlugin(Plugin *) const =0
Returns true if this track can contain a specific Plugin.
virtual void showWarningMessage(const juce::String &message)
Should display a temporary warning message.
T is_pointer_v
#define TRANS(stringLiteral)
#define jassert(expression)
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
#define jassertfalse
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.