Audacity 3.2.0
LV2FeaturesList.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file LV2FeaturesList.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
14#if defined(USE_LV2)
15
16#if defined(__GNUC__)
17#pragma GCC diagnostic ignored "-Wparentheses"
18#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
19#elif defined(__clang__)
20#pragma clang diagnostic ignored "-Wparentheses"
21#pragma clang diagnostic ignored "-Wdeprecated-declarations"
22#endif
23
24#include "LV2FeaturesList.h"
25#include <wx/crt.h>
26#include <wx/log.h>
27#include "lv2/buf-size/buf-size.h"
28#include "lv2_external_ui.h"
29#include "lv2/worker/worker.h"
30
32
35 const LV2FeaturesListBase &baseFeatures
36) : LV2FeaturesListBase{ baseFeatures.mPlug }
37 , mBaseFeatures{ baseFeatures }
38{
39}
40
42{
44 result.pop_back();
45 for (auto &feature : mFeatures)
46 result.push_back(&feature);
47 result.push_back(nullptr);
48 return result;
49}
50
51void ExtendedLV2FeaturesList::AddFeature(const char *uri, const void *data)
52{
53 // This casting to const is innocent
54 // We pass our "virtual function tables" or array of options, which the
55 // library presumably will not change
56 mFeatures.emplace_back(LV2_Feature{ uri, const_cast<void*>(data) });
57}
58
60
62LV2FeaturesList::GetPluginSymbol(const LilvPlugin &plug)
63{
64 return LilvStringMove(lilv_plugin_get_name(&plug));
65}
66
67LV2FeaturesListBase::LV2FeaturesListBase(const LilvPlugin &plug) : mPlug{ plug }
68{
69}
70
71LV2FeaturesList::LV2FeaturesList(const LilvPlugin &plug)
72 : LV2FeaturesListBase{ plug }
73 , mSuppliesWorkerInterface{ SuppliesWorkerInterface(plug) }
74 , mOk{ InitializeFeatures() }
75{
76}
77
79{
80 // Construct null-terminated array of "features" describing our capabilities
81 // to lv2, and validate
82 AddFeature(LV2_UI__noUserResize, nullptr);
83 AddFeature(LV2_UI__fixedSize, nullptr);
84 AddFeature(LV2_UI__idleInterface, nullptr);
86 AddFeature(LV2_BUF_SIZE__boundedBlockLength, nullptr);
87 AddFeature(LV2_BUF_SIZE__fixedBlockLength, nullptr);
88 AddFeature(LV2_URI_MAP_URI, &mUriMapFeature);
89 AddFeature(LV2_URID__map, &mURIDMapFeature);
90 AddFeature(LV2_URID__unmap, &mURIDUnmapFeature);
91 AddFeature(LV2_LOG__log, &mLogFeature);
92 // Some plugins specify this as a feature
94 return true;
95}
96
97bool LV2FeaturesList::SuppliesWorkerInterface(const LilvPlugin &plug)
98{
99 bool result = false;
100 if (LilvNodesPtr extdata{ lilv_plugin_get_extension_data(&plug) }) {
101 LILV_FOREACH(nodes, i, extdata.get()) {
102 const auto node = lilv_nodes_get(extdata.get(), i);
103 const auto uri = lilv_node_as_string(node);
104 if (strcmp(uri, LV2_WORKER__interface) == 0)
105 result = true;
106 }
107 }
108 return result;
109}
110
111void LV2FeaturesList::AddFeature(const char *uri, const void *data)
112{
113 // This casting to const is innocent
114 // We pass our "virtual function tables" or array of options, which the
115 // library presumably will not change
116 mFeatures.emplace_back(LV2_Feature{ uri, const_cast<void*>(data) });
117}
118
120{
121 FeaturePointers result;
122 for (auto &feature : mFeatures)
123 result.push_back(&feature);
124 result.push_back(nullptr);
125 return result;
126}
127
128bool LV2FeaturesListBase::ValidateFeatures(const LilvNode *subject)
129{
130 return CheckFeatures(subject, true) && CheckFeatures(subject, false);
131}
132
133bool LV2FeaturesListBase::CheckFeatures(const LilvNode *subject, bool required)
134{
135 using namespace LV2Symbols;
136 bool supported = true;
137 auto predicate = required ? node_RequiredFeature : node_OptionalFeature;
138 if (LilvNodesPtr nodes{
139 lilv_world_find_nodes(gWorld, subject, predicate, nullptr) }
140 ){
141 LILV_FOREACH(nodes, i, nodes.get()) {
142 const auto node = lilv_nodes_get(nodes.get(), i);
143 const auto uri = lilv_node_as_string(node);
144 if ((strcmp(uri, LV2_UI__noUserResize) == 0) ||
145 (strcmp(uri, LV2_UI__fixedSize) == 0))
146 mNoResize = true;
147 else if (strcmp(uri, LV2_WORKER__schedule) == 0) {
148 /* Supported but handled in LV2Wrapper */
149 }
150 else if (required) {
151 auto features = GetFeaturePointers();
152 const auto end = features.end();
153 supported = (end != std::find_if(features.begin(), end,
154 [&](auto &pFeature){ return pFeature &&
155 strcmp(pFeature->URI, uri) == 0; }));
156 if (!supported) {
157 wxLogError(wxT("%s requires unsupported feature %s"),
158 lilv_node_as_string(lilv_plugin_get_uri(&mPlug)), uri);
159 break;
160 }
161 }
162 }
163 }
164 return supported;
165}
166
167// ============================================================================
168// Feature handlers
169// ============================================================================
170
171// static callback
173 LV2_URI_Map_Callback_Data callback_data, const char *, const char *uri)
174{
175 return static_cast<LV2FeaturesList *>(callback_data)->URID_Map(uri);
176}
177
178// static callback
179LV2_URID LV2FeaturesList::urid_map(LV2_URID_Map_Handle handle, const char *uri)
180{
181 return static_cast<LV2FeaturesList *>(handle)->URID_Map(uri);
182}
183
184LV2_URID LV2FeaturesList::URID_Map(const char *uri) const
185{
186 using namespace LV2Symbols;
187 // Map global URIs to lower indices
188 auto urid = Lookup_URI(gURIDMap, uri, false);
189 if (urid > 0)
190 return urid;
191 // Map local URIs to higher indices
192 urid = Lookup_URI(mURIDMap, uri);
193 if (urid > 0)
194 return urid + gURIDMap.size();
195 return 0;
196}
197
198// static callback
199const char *LV2FeaturesList::urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid)
200{
201 return static_cast<LV2FeaturesList *>(handle)->URID_Unmap(urid);
202}
203
204const char *LV2FeaturesList::URID_Unmap(LV2_URID urid)
205{
206 using namespace LV2Symbols;
207 if (urid > 0) {
208 // Unmap lower indices to global URIs
209 if (urid <= static_cast<LV2_URID>(gURIDMap.size()))
210 return gURIDMap[urid - 1].get();
211 // Unmap higher indices to local URIs
212 urid -= gURIDMap.size();
213 if (urid <= static_cast<LV2_URID>(mURIDMap.size()))
214 return mURIDMap[urid - 1].get();
215 }
216 return nullptr;
217}
218
219// static callback
221 LV2_Log_Handle handle, LV2_URID type, const char *fmt, ...)
222{
223 va_list ap;
224 int len;
225
226 va_start(ap, fmt);
227 len = static_cast<LV2FeaturesList *>(handle)->LogVPrintf(type, fmt, ap);
228 va_end(ap);
229
230 return len;
231}
232
233// static callback
235 LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list ap)
236{
237 return static_cast<LV2FeaturesList *>(handle)->LogVPrintf(type, fmt, ap);
238}
239
240int LV2FeaturesList::LogVPrintf(LV2_URID type, const char *fmt, va_list ap)
241{
242 using namespace LV2Symbols;
243 long level = wxLOG_Error;
244 if (type == urid_Error)
245 level = wxLOG_Error;
246 else if (type == urid_Note)
247 level = wxLOG_Info;
248 else if (type == urid_Trace)
249 level = wxLOG_Trace;
250 else if (type == urid_Warning)
251 level = wxLOG_Warning;
252 else
253 level = wxLOG_Message;
254 int len = wxCRT_VsnprintfA(nullptr, 0, fmt, ap);
255 auto msg = std::make_unique<char[]>(len + 1);
256 wxCRT_VsnprintfA(msg.get(), len, fmt, ap);
257 wxString text(msg.get());
258 wxLogGeneric(level,
259 wxT("%s: %s"), GetPluginSymbol(mPlug).Msgid().Translation(), text);
260 return len;
261}
262#endif
wxT("CloseDown"))
Lilv_ptr< LilvNodes, lilv_nodes_free > LilvNodesPtr
#define LV2_UI__makeResident
Definition: LV2Symbols.h:30
wxString LilvStringMove(LilvNode *node)
Definition: LV2Utils.h:45
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
virtual ~ExtendedLV2FeaturesList()
FeaturePointers GetFeaturePointers() const override
void AddFeature(const char *uri, const void *data)
const LV2FeaturesListBase & mBaseFeatures
ExtendedLV2FeaturesList(WithBase_t, const LV2FeaturesListBase &baseFeatures)
std::vector< LV2_Feature > mFeatures
LV2FeaturesListBase(const LilvPlugin &plug)
bool CheckFeatures(const LilvNode *subject, bool required)
bool ValidateFeatures(const LilvNode *subject)
const LilvPlugin & mPlug
std::vector< const LV2_Feature * > FeaturePointers
Get vector of pointers to features, whose .data() can be passed to lv2.
virtual ~LV2FeaturesListBase()
virtual FeaturePointers GetFeaturePointers() const =0
~LV2FeaturesList() override
void AddFeature(const char *uri, const void *data)
const LV2_URID_Map mURIDMapFeature
LV2Symbols::URIDMap mURIDMap
Per-effect URID map allocates an ID for each URI on first lookup.
LV2_URID URID_Map(const char *uri) const
const LV2_Log_Log mLogFeature
static LV2_URID urid_map(LV2_URID_Map_Handle handle, const char *uri)
LV2FeaturesList(const LilvPlugin &plug)
const char * URID_Unmap(LV2_URID urid)
std::vector< LV2_Feature > mFeatures
const LV2_URI_Map_Feature mUriMapFeature
static uint32_t uri_to_id(LV2_URI_Map_Callback_Data callback_data, const char *map, const char *uri)
const LV2_URID_Unmap mURIDUnmapFeature
static int log_printf(LV2_Log_Handle handle, LV2_URID type, const char *fmt,...)
static const char * urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid)
static ComponentInterfaceSymbol GetPluginSymbol(const LilvPlugin &plug)
FeaturePointers GetFeaturePointers() const override
static int log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char *fmt, va_list ap)
int LogVPrintf(LV2_URID type, const char *fmt, va_list ap)
bool SuppliesWorkerInterface() const
#define LV2_EXTERNAL_UI__Widget
LV2_URID Lookup_URI(URIDMap &map, const char *uri, bool add)
Definition: LV2Symbols.cpp:76
LilvWorld * gWorld
Definition: LV2Symbols.cpp:31
URIDMap gURIDMap
Declare the global map of positive integers to URIs.
Definition: LV2Symbols.cpp:34
const char * end(const char *str) noexcept
Definition: StringUtils.h:106