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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_PatchBay.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
14PatchBayPlugin::Wire::Wire (const juce::ValueTree& v, juce::UndoManager* um) : state (v)
15{
16 sourceChannelIndex.referTo (state, IDs::srcChan, um);
17 destChannelIndex.referTo (state, IDs::dstChan, um);
18 gainDb.referTo (state, IDs::gainDb, um);
19}
20
21struct PatchBayPlugin::WireList : public ValueTreeObjectList<PatchBayPlugin::Wire, juce::CriticalSection>,
22 private juce::AsyncUpdater
23{
24 WireList (PatchBayPlugin& pb, const juce::ValueTree& parentTree)
25 : ValueTreeObjectList<Wire, juce::CriticalSection> (parentTree), patchbay (pb)
26 {
27 rebuildObjects();
28 }
29
30 ~WireList() override
31 {
32 freeObjects();
33 }
34
35 bool isSuitableType (const juce::ValueTree& v) const override { return v.hasType (IDs::CONNECTION); }
36 Wire* createNewObject (const juce::ValueTree& v) override { return new Wire (v, patchbay.getUndoManager()); }
37 void deleteObject (Wire* w) override { delete w; }
38
39 void newObjectAdded (Wire*) override { triggerAsyncUpdate(); }
40 void objectRemoved (Wire*) override { triggerAsyncUpdate(); }
41 void objectOrderChanged() override {}
42 void valueTreePropertyChanged (juce::ValueTree&, const juce::Identifier&) override { triggerAsyncUpdate(); }
43
44 void handleAsyncUpdate() override
45 {
46 patchbay.changed();
47 }
48
49 PatchBayPlugin& patchbay;
50};
51
52//==============================================================================
53PatchBayPlugin::PatchBayPlugin (PluginCreationInfo info) : Plugin (info)
54{
55 list = std::make_unique<WireList> (*this, state);
56
57 if (info.isNewPlugin)
58 for (int i = 0; i < 2; ++i)
59 makeConnection (i, i, 0.0f, nullptr);
60}
61
62PatchBayPlugin::~PatchBayPlugin()
63{
64 notifyListenersOfDeletion();
65}
66
67const char* PatchBayPlugin::xmlTypeName = "patchbay";
68
69int PatchBayPlugin::getNumWires() const { return list->objects.size(); }
70PatchBayPlugin::Wire* PatchBayPlugin::getWire (int index) const { return list->objects[index]; }
71
72void PatchBayPlugin::getChannelNames (juce::StringArray* ins,
74{
75 if (baseClassNeedsInitialising())
76 cacheInputAndOutputPlugins();
77
78 if (ins != nullptr)
79 {
80 if (inputPlugin != nullptr && ! recursionCheck)
81 {
83 recursionCheck = true;
84 inputPlugin->getChannelNames (nullptr, &out);
85 recursionCheck = false;
86 ins->addArray (out);
87 }
88 else
89 {
90 getLeftRightChannelNames (ins);
91 }
92 }
93
94 if (outs != nullptr)
95 {
96 if (outputPlugin != nullptr && ! recursionCheck)
97 {
99 recursionCheck = true;
100 outputPlugin->getChannelNames (&in, nullptr);
101 recursionCheck = false;
102 outs->addArray (in);
103 }
104 else
105 {
106 getLeftRightChannelNames (outs);
107 }
108 }
109}
110
111void PatchBayPlugin::initialise (const PluginInitialisationInfo&)
112{
113 cacheInputAndOutputPlugins();
114}
115
119
121{
122 if (fc.destBuffer != nullptr)
123 {
124 SCOPED_REALTIME_CHECK
125
126 int maxOutputChan = 1;
127 AudioScratchBuffer scratch (2, fc.bufferNumSamples);
128 auto& outputBuffer = scratch.buffer;
129 outputBuffer.clear();
130
131 {
132 const juce::ScopedLock sl (list->arrayLock);
133
134 for (auto w : list->objects)
135 {
136 maxOutputChan = std::max (w->destChannelIndex.get(), maxOutputChan);
137
138 if (w->destChannelIndex < 2 && w->sourceChannelIndex < fc.destBuffer->getNumChannels())
139 outputBuffer.addFrom (w->destChannelIndex, 0,
140 *fc.destBuffer, w->sourceChannelIndex, fc.bufferStartSample,
142 dbToGain (w->gainDb));
143 }
144 }
145
146 maxOutputChan = std::min (2, maxOutputChan + 1);
147 fc.destBuffer->setSize (maxOutputChan, fc.destBuffer->getNumSamples(), false);
148
149 for (int i = maxOutputChan; --i >= 0;)
150 fc.destBuffer->copyFrom (i, fc.bufferStartSample, outputBuffer, i, 0, fc.bufferNumSamples);
151 }
152}
153
154void PatchBayPlugin::makeConnection (int inputChannel, int outputChannel,
155 float gainDb, juce::UndoManager* um)
156{
157 for (auto w : list->objects)
158 if (w->sourceChannelIndex == inputChannel && w->destChannelIndex == outputChannel)
159 return;
160
161 auto w = createValueTree (IDs::CONNECTION,
162 IDs::srcChan, inputChannel,
163 IDs::dstChan, outputChannel,
164 IDs::gainDb, gainDb);
165
166 state.addChild (w, -1, um);
167}
168
169void PatchBayPlugin::breakConnection (int inputChannel, int outputChannel)
170{
171 for (auto w : list->objects)
172 {
173 if (w->sourceChannelIndex == inputChannel && w->destChannelIndex == outputChannel)
174 {
175 state.removeChild (w->state, getUndoManager());
176 break;
177 }
178 }
179}
180
181void PatchBayPlugin::cacheInputAndOutputPlugins()
182{
183 inputPlugin = findPluginThatFeedsIntoThis().get();
184 outputPlugin = findPluginThatThisFeedsInto().get();
185}
186
187
188}} // namespace tracktion { inline namespace engine
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
int getNumChannels() const noexcept
int getNumSamples() const noexcept
void clear() noexcept
void copyFrom(int destChannel, int destStartSample, const AudioBuffer &source, int sourceChannel, int sourceStartSample, int numSamples) noexcept
ReferencedType * get() const noexcept
void addArray(const StringArray &other, int startIndex=0, int numElementsToAdd=-1)
void removeChild(const ValueTree &child, UndoManager *undoManager)
void addChild(const ValueTree &child, int index, UndoManager *undoManager)
An audio scratch buffer that has pooled storage.
juce::AudioBuffer< float > & buffer
The buffer to use.
void applyToBuffer(const PluginRenderContext &) override
Process the next block of data.
void deinitialise() override
Called after play stops to release resources.
T is_pointer_v
T max(T... args)
T min(T... args)
Passed into Plugins when they are being initialised, to give them useful contextual information that ...
The context passed to plugin render methods to provide it with buffers to fill.
int bufferNumSamples
The number of samples to write into the audio buffer.
juce::AudioBuffer< float > * destBuffer
The target audio buffer which needs to be filled.
int bufferStartSample
The index of the start point in the audio buffer from which data must be written.