Clean water File(const String&) usage
[carla.git] / source / backend / utils / CachedPlugins.cpp
blobf72530cd5bb1438d58e0abfc9f0b2728e9223ada
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #include "CarlaUtils.h"
6 #include "CarlaNative.h"
7 #include "CarlaString.hpp"
8 #include "CarlaBackendUtils.hpp"
9 #include "CarlaLv2Utils.hpp"
11 #ifndef STATIC_PLUGIN_TARGET
12 # define HAVE_SFZ
13 # include "water/containers/Array.h"
14 #endif
16 #ifdef HAVE_YSFX
17 # include "CarlaJsfxUtils.hpp"
18 #endif
20 #include "water/files/File.h"
22 namespace CB = CARLA_BACKEND_NAMESPACE;
24 // -------------------------------------------------------------------------------------------------------------------
26 static const char* const gCachedPluginsNullCharPtr = "";
28 static bool isCachedPluginType(const CB::PluginType ptype)
30 switch (ptype)
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;
43 // -------------------------------------------------------------------------------------------------------------------
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),
57 name(gCachedPluginsNullCharPtr),
58 label(gCachedPluginsNullCharPtr),
59 maker(gCachedPluginsNullCharPtr),
60 copyright(gCachedPluginsNullCharPtr) {}
62 // -------------------------------------------------------------------------------------------------------------------
64 #ifdef HAVE_SFZ
65 static std::vector<water::File> gSFZs;
67 static void findSFZs(const char* const sfzPaths)
69 gSFZs.clear();
71 CARLA_SAFE_ASSERT_RETURN(sfzPaths != nullptr,);
73 if (sfzPaths[0] == '\0')
74 return;
76 const water::StringArray splitPaths(water::StringArray::fromTokens(sfzPaths, CARLA_OS_SPLIT_STR, ""));
78 for (water::String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
80 std::vector<water::File> results;
82 if (water::File(it->toRawUTF8()).findChildFiles(results, water::File::findFiles|water::File::ignoreHiddenFiles, true, "*.sfz") > 0)
84 gSFZs.reserve(gSFZs.size() + results.size());
85 gSFZs.insert(gSFZs.end(), results.begin(), results.end());
89 #endif
91 // -------------------------------------------------------------------------------------------------------------------
93 #ifdef HAVE_YSFX
94 static std::vector<CB::CarlaJsfxUnit> gJSFXs;
96 static void findJSFXs(const char* const jsfxPaths)
98 gJSFXs.clear();
100 CARLA_SAFE_ASSERT_RETURN(jsfxPaths != nullptr,);
102 if (jsfxPaths[0] == '\0')
103 return;
105 const water::StringArray splitPaths(water::StringArray::fromTokens(jsfxPaths, CARLA_OS_SPLIT_STR, ""));
107 for (water::String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
109 std::vector<water::File> results;
110 const water::File path(it->toRawUTF8());
112 if (path.findChildFiles(results, water::File::findFiles|water::File::ignoreHiddenFiles, true, "*") > 0)
114 gJSFXs.reserve(gJSFXs.size() + results.size());
116 for (std::vector<water::File>::iterator it2=results.begin(), end2=results.end(); it2 != end2; ++it2)
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));
126 #endif
128 // -------------------------------------------------------------------------------------------------------------------
130 static const CarlaCachedPluginInfo* get_cached_plugin_internal(const NativePluginDescriptor& desc)
132 static CarlaCachedPluginInfo info;
134 info.category = static_cast<CB::PluginCategory>(desc.category);
135 info.hints = 0x0;
137 if (desc.hints & NATIVE_PLUGIN_IS_RTSAFE)
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;
143 if (desc.hints & NATIVE_PLUGIN_HAS_INLINE_DISPLAY)
144 info.hints |= CB::PLUGIN_HAS_INLINE_DISPLAY;
145 if (desc.hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS)
146 info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS;
147 if (desc.hints & NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD)
148 info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD;
149 if (desc.hints & NATIVE_PLUGIN_USES_MULTI_PROGS)
150 info.hints |= CB::PLUGIN_USES_MULTI_PROGS;
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;
168 // -------------------------------------------------------------------------------------------------------------------
170 static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2World, Lilv::Plugin& lilvPlugin)
172 static CarlaCachedPluginInfo info;
174 info.valid = false;
175 bool supported = true;
177 // ----------------------------------------------------------------------------------------------------------------
178 // text data
181 static CarlaString suri, sname, smaker, slicense;
182 suri.clear(); sname.clear(); smaker.clear(); slicense.clear();
184 suri = lilvPlugin.get_uri().as_uri();
186 if (char* const bundle = lilv_file_uri_parse(lilvPlugin.get_bundle_uri().as_uri(), nullptr))
188 const water::File fbundle(bundle);
189 suri = (fbundle.getFileName() + CARLA_OS_SEP).toRawUTF8() + suri;
190 lilv_free(bundle);
192 else
194 suri = CARLA_OS_SEP_STR + suri;
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
205 if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me))
207 if (const char* const name = lilv_node_as_string(nameNode))
208 sname = name;
209 lilv_node_free(nameNode);
212 if (LilvNode* const authorNode = lilv_plugin_get_author_name(lilvPlugin.me))
214 if (const char* const author = lilv_node_as_string(authorNode))
215 smaker = author;
216 lilv_node_free(authorNode);
219 Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license));
221 if (licenseNodes.size() > 0)
223 if (LilvNode* const licenseNode = lilv_nodes_get_first(licenseNodes.me))
225 if (const char* const license = lilv_node_as_string(licenseNode))
226 slicense = license;
227 // lilv_node_free(licenseNode);
231 lilv_nodes_free(const_cast<LilvNodes*>(licenseNodes.me));
233 info.name = sname.buffer();
234 info.label = suri.buffer();
235 info.maker = smaker.buffer();
236 info.copyright = slicense.buffer();
239 // ----------------------------------------------------------------------------------------------------------------
240 // features
242 info.hints = 0x0;
245 Lilv::UIs lilvUIs(lilvPlugin.get_uis());
247 if (lilvUIs.size() > 0)
249 info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
251 LILV_FOREACH(uis, it, lilvUIs)
253 Lilv::UI lilvUI(lilvUIs.get(it));
254 lv2World.load_resource(lilvUI.get_uri());
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
266 info.hints |= CB::PLUGIN_HAS_CUSTOM_EMBED_UI;
267 break;
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
276 lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));
280 Lilv::Nodes lilvRequiredFeatureNodes(lilvPlugin.get_required_features());
282 LILV_FOREACH(nodes, it, lilvRequiredFeatureNodes)
284 Lilv::Node lilvFeatureNode(lilvRequiredFeatureNodes.get(it));
285 const char* const featureURI(lilvFeatureNode.as_uri());
286 CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
288 if (! is_lv2_feature_supported(featureURI))
290 if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0
291 || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0)
293 // we give a warning about this below
294 continue;
297 supported = false;
298 carla_stderr("LV2 plugin '%s' requires unsupported feature '%s'", info.label, featureURI);
302 lilv_nodes_free(const_cast<LilvNodes*>(lilvRequiredFeatureNodes.me));
306 Lilv::Nodes lilvSupportedFeatureNodes(lilvPlugin.get_supported_features());
308 LILV_FOREACH(nodes, it, lilvSupportedFeatureNodes)
310 Lilv::Node lilvFeatureNode(lilvSupportedFeatureNodes.get(it));
311 const char* const featureURI(lilvFeatureNode.as_uri());
312 CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
314 /**/ if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0)
316 info.hints |= CB::PLUGIN_IS_RTSAFE;
318 else if (std::strcmp(featureURI, LV2_INLINEDISPLAY__queue_draw) == 0)
320 info.hints |= CB::PLUGIN_HAS_INLINE_DISPLAY;
322 else if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0
323 || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0)
325 carla_stderr("LV2 plugin '%s' DSP wants UI feature '%s', ignoring this", info.label, featureURI);
329 lilv_nodes_free(const_cast<LilvNodes*>(lilvSupportedFeatureNodes.me));
332 // ----------------------------------------------------------------------------------------------------------------
333 // category
335 info.category = CB::PLUGIN_CATEGORY_NONE;
338 Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type));
340 if (typeNodes.size() > 0)
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))
416 info.category = CB::PLUGIN_CATEGORY_SYNTH;
417 info.hints |= CB::PLUGIN_IS_SYNTH;
421 lilv_nodes_free(const_cast<LilvNodes*>(typeNodes.me));
424 // ----------------------------------------------------------------------------------------------------------------
425 // number data
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;
436 for (uint i=0, count=lilvPlugin.get_num_ports(); i<count; ++i)
438 Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i));
440 bool isInput;
442 /**/ if (lilvPort.is_a(lv2World.port_input))
444 isInput = true;
446 else if (lilvPort.is_a(lv2World.port_output))
448 isInput = false;
450 else
452 const LilvNode* const symbolNode = lilvPort.get_symbol();
453 CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode));
455 const char* const symbol = lilv_node_as_string(symbolNode);
456 CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr);
458 carla_stderr("LV2 plugin '%s' port '%s' is neither input or output", info.label, symbol);
459 continue;
462 /**/ if (lilvPort.is_a(lv2World.port_control))
464 // skip some control ports
465 if (lilvPort.has_property(lv2World.reportsLatency))
466 continue;
468 if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me))
470 bool skip = false;
472 if (const char* const designation = lilv_node_as_string(designationNode))
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;
504 lilv_node_free(designationNode);
506 if (skip)
507 continue;
510 if (isInput)
511 ++(info.parameterIns);
512 else
513 ++(info.parameterOuts);
515 else if (lilvPort.is_a(lv2World.port_audio))
517 if (isInput)
518 ++(info.audioIns);
519 else
520 ++(info.audioOuts);
522 else if (lilvPort.is_a(lv2World.port_cv))
524 if (isInput)
525 ++(info.cvIns);
526 else
527 ++(info.cvOuts);
529 else if (lilvPort.is_a(lv2World.port_atom))
531 Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports));
533 for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it))
535 const Lilv::Node node(lilv_nodes_get(supportNodes.me, it));
536 CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
538 if (node.equals(lv2World.midi_event))
540 if (isInput)
541 ++(info.midiIns);
542 else
543 ++(info.midiOuts);
547 lilv_nodes_free(const_cast<LilvNodes*>(supportNodes.me));
549 else if (lilvPort.is_a(lv2World.port_event))
551 if (lilvPort.supports_event(lv2World.midi_event))
553 if (isInput)
554 ++(info.midiIns);
555 else
556 ++(info.midiOuts);
559 else if (lilvPort.is_a(lv2World.port_midi))
561 if (isInput)
562 ++(info.midiIns);
563 else
564 ++(info.midiOuts);
566 else
568 const LilvNode* const symbolNode = lilvPort.get_symbol();
569 CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode));
571 const char* const symbol = lilv_node_as_string(symbolNode);
572 CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr);
574 supported = false;
575 carla_stderr("LV2 plugin '%s' port '%s' is required but has unsupported type", info.label, symbol);
579 if (supported)
580 info.valid = true;
582 return &info;
585 // -------------------------------------------------------------------------------------------------------------------
587 #ifdef HAVE_SFZ
588 static const CarlaCachedPluginInfo* get_cached_plugin_sfz(const water::File& file)
590 static CarlaCachedPluginInfo info;
592 static CarlaString name, filename;
594 name = file.getFileNameWithoutExtension().toRawUTF8();
595 name.replace('_',' ');
597 filename = file.getFullPathName().toRawUTF8();
599 info.category = CB::PLUGIN_CATEGORY_SYNTH;
600 info.hints = CB::PLUGIN_IS_SYNTH;
601 // CB::PLUGIN_IS_RTSAFE
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;
613 info.name = name.buffer();
614 info.label = filename.buffer();
615 info.maker = gCachedPluginsNullCharPtr;
616 info.copyright = gCachedPluginsNullCharPtr;
617 return &info;
619 #endif
621 // -------------------------------------------------------------------------------------------------------------------
623 #ifdef HAVE_YSFX
624 static const CarlaCachedPluginInfo* get_cached_plugin_jsfx(const CB::CarlaJsfxUnit& unit)
626 static CarlaCachedPluginInfo info;
628 ysfx_config_u config(ysfx_config_new());
630 const water::String rootPath = unit.getRootPath();
631 const water::String filePath = unit.getFilePath();
633 ysfx_register_builtin_audio_formats(config.get());
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);
638 ysfx_u effect(ysfx_new(config.get()));
640 if (! ysfx_load_file(effect.get(), filePath.toRawUTF8(), 0))
642 info.valid = false;
643 return &info;
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))
652 info.valid = false;
653 return &info;
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());
661 info.valid = true;
663 info.category = CB::CarlaJsfxCategories::getFromEffect(effect.get());
665 info.audioIns = ysfx_get_num_inputs(effect.get());
666 info.audioOuts = ysfx_get_num_outputs(effect.get());
668 info.cvIns = 0;
669 info.cvOuts = 0;
671 info.midiIns = 1;
672 info.midiOuts = 1;
674 info.parameterIns = 0;
675 info.parameterOuts = 0;
676 for (uint32_t sliderIndex = 0; sliderIndex < ysfx_max_sliders; ++sliderIndex)
678 if (ysfx_slider_exists(effect.get(), sliderIndex))
679 ++info.parameterIns;
682 info.hints = 0;
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
689 info.name = name.buffer();
690 info.label = label.buffer();
691 info.maker = maker.buffer();
692 info.copyright = gCachedPluginsNullCharPtr;
694 return &info;
696 #endif
698 // -------------------------------------------------------------------------------------------------------------------
700 uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath)
702 CARLA_SAFE_ASSERT_RETURN(isCachedPluginType(ptype), 0);
703 carla_debug("carla_get_cached_plugin_count(%i:%s, %s)", ptype, CB::PluginType2Str(ptype), pluginPath);
705 switch (ptype)
707 case CB::PLUGIN_INTERNAL: {
708 uint32_t count = 0;
709 carla_get_native_plugins_data(&count);
710 return count;
713 case CB::PLUGIN_LV2: {
714 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
715 lv2World.initIfNeeded(pluginPath);
716 return lv2World.getPluginCount();
719 #ifdef HAVE_SFZ
720 case CB::PLUGIN_SFZ:
721 findSFZs(pluginPath);
722 return static_cast<uint>(gSFZs.size());
723 #endif
725 #ifdef HAVE_YSFX
726 case CB::PLUGIN_JSFX:
727 findJSFXs(pluginPath);
728 return static_cast<uint>(gJSFXs.size());
729 #endif
731 default:
732 return 0;
736 const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, uint index)
738 carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index);
740 switch (ptype)
742 case CB::PLUGIN_INTERNAL: {
743 uint32_t count = 0;
744 const NativePluginDescriptor* const descs(carla_get_native_plugins_data(&count));
745 CARLA_SAFE_ASSERT_BREAK(index < count);
746 CARLA_SAFE_ASSERT_BREAK(descs != nullptr);
748 const NativePluginDescriptor& desc(descs[index]);
749 return get_cached_plugin_internal(desc);
752 case CB::PLUGIN_LV2: {
753 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
755 const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index));
756 CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr);
758 Lilv::Plugin lilvPlugin(cPlugin);
759 CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri());
761 return get_cached_plugin_lv2(lv2World, lilvPlugin);
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
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
776 default:
777 break;
780 static CarlaCachedPluginInfo info;
781 return &info;
784 // -------------------------------------------------------------------------------------------------------------------
786 #ifndef CARLA_PLUGIN_BUILD
787 # include "../native-plugins/_data.cpp"
788 #endif
790 // -------------------------------------------------------------------------------------------------------------------