Audacity 3.2.0
LV2EffectBase.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LV2EffectBase.cpp
6
7 Paul Licameli split from LV2Effect.cpp
8
9 Audacity(R) is copyright (c) 1999-2008 Audacity Team.
10 License: GPL v2 or later. See License.txt.
11
12**********************************************************************/
13#if defined(USE_LV2)
14
15#if defined(__GNUC__)
16#pragma GCC diagnostic ignored "-Wparentheses"
17#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
18#elif defined(__clang__)
19#pragma clang diagnostic ignored "-Wparentheses"
20#pragma clang diagnostic ignored "-Wdeprecated-declarations"
21#endif
22
23#include "LV2EffectBase.h"
24#include "LV2Instance.h"
25#include "LV2Wrapper.h"
26#include "ConfigInterface.h"
27
28LV2EffectBase::LV2EffectBase(const LilvPlugin &plug) : mPlug{ plug }
29{
30}
31
33
34// ============================================================================
35// ComponentInterface Implementation
36// ============================================================================
37
39{
40 return LilvString(lilv_plugin_get_uri(&mPlug));
41}
42
44{
46}
47
49{
50 wxString vendor = LilvStringMove(lilv_plugin_get_author_name(&mPlug));
51
52 if (vendor.empty())
53 {
54 return XO("n/a");
55 }
56
57 return {vendor};
58}
59
61{
62 return wxT("1.0");
63}
64
66{
67 return XO("n/a");
68}
69
70// ============================================================================
71// EffectDefinitionInterface Implementation
72// ============================================================================
73
75{
76 if (mPorts.mAudioIn == 0 && mPorts.mAudioOut == 0)
77 {
78 return EffectTypeTool;
79 }
80
81 if (mPorts.mAudioIn == 0)
82 {
83 return EffectTypeGenerate;
84 }
85
86 if (mPorts.mAudioOut == 0)
87 {
88 return EffectTypeAnalyze;
89 }
90
91 return EffectTypeProcess;
92}
93
95{
96 return LV2EFFECTS_FAMILY;
97}
98
100{
101 return mPorts.mControlPorts.size() != 0;
102}
103
105{
106 return false;
107}
108
110{
111 // TODO reenable after achieving statelessness
112 return GetType() == EffectTypeProcess
115}
116
118{
119 return true;
120}
121
123{
124 if (!mFeatures.mOk)
125 return false;
126
127 // Do a check only on temporary feature list objects
128 auto instanceFeatures = LV2InstanceFeaturesList{ mFeatures };
129 if (!instanceFeatures.mOk)
130 return false;
132 return false;
133
134 // Determine available extensions
136 mWantsStateInterface = false;
137 if (LilvNodesPtr extdata{ lilv_plugin_get_extension_data(&mPlug) }) {
138 LILV_FOREACH(nodes, i, extdata.get()) {
139 const auto node = lilv_nodes_get(extdata.get(), i);
140 const auto uri = lilv_node_as_string(node);
141 if (strcmp(uri, LV2_OPTIONS__interface) == 0)
143 else if (strcmp(uri, LV2_STATE__interface) == 0)
145 }
146 }
147
148 return true;
149}
150
152{
153 auto result = EffectSettings::Make<LV2EffectSettings>();
154 auto &settings = GetSettings(result);
155 // This may waste a bit of space on output ports, but not likely much
156 settings.values.reserve(mPorts.mControlPorts.size());
157 for (auto &controlPort : mPorts.mControlPorts) {
158 auto &value = settings.values.emplace_back();
159 value = controlPort->mDef;
160 }
161 return result;
162}
163
165 const EffectSettings &src, EffectSettings &dst) const
166{
167 auto &srcControls = GetSettings(src).values;
168 auto &dstControls = GetSettings(dst).values;
169
170 const auto &controlPorts = mPorts.mControlPorts;
171 const auto portsCount = controlPorts.size();
172 // Do not use the copy constructor of std::vector. Do an in-place rewrite
173 // of the destination vector, which will not allocate memory if dstControls
174 // began with sufficient capacity.
175 // And that will be true if dstControls originated with MakeSettings() or a
176 // copy of it, because the set of control ports does not vary after
177 // initialization of the plug-in.
178 assert(srcControls.size() == portsCount);
179 assert(dstControls.size() == portsCount);
180 // But let's be sure
181 const auto portValuesCount =
182 std::min(srcControls.size(), dstControls.size());
183
184 if (portValuesCount != portsCount)
185 return false;
186
187 size_t portIndex {};
188
189 for (auto& port : controlPorts)
190 {
191 if (port->mIsInput)
192 dstControls[portIndex] = srcControls[portIndex];
193
194 ++portIndex;
195 }
196
197 // Ignore mpState
198
199 return true;
200}
201
202auto LV2EffectBase::MakeOutputs() const -> std::unique_ptr<EffectOutputs>
203{
204 auto result = std::make_unique<LV2EffectOutputs>();
205 auto &values = result->values;
206 // This may waste a bit of space on input ports, but not likely much
207 values.resize(mPorts.mControlPorts.size());
208 return result;
209}
210
211std::shared_ptr<EffectInstance> LV2EffectBase::MakeInstance() const
212{
213 auto result = std::make_shared<LV2Instance>(*this, mFeatures, mPorts);
214 if (result->IsOk())
215 return result;
216 return nullptr;
217}
218
220 const EffectSettings &settings, CommandParameters & parms) const
221{
222 auto &values = GetSettings(settings).values;
223 size_t index = 0;
224 for (auto & port : mPorts.mControlPorts) {
225 if (port->mIsInput)
226 if (!parms.Write(port->mName, values[index]))
227 return false;
228 ++index;
229 }
230 return true;
231}
232
234 const CommandParameters & parms, EffectSettings &settings) const
235{
236 // First pass validates values
237 for (auto & port : mPorts.mControlPorts) {
238 if (port->mIsInput) {
239 double d = 0.0;
240 if (!parms.Read(port->mName, &d))
241 return false;
242 // Use unscaled range here
243 if (d < port->mMin || d > port->mMax)
244 return false;
245 }
246 }
247
248 // Second pass actually sets the values
249 auto &values = GetSettings(settings).values;
250 size_t index = 0;
251 for (auto & port : mPorts.mControlPorts) {
252 if (port->mIsInput) {
253 double d = 0.0;
254 if (!parms.Read(port->mName, &d))
255 return false;
256 values[index] = d;
257 }
258 ++index;
259 }
260
261 return true;
262}
263
266{
268}
269
271 const RegistryPath &name, const EffectSettings &settings) const
272{
274}
275
277{
278 using namespace LV2Symbols;
280 return mFactoryPresetNames;
281
282 if (LilvNodesPtr presets{ lilv_plugin_get_related(&mPlug, node_Preset) }) {
283 LILV_FOREACH(nodes, i, presets.get()) {
284 const auto preset = lilv_nodes_get(presets.get(), i);
285
287
288 lilv_world_load_resource(gWorld, preset);
289
290 if (LilvNodesPtr labels{ lilv_world_find_nodes(gWorld, preset,
291 node_Label, nullptr) }) {
292 const auto label = lilv_nodes_get_first(labels.get());
294 }
295 else
296 mFactoryPresetNames.push_back(
297 LilvString(preset).AfterLast(wxT('#')));
298 }
299 }
300
302
303 return mFactoryPresetNames;
304}
305
308{
309 using namespace LV2Symbols;
310 if (id < 0 || id >= (int) mFactoryPresetUris.size())
311 return {};
312
313 LilvNodePtr preset{ lilv_new_uri(gWorld, mFactoryPresetUris[id].ToUTF8()) };
314 if (!preset)
315 return {};
316
317 using LilvStatePtr = Lilv_ptr<LilvState, lilv_state_free>;
318 LilvStatePtr state{
319 lilv_state_new_from_world(gWorld,
321 };
322 if (!state)
323 return {};
324
325 auto &mySettings = GetSettings(settings);
326 mPorts.EmitPortValues(*state, mySettings);
327 // Save the state, for whatever might not be contained in port values
328 mySettings.mpState = move(state);
329 return { nullptr };
330}
331
333{
334 return false;
335}
336
338{
339 return true;
340}
341
342// ============================================================================
343// LV2Effect Implementation
344// ============================================================================
345
347 const RegistryPath &group, EffectSettings &settings) const
348{
349 wxString parms;
350 if (!GetConfig(*this,
351 PluginSettings::Private, group, wxT("Parameters"), parms, wxEmptyString))
352 return {};
354 if (!eap.SetParameters(parms))
355 return {};
356 if (!LoadSettings(eap, settings))
357 return {};
358 return { nullptr };
359}
360
362 const RegistryPath &group, const EffectSettings &settings) const
363{
364 // PRL: This function just dumps the several control port values to the
365 // config files. Should it be reimplemented with
366 // lilv_state_new_from_instance to capture -- I don't know what -- other
367 // important state?
368
370 if (!SaveSettings(settings, eap))
371 return false;
372
373 wxString parms;
374 if (!eap.GetParameters(parms))
375 return false;
376
377 return SetConfig(*this,
378 PluginSettings::Private, group, wxT("Parameters"), parms);
379}
380#endif
wxT("CloseDown"))
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:76
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
const wxChar * values
XO("Cut/Copy/Paste")
wxString RegistryPath
Definition: Identifier.h:218
wxString PluginPath
type alias for identifying a Plugin supplied by a module, each module defining its own interpretation...
Definition: Identifier.h:214
std::vector< RegistryPath > RegistryPaths
Definition: Identifier.h:219
#define LV2EFFECTS_FAMILY
Definition: LV2Effect.h:31
Lilv_ptr< LilvNodes, lilv_nodes_free > LilvNodesPtr
wxString LilvString(const LilvNode *node)
Definition: LV2Utils.h:37
std::unique_ptr< Type, Lilv_deleter< Type, f > > Lilv_ptr
Generate classes of smart pointers to lv2 resources.
Definition: LV2Utils.h:26
wxString LilvStringMove(LilvNode *node)
Definition: LV2Utils.h:45
Lilv_ptr< LilvNode, lilv_node_free > LilvNodePtr
Definition: LV2Utils.h:33
EffectReverbSettings preset
Definition: Reverb.cpp:44
TranslatableString label
Definition: TagsEditor.cpp:165
static Settings & settings()
Definition: TrackInfo.cpp:47
CommandParameters, derived from wxFileConfig, is essentially doing the same things as the SettingsVis...
bool GetParameters(wxString &parms)
bool SetParameters(const wxString &parms)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
RealtimeSince
In which versions of Audacity was an effect realtime capable?
Hold values to send to effect output meters.
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
wxString GetVersion() const override
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
bool mFactoryPresetsLoaded
bool SaveParameters(const RegistryPath &group, const EffectSettings &settings) const
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
std::unique_ptr< EffectOutputs > MakeOutputs() const override
Produce an object to hold values to send to effect output meters.
EffectSettings MakeSettings() const override
VendorSymbol GetVendor() const override
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
TranslatableString GetDescription() const override
const LV2Ports mPorts
Definition: LV2EffectBase.h:90
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
PluginPath GetPath() const override
bool CanExportPresets() const override
Whether the effect supports export of presets to files, and importing too.
OptionalMessage LoadParameters(const RegistryPath &group, EffectSettings &settings) const
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
RealtimeSince RealtimeSupport() const override
Since which version of Audacity has the effect supported realtime?
bool CopySettingsContents(const EffectSettings &src, EffectSettings &dst) const override
Update one settings object from another.
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
RegistryPaths mFactoryPresetNames
bool InitializePlugin()
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
bool mWantsStateInterface
Definition: LV2EffectBase.h:93
bool HasOptions() const override
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
~LV2EffectBase() override
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
LV2EffectBase(const LilvPlugin &plug)
OptionalMessage LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
OptionalMessage LoadFactoryPreset(int id, EffectSettings &settings) const override
ComponentInterfaceSymbol GetSymbol() const override
EffectType GetType() const override
Type determines how it behaves.
wxArrayString mFactoryPresetUris
const LV2FeaturesList mFeatures
Definition: LV2EffectBase.h:88
bool mWantsOptionsInterface
Definition: LV2EffectBase.h:92
const LilvPlugin & mPlug
Definition: LV2EffectBase.h:87
LV2_URID_Map * URIDMapFeature() const
static ComponentInterfaceSymbol GetPluginSymbol(const LilvPlugin &plug)
void EmitPortValues(const LilvState &state, LV2EffectSettings &settings) const
Definition: LV2Ports.cpp:411
unsigned mAudioOut
Definition: LV2Ports.h:273
unsigned mAudioIn
Definition: LV2Ports.h:272
LV2ControlPortArray mControlPorts
Definition: LV2Ports.h:283
Holds a msgid for the translation catalog; may also bind format arguments.
LilvWorld * gWorld
Definition: LV2Symbols.cpp:31
bool SetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, const Value &value)
bool GetConfig(const EffectDefinitionInterface &ident, ConfigurationType type, const RegistryPath &group, const RegistryPath &key, Value &var, const Value &defval)
DynamicRangeProcessorSettings GetSettings(EffectSettingsAccess &access)
std::string ToUTF8(const std::wstring &wstr)
STL namespace.
Externalized state of a plug-in.