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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_RackInstance.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
15{
17 Plugin& owner, juce::Range<float> valueRangeToUse)
18 : AutomatableParameter (xmlTag, name, owner, valueRangeToUse)
19 {
20 }
21
23 {
24 notifyListenersOfDeletion();
25 }
26
27 bool isParameterActive() const override
28 {
29 if (auto rp = dynamic_cast<RackInstance*> (plugin))
30 return ! rp->linkInputs;
31
32 return false;
33 }
34};
35
37{
39 Plugin& owner, juce::Range<float> valueRangeToUse)
40 : AutomatableParameter (xmlTag, name, owner, valueRangeToUse)
41 {
42 }
43
45 {
46 notifyListenersOfDeletion();
47 }
48
49 bool isParameterActive() const override
50 {
51 if (auto rp = dynamic_cast<RackInstance*> (plugin))
52 return ! rp->linkOutputs;
53
54 return false;
55 }
56};
57
59{
60 RackWetDryAutomatableParam (const juce::String& xmlTag, const juce::String& name,
61 RackInstance& owner, juce::Range<float> valueRangeToUse)
62 : AutomatableParameter (xmlTag, name, owner, valueRangeToUse)
63 {
64 }
65
67 {
68 notifyListenersOfDeletion();
69 }
70
71 juce::String valueToString (float value) override { return juce::Decibels::toString (juce::Decibels::gainToDecibels (value), 1); }
72 float stringToValue (const juce::String& s) override { return dbStringToDb (s); }
73};
74
75//==============================================================================
76RackInstance::RackInstance (PluginCreationInfo info)
77 : Plugin (info),
78 rackTypeID (EditItemID::fromProperty (state, IDs::rackType)),
79 type (info.edit.getRackList().getRackTypeForID (rackTypeID))
80{
81 jassert (type != nullptr);
82
83 addAutomatableParameter (dryGain = new RackWetDryAutomatableParam ("dry level", TRANS("Dry level"), *this, { 0.0f, 1.0f }));
84 addAutomatableParameter (wetGain = new RackWetDryAutomatableParam ("wet level", TRANS("Wet level"), *this, { 0.0f, 1.0f }));
85 leftInDb = addParam ("left input level", TRANS("Left input level"), { (float) RackInstance::rackMinDb, (float) RackInstance::rackMaxDb });
86 addAutomatableParameter (rightInDb = new RackInputAutomatableParameter ("right input level", TRANS("Right input level"), *this, { (float) RackInstance::rackMinDb, (float) RackInstance::rackMaxDb }));
87 leftOutDb = addParam ("left output level", TRANS("Left output level"), { (float) RackInstance::rackMinDb, (float) RackInstance::rackMaxDb });
88 addAutomatableParameter (rightOutDb = new RackOutputAutomatableParameter ("right output level", TRANS("Right output level"), *this, { (float) RackInstance::rackMinDb, (float) RackInstance::rackMaxDb }));
89
90 auto um = getUndoManager();
91
92 dryValue.referTo (state, IDs::dry, um);
93 wetValue.referTo (state, IDs::wet, um, 1.0f);
94 leftInValue.referTo (state, IDs::leftInDb, um);
95 rightInValue.referTo (state, IDs::rightInDb, um);
96 leftOutValue.referTo (state, IDs::leftOutDb, um);
97 rightOutValue.referTo (state, IDs::rightOutDb, um);
98
99 leftInputGoesTo.referTo (state, IDs::leftTo, um, 1);
100 rightInputGoesTo.referTo (state, IDs::rightTo, um, 2);
101 leftOutputComesFrom.referTo (state, IDs::leftFrom, um, 1);
102 rightOutputComesFrom.referTo (state, IDs::rightFrom, um, 2);
103
104 dryGain->attachToCurrentValue (dryValue);
105 wetGain->attachToCurrentValue (wetValue);
106 leftInDb->attachToCurrentValue (leftInValue);
107 rightInDb->attachToCurrentValue (rightInValue);
108 leftOutDb->attachToCurrentValue (leftOutValue);
109 rightOutDb->attachToCurrentValue (rightOutValue);
110}
111
112RackInstance::~RackInstance()
113{
114 notifyListenersOfDeletion();
115
116 dryGain->detachFromCurrentValue();
117 wetGain->detachFromCurrentValue();
118 leftInDb->detachFromCurrentValue();
119 rightInDb->detachFromCurrentValue();
120 leftOutDb->detachFromCurrentValue();
121 rightOutDb->detachFromCurrentValue();
122}
123
124juce::ValueTree RackInstance::create (RackType& type)
125{
126 return createValueTree (IDs::PLUGIN,
127 IDs::type, RackInstance::xmlTypeName,
128 IDs::rackType, type.rackID);
129}
130
132{
133 if (engine.getPluginManager().doubleClickToOpenWindows())
134 return getName() + " (" + TRANS("Double-click to edit the rack") + ")";
135
136 return getName() + " (" + TRANS("Click to edit the rack") + ")";
137}
138
139const char* RackInstance::xmlTypeName = "rack";
140
142{
143 return type != nullptr ? type->rackName
144 : TRANS("Rack type missing!");
145}
146
147void RackInstance::replaceRackWithPluginSequence (SelectionManager* sm)
148{
149 if (RackType::Ptr thisType = type) // (keep a local reference)
150 {
151 const bool replaceRack = getRackInstancesInEditForType (*type).size() == 1;
152 jassert (! replaceRack || getRackInstancesInEditForType (*type).getFirst() == this);
153
154 struct PluginIndexAndPos
155 {
156 bool operator< (const PluginIndexAndPos& other) const { return x < other.x; }
157
158 float x = 0.0f;
159 Plugin* plugin = nullptr;
160 };
161
162 auto rackPlugins = thisType->getPlugins();
163 juce::Array<PluginIndexAndPos> pluginLocations;
164
165 for (int i = 0; i < rackPlugins.size(); ++i)
166 if (auto rackPlugin = rackPlugins[i])
167 pluginLocations.add ({ thisType->getPluginPosition (rackPlugin).x, rackPlugin });
168
169 std::sort (pluginLocations.begin(), pluginLocations.end());
170
171 if (auto list = getOwnerList())
172 {
173 auto index = list->getPlugins().indexOf (this);
174
175 for (int i = pluginLocations.size(); --i >= 0;)
176 {
177 auto srcPlugin = pluginLocations.getUnchecked (i).plugin;
178 jassert (srcPlugin != nullptr);
179 srcPlugin->flushPluginStateToValueTree();
180 auto pluginState = srcPlugin->state;
181
182 if (! replaceRack)
183 {
184 auto newState = srcPlugin->state.createCopy();
185 EditItemID::remapIDs (newState, nullptr, edit);
186 jassert (EditItemID::fromID (newState) != EditItemID::fromID (srcPlugin->state));
187 pluginState = newState;
188 }
189
190 if (auto p = list->insertPlugin (pluginState, index))
191 if (sm != nullptr)
192 sm->selectOnly (*p);
193 }
194
196
197 if (replaceRack)
198 edit.getRackList().removeRackType (thisType);
199 }
200 else
201 {
202 engine.getUIBehaviour().showWarningMessage (TRANS("Unable to replace rack with plugins"));
203 }
204 }
205}
206
207juce::StringArray RackInstance::getInputChoices (bool includeNumberPrefix)
208{
209 juce::StringArray inputChoices;
210
211 if (type != nullptr)
212 {
213 inputChoices.add (getNoPinName());
214 auto inputs = type->getInputNames();
215
216 for (int i = 1; i < inputs.size(); ++i)
217 {
218 if (includeNumberPrefix)
219 inputChoices.add (juce::String (i) + ". " + inputs[i]);
220 else
221 inputChoices.add (inputs[i]);
222 }
223 }
224
225 return inputChoices;
226}
227
228juce::StringArray RackInstance::getOutputChoices (bool includeNumberPrefix)
229{
230 juce::StringArray outputChoices;
231
232 if (type != nullptr)
233 {
234 outputChoices.add (getNoPinName());
235 auto outputs = type->getOutputNames();
236
237 for (int i = 1; i < outputs.size(); ++i)
238 {
239 if (includeNumberPrefix)
240 outputChoices.add (juce::String (i) + ". " + outputs[i]);
241 else
242 outputChoices.add (outputs[i]);
243 }
244 }
245
246 return outputChoices;
247}
248
249juce::String RackInstance::getNoPinName()
250{
251 return TRANS("<none>");
252}
253
254void RackInstance::setInputName (Channel c, const juce::String& inputName)
255{
256 auto index = getInputChoices (false).indexOf (inputName);
257
258 if (index == -1)
259 return;
260
261 if (index == 0)
262 index = -1;
263
264 switch (c)
265 {
266 case left: leftInputGoesTo = index; break;
267 case right: rightInputGoesTo = index; break;
268 default: break;
269 }
270}
271
272void RackInstance::setOutputName (Channel c, const juce::String& outputName)
273{
274 auto index = getOutputChoices (false).indexOf (outputName);
275
276 if (index == -1)
277 return;
278
279 if (index == 0)
280 index = -1;
281
282 switch (c)
283 {
284 case left: leftOutputComesFrom = index; break;
285 case right: rightOutputComesFrom = index; break;
286 default: break;
287 }
288}
289
290void RackInstance::initialise (const PluginInitialisationInfo& info)
291{
292 if (type != nullptr)
293 type->registerInstance (this, info);
294}
295
297{
298 if (type != nullptr)
299 type->deregisterInstance (this);
300}
301
303{
305
306 if (type != nullptr)
307 type->updateAutomatableParamPositions (time);
308}
309
310double RackInstance::getLatencySeconds()
311{
312 return 0.0;
313}
314
318
322
324{
325 return TRANS("Plugin Rack");
326}
327
328void RackInstance::setInputLevel (Channel c, float v)
329{
330 const auto& param = c == left ? leftInDb : rightInDb;
331
332 param->setParameter (v, juce::sendNotification);
333
334 if (linkInputs)
335 {
336 const auto& linkedParam = c == left ? rightInDb : leftInDb;
337 linkedParam->setParameter (v, juce::sendNotification);
338 }
339}
340
341void RackInstance::setOutputLevel (Channel c, float v)
342{
343 const auto& param = c == left ? leftOutDb : rightOutDb;
344
345 param->setParameter (v, juce::sendNotification);
346
347 if (linkOutputs)
348 {
349 const auto& linkedParam = c == left ? rightOutDb : leftOutDb;
350 linkedParam->setParameter (v, juce::sendNotification);
351 }
352}
353
354juce::String RackInstance::getInputName (Channel c)
355{
356 const auto& input = c == left ? leftInputGoesTo : rightInputGoesTo;
357
358 if (type == nullptr || input < 0 || type->getInputNames()[input].isEmpty())
359 return getNoPinName();
360
361 return juce::String (input) + ". " + type->getInputNames()[input];
362}
363
364juce::String RackInstance::getOutputName (Channel c)
365{
366 const auto& ouput = c == left ? leftOutputComesFrom : rightOutputComesFrom;
367
368 if (type == nullptr || ouput < 0 || type->getOutputNames()[ouput].isEmpty())
369 return getNoPinName();
370
371 return juce::String (ouput) + ". " + type->getOutputNames()[ouput];
372}
373
374}} // namespace tracktion { inline namespace engine
ElementType getUnchecked(int index) const
int size() const noexcept
ElementType * begin() noexcept
ElementType * end() noexcept
void add(const ElementType &newElement)
static Type gainToDecibels(Type gain, Type minusInfinityDb=Type(defaultMinusInfinitydB))
static String toString(Type decibels, int decimalPlaces=2, Type minusInfinityDb=Type(defaultMinusInfinitydB), bool shouldIncludeSuffix=true, StringRef customMinusInfinityString={})
int indexOf(StringRef stringToLookFor, bool ignoreCase=false, int startIndex=0) const
void add(String stringToAdd)
virtual void updateAutomatableParamPosition(TimePosition)
Updates all the auto params to their positions at this time.
RackTypeList & getRackList() const noexcept
Returns the RackTypeList which contains all the RackTypes for the Edit.
UIBehaviour & getUIBehaviour() const
Returns the UIBehaviour class.
PluginManager & getPluginManager() const
Returns the PluginManager instance.
virtual void deleteFromParent()
Attempts to delete this plugin, whether it's a master plugin, track plugin, etc.
juce::String getSelectableDescription() override
Subclasses must return a description of what they are.
void applyToBuffer(const PluginRenderContext &) override
Process the next block of data.
juce::String getTooltip() override
default returns the name, others can return special stuff if needed
void prepareForNextBlock(TimePosition) override
Called between successive rendering blocks.
juce::String getName() const override
The name of the type, e.g.
void deinitialise() override
Called after play stops to release resources.
void updateAutomatableParamPosition(TimePosition) override
Updates all the auto params to their positions at this time.
Manages a list of items that are currently selected.
virtual void showWarningMessage(const juce::String &message)
Should display a temporary warning message.
#define TRANS(stringLiteral)
#define jassert(expression)
typedef float
sendNotification
juce::Array< RackInstance * > getRackInstancesInEditForType(const RackType &rt)
Returns all of the instances of a specific RackType in an Edit.
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
T sort(T... args)
Represents a position in real-life time.
ID for objects of type EditElement - e.g.
The context passed to plugin render methods to provide it with buffers to fill.
time