LMMS
Loading...
Searching...
No Matches
CachedPlugins.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "CarlaUtils.h"
5
6#include "CarlaNative.h"
7#include "CarlaString.hpp"
8#include "CarlaBackendUtils.hpp"
9#include "CarlaLv2Utils.hpp"
10
11#ifndef STATIC_PLUGIN_TARGET
12# define HAVE_SFZ
14#endif
15
16#ifdef HAVE_YSFX
17# include "CarlaJsfxUtils.hpp"
18#endif
19
20#include "water/files/File.h"
21
22namespace CB = CARLA_BACKEND_NAMESPACE;
23
24// -------------------------------------------------------------------------------------------------------------------
25
26static const char* const gCachedPluginsNullCharPtr = "";
27
28static bool isCachedPluginType(const CB::PluginType ptype)
29{
30 switch (ptype)
31 {
32 case CB::PLUGIN_INTERNAL:
33 case CB::PLUGIN_LV2:
34 case CB::PLUGIN_AU:
35 case CB::PLUGIN_SFZ:
36 case CB::PLUGIN_JSFX:
37 return true;
38 default:
39 return false;
40 }
41}
42
43// -------------------------------------------------------------------------------------------------------------------
44
45_CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept
46 : valid(false),
47 category(CB::PLUGIN_CATEGORY_NONE),
48 hints(0x0),
49 audioIns(0),
50 audioOuts(0),
51 cvIns(0),
52 cvOuts(0),
53 midiIns(0),
54 midiOuts(0),
55 parameterIns(0),
56 parameterOuts(0),
61
62// -------------------------------------------------------------------------------------------------------------------
63
64#ifdef HAVE_SFZ
65static std::vector<water::File> gSFZs;
66
67static void findSFZs(const char* const sfzPaths)
68{
69 gSFZs.clear();
70
71 CARLA_SAFE_ASSERT_RETURN(sfzPaths != nullptr,);
72
73 if (sfzPaths[0] == '\0')
74 return;
75
77
78 for (water::String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
79 {
80 std::vector<water::File> results;
81
83 {
84 gSFZs.reserve(gSFZs.size() + results.size());
85 gSFZs.insert(gSFZs.end(), results.begin(), results.end());
86 }
87 }
88}
89#endif
90
91// -------------------------------------------------------------------------------------------------------------------
92
93#ifdef HAVE_YSFX
94static std::vector<CB::CarlaJsfxUnit> gJSFXs;
95
96static void findJSFXs(const char* const jsfxPaths)
97{
98 gJSFXs.clear();
99
100 CARLA_SAFE_ASSERT_RETURN(jsfxPaths != nullptr,);
101
102 if (jsfxPaths[0] == '\0')
103 return;
104
106
107 for (water::String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
108 {
109 std::vector<water::File> results;
110 const water::File path(*it);
111
112 if (path.findChildFiles(results, water::File::findFiles|water::File::ignoreHiddenFiles, true, "*") > 0)
113 {
114 gJSFXs.reserve(gJSFXs.size() + results.size());
115
116 for (std::vector<water::File>::iterator it2=results.begin(), end2=results.end(); it2 != end2; ++it2)
117 {
118 const water::File& file(*it2);
119 const water::String fileExt = file.getFileExtension();
120 if (fileExt.isEmpty() || fileExt.equalsIgnoreCase(".jsfx"))
121 gJSFXs.push_back(CB::CarlaJsfxUnit(path, file));
122 }
123 }
124 }
125}
126#endif
127
128// -------------------------------------------------------------------------------------------------------------------
129
131{
133
134 info.category = static_cast<CB::PluginCategory>(desc.category);
135 info.hints = 0x0;
136
138 info.hints |= CB::PLUGIN_IS_RTSAFE;
139 if (desc.hints & NATIVE_PLUGIN_IS_SYNTH)
140 info.hints |= CB::PLUGIN_IS_SYNTH;
141 if (desc.hints & NATIVE_PLUGIN_HAS_UI)
142 info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
144 info.hints |= CB::PLUGIN_HAS_INLINE_DISPLAY;
146 info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS;
148 info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD;
150 info.hints |= CB::PLUGIN_USES_MULTI_PROGS;
151
152 info.valid = true;
153 info.audioIns = desc.audioIns;
154 info.audioOuts = desc.audioOuts;
155 info.cvIns = desc.cvIns;
156 info.cvOuts = desc.cvOuts;
157 info.midiIns = desc.midiIns;
158 info.midiOuts = desc.midiOuts;
159 info.parameterIns = desc.paramIns;
160 info.parameterOuts = desc.paramOuts;
161 info.name = desc.name;
162 info.label = desc.label;
163 info.maker = desc.maker;
164 info.copyright = desc.copyright;
165 return &info;
166}
167
168// -------------------------------------------------------------------------------------------------------------------
169
170static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2World, Lilv::Plugin& lilvPlugin)
171{
173
174 info.valid = false;
175 bool supported = true;
176
177 // ----------------------------------------------------------------------------------------------------------------
178 // text data
179
180 {
181 static CarlaString suri, sname, smaker, slicense;
182 suri.clear(); sname.clear(); smaker.clear(); slicense.clear();
183
184 suri = lilvPlugin.get_uri().as_uri();
185
186 if (char* const bundle = lilv_file_uri_parse(lilvPlugin.get_bundle_uri().as_uri(), nullptr))
187 {
188 const water::File fbundle(bundle);
189 suri = (fbundle.getFileName() + CARLA_OS_SEP).toRawUTF8() + suri;
190 lilv_free(bundle);
191 }
192 else
193 {
194 suri = CARLA_OS_SEP_STR + suri;
195 }
196
197#if 0 // def HAVE_FLUIDSYNTH
198 // If we have fluidsynth support built-in, loading these plugins will lead to issues
199 if (suri == "urn:ardour:a-fluidsynth")
200 return &info;
201 if (suri == "http://calf.sourceforge.net/plugins/Fluidsynth")
202 return &info;
203#endif
204
205 if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me))
206 {
207 if (const char* const name = lilv_node_as_string(nameNode))
208 sname = name;
209 lilv_node_free(nameNode);
210 }
211
212 if (LilvNode* const authorNode = lilv_plugin_get_author_name(lilvPlugin.me))
213 {
214 if (const char* const author = lilv_node_as_string(authorNode))
215 smaker = author;
216 lilv_node_free(authorNode);
217 }
218
219 Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license));
220
221 if (licenseNodes.size() > 0)
222 {
223 if (LilvNode* const licenseNode = lilv_nodes_get_first(licenseNodes.me))
224 {
225 if (const char* const license = lilv_node_as_string(licenseNode))
226 slicense = license;
227 // lilv_node_free(licenseNode);
228 }
229 }
230
231 lilv_nodes_free(const_cast<LilvNodes*>(licenseNodes.me));
232
233 info.name = sname.buffer();
234 info.label = suri.buffer();
235 info.maker = smaker.buffer();
236 info.copyright = slicense.buffer();
237 }
238
239 // ----------------------------------------------------------------------------------------------------------------
240 // features
241
242 info.hints = 0x0;
243
244 {
245 Lilv::UIs lilvUIs(lilvPlugin.get_uis());
246
247 if (lilvUIs.size() > 0)
248 {
249 info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
250
251 LILV_FOREACH(uis, it, lilvUIs)
252 {
253 Lilv::UI lilvUI(lilvUIs.get(it));
254 lv2World.load_resource(lilvUI.get_uri());
255
256 #if defined(CARLA_OS_MAC)
257 if (lilvUI.is_a(lv2World.ui_cocoa))
258 #elif defined(CARLA_OS_WIN)
259 if (lilvUI.is_a(lv2World.ui_windows))
260 #elif defined(HAVE_X11)
261 if (lilvUI.is_a(lv2World.ui_x11))
262 #else
263 if (false)
264 #endif
265 {
266 info.hints |= CB::PLUGIN_HAS_CUSTOM_EMBED_UI;
267 break;
268 }
269 }
270 }
271#ifdef CARLA_OS_LINUX
272 else if (lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr)
273 info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
274#endif
275
276 lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));
277 }
278
279 {
280 Lilv::Nodes lilvRequiredFeatureNodes(lilvPlugin.get_required_features());
281
282 LILV_FOREACH(nodes, it, lilvRequiredFeatureNodes)
283 {
284 Lilv::Node lilvFeatureNode(lilvRequiredFeatureNodes.get(it));
285 const char* const featureURI(lilvFeatureNode.as_uri());
286 CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
287
288 if (! is_lv2_feature_supported(featureURI))
289 {
290 if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0
291 || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0)
292 {
293 // we give a warning about this below
294 continue;
295 }
296
297 supported = false;
298 carla_stderr("LV2 plugin '%s' requires unsupported feature '%s'", info.label, featureURI);
299 }
300 }
301
302 lilv_nodes_free(const_cast<LilvNodes*>(lilvRequiredFeatureNodes.me));
303 }
304
305 {
306 Lilv::Nodes lilvSupportedFeatureNodes(lilvPlugin.get_supported_features());
307
308 LILV_FOREACH(nodes, it, lilvSupportedFeatureNodes)
309 {
310 Lilv::Node lilvFeatureNode(lilvSupportedFeatureNodes.get(it));
311 const char* const featureURI(lilvFeatureNode.as_uri());
312 CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
313
314 /**/ if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0)
315 {
316 info.hints |= CB::PLUGIN_IS_RTSAFE;
317 }
318 else if (std::strcmp(featureURI, LV2_INLINEDISPLAY__queue_draw) == 0)
319 {
320 info.hints |= CB::PLUGIN_HAS_INLINE_DISPLAY;
321 }
322 else if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0
323 || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0)
324 {
325 carla_stderr("LV2 plugin '%s' DSP wants UI feature '%s', ignoring this", info.label, featureURI);
326 }
327 }
328
329 lilv_nodes_free(const_cast<LilvNodes*>(lilvSupportedFeatureNodes.me));
330 }
331
332 // ----------------------------------------------------------------------------------------------------------------
333 // category
334
335 info.category = CB::PLUGIN_CATEGORY_NONE;
336
337 {
338 Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type));
339
340 if (typeNodes.size() > 0)
341 {
342 if (typeNodes.contains(lv2World.class_allpass))
343 info.category = CB::PLUGIN_CATEGORY_FILTER;
344 if (typeNodes.contains(lv2World.class_amplifier))
345 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
346 if (typeNodes.contains(lv2World.class_analyzer))
347 info.category = CB::PLUGIN_CATEGORY_UTILITY;
348 if (typeNodes.contains(lv2World.class_bandpass))
349 info.category = CB::PLUGIN_CATEGORY_FILTER;
350 if (typeNodes.contains(lv2World.class_chorus))
351 info.category = CB::PLUGIN_CATEGORY_MODULATOR;
352 if (typeNodes.contains(lv2World.class_comb))
353 info.category = CB::PLUGIN_CATEGORY_FILTER;
354 if (typeNodes.contains(lv2World.class_compressor))
355 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
356 if (typeNodes.contains(lv2World.class_constant))
357 info.category = CB::PLUGIN_CATEGORY_OTHER;
358 if (typeNodes.contains(lv2World.class_converter))
359 info.category = CB::PLUGIN_CATEGORY_UTILITY;
360 if (typeNodes.contains(lv2World.class_delay))
361 info.category = CB::PLUGIN_CATEGORY_DELAY;
362 if (typeNodes.contains(lv2World.class_distortion))
363 info.category = CB::PLUGIN_CATEGORY_DISTORTION;
364 if (typeNodes.contains(lv2World.class_dynamics))
365 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
366 if (typeNodes.contains(lv2World.class_eq))
367 info.category = CB::PLUGIN_CATEGORY_EQ;
368 if (typeNodes.contains(lv2World.class_envelope))
369 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
370 if (typeNodes.contains(lv2World.class_expander))
371 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
372 if (typeNodes.contains(lv2World.class_filter))
373 info.category = CB::PLUGIN_CATEGORY_FILTER;
374 if (typeNodes.contains(lv2World.class_flanger))
375 info.category = CB::PLUGIN_CATEGORY_MODULATOR;
376 if (typeNodes.contains(lv2World.class_function))
377 info.category = CB::PLUGIN_CATEGORY_UTILITY;
378 if (typeNodes.contains(lv2World.class_gate))
379 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
380 if (typeNodes.contains(lv2World.class_generator))
381 info.category = CB::PLUGIN_CATEGORY_OTHER;
382 if (typeNodes.contains(lv2World.class_highpass))
383 info.category = CB::PLUGIN_CATEGORY_FILTER;
384 if (typeNodes.contains(lv2World.class_limiter))
385 info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
386 if (typeNodes.contains(lv2World.class_lowpass))
387 info.category = CB::PLUGIN_CATEGORY_FILTER;
388 if (typeNodes.contains(lv2World.class_mixer))
389 info.category = CB::PLUGIN_CATEGORY_UTILITY;
390 if (typeNodes.contains(lv2World.class_modulator))
391 info.category = CB::PLUGIN_CATEGORY_MODULATOR;
392 if (typeNodes.contains(lv2World.class_multiEQ))
393 info.category = CB::PLUGIN_CATEGORY_EQ;
394 if (typeNodes.contains(lv2World.class_oscillator))
395 info.category = CB::PLUGIN_CATEGORY_OTHER;
396 if (typeNodes.contains(lv2World.class_paraEQ))
397 info.category = CB::PLUGIN_CATEGORY_EQ;
398 if (typeNodes.contains(lv2World.class_phaser))
399 info.category = CB::PLUGIN_CATEGORY_MODULATOR;
400 if (typeNodes.contains(lv2World.class_pitch))
401 info.category = CB::PLUGIN_CATEGORY_OTHER;
402 if (typeNodes.contains(lv2World.class_reverb))
403 info.category = CB::PLUGIN_CATEGORY_DELAY;
404 if (typeNodes.contains(lv2World.class_simulator))
405 info.category = CB::PLUGIN_CATEGORY_OTHER;
406 if (typeNodes.contains(lv2World.class_spatial))
407 info.category = CB::PLUGIN_CATEGORY_OTHER;
408 if (typeNodes.contains(lv2World.class_spectral))
409 info.category = CB::PLUGIN_CATEGORY_OTHER;
410 if (typeNodes.contains(lv2World.class_utility))
411 info.category = CB::PLUGIN_CATEGORY_UTILITY;
412 if (typeNodes.contains(lv2World.class_waveshaper))
413 info.category = CB::PLUGIN_CATEGORY_DISTORTION;
414 if (typeNodes.contains(lv2World.class_instrument))
415 {
416 info.category = CB::PLUGIN_CATEGORY_SYNTH;
417 info.hints |= CB::PLUGIN_IS_SYNTH;
418 }
419 }
420
421 lilv_nodes_free(const_cast<LilvNodes*>(typeNodes.me));
422 }
423
424 // ----------------------------------------------------------------------------------------------------------------
425 // number data
426
427 info.audioIns = 0;
428 info.audioOuts = 0;
429 info.cvIns = 0;
430 info.cvOuts = 0;
431 info.midiIns = 0;
432 info.midiOuts = 0;
433 info.parameterIns = 0;
434 info.parameterOuts = 0;
435
436 for (uint i=0, count=lilvPlugin.get_num_ports(); i<count; ++i)
437 {
438 Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i));
439
440 bool isInput;
441
442 /**/ if (lilvPort.is_a(lv2World.port_input))
443 {
444 isInput = true;
445 }
446 else if (lilvPort.is_a(lv2World.port_output))
447 {
448 isInput = false;
449 }
450 else
451 {
452 const LilvNode* const symbolNode = lilvPort.get_symbol();
453 CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode));
454
455 const char* const symbol = lilv_node_as_string(symbolNode);
456 CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr);
457
458 carla_stderr("LV2 plugin '%s' port '%s' is neither input or output", info.label, symbol);
459 continue;
460 }
461
462 /**/ if (lilvPort.is_a(lv2World.port_control))
463 {
464 // skip some control ports
465 if (lilvPort.has_property(lv2World.reportsLatency))
466 continue;
467
468 if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me))
469 {
470 bool skip = false;
471
472 if (const char* const designation = lilv_node_as_string(designationNode))
473 {
474 /**/ if (std::strcmp(designation, LV2_CORE__control) == 0)
475 skip = true;
476 else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0)
477 skip = true;
478 else if (std::strcmp(designation, LV2_CORE__latency) == 0)
479 skip = true;
480 else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0)
481 skip = true;
482 else if (std::strcmp(designation, LV2_TIME__bar) == 0)
483 skip = true;
484 else if (std::strcmp(designation, LV2_TIME__barBeat) == 0)
485 skip = true;
486 else if (std::strcmp(designation, LV2_TIME__beat) == 0)
487 skip = true;
488 else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0)
489 skip = true;
490 else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0)
491 skip = true;
492 else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0)
493 skip = true;
494 else if (std::strcmp(designation, LV2_TIME__frame) == 0)
495 skip = true;
496 else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0)
497 skip = true;
498 else if (std::strcmp(designation, LV2_TIME__speed) == 0)
499 skip = true;
500 else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
501 skip = true;
502 }
503
504 lilv_node_free(designationNode);
505
506 if (skip)
507 continue;
508 }
509
510 if (isInput)
511 ++(info.parameterIns);
512 else
513 ++(info.parameterOuts);
514 }
515 else if (lilvPort.is_a(lv2World.port_audio))
516 {
517 if (isInput)
518 ++(info.audioIns);
519 else
520 ++(info.audioOuts);
521 }
522 else if (lilvPort.is_a(lv2World.port_cv))
523 {
524 if (isInput)
525 ++(info.cvIns);
526 else
527 ++(info.cvOuts);
528 }
529 else if (lilvPort.is_a(lv2World.port_atom))
530 {
531 Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports));
532
533 for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it))
534 {
535 const Lilv::Node node(lilv_nodes_get(supportNodes.me, it));
536 CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
537
538 if (node.equals(lv2World.midi_event))
539 {
540 if (isInput)
541 ++(info.midiIns);
542 else
543 ++(info.midiOuts);
544 }
545 }
546
547 lilv_nodes_free(const_cast<LilvNodes*>(supportNodes.me));
548 }
549 else if (lilvPort.is_a(lv2World.port_event))
550 {
551 if (lilvPort.supports_event(lv2World.midi_event))
552 {
553 if (isInput)
554 ++(info.midiIns);
555 else
556 ++(info.midiOuts);
557 }
558 }
559 else if (lilvPort.is_a(lv2World.port_midi))
560 {
561 if (isInput)
562 ++(info.midiIns);
563 else
564 ++(info.midiOuts);
565 }
566 else
567 {
568 const LilvNode* const symbolNode = lilvPort.get_symbol();
569 CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode));
570
571 const char* const symbol = lilv_node_as_string(symbolNode);
572 CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr);
573
574 supported = false;
575 carla_stderr("LV2 plugin '%s' port '%s' is required but has unsupported type", info.label, symbol);
576 }
577 }
578
579 if (supported)
580 info.valid = true;
581
582 return &info;
583}
584
585// -------------------------------------------------------------------------------------------------------------------
586
587#ifdef HAVE_SFZ
589{
591
592 static CarlaString name, filename;
593
594 name = file.getFileNameWithoutExtension().toRawUTF8();
595 name.replace('_',' ');
596
597 filename = file.getFullPathName().toRawUTF8();
598
599 info.category = CB::PLUGIN_CATEGORY_SYNTH;
600 info.hints = CB::PLUGIN_IS_SYNTH;
601 // CB::PLUGIN_IS_RTSAFE
602
603 info.valid = true;
604 info.audioIns = 0;
605 info.audioOuts = 2;
606 info.cvIns = 0;
607 info.cvOuts = 0;
608 info.midiIns = 1;
609 info.midiOuts = 0;
610 info.parameterIns = 0;
611 info.parameterOuts = 1;
612
613 info.name = name.buffer();
614 info.label = filename.buffer();
617 return &info;
618}
619#endif
620
621// -------------------------------------------------------------------------------------------------------------------
622
623#ifdef HAVE_YSFX
624static const CarlaCachedPluginInfo* get_cached_plugin_jsfx(const CB::CarlaJsfxUnit& unit)
625{
627
628 ysfx_config_u config(ysfx_config_new());
629
630 const water::String rootPath = unit.getRootPath();
631 const water::String filePath = unit.getFilePath();
632
634 ysfx_set_import_root(config.get(), rootPath.toRawUTF8());
635 ysfx_guess_file_roots(config.get(), filePath.toRawUTF8());
636 ysfx_set_log_reporter(config.get(), &CB::CarlaJsfxLogging::logErrorsOnly);
637
638 ysfx_u effect(ysfx_new(config.get()));
639
640 if (! ysfx_load_file(effect.get(), filePath.toRawUTF8(), 0))
641 {
642 info.valid = false;
643 return &info;
644 }
645
646 // plugins with neither @block nor @sample are valid, but they are useless
647 // also use this as a sanity check against misdetected files
648 // since JSFX parsing is so permissive, it might accept lambda text files
649 if (! ysfx_has_section(effect.get(), ysfx_section_block) &&
650 ! ysfx_has_section(effect.get(), ysfx_section_sample))
651 {
652 info.valid = false;
653 return &info;
654 }
655
656 static CarlaString name, label, maker;
657 label = unit.getFileId().toRawUTF8();
658 name = ysfx_get_name(effect.get());
659 maker = ysfx_get_author(effect.get());
660
661 info.valid = true;
662
663 info.category = CB::CarlaJsfxCategories::getFromEffect(effect.get());
664
665 info.audioIns = ysfx_get_num_inputs(effect.get());
666 info.audioOuts = ysfx_get_num_outputs(effect.get());
667
668 info.cvIns = 0;
669 info.cvOuts = 0;
670
671 info.midiIns = 1;
672 info.midiOuts = 1;
673
674 info.parameterIns = 0;
675 info.parameterOuts = 0;
676 for (uint32_t sliderIndex = 0; sliderIndex < ysfx_max_sliders; ++sliderIndex)
677 {
678 if (ysfx_slider_exists(effect.get(), sliderIndex))
679 ++info.parameterIns;
680 }
681
682 info.hints = 0;
683
684#if 0 // TODO(jsfx) when supporting custom graphics
685 if (ysfx_has_section(effect.get(), ysfx_section_gfx))
686 info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
687#endif
688
689 info.name = name.buffer();
690 info.label = label.buffer();
691 info.maker = maker.buffer();
693
694 return &info;
695}
696#endif
697
698// -------------------------------------------------------------------------------------------------------------------
699
700uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath)
701{
703 carla_debug("carla_get_cached_plugin_count(%i:%s, %s)", ptype, CB::PluginType2Str(ptype), pluginPath);
704
705 switch (ptype)
706 {
707 case CB::PLUGIN_INTERNAL: {
708 uint32_t count = 0;
710 return count;
711 }
712
713 case CB::PLUGIN_LV2: {
714 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
715 lv2World.initIfNeeded(pluginPath);
716 return lv2World.getPluginCount();
717 }
718
719 #ifdef HAVE_SFZ
720 case CB::PLUGIN_SFZ:
721 findSFZs(pluginPath);
722 return static_cast<uint>(gSFZs.size());
723 #endif
724
725 #ifdef HAVE_YSFX
726 case CB::PLUGIN_JSFX:
727 findJSFXs(pluginPath);
728 return static_cast<uint>(gJSFXs.size());
729 #endif
730
731 default:
732 return 0;
733 }
734}
735
736const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, uint index)
737{
738 carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index);
739
740 switch (ptype)
741 {
742 case CB::PLUGIN_INTERNAL: {
743 uint32_t count = 0;
746 CARLA_SAFE_ASSERT_BREAK(descs != nullptr);
747
748 const NativePluginDescriptor& desc(descs[index]);
749 return get_cached_plugin_internal(desc);
750 }
751
752 case CB::PLUGIN_LV2: {
753 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
754
755 const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index));
756 CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr);
757
758 Lilv::Plugin lilvPlugin(cPlugin);
759 CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri());
760
761 return get_cached_plugin_lv2(lv2World, lilvPlugin);
762 }
763
764 #ifdef HAVE_SFZ
765 case CB::PLUGIN_SFZ:
766 CARLA_SAFE_ASSERT_BREAK(index < gSFZs.size());
767 return get_cached_plugin_sfz(gSFZs[index]);
768 #endif
769
770 #ifdef HAVE_YSFX
771 case CB::PLUGIN_JSFX:
772 CARLA_SAFE_ASSERT_BREAK(index < static_cast<uint>(gJSFXs.size()));
773 return get_cached_plugin_jsfx(gJSFXs[index]);
774 #endif
775
776 default:
777 break;
778 }
779
781 return &info;
782}
783
784// -------------------------------------------------------------------------------------------------------------------
785
786#ifndef CARLA_PLUGIN_BUILD
787# include "../native-plugins/_data.cpp"
788#endif
789
790// -------------------------------------------------------------------------------------------------------------------
#define CARLA_BACKEND_NAMESPACE
Definition CarlaBackend.h:32
#define CARLA_OS_SEP_STR
Definition CarlaDefines.h:319
#define CARLA_OS_SEP
Definition CarlaDefines.h:318
#define CARLA_OS_SPLIT_STR
Definition CarlaDefines.h:321
#define CARLA_SAFE_ASSERT_CONTINUE(cond)
Definition CarlaDefines.h:189
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
unsigned int uint
Definition CarlaDefines.h:327
#define CARLA_SAFE_ASSERT_BREAK(cond)
Definition CarlaDefines.h:188
#define noexcept
Definition DistrhoDefines.h:72
static void copyright()
Definition adplugdb.cpp:261
static const CarlaCachedPluginInfo * get_cached_plugin_lv2(Lv2WorldClass &lv2World, Lilv::Plugin &lilvPlugin)
Definition CachedPlugins.cpp:170
static std::vector< water::File > gSFZs
Definition CachedPlugins.cpp:65
static const CarlaCachedPluginInfo * get_cached_plugin_sfz(const water::File &file)
Definition CachedPlugins.cpp:588
static void findSFZs(const char *const sfzPaths)
Definition CachedPlugins.cpp:67
static const char *const gCachedPluginsNullCharPtr
Definition CachedPlugins.cpp:26
const CarlaCachedPluginInfo * carla_get_cached_plugin_info(CB::PluginType ptype, uint index)
Definition CachedPlugins.cpp:736
uint carla_get_cached_plugin_count(CB::PluginType ptype, const char *pluginPath)
Definition CachedPlugins.cpp:700
static bool isCachedPluginType(const CB::PluginType ptype)
Definition CachedPlugins.cpp:28
static const CarlaCachedPluginInfo * get_cached_plugin_internal(const NativePluginDescriptor &desc)
Definition CachedPlugins.cpp:130
Definition File.h:50
@ findFiles
Definition File.h:462
@ ignoreHiddenFiles
Definition File.h:464
String getFileName() const
Definition File.cpp:373
uint findChildFiles(std::vector< File > &results, int whatToLookFor, bool searchRecursively, const String &wildCardPattern="*") const
Definition File.cpp:581
Definition StringArray.h:41
String * begin() const noexcept
Definition StringArray.h:120
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition StringArray.cpp:369
String * end() const noexcept
Definition StringArray.h:125
Definition String.h:48
bool equalsIgnoreCase(const String &other) const noexcept
Definition String.cpp:518
const char * toRawUTF8() const
Definition String.cpp:1925
bool isEmpty() const noexcept
Definition String.h:238
register unsigned i
Definition inflate.c:1575
struct config_s config
static char filename[]
Definition features.c:5
@ PLUGIN_CATEGORY_NONE
Definition CarlaBackend.h:708
CARLA_API_EXPORT const NativePluginDescriptor * carla_get_native_plugins_data(uint32_t *count)
Definition _data.cpp:599
struct _NativePluginDescriptor NativePluginDescriptor
@ NATIVE_PLUGIN_USES_MULTI_PROGS
Definition CarlaNative.h:62
@ NATIVE_PLUGIN_IS_SYNTH
Definition CarlaNative.h:57
@ NATIVE_PLUGIN_HAS_INLINE_DISPLAY
Definition CarlaNative.h:67
@ NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD
Definition CarlaNative.h:60
@ NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS
Definition CarlaNative.h:59
@ NATIVE_PLUGIN_IS_RTSAFE
Definition CarlaNative.h:56
@ NATIVE_PLUGIN_HAS_UI
Definition CarlaNative.h:58
struct _CarlaCachedPluginInfo CarlaCachedPluginInfo
#define LV2_DATA_ACCESS_URI
http://lv2plug.in/ns/ext/data-access
Definition data-access.h:30
static const char * name
Definition pugl.h:1582
#define LV2_INLINEDISPLAY__queue_draw
Definition inline-display.h:37
#define LV2_INSTANCE_ACCESS_URI
http://lv2plug.in/ns/ext/instance-access
Definition instance-access.h:30
LILV_API LilvNode * lilv_nodes_get_first(const LilvNodes *collection)
Definition collections.c:236
LILV_API LilvIter * lilv_nodes_begin(const LilvNodes *collection)
LILV_API bool lilv_nodes_is_end(const LilvNodes *collection, LilvIter *i)
LILV_API LilvIter * lilv_nodes_next(const LilvNodes *collection, LilvIter *i)
LILV_API void lilv_nodes_free(LilvNodes *collection)
Definition collections.c:230
LILV_API const LilvNode * lilv_nodes_get(const LilvNodes *collection, LilvIter *i)
#define LILV_FOREACH(colltype, iter, collection)
Definition lilv.h:398
LILV_API bool lilv_node_is_string(const LilvNode *value)
Definition node.c:351
LILV_API const char * lilv_node_as_string(const LilvNode *value)
Definition node.c:357
LILV_API char * lilv_file_uri_parse(const char *uri, char **hostname)
Definition util.c:106
LILV_API void lilv_node_free(LilvNode *val)
Definition node.c:229
LILV_API LilvNode * lilv_plugin_get_author_name(const LilvPlugin *plugin)
Definition plugin.c:922
LILV_API LilvNode * lilv_plugin_get_name(const LilvPlugin *plugin)
Definition plugin.c:498
LILV_API LilvNode * lilv_port_get(const LilvPlugin *plugin, const LilvPort *port, const LilvNode *predicate)
Definition port.c:139
void LilvNodes
Definition lilv.h:97
LILV_API void lilv_free(void *ptr)
Definition util.c:37
struct LilvPluginImpl LilvPlugin
Definition lilv.h:82
struct LilvNodeImpl LilvNode
Definition lilv.h:87
void LilvIter
Definition lilv.h:92
#define LV2_CORE__freeWheeling
http://lv2plug.in/ns/lv2core#freeWheeling
Definition lv2.h:98
#define LV2_CORE__hardRTCapable
http://lv2plug.in/ns/lv2core#hardRTCapable
Definition lv2.h:99
#define LV2_CORE__control
http://lv2plug.in/ns/lv2core#control
Definition lv2.h:92
#define LV2_CORE__latency
http://lv2plug.in/ns/lv2core#latency
Definition lv2.h:104
#define LV2_PARAMETERS__sampleRate
http://lv2plug.in/ns/ext/parameters#sampleRate
Definition parameters.h:51
#define LV2_TIME__framesPerSecond
http://lv2plug.in/ns/ext/time#framesPerSecond
Definition time.h:46
#define LV2_TIME__beat
http://lv2plug.in/ns/ext/time#beat
Definition time.h:41
#define LV2_TIME__frame
http://lv2plug.in/ns/ext/time#frame
Definition time.h:45
#define LV2_TIME__barBeat
http://lv2plug.in/ns/ext/time#barBeat
Definition time.h:39
#define LV2_TIME__beatsPerMinute
http://lv2plug.in/ns/ext/time#beatsPerMinute
Definition time.h:44
#define LV2_TIME__speed
http://lv2plug.in/ns/ext/time#speed
Definition time.h:47
#define LV2_TIME__beatUnit
http://lv2plug.in/ns/ext/time#beatUnit
Definition time.h:42
#define LV2_TIME__beatsPerBar
http://lv2plug.in/ns/ext/time#beatsPerBar
Definition time.h:43
#define LV2_TIME__bar
http://lv2plug.in/ns/ext/time#bar
Definition time.h:40
struct backing_store_struct * info
Definition jmemsys.h:183
#define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat
Definition lv2_kxstudio_properties.h:30
unsigned int uint32_t
Definition mid.cpp:100
@ label
Definition juce_AccessibilityRole.h:44
#define false
Definition ordinals.h:83
png_const_structrp png_const_inforp int * unit
Definition png.h:2161
const char *const copyright
Definition CarlaNative.h:260
const char *const name
Definition CarlaNative.h:257
const uint32_t midiOuts
Definition CarlaNative.h:254
const uint32_t audioIns
Definition CarlaNative.h:251
const uint32_t cvIns
Definition CarlaNative.h:302
const uint32_t cvOuts
Definition CarlaNative.h:303
const char *const maker
Definition CarlaNative.h:259
const NativePluginCategory category
Definition CarlaNative.h:248
const uint32_t audioOuts
Definition CarlaNative.h:252
const char *const label
Definition CarlaNative.h:258
const NativePluginHints hints
Definition CarlaNative.h:249
const uint32_t midiIns
Definition CarlaNative.h:253
const uint32_t paramOuts
Definition CarlaNative.h:256
const uint32_t paramIns
Definition CarlaNative.h:255
struct zdirent * file
Definition win32.c:1500
_WDL_CSTRING_PREFIX void INT_PTR count
Definition wdlcstring.h:263
@ ysfx_max_sliders
Definition ysfx.h:52
@ ysfx_section_gfx
Definition ysfx.h:157
@ ysfx_section_sample
Definition ysfx.h:156
@ ysfx_section_block
Definition ysfx.h:155
YSFX_API const char * ysfx_get_author(ysfx_t *fx)
Definition ysfx.cpp:569
YSFX_API ysfx_t * ysfx_new(ysfx_config_t *config)
Definition ysfx.cpp:82
YSFX_API void ysfx_register_builtin_audio_formats(ysfx_config_t *config)
Definition ysfx_config.cpp:105
YSFX_API ysfx_config_t * ysfx_config_new()
Definition ysfx_config.cpp:24
YSFX_API bool ysfx_load_file(ysfx_t *fx, const char *filepath, uint32_t loadopts)
Definition ysfx.cpp:197
YSFX_API void ysfx_guess_file_roots(ysfx_config_t *config, const char *sourcepath)
Definition ysfx_config.cpp:63
YSFX_API uint32_t ysfx_get_num_outputs(ysfx_t *fx)
Definition ysfx.cpp:608
YSFX_API bool ysfx_slider_exists(ysfx_t *fx, uint32_t index)
Definition ysfx.cpp:703
YSFX_API uint32_t ysfx_get_num_inputs(ysfx_t *fx)
Definition ysfx.cpp:600
YSFX_API bool ysfx_has_section(ysfx_t *fx, uint32_t type)
Definition ysfx.cpp:698
YSFX_API void ysfx_set_log_reporter(ysfx_config_t *config, ysfx_log_reporter_t *reporter)
Definition ysfx_config.cpp:111
YSFX_API const char * ysfx_get_name(ysfx_t *fx)
Definition ysfx.cpp:556
YSFX_API void ysfx_set_import_root(ysfx_config_t *config, const char *root)
Definition ysfx_config.cpp:43