| @@ -142,82 +142,6 @@ typedef struct _CarlaPluginInfo { | |||||
| } 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. | * Port count information, used for Audio and MIDI ports and parameters. | ||||
| * @see carla_get_audio_port_count_info() | * @see carla_get_audio_port_count_info() | ||||
| @@ -347,26 +271,6 @@ typedef struct _CarlaTransportInfo { | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Carla Host API (C functions) */ | * 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. | * 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); | 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 | #ifdef __cplusplus | ||||
| /*! | /*! | ||||
| * Get the currently used engine, maybe be NULL. | * 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(); | 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(); | 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(); | CARLA_EXPORT const char* carla_get_library_folder(); | ||||
| @@ -16,19 +16,8 @@ | |||||
| */ | */ | ||||
| #include "CarlaHost.h" | #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; | namespace CB = CarlaBackend; | ||||
| @@ -72,20 +61,6 @@ _CarlaPluginInfo::~_CarlaPluginInfo() noexcept | |||||
| delete[] copyright; | 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 | _CarlaParameterInfo::_CarlaParameterInfo() noexcept | ||||
| : name(gNullCharPtr), | : name(gNullCharPtr), | ||||
| symbol(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 = | |||||
| "<p>This current Carla build is using the following features and 3rd-party code:</p>" | |||||
| "<ul>" | |||||
| // Plugin formats | |||||
| "<li>LADSPA plugin support</li>" | |||||
| "<li>DSSI plugin support</li>" | |||||
| "<li>LV2 plugin support</li>" | |||||
| #ifdef VESTIGE_HEADER | |||||
| "<li>VST2 plugin support using VeSTige header by Javier Serrano Polo</li>" | |||||
| #else | |||||
| "<li>VST2 plugin support using official VST SDK 2.4 [1]</li>" | |||||
| #endif | |||||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
| "<li>VST3 plugin support using official VST SDK 3.6 [1]</li>" | |||||
| #endif | |||||
| #ifdef CARLA_OS_MAC | |||||
| "<li>AU plugin support</li>" | |||||
| #endif | |||||
| // Sample kit libraries | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "<li>FluidSynth library for SF2 support</li>" | |||||
| #endif | |||||
| #ifdef HAVE_LINUXSAMPLER | |||||
| "<li>LinuxSampler library for GIG and SFZ support [2]</li>" | |||||
| #endif | |||||
| // Internal plugins | |||||
| "<li>NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen</li>" | |||||
| #ifdef WANT_ZYNADDSUBFX | |||||
| "<li>ZynAddSubFX plugin code</li>" | |||||
| #endif | |||||
| // misc libs | |||||
| "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</li>" | |||||
| #ifdef CARLA_OS_MAC | |||||
| "<li>sem_timedwait for Mac OS by Keith Shortridge</li>" | |||||
| #endif | |||||
| "<li>liblo library for OSC support</li>" | |||||
| "<li>rtmempool library by Nedko Arnaudov" | |||||
| "<li>serd, sord, sratom and lilv libraries for LV2 discovery</li>" | |||||
| #if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||||
| "<li>RtAudio and RtMidi libraries for extra Audio and MIDI support</li>" | |||||
| #endif | |||||
| // end | |||||
| "</ul>" | |||||
| "<p>" | |||||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) || ! defined(VESTIGE_HEADER) | |||||
| // Required by VST SDK | |||||
| " [1] Trademark of Steinberg Media Technologies GmbH.<br/>" | |||||
| #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 | |||||
| "</p>" | |||||
| ; | |||||
| } | |||||
| 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<uint>(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<uint>(gCachedAuPluginResults.size()); | |||||
| initiated = true; | |||||
| AudioUnitPluginFormat auFormat; | |||||
| gCachedAuPluginResults = auFormat.searchPathsForPlugins(juce::FileSearchPath(), false); | |||||
| return static_cast<uint>(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<CB::PluginCategory>(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<LilvNodes*>(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<LilvNodes*>(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<count; ++i) | |||||
| { | |||||
| Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i)); | |||||
| bool isInput; | |||||
| /**/ if (lilvPort.is_a(lv2World.port_input)) | |||||
| isInput = true; | |||||
| else if (lilvPort.is_a(lv2World.port_output)) | |||||
| isInput = false; | |||||
| else | |||||
| continue; | |||||
| /**/ if (lilvPort.is_a(lv2World.port_control)) | |||||
| { | |||||
| // skip some control ports | |||||
| if (lilvPort.has_property(lv2World.reportsLatency)) | |||||
| continue; | |||||
| if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me)) | |||||
| { | |||||
| bool skip = false; | |||||
| if (const char* const designation = lilv_node_as_string(designationNode)) | |||||
| { | |||||
| /**/ if (std::strcmp(designation, LV2_CORE__control) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_CORE__latency) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__bar) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__barBeat) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beat) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__frame) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__speed) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0) | |||||
| skip = true; | |||||
| } | |||||
| lilv_node_free(designationNode); | |||||
| if (skip) | |||||
| continue; | |||||
| } | |||||
| if (isInput) | |||||
| ++(info.parameterIns); | |||||
| else | |||||
| ++(info.parameterOuts); | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_audio)) | |||||
| { | |||||
| if (isInput) | |||||
| ++(info.audioIns); | |||||
| else | |||||
| ++(info.audioOuts); | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_cv)) | |||||
| { | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_atom)) | |||||
| { | |||||
| Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports)); | |||||
| for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it)) | |||||
| { | |||||
| 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); | |||||
| else | |||||
| ++(info.midiOuts); | |||||
| } | |||||
| } | |||||
| lilv_nodes_free(const_cast<LilvNodes*>(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<LilvNodes*>(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<int>(index)); | |||||
| CARLA_SAFE_ASSERT_BREAK(indexi < gCachedAuPluginResults.size()); | |||||
| using namespace juce; | |||||
| String pluginId(gCachedAuPluginResults[indexi]); | |||||
| OwnedArray<PluginDescription> 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<uint32_t>(desc->numInputChannels); | |||||
| info.audioOuts = static_cast<uint32_t>(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() | const char* carla_get_library_filename() | ||||
| { | { | ||||
| carla_debug("carla_get_library_filename()"); | carla_debug("carla_get_library_filename()"); | ||||
| @@ -889,9 +889,6 @@ public: | |||||
| const int64_t uniqueId; | 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* newNative(const Initializer& init); | ||||
| static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeBinary); | static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeBinary); | ||||
| @@ -17,48 +17,779 @@ | |||||
| #include "CarlaUtils.h" | #include "CarlaUtils.h" | ||||
| #include "CarlaNative.h" | |||||
| #include "CarlaBackendUtils.hpp" | |||||
| #include "CarlaLv2Utils.hpp" | |||||
| #include "CarlaPipeUtils.hpp" | #include "CarlaPipeUtils.hpp" | ||||
| #include "CarlaThread.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<NativePluginHints>(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<NativePluginSupports>(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<NativePluginHints>(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<NativePluginSupports>(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<NativePluginHints>(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<NativePluginSupports>(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<NativePluginHints>(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<NativePluginSupports>(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<NativePluginHints>(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<NativePluginSupports>(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<const NativePluginDescriptor*> 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 = | |||||
| "<p>This current Carla build is using the following features and 3rd-party code:</p>" | |||||
| "<ul>" | |||||
| // Plugin formats | |||||
| "<li>LADSPA plugin support</li>" | |||||
| "<li>DSSI plugin support</li>" | |||||
| "<li>LV2 plugin support</li>" | |||||
| #ifdef VESTIGE_HEADER | |||||
| "<li>VST2 plugin support using VeSTige header by Javier Serrano Polo</li>" | |||||
| #else | |||||
| "<li>VST2 plugin support using official VST SDK 2.4 [1]</li>" | |||||
| #endif | |||||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
| "<li>VST3 plugin support using official VST SDK 3.6 [1]</li>" | |||||
| #endif | |||||
| #ifdef CARLA_OS_MAC | |||||
| "<li>AU plugin support</li>" | |||||
| #endif | |||||
| // Sample kit libraries | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "<li>FluidSynth library for SF2 support</li>" | |||||
| #endif | |||||
| #ifdef HAVE_LINUXSAMPLER | |||||
| "<li>LinuxSampler library for GIG and SFZ support [2]</li>" | |||||
| #endif | |||||
| // Internal plugins | |||||
| "<li>NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen</li>" | |||||
| #ifdef WANT_ZYNADDSUBFX | |||||
| "<li>ZynAddSubFX plugin code</li>" | |||||
| #endif | |||||
| // misc libs | |||||
| "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</li>" | |||||
| #ifdef CARLA_OS_MAC | |||||
| "<li>sem_timedwait for Mac OS by Keith Shortridge</li>" | |||||
| #endif | |||||
| "<li>liblo library for OSC support</li>" | |||||
| "<li>rtmempool library by Nedko Arnaudov" | |||||
| "<li>serd, sord, sratom and lilv libraries for LV2 discovery</li>" | |||||
| #if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||||
| "<li>RtAudio and RtMidi libraries for extra Audio and MIDI support</li>" | |||||
| #endif | |||||
| // end | |||||
| "</ul>" | |||||
| "<p>" | |||||
| #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) || ! defined(VESTIGE_HEADER) | |||||
| // Required by VST SDK | |||||
| " [1] Trademark of Steinberg Media Technologies GmbH.<br/>" | |||||
| #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 | |||||
| "</p>" | |||||
| ; | |||||
| } | } | ||||
| 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<uint>(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<uint>(gCachedAuPluginResults.size()); | |||||
| using namespace juce; | |||||
| initiated = true; | |||||
| AudioUnitPluginFormat auFormat; | |||||
| gCachedAuPluginResults = auFormat.searchPathsForPlugins(juce::FileSearchPath(), false); | |||||
| return static_cast<uint>(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<CB::PluginCategory>(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<LilvNodes*>(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<LilvNodes*>(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<count; ++i) | |||||
| { | |||||
| Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i)); | |||||
| bool isInput; | |||||
| /**/ if (lilvPort.is_a(lv2World.port_input)) | |||||
| isInput = true; | |||||
| else if (lilvPort.is_a(lv2World.port_output)) | |||||
| isInput = false; | |||||
| else | |||||
| continue; | |||||
| /**/ if (lilvPort.is_a(lv2World.port_control)) | |||||
| { | |||||
| // skip some control ports | |||||
| if (lilvPort.has_property(lv2World.reportsLatency)) | |||||
| continue; | |||||
| if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me)) | |||||
| { | |||||
| bool skip = false; | |||||
| if (const char* const designation = lilv_node_as_string(designationNode)) | |||||
| { | |||||
| /**/ if (std::strcmp(designation, LV2_CORE__control) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_CORE__latency) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__bar) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__barBeat) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beat) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__frame) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_TIME__speed) == 0) | |||||
| skip = true; | |||||
| else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0) | |||||
| skip = true; | |||||
| } | |||||
| lilv_node_free(designationNode); | |||||
| if (skip) | |||||
| continue; | |||||
| } | |||||
| if (isInput) | |||||
| ++(info.parameterIns); | |||||
| else | |||||
| ++(info.parameterOuts); | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_audio)) | |||||
| { | |||||
| if (isInput) | |||||
| ++(info.audioIns); | |||||
| else | |||||
| ++(info.audioOuts); | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_cv)) | |||||
| { | |||||
| } | |||||
| else if (lilvPort.is_a(lv2World.port_atom)) | |||||
| { | |||||
| Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports)); | |||||
| for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it)) | |||||
| { | |||||
| 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); | |||||
| else | |||||
| ++(info.midiOuts); | |||||
| } | |||||
| } | |||||
| lilv_nodes_free(const_cast<LilvNodes*>(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<LilvNodes*>(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<int>(index)); | |||||
| CARLA_SAFE_ASSERT_BREAK(indexi < gCachedAuPluginResults.size()); | |||||
| using namespace juce; | |||||
| String pluginId(gCachedAuPluginResults[indexi]); | |||||
| OwnedArray<PluginDescription> 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<uint32_t>(desc->numInputChannels); | |||||
| info.audioOuts = static_cast<uint32_t>(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" | #include "CarlaPipeUtils.cpp" | ||||
| // ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -18,7 +18,12 @@ | |||||
| #ifndef CARLA_UTILS_H_INCLUDED | #ifndef CARLA_UTILS_H_INCLUDED | ||||
| #define 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 | * @defgroup CarlaUtilsAPI Carla Utils API | ||||
| @@ -40,25 +45,127 @@ typedef void* CarlaPipeClientHandle; | |||||
| typedef void (*CarlaPipeCallbackFunc)(void* ptr, const char* msg); | 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); | CARLA_EXPORT void carla_set_process_name(const char* name); | ||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * pipes */ | |||||
| /*! | /*! | ||||
| * TODO. | * 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); | 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 */ | #endif /* CARLA_UTILS_H_INCLUDED */ | ||||
| @@ -45,7 +45,11 @@ STANDALONE_LIBS += $(MODULEDIR)/rtaudio.a | |||||
| STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a | STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a | ||||
| endif | 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 | STANDALONE_LINK_FLAGS += -lmagic | ||||
| endif | 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) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -31,6 +31,7 @@ | |||||
| #include "CarlaStateUtils.hpp" | #include "CarlaStateUtils.hpp" | ||||
| #include "CarlaExternalUI.hpp" | #include "CarlaExternalUI.hpp" | ||||
| #include "CarlaHost.h" | |||||
| #include "CarlaNative.hpp" | #include "CarlaNative.hpp" | ||||
| #include "juce_audio_basics.h" | #include "juce_audio_basics.h" | ||||
| @@ -973,15 +974,6 @@ protected: | |||||
| const CarlaMutexLocker cml(fUiServer.getPipeLock()); | 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"); | fUiServer.writeAndFixMessage("max-plugin-number"); | ||||
| std::sprintf(fTmpBuf, "%i\n", pData->maxPluginNumber); | std::sprintf(fTmpBuf, "%i\n", pData->maxPluginNumber); | ||||
| fUiServer.writeMessage(fTmpBuf); | fUiServer.writeMessage(fTmpBuf); | ||||
| @@ -26,7 +26,15 @@ | |||||
| using juce::String; | using juce::String; | ||||
| using juce::StringArray; | 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<const NativePluginDescriptor*> gPluginDescriptors; | static LinkedList<const NativePluginDescriptor*> gPluginDescriptors; | ||||
| @@ -35,6 +43,16 @@ void carla_register_native_plugin(const NativePluginDescriptor* desc) | |||||
| gPluginDescriptors.append(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 | CARLA_BACKEND_START_NAMESPACE | ||||
| @@ -123,7 +141,7 @@ struct ScopedInitializer { | |||||
| carla_register_all_plugins(); | carla_register_all_plugins(); | ||||
| } | } | ||||
| ~ScopedInitializer() | |||||
| ~ScopedInitializer() noexcept | |||||
| { | { | ||||
| gPluginDescriptors.clear(); | gPluginDescriptors.clear(); | ||||
| } | } | ||||
| @@ -2201,20 +2219,6 @@ protected: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| public: | 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 | void* getNativeHandle() const noexcept override | ||||
| { | { | ||||
| return fHandle; | 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) | 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); | carla_debug("CarlaPlugin::newNative({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.label, init.uniqueId); | ||||
| @@ -1060,48 +1060,6 @@ class CarlaPluginInfo(Structure): | |||||
| ("uniqueId", c_int64) | ("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. | # Port count information, used for Audio and MIDI ports and parameters. | ||||
| # @see carla_get_audio_port_count_info() | # @see carla_get_audio_port_count_info() | ||||
| # @see carla_get_midi_port_count_info() | # @see carla_get_midi_port_count_info() | ||||
| @@ -1186,22 +1144,6 @@ PyCarlaPluginInfo = { | |||||
| 'uniqueId': 0 | '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 | # @see CarlaPortCountInfo | ||||
| PyCarlaPortCountInfo = { | PyCarlaPortCountInfo = { | ||||
| 'ins': 0, | 'ins': 0, | ||||
| @@ -1299,26 +1241,6 @@ class CarlaHostMeta(object): | |||||
| keyrm = "%s=" % key | keyrm = "%s=" % key | ||||
| self.msvcrt._putenv(keyrm.encode("utf-8")) | 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. | # Get how many engine drivers are available. | ||||
| @abstractmethod | @abstractmethod | ||||
| def get_engine_driver_count(self): | def get_engine_driver_count(self): | ||||
| @@ -1343,16 +1265,6 @@ class CarlaHostMeta(object): | |||||
| def get_engine_driver_device_info(self, index, name): | def get_engine_driver_device_info(self, index, name): | ||||
| raise NotImplementedError | 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. | # Initialize the engine. | ||||
| # Make sure to call carla_engine_idle() at regular intervals afterwards. | # Make sure to call carla_engine_idle() at regular intervals afterwards. | ||||
| # @param driverName Driver to use | # @param driverName Driver to use | ||||
| @@ -1925,53 +1837,6 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| self.fEngineCallback = None | self.fEngineCallback = None | ||||
| self.fEngineRunning = False | self.fEngineRunning = False | ||||
| def get_complete_license_text(self): | |||||
| text = ( | |||||
| "<p>This current Carla build is using the following features and 3rd-party code:</p>" | |||||
| "<ul>" | |||||
| # Plugin formats | |||||
| "<li>LADSPA plugin support</li>" | |||||
| "<li>DSSI plugin support</li>" | |||||
| "<li>LV2 plugin support</li>" | |||||
| "<li>VST2 plugin support using official VST SDK 2.4 [1]</li>" | |||||
| "<li>VST3 plugin support using official VST SDK 3.6 [1]</li>" | |||||
| "<li>AU plugin support</li>" | |||||
| # Sample kit libraries | |||||
| "<li>FluidSynth library for SF2 support</li>" | |||||
| "<li>LinuxSampler library for GIG and SFZ support [2]</li>" | |||||
| # Internal plugins | |||||
| "<li>NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen</li>" | |||||
| "<li>ZynAddSubFX plugin code</li>" | |||||
| # misc libs | |||||
| "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</li>" | |||||
| "<li>sem_timedwait for Mac OS by Keith Shortridge</li>" | |||||
| "<li>liblo library for OSC support</li>" | |||||
| "<li>rtmempool library by Nedko Arnaudov" | |||||
| "<li>serd, sord, sratom and lilv libraries for LV2 discovery</li>" | |||||
| "<li>RtAudio and RtMidi libraries for extra Audio and MIDI support</li>" | |||||
| # end | |||||
| "</ul>" | |||||
| "<p>" | |||||
| # Required by VST SDK | |||||
| " [1] Trademark of Steinberg Media Technologies GmbH.<br/>" | |||||
| # LinuxSampler GPL exception | |||||
| " [2] Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors." | |||||
| "</p>" | |||||
| ) | |||||
| 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): | def get_engine_driver_count(self): | ||||
| return 0 | return 0 | ||||
| @@ -1984,12 +1849,6 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| def get_engine_driver_device_info(self, index, name): | def get_engine_driver_device_info(self, index, name): | ||||
| return PyEngineDriverDeviceInfo | 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): | def engine_init(self, driverName, clientName): | ||||
| self.fEngineRunning = True | self.fEngineRunning = True | ||||
| if self.fEngineCallback is not None: | if self.fEngineCallback is not None: | ||||
| @@ -2251,15 +2110,6 @@ class CarlaHostDLL(CarlaHostMeta): | |||||
| self.lib = cdll.LoadLibrary(libName) | 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.argtypes = None | ||||
| self.lib.carla_get_engine_driver_count.restype = c_uint | 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.argtypes = [c_uint, c_char_p] | ||||
| self.lib.carla_get_engine_driver_device_info.restype = POINTER(EngineDriverDeviceInfo) | 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.argtypes = [c_char_p, c_char_p] | ||||
| self.lib.carla_engine_init.restype = c_bool | 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): | def get_engine_driver_count(self): | ||||
| return int(self.lib.carla_get_engine_driver_count()) | 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): | 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) | 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): | def engine_init(self, driverName, clientName): | ||||
| return bool(self.lib.carla_engine_init(driverName.encode("utf-8"), clientName.encode("utf-8"))) | 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 | self.processModeForced = True | ||||
| # text data to return when requested | # text data to return when requested | ||||
| self.fCompleteLicenseText = "" | |||||
| self.fJuceVersion = "" | |||||
| self.fSupportedFileExts = "" | |||||
| self.fMaxPluginNumber = 0 | |||||
| self.fLastError = "" | |||||
| self.fMaxPluginNumber = 0 | |||||
| self.fLastError = "" | |||||
| # plugin info | # plugin info | ||||
| self.fPluginsInfo = [] | 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): | def get_engine_driver_count(self): | ||||
| return 1 | return 1 | ||||
| @@ -2897,12 +2714,6 @@ class CarlaHostPlugin(CarlaHostMeta): | |||||
| def get_engine_driver_device_info(self, index, name): | def get_engine_driver_device_info(self, index, name): | ||||
| return PyEngineDriverDeviceInfo | 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): | def set_engine_callback(self, func): | ||||
| return # TODO | 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): | def _set_transport(self, playing, frame, bar, beat, tick, bpm): | ||||
| self.fTransportInfo = { | self.fTransportInfo = { | ||||
| "playing": playing, | "playing": playing, | ||||
| @@ -1482,9 +1482,9 @@ class PluginDatabaseW(QDialog): | |||||
| AU_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_AU, CARLA_DEFAULT_AU_PATH))) | AU_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_AU, CARLA_DEFAULT_AU_PATH))) | ||||
| del settings | 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 | if internalCountNew != internalCount or (len(internalPlugins) > 0 and | ||||
| len(internalPlugins[0]) > 0 and | len(internalPlugins[0]) > 0 and | ||||
| @@ -1492,7 +1492,7 @@ class PluginDatabaseW(QDialog): | |||||
| internalPlugins = [] | internalPlugins = [] | ||||
| for i in range(internalCountNew): | 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) | plugins = checkPluginCached(descInfo, PLUGIN_INTERNAL) | ||||
| if plugins: | if plugins: | ||||
| @@ -1506,7 +1506,7 @@ class PluginDatabaseW(QDialog): | |||||
| lv2Plugins = [] | lv2Plugins = [] | ||||
| for i in range(lv2CountNew): | 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) | plugins = checkPluginCached(descInfo, PLUGIN_LV2) | ||||
| if plugins: | if plugins: | ||||
| @@ -1520,7 +1520,7 @@ class PluginDatabaseW(QDialog): | |||||
| auPlugins = [] | auPlugins = [] | ||||
| for i in range(auCountNew): | 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) | plugins = checkPluginCached(descInfo, PLUGIN_AU) | ||||
| if plugins: | if plugins: | ||||
| @@ -207,7 +207,7 @@ class HostWindow(QMainWindow): | |||||
| self.fDirModel = QFileSystemModel(self) | self.fDirModel = QFileSystemModel(self) | ||||
| self.fDirModel.setRootPath(HOME) | 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.setModel(self.fDirModel) | ||||
| self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME)) | self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME)) | ||||
| @@ -1328,7 +1328,7 @@ class HostWindow(QMainWindow): | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_aboutJuce(self): | def slot_aboutJuce(self): | ||||
| JuceAboutW(self, self.host).exec_() | |||||
| JuceAboutW(self).exec_() | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_aboutQt(self): | def slot_aboutQt(self): | ||||
| @@ -88,11 +88,72 @@ def getPluginTypeFromString(stype): | |||||
| return PLUGIN_NONE | return PLUGIN_NONE | ||||
| # ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
| # Carla Pipe stuff | |||||
| # Carla Utils API (C stuff) | |||||
| CarlaPipeClientHandle = c_void_p | CarlaPipeClientHandle = c_void_p | ||||
| CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_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 | # Carla Utils object using a DLL | ||||
| @@ -102,14 +163,20 @@ class CarlaUtils(object): | |||||
| self.lib = cdll.LoadLibrary(filename) | 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.argtypes = [c_char_p] | ||||
| self.lib.carla_set_process_name.restype = None | 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): | def set_process_name(self, name): | ||||
| self.lib.carla_set_process_name(name.encode("utf-8")) | self.lib.carla_set_process_name(name.encode("utf-8")) | ||||
| @@ -87,7 +87,7 @@ class CarlaAboutW(QDialog): | |||||
| elif host.isPlugin: | elif host.isPlugin: | ||||
| self.ui.tabWidget.removeTab(2) | 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): | 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()) | self.ui.le_osc_url_tcp.setText(host.get_host_osc_url_tcp()) | ||||
| @@ -172,16 +172,12 @@ class CarlaAboutW(QDialog): | |||||
| # JUCE About dialog | # JUCE About dialog | ||||
| class JuceAboutW(QDialog): | class JuceAboutW(QDialog): | ||||
| def __init__(self, parent, host): | |||||
| def __init__(self, parent): | |||||
| QDialog.__init__(self, parent) | QDialog.__init__(self, parent) | ||||
| self.ui = ui_carla_about_juce.Ui_JuceAboutW() | self.ui = ui_carla_about_juce.Ui_JuceAboutW() | ||||
| self.ui.setupUi(self) | 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.adjustSize() | ||||
| self.setFixedSize(self.size()) | self.setFixedSize(self.size()) | ||||
| @@ -33,6 +33,14 @@ | |||||
| using CarlaBackend::CarlaPlugin; | 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 | // Plugin List | ||||
| @@ -49,9 +57,9 @@ struct PluginListManager { | |||||
| #endif | #endif | ||||
| descs() | 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 | // Open/Save not possible in plugins | ||||
| if (desc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | if (desc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | ||||
| @@ -19,7 +19,6 @@ | |||||
| #define CARLA_BACKEND_UTILS_HPP_INCLUDED | #define CARLA_BACKEND_UTILS_HPP_INCLUDED | ||||
| #include "CarlaBackend.h" | #include "CarlaBackend.h" | ||||
| #include "CarlaHost.h" | |||||
| #include "CarlaString.hpp" | #include "CarlaString.hpp" | ||||
| CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
| @@ -134,7 +134,16 @@ class RackListWidget(QListWidget): | |||||
| host = CarlaHostMeta() | host = CarlaHostMeta() | ||||
| self.host = host | 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.fWasLastDragValid = False | ||||
| self.setMinimumWidth(640) | self.setMinimumWidth(640) | ||||
| @@ -162,17 +171,6 @@ class RackListWidget(QListWidget): | |||||
| def setHost(self, host): | def setHost(self, host): | ||||
| self.host = 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): | def isDragUrlValid(self, url): | ||||