11namespace tracktion {
inline namespace engine
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)
31 sourceChannelIndex.referTo (state, IDs::srcChan, um);
32 destChannelIndex.referTo (state, IDs::dstChan, um);
49 bool isSuitableType (
const juce::ValueTree& v)
const override {
return v.hasType (IDs::SIDECHAINCONNECTION); }
51 void deleteObject (
Wire* w)
override {
delete w; }
53 void newObjectAdded (
Wire*)
override { triggerAsyncUpdate(); }
54 void objectRemoved (
Wire*)
override { triggerAsyncUpdate(); }
55 void objectOrderChanged()
override {}
58 void handleAsyncUpdate()
override { plugin.changed(); }
71 engine (info.edit.engine),
74 isClipEffect = state.getParent().hasType (IDs::EFFECT);
79 auto um = getUndoManager();
81 auto wires = state.getChildWithName (IDs::SIDECHAINCONNECTIONS);
86 enabled.referTo (state, IDs::enabled, um,
true);
88 if (enabled.isUsingDefault())
89 enabled = enabled.getDefault();
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);
97 state.addListener (
this);
99 #if TRACKTION_ENABLE_AUTOMAP && TRACKTION_ENABLE_CONTROL_SURFACES
100 if (! edit.isLoading())
104 juce::MessageManager::callAsync ([ref =
makeSafeRef (*
this), &e]()
mutable
106 if (
auto plugin = ref.get())
107 if (
auto na = e.getExternalControllerManager().getAutomap())
108 na->pluginChanged (plugin);
113 windowState->windowLocked = state [IDs::windowLocked];
115 if (state.hasProperty (IDs::windowX))
117 state[IDs::windowY], 1, 1);
123 windowState->hideWindowForShutdown();
125 #if TRACKTION_ENABLE_AUTOMAP && TRACKTION_ENABLE_CONTROL_SURFACES
127 na->removePlugin (
this);
136 quickControlParameter =
nullptr;
137 deleteAutomatableParameters();
143 getChannelNames (
nullptr, &outs);
147int Plugin::getNumWires()
const
149 if (sidechainWireList !=
nullptr)
150 return sidechainWireList->objects.size();
155Plugin::Wire* Plugin::getWire (
int index)
const
157 if (sidechainWireList !=
nullptr)
158 return sidechainWireList->objects[index];
171 state.
addChild (p, -2, getUndoManager());
175void Plugin::makeConnection (
int srcChannel,
int dstChannel,
juce::UndoManager* um)
177 if (sidechainWireList !=
nullptr)
178 for (
auto w : sidechainWireList->objects)
179 if (w->sourceChannelIndex == srcChannel && w->destChannelIndex == dstChannel)
182 auto w = createValueTree (IDs::SIDECHAINCONNECTION,
183 IDs::srcChan, srcChannel,
184 IDs::dstChan, dstChannel);
186 getConnectionsTree().
addChild (w, -1, um);
189void Plugin::breakConnection (
int srcChannel,
int dstChannel)
191 auto p = getConnectionsTree();
193 if (sidechainWireList !=
nullptr)
195 for (
auto w : sidechainWireList->objects)
197 if (w->sourceChannelIndex == srcChannel && w->destChannelIndex == dstChannel)
199 p.removeChild (w->state, getUndoManager());
205 if (p.getNumChildren() == 0)
209bool Plugin::canSidechain()
214 getChannelNames (&ins, &outs);
241void Plugin::setSidechainSourceByName (
const juce::String& name)
250 sidechainSourceID = at->itemID;
252 if (getNumWires() == 0)
253 guessSidechainRouting();
262 sidechainSourceID.resetToDefault();
266void Plugin::guessSidechainRouting()
269 getChannelNames (&ins,
nullptr);
271 auto* um = getUndoManager();
275 makeConnection (0, 0, um);
276 makeConnection (1, 0, um);
278 else if (ins.
size() == 2)
280 makeConnection (0, 0, um);
281 makeConnection (1, 0, um);
283 makeConnection (2, 1, um);
284 makeConnection (3, 1, um);
286 else if (ins.
size() == 3)
288 makeConnection (0, 0, um);
289 makeConnection (1, 1, um);
291 makeConnection (2, 2, um);
292 makeConnection (3, 2, um);
296 makeConnection (0, 0, um);
297 makeConnection (1, 1, um);
299 makeConnection (2, 2, um);
300 makeConnection (3, 3, um);
306 if (sidechainSourceID->isValid())
315 getLeftRightChannelNames (ins, outs);
321 getChannelNames (&ins,
nullptr);
343 auto* um = getUndoManager();
347 if (parent.hasType (IDs::PLUGININSTANCE))
349 auto rack = parent.getParent();
350 rack.removeChild (parent, um);
351 RackType::removeBrokenConnections (rack, um);
354 parent.removeChild (state, um);
357bool Plugin::isInRack()
const
362RackType::Ptr Plugin::getOwnerRackType()
const
365 return RackType::findRackTypeContaining (*
this);
370bool Plugin::isClipEffectPlugin()
const
377 if (i == IDs::process)
383void Plugin::valueTreeChanged()
390 if (c.getType() == IDs::SIDECHAINCONNECTIONS)
398 if (c.getType() == IDs::SIDECHAINCONNECTIONS)
399 sidechainWireList =
nullptr;
408 if (v.hasType (IDs::PLUGIN))
409 hideWindowForShutdown();
423 enabled = (b || ! canBeDisabled());
431 frozen = shouldBeFrozen;
439 return getName() +
"$genericfilter";
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;
457 const double msPerBlock = (sampleRate > 0.0) ? (1000.0 * (blockSizeSamples / sampleRate)) : 0.0;
458 timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0;
461 if (initialiseCount++ == 0 || sampleRateOrBlockSizeChanged)
464 isInitialisingFlag =
true;
466 isInitialisingFlag =
false;
471 hasUpdatedWithoutStopping =
true;
480 if (! hasUpdatedWithoutStopping)
483 setAutomatableParamPosition (info.startTime);
486 if (sampleRateOrBlockSizeChanged)
493void Plugin::baseClassDeinitialise()
497 if (initialiseCount > 0 && --initialiseCount == 0)
503 timeToCpuScale = 0.0;
512 mpl->hideMacroParametersFromTracks();
515 t->hideAutomatableParametersForSource (
itemID);
517 hideWindowForShutdown();
539 if (
auto c = p.getOwnerClip())
540 return c->getPluginList();
542 if (
auto t = p.getOwnerTrack())
543 return &t->pluginList;
545 return &p.edit.getMasterPluginList();
548Plugin::Ptr Plugin::findPluginThatFeedsIntoThis()
const
550 if (
auto l = getListContaining (*
this))
551 return l->getPlugins()[l->indexOf (
this) - 1];
556Plugin::Ptr Plugin::findPluginThatThisFeedsInto()
const
558 if (
auto l = getListContaining (*
this))
559 return l->getPlugins()[l->indexOf (
this) + 1];
564PluginList* Plugin::getOwnerList()
const
566 return getListContaining (*
this);
573 auto p =
new AutomatableParameter (paramID, name, *
this, valueRange);
574 addAutomatableParameter (*p);
583 auto p = addParam (paramID, name, valueRange);
584 p->valueToStringFunction = valueToStringFn;
585 p->stringToValueFunction = stringToValueFn;
589AutomatableParameter::Ptr Plugin::getQuickControlParameter()
const
595 quickControlParameter =
nullptr;
599 if (quickControlParameter ==
nullptr || currentID != quickControlParameter->paramID)
601 quickControlParameter = getAutomatableParameterByID (currentID);
603 if (quickControlParameter ==
nullptr)
606 if (
auto rf =
dynamic_cast<const RackInstance*
> (
this))
608 if (rf->type !=
nullptr)
611 if (
auto mpl = rf->type->getMacroParameterList())
613 for (
auto param : mpl->getAutomatableParameters())
615 if (param->paramID == currentID)
617 quickControlParameter = param;
624 for (
auto p : rf->type->getPlugins())
626 for (
int j = 0; j < p->getNumAutomatableParameters(); j++)
628 auto param = p->getAutomatableParameter(j);
630 if (param->paramID == currentID)
632 quickControlParameter = param;
643 return quickControlParameter;
646void Plugin::setQuickControlParameter (AutomatableParameter* param)
648 if (param ==
nullptr)
651 quickParamName = param->paramID;
654void Plugin::applyToBufferWithAutomation (
const PluginRenderContext& pc)
656 SCOPED_REALTIME_CHECK
661 cpuMeter.
emplace (cpuUsageMs, 0.2);
666 jassert (! isInitialisingFlag);
669 updateLastPlaybackTime();
671 if (isAutomationNeeded()
672 && (arm.isReadingAutomation() || isClipEffect.
load()))
674 if (pc.isScrubbing || ! pc.isPlaying)
676 SCOPED_REALTIME_CHECK
680 : pc.editTime.getStart());
685 SCOPED_REALTIME_CHECK
692 SCOPED_REALTIME_CHECK
700 jassert (midiChannel >= 1 && midiChannel <= 16);
717void Plugin::reassignReferencedItem (
const ReferencedItem&, ProjectItemID,
double) {}
720static bool mirrorPluginIsRecursive (Plugin& p,
int depth)
725 if (
auto mirrored = p.getMirroredPlugin())
726 return mirrorPluginIsRecursive (*mirrored, depth + 1);
731bool Plugin::setPluginToMirror (
const Plugin::Ptr& newMaster)
733 if (newMaster !=
nullptr)
735 if (
getName() != newMaster->getName())
738 auto p1 =
dynamic_cast<ExternalPlugin*
> (
this);
739 auto p2 =
dynamic_cast<ExternalPlugin*
> (newMaster.get());
741 if (p1 !=
nullptr || p2 !=
nullptr)
743 if (p1 ==
nullptr || p2 ==
nullptr)
746 if (! p1->desc.isDuplicateOf (p2->desc))
751 auto newID = newMaster !=
nullptr ? newMaster->itemID : EditItemID();
753 if (newID != masterPluginID)
755 auto oldID = masterPluginID.get();
756 masterPluginID = newID;
758 if (mirrorPluginIsRecursive (*
this, 0))
760 masterPluginID = oldID;
764 if (newMaster !=
nullptr)
765 updateFromMirroredPluginIfNeeded (*newMaster);
771Plugin::Ptr Plugin::getMirroredPlugin()
const
773 if (masterPluginID.get().isValid())
795 for (
auto plugin : selectionManager.getItemsOfType<
Plugin>())
797 if (plugin->canBeAddedToRack() && ! plugin->isInRack())
799 if (! lastList.
isValid() || lastList == plugin->state.getParent())
804 list.initialise (lastList);
806 auto index = list.indexOf (plugin);
811 pluginIndex.
add (sf);
820 for (
int i = 0; i < pluginIndex.
size() - 1; ++i)
821 if (pluginIndex[i].index != pluginIndex[i + 1].index - 1)
824 for (
auto& i : pluginIndex)
825 result.add (i.plugin);
830bool Plugin::areSelectedPluginsRackable (SelectionManager& selectionManager)
832 return getRackablePlugins (selectionManager).size() > 0;
835RackInstance* Plugin::wrapSelectedPluginsInRack (SelectionManager& selectionManager)
837 auto plugins = getRackablePlugins (selectionManager);
839 if (
auto first = plugins.getFirst())
841 auto& ed = first->edit;
842 ed.getTransport().stop (
false,
true);
844 if (
auto list = getListContaining (*first))
846 auto insertIndex = list->indexOf (first.get());
848 if (
auto newRackType = RackType::createTypeToWrapPlugins (plugins, ed))
849 return dynamic_cast<RackInstance*
> (list->insertPlugin (RackInstance::create (*newRackType), insertIndex).get());
856void Plugin::sortPlugins (Plugin::Array& plugins)
858 if (
auto first = plugins.getFirst())
860 PluginList list (first->edit);
861 list.initialise (first->state.getParent());
863 std::sort (plugins.begin(), plugins.end(),
864 [&list] (Plugin* a, Plugin* b)
866 jassert (a != nullptr && b != nullptr);
867 return list.indexOf (a) < list.indexOf (b);
874 if (plugins.
size() == 0 || plugins[0] ==
nullptr)
877 auto first = plugins[0];
879 PluginList list (first->edit);
880 list.initialise (first->state.getParent());
883 [&list] (Plugin* a, Plugin* b)
885 jassert (a != nullptr && b != nullptr);
886 return list.indexOf (a) < list.indexOf (b);
892 if (chans !=
nullptr)
902 getLeftRightChannelNames (ins);
903 getLeftRightChannelNames (outs);
906void Plugin::showWindowExplicitly()
908 windowState->showWindowExplicitly();
911void Plugin::hideWindowForShutdown()
913 windowState->hideWindowForShutdown();
916void Plugin::processingChanged()
919 windowState->hideWindowForShutdown();
922void Plugin::flushPluginStateToValueTree()
924 AutomatableEditItem::flushPluginStateToValueTree();
926 if (! windowState->lastWindowBounds.isEmpty())
928 auto um = getUndoManager();
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);
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.
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].
#define TRANS(stringLiteral)
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 ...
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.