| @@ -142,82 +142,6 @@ typedef struct _CarlaPluginInfo { | |||
| } CarlaPluginInfo; | |||
| /*! | |||
| * Information about a cached plugin. | |||
| * @see carla_get_cached_plugin_info() | |||
| */ | |||
| typedef struct _CarlaCachedPluginInfo { | |||
| /*! | |||
| * Plugin category. | |||
| */ | |||
| PluginCategory category; | |||
| /*! | |||
| * Plugin hints. | |||
| * @see PluginHints | |||
| */ | |||
| uint hints; | |||
| /*! | |||
| * Number of audio inputs. | |||
| */ | |||
| uint32_t audioIns; | |||
| /*! | |||
| * Number of audio outputs. | |||
| */ | |||
| uint32_t audioOuts; | |||
| /*! | |||
| * Number of MIDI inputs. | |||
| */ | |||
| uint32_t midiIns; | |||
| /*! | |||
| * Number of MIDI outputs. | |||
| */ | |||
| uint32_t midiOuts; | |||
| /*! | |||
| * Number of input parameters. | |||
| */ | |||
| uint32_t parameterIns; | |||
| /*! | |||
| * Number of output parameters. | |||
| */ | |||
| uint32_t parameterOuts; | |||
| /*! | |||
| * Plugin name. | |||
| */ | |||
| const char* name; | |||
| /*! | |||
| * Plugin label. | |||
| */ | |||
| const char* label; | |||
| /*! | |||
| * Plugin author/maker. | |||
| */ | |||
| const char* maker; | |||
| /*! | |||
| * Plugin copyright/license. | |||
| */ | |||
| const char* copyright; | |||
| #ifdef __cplusplus | |||
| /*! | |||
| * C++ constructor. | |||
| */ | |||
| CARLA_API _CarlaCachedPluginInfo() noexcept; | |||
| CARLA_DECLARE_NON_COPY_STRUCT(_CarlaCachedPluginInfo) | |||
| #endif | |||
| } CarlaCachedPluginInfo; | |||
| /*! | |||
| * Port count information, used for Audio and MIDI ports and parameters. | |||
| * @see carla_get_audio_port_count_info() | |||
| @@ -347,26 +271,6 @@ typedef struct _CarlaTransportInfo { | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * Carla Host API (C functions) */ | |||
| /*! | |||
| * Get the complete license text of used third-party code and features. | |||
| * Returned string is in basic html format. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_complete_license_text(); | |||
| /*! | |||
| * Get the juce version used in the current Carla build. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_juce_version(); | |||
| /*! | |||
| * Get all the supported file extensions in carla_load_file(). | |||
| * Returned string uses this syntax: | |||
| * @code | |||
| * "*.ext1;*.ext2;*.ext3" | |||
| * @endcode | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_supported_file_extensions(); | |||
| /*! | |||
| * Get how many engine drivers are available. | |||
| */ | |||
| @@ -391,18 +295,6 @@ CARLA_EXPORT const char* const* carla_get_engine_driver_device_names(uint index) | |||
| */ | |||
| CARLA_EXPORT const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name); | |||
| /*! | |||
| * Get how many cached plugins are available. | |||
| * Internal, LV2 and AU plugin formats are cached and need to be discovered via this function. | |||
| * Do not call this for any other plugin formats. | |||
| */ | |||
| CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); | |||
| /*! | |||
| * Get information about a cached plugin. | |||
| */ | |||
| CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index); | |||
| #ifdef __cplusplus | |||
| /*! | |||
| * Get the currently used engine, maybe be NULL. | |||
| @@ -995,12 +887,12 @@ CARLA_EXPORT const char* carla_get_host_osc_url_tcp(); | |||
| CARLA_EXPORT const char* carla_get_host_osc_url_udp(); | |||
| /*! | |||
| * Get the current carla library filename. | |||
| * Get the absolute filename of this carla library. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_filename(); | |||
| /*! | |||
| * Get the folder where the current use carla library resides. | |||
| * Get the folder where this carla library resides. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_folder(); | |||
| @@ -16,19 +16,8 @@ | |||
| */ | |||
| #include "CarlaHost.h" | |||
| #include "CarlaNative.h" | |||
| #include "CarlaLv2Utils.hpp" | |||
| #include "CarlaPlugin.hpp" | |||
| #include "CarlaString.hpp" | |||
| #include "juce_audio_formats.h" | |||
| #ifdef CARLA_OS_MAC | |||
| # include "juce_audio_processors.h" | |||
| using juce::AudioUnitPluginFormat; | |||
| using juce::StringArray; | |||
| #endif | |||
| #include "juce_core.h" | |||
| namespace CB = CarlaBackend; | |||
| @@ -72,20 +61,6 @@ _CarlaPluginInfo::~_CarlaPluginInfo() noexcept | |||
| delete[] copyright; | |||
| } | |||
| _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept | |||
| : category(CB::PLUGIN_CATEGORY_NONE), | |||
| hints(0x0), | |||
| audioIns(0), | |||
| audioOuts(0), | |||
| midiIns(0), | |||
| midiOuts(0), | |||
| parameterIns(0), | |||
| parameterOuts(0), | |||
| name(gNullCharPtr), | |||
| label(gNullCharPtr), | |||
| maker(gNullCharPtr), | |||
| copyright(gNullCharPtr) {} | |||
| _CarlaParameterInfo::_CarlaParameterInfo() noexcept | |||
| : name(gNullCharPtr), | |||
| symbol(gNullCharPtr), | |||
| @@ -122,592 +97,6 @@ _CarlaTransportInfo::_CarlaTransportInfo() noexcept | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| const char* carla_get_complete_license_text() | |||
| { | |||
| carla_debug("carla_get_complete_license_text()"); | |||
| static CarlaString retText; | |||
| if (retText.isEmpty()) | |||
| { | |||
| retText = | |||
| "<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() | |||
| { | |||
| carla_debug("carla_get_library_filename()"); | |||
| @@ -889,9 +889,6 @@ public: | |||
| const int64_t uniqueId; | |||
| }; | |||
| static std::size_t getNativePluginCount() noexcept; | |||
| static const NativePluginDescriptor* getNativePluginDescriptor(const std::size_t index) noexcept; | |||
| static CarlaPlugin* newNative(const Initializer& init); | |||
| static CarlaPlugin* newBridge(const Initializer& init, const BinaryType btype, const PluginType ptype, const char* const bridgeBinary); | |||
| @@ -17,48 +17,779 @@ | |||
| #include "CarlaUtils.h" | |||
| #include "CarlaNative.h" | |||
| #include "CarlaBackendUtils.hpp" | |||
| #include "CarlaLv2Utils.hpp" | |||
| #include "CarlaPipeUtils.hpp" | |||
| #include "CarlaThread.hpp" | |||
| #include "LinkedList.hpp" | |||
| #include "juce_audio_formats.h" | |||
| #ifdef CARLA_OS_MAC | |||
| # include "juce_audio_processors.h" | |||
| #endif | |||
| #include "juce_core.h" | |||
| namespace CB = CarlaBackend; | |||
| static const char* const gNullCharPtr = ""; | |||
| #ifdef CARLA_OS_MAC | |||
| static juce::StringArray gCachedAuPluginResults; | |||
| #endif | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| const char* carla_get_library_filename() | |||
| _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept | |||
| : category(CB::PLUGIN_CATEGORY_NONE), | |||
| hints(0x0), | |||
| audioIns(0), | |||
| audioOuts(0), | |||
| midiIns(0), | |||
| midiOuts(0), | |||
| parameterIns(0), | |||
| parameterOuts(0), | |||
| name(gNullCharPtr), | |||
| label(gNullCharPtr), | |||
| maker(gNullCharPtr), | |||
| copyright(gNullCharPtr) {} | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| static const NativePluginDescriptor carlaRackDesc = { | |||
| /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, | |||
| /* hints */ static_cast<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" | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| @@ -18,7 +18,12 @@ | |||
| #ifndef CARLA_UTILS_H_INCLUDED | |||
| #define CARLA_UTILS_H_INCLUDED | |||
| #include "CarlaDefines.h" | |||
| #include "CarlaBackend.h" | |||
| #ifdef __cplusplus | |||
| using CarlaBackend::PluginCategory; | |||
| using CarlaBackend::PluginType; | |||
| #endif | |||
| /*! | |||
| * @defgroup CarlaUtilsAPI Carla Utils API | |||
| @@ -40,25 +45,127 @@ typedef void* CarlaPipeClientHandle; | |||
| typedef void (*CarlaPipeCallbackFunc)(void* ptr, const char* msg); | |||
| /*! | |||
| * Get the current carla library filename. | |||
| * Information about a cached plugin. | |||
| * @see carla_get_cached_plugin_info() | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_filename(); | |||
| typedef struct _CarlaCachedPluginInfo { | |||
| /*! | |||
| * Plugin category. | |||
| */ | |||
| PluginCategory category; | |||
| /*! | |||
| * Plugin hints. | |||
| * @see PluginHints | |||
| */ | |||
| uint hints; | |||
| /*! | |||
| * Number of audio inputs. | |||
| */ | |||
| uint32_t audioIns; | |||
| /*! | |||
| * Number of audio outputs. | |||
| */ | |||
| uint32_t audioOuts; | |||
| /*! | |||
| * Number of MIDI inputs. | |||
| */ | |||
| uint32_t midiIns; | |||
| /*! | |||
| * Number of MIDI outputs. | |||
| */ | |||
| uint32_t midiOuts; | |||
| /*! | |||
| * Number of input parameters. | |||
| */ | |||
| uint32_t parameterIns; | |||
| /*! | |||
| * Number of output parameters. | |||
| */ | |||
| uint32_t parameterOuts; | |||
| /*! | |||
| * Plugin name. | |||
| */ | |||
| const char* name; | |||
| /*! | |||
| * Plugin label. | |||
| */ | |||
| const char* label; | |||
| /*! | |||
| * Plugin author/maker. | |||
| */ | |||
| const char* maker; | |||
| /*! | |||
| * Plugin copyright/license. | |||
| */ | |||
| const char* copyright; | |||
| #ifdef __cplusplus | |||
| /*! | |||
| * C++ constructor. | |||
| */ | |||
| CARLA_API _CarlaCachedPluginInfo() noexcept; | |||
| CARLA_DECLARE_NON_COPY_STRUCT(_CarlaCachedPluginInfo) | |||
| #endif | |||
| } CarlaCachedPluginInfo; | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * get stuff */ | |||
| /*! | |||
| * Get the folder where the current use carla library resides. | |||
| * Get the complete license text of used third-party code and features. | |||
| * Returned string is in basic html format. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_folder(); | |||
| CARLA_EXPORT const char* carla_get_complete_license_text(); | |||
| /*! | |||
| * TODO. | |||
| * Get the juce version used in the current Carla build. | |||
| */ | |||
| CARLA_EXPORT void carla_set_locale_C(); | |||
| CARLA_EXPORT const char* carla_get_juce_version(); | |||
| /*! | |||
| * Get the juce version used in the current Carla build. | |||
| * Get all the supported file extensions in carla_load_file(). | |||
| * Returned string uses this syntax: | |||
| * @code | |||
| * "*.ext1;*.ext2;*.ext3" | |||
| * @endcode | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_supported_file_extensions(); | |||
| /*! | |||
| * Get how many cached plugins are available. | |||
| * Internal, LV2 and AU plugin formats are cached and need to be discovered via this function. | |||
| * Do not call this for any other plugin formats. | |||
| */ | |||
| CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); | |||
| /*! | |||
| * Get information about a cached plugin. | |||
| */ | |||
| CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index); | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * set stuff */ | |||
| /*! | |||
| * Set the current process name to @a name. | |||
| */ | |||
| CARLA_EXPORT void carla_set_process_name(const char* name); | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * pipes */ | |||
| /*! | |||
| * TODO. | |||
| */ | |||
| @@ -114,6 +221,21 @@ CARLA_EXPORT bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handl | |||
| */ | |||
| CARLA_EXPORT void carla_pipe_client_destroy(CarlaPipeClientHandle handle); | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| * info about current library */ | |||
| /*! | |||
| * Get the absolute filename of this carla library. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_filename(); | |||
| /*! | |||
| * Get the folder where this carla library resides. | |||
| */ | |||
| CARLA_EXPORT const char* carla_get_library_folder(); | |||
| // ------------------------------------------------------------------------------------------------------------------- | |||
| /** @} */ | |||
| #endif /* CARLA_UTILS_H_INCLUDED */ | |||
| @@ -45,7 +45,11 @@ STANDALONE_LIBS += $(MODULEDIR)/rtaudio.a | |||
| STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a | |||
| endif | |||
| UTILS_LIBS = $(MODULEDIR)/juce_core.a | |||
| UTILS_LIBS = $(MODULEDIR)/juce_audio_basics.a | |||
| UTILS_LIBS += $(MODULEDIR)/juce_audio_formats.a | |||
| UTILS_LIBS += $(MODULEDIR)/juce_core.a | |||
| UTILS_LIBS += $(MODULEDIR)/lilv.a | |||
| UTILS_LIBS += $(MODULEDIR)/native-plugins.a | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| @@ -89,10 +93,11 @@ ifeq ($(UNIX),true) | |||
| STANDALONE_LINK_FLAGS += -lmagic | |||
| endif | |||
| UTILS_LINK_FLAGS = $(JUCE_CORE_LIBS) | |||
| ifeq ($(UNIX),true) | |||
| UTILS_LINK_FLAGS += -lpthread | |||
| endif | |||
| UTILS_LINK_FLAGS = $(JUCE_AUDIO_BASICS_LIBS) | |||
| UTILS_LINK_FLAGS += $(JUCE_AUDIO_FORMATS_LIBS) | |||
| UTILS_LINK_FLAGS += $(JUCE_CORE_LIBS) | |||
| UTILS_LINK_FLAGS += $(LILV_LIBS) | |||
| UTILS_LINK_FLAGS += $(NATIVE_PLUGINS_LIBS) | |||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||
| @@ -31,6 +31,7 @@ | |||
| #include "CarlaStateUtils.hpp" | |||
| #include "CarlaExternalUI.hpp" | |||
| #include "CarlaHost.h" | |||
| #include "CarlaNative.hpp" | |||
| #include "juce_audio_basics.h" | |||
| @@ -973,15 +974,6 @@ protected: | |||
| const CarlaMutexLocker cml(fUiServer.getPipeLock()); | |||
| fUiServer.writeAndFixMessage("complete-license"); | |||
| fUiServer.writeAndFixMessage(carla_get_complete_license_text()); | |||
| fUiServer.writeAndFixMessage("juce-version"); | |||
| fUiServer.writeAndFixMessage(carla_get_juce_version()); | |||
| fUiServer.writeAndFixMessage("file-exts"); | |||
| fUiServer.writeAndFixMessage(carla_get_supported_file_extensions()); | |||
| fUiServer.writeAndFixMessage("max-plugin-number"); | |||
| std::sprintf(fTmpBuf, "%i\n", pData->maxPluginNumber); | |||
| fUiServer.writeMessage(fTmpBuf); | |||
| @@ -26,7 +26,15 @@ | |||
| using juce::String; | |||
| using juce::StringArray; | |||
| // ----------------------------------------------------- | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_EXTERN_C | |||
| std::size_t carla_getNativePluginCount(); | |||
| CARLA_EXTERN_C | |||
| const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index); | |||
| // ----------------------------------------------------------------------- | |||
| static LinkedList<const NativePluginDescriptor*> gPluginDescriptors; | |||
| @@ -35,6 +43,16 @@ void carla_register_native_plugin(const NativePluginDescriptor* desc) | |||
| gPluginDescriptors.append(desc); | |||
| } | |||
| std::size_t carla_getNativePluginCount() | |||
| { | |||
| return gPluginDescriptors.count(); | |||
| } | |||
| const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index) | |||
| { | |||
| return gPluginDescriptors.getAt(index, nullptr); | |||
| } | |||
| // ----------------------------------------------------- | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -123,7 +141,7 @@ struct ScopedInitializer { | |||
| carla_register_all_plugins(); | |||
| } | |||
| ~ScopedInitializer() | |||
| ~ScopedInitializer() noexcept | |||
| { | |||
| gPluginDescriptors.clear(); | |||
| } | |||
| @@ -2201,20 +2219,6 @@ protected: | |||
| // ------------------------------------------------------------------- | |||
| public: | |||
| static size_t getPluginCount() noexcept | |||
| { | |||
| return gPluginDescriptors.count(); | |||
| } | |||
| static const NativePluginDescriptor* getPluginDescriptor(const size_t index) noexcept | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(index < gPluginDescriptors.count(), nullptr); | |||
| return gPluginDescriptors.getAt(index, nullptr); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| void* getNativeHandle() const noexcept override | |||
| { | |||
| return fHandle; | |||
| @@ -2435,18 +2439,6 @@ private: | |||
| // ----------------------------------------------------------------------- | |||
| std::size_t CarlaPlugin::getNativePluginCount() noexcept | |||
| { | |||
| return CarlaPluginNative::getPluginCount(); | |||
| } | |||
| const NativePluginDescriptor* CarlaPlugin::getNativePluginDescriptor(const std::size_t index) noexcept | |||
| { | |||
| return CarlaPluginNative::getPluginDescriptor(index); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| CarlaPlugin* CarlaPlugin::newNative(const Initializer& init) | |||
| { | |||
| carla_debug("CarlaPlugin::newNative({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.label, init.uniqueId); | |||
| @@ -1060,48 +1060,6 @@ class CarlaPluginInfo(Structure): | |||
| ("uniqueId", c_int64) | |||
| ] | |||
| # Information about an internal Carla plugin. | |||
| # @see carla_get_cached_plugin_info() | |||
| class CarlaCachedPluginInfo(Structure): | |||
| _fields_ = [ | |||
| # Plugin category. | |||
| ("category", c_enum), | |||
| # Plugin hints. | |||
| # @see PluginHints | |||
| ("hints", c_uint), | |||
| # Number of audio inputs. | |||
| ("audioIns", c_uint32), | |||
| # Number of audio outputs. | |||
| ("audioOuts", c_uint32), | |||
| # Number of MIDI inputs. | |||
| ("midiIns", c_uint32), | |||
| # Number of MIDI outputs. | |||
| ("midiOuts", c_uint32), | |||
| # Number of input parameters. | |||
| ("parameterIns", c_uint32), | |||
| # Number of output parameters. | |||
| ("parameterOuts", c_uint32), | |||
| # Plugin name. | |||
| ("name", c_char_p), | |||
| # Plugin label. | |||
| ("label", c_char_p), | |||
| # Plugin author/maker. | |||
| ("maker", c_char_p), | |||
| # Plugin copyright/license. | |||
| ("copyright", c_char_p) | |||
| ] | |||
| # Port count information, used for Audio and MIDI ports and parameters. | |||
| # @see carla_get_audio_port_count_info() | |||
| # @see carla_get_midi_port_count_info() | |||
| @@ -1186,22 +1144,6 @@ PyCarlaPluginInfo = { | |||
| 'uniqueId': 0 | |||
| } | |||
| # @see CarlaCachedPluginInfo | |||
| PyCarlaCachedPluginInfo = { | |||
| 'category': PLUGIN_CATEGORY_NONE, | |||
| 'hints': 0x0, | |||
| 'audioIns': 0, | |||
| 'audioOuts': 0, | |||
| 'midiIns': 0, | |||
| 'midiOuts': 0, | |||
| 'parameterIns': 0, | |||
| 'parameterOuts': 0, | |||
| 'name': "", | |||
| 'label': "", | |||
| 'maker': "", | |||
| 'copyright': "" | |||
| } | |||
| # @see CarlaPortCountInfo | |||
| PyCarlaPortCountInfo = { | |||
| 'ins': 0, | |||
| @@ -1299,26 +1241,6 @@ class CarlaHostMeta(object): | |||
| keyrm = "%s=" % key | |||
| self.msvcrt._putenv(keyrm.encode("utf-8")) | |||
| # Get the complete license text of used third-party code and features. | |||
| # Returned string is in basic html format. | |||
| @abstractmethod | |||
| def get_complete_license_text(self): | |||
| raise NotImplementedError | |||
| # Get the juce version used in the current Carla build. | |||
| @abstractmethod | |||
| def get_juce_version(self): | |||
| raise NotImplementedError | |||
| # Get all the supported file extensions in carla_load_file(). | |||
| # Returned string uses this syntax: | |||
| # @code | |||
| # "*.ext1;*.ext2;*.ext3" | |||
| # @endcode | |||
| @abstractmethod | |||
| def get_supported_file_extensions(self): | |||
| raise NotImplementedError | |||
| # Get how many engine drivers are available. | |||
| @abstractmethod | |||
| def get_engine_driver_count(self): | |||
| @@ -1343,16 +1265,6 @@ class CarlaHostMeta(object): | |||
| def get_engine_driver_device_info(self, index, name): | |||
| raise NotImplementedError | |||
| # Get how many internal plugins are available. | |||
| @abstractmethod | |||
| def get_cached_plugin_count(self, ptype, pluginPath): | |||
| raise NotImplementedError | |||
| # Get information about a cached plugin. | |||
| @abstractmethod | |||
| def get_cached_plugin_info(self, ptype, index): | |||
| raise NotImplementedError | |||
| # Initialize the engine. | |||
| # Make sure to call carla_engine_idle() at regular intervals afterwards. | |||
| # @param driverName Driver to use | |||
| @@ -1925,53 +1837,6 @@ class CarlaHostNull(CarlaHostMeta): | |||
| self.fEngineCallback = None | |||
| self.fEngineRunning = False | |||
| def get_complete_license_text(self): | |||
| text = ( | |||
| "<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): | |||
| return 0 | |||
| @@ -1984,12 +1849,6 @@ class CarlaHostNull(CarlaHostMeta): | |||
| def get_engine_driver_device_info(self, index, name): | |||
| return PyEngineDriverDeviceInfo | |||
| def get_cached_plugin_count(self, ptype, pluginPath): | |||
| return 0 | |||
| def get_cached_plugin_info(self, ptype, index): | |||
| return PyCarlaCachedPluginInfo | |||
| def engine_init(self, driverName, clientName): | |||
| self.fEngineRunning = True | |||
| if self.fEngineCallback is not None: | |||
| @@ -2251,15 +2110,6 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| self.lib = cdll.LoadLibrary(libName) | |||
| self.lib.carla_get_complete_license_text.argtypes = None | |||
| self.lib.carla_get_complete_license_text.restype = c_char_p | |||
| self.lib.carla_get_juce_version.argtypes = None | |||
| self.lib.carla_get_juce_version.restype = c_char_p | |||
| self.lib.carla_get_supported_file_extensions.argtypes = None | |||
| self.lib.carla_get_supported_file_extensions.restype = c_char_p | |||
| self.lib.carla_get_engine_driver_count.argtypes = None | |||
| self.lib.carla_get_engine_driver_count.restype = c_uint | |||
| @@ -2272,12 +2122,6 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| self.lib.carla_get_engine_driver_device_info.argtypes = [c_uint, c_char_p] | |||
| self.lib.carla_get_engine_driver_device_info.restype = POINTER(EngineDriverDeviceInfo) | |||
| self.lib.carla_get_cached_plugin_count.argtypes = [c_enum, c_char_p] | |||
| self.lib.carla_get_cached_plugin_count.restype = c_uint | |||
| self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint] | |||
| self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo) | |||
| self.lib.carla_engine_init.argtypes = [c_char_p, c_char_p] | |||
| self.lib.carla_engine_init.restype = c_bool | |||
| @@ -2523,15 +2367,6 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def get_complete_license_text(self): | |||
| return charPtrToString(self.lib.carla_get_complete_license_text()) | |||
| def get_juce_version(self): | |||
| return charPtrToString(self.lib.carla_get_juce_version()) | |||
| def get_supported_file_extensions(self): | |||
| return charPtrToString(self.lib.carla_get_supported_file_extensions()) | |||
| def get_engine_driver_count(self): | |||
| return int(self.lib.carla_get_engine_driver_count()) | |||
| @@ -2544,12 +2379,6 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| def get_engine_driver_device_info(self, index, name): | |||
| return structToDict(self.lib.carla_get_engine_driver_device_info(index, name.encode("utf-8")).contents) | |||
| def get_cached_plugin_count(self, ptype, pluginPath): | |||
| return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) | |||
| def get_cached_plugin_info(self, ptype, index): | |||
| return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents) | |||
| def engine_init(self, driverName, clientName): | |||
| return bool(self.lib.carla_engine_init(driverName.encode("utf-8"), clientName.encode("utf-8"))) | |||
| @@ -2836,11 +2665,8 @@ class CarlaHostPlugin(CarlaHostMeta): | |||
| self.processModeForced = True | |||
| # text data to return when requested | |||
| self.fCompleteLicenseText = "" | |||
| self.fJuceVersion = "" | |||
| self.fSupportedFileExts = "" | |||
| self.fMaxPluginNumber = 0 | |||
| self.fLastError = "" | |||
| self.fMaxPluginNumber = 0 | |||
| self.fLastError = "" | |||
| # plugin info | |||
| self.fPluginsInfo = [] | |||
| @@ -2876,15 +2702,6 @@ class CarlaHostPlugin(CarlaHostMeta): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def get_complete_license_text(self): | |||
| return self.fCompleteLicenseText | |||
| def get_juce_version(self): | |||
| return self.fJuceVersion | |||
| def get_supported_file_extensions(self): | |||
| return self.fSupportedFileExts | |||
| def get_engine_driver_count(self): | |||
| return 1 | |||
| @@ -2897,12 +2714,6 @@ class CarlaHostPlugin(CarlaHostMeta): | |||
| def get_engine_driver_device_info(self, index, name): | |||
| return PyEngineDriverDeviceInfo | |||
| def get_cached_plugin_count(self, ptype, pluginPath): | |||
| return 0 | |||
| def get_cached_plugin_info(self, ptype, index): | |||
| return PyCarlaCachedPluginInfo | |||
| def set_engine_callback(self, func): | |||
| return # TODO | |||
| @@ -3143,12 +2954,6 @@ class CarlaHostPlugin(CarlaHostMeta): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def _set_info(self, license, juceversion, fileexts, maxnum): | |||
| self.fCompleteLicenseText = license | |||
| self.fJuceVersion = juceversion | |||
| self.fSupportedFileExts = fileexts | |||
| self.fMaxPluginNumber = maxnum | |||
| def _set_transport(self, playing, frame, bar, beat, tick, bpm): | |||
| self.fTransportInfo = { | |||
| "playing": playing, | |||
| @@ -1482,9 +1482,9 @@ class PluginDatabaseW(QDialog): | |||
| AU_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_AU, CARLA_DEFAULT_AU_PATH))) | |||
| del settings | |||
| internalCountNew = self.host.get_cached_plugin_count(PLUGIN_INTERNAL, "") | |||
| lv2CountNew = self.host.get_cached_plugin_count(PLUGIN_LV2, LV2_PATH) | |||
| auCountNew = self.host.get_cached_plugin_count(PLUGIN_AU, AU_PATH) | |||
| internalCountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_INTERNAL, "") | |||
| lv2CountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_LV2, LV2_PATH) | |||
| auCountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_AU, AU_PATH) | |||
| if internalCountNew != internalCount or (len(internalPlugins) > 0 and | |||
| len(internalPlugins[0]) > 0 and | |||
| @@ -1492,7 +1492,7 @@ class PluginDatabaseW(QDialog): | |||
| internalPlugins = [] | |||
| for i in range(internalCountNew): | |||
| descInfo = self.host.get_cached_plugin_info(PLUGIN_INTERNAL, i) | |||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_INTERNAL, i) | |||
| plugins = checkPluginCached(descInfo, PLUGIN_INTERNAL) | |||
| if plugins: | |||
| @@ -1506,7 +1506,7 @@ class PluginDatabaseW(QDialog): | |||
| lv2Plugins = [] | |||
| for i in range(lv2CountNew): | |||
| descInfo = self.host.get_cached_plugin_info(PLUGIN_LV2, i) | |||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_LV2, i) | |||
| plugins = checkPluginCached(descInfo, PLUGIN_LV2) | |||
| if plugins: | |||
| @@ -1520,7 +1520,7 @@ class PluginDatabaseW(QDialog): | |||
| auPlugins = [] | |||
| for i in range(auCountNew): | |||
| descInfo = self.host.get_cached_plugin_info(PLUGIN_AU, i) | |||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_AU, i) | |||
| plugins = checkPluginCached(descInfo, PLUGIN_AU) | |||
| if plugins: | |||
| @@ -207,7 +207,7 @@ class HostWindow(QMainWindow): | |||
| self.fDirModel = QFileSystemModel(self) | |||
| self.fDirModel.setRootPath(HOME) | |||
| self.fDirModel.setNameFilters(host.get_supported_file_extensions().split(";")) | |||
| self.fDirModel.setNameFilters(gCarla.utils.get_supported_file_extensions().split(";")) | |||
| self.ui.fileTreeView.setModel(self.fDirModel) | |||
| self.ui.fileTreeView.setRootIndex(self.fDirModel.index(HOME)) | |||
| @@ -1328,7 +1328,7 @@ class HostWindow(QMainWindow): | |||
| @pyqtSlot() | |||
| def slot_aboutJuce(self): | |||
| JuceAboutW(self, self.host).exec_() | |||
| JuceAboutW(self).exec_() | |||
| @pyqtSlot() | |||
| def slot_aboutQt(self): | |||
| @@ -88,11 +88,72 @@ def getPluginTypeFromString(stype): | |||
| return PLUGIN_NONE | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Carla Pipe stuff | |||
| # Carla Utils API (C stuff) | |||
| CarlaPipeClientHandle = c_void_p | |||
| CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_p) | |||
| # Information about an internal Carla plugin. | |||
| # @see carla_get_cached_plugin_info() | |||
| class CarlaCachedPluginInfo(Structure): | |||
| _fields_ = [ | |||
| # Plugin category. | |||
| ("category", c_enum), | |||
| # Plugin hints. | |||
| # @see PluginHints | |||
| ("hints", c_uint), | |||
| # Number of audio inputs. | |||
| ("audioIns", c_uint32), | |||
| # Number of audio outputs. | |||
| ("audioOuts", c_uint32), | |||
| # Number of MIDI inputs. | |||
| ("midiIns", c_uint32), | |||
| # Number of MIDI outputs. | |||
| ("midiOuts", c_uint32), | |||
| # Number of input parameters. | |||
| ("parameterIns", c_uint32), | |||
| # Number of output parameters. | |||
| ("parameterOuts", c_uint32), | |||
| # Plugin name. | |||
| ("name", c_char_p), | |||
| # Plugin label. | |||
| ("label", c_char_p), | |||
| # Plugin author/maker. | |||
| ("maker", c_char_p), | |||
| # Plugin copyright/license. | |||
| ("copyright", c_char_p) | |||
| ] | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Carla Utils API (Python compatible stuff) | |||
| # @see CarlaCachedPluginInfo | |||
| PyCarlaCachedPluginInfo = { | |||
| 'category': PLUGIN_CATEGORY_NONE, | |||
| 'hints': 0x0, | |||
| 'audioIns': 0, | |||
| 'audioOuts': 0, | |||
| 'midiIns': 0, | |||
| 'midiOuts': 0, | |||
| 'parameterIns': 0, | |||
| 'parameterOuts': 0, | |||
| 'name': "", | |||
| 'label': "", | |||
| 'maker': "", | |||
| 'copyright': "" | |||
| } | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Carla Utils object using a DLL | |||
| @@ -102,14 +163,20 @@ class CarlaUtils(object): | |||
| self.lib = cdll.LoadLibrary(filename) | |||
| self.lib.carla_get_library_filename.argtypes = None | |||
| self.lib.carla_get_library_filename.restype = c_char_p | |||
| self.lib.carla_get_complete_license_text.argtypes = None | |||
| self.lib.carla_get_complete_license_text.restype = c_char_p | |||
| self.lib.carla_get_library_folder.argtypes = None | |||
| self.lib.carla_get_library_folder.restype = c_char_p | |||
| self.lib.carla_get_juce_version.argtypes = None | |||
| self.lib.carla_get_juce_version.restype = c_char_p | |||
| self.lib.carla_set_locale_C.argtypes = None | |||
| self.lib.carla_set_locale_C.restype = None | |||
| self.lib.carla_get_supported_file_extensions.argtypes = None | |||
| self.lib.carla_get_supported_file_extensions.restype = c_char_p | |||
| self.lib.carla_get_cached_plugin_count.argtypes = [c_enum, c_char_p] | |||
| self.lib.carla_get_cached_plugin_count.restype = c_uint | |||
| self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint] | |||
| self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo) | |||
| self.lib.carla_set_process_name.argtypes = [c_char_p] | |||
| self.lib.carla_set_process_name.restype = None | |||
| @@ -149,14 +216,30 @@ class CarlaUtils(object): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def get_library_filename(self): | |||
| return charPtrToString(self.lib.carla_get_library_filename()) | |||
| def get_library_folder(self): | |||
| return charPtrToString(self.lib.carla_get_library_folder()) | |||
| def set_locale_C(self): | |||
| self.lib.carla_set_locale_C() | |||
| # Get the complete license text of used third-party code and features. | |||
| # Returned string is in basic html format. | |||
| def get_complete_license_text(self): | |||
| return charPtrToString(self.lib.carla_get_complete_license_text()) | |||
| # Get the juce version used in the current Carla build. | |||
| def get_juce_version(self): | |||
| return charPtrToString(self.lib.carla_get_juce_version()) | |||
| # Get all the supported file extensions in carla_load_file(). | |||
| # Returned string uses this syntax: | |||
| # @code | |||
| # "*.ext1;*.ext2;*.ext3" | |||
| # @endcode | |||
| def get_supported_file_extensions(self): | |||
| return charPtrToString(self.lib.carla_get_supported_file_extensions()) | |||
| # Get how many internal plugins are available. | |||
| def get_cached_plugin_count(self, ptype, pluginPath): | |||
| return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) | |||
| # Get information about a cached plugin. | |||
| def get_cached_plugin_info(self, ptype, index): | |||
| return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents) | |||
| def set_process_name(self, name): | |||
| self.lib.carla_set_process_name(name.encode("utf-8")) | |||
| @@ -87,7 +87,7 @@ class CarlaAboutW(QDialog): | |||
| elif host.isPlugin: | |||
| self.ui.tabWidget.removeTab(2) | |||
| self.ui.l_extended.setText(host.get_complete_license_text()) | |||
| self.ui.l_extended.setText(gCarla.utils.get_complete_license_text()) | |||
| if host.is_engine_running() and not (host.isControl or host.isPlugin): | |||
| self.ui.le_osc_url_tcp.setText(host.get_host_osc_url_tcp()) | |||
| @@ -172,16 +172,12 @@ class CarlaAboutW(QDialog): | |||
| # JUCE About dialog | |||
| class JuceAboutW(QDialog): | |||
| def __init__(self, parent, host): | |||
| def __init__(self, parent): | |||
| QDialog.__init__(self, parent) | |||
| self.ui = ui_carla_about_juce.Ui_JuceAboutW() | |||
| self.ui.setupUi(self) | |||
| if False: | |||
| # kdevelop likes this :) | |||
| host = CarlaHostMeta() | |||
| self.ui.l_text2.setText(self.tr("This program uses JUCE version %s." % host.get_juce_version())) | |||
| self.ui.l_text2.setText(self.tr("This program uses JUCE version %s." % gCarla.utils.get_juce_version())) | |||
| self.adjustSize() | |||
| self.setFixedSize(self.size()) | |||
| @@ -33,6 +33,14 @@ | |||
| using CarlaBackend::CarlaPlugin; | |||
| // ----------------------------------------------------------------------- | |||
| CARLA_EXTERN_C | |||
| std::size_t carla_getNativePluginCount(); | |||
| CARLA_EXTERN_C | |||
| const NativePluginDescriptor* carla_getNativePluginDescriptor(const std::size_t index); | |||
| // ----------------------------------------------------------------------- | |||
| // Plugin List | |||
| @@ -49,9 +57,9 @@ struct PluginListManager { | |||
| #endif | |||
| descs() | |||
| { | |||
| for (size_t i=0, count = CarlaPlugin::getNativePluginCount(); i < count; ++i) | |||
| for (std::size_t i=0, count = carla_getNativePluginCount(); i < count; ++i) | |||
| { | |||
| const NativePluginDescriptor* const desc(CarlaPlugin::getNativePluginDescriptor(i)); | |||
| const NativePluginDescriptor* const desc(carla_getNativePluginDescriptor(i)); | |||
| // Open/Save not possible in plugins | |||
| if (desc->hints & NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE) | |||
| @@ -19,7 +19,6 @@ | |||
| #define CARLA_BACKEND_UTILS_HPP_INCLUDED | |||
| #include "CarlaBackend.h" | |||
| #include "CarlaHost.h" | |||
| #include "CarlaString.hpp" | |||
| CARLA_BACKEND_START_NAMESPACE | |||
| @@ -134,7 +134,16 @@ class RackListWidget(QListWidget): | |||
| host = CarlaHostMeta() | |||
| self.host = host | |||
| self.fSupportedExtensions = [] | |||
| exts = gCarla.utils.get_supported_file_extensions().split(";") | |||
| exts.append(".dll") | |||
| if MACOS: | |||
| exts.append(".dylib") | |||
| if not WINDOWS: | |||
| exts.append(".so") | |||
| self.fSupportedExtensions = tuple(i.replace("*","") for i in exts) | |||
| self.fWasLastDragValid = False | |||
| self.setMinimumWidth(640) | |||
| @@ -162,17 +171,6 @@ class RackListWidget(QListWidget): | |||
| def setHost(self, host): | |||
| self.host = host | |||
| exts = host.get_supported_file_extensions().split(";") | |||
| exts.append(".dll") | |||
| if MACOS: | |||
| exts.append(".dylib") | |||
| if not WINDOWS: | |||
| exts.append(".so") | |||
| self.fSupportedExtensions = tuple(i.replace("*","") for i in exts) | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| def isDragUrlValid(self, url): | |||