Audacity 3.2.0
LV2Effect.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 LV2Effect.cpp
6
7 Audacity(R) is copyright (c) 1999-2008 Audacity Team.
8 License: GPL v2 or later. See License.txt.
9
10**********************************************************************/
11
12#if defined(USE_LV2)
13
14#if defined(__GNUC__)
15#pragma GCC diagnostic ignored "-Wparentheses"
16#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
17#elif defined(__clang__)
18#pragma clang diagnostic ignored "-Wparentheses"
19#pragma clang diagnostic ignored "-Wdeprecated-declarations"
20#endif
21
22#include "LV2Effect.h"
23#include "LV2Instance.h"
24#include "LV2Validator.h"
25#include "LV2Wrapper.h"
26#include "SampleCount.h"
27
28#include <cmath>
29#include <exception>
30#include <functional>
31
32
33#ifdef __WXMAC__
34#include <wx/evtloop.h>
35#endif
36
37#include "ConfigInterface.h"
38#include "../../widgets/AudacityMessageBox.h"
39
40#if defined(__WXGTK__)
41#include <gtk/gtk.h>
42#endif
43
44#if defined(__WXMSW__)
45#include <wx/msw/wrapwin.h>
46#endif
47
49//
50// LV2Effect
51//
53
54LV2Effect::LV2Effect(const LilvPlugin &plug) : mPlug{ plug }
55{
56}
57
59{
60}
61
62// ============================================================================
63// ComponentInterface Implementation
64// ============================================================================
65
67{
68 return LilvString(lilv_plugin_get_uri(&mPlug));
69}
70
72{
74}
75
77{
78 wxString vendor = LilvStringMove(lilv_plugin_get_author_name(&mPlug));
79
80 if (vendor.empty())
81 {
82 return XO("n/a");
83 }
84
85 return {vendor};
86}
87
88wxString LV2Effect::GetVersion() const
89{
90 return wxT("1.0");
91}
92
94{
95 return XO("n/a");
96}
97
98// ============================================================================
99// EffectDefinitionInterface Implementation
100// ============================================================================
101
103{
104 if (mPorts.mAudioIn == 0 && mPorts.mAudioOut == 0)
105 {
106 return EffectTypeTool;
107 }
108
109 if (mPorts.mAudioIn == 0)
110 {
111 return EffectTypeGenerate;
112 }
113
114 if (mPorts.mAudioOut == 0)
115 {
116 return EffectTypeAnalyze;
117 }
118
119 return EffectTypeProcess;
120}
121
123{
124 return LV2EFFECTS_FAMILY;
125}
126
128{
129 return mPorts.mControlPorts.size() != 0;
130}
131
133{
134 return false;
135}
136
138{
139 // TODO reenable after achieving statelessness
140 return GetType() == EffectTypeProcess
143}
144
146{
147 return true;
148}
149
151{
152 if (!mFeatures.mOk)
153 return false;
154
155 // Do a check only on temporary feature list objects
156 auto instanceFeatures = LV2InstanceFeaturesList{ mFeatures };
157 if (!instanceFeatures.mOk)
158 return false;
159 if (!LV2UIFeaturesList{ LV2WrapperFeaturesList{instanceFeatures},
160 nullptr, lilv_plugin_get_uri(&mPlug)
161 }.mOk)
162 return false;
163
164 // Determine available extensions
166 mWantsStateInterface = false;
167 if (LilvNodesPtr extdata{ lilv_plugin_get_extension_data(&mPlug) }) {
168 LILV_FOREACH(nodes, i, extdata.get()) {
169 const auto node = lilv_nodes_get(extdata.get(), i);
170 const auto uri = lilv_node_as_string(node);
171 if (strcmp(uri, LV2_OPTIONS__interface) == 0)
173 else if (strcmp(uri, LV2_STATE__interface) == 0)
175 }
176 }
177
178 return true;
179}
180
182{
183 auto result = EffectSettings::Make<LV2EffectSettings>();
184 auto &settings = GetSettings(result);
185 // This may waste a bit of space on output ports, but not likely much
186 settings.values.reserve(mPorts.mControlPorts.size());
187 for (auto &controlPort : mPorts.mControlPorts) {
188 auto &value = settings.values.emplace_back();
189 value = controlPort->mDef;
190 }
191 return result;
192}
193
195 const EffectSettings &src, EffectSettings &dst) const
196{
197 auto &srcControls = GetSettings(src).values;
198 auto &dstControls = GetSettings(dst).values;
199
200 const auto &controlPorts = mPorts.mControlPorts;
201 const auto portsCount = controlPorts.size();
202 // Do not use the copy constructor of std::vector. Do an in-place rewrite
203 // of the destination vector, which will not allocate memory if dstControls
204 // began with sufficient capacity.
205 // And that will be true if dstControls originated with MakeSettings() or a
206 // copy of it, because the set of control ports does not vary after
207 // initialization of the plug-in.
208 assert(srcControls.size() == portsCount);
209 assert(dstControls.size() == portsCount);
210 // But let's be sure
211 const auto portValuesCount =
212 std::min(srcControls.size(), dstControls.size());
213
214 if (portValuesCount != portsCount)
215 return false;
216
217 size_t portIndex {};
218
219 for (auto& port : controlPorts)
220 {
221 if (port->mIsInput)
222 dstControls[portIndex] = srcControls[portIndex];
223
224 ++portIndex;
225 }
226
227 // Ignore mpState
228
229 return true;
230}
231
232auto LV2Effect::MakeOutputs() const -> std::unique_ptr<EffectOutputs>
233{
234 auto result = std::make_unique<LV2EffectOutputs>();
235 auto &values = result->values;
236 // This may waste a bit of space on input ports, but not likely much
237 values.resize(mPorts.mControlPorts.size());
238 return result;
239}
240
241std::shared_ptr<EffectInstance> LV2Effect::MakeInstance() const
242{
243 auto result = std::make_shared<LV2Instance>(*this, mFeatures, mPorts);
244 if (result->IsOk())
245 return result;
246 return nullptr;
247}
248
249int LV2Effect::ShowClientInterface(wxWindow &parent, wxDialog &dialog,
250 EffectUIValidator *pValidator, bool forceModal)
251{
252 if (pValidator)
253 // Remember the dialog with a weak pointer, but don't control its lifetime
254 static_cast<LV2Validator*>(pValidator)->mDialog = &dialog;
255 // Try to give the window a sensible default/minimum size
256 dialog.Layout();
257 dialog.Fit();
258 dialog.SetMinSize(dialog.GetSize());
260 dialog.SetMaxSize(dialog.GetSize());
261 if ((SupportsRealtime() || GetType() == EffectTypeAnalyze) && !forceModal) {
262 dialog.Show();
263 return 0;
264 }
265 return dialog.ShowModal();
266}
267
269 const EffectSettings &settings, CommandParameters & parms) const
270{
272 size_t index = 0;
273 for (auto & port : mPorts.mControlPorts) {
274 if (port->mIsInput)
275 if (!parms.Write(port->mName, values[index]))
276 return false;
277 ++index;
278 }
279 return true;
280}
281
283 const CommandParameters & parms, EffectSettings &settings) const
284{
285 // First pass validates values
286 for (auto & port : mPorts.mControlPorts) {
287 if (port->mIsInput) {
288 double d = 0.0;
289 if (!parms.Read(port->mName, &d))
290 return false;
291 // Use unscaled range here
292 if (d < port->mMin || d > port->mMax)
293 return false;
294 }
295 }
296
297 // Second pass actually sets the values
299 size_t index = 0;
300 for (auto & port : mPorts.mControlPorts) {
301 if (port->mIsInput) {
302 double d = 0.0;
303 if (!parms.Read(port->mName, &d))
304 return false;
305 values[index] = d;
306 }
307 ++index;
308 }
309
310 return true;
311}
312
313// ============================================================================
314// EffectUIClientInterface Implementation
315// ============================================================================
316
317// May come here before destructive processing
318// Or maybe not (if you "Repeat Last Effect")
319std::unique_ptr<EffectUIValidator> LV2Effect::PopulateUI(ShuttleGui &S,
320 EffectInstance &instance, EffectSettingsAccess &access,
321 const EffectOutputs *pOutputs)
322{
323 auto &settings = access.Get();
324 auto parent = S.GetParent();
325 mParent = parent;
326
327 auto &myInstance = dynamic_cast<LV2Instance &>(instance);
328 auto pWrapper =
329 // Output port connection isn't needed for fancy UI wrapper. Its
330 // features are needed to make the suil_instance
331 myInstance.MakeWrapper(settings, mProjectRate, nullptr);
332 if (!pWrapper) {
333 AudacityMessageBox( XO("Couldn't instantiate effect") );
334 return nullptr;
335 }
336
337 // Determine if the GUI editor is supposed to be used or not
338 bool useGUI = false;
339 LV2Preferences::GetUseGUI(*this, useGUI);
340
341 // Until I figure out where to put the "Duration" control in the
342 // graphical editor, force usage of plain editor.
344 useGUI = false;
345
346 auto result = std::make_unique<LV2Validator>(*this, mPlug,
347 dynamic_cast<LV2Instance&>(instance),
348 access, pOutputs, mProjectRate, mFeatures, mPorts, parent, useGUI);
349
350#ifdef __WXMAC__
351 const auto vendor = GetVendor().Msgid().Translation();
352 const bool doX42Hack = vendor == "Robin Gareus";
353 result->mUI.mJustLeakMemory = doX42Hack;
354#endif
355
356 if (result->mUseGUI)
357 result->mUseGUI = result->BuildFancy(move(pWrapper), settings);
358 if (!result->mUseGUI && !result->BuildPlain(access))
359 return nullptr;
360 result->UpdateUI();
361
362 return result;
363}
364
366{
367#ifdef __WXMAC__
368#ifdef __WX_EVTLOOP_BUSY_WAITING__
369 wxEventLoop::SetBusyWaiting(false);
370#endif
371#endif
372
373 mParent = nullptr;
374 return true;
375}
376
379{
381}
382
384 const RegistryPath &name, const EffectSettings &settings) const
385{
387}
388
390{
391 using namespace LV2Symbols;
393 return mFactoryPresetNames;
394
395 if (LilvNodesPtr presets{ lilv_plugin_get_related(&mPlug, node_Preset) }) {
396 LILV_FOREACH(nodes, i, presets.get()) {
397 const auto preset = lilv_nodes_get(presets.get(), i);
398
400
401 lilv_world_load_resource(gWorld, preset);
402
403 if (LilvNodesPtr labels{ lilv_world_find_nodes(gWorld, preset,
404 node_Label, nullptr) }) {
405 const auto label = lilv_nodes_get_first(labels.get());
407 }
408 else
409 mFactoryPresetNames.push_back(
410 LilvString(preset).AfterLast(wxT('#')));
411 }
412 }
413
415
416 return mFactoryPresetNames;
417}
418
421{
422 using namespace LV2Symbols;
423 if (id < 0 || id >= (int) mFactoryPresetUris.size())
424 return {};
425
426 LilvNodePtr preset{ lilv_new_uri(gWorld, mFactoryPresetUris[id].ToUTF8()) };
427 if (!preset)
428 return {};
429
430 using LilvStatePtr = Lilv_ptr<LilvState, lilv_state_free>;
431 LilvStatePtr state{
432 lilv_state_new_from_world(gWorld,
434 };
435 if (!state)
436 return {};
437
438 auto &mySettings = GetSettings(settings);
439 mPorts.EmitPortValues(*state, mySettings);
440 // Save the state, for whatever might not be contained in port values
441 mySettings.mpState = move(state);
442 return { nullptr };
443}
444
446{
447 return false;
448}
449
451{
452}
453
455{
456 return { nullptr };
457}
458
460{
461 return true;
462}
463
465{
466 LV2Preferences::Dialog{ mParent, *this }.ShowModal();
467}
468
469// ============================================================================
470// LV2Effect Implementation
471// ============================================================================
472
474 const RegistryPath &group, EffectSettings &settings) const
475{
476 wxString parms;
477 if (!GetConfig(*this,
478 PluginSettings::Private, group, wxT("Parameters"), parms, wxEmptyString))
479 return {};
481 if (!eap.SetParameters(parms))
482 return {};
483 if (!LoadSettings(eap, settings))
484 return {};
485 return { nullptr };
486}
487
489 const RegistryPath &group, const EffectSettings &settings) const
490{
491 // PRL: This function just dumps the several control port values to the
492 // config files. Should it be reimplemented with
493 // lilv_state_new_from_instance to capture -- I don't know what -- other
494 // important state?
495
497 if (!SaveSettings(settings, eap))
498 return false;
499
500 wxString parms;
501 if (!eap.GetParameters(parms))
502 return false;
503
504 return SetConfig(*this,
505 PluginSettings::Private, group, wxT("Parameters"), parms);
506}
507#endif
wxT("CloseDown"))
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
int min(int a, int b)
const TranslatableString name
Definition: Distortion.cpp:74
std::optional< std::unique_ptr< EffectSettingsAccess::Message > > OptionalMessage
EffectType
@ EffectTypeAnalyze
@ EffectTypeGenerate
@ EffectTypeTool
@ EffectTypeProcess
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:32
Lilv_ptr< LilvNodes, lilv_nodes_free > LilvNodesPtr
LV2EffectSettings & GetSettings(EffectSettings &settings)
Definition: LV2Ports.h:215
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:45
TranslatableString label
Definition: TagsEditor.cpp:164
#define S(N)
Definition: ToChars.cpp:64
static Settings & settings()
Definition: TrackInfo.cpp:87
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,...
const TranslatableString & Msgid() const
double mProjectRate
Definition: EffectBase.h:101
RealtimeSince
In which versions of Audacity was an effect realtime capable?
Performs effect computation.
Hold values to send to effect output meters.
virtual const EffectSettings & Get()=0
Interface for transferring values from a panel of effect controls.
Definition: EffectPlugin.h:239
virtual ~LV2Effect()
Definition: LV2Effect.cpp:58
VendorSymbol GetVendor() const override
Definition: LV2Effect.cpp:76
bool mFactoryPresetsLoaded
Definition: LV2Effect.h:129
bool CopySettingsContents(const EffectSettings &src, EffectSettings &dst) const override
Update one settings object from another.
Definition: LV2Effect.cpp:194
PluginPath GetPath() const override
Definition: LV2Effect.cpp:66
int ShowClientInterface(wxWindow &parent, wxDialog &dialog, EffectUIValidator *pValidator, bool forceModal) override
Definition: LV2Effect.cpp:249
RegistryPaths GetFactoryPresets() const override
Report names of factory presets.
Definition: LV2Effect.cpp:389
bool SupportsAutomation() const override
Whether the effect has any automatable controls.
Definition: LV2Effect.cpp:145
OptionalMessage LoadUserPreset(const RegistryPath &name, EffectSettings &settings) const override
Definition: LV2Effect.cpp:377
RealtimeSince RealtimeSupport() const override
Since which version of Audacity has the effect supported realtime?
Definition: LV2Effect.cpp:137
EffectFamilySymbol GetFamily() const override
Report identifier and user-visible name of the effect protocol.
Definition: LV2Effect.cpp:122
void ExportPresets(const EffectSettings &settings) const override
Definition: LV2Effect.cpp:450
void ShowOptions() override
Definition: LV2Effect.cpp:464
bool HasOptions() override
Definition: LV2Effect.cpp:459
bool SaveParameters(const RegistryPath &group, const EffectSettings &settings) const
Definition: LV2Effect.cpp:488
bool InitializePlugin()
Definition: LV2Effect.cpp:150
RegistryPaths mFactoryPresetNames
Definition: LV2Effect.h:130
EffectSettings MakeSettings() const override
Definition: LV2Effect.cpp:181
bool mWantsStateInterface
Definition: LV2Effect.h:117
bool SaveSettings(const EffectSettings &settings, CommandParameters &parms) const override
Store settings as keys and values.
Definition: LV2Effect.cpp:268
LV2Effect(const LilvPlugin &plug)
Definition: LV2Effect.cpp:54
std::unique_ptr< EffectOutputs > MakeOutputs() const override
Produce an object to hold values to send to effect output meters.
Definition: LV2Effect.cpp:232
bool CloseUI() override
Definition: LV2Effect.cpp:365
EffectType GetType() const override
Type determines how it behaves.
Definition: LV2Effect.cpp:102
wxString GetVersion() const override
Definition: LV2Effect.cpp:88
OptionalMessage LoadParameters(const RegistryPath &group, EffectSettings &settings) const
Definition: LV2Effect.cpp:473
wxArrayString mFactoryPresetUris
Definition: LV2Effect.h:131
bool mWantsOptionsInterface
Definition: LV2Effect.h:116
const LV2Ports mPorts
Definition: LV2Effect.h:114
ComponentInterfaceSymbol GetSymbol() const override
Definition: LV2Effect.cpp:71
std::unique_ptr< EffectUIValidator > PopulateUI(ShuttleGui &S, EffectInstance &instance, EffectSettingsAccess &access, const EffectOutputs *pOutputs) override
Adds controls to a panel that is given as the parent window of S
Definition: LV2Effect.cpp:319
bool LoadSettings(const CommandParameters &parms, EffectSettings &settings) const override
Restore settings from keys and values.
Definition: LV2Effect.cpp:282
std::shared_ptr< EffectInstance > MakeInstance() const override
Make an object maintaining short-term state of an Effect.
Definition: LV2Effect.cpp:241
bool IsInteractive() const override
Whether the effect needs a dialog for entry of settings.
Definition: LV2Effect.cpp:127
const LV2FeaturesList mFeatures
Definition: LV2Effect.h:112
bool CanExportPresets() override
Definition: LV2Effect.cpp:445
OptionalMessage LoadFactoryPreset(int id, EffectSettings &settings) const override
Definition: LV2Effect.cpp:420
OptionalMessage ImportPresets(EffectSettings &settings) override
Definition: LV2Effect.cpp:454
TranslatableString GetDescription() const override
Definition: LV2Effect.cpp:93
bool SaveUserPreset(const RegistryPath &name, const EffectSettings &settings) const override
Save settings in the configuration file as a user-named preset.
Definition: LV2Effect.cpp:383
wxWindow * mParent
Definition: LV2Effect.h:126
bool IsDefault() const override
Whether the effect sorts "above the line" in the menus.
Definition: LV2Effect.cpp:132
const LilvPlugin & mPlug
Definition: LV2Effect.h:111
LV2_URID_Map * URIDMapFeature() const
static ComponentInterfaceSymbol GetPluginSymbol(const LilvPlugin &plug)
std::unique_ptr< LV2Wrapper > MakeWrapper(const EffectSettings &settings, double sampleRate, EffectOutputs *pOutputs)
Definition: LV2Instance.cpp:59
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
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:628
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
bool GetUseGUI(const EffectDefinitionInterface &effect, bool &useGUI)
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)
std::string ToUTF8(const std::wstring &wstr)
STL namespace.
Externalized state of a plug-in.
std::vector< float > values
vector of values in correspondence with the control ports
Definition: LV2Ports.h:208