diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index b57711547..989ffa169 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -142,82 +142,6 @@ typedef struct _CarlaPluginInfo { } CarlaPluginInfo; -/*! - * Information about a cached plugin. - * @see carla_get_cached_plugin_info() - */ -typedef struct _CarlaCachedPluginInfo { - /*! - * Plugin category. - */ - PluginCategory category; - - /*! - * Plugin hints. - * @see PluginHints - */ - uint hints; - - /*! - * Number of audio inputs. - */ - uint32_t audioIns; - - /*! - * Number of audio outputs. - */ - uint32_t audioOuts; - - /*! - * Number of MIDI inputs. - */ - uint32_t midiIns; - - /*! - * Number of MIDI outputs. - */ - uint32_t midiOuts; - - /*! - * Number of input parameters. - */ - uint32_t parameterIns; - - /*! - * Number of output parameters. - */ - uint32_t parameterOuts; - - /*! - * Plugin name. - */ - const char* name; - - /*! - * Plugin label. - */ - const char* label; - - /*! - * Plugin author/maker. - */ - const char* maker; - - /*! - * Plugin copyright/license. - */ - const char* copyright; - -#ifdef __cplusplus - /*! - * C++ constructor. - */ - CARLA_API _CarlaCachedPluginInfo() noexcept; - CARLA_DECLARE_NON_COPY_STRUCT(_CarlaCachedPluginInfo) -#endif - -} CarlaCachedPluginInfo; - /*! * Port count information, used for Audio and MIDI ports and parameters. * @see carla_get_audio_port_count_info() @@ -347,26 +271,6 @@ typedef struct _CarlaTransportInfo { /* ------------------------------------------------------------------------------------------------------------ * Carla Host API (C functions) */ -/*! - * Get the complete license text of used third-party code and features. - * Returned string is in basic html format. - */ -CARLA_EXPORT const char* carla_get_complete_license_text(); - -/*! - * Get the juce version used in the current Carla build. - */ -CARLA_EXPORT const char* carla_get_juce_version(); - -/*! - * Get all the supported file extensions in carla_load_file(). - * Returned string uses this syntax: - * @code - * "*.ext1;*.ext2;*.ext3" - * @endcode - */ -CARLA_EXPORT const char* carla_get_supported_file_extensions(); - /*! * Get how many engine drivers are available. */ @@ -391,18 +295,6 @@ CARLA_EXPORT const char* const* carla_get_engine_driver_device_names(uint index) */ CARLA_EXPORT const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name); -/*! - * Get how many cached plugins are available. - * Internal, LV2 and AU plugin formats are cached and need to be discovered via this function. - * Do not call this for any other plugin formats. - */ -CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); - -/*! - * Get information about a cached plugin. - */ -CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index); - #ifdef __cplusplus /*! * Get the currently used engine, maybe be NULL. @@ -995,12 +887,12 @@ CARLA_EXPORT const char* carla_get_host_osc_url_tcp(); CARLA_EXPORT const char* carla_get_host_osc_url_udp(); /*! - * Get the current carla library filename. + * Get the absolute filename of this carla library. */ CARLA_EXPORT const char* carla_get_library_filename(); /*! - * Get the folder where the current use carla library resides. + * Get the folder where this carla library resides. */ CARLA_EXPORT const char* carla_get_library_folder(); diff --git a/source/backend/CarlaHostCommon.cpp b/source/backend/CarlaHostCommon.cpp index e3f544bf1..65547a378 100644 --- a/source/backend/CarlaHostCommon.cpp +++ b/source/backend/CarlaHostCommon.cpp @@ -16,19 +16,8 @@ */ #include "CarlaHost.h" -#include "CarlaNative.h" -#include "CarlaLv2Utils.hpp" -#include "CarlaPlugin.hpp" -#include "CarlaString.hpp" - -#include "juce_audio_formats.h" - -#ifdef CARLA_OS_MAC -# include "juce_audio_processors.h" -using juce::AudioUnitPluginFormat; -using juce::StringArray; -#endif +#include "juce_core.h" namespace CB = CarlaBackend; @@ -72,20 +61,6 @@ _CarlaPluginInfo::~_CarlaPluginInfo() noexcept delete[] copyright; } -_CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept - : category(CB::PLUGIN_CATEGORY_NONE), - hints(0x0), - audioIns(0), - audioOuts(0), - midiIns(0), - midiOuts(0), - parameterIns(0), - parameterOuts(0), - name(gNullCharPtr), - label(gNullCharPtr), - maker(gNullCharPtr), - copyright(gNullCharPtr) {} - _CarlaParameterInfo::_CarlaParameterInfo() noexcept : name(gNullCharPtr), symbol(gNullCharPtr), @@ -122,592 +97,6 @@ _CarlaTransportInfo::_CarlaTransportInfo() noexcept // ------------------------------------------------------------------------------------------------------------------- -const char* carla_get_complete_license_text() -{ - carla_debug("carla_get_complete_license_text()"); - - static CarlaString retText; - - if (retText.isEmpty()) - { - retText = - "

This current Carla build is using the following features and 3rd-party code:

" - "" - - "

" -#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) || ! defined(VESTIGE_HEADER) - // Required by VST SDK - " [1] Trademark of Steinberg Media Technologies GmbH.
" -#endif -#ifdef HAVE_LINUXSAMPLER - // LinuxSampler GPL exception - " [2] Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors." -#endif - "

" - ; - } - - return retText; -} - -const char* carla_get_juce_version() -{ - carla_debug("carla_get_juce_version()"); - - static CarlaString retVersion; - - if (retVersion.isEmpty()) - { - if (const char* const version = juce::SystemStats::getJUCEVersion().toRawUTF8()) - retVersion = version+6; - else - retVersion = "3.0"; - } - - return retVersion; -} - -const char* carla_get_supported_file_extensions() -{ - carla_debug("carla_get_supported_file_extensions()"); - - static CarlaString retText; - - if (retText.isEmpty()) - { - retText = - // Base types - "*.carxp;*.carxs" - // MIDI files - ";*.mid;*.midi" -#ifdef HAVE_FLUIDSYNTH - // fluidsynth (sf2) - ";*.sf2" -#endif -#ifdef HAVE_LINUXSAMPLER - // linuxsampler (gig and sfz) - ";*.gig;*.sfz" -#endif -#ifdef WANT_ZYNADDSUBFX - // zynaddsubfx presets - ";*.xmz;*.xiz" -#endif - ; - -#ifndef BUILD_BRIDGE - // Audio files - { - using namespace juce; - - AudioFormatManager afm; - afm.registerBasicFormats(); - - String juceFormats; - - for (AudioFormat **it=afm.begin(), **end=afm.end(); it != end; ++it) - { - const StringArray& exts((*it)->getFileExtensions()); - - for (String *eit=exts.begin(), *eend=exts.end(); eit != eend; ++eit) - juceFormats += String(";*" + (*eit)).toRawUTF8(); - } - - retText += juceFormats.toRawUTF8(); - } -#endif - } - - return retText; -} - -// ------------------------------------------------------------------------------------------------------------------- - -#ifdef CARLA_OS_MAC -static StringArray gCachedAuPluginResults; -#endif - -uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath) -{ - CARLA_SAFE_ASSERT_RETURN(ptype == CB::PLUGIN_INTERNAL || ptype == CB::PLUGIN_LV2 || ptype == CB::PLUGIN_AU, 0); - carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype)); - - switch (ptype) - { - case CB::PLUGIN_INTERNAL: { -#ifndef BUILD_BRIDGE - return static_cast(CarlaPlugin::getNativePluginCount()); -#else - return 0; -#endif - } - - case CB::PLUGIN_LV2: { - Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); - lv2World.initIfNeeded(pluginPath); - return lv2World.getPluginCount(); - } - - case CB::PLUGIN_AU: { -#ifdef CARLA_OS_MAC - static bool initiated = false; - - if (initiated) - return static_cast(gCachedAuPluginResults.size()); - - initiated = true; - AudioUnitPluginFormat auFormat; - gCachedAuPluginResults = auFormat.searchPathsForPlugins(juce::FileSearchPath(), false); - - return static_cast(gCachedAuPluginResults.size()); -#else - return 0; -#endif - } - - default: - return 0; - } -} - -const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index) -{ - carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index); - - static CarlaCachedPluginInfo info; - - switch (ptype) - { - case CB::PLUGIN_INTERNAL: { -#ifndef BUILD_BRIDGE - const NativePluginDescriptor* const desc(CarlaPlugin::getNativePluginDescriptor(index)); - CARLA_SAFE_ASSERT_BREAK(desc != nullptr); - - 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_SINGLE_THREAD) - info.hints |= CB::PLUGIN_NEEDS_SINGLE_THREAD; - - 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; -#else - break; -#endif - } - - 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()); - - carla_stdout("Filling info for LV2 with URI '%s'", lilvPlugin.get_uri().as_uri()); - - // features - info.hints = 0x0; - - if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr) - info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; - - { - Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features()); - - LILV_FOREACH(nodes, it, lilvFeatureNodes) - { - Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it)); - const char* const featureURI(lilvFeatureNode.as_uri()); - CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); - - if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0) - info.hints |= CB::PLUGIN_IS_RTSAFE; - } - - lilv_nodes_free(const_cast(lilvFeatureNodes.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; - } - } - - lilv_nodes_free(const_cast(typeNodes.me)); - } - - // number data - info.audioIns = 0; - info.audioOuts = 0; - info.midiIns = 0; - info.midiOuts = 0; - info.parameterIns = 0; - info.parameterOuts = 0; - - for (uint i=0, count=lilvPlugin.get_num_ports(); i(supportNodes.me)); - } - else if (lilvPort.is_a(lv2World.port_event)) - { - if (lilvPort.supports_event(lv2World.midi_event)) - { - if (isInput) - ++(info.midiIns); - else - ++(info.midiOuts); - } - } - else if (lilvPort.is_a(lv2World.port_midi)) - { - if (isInput) - ++(info.midiIns); - else - ++(info.midiOuts); - } - } - - // text data - static CarlaString suri, sname, smaker, slicense; - suri.clear(); sname.clear(); smaker.clear(); slicense.clear(); - - suri = lilvPlugin.get_uri().as_uri(); - - if (const char* const name = lilvPlugin.get_name().as_string()) - sname = name; - else - sname.clear(); - - if (const char* const author = lilvPlugin.get_author_name().as_string()) - smaker = author; - else - smaker.clear(); - - Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license)); - - if (licenseNodes.size() > 0) - { - if (const char* const license = licenseNodes.get_first().as_string()) - slicense = license; - } - - lilv_nodes_free(const_cast(licenseNodes.me)); - - info.name = sname; - info.label = suri; - info.maker = smaker; - info.copyright = slicense; - - return &info; - } - - case CB::PLUGIN_AU: { -#ifdef CARLA_OS_MAC - const int indexi(static_cast(index)); - CARLA_SAFE_ASSERT_BREAK(indexi < gCachedAuPluginResults.size()); - - using namespace juce; - - String pluginId(gCachedAuPluginResults[indexi]); - OwnedArray results; - - AudioUnitPluginFormat auFormat; - auFormat.findAllTypesForFile(results, pluginId); - CARLA_SAFE_ASSERT_BREAK(results.size() > 0); - CARLA_SAFE_ASSERT(results.size() == 1); - - PluginDescription* const desc(results[0]); - CARLA_SAFE_ASSERT_BREAK(desc != nullptr); - - info.category = CB::getPluginCategoryFromName(desc->category.toRawUTF8()); - info.hints = 0x0; - - if (desc->isInstrument) - info.hints |= CB::PLUGIN_IS_SYNTH; - if (true) - info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; - - info.audioIns = static_cast(desc->numInputChannels); - info.audioOuts = static_cast(desc->numOutputChannels); - info.midiIns = desc->isInstrument ? 1 : 0; - info.midiOuts = 0; - info.parameterIns = 0; - info.parameterOuts = 0; - - static CarlaString sname, slabel, smaker; - - sname = desc->name.toRawUTF8(); - slabel = desc->fileOrIdentifier.toRawUTF8(); - smaker = desc->manufacturerName.toRawUTF8(); - - info.name = sname; - info.label = slabel; - info.maker = smaker; - info.copyright = gNullCharPtr; - - return &info; -#else - break; -#endif - } - - default: - break; - } - - 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; - return &info; -} - -// ------------------------------------------------------------------------------------------------------------------- - const char* carla_get_library_filename() { carla_debug("carla_get_library_filename()"); diff --git a/source/backend/CarlaPlugin.hpp b/source/backend/CarlaPlugin.hpp index 27ad8357a..a93f0dbe6 100644 --- a/source/backend/CarlaPlugin.hpp +++ b/source/backend/CarlaPlugin.hpp @@ -889,9 +889,6 @@ public: const int64_t uniqueId; }; - static std::size_t getNativePluginCount() noexcept; - static const NativePluginDescriptor* getNativePluginDescriptor(const std::size_t index) noexcept; - static CarlaPlugin* newNative(const Initializer& init); static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeBinary); diff --git a/source/backend/CarlaUtils.cpp b/source/backend/CarlaUtils.cpp index bb8e543de..86620b76f 100644 --- a/source/backend/CarlaUtils.cpp +++ b/source/backend/CarlaUtils.cpp @@ -17,48 +17,779 @@ #include "CarlaUtils.h" +#include "CarlaNative.h" + +#include "CarlaBackendUtils.hpp" +#include "CarlaLv2Utils.hpp" #include "CarlaPipeUtils.hpp" #include "CarlaThread.hpp" +#include "LinkedList.hpp" + +#include "juce_audio_formats.h" + +#ifdef CARLA_OS_MAC +# include "juce_audio_processors.h" +#endif -#include "juce_core.h" +namespace CB = CarlaBackend; + +static const char* const gNullCharPtr = ""; + +#ifdef CARLA_OS_MAC +static juce::StringArray gCachedAuPluginResults; +#endif // ------------------------------------------------------------------------------------------------------------------- -const char* carla_get_library_filename() +_CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept + : category(CB::PLUGIN_CATEGORY_NONE), + hints(0x0), + audioIns(0), + audioOuts(0), + midiIns(0), + midiOuts(0), + parameterIns(0), + parameterOuts(0), + name(gNullCharPtr), + label(gNullCharPtr), + maker(gNullCharPtr), + copyright(gNullCharPtr) {} + +// ------------------------------------------------------------------------------------------------------------------- + +static const NativePluginDescriptor carlaRackDesc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS + |NATIVE_PLUGIN_NEEDS_SINGLE_THREAD + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 2, + /* audioOuts */ 2, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "Carla-Rack", + /* label */ "carlarack", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, +}; + +static const NativePluginDescriptor carlaPatchbayDesc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS + |NATIVE_PLUGIN_NEEDS_SINGLE_THREAD + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 2, + /* audioOuts */ 2, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "Carla-Patchbay", + /* label */ "carlapatchbay", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, +}; + +static const NativePluginDescriptor carlaPatchbay3sDesc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS + |NATIVE_PLUGIN_NEEDS_SINGLE_THREAD + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 3, + /* audioOuts */ 2, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "Carla-Patchbay (sidechain)", + /* label */ "carlapatchbay3s", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, +}; + +static const NativePluginDescriptor carlaPatchbay16Desc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS + |NATIVE_PLUGIN_NEEDS_SINGLE_THREAD + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 16, + /* audioOuts */ 16, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "Carla-Patchbay (16chan)", + /* label */ "carlapatchbay16", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, +}; + +static const NativePluginDescriptor carlaPatchbay32Desc = { + /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, + /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH + |NATIVE_PLUGIN_HAS_UI + |NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS + |NATIVE_PLUGIN_NEEDS_SINGLE_THREAD + |NATIVE_PLUGIN_USES_STATE + |NATIVE_PLUGIN_USES_TIME), + /* supports */ static_cast(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), + /* audioIns */ 32, + /* audioOuts */ 32, + /* midiIns */ 1, + /* midiOuts */ 1, + /* paramIns */ 0, + /* paramOuts */ 0, + /* name */ "Carla-Patchbay (32chan)", + /* label */ "carlapatchbay32", + /* maker */ "falkTX", + /* copyright */ "GNU GPL v2+", + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, +}; + +static LinkedList gPluginDescriptors; + +static const +struct ScopedInitializer { + ScopedInitializer() + { + carla_register_all_plugins(); + } + + ~ScopedInitializer() + { + gPluginDescriptors.clear(); + } +} _si; + +// ------------------------------------------------------------------------------------------------------------------- + +CARLA_EXTERN_C +void carla_register_native_plugin_carla(); + +void carla_register_native_plugin_carla() { - carla_debug("carla_get_library_filename()"); + gPluginDescriptors.append(&carlaRackDesc); + gPluginDescriptors.append(&carlaPatchbayDesc); + gPluginDescriptors.append(&carlaPatchbay3sDesc); + gPluginDescriptors.append(&carlaPatchbay16Desc); + gPluginDescriptors.append(&carlaPatchbay32Desc); +} - static CarlaString ret; +void carla_register_native_plugin(const NativePluginDescriptor* desc) +{ + gPluginDescriptors.append(desc); +} - if (ret.isEmpty()) +// ------------------------------------------------------------------------------------------------------------------- + +const char* carla_get_complete_license_text() +{ + carla_debug("carla_get_complete_license_text()"); + + static CarlaString retText; + + if (retText.isEmpty()) { - using juce::File; - ret = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName().toRawUTF8(); + retText = + "

This current Carla build is using the following features and 3rd-party code:

" + "
    " + + // Plugin formats + "
  • LADSPA plugin support
  • " + "
  • DSSI plugin support
  • " + "
  • LV2 plugin support
  • " +#ifdef VESTIGE_HEADER + "
  • VST2 plugin support using VeSTige header by Javier Serrano Polo
  • " +#else + "
  • VST2 plugin support using official VST SDK 2.4 [1]
  • " +#endif +#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) + "
  • VST3 plugin support using official VST SDK 3.6 [1]
  • " +#endif +#ifdef CARLA_OS_MAC + "
  • AU plugin support
  • " +#endif + + // Sample kit libraries +#ifdef HAVE_FLUIDSYNTH + "
  • FluidSynth library for SF2 support
  • " +#endif +#ifdef HAVE_LINUXSAMPLER + "
  • LinuxSampler library for GIG and SFZ support [2]
  • " +#endif + + // Internal plugins + "
  • NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen
  • " +#ifdef WANT_ZYNADDSUBFX + "
  • ZynAddSubFX plugin code
  • " +#endif + + // misc libs + "
  • base64 utilities based on code by Ren\u00E9 Nyffenegger
  • " +#ifdef CARLA_OS_MAC + "
  • sem_timedwait for Mac OS by Keith Shortridge
  • " +#endif + "
  • liblo library for OSC support
  • " + "
  • rtmempool library by Nedko Arnaudov" + "
  • serd, sord, sratom and lilv libraries for LV2 discovery
  • " +#if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) + "
  • RtAudio and RtMidi libraries for extra Audio and MIDI support
  • " +#endif + + // end + "
" + + "

" +#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) || ! defined(VESTIGE_HEADER) + // Required by VST SDK + " [1] Trademark of Steinberg Media Technologies GmbH.
" +#endif +#ifdef HAVE_LINUXSAMPLER + // LinuxSampler GPL exception + " [2] Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors." +#endif + "

" + ; } - return ret; + return retText; } -const char* carla_get_library_folder() +const char* carla_get_juce_version() { - carla_debug("carla_get_library_folder()"); + carla_debug("carla_get_juce_version()"); - static CarlaString ret; + static CarlaString retVersion; - if (ret.isEmpty()) + if (retVersion.isEmpty()) { - using juce::File; - ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8(); + if (const char* const version = juce::SystemStats::getJUCEVersion().toRawUTF8()) + retVersion = version+6; + else + retVersion = "3.0"; } - return ret; + return retVersion; +} + +const char* carla_get_supported_file_extensions() +{ + carla_debug("carla_get_supported_file_extensions()"); + + static CarlaString retText; + + if (retText.isEmpty()) + { + retText = + // Base types + "*.carxp;*.carxs" + // MIDI files + ";*.mid;*.midi" +#ifdef HAVE_FLUIDSYNTH + // fluidsynth (sf2) + ";*.sf2" +#endif +#ifdef HAVE_LINUXSAMPLER + // linuxsampler (gig and sfz) + ";*.gig;*.sfz" +#endif +#ifdef WANT_ZYNADDSUBFX + // zynaddsubfx presets + ";*.xmz;*.xiz" +#endif + ; + + // Audio files + { + using namespace juce; + + AudioFormatManager afm; + afm.registerBasicFormats(); + + String juceFormats; + + for (AudioFormat **it=afm.begin(), **end=afm.end(); it != end; ++it) + { + const StringArray& exts((*it)->getFileExtensions()); + + for (String *eit=exts.begin(), *eend=exts.end(); eit != eend; ++eit) + juceFormats += String(";*" + (*eit)).toRawUTF8(); + } + + retText += juceFormats.toRawUTF8(); + } + } + + return retText; } // ------------------------------------------------------------------------------------------------------------------- -void carla_set_locale_C() +uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath) { - ::setlocale(LC_NUMERIC, "C"); + CARLA_SAFE_ASSERT_RETURN(ptype == CB::PLUGIN_INTERNAL || ptype == CB::PLUGIN_LV2 || ptype == CB::PLUGIN_AU, 0); + carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype)); + + switch (ptype) + { + case CB::PLUGIN_INTERNAL: { + return static_cast(gPluginDescriptors.count()); + } + + case CB::PLUGIN_LV2: { + Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); + lv2World.initIfNeeded(pluginPath); + return lv2World.getPluginCount(); + } + + case CB::PLUGIN_AU: { +#ifdef CARLA_OS_MAC + static bool initiated = false; + + if (initiated) + return static_cast(gCachedAuPluginResults.size()); + + using namespace juce; + + initiated = true; + AudioUnitPluginFormat auFormat; + gCachedAuPluginResults = auFormat.searchPathsForPlugins(juce::FileSearchPath(), false); + + return static_cast(gCachedAuPluginResults.size()); +#else + return 0; +#endif + } + + 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); + + static CarlaCachedPluginInfo info; + + switch (ptype) + { + case CB::PLUGIN_INTERNAL: { + const NativePluginDescriptor* const desc(gPluginDescriptors.getAt(index, nullptr)); + CARLA_SAFE_ASSERT_BREAK(desc != nullptr); + + 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_SINGLE_THREAD) + info.hints |= CB::PLUGIN_NEEDS_SINGLE_THREAD; + + 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; + } + + 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()); + + carla_stdout("Filling info for LV2 with URI '%s'", lilvPlugin.get_uri().as_uri()); + + // features + info.hints = 0x0; + +#if 0 + if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr) + info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; +#endif + + { + Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features()); + + LILV_FOREACH(nodes, it, lilvFeatureNodes) + { + Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it)); + const char* const featureURI(lilvFeatureNode.as_uri()); + CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); + + if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0) + info.hints |= CB::PLUGIN_IS_RTSAFE; + } + + lilv_nodes_free(const_cast(lilvFeatureNodes.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; + } + } + + lilv_nodes_free(const_cast(typeNodes.me)); + } + + // number data + info.audioIns = 0; + info.audioOuts = 0; + info.midiIns = 0; + info.midiOuts = 0; + info.parameterIns = 0; + info.parameterOuts = 0; + + for (uint i=0, count=lilvPlugin.get_num_ports(); i(supportNodes.me)); + } + else if (lilvPort.is_a(lv2World.port_event)) + { + if (lilvPort.supports_event(lv2World.midi_event)) + { + if (isInput) + ++(info.midiIns); + else + ++(info.midiOuts); + } + } + else if (lilvPort.is_a(lv2World.port_midi)) + { + if (isInput) + ++(info.midiIns); + else + ++(info.midiOuts); + } + } + + // text data + static CarlaString suri, sname, smaker, slicense; + suri.clear(); sname.clear(); smaker.clear(); slicense.clear(); + + suri = lilvPlugin.get_uri().as_uri(); + + if (const char* const name = lilvPlugin.get_name().as_string()) + sname = name; + else + sname.clear(); + + if (const char* const author = lilvPlugin.get_author_name().as_string()) + smaker = author; + else + smaker.clear(); + + Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license)); + + if (licenseNodes.size() > 0) + { + if (const char* const license = licenseNodes.get_first().as_string()) + slicense = license; + } + + lilv_nodes_free(const_cast(licenseNodes.me)); + + info.name = sname; + info.label = suri; + info.maker = smaker; + info.copyright = slicense; + + return &info; + } + + case CB::PLUGIN_AU: { +#ifdef CARLA_OS_MAC + const int indexi(static_cast(index)); + CARLA_SAFE_ASSERT_BREAK(indexi < gCachedAuPluginResults.size()); + + using namespace juce; + + String pluginId(gCachedAuPluginResults[indexi]); + OwnedArray results; + + AudioUnitPluginFormat auFormat; + auFormat.findAllTypesForFile(results, pluginId); + CARLA_SAFE_ASSERT_BREAK(results.size() > 0); + CARLA_SAFE_ASSERT(results.size() == 1); + + PluginDescription* const desc(results[0]); + CARLA_SAFE_ASSERT_BREAK(desc != nullptr); + + info.category = CB::getPluginCategoryFromName(desc->category.toRawUTF8()); + info.hints = 0x0; + + if (desc->isInstrument) + info.hints |= CB::PLUGIN_IS_SYNTH; + if (true) + info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; + + info.audioIns = static_cast(desc->numInputChannels); + info.audioOuts = static_cast(desc->numOutputChannels); + info.midiIns = desc->isInstrument ? 1 : 0; + info.midiOuts = 0; + info.parameterIns = 0; + info.parameterOuts = 0; + + static CarlaString sname, slabel, smaker; + + sname = desc->name.toRawUTF8(); + slabel = desc->fileOrIdentifier.toRawUTF8(); + smaker = desc->manufacturerName.toRawUTF8(); + + info.name = sname; + info.label = slabel; + info.maker = smaker; + info.copyright = gNullCharPtr; + + return &info; +#else + break; +#endif + } + + default: + break; + } + + 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; + return &info; } // ------------------------------------------------------------------------------------------------------------------- @@ -202,6 +933,38 @@ void carla_pipe_client_destroy(CarlaPipeClientHandle handle) // ------------------------------------------------------------------------------------------------------------------- +const char* carla_get_library_filename() +{ + carla_debug("carla_get_library_filename()"); + + static CarlaString ret; + + if (ret.isEmpty()) + { + using juce::File; + ret = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName().toRawUTF8(); + } + + return ret; +} + +const char* carla_get_library_folder() +{ + carla_debug("carla_get_library_folder()"); + + static CarlaString ret; + + if (ret.isEmpty()) + { + using juce::File; + ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8(); + } + + return ret; +} + +// ------------------------------------------------------------------------------------------------------------------- + #include "CarlaPipeUtils.cpp" // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/backend/CarlaUtils.h b/source/backend/CarlaUtils.h index 1aec97be2..5c0f29665 100644 --- a/source/backend/CarlaUtils.h +++ b/source/backend/CarlaUtils.h @@ -18,7 +18,12 @@ #ifndef CARLA_UTILS_H_INCLUDED #define CARLA_UTILS_H_INCLUDED -#include "CarlaDefines.h" +#include "CarlaBackend.h" + +#ifdef __cplusplus +using CarlaBackend::PluginCategory; +using CarlaBackend::PluginType; +#endif /*! * @defgroup CarlaUtilsAPI Carla Utils API @@ -40,25 +45,127 @@ typedef void* CarlaPipeClientHandle; typedef void (*CarlaPipeCallbackFunc)(void* ptr, const char* msg); /*! - * Get the current carla library filename. + * Information about a cached plugin. + * @see carla_get_cached_plugin_info() */ -CARLA_EXPORT const char* carla_get_library_filename(); +typedef struct _CarlaCachedPluginInfo { + /*! + * Plugin category. + */ + PluginCategory category; + + /*! + * Plugin hints. + * @see PluginHints + */ + uint hints; + + /*! + * Number of audio inputs. + */ + uint32_t audioIns; + + /*! + * Number of audio outputs. + */ + uint32_t audioOuts; + + /*! + * Number of MIDI inputs. + */ + uint32_t midiIns; + + /*! + * Number of MIDI outputs. + */ + uint32_t midiOuts; + + /*! + * Number of input parameters. + */ + uint32_t parameterIns; + + /*! + * Number of output parameters. + */ + uint32_t parameterOuts; + + /*! + * Plugin name. + */ + const char* name; + + /*! + * Plugin label. + */ + const char* label; + + /*! + * Plugin author/maker. + */ + const char* maker; + + /*! + * Plugin copyright/license. + */ + const char* copyright; + +#ifdef __cplusplus + /*! + * C++ constructor. + */ + CARLA_API _CarlaCachedPluginInfo() noexcept; + CARLA_DECLARE_NON_COPY_STRUCT(_CarlaCachedPluginInfo) +#endif + +} CarlaCachedPluginInfo; + +/* ------------------------------------------------------------------------------------------------------------ + * get stuff */ /*! - * Get the folder where the current use carla library resides. + * Get the complete license text of used third-party code and features. + * Returned string is in basic html format. */ -CARLA_EXPORT const char* carla_get_library_folder(); +CARLA_EXPORT const char* carla_get_complete_license_text(); /*! - * TODO. + * Get the juce version used in the current Carla build. */ -CARLA_EXPORT void carla_set_locale_C(); +CARLA_EXPORT const char* carla_get_juce_version(); /*! - * Get the juce version used in the current Carla build. + * Get all the supported file extensions in carla_load_file(). + * Returned string uses this syntax: + * @code + * "*.ext1;*.ext2;*.ext3" + * @endcode + */ +CARLA_EXPORT const char* carla_get_supported_file_extensions(); + +/*! + * Get how many cached plugins are available. + * Internal, LV2 and AU plugin formats are cached and need to be discovered via this function. + * Do not call this for any other plugin formats. + */ +CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); + +/*! + * Get information about a cached plugin. + */ +CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index); + +/* ------------------------------------------------------------------------------------------------------------ + * set stuff */ + +/*! + * Set the current process name to @a name. */ CARLA_EXPORT void carla_set_process_name(const char* name); +/* ------------------------------------------------------------------------------------------------------------ + * pipes */ + /*! * TODO. */ @@ -114,6 +221,21 @@ CARLA_EXPORT bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handl */ CARLA_EXPORT void carla_pipe_client_destroy(CarlaPipeClientHandle handle); +/* ------------------------------------------------------------------------------------------------------------ + * info about current library */ + +/*! + * Get the absolute filename of this carla library. + */ +CARLA_EXPORT const char* carla_get_library_filename(); + +/*! + * Get the folder where this carla library resides. + */ +CARLA_EXPORT const char* carla_get_library_folder(); + +// ------------------------------------------------------------------------------------------------------------------- + /** @} */ #endif /* CARLA_UTILS_H_INCLUDED */ diff --git a/source/backend/Makefile b/source/backend/Makefile index 1c3f6048b..b4cf348c9 100644 --- a/source/backend/Makefile +++ b/source/backend/Makefile @@ -45,7 +45,11 @@ STANDALONE_LIBS += $(MODULEDIR)/rtaudio.a STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a endif -UTILS_LIBS = $(MODULEDIR)/juce_core.a +UTILS_LIBS = $(MODULEDIR)/juce_audio_basics.a +UTILS_LIBS += $(MODULEDIR)/juce_audio_formats.a +UTILS_LIBS += $(MODULEDIR)/juce_core.a +UTILS_LIBS += $(MODULEDIR)/lilv.a +UTILS_LIBS += $(MODULEDIR)/native-plugins.a # ---------------------------------------------------------------------------------------------------------------------------- @@ -89,10 +93,11 @@ ifeq ($(UNIX),true) STANDALONE_LINK_FLAGS += -lmagic endif -UTILS_LINK_FLAGS = $(JUCE_CORE_LIBS) -ifeq ($(UNIX),true) -UTILS_LINK_FLAGS += -lpthread -endif +UTILS_LINK_FLAGS = $(JUCE_AUDIO_BASICS_LIBS) +UTILS_LINK_FLAGS += $(JUCE_AUDIO_FORMATS_LIBS) +UTILS_LINK_FLAGS += $(JUCE_CORE_LIBS) +UTILS_LINK_FLAGS += $(LILV_LIBS) +UTILS_LINK_FLAGS += $(NATIVE_PLUGINS_LIBS) # ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index f569e38a9..d23cda0d8 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -31,6 +31,7 @@ #include "CarlaStateUtils.hpp" #include "CarlaExternalUI.hpp" +#include "CarlaHost.h" #include "CarlaNative.hpp" #include "juce_audio_basics.h" @@ -973,15 +974,6 @@ protected: const CarlaMutexLocker cml(fUiServer.getPipeLock()); - fUiServer.writeAndFixMessage("complete-license"); - fUiServer.writeAndFixMessage(carla_get_complete_license_text()); - - fUiServer.writeAndFixMessage("juce-version"); - fUiServer.writeAndFixMessage(carla_get_juce_version()); - - fUiServer.writeAndFixMessage("file-exts"); - fUiServer.writeAndFixMessage(carla_get_supported_file_extensions()); - fUiServer.writeAndFixMessage("max-plugin-number"); std::sprintf(fTmpBuf, "%i\n", pData->maxPluginNumber); fUiServer.writeMessage(fTmpBuf); diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index e1699f053..98995c8f0 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -26,7 +26,15 @@ using juce::String; using juce::StringArray; -// ----------------------------------------------------- +// ----------------------------------------------------------------------- + +CARLA_EXTERN_C +std::size_t carla_getNativePluginCount(); + +CARLA_EXTERN_C +const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index); + +// ----------------------------------------------------------------------- static LinkedList gPluginDescriptors; @@ -35,6 +43,16 @@ void carla_register_native_plugin(const NativePluginDescriptor* desc) gPluginDescriptors.append(desc); } +std::size_t carla_getNativePluginCount() +{ + return gPluginDescriptors.count(); +} + +const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) +{ + return gPluginDescriptors.getAt(index, nullptr); +} + // ----------------------------------------------------- CARLA_BACKEND_START_NAMESPACE @@ -123,7 +141,7 @@ struct ScopedInitializer { carla_register_all_plugins(); } - ~ScopedInitializer() + ~ScopedInitializer() noexcept { gPluginDescriptors.clear(); } @@ -2201,20 +2219,6 @@ protected: // ------------------------------------------------------------------- public: - static size_t getPluginCount() noexcept - { - return gPluginDescriptors.count(); - } - - static const NativePluginDescriptor* getPluginDescriptor(const size_t index) noexcept - { - CARLA_SAFE_ASSERT_RETURN(index < gPluginDescriptors.count(), nullptr); - - return gPluginDescriptors.getAt(index, nullptr); - } - - // ------------------------------------------------------------------- - void* getNativeHandle() const noexcept override { return fHandle; @@ -2435,18 +2439,6 @@ private: // ----------------------------------------------------------------------- -std::size_t CarlaPlugin::getNativePluginCount() noexcept -{ - return CarlaPluginNative::getPluginCount(); -} - -const NativePluginDescriptor* CarlaPlugin::getNativePluginDescriptor(const std::size_t index) noexcept -{ - return CarlaPluginNative::getPluginDescriptor(index); -} - -// ----------------------------------------------------------------------- - CarlaPlugin* CarlaPlugin::newNative(const Initializer& init) { carla_debug("CarlaPlugin::newNative({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.label, init.uniqueId); diff --git a/source/carla_backend.py b/source/carla_backend.py index e81e7b442..ffd40b604 100644 --- a/source/carla_backend.py +++ b/source/carla_backend.py @@ -1060,48 +1060,6 @@ class CarlaPluginInfo(Structure): ("uniqueId", c_int64) ] -# Information about an internal Carla plugin. -# @see carla_get_cached_plugin_info() -class CarlaCachedPluginInfo(Structure): - _fields_ = [ - # Plugin category. - ("category", c_enum), - - # Plugin hints. - # @see PluginHints - ("hints", c_uint), - - # Number of audio inputs. - ("audioIns", c_uint32), - - # Number of audio outputs. - ("audioOuts", c_uint32), - - # Number of MIDI inputs. - ("midiIns", c_uint32), - - # Number of MIDI outputs. - ("midiOuts", c_uint32), - - # Number of input parameters. - ("parameterIns", c_uint32), - - # Number of output parameters. - ("parameterOuts", c_uint32), - - # Plugin name. - ("name", c_char_p), - - # Plugin label. - ("label", c_char_p), - - # Plugin author/maker. - ("maker", c_char_p), - - # Plugin copyright/license. - ("copyright", c_char_p) - ] - # Port count information, used for Audio and MIDI ports and parameters. # @see carla_get_audio_port_count_info() # @see carla_get_midi_port_count_info() @@ -1186,22 +1144,6 @@ PyCarlaPluginInfo = { 'uniqueId': 0 } -# @see CarlaCachedPluginInfo -PyCarlaCachedPluginInfo = { - 'category': PLUGIN_CATEGORY_NONE, - 'hints': 0x0, - 'audioIns': 0, - 'audioOuts': 0, - 'midiIns': 0, - 'midiOuts': 0, - 'parameterIns': 0, - 'parameterOuts': 0, - 'name': "", - 'label': "", - 'maker': "", - 'copyright': "" -} - # @see CarlaPortCountInfo PyCarlaPortCountInfo = { 'ins': 0, @@ -1299,26 +1241,6 @@ class CarlaHostMeta(object): keyrm = "%s=" % key self.msvcrt._putenv(keyrm.encode("utf-8")) - # Get the complete license text of used third-party code and features. - # Returned string is in basic html format. - @abstractmethod - def get_complete_license_text(self): - raise NotImplementedError - - # Get the juce version used in the current Carla build. - @abstractmethod - def get_juce_version(self): - raise NotImplementedError - - # Get all the supported file extensions in carla_load_file(). - # Returned string uses this syntax: - # @code - # "*.ext1;*.ext2;*.ext3" - # @endcode - @abstractmethod - def get_supported_file_extensions(self): - raise NotImplementedError - # Get how many engine drivers are available. @abstractmethod def get_engine_driver_count(self): @@ -1343,16 +1265,6 @@ class CarlaHostMeta(object): def get_engine_driver_device_info(self, index, name): raise NotImplementedError - # Get how many internal plugins are available. - @abstractmethod - def get_cached_plugin_count(self, ptype, pluginPath): - raise NotImplementedError - - # Get information about a cached plugin. - @abstractmethod - def get_cached_plugin_info(self, ptype, index): - raise NotImplementedError - # Initialize the engine. # Make sure to call carla_engine_idle() at regular intervals afterwards. # @param driverName Driver to use @@ -1925,53 +1837,6 @@ class CarlaHostNull(CarlaHostMeta): self.fEngineCallback = None self.fEngineRunning = False - def get_complete_license_text(self): - text = ( - "

This current Carla build is using the following features and 3rd-party code:

" - "
    " - - # Plugin formats - "
  • LADSPA plugin support
  • " - "
  • DSSI plugin support
  • " - "
  • LV2 plugin support
  • " - "
  • VST2 plugin support using official VST SDK 2.4 [1]
  • " - "
  • VST3 plugin support using official VST SDK 3.6 [1]
  • " - "
  • AU plugin support
  • " - - # Sample kit libraries - "
  • FluidSynth library for SF2 support
  • " - "
  • LinuxSampler library for GIG and SFZ support [2]
  • " - - # Internal plugins - "
  • NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen
  • " - "
  • ZynAddSubFX plugin code
  • " - - # misc libs - "
  • base64 utilities based on code by Ren\u00E9 Nyffenegger
  • " - "
  • sem_timedwait for Mac OS by Keith Shortridge
  • " - "
  • liblo library for OSC support
  • " - "
  • rtmempool library by Nedko Arnaudov" - "
  • serd, sord, sratom and lilv libraries for LV2 discovery
  • " - "
  • RtAudio and RtMidi libraries for extra Audio and MIDI support
  • " - - # end - "
" - - "

" - # Required by VST SDK - " [1] Trademark of Steinberg Media Technologies GmbH.
" - # LinuxSampler GPL exception - " [2] Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors." - "

" - ) - return text - - def get_juce_version(self): - return "3.0" - - def get_supported_file_extensions(self): - return "*.carxp;*.carxs;*.mid;*.midi;*.sf2;*.gig;*.sfz;*.xmz;*.xiz" - def get_engine_driver_count(self): return 0 @@ -1984,12 +1849,6 @@ class CarlaHostNull(CarlaHostMeta): def get_engine_driver_device_info(self, index, name): return PyEngineDriverDeviceInfo - def get_cached_plugin_count(self, ptype, pluginPath): - return 0 - - def get_cached_plugin_info(self, ptype, index): - return PyCarlaCachedPluginInfo - def engine_init(self, driverName, clientName): self.fEngineRunning = True if self.fEngineCallback is not None: @@ -2251,15 +2110,6 @@ class CarlaHostDLL(CarlaHostMeta): self.lib = cdll.LoadLibrary(libName) - self.lib.carla_get_complete_license_text.argtypes = None - self.lib.carla_get_complete_license_text.restype = c_char_p - - self.lib.carla_get_juce_version.argtypes = None - self.lib.carla_get_juce_version.restype = c_char_p - - self.lib.carla_get_supported_file_extensions.argtypes = None - self.lib.carla_get_supported_file_extensions.restype = c_char_p - self.lib.carla_get_engine_driver_count.argtypes = None self.lib.carla_get_engine_driver_count.restype = c_uint @@ -2272,12 +2122,6 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_get_engine_driver_device_info.argtypes = [c_uint, c_char_p] self.lib.carla_get_engine_driver_device_info.restype = POINTER(EngineDriverDeviceInfo) - self.lib.carla_get_cached_plugin_count.argtypes = [c_enum, c_char_p] - self.lib.carla_get_cached_plugin_count.restype = c_uint - - self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint] - self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo) - self.lib.carla_engine_init.argtypes = [c_char_p, c_char_p] self.lib.carla_engine_init.restype = c_bool @@ -2523,15 +2367,6 @@ class CarlaHostDLL(CarlaHostMeta): # -------------------------------------------------------------------------------------------------------- - def get_complete_license_text(self): - return charPtrToString(self.lib.carla_get_complete_license_text()) - - def get_juce_version(self): - return charPtrToString(self.lib.carla_get_juce_version()) - - def get_supported_file_extensions(self): - return charPtrToString(self.lib.carla_get_supported_file_extensions()) - def get_engine_driver_count(self): return int(self.lib.carla_get_engine_driver_count()) @@ -2544,12 +2379,6 @@ class CarlaHostDLL(CarlaHostMeta): def get_engine_driver_device_info(self, index, name): return structToDict(self.lib.carla_get_engine_driver_device_info(index, name.encode("utf-8")).contents) - def get_cached_plugin_count(self, ptype, pluginPath): - return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) - - def get_cached_plugin_info(self, ptype, index): - return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents) - def engine_init(self, driverName, clientName): return bool(self.lib.carla_engine_init(driverName.encode("utf-8"), clientName.encode("utf-8"))) @@ -2836,11 +2665,8 @@ class CarlaHostPlugin(CarlaHostMeta): self.processModeForced = True # text data to return when requested - self.fCompleteLicenseText = "" - self.fJuceVersion = "" - self.fSupportedFileExts = "" - self.fMaxPluginNumber = 0 - self.fLastError = "" + self.fMaxPluginNumber = 0 + self.fLastError = "" # plugin info self.fPluginsInfo = [] @@ -2876,15 +2702,6 @@ class CarlaHostPlugin(CarlaHostMeta): # -------------------------------------------------------------------------------------------------------- - def get_complete_license_text(self): - return self.fCompleteLicenseText - - def get_juce_version(self): - return self.fJuceVersion - - def get_supported_file_extensions(self): - return self.fSupportedFileExts - def get_engine_driver_count(self): return 1 @@ -2897,12 +2714,6 @@ class CarlaHostPlugin(CarlaHostMeta): def get_engine_driver_device_info(self, index, name): return PyEngineDriverDeviceInfo - def get_cached_plugin_count(self, ptype, pluginPath): - return 0 - - def get_cached_plugin_info(self, ptype, index): - return PyCarlaCachedPluginInfo - def set_engine_callback(self, func): return # TODO @@ -3143,12 +2954,6 @@ class CarlaHostPlugin(CarlaHostMeta): # -------------------------------------------------------------------------------------------------------- - def _set_info(self, license, juceversion, fileexts, maxnum): - self.fCompleteLicenseText = license - self.fJuceVersion = juceversion - self.fSupportedFileExts = fileexts - self.fMaxPluginNumber = maxnum - def _set_transport(self, playing, frame, bar, beat, tick, bpm): self.fTransportInfo = { "playing": playing, diff --git a/source/carla_database.py b/source/carla_database.py index 5ce407b37..14ef20bd7 100755 --- a/source/carla_database.py +++ b/source/carla_database.py @@ -1482,9 +1482,9 @@ class PluginDatabaseW(QDialog): AU_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_AU, CARLA_DEFAULT_AU_PATH))) del settings - internalCountNew = self.host.get_cached_plugin_count(PLUGIN_INTERNAL, "") - lv2CountNew = self.host.get_cached_plugin_count(PLUGIN_LV2, LV2_PATH) - auCountNew = self.host.get_cached_plugin_count(PLUGIN_AU, AU_PATH) + internalCountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_INTERNAL, "") + lv2CountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_LV2, LV2_PATH) + auCountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_AU, AU_PATH) if internalCountNew != internalCount or (len(internalPlugins) > 0 and len(internalPlugins[0]) > 0 and @@ -1492,7 +1492,7 @@ class PluginDatabaseW(QDialog): internalPlugins = [] for i in range(internalCountNew): - descInfo = self.host.get_cached_plugin_info(PLUGIN_INTERNAL, i) + descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_INTERNAL, i) plugins = checkPluginCached(descInfo, PLUGIN_INTERNAL) if plugins: @@ -1506,7 +1506,7 @@ class PluginDatabaseW(QDialog): lv2Plugins = [] for i in range(lv2CountNew): - descInfo = self.host.get_cached_plugin_info(PLUGIN_LV2, i) + descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_LV2, i) plugins = checkPluginCached(descInfo, PLUGIN_LV2) if plugins: @@ -1520,7 +1520,7 @@ class PluginDatabaseW(QDialog): auPlugins = [] for i in range(auCountNew): - descInfo = self.host.get_cached_plugin_info(PLUGIN_AU, i) + descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_AU, i) plugins = checkPluginCached(descInfo, PLUGIN_AU) if plugins: diff --git a/source/carla_host.py b/source/carla_host.py index 3f7340a34..65244d7c1 100644 --- a/source/carla_host.py +++ b/source/carla_host.py @@ -207,7 +207,7 @@ class HostWindow(QMainWindow): self.fDirModel = QFileSystemModel(self) self.fDirModel.setRootPath(HOME) - self.fDirModel.setNameFilters(host.get_supported_file_extensions().split(";")) + self.fDirModel.setNameFilters(gCarla.utils.get_supported_file_extensions().split(";")) self.ui.fileTreeView.setModel(self.fDirModel) self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME)) @@ -1328,7 +1328,7 @@ class HostWindow(QMainWindow): @pyqtSlot() def slot_aboutJuce(self): - JuceAboutW(self, self.host).exec_() + JuceAboutW(self).exec_() @pyqtSlot() def slot_aboutQt(self): diff --git a/source/carla_utils.py b/source/carla_utils.py index 91627336b..0eb5d72e5 100644 --- a/source/carla_utils.py +++ b/source/carla_utils.py @@ -88,11 +88,72 @@ def getPluginTypeFromString(stype): return PLUGIN_NONE # ------------------------------------------------------------------------------------------------------------ -# Carla Pipe stuff +# Carla Utils API (C stuff) CarlaPipeClientHandle = c_void_p CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_p) +# Information about an internal Carla plugin. +# @see carla_get_cached_plugin_info() +class CarlaCachedPluginInfo(Structure): + _fields_ = [ + # Plugin category. + ("category", c_enum), + + # Plugin hints. + # @see PluginHints + ("hints", c_uint), + + # Number of audio inputs. + ("audioIns", c_uint32), + + # Number of audio outputs. + ("audioOuts", c_uint32), + + # Number of MIDI inputs. + ("midiIns", c_uint32), + + # Number of MIDI outputs. + ("midiOuts", c_uint32), + + # Number of input parameters. + ("parameterIns", c_uint32), + + # Number of output parameters. + ("parameterOuts", c_uint32), + + # Plugin name. + ("name", c_char_p), + + # Plugin label. + ("label", c_char_p), + + # Plugin author/maker. + ("maker", c_char_p), + + # Plugin copyright/license. + ("copyright", c_char_p) + ] + +# ------------------------------------------------------------------------------------------------------------ +# Carla Utils API (Python compatible stuff) + +# @see CarlaCachedPluginInfo +PyCarlaCachedPluginInfo = { + 'category': PLUGIN_CATEGORY_NONE, + 'hints': 0x0, + 'audioIns': 0, + 'audioOuts': 0, + 'midiIns': 0, + 'midiOuts': 0, + 'parameterIns': 0, + 'parameterOuts': 0, + 'name': "", + 'label': "", + 'maker': "", + 'copyright': "" +} + # ------------------------------------------------------------------------------------------------------------ # Carla Utils object using a DLL @@ -102,14 +163,20 @@ class CarlaUtils(object): self.lib = cdll.LoadLibrary(filename) - self.lib.carla_get_library_filename.argtypes = None - self.lib.carla_get_library_filename.restype = c_char_p + self.lib.carla_get_complete_license_text.argtypes = None + self.lib.carla_get_complete_license_text.restype = c_char_p - self.lib.carla_get_library_folder.argtypes = None - self.lib.carla_get_library_folder.restype = c_char_p + self.lib.carla_get_juce_version.argtypes = None + self.lib.carla_get_juce_version.restype = c_char_p - self.lib.carla_set_locale_C.argtypes = None - self.lib.carla_set_locale_C.restype = None + self.lib.carla_get_supported_file_extensions.argtypes = None + self.lib.carla_get_supported_file_extensions.restype = c_char_p + + self.lib.carla_get_cached_plugin_count.argtypes = [c_enum, c_char_p] + self.lib.carla_get_cached_plugin_count.restype = c_uint + + self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint] + self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo) self.lib.carla_set_process_name.argtypes = [c_char_p] self.lib.carla_set_process_name.restype = None @@ -149,14 +216,30 @@ class CarlaUtils(object): # -------------------------------------------------------------------------------------------------------- - def get_library_filename(self): - return charPtrToString(self.lib.carla_get_library_filename()) - - def get_library_folder(self): - return charPtrToString(self.lib.carla_get_library_folder()) - - def set_locale_C(self): - self.lib.carla_set_locale_C() + # Get the complete license text of used third-party code and features. + # Returned string is in basic html format. + def get_complete_license_text(self): + return charPtrToString(self.lib.carla_get_complete_license_text()) + + # Get the juce version used in the current Carla build. + def get_juce_version(self): + return charPtrToString(self.lib.carla_get_juce_version()) + + # Get all the supported file extensions in carla_load_file(). + # Returned string uses this syntax: + # @code + # "*.ext1;*.ext2;*.ext3" + # @endcode + def get_supported_file_extensions(self): + return charPtrToString(self.lib.carla_get_supported_file_extensions()) + + # Get how many internal plugins are available. + def get_cached_plugin_count(self, ptype, pluginPath): + return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) + + # Get information about a cached plugin. + def get_cached_plugin_info(self, ptype, index): + return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents) def set_process_name(self, name): self.lib.carla_set_process_name(name.encode("utf-8")) diff --git a/source/carla_widgets.py b/source/carla_widgets.py index ce9b0c787..4061bf6bc 100755 --- a/source/carla_widgets.py +++ b/source/carla_widgets.py @@ -87,7 +87,7 @@ class CarlaAboutW(QDialog): elif host.isPlugin: self.ui.tabWidget.removeTab(2) - self.ui.l_extended.setText(host.get_complete_license_text()) + self.ui.l_extended.setText(gCarla.utils.get_complete_license_text()) if host.is_engine_running() and not (host.isControl or host.isPlugin): self.ui.le_osc_url_tcp.setText(host.get_host_osc_url_tcp()) @@ -172,16 +172,12 @@ class CarlaAboutW(QDialog): # JUCE About dialog class JuceAboutW(QDialog): - def __init__(self, parent, host): + def __init__(self, parent): QDialog.__init__(self, parent) self.ui = ui_carla_about_juce.Ui_JuceAboutW() self.ui.setupUi(self) - if False: - # kdevelop likes this :) - host = CarlaHostMeta() - - self.ui.l_text2.setText(self.tr("This program uses JUCE version %s." % host.get_juce_version())) + self.ui.l_text2.setText(self.tr("This program uses JUCE version %s." % gCarla.utils.get_juce_version())) self.adjustSize() self.setFixedSize(self.size()) diff --git a/source/plugin/carla-base.cpp b/source/plugin/carla-base.cpp index 313aee79d..5d28f5900 100644 --- a/source/plugin/carla-base.cpp +++ b/source/plugin/carla-base.cpp @@ -33,6 +33,14 @@ using CarlaBackend::CarlaPlugin; +// ----------------------------------------------------------------------- + +CARLA_EXTERN_C +std::size_t carla_getNativePluginCount(); + +CARLA_EXTERN_C +const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index); + // ----------------------------------------------------------------------- // Plugin List @@ -49,9 +57,9 @@ struct PluginListManager { #endif descs() { - for (size_t i=0, count = CarlaPlugin::getNativePluginCount(); i < count; ++i) + for (std::size_t i=0, count = carla_getNativePluginCount(); i < count; ++i) { - const NativePluginDescriptor* const desc(CarlaPlugin::getNativePluginDescriptor(i)); + const NativePluginDescriptor* const desc(carla_getNativePluginDescriptor(i)); // Open/Save not possible in plugins if (desc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) diff --git a/source/utils/CarlaBackendUtils.hpp b/source/utils/CarlaBackendUtils.hpp index b31659a67..8783aa421 100644 --- a/source/utils/CarlaBackendUtils.hpp +++ b/source/utils/CarlaBackendUtils.hpp @@ -19,7 +19,6 @@ #define CARLA_BACKEND_UTILS_HPP_INCLUDED #include "CarlaBackend.h" -#include "CarlaHost.h" #include "CarlaString.hpp" CARLA_BACKEND_START_NAMESPACE diff --git a/source/widgets/racklistwidget.py b/source/widgets/racklistwidget.py index d32330a4e..5e4b28673 100644 --- a/source/widgets/racklistwidget.py +++ b/source/widgets/racklistwidget.py @@ -134,7 +134,16 @@ class RackListWidget(QListWidget): host = CarlaHostMeta() self.host = host - self.fSupportedExtensions = [] + exts = gCarla.utils.get_supported_file_extensions().split(";") + + exts.append(".dll") + + if MACOS: + exts.append(".dylib") + if not WINDOWS: + exts.append(".so") + + self.fSupportedExtensions = tuple(i.replace("*","") for i in exts) self.fWasLastDragValid = False self.setMinimumWidth(640) @@ -162,17 +171,6 @@ class RackListWidget(QListWidget): def setHost(self, host): self.host = host - exts = host.get_supported_file_extensions().split(";") - - exts.append(".dll") - - if MACOS: - exts.append(".dylib") - if not WINDOWS: - exts.append(".so") - - self.fSupportedExtensions = tuple(i.replace("*","") for i in exts) - # -------------------------------------------------------------------------------------------------------- def isDragUrlValid(self, url):