diff --git a/source/backend/Makefile b/source/backend/Makefile index 3f353fef7..c37bfc3c1 100644 --- a/source/backend/Makefile +++ b/source/backend/Makefile @@ -60,6 +60,7 @@ STANDALONE_LINK_FLAGS += $(X11_LIBS) # ---------------------------------------------------------------------------------------------------------------------------- all: $(TARGETS) + $(MAKE) -C utils # ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/backend/utils/CachedPlugins.cpp b/source/backend/utils/CachedPlugins.cpp index 7b1c13e6e..44fef37c5 100644 --- a/source/backend/utils/CachedPlugins.cpp +++ b/source/backend/utils/CachedPlugins.cpp @@ -31,6 +31,7 @@ static bool isCachedPluginType(const CB::PluginType ptype) { case CB::PLUGIN_INTERNAL: case CB::PLUGIN_LV2: + case CB::PLUGIN_SFZ: return false; default: return true; @@ -56,304 +57,333 @@ _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept // ------------------------------------------------------------------------------------------------------------------- -uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath) +const CarlaCachedPluginInfo* get_cached_plugin_internal(const NativePluginDescriptor& desc) { - CARLA_SAFE_ASSERT_RETURN(isCachedPluginType(ptype), 0); - carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype)); + static CarlaCachedPluginInfo info; - switch (ptype) - { - case CB::PLUGIN_INTERNAL: { - uint32_t count = 0; - carla_get_native_plugins_data(&count); - return count; - } + info.category = static_cast(desc.category); + info.hints = 0x0; + + if (desc.hints & NATIVE_PLUGIN_IS_RTSAFE) + info.hints |= CB::PLUGIN_IS_RTSAFE; + if (desc.hints & NATIVE_PLUGIN_IS_SYNTH) + info.hints |= CB::PLUGIN_IS_SYNTH; + if (desc.hints & NATIVE_PLUGIN_HAS_UI) + info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; + if (desc.hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) + info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS; + if (desc.hints & NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD) + info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD; + if (desc.hints & NATIVE_PLUGIN_USES_MULTI_PROGS) + info.hints |= CB::PLUGIN_USES_MULTI_PROGS; - case CB::PLUGIN_LV2: { - Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); - lv2World.initIfNeeded(pluginPath); - return lv2World.getPluginCount(); - } - - default: - return 0; - } + info.valid = true; + info.audioIns = desc.audioIns; + info.audioOuts = desc.audioOuts; + info.midiIns = desc.midiIns; + info.midiOuts = desc.midiOuts; + info.parameterIns = desc.paramIns; + info.parameterOuts = desc.paramOuts; + info.name = desc.name; + info.label = desc.label; + info.maker = desc.maker; + info.copyright = desc.copyright; + return &info; } -const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, uint index) +const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2World, Lilv::Plugin& lilvPlugin) { - carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index); - static CarlaCachedPluginInfo info; - switch (ptype) + info.valid = false; + bool supported = true; + + // ---------------------------------------------------------------------------------------------------------------- + // text data + { - case CB::PLUGIN_INTERNAL: { - uint32_t count = 0; - const NativePluginDescriptor* const descs(carla_get_native_plugins_data(&count)); - CARLA_SAFE_ASSERT_BREAK(index < count); - CARLA_SAFE_ASSERT_BREAK(descs != nullptr); + static CarlaString suri, sname, smaker, slicense; + suri.clear(); sname.clear(); smaker.clear(); slicense.clear(); - const NativePluginDescriptor& desc(descs[index]); + suri = lilvPlugin.get_uri().as_uri(); - info.category = static_cast(desc.category); - info.hints = 0x0; - - if (desc.hints & NATIVE_PLUGIN_IS_RTSAFE) - info.hints |= CB::PLUGIN_IS_RTSAFE; - if (desc.hints & NATIVE_PLUGIN_IS_SYNTH) - info.hints |= CB::PLUGIN_IS_SYNTH; - if (desc.hints & NATIVE_PLUGIN_HAS_UI) - info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; - if (desc.hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) - info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS; - if (desc.hints & NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD) - info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD; - if (desc.hints & NATIVE_PLUGIN_USES_MULTI_PROGS) - info.hints |= CB::PLUGIN_USES_MULTI_PROGS; - - info.valid = true; - info.audioIns = desc.audioIns; - info.audioOuts = desc.audioOuts; - info.midiIns = desc.midiIns; - info.midiOuts = desc.midiOuts; - info.parameterIns = desc.paramIns; - info.parameterOuts = desc.paramOuts; - info.name = desc.name; - info.label = desc.label; - info.maker = desc.maker; - info.copyright = desc.copyright; - return &info; - } + if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me)) + { + if (const char* const name = lilv_node_as_string(nameNode)) + sname = name; + lilv_node_free(nameNode); + } - case CB::PLUGIN_LV2: { - Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + if (const char* const author = lilvPlugin.get_author_name().as_string()) + smaker = author; - const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index)); - CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr); + Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license)); - Lilv::Plugin lilvPlugin(cPlugin); - CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri()); + if (licenseNodes.size() > 0) + { + if (const char* const license = licenseNodes.get_first().as_string()) + slicense = license; + } - // features - info.hints = 0x0; + lilv_nodes_free(const_cast(licenseNodes.me)); - if (lilvPlugin.get_uis().size() > 0) - info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; + info.name = sname.buffer(); + info.label = suri.buffer(); + info.maker = smaker.buffer(); + info.copyright = slicense.buffer(); + } + // ---------------------------------------------------------------------------------------------------------------- + // features + + info.hints = 0x0; + + if (lilvPlugin.get_uis().size() > 0) + info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; + + { + Lilv::Nodes lilvRequiredFeatureNodes(lilvPlugin.get_required_features()); + + LILV_FOREACH(nodes, it, lilvRequiredFeatureNodes) { - Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features()); + Lilv::Node lilvFeatureNode(lilvRequiredFeatureNodes.get(it)); + const char* const featureURI(lilvFeatureNode.as_uri()); + CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); - LILV_FOREACH(nodes, it, lilvFeatureNodes) + if (! is_lv2_feature_supported(featureURI)) { - Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it)); - const char* const featureURI(lilvFeatureNode.as_uri()); - CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); + if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0 + || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0) + { + // we give a warning about this below + continue; + } - if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0) - info.hints |= CB::PLUGIN_IS_RTSAFE; + supported = false; + carla_stderr("LV2 plugin '%s' requires unsupported feature '%s'", info.label, featureURI); } - - lilv_nodes_free(const_cast(lilvFeatureNodes.me)); } - // category - info.category = CB::PLUGIN_CATEGORY_NONE; + lilv_nodes_free(const_cast(lilvRequiredFeatureNodes.me)); + } + { + Lilv::Nodes lilvSupportedFeatureNodes(lilvPlugin.get_supported_features()); + + LILV_FOREACH(nodes, it, lilvSupportedFeatureNodes) { - Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type)); + Lilv::Node lilvFeatureNode(lilvSupportedFeatureNodes.get(it)); + const char* const featureURI(lilvFeatureNode.as_uri()); + CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); - if (typeNodes.size() > 0) + if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0) { - if (typeNodes.contains(lv2World.class_allpass)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_amplifier)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_analyzer)) - info.category = CB::PLUGIN_CATEGORY_UTILITY; - if (typeNodes.contains(lv2World.class_bandpass)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_chorus)) - info.category = CB::PLUGIN_CATEGORY_MODULATOR; - if (typeNodes.contains(lv2World.class_comb)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_compressor)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_constant)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_converter)) - info.category = CB::PLUGIN_CATEGORY_UTILITY; - if (typeNodes.contains(lv2World.class_delay)) - info.category = CB::PLUGIN_CATEGORY_DELAY; - if (typeNodes.contains(lv2World.class_distortion)) - info.category = CB::PLUGIN_CATEGORY_DISTORTION; - if (typeNodes.contains(lv2World.class_dynamics)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_eq)) - info.category = CB::PLUGIN_CATEGORY_EQ; - if (typeNodes.contains(lv2World.class_envelope)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_expander)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_filter)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_flanger)) - info.category = CB::PLUGIN_CATEGORY_MODULATOR; - if (typeNodes.contains(lv2World.class_function)) - info.category = CB::PLUGIN_CATEGORY_UTILITY; - if (typeNodes.contains(lv2World.class_gate)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_generator)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_highpass)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_limiter)) - info.category = CB::PLUGIN_CATEGORY_DYNAMICS; - if (typeNodes.contains(lv2World.class_lowpass)) - info.category = CB::PLUGIN_CATEGORY_FILTER; - if (typeNodes.contains(lv2World.class_mixer)) - info.category = CB::PLUGIN_CATEGORY_UTILITY; - if (typeNodes.contains(lv2World.class_modulator)) - info.category = CB::PLUGIN_CATEGORY_MODULATOR; - if (typeNodes.contains(lv2World.class_multiEQ)) - info.category = CB::PLUGIN_CATEGORY_EQ; - if (typeNodes.contains(lv2World.class_oscillator)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_paraEQ)) - info.category = CB::PLUGIN_CATEGORY_EQ; - if (typeNodes.contains(lv2World.class_phaser)) - info.category = CB::PLUGIN_CATEGORY_MODULATOR; - if (typeNodes.contains(lv2World.class_pitch)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_reverb)) - info.category = CB::PLUGIN_CATEGORY_DELAY; - if (typeNodes.contains(lv2World.class_simulator)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_spatial)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_spectral)) - info.category = CB::PLUGIN_CATEGORY_OTHER; - if (typeNodes.contains(lv2World.class_utility)) - info.category = CB::PLUGIN_CATEGORY_UTILITY; - if (typeNodes.contains(lv2World.class_waveshaper)) - info.category = CB::PLUGIN_CATEGORY_DISTORTION; - if (typeNodes.contains(lv2World.class_instrument)) - { - info.category = CB::PLUGIN_CATEGORY_SYNTH; - info.hints |= CB::PLUGIN_IS_SYNTH; - } + info.hints |= CB::PLUGIN_IS_RTSAFE; + } + else if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0 + || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0) + { + carla_stderr("LV2 plugin '%s' DSP wants UI feature '%s', ignoring this", info.label, featureURI); } + } + + lilv_nodes_free(const_cast(lilvSupportedFeatureNodes.me)); + } - lilv_nodes_free(const_cast(typeNodes.me)); + // ---------------------------------------------------------------------------------------------------------------- + // category + + info.category = CB::PLUGIN_CATEGORY_NONE; + + { + Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type)); + + if (typeNodes.size() > 0) + { + if (typeNodes.contains(lv2World.class_allpass)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_amplifier)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_analyzer)) + info.category = CB::PLUGIN_CATEGORY_UTILITY; + if (typeNodes.contains(lv2World.class_bandpass)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_chorus)) + info.category = CB::PLUGIN_CATEGORY_MODULATOR; + if (typeNodes.contains(lv2World.class_comb)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_compressor)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_constant)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_converter)) + info.category = CB::PLUGIN_CATEGORY_UTILITY; + if (typeNodes.contains(lv2World.class_delay)) + info.category = CB::PLUGIN_CATEGORY_DELAY; + if (typeNodes.contains(lv2World.class_distortion)) + info.category = CB::PLUGIN_CATEGORY_DISTORTION; + if (typeNodes.contains(lv2World.class_dynamics)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_eq)) + info.category = CB::PLUGIN_CATEGORY_EQ; + if (typeNodes.contains(lv2World.class_envelope)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_expander)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_filter)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_flanger)) + info.category = CB::PLUGIN_CATEGORY_MODULATOR; + if (typeNodes.contains(lv2World.class_function)) + info.category = CB::PLUGIN_CATEGORY_UTILITY; + if (typeNodes.contains(lv2World.class_gate)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_generator)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_highpass)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_limiter)) + info.category = CB::PLUGIN_CATEGORY_DYNAMICS; + if (typeNodes.contains(lv2World.class_lowpass)) + info.category = CB::PLUGIN_CATEGORY_FILTER; + if (typeNodes.contains(lv2World.class_mixer)) + info.category = CB::PLUGIN_CATEGORY_UTILITY; + if (typeNodes.contains(lv2World.class_modulator)) + info.category = CB::PLUGIN_CATEGORY_MODULATOR; + if (typeNodes.contains(lv2World.class_multiEQ)) + info.category = CB::PLUGIN_CATEGORY_EQ; + if (typeNodes.contains(lv2World.class_oscillator)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_paraEQ)) + info.category = CB::PLUGIN_CATEGORY_EQ; + if (typeNodes.contains(lv2World.class_phaser)) + info.category = CB::PLUGIN_CATEGORY_MODULATOR; + if (typeNodes.contains(lv2World.class_pitch)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_reverb)) + info.category = CB::PLUGIN_CATEGORY_DELAY; + if (typeNodes.contains(lv2World.class_simulator)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_spatial)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_spectral)) + info.category = CB::PLUGIN_CATEGORY_OTHER; + if (typeNodes.contains(lv2World.class_utility)) + info.category = CB::PLUGIN_CATEGORY_UTILITY; + if (typeNodes.contains(lv2World.class_waveshaper)) + info.category = CB::PLUGIN_CATEGORY_DISTORTION; + if (typeNodes.contains(lv2World.class_instrument)) + { + info.category = CB::PLUGIN_CATEGORY_SYNTH; + info.hints |= CB::PLUGIN_IS_SYNTH; + } } - // number data - info.audioIns = 0; - info.audioOuts = 0; - info.midiIns = 0; - info.midiOuts = 0; - info.parameterIns = 0; - info.parameterOuts = 0; + lilv_nodes_free(const_cast(typeNodes.me)); + } + + // ---------------------------------------------------------------------------------------------------------------- + // number data + + for (uint i=0, count=lilvPlugin.get_num_ports(); i(supportNodes.me)); - } - else if (lilvPort.is_a(lv2World.port_event)) + for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it)) { - if (lilvPort.supports_event(lv2World.midi_event)) + const Lilv::Node node(lilv_nodes_get(supportNodes.me, it)); + CARLA_SAFE_ASSERT_CONTINUE(node.is_uri()); + + if (node.equals(lv2World.midi_event)) { if (isInput) ++(info.midiIns); @@ -361,7 +391,12 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, ++(info.midiOuts); } } - else if (lilvPort.is_a(lv2World.port_midi)) + + lilv_nodes_free(const_cast(supportNodes.me)); + } + else if (lilvPort.is_a(lv2World.port_event)) + { + if (lilvPort.supports_event(lv2World.midi_event)) { if (isInput) ++(info.midiIns); @@ -369,59 +404,105 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, ++(info.midiOuts); } } + else if (lilvPort.is_a(lv2World.port_midi)) + { + if (isInput) + ++(info.midiIns); + else + ++(info.midiOuts); + } + else + { + const LilvNode* const symbolNode = lilvPort.get_symbol(); + CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode)); - // text data - static CarlaString suri, sname, smaker, slicense; - suri.clear(); sname.clear(); smaker.clear(); slicense.clear(); - - suri = lilvPlugin.get_uri().as_uri(); + const char* const symbol = lilv_node_as_string(symbolNode); + CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr); - if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me)) - { - if (const char* const name = lilv_node_as_string(nameNode)) - sname = name; - lilv_node_free(nameNode); + supported = false; + carla_stderr("LV2 plugin '%s' port '%s' is required but has unsupported type", info.label, symbol); } + } - if (const char* const author = lilvPlugin.get_author_name().as_string()) - smaker = author; + if (supported) + info.valid = true; - Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license)); + return &info; +} - if (licenseNodes.size() > 0) - { - if (const char* const license = licenseNodes.get_first().as_string()) - slicense = license; - } +const CarlaCachedPluginInfo* get_cached_plugin_sfz() +{ + static CarlaCachedPluginInfo info; + return &info; +} - lilv_nodes_free(const_cast(licenseNodes.me)); +// ------------------------------------------------------------------------------------------------------------------- - info.valid = true; - info.name = sname; - info.label = suri; - info.maker = smaker; - info.copyright = slicense; +uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath) +{ + CARLA_SAFE_ASSERT_RETURN(isCachedPluginType(ptype), 0); + carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype)); + + switch (ptype) + { + case CB::PLUGIN_INTERNAL: { + uint32_t count = 0; + carla_get_native_plugins_data(&count); + return count; + } + + case CB::PLUGIN_LV2: { + Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + lv2World.initIfNeeded(pluginPath); + return lv2World.getPluginCount(); + } + + case CB::PLUGIN_SFZ: { + return 0; + } + + default: + return 0; + } +} + +const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, uint index) +{ + carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index); + + switch (ptype) + { + case CB::PLUGIN_INTERNAL: { + uint32_t count = 0; + const NativePluginDescriptor* const descs(carla_get_native_plugins_data(&count)); + CARLA_SAFE_ASSERT_BREAK(index < count); + CARLA_SAFE_ASSERT_BREAK(descs != nullptr); + + const NativePluginDescriptor& desc(descs[index]); + return get_cached_plugin_internal(desc); + } - return &info; + case CB::PLUGIN_LV2: { + Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + + const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index)); + CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr); + + Lilv::Plugin lilvPlugin(cPlugin); + CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri()); + + return get_cached_plugin_lv2(lv2World, lilvPlugin); + } + + case CB::PLUGIN_SFZ: { + return get_cached_plugin_sfz(); } default: break; } - info.valid = true; - info.category = CB::PLUGIN_CATEGORY_NONE; - info.hints = 0x0; - info.audioIns = 0; - info.audioOuts = 0; - info.midiIns = 0; - info.midiOuts = 0; - info.parameterIns = 0; - info.parameterOuts = 0; - info.name = gNullCharPtr; - info.label = gNullCharPtr; - info.maker = gNullCharPtr; - info.copyright = gNullCharPtr; + static CarlaCachedPluginInfo info; return &info; } diff --git a/source/backend/utils/PipeClient.cpp b/source/backend/utils/PipeClient.cpp index a5f481280..7aa7bfe7a 100644 --- a/source/backend/utils/PipeClient.cpp +++ b/source/backend/utils/PipeClient.cpp @@ -107,6 +107,13 @@ void carla_pipe_client_lock(CarlaPipeClientHandle handle) return ((ExposedCarlaPipeClient*)handle)->lockPipe(); } +void carla_pipe_client_unlock(CarlaPipeClientHandle handle) +{ + CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); + + return ((ExposedCarlaPipeClient*)handle)->unlockPipe(); +} + const char* carla_pipe_client_readlineblock(CarlaPipeClientHandle handle, uint timeout) { CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); diff --git a/source/discovery/carla-discovery.cpp b/source/discovery/carla-discovery.cpp index 3a14eca90..7df95f86d 100644 --- a/source/discovery/carla-discovery.cpp +++ b/source/discovery/carla-discovery.cpp @@ -269,6 +269,26 @@ static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t // ------------------------------ Plugin Checks ----------------------------- #ifndef BUILD_BRIDGE +static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo) +{ + if (! pinfo->valid) + return; + + DISCOVERY_OUT("init", "-----------"); + DISCOVERY_OUT("build", BINARY_NATIVE); + DISCOVERY_OUT("hints", pinfo->hints); + DISCOVERY_OUT("name", pinfo->name); + DISCOVERY_OUT("maker", pinfo->maker); + DISCOVERY_OUT("label", pinfo->label); + DISCOVERY_OUT("audio.ins", pinfo->audioIns); + DISCOVERY_OUT("audio.outs", pinfo->audioOuts); + DISCOVERY_OUT("midi.ins", pinfo->midiIns); + DISCOVERY_OUT("midi.outs", pinfo->midiOuts); + DISCOVERY_OUT("parameters.ins", pinfo->parameterIns); + DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts); + DISCOVERY_OUT("end", "------------"); +} + static void do_cached_check(const PluginType type) { const char* const plugPath = (type == PLUGIN_LV2) ? std::getenv("LV2_PATH") : nullptr; @@ -279,22 +299,7 @@ static void do_cached_check(const PluginType type) const CarlaCachedPluginInfo* pinfo(carla_get_cached_plugin_info(type, i)); CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr); - if (! pinfo->valid) - continue; - - DISCOVERY_OUT("init", "-----------"); - DISCOVERY_OUT("build", BINARY_NATIVE); - DISCOVERY_OUT("hints", pinfo->hints); - DISCOVERY_OUT("name", pinfo->name); - DISCOVERY_OUT("maker", pinfo->maker); - DISCOVERY_OUT("label", pinfo->label); - DISCOVERY_OUT("audio.ins", pinfo->audioIns); - DISCOVERY_OUT("audio.outs", pinfo->audioOuts); - DISCOVERY_OUT("midi.ins", pinfo->midiIns); - DISCOVERY_OUT("midi.outs", pinfo->midiOuts); - DISCOVERY_OUT("parameters.ins", pinfo->parameterIns); - DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts); - DISCOVERY_OUT("end", "------------"); + print_cached_plugin(pinfo); } } #endif @@ -868,17 +873,18 @@ static void do_lv2_check(const char* const bundle, const bool doInit) // Get & check every plugin-instance for (int i=0, count=URIs.size(); i < count; ++i) { - const LV2_RDF_Descriptor* const rdfDescriptor(lv2_rdf_new(URIs[i].toRawUTF8(), false)); + const char* const URI = URIs[i].toRawUTF8(); + ScopedPointer rdfDescriptor(lv2_rdf_new(URI, false)); if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr) { - DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URIs[i].toRawUTF8() << "'"); + DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'"); continue; } if (doInit) { - // test if DLL is loadable, twice + // test if lib is loadable, twice const lib_t libHandle1 = lib_open(rdfDescriptor->Binary); if (libHandle1 == nullptr) @@ -902,137 +908,13 @@ static void do_lv2_check(const char* const bundle, const bool doInit) lib_close(libHandle2); } - // test if we support all required ports and features - { - bool supported = true; - - for (uint32_t j=0; j < rdfDescriptor->PortCount && supported; ++j) - { - const LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[j]); - - if (is_lv2_port_supported(rdfPort->Types)) - { - pass(); - } - else if (! LV2_IS_PORT_OPTIONAL(rdfPort->Properties)) - { - DISCOVERY_OUT("error", "Plugin '" << rdfDescriptor->URI << "' requires a non-supported port type (portName: '" << rdfPort->Name << "')"); - supported = false; - break; - } - } - - for (uint32_t j=0; j < rdfDescriptor->FeatureCount && supported; ++j) - { - const LV2_RDF_Feature& feature(rdfDescriptor->Features[j]); - - if (std::strcmp(feature.URI, LV2_DATA_ACCESS_URI) == 0 || std::strcmp(feature.URI, LV2_INSTANCE_ACCESS_URI) == 0) - { - DISCOVERY_OUT("warning", "Plugin '" << rdfDescriptor->URI << "' DSP wants UI feature '" << feature.URI << "', ignoring this"); - } - else if (feature.Required && ! is_lv2_feature_supported(feature.URI)) - { - DISCOVERY_OUT("error", "Plugin '" << rdfDescriptor->URI << "' requires a non-supported feature '" << feature.URI << "'"); - supported = false; - break; - } - } - - if (! supported) - { - delete rdfDescriptor; - continue; - } - } - - uint hints = 0x0; - int audioIns = 0; - int audioOuts = 0; - int midiIns = 0; - int midiOuts = 0; - int parametersIns = 0; - int parametersOuts = 0; - - for (uint32_t j=0; j < rdfDescriptor->FeatureCount; ++j) - { - const LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[j]); - - if (std::strcmp(rdfFeature->URI, LV2_CORE__hardRTCapable) == 0) - hints |= PLUGIN_IS_RTSAFE; - } - - for (uint32_t j=0; j < rdfDescriptor->PortCount; ++j) - { - const LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[j]); + const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI)); + CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr); - if (LV2_IS_PORT_AUDIO(rdfPort->Types)) - { - if (LV2_IS_PORT_INPUT(rdfPort->Types)) - audioIns += 1; - else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) - audioOuts += 1; - } - else if (LV2_IS_PORT_CONTROL(rdfPort->Types)) - { - if (LV2_IS_PORT_DESIGNATION_LATENCY(rdfPort->Designation)) - { - pass(); - } - else if (LV2_IS_PORT_DESIGNATION_SAMPLE_RATE(rdfPort->Designation)) - { - pass(); - } - else if (LV2_IS_PORT_DESIGNATION_FREEWHEELING(rdfPort->Designation)) - { - pass(); - } - else if (LV2_IS_PORT_DESIGNATION_TIME(rdfPort->Designation)) - { - pass(); - } - else - { - if (LV2_IS_PORT_INPUT(rdfPort->Types)) - parametersIns += 1; - else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) - parametersOuts += 1; - } - } - else if (LV2_PORT_SUPPORTS_MIDI_EVENT(rdfPort->Types)) - { - if (LV2_IS_PORT_INPUT(rdfPort->Types)) - midiIns += 1; - else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) - midiOuts += 1; - } - } - - if (LV2_IS_INSTRUMENT(rdfDescriptor->Type[0], rdfDescriptor->Type[1])) - hints |= PLUGIN_IS_SYNTH; - - if (rdfDescriptor->UICount > 0) - hints |= PLUGIN_HAS_CUSTOM_UI; - - DISCOVERY_OUT("init", "-----------"); - DISCOVERY_OUT("build", BINARY_NATIVE); - DISCOVERY_OUT("hints", hints); - - if (rdfDescriptor->Name != nullptr) - DISCOVERY_OUT("name", rdfDescriptor->Name); - if (rdfDescriptor->Author != nullptr) - DISCOVERY_OUT("maker", rdfDescriptor->Author); - - DISCOVERY_OUT("uri", rdfDescriptor->URI); - DISCOVERY_OUT("uniqueId", rdfDescriptor->UniqueID); - DISCOVERY_OUT("audio.ins", audioIns); - DISCOVERY_OUT("audio.outs", audioOuts); - DISCOVERY_OUT("midi.ins", midiIns); - DISCOVERY_OUT("midi.outs", midiOuts); - DISCOVERY_OUT("parameters.ins", parametersIns); - DISCOVERY_OUT("parameters.outs", parametersOuts); - DISCOVERY_OUT("end", "------------"); + Lilv::Plugin lilvPlugin(cPlugin); + CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri()); - delete rdfDescriptor; + print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin)); } }