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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_Plugin.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
14PluginRenderContext::PluginRenderContext (juce::AudioBuffer<float>* buffer,
15 const juce::AudioChannelSet& bufferChannels,
16 int bufferStart, int bufferSize,
17 MidiMessageArray* midiBuffer, double midiOffset,
18 TimeRange editTimeRange, bool playing, bool scrubbing, bool rendering,
19 bool shouldAllowBypassedProcessing) noexcept
20 : destBuffer (buffer), destBufferChannels (bufferChannels),
21 bufferStartSample (bufferStart), bufferNumSamples (bufferSize),
22 bufferForMidiMessages (midiBuffer), midiBufferOffset (midiOffset),
23 editTime (editTimeRange),
24 isPlaying (playing), isScrubbing (scrubbing), isRendering (rendering),
25 allowBypassedProcessing (shouldAllowBypassedProcessing)
26{}
27
28//==============================================================================
29Plugin::Wire::Wire (const juce::ValueTree& v, juce::UndoManager* um) : state (v)
30{
31 sourceChannelIndex.referTo (state, IDs::srcChan, um);
32 destChannelIndex.referTo (state, IDs::dstChan, um);
33}
34
35struct Plugin::WireList : public ValueTreeObjectList<Plugin::Wire, juce::CriticalSection>,
36 private juce::AsyncUpdater
37{
38 WireList (Plugin& p, const juce::ValueTree& parentTree)
40 {
41 rebuildObjects();
42 }
43
44 ~WireList() override
45 {
46 freeObjects();
47 }
48
49 bool isSuitableType (const juce::ValueTree& v) const override { return v.hasType (IDs::SIDECHAINCONNECTION); }
50 Wire* createNewObject (const juce::ValueTree& v) override { return new Wire (v, plugin.getUndoManager()); }
51 void deleteObject (Wire* w) override { delete w; }
52
53 void newObjectAdded (Wire*) override { triggerAsyncUpdate(); }
54 void objectRemoved (Wire*) override { triggerAsyncUpdate(); }
55 void objectOrderChanged() override {}
56 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override { triggerAsyncUpdate(); }
57
58 void handleAsyncUpdate() override { plugin.changed(); }
59
60 Plugin& plugin;
61};
62
63
64//==============================================================================
65Plugin::WindowState::WindowState (Plugin& p) : PluginWindowState (p.edit), plugin (p) {}
66
67//==============================================================================
68Plugin::Plugin (PluginCreationInfo info)
69 : AutomatableEditItem (info.edit, info.state),
70 MacroParameterElement (info.edit, info.state),
71 engine (info.edit.engine),
72 state (info.state)
73{
74 isClipEffect = state.getParent().hasType (IDs::EFFECT);
75 windowState = std::make_unique<WindowState> (*this);
76
77 jassert (state.isValid());
78
79 auto um = getUndoManager();
80
81 auto wires = state.getChildWithName (IDs::SIDECHAINCONNECTIONS);
82
83 if (wires.isValid())
84 sidechainWireList = std::make_unique<WireList> (*this, wires);
85
86 enabled.referTo (state, IDs::enabled, um, true);
87
88 if (enabled.isUsingDefault())
89 enabled = enabled.getDefault();
90
91 processing.referTo (state, IDs::process, um, true);
92 frozen.referTo (state, IDs::frozen, um);
93 quickParamName.referTo (state, IDs::quickParamName, um);
94 masterPluginID.referTo (state, IDs::masterPluginID, um);
95 sidechainSourceID.referTo (state, IDs::sidechainSourceID, um);
96
97 state.addListener (this);
98
99 #if TRACKTION_ENABLE_AUTOMAP && TRACKTION_ENABLE_CONTROL_SURFACES
100 if (! edit.isLoading())
101 {
102 auto& e = engine;
103
104 juce::MessageManager::callAsync ([ref = makeSafeRef (*this), &e]() mutable
105 {
106 if (auto plugin = ref.get())
107 if (auto na = e.getExternalControllerManager().getAutomap())
108 na->pluginChanged (plugin);
109 });
110 }
111 #endif
112
113 windowState->windowLocked = state [IDs::windowLocked];
114
115 if (state.hasProperty (IDs::windowX))
116 windowState->lastWindowBounds = juce::Rectangle<int> (state[IDs::windowX],
117 state[IDs::windowY], 1, 1);
118}
119
120Plugin::~Plugin()
121{
123 windowState->hideWindowForShutdown();
124
125 #if TRACKTION_ENABLE_AUTOMAP && TRACKTION_ENABLE_CONTROL_SURFACES
126 if (auto na = engine.getExternalControllerManager().getAutomap())
127 na->removePlugin (this);
128 #endif
129}
130
132{
133 // Remove ths listener in case the tree gets modified during descruction
134 state.removeListener (this);
135
136 quickControlParameter = nullptr;
137 deleteAutomatableParameters();
138}
139
141{
143 getChannelNames (nullptr, &outs);
144 return outs.size();
145}
146
147int Plugin::getNumWires() const
148{
149 if (sidechainWireList != nullptr)
150 return sidechainWireList->objects.size();
151
152 return 0;
153}
154
155Plugin::Wire* Plugin::getWire (int index) const
156{
157 if (sidechainWireList != nullptr)
158 return sidechainWireList->objects[index];
159
160 return {};
161}
162
163juce::ValueTree Plugin::getConnectionsTree()
164{
165 auto p = state.getChildWithName (IDs::SIDECHAINCONNECTIONS);
166
167 if (p.isValid())
168 return p;
169
170 p = juce::ValueTree (IDs::SIDECHAINCONNECTIONS);
171 state.addChild (p, -2, getUndoManager());
172 return p;
173}
174
175void Plugin::makeConnection (int srcChannel, int dstChannel, juce::UndoManager* um)
176{
177 if (sidechainWireList != nullptr)
178 for (auto w : sidechainWireList->objects)
179 if (w->sourceChannelIndex == srcChannel && w->destChannelIndex == dstChannel)
180 return;
181
182 auto w = createValueTree (IDs::SIDECHAINCONNECTION,
183 IDs::srcChan, srcChannel,
184 IDs::dstChan, dstChannel);
185
186 getConnectionsTree().addChild (w, -1, um);
187}
188
189void Plugin::breakConnection (int srcChannel, int dstChannel)
190{
191 auto p = getConnectionsTree();
192
193 if (sidechainWireList != nullptr)
194 {
195 for (auto w : sidechainWireList->objects)
196 {
197 if (w->sourceChannelIndex == srcChannel && w->destChannelIndex == dstChannel)
198 {
199 p.removeChild (w->state, getUndoManager());
200 break;
201 }
202 }
203 }
204
205 if (p.getNumChildren() == 0)
206 state.removeChild (p, getUndoManager());
207}
208
209bool Plugin::canSidechain()
210{
211 if (! isInRack())
212 {
213 juce::StringArray ins, outs;
214 getChannelNames (&ins, &outs);
215 return ins.size() > 2 || ins.size() > outs.size();
216 }
217
218 return false;
219}
220
221juce::StringArray Plugin::getSidechainSourceNames (bool allowNone)
222{
223 juce::StringArray srcNames;
224
225 if (allowNone)
226 srcNames.add (TRANS("<none>"));
227
228 int idx = 0;
229
230 for (auto at : getAudioTracks (edit))
231 {
232 idx++;
233
234 if (at != getOwnerTrack())
235 srcNames.add (juce::String::formatted ("%d. ", idx) + at->getName());
236 }
237
238 return srcNames;
239}
240
241void Plugin::setSidechainSourceByName (const juce::String& name)
242{
243 bool found = false;
244 int idx = 0;
245
246 for (AudioTrack* at : getAudioTracks (edit))
247 {
248 if (juce::String::formatted ("%d. ", ++idx) + at->getName() == name)
249 {
250 sidechainSourceID = at->itemID;
251
252 if (getNumWires() == 0)
253 guessSidechainRouting();
254
255 found = true;
256 break;
257 }
258 }
259
260 if (!found)
261 {
262 sidechainSourceID.resetToDefault();
263 }
264}
265
266void Plugin::guessSidechainRouting()
267{
269 getChannelNames (&ins, nullptr);
270
271 auto* um = getUndoManager();
272
273 if (ins.size() == 1)
274 {
275 makeConnection (0, 0, um);
276 makeConnection (1, 0, um);
277 }
278 else if (ins.size() == 2)
279 {
280 makeConnection (0, 0, um);
281 makeConnection (1, 0, um);
282
283 makeConnection (2, 1, um);
284 makeConnection (3, 1, um);
285 }
286 else if (ins.size() == 3)
287 {
288 makeConnection (0, 0, um);
289 makeConnection (1, 1, um);
290
291 makeConnection (2, 2, um);
292 makeConnection (3, 2, um);
293 }
294 else
295 {
296 makeConnection (0, 0, um);
297 makeConnection (1, 1, um);
298
299 makeConnection (2, 2, um);
300 makeConnection (3, 3, um);
301 }
302}
303
304juce::String Plugin::getSidechainSourceName()
305{
306 if (sidechainSourceID->isValid())
307 if (auto t = findTrackForID (edit, sidechainSourceID))
308 return t->getName();
309
310 return {};
311}
312
313void Plugin::getChannelNames (juce::StringArray* ins, juce::StringArray* outs)
314{
315 getLeftRightChannelNames (ins, outs);
316}
317
318juce::StringArray Plugin::getInputChannelNames()
319{
321 getChannelNames (&ins, nullptr);
322
323 return ins;
324}
325
326juce::UndoManager* Plugin::getUndoManager() const noexcept
327{
328 return &edit.getUndoManager();
329}
330
335
340
342{
343 auto* um = getUndoManager();
344
345 auto parent = state.getParent();
346
347 if (parent.hasType (IDs::PLUGININSTANCE)) // If it's in a rack..
348 {
349 auto rack = parent.getParent();
350 rack.removeChild (parent, um);
351 RackType::removeBrokenConnections (rack, um);
352 }
353
354 parent.removeChild (state, um);
355}
356
357bool Plugin::isInRack() const
358{
359 return state.getParent().hasType (IDs::PLUGININSTANCE);
360}
361
362RackType::Ptr Plugin::getOwnerRackType() const
363{
364 if (isInRack())
365 return RackType::findRackTypeContaining (*this);
366
367 return {};
368}
369
370bool Plugin::isClipEffectPlugin() const
371{
372 return isClipEffect;
373}
374
375void Plugin::valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier& i)
376{
377 if (i == IDs::process)
378 processingChanged();
379 else
380 valueTreeChanged();
381}
382
383void Plugin::valueTreeChanged()
384{
385 changed();
386}
387
388void Plugin::valueTreeChildAdded (juce::ValueTree&, juce::ValueTree& c)
389{
390 if (c.getType() == IDs::SIDECHAINCONNECTIONS)
391 sidechainWireList = std::make_unique<WireList> (*this, c);
392
393 valueTreeChanged();
394}
395
396void Plugin::valueTreeChildRemoved (juce::ValueTree&, juce::ValueTree& c, int)
397{
398 if (c.getType() == IDs::SIDECHAINCONNECTIONS)
399 sidechainWireList = nullptr;
400
401 valueTreeChanged();
402}
403
404void Plugin::valueTreeParentChanged (juce::ValueTree& v)
405{
406 isClipEffect = state.getParent().hasType (IDs::EFFECT);
407
408 if (v.hasType (IDs::PLUGIN))
409 hideWindowForShutdown();
410}
411
412//==============================================================================
419
420//==============================================================================
422{
423 enabled = (b || ! canBeDisabled());
424
425 if (! enabled.get())
426 cpuUsageMs = 0.0;
427}
428
429void Plugin::setFrozen (bool shouldBeFrozen)
430{
431 frozen = shouldBeFrozen;
432
433 if (frozen)
434 cpuUsageMs = 0.0;
435}
436
438{
439 return getName() + "$genericfilter";
440}
441
443{
444}
445
446//==============================================================================
447void Plugin::baseClassInitialise (const PluginInitialisationInfo& info)
448{
449 TRACKTION_ASSERT_MESSAGE_THREAD
450 const bool sampleRateOrBlockSizeChanged = (sampleRate != info.sampleRate) || (blockSizeSamples != info.blockSizeSamples);
451 bool hasUpdatedWithoutStopping = false;
452 sampleRate = info.sampleRate;
453 blockSizeSamples = info.blockSizeSamples;
454 cpuUsageMs = 0.0;
455
456 {
457 const double msPerBlock = (sampleRate > 0.0) ? (1000.0 * (blockSizeSamples / sampleRate)) : 0.0;
458 timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0;
459 }
460
461 if (initialiseCount++ == 0 || sampleRateOrBlockSizeChanged)
462 {
464 isInitialisingFlag = true;
465 initialise (info);
466 isInitialisingFlag = false;
467 }
468 else
469 {
471 hasUpdatedWithoutStopping = true;
473 }
474
475 {
478 }
479
480 if (! hasUpdatedWithoutStopping)
481 {
483 setAutomatableParamPosition (info.startTime);
484 }
485
486 if (sampleRateOrBlockSizeChanged)
487 {
489 reset();
490 }
491}
492
493void Plugin::baseClassDeinitialise()
494{
495 jassert (initialiseCount > 0);
496
497 if (initialiseCount > 0 && --initialiseCount == 0)
498 {
500 deinitialise();
502
503 timeToCpuScale = 0.0;
504 cpuUsageMs = 0.0;
505 }
506}
507
508//==============================================================================
510{
511 if (auto mpl = getMacroParameterList())
512 mpl->hideMacroParametersFromTracks();
513
514 for (auto t : getAllTracks (edit))
515 t->hideAutomatableParametersForSource (itemID);
516
517 hideWindowForShutdown();
518 deselect();
520}
521
523{
524 return getTrackContainingPlugin (edit, this);
525}
526
528{
529 auto parent = state.getParent();
530
531 if (Clip::isClipState (parent))
532 return findClipForID (edit, EditItemID::fromID (parent));
533
534 return {};
535}
536
537static PluginList* getListContaining (const Plugin& p)
538{
539 if (auto c = p.getOwnerClip())
540 return c->getPluginList();
541
542 if (auto t = p.getOwnerTrack())
543 return &t->pluginList;
544
545 return &p.edit.getMasterPluginList();
546}
547
548Plugin::Ptr Plugin::findPluginThatFeedsIntoThis() const
549{
550 if (auto l = getListContaining (*this))
551 return l->getPlugins()[l->indexOf (this) - 1];
552
553 return {};
554}
555
556Plugin::Ptr Plugin::findPluginThatThisFeedsInto() const
557{
558 if (auto l = getListContaining (*this))
559 return l->getPlugins()[l->indexOf (this) + 1];
560
561 return {};
562}
563
564PluginList* Plugin::getOwnerList() const
565{
566 return getListContaining (*this);
567}
568
569//==============================================================================
570AutomatableParameter* Plugin::addParam (const juce::String& paramID, const juce::String& name,
572{
573 auto p = new AutomatableParameter (paramID, name, *this, valueRange);
574 addAutomatableParameter (*p);
575 return p;
576}
577
578AutomatableParameter* Plugin::addParam (const juce::String& paramID, const juce::String& name,
580 std::function<juce::String(float)> valueToStringFn,
581 std::function<float(const juce::String&)> stringToValueFn)
582{
583 auto p = addParam (paramID, name, valueRange);
584 p->valueToStringFunction = valueToStringFn;
585 p->stringToValueFunction = stringToValueFn;
586 return p;
587}
588
589AutomatableParameter::Ptr Plugin::getQuickControlParameter() const
590{
591 juce::String currentID = quickParamName;
592
593 if (currentID.isEmpty())
594 {
595 quickControlParameter = nullptr;
596 }
597 else
598 {
599 if (quickControlParameter == nullptr || currentID != quickControlParameter->paramID)
600 {
601 quickControlParameter = getAutomatableParameterByID (currentID);
602
603 if (quickControlParameter == nullptr)
604 {
605 // if this is a rack, dig around trying to get the name
606 if (auto rf = dynamic_cast<const RackInstance*> (this))
607 {
608 if (rf->type != nullptr)
609 {
610 // First check macros
611 if (auto mpl = rf->type->getMacroParameterList())
612 {
613 for (auto param : mpl->getAutomatableParameters())
614 {
615 if (param->paramID == currentID)
616 {
617 quickControlParameter = param;
618 break;
619 }
620 }
621 }
622
623 // Then plugins
624 for (auto p : rf->type->getPlugins())
625 {
626 for (int j = 0; j < p->getNumAutomatableParameters(); j++)
627 {
628 auto param = p->getAutomatableParameter(j);
629
630 if (param->paramID == currentID)
631 {
632 quickControlParameter = param;
633 break;
634 }
635 }
636 }
637 }
638 }
639 }
640 }
641 }
642
643 return quickControlParameter;
644}
645
646void Plugin::setQuickControlParameter (AutomatableParameter* param)
647{
648 if (param == nullptr)
649 state.removeProperty (IDs::quickParamName, getUndoManager());
650 else
651 quickParamName = param->paramID;
652}
653
654void Plugin::applyToBufferWithAutomation (const PluginRenderContext& pc)
655{
656 SCOPED_REALTIME_CHECK
657
659
661 cpuMeter.emplace (cpuUsageMs, 0.2);
662
663 auto& arm = edit.getAutomationRecordManager();
664 jassert (initialiseCount > 0);
665 #if JUCE_DEBUG
666 jassert (! isInitialisingFlag);
667 #endif
668
669 updateLastPlaybackTime();
670
671 if (isAutomationNeeded()
672 && (arm.isReadingAutomation() || isClipEffect.load()))
673 {
674 if (pc.isScrubbing || ! pc.isPlaying)
675 {
676 SCOPED_REALTIME_CHECK
677 auto& tc = edit.getTransport();
678 updateParameterStreams (tc.isPlayContextActive() && ! pc.isRendering
679 ? tc.getPosition()
680 : pc.editTime.getStart());
681 applyToBuffer (pc);
682 }
683 else
684 {
685 SCOPED_REALTIME_CHECK
686 updateParameterStreams (pc.editTime.getStart());
687 applyToBuffer (pc);
688 }
689 }
690 else
691 {
692 SCOPED_REALTIME_CHECK
693 applyToBuffer (pc);
694 }
695}
696
697//==============================================================================
699{
700 jassert (midiChannel >= 1 && midiChannel <= 16);
701 juce::ignoreUnused (midiChannel);
702 return false;
703}
704
706{
707 return false;
708}
709
710bool Plugin::hasNameForMidiBank (int, juce::String&)
711{
712 return false;
713}
714
715//==============================================================================
716juce::Array<Exportable::ReferencedItem> Plugin::getReferencedItems() { return {}; }
717void Plugin::reassignReferencedItem (const ReferencedItem&, ProjectItemID, double) {}
718
719//==============================================================================
720static bool mirrorPluginIsRecursive (Plugin& p, int depth)
721{
722 if (depth > 20)
723 return true;
724
725 if (auto mirrored = p.getMirroredPlugin())
726 return mirrorPluginIsRecursive (*mirrored, depth + 1);
727
728 return false;
729}
730
731bool Plugin::setPluginToMirror (const Plugin::Ptr& newMaster)
732{
733 if (newMaster != nullptr)
734 {
735 if (getName() != newMaster->getName())
736 return false;
737
738 auto p1 = dynamic_cast<ExternalPlugin*> (this);
739 auto p2 = dynamic_cast<ExternalPlugin*> (newMaster.get());
740
741 if (p1 != nullptr || p2 != nullptr)
742 {
743 if (p1 == nullptr || p2 == nullptr)
744 return false;
745
746 if (! p1->desc.isDuplicateOf (p2->desc))
747 return false;
748 }
749 }
750
751 auto newID = newMaster != nullptr ? newMaster->itemID : EditItemID();
752
753 if (newID != masterPluginID)
754 {
755 auto oldID = masterPluginID.get();
756 masterPluginID = newID;
757
758 if (mirrorPluginIsRecursive (*this, 0))
759 {
760 masterPluginID = oldID;
761 return false;
762 }
763
764 if (newMaster != nullptr)
765 updateFromMirroredPluginIfNeeded (*newMaster);
766 }
767
768 return true;
769}
770
771Plugin::Ptr Plugin::getMirroredPlugin() const
772{
773 if (masterPluginID.get().isValid())
774 return edit.getPluginCache().getPluginFor (masterPluginID.get());
775
776 return {};
777}
778
780{
781 int index;
782 Plugin* plugin;
783
784 bool operator== (const SelectedPluginIndex& other) const { return index == other.index; }
785 bool operator< (const SelectedPluginIndex& other) const { return index < other.index; }
786};
787
788static Plugin::Array getRackablePlugins (SelectionManager& selectionManager)
789{
790 Plugin::Array result;
791
793 juce::ValueTree lastList;
794
795 for (auto plugin : selectionManager.getItemsOfType<Plugin>())
796 {
797 if (plugin->canBeAddedToRack() && ! plugin->isInRack())
798 {
799 if (! lastList.isValid() || lastList == plugin->state.getParent())
800 {
801 lastList = plugin->state.getParent();
802
803 PluginList list (plugin->edit);
804 list.initialise (lastList);
805
806 auto index = list.indexOf (plugin);
807
808 if (index >= 0)
809 {
810 SelectedPluginIndex sf = { index, plugin };
811 pluginIndex.add (sf);
812 continue;
813 }
814 }
815 }
816
817 break;
818 }
819
820 for (int i = 0; i < pluginIndex.size() - 1; ++i)
821 if (pluginIndex[i].index != pluginIndex[i + 1].index - 1)
822 return result;
823
824 for (auto& i : pluginIndex)
825 result.add (i.plugin);
826
827 return result;
828}
829
830bool Plugin::areSelectedPluginsRackable (SelectionManager& selectionManager)
831{
832 return getRackablePlugins (selectionManager).size() > 0;
833}
834
835RackInstance* Plugin::wrapSelectedPluginsInRack (SelectionManager& selectionManager)
836{
837 auto plugins = getRackablePlugins (selectionManager);
838
839 if (auto first = plugins.getFirst())
840 {
841 auto& ed = first->edit;
842 ed.getTransport().stop (false, true);
843
844 if (auto list = getListContaining (*first))
845 {
846 auto insertIndex = list->indexOf (first.get());
847
848 if (auto newRackType = RackType::createTypeToWrapPlugins (plugins, ed))
849 return dynamic_cast<RackInstance*> (list->insertPlugin (RackInstance::create (*newRackType), insertIndex).get());
850 }
851 }
852
853 return {};
854}
855
856void Plugin::sortPlugins (Plugin::Array& plugins)
857{
858 if (auto first = plugins.getFirst())
859 {
860 PluginList list (first->edit);
861 list.initialise (first->state.getParent());
862
863 std::sort (plugins.begin(), plugins.end(),
864 [&list] (Plugin* a, Plugin* b)
865 {
866 jassert (a != nullptr && b != nullptr);
867 return list.indexOf (a) < list.indexOf (b);
868 });
869 }
870}
871
872void Plugin::sortPlugins (std::vector<Plugin*>& plugins)
873{
874 if (plugins.size() == 0 || plugins[0] == nullptr)
875 return;
876
877 auto first = plugins[0];
878
879 PluginList list (first->edit);
880 list.initialise (first->state.getParent());
881
882 std::sort (plugins.begin(), plugins.end(),
883 [&list] (Plugin* a, Plugin* b)
884 {
885 jassert (a != nullptr && b != nullptr);
886 return list.indexOf (a) < list.indexOf (b);
887 });
888}
889
890void Plugin::getLeftRightChannelNames (juce::StringArray* chans)
891{
892 if (chans != nullptr)
893 {
894 chans->add (TRANS("Left"));
895 chans->add (TRANS("Right"));
896 }
897}
898
899void Plugin::getLeftRightChannelNames (juce::StringArray* ins,
900 juce::StringArray* outs)
901{
902 getLeftRightChannelNames (ins);
903 getLeftRightChannelNames (outs);
904}
905
906void Plugin::showWindowExplicitly()
907{
908 windowState->showWindowExplicitly();
909}
910
911void Plugin::hideWindowForShutdown()
912{
913 windowState->hideWindowForShutdown();
914}
915
916void Plugin::processingChanged()
917{
918 if (! processing)
919 windowState->hideWindowForShutdown();
920}
921
922void Plugin::flushPluginStateToValueTree()
923{
924 AutomatableEditItem::flushPluginStateToValueTree();
925
926 if (! windowState->lastWindowBounds.isEmpty())
927 {
928 auto um = getUndoManager();
929
930 state.setProperty (IDs::windowX, windowState->lastWindowBounds.getX(), um);
931 state.setProperty (IDs::windowY, windowState->lastWindowBounds.getY(), um);
932 state.setProperty (IDs::windowLocked, windowState->windowLocked, um);
933 }
934}
935
936}} // namespace tracktion { inline namespace engine
T begin(T... args)
bool isValid() const noexcept
int size() const noexcept
bool add(const ElementType &newElement) noexcept
int size() const noexcept
void add(String stringToAdd)
bool isEmpty() const noexcept
static String formatted(const String &formatStr, Args... args)
bool hasType(const Identifier &typeName) const noexcept
void removeChild(const ValueTree &child, UndoManager *undoManager)
bool isValid() const noexcept
ValueTree & setProperty(const Identifier &name, const var &newValue, UndoManager *undoManager)
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
ValueTree getParent() const noexcept
ValueTree getChildWithName(const Identifier &type) const
void removeListener(Listener *listener)
void removeProperty(const Identifier &name, UndoManager *undoManager)
Base class for elements that have some kind of automatable parameters.
void resetRecordingStatus()
Marks the end of an automation recording stream.
void restoreChangedParametersFromState()
Restores the value of any explicitly set parameters.
void updateParameterStreams(TimePosition)
Updates all the parameter streams to their positions at this time.
A clip in an edit.
static bool isClipState(const juce::ValueTree &)
Checks whether a ValueTree is some kind of clip state.
const EditItemID itemID
Every EditItem has an ID which is unique within the edit.
TransportControl & getTransport() const noexcept
Returns the TransportControl which is used to stop/stop/position playback and recording.
PluginCache & getPluginCache() noexcept
Returns the PluginCache which manages all active Plugin[s] for this Edit.
AutomationRecordManager & getAutomationRecordManager() noexcept
Returns the AutomationRecordManager for the Edit.
void updateMirroredPlugin(Plugin &)
Adds this plugin to a list so mirrored Plugin[s] are updated asyncronously.
juce::UndoManager & getUndoManager() noexcept
Returns the juce::UndoManager used for this Edit.
ExternalControllerManager & getExternalControllerManager() const
Returns the ExternalControllerManager instance.
Base class for elements which can contain macro parameters.
MacroParameterList * getMacroParameterList()
If no parameters have been created, this may return nullptr.
Holds a sequence of plugins.
void changed() override
method from Selectable, that's been overridden here to also tell the edit that it's changed.
virtual void reset()
Should reset synth voices, tails, clear delay buffers, etc.
virtual void deinitialise()=0
Called after play stops to release resources.
virtual juce::String getName() const override=0
The name of the type, e.g.
virtual bool hasNameForMidiNoteNumber(int note, int midiChannel, juce::String &name)
If it's a synth that names its notes, this can return the name it uses for this note 0-127.
virtual juce::String getTooltip()
default returns the name, others can return special stuff if needed
virtual void initialiseWithoutStopping(const PluginInitialisationInfo &)
Tells the plugin that the audio graph has changed but the plugin isn't being re-initialised - i....
void setFrozen(bool shouldBeFrozen)
This is a bit different to being enabled as when frozen a plugin can't be interacted with.
virtual bool shoulMeasureCpuUsage() const noexcept
Plugins can return false if they want to avoid the overhead of measuring the CPU usage.
virtual int getNumOutputChannelsGivenInputs(int numInputChannels)
This must return the number of output channels that the plugin will produce, given a number of input ...
void removeFromParent()
Detaches the plugin from any parent it might be in.
Clip * getOwnerClip() const
Returns the clip if that's what it's in.
void playStartedOrStopped()
called by the system to let the plugin manage its automation stuff
virtual void setEnabled(bool)
Enable/disable the plugin.
virtual void initialiseFully()
Gives the plugin a chance to do extra initialisation when it's been added to an edit.
void selectableAboutToBeDeleted() override
Called just before the selectable is about to be deleted so any subclasses should still be valid at t...
virtual void applyToBuffer(const PluginRenderContext &)=0
Process the next block of data.
virtual bool hasNameForMidiProgram(int programNum, int bank, juce::String &name)
Returns the name for a midi program, if there is one.
Track * getOwnerTrack() const
Returns the track if it's a track or clip plugin.
virtual void deleteFromParent()
Attempts to delete this plugin, whether it's a master plugin, track plugin, etc.
virtual void changed()
This should be called to send a change notification to any SelectableListeners that are registered wi...
static bool isSelectableValid(const Selectable *) noexcept
checks whether this object has been deleted.
Manages a list of items that are currently selected.
Base class for tracks which contain clips and plugins and can be added to Edit[s].
T emplace(T... args)
T end(T... args)
T is_pointer_v
#define TRANS(stringLiteral)
#define jassert(expression)
T load(T... args)
void ignoreUnused(Types &&...) noexcept
Clip * findClipForID(ClipOwner &co, EditItemID id)
Returns a clip with the given ID if the ClipOwner contains it.
juce::Array< Track * > getAllTracks(const Edit &edit)
Returns all the tracks in an Edit.
juce::Array< AudioTrack * > getAudioTracks(const Edit &edit)
Returns all the AudioTracks in an Edit.
Track * getTrackContainingPlugin(const Edit &edit, const Plugin *p)
Returns the track for the track which the plugin is located on.
Track * findTrackForID(const Edit &edit, EditItemID id)
Returns the Track with a given ID if contained in the Edit.
SafeSelectable< SelectableType > makeSafeRef(SelectableType &selectable)
Creates a SafeSelectable for a given selectable object.
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
T size(T... args)
T sort(T... args)
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.