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

« « « Anklang Documentation
Loading...
Searching...
No Matches
tracktion_InsertPlugin.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
14static void getPossibleInputDeviceNames (Engine& e,
16 juce::BigInteger& hasAudio,
17 juce::BigInteger& hasMidi)
18{
19 auto& dm = e.getDeviceManager();
20
21 for (int i = 0; i < dm.getNumInputDevices(); ++i)
22 {
23 if (auto in = dm.getInputDevice (i))
24 {
25 if (! in->isEnabled())
26 continue;
27
28 if (dynamic_cast<MidiInputDevice*> (in) != nullptr)
29 hasMidi.setBit (s.size(), true);
30 else
31 hasAudio.setBit (s.size(), true);
32
33 s.add (in->getName());
34 a.add (in->getAlias());
35 }
36 }
37}
38
39static void getPossibleOutputDeviceNames (Engine& e,
41 juce::BigInteger& hasAudio,
42 juce::BigInteger& hasMidi)
43{
44 auto& dm = e.getDeviceManager();
45
46 for (int i = 0; i < dm.getNumOutputDevices(); ++i)
47 {
48 if (auto out = dm.getOutputDeviceAt (i))
49 {
50 if (! out->isEnabled())
51 continue;
52
53 if (auto m = dynamic_cast<MidiOutputDevice*> (out))
54 {
55 if (m->isConnectedToExternalController())
56 continue;
57
58 hasMidi.setBit (s.size(), true);
59 }
60 else
61 {
62 hasAudio.setBit (s.size(), true);
63 }
64
65 s.add (out->getName());
66 a.add (out->getAlias());
67 }
68 }
69}
70
71
72//==============================================================================
73InsertPlugin::InsertPlugin (PluginCreationInfo info) : Plugin (info)
74{
75 auto um = getUndoManager();
76 name.referTo (state, IDs::name, um);
77 inputDevice.referTo (state, IDs::inputDevice, um);
78 outputDevice.referTo (state, IDs::outputDevice, um);
79 manualAdjustMs.referTo (state, IDs::manualAdjustMs, um);
80
81 updateDeviceTypes();
82}
83
84InsertPlugin::~InsertPlugin()
85{
86 notifyListenersOfDeletion();
87}
88
89//==============================================================================
90const char* InsertPlugin::xmlTypeName ("insert");
91
92juce::String InsertPlugin::getName() const { return name.get().isNotEmpty() ? name : TRANS("Insert Plugin"); }
93juce::String InsertPlugin::getPluginType() { return xmlTypeName; }
94juce::String InsertPlugin::getShortName (int) { return TRANS("Insert"); }
95double InsertPlugin::getLatencySeconds() { return latencySeconds; }
96void InsertPlugin::getChannelNames (juce::StringArray*, juce::StringArray*) {}
97bool InsertPlugin::takesAudioInput() { return true; }
98bool InsertPlugin::takesMidiInput() { return true; }
99bool InsertPlugin::canBeAddedToClip() { return false; }
100bool InsertPlugin::needsConstantBufferSize() { return true; }
101
102void InsertPlugin::initialise (const PluginInitialisationInfo& info)
103{
104 initialiseWithoutStopping (info);
105}
106
107void InsertPlugin::initialiseWithoutStopping (const PluginInitialisationInfo& info)
108{
109 TRACKTION_ASSERT_MESSAGE_THREAD
110 // This latency number is from trial and error, may need more testing.
111 // It should be accurate on well reporting devices though
112 int latency = static_cast<int> (timeToSample (manualAdjustMs / 1000.0, info.sampleRate));
113
114 if (auto device = engine.getDeviceManager().deviceManager.getCurrentAudioDevice())
115 {
116 if (sendDeviceType == audioDevice)
117 latency += device->getOutputLatencyInSamples();
118
119 if (returnDeviceType == audioDevice)
120 latency += device->getInputLatencyInSamples();
121 }
122
123 latency = std::max (0, latency);
124 latencyNumSamples = latency;
125 latencySeconds = TimeDuration::fromSamples (latency, info.sampleRate).inSeconds();
126}
127
128void InsertPlugin::deinitialise()
129{
130}
131
132void InsertPlugin::applyToBuffer (const PluginRenderContext&)
133{
135 jassertfalse; // This shouldn't be called anymore, it's handled directly by the playback graph
136}
137
138juce::String InsertPlugin::getSelectableDescription()
139{
140 return TRANS("Insert Plugin");
141}
142
143void InsertPlugin::restorePluginStateFromValueTree (const juce::ValueTree& v)
144{
145 if (v.hasProperty (IDs::name))
146 name = v.getProperty (IDs::name).toString();
147
148 if (v.hasProperty (IDs::outputDevice))
149 outputDevice = v.getProperty (IDs::outputDevice).toString();
150
151 if (v.hasProperty (IDs::inputDevice))
152 inputDevice = v.getProperty (IDs::inputDevice).toString();
153
154 for (auto p : getAutomatableParameters())
155 p->updateFromAttachedValue();
156}
157
158void InsertPlugin::updateDeviceTypes()
159{
161 TRACKTION_ASSERT_MESSAGE_THREAD
162
163 juce::StringArray devices, aliases;
164 juce::BigInteger hasAudio, hasMidi;
165
166 auto setDeviceType = [] (DeviceType& deviceType, juce::BigInteger& audio, juce::BigInteger& midi, int index)
167 {
168 if (audio[index]) deviceType = audioDevice;
169 else if (midi[index]) deviceType = midiDevice;
170 else deviceType = noDevice;
171 };
172
173 getPossibleInputDeviceNames (engine, devices, aliases, hasAudio, hasMidi);
174 setDeviceType (returnDeviceType, hasAudio, hasMidi, devices.indexOf (inputDevice.get()));
175
176 getPossibleOutputDeviceNames (engine, devices, aliases, hasAudio, hasMidi);
177 setDeviceType (sendDeviceType, hasAudio, hasMidi, devices.indexOf (outputDevice.get()));
178
179 propertiesChanged();
180 changed();
181}
182
183void InsertPlugin::getPossibleDeviceNames (Engine& e,
185 juce::BigInteger& hasAudio,
186 juce::BigInteger& hasMidi,
187 bool forInput)
188{
189 if (forInput)
190 getPossibleInputDeviceNames (e, s, a, hasAudio, hasMidi);
191 else
192 getPossibleOutputDeviceNames (e, s, a, hasAudio, hasMidi);
193}
194
195bool InsertPlugin::hasAudio() const { return sendDeviceType == audioDevice || returnDeviceType == audioDevice; }
196bool InsertPlugin::hasMidi() const { return sendDeviceType == midiDevice || returnDeviceType == midiDevice; }
197
198int InsertPlugin::getLatencyNumSamples() const
199{
200 return latencyNumSamples.load (std::memory_order_acquire);
201}
202
203void InsertPlugin::valueTreePropertyChanged (juce::ValueTree& v, const juce::Identifier& i)
204{
205 if (v == state)
206 {
207 auto update = [&i] (juce::CachedValue<juce::String>& deviceName) -> bool
208 {
209 if (i != deviceName.getPropertyID())
210 return false;
211
212 deviceName.forceUpdateOfCachedValue();
213 return true;
214 };
215
216 if (update (outputDevice) || update (inputDevice))
217 updateDeviceTypes();
218 }
219
220 Plugin::valueTreePropertyChanged (v, i);
221}
222
223}} // namespace tracktion { inline namespace engine
BigInteger & setBit(int bitNumber)
const String & toString() const noexcept
int size() const noexcept
void add(String stringToAdd)
T is_pointer_v
#define TRANS(stringLiteral)
#define jassertfalse
T max(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.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.