| @@ -93,12 +93,8 @@ carla-discovery-native | |||||
| carla-discovery-posix32 | carla-discovery-posix32 | ||||
| carla-discovery-posix64 | carla-discovery-posix64 | ||||
| carla-frontend | |||||
| carla-lv2-export | carla-lv2-export | ||||
| zita-at1-ui | |||||
| zita-bls1-ui | |||||
| zita-rev1-ui | |||||
| carla-rest-server | |||||
| zynaddsubfx-ui | zynaddsubfx-ui | ||||
| stoat-output.png | stoat-output.png | ||||
| @@ -152,6 +148,17 @@ source/includes/rewire/ | |||||
| source/includes/vst2 | source/includes/vst2 | ||||
| source/includes/vst3 | source/includes/vst3 | ||||
| source/includes/config.h | source/includes/config.h | ||||
| source/modules/dgl/src/Resources.cpp | |||||
| source/modules/dgl/src/Resources.hpp | |||||
| source/modules/dgl/src/resources/ | |||||
| source/modules/dgl/src/sofd/ | |||||
| source/modules/distrho/src/DistrhoPluginJack.cpp | |||||
| source/modules/distrho/src/DistrhoPluginLADSPA+DSSI.cpp | |||||
| source/modules/distrho/src/DistrhoPluginLV2.cpp | |||||
| source/modules/distrho/src/DistrhoPluginLV2export.cpp | |||||
| source/modules/distrho/src/DistrhoPluginVST.cpp | |||||
| source/modules/distrho/src/DistrhoUIDSSI.cpp | |||||
| source/modules/distrho/src/DistrhoUILV2.cpp | |||||
| data/linux/*.gz | data/linux/*.gz | ||||
| data/linux/*.tgz | data/linux/*.tgz | ||||
| @@ -163,6 +163,9 @@ libjack: libs | |||||
| plugin: backend bridges-plugin bridges-ui discovery | plugin: backend bridges-plugin bridges-ui discovery | ||||
| @$(MAKE) -C source/plugin | @$(MAKE) -C source/plugin | ||||
| rest: libs | |||||
| @$(MAKE) -C source/rest | |||||
| theme: libs | theme: libs | ||||
| @$(MAKE) -C source/theme | @$(MAKE) -C source/theme | ||||
| @@ -900,7 +903,7 @@ endif | |||||
| ifeq ($(HAVE_FLUIDSYNTH),true) | ifeq ($(HAVE_FLUIDSYNTH),true) | ||||
| @printf -- "SF2/3: $(ANS_YES)\n" | @printf -- "SF2/3: $(ANS_YES)\n" | ||||
| else | else | ||||
| @printf -- "SF2/3: $(ANS_NO) $(mS)FluidSynth missing$(mE)\n" | |||||
| @printf -- "SF2/3: $(ANS_NO) $(mS)FluidSynth missing$(mE)\n" | |||||
| endif | endif | ||||
| @printf -- "SFZ: $(ANS_YES)\n" | @printf -- "SFZ: $(ANS_YES)\n" | ||||
| @printf -- "\n" | @printf -- "\n" | ||||
| @@ -911,8 +914,8 @@ ifneq ($(WIN32),true) | |||||
| @printf -- "Carla-Patchbay: $(ANS_YES)\n" | @printf -- "Carla-Patchbay: $(ANS_YES)\n" | ||||
| @printf -- "Carla-Rack: $(ANS_YES)\n" | @printf -- "Carla-Rack: $(ANS_YES)\n" | ||||
| else | else | ||||
| @printf -- "Carla-Patchbay: $(ANS_NO) $(mS)Not available for Windows$(mE)\n" | |||||
| @printf -- "Carla-Rack: $(ANS_NO) $(mS)Not available for Windows$(mE)\n" | |||||
| @printf -- "Carla-Patchbay: $(ANS_NO) $(mS)Not available for Windows$(mE)\n" | |||||
| @printf -- "Carla-Rack: $(ANS_NO) $(mS)Not available for Windows$(mE)\n" | |||||
| endif | endif | ||||
| ifeq ($(EXTERNAL_PLUGINS),true) | ifeq ($(EXTERNAL_PLUGINS),true) | ||||
| @printf -- "External Plugins: $(ANS_YES)\n" | @printf -- "External Plugins: $(ANS_YES)\n" | ||||
| @@ -0,0 +1,19 @@ | |||||
| #!/bin/bash | |||||
| set -e | |||||
| export MACOS_OLD=true | |||||
| export CROSS_COMPILING=true | |||||
| _FLAGS="-mmacosx-version-min=10.6 -Wno-attributes -Wno-deprecated-declarations -Werror" | |||||
| export CFLAGS="${_FLAGS} -m32" | |||||
| export CXXFLAGS="${_FLAGS} -m32" | |||||
| export LDFLAGS="-m32" | |||||
| apple-cross-setup make -j4 | |||||
| export CFLAGS="${_FLAGS} -m64" | |||||
| export CXXFLAGS="${_FLAGS} -m64" | |||||
| export LDFLAGS="-m64" | |||||
| # FIXME | |||||
| apple-cross-setup make posix64 -j4 | |||||
| @@ -0,0 +1,31 @@ | |||||
| #!/bin/bash | |||||
| export CARLA_VALGRIND_TEST=1 | |||||
| export WINEDEBUG=-all | |||||
| # export CARLA_DEV=1 | |||||
| # export PYTHONMALLOC=malloc | |||||
| # export SKIP_STRIPPING=true | |||||
| valgrind \ | |||||
| --tool=memcheck \ | |||||
| --leak-check=full \ | |||||
| --show-leak-kinds=all \ | |||||
| --track-origins=yes \ | |||||
| --gen-suppressions=all \ | |||||
| --suppressions=./data/valgrind.supp \ | |||||
| -- ./bin/carla-bridge-native internal "" carlapatchbay & | |||||
| PID=$! | |||||
| while true; do | |||||
| if jack_lsp | grep -q Carla-Patchbay:output_1; then | |||||
| jack_connect Carla-Patchbay:output_2 system:playback_2 | |||||
| jack_connect Carla-Patchbay:output_1 system:playback_1 | |||||
| # jack_connect Carla-Patchbay:events-out "a2j:ZynAddSubFX [129] (playback): ZynAddSubFX" | |||||
| break | |||||
| else | |||||
| sleep 1 | |||||
| fi | |||||
| done | |||||
| wait ${PID} | |||||
| @@ -0,0 +1,56 @@ | |||||
| # ld related errors, unfixed since the dawn of time | |||||
| { | |||||
| _dl_init-1 | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: reachable | |||||
| ... | |||||
| fun:call_init | |||||
| fun:_dl_init | |||||
| obj:/lib/x86_64-linux-gnu/ld-2.27.so | |||||
| } | |||||
| { | |||||
| _dl_init-2 | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: possible | |||||
| ... | |||||
| fun:call_init | |||||
| fun:_dl_init | |||||
| obj:/lib/x86_64-linux-gnu/ld-2.27.so | |||||
| } | |||||
| { | |||||
| _dl_init-3 | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: definite | |||||
| ... | |||||
| fun:call_init | |||||
| fun:_dl_init | |||||
| obj:/lib/x86_64-linux-gnu/ld-2.27.so | |||||
| } | |||||
| { | |||||
| dlclose-1 | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: reachable | |||||
| fun:calloc | |||||
| fun:_dlerror_run | |||||
| fun:dlopen@@GLIBC_2.2.5 | |||||
| ... | |||||
| } | |||||
| { | |||||
| dlclose-2 | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: reachable | |||||
| ... | |||||
| fun:_dl_open | |||||
| ... | |||||
| } | |||||
| # XInitThreads | |||||
| { | |||||
| XInitThreads | |||||
| Memcheck:Leak | |||||
| match-leak-kinds: reachable | |||||
| fun:malloc | |||||
| fun:XInitThreads | |||||
| fun:main | |||||
| } | |||||
| @@ -243,8 +243,8 @@ INCLUDE_PATH = | |||||
| INCLUDE_FILE_PATTERNS = | INCLUDE_FILE_PATTERNS = | ||||
| PREDEFINED = DOXYGEN \ | PREDEFINED = DOXYGEN \ | ||||
| BUILDING_CARLA REAL_BUILD \ | BUILDING_CARLA REAL_BUILD \ | ||||
| HAVE_DGL HAVE_LIBLO HAVE_LIBMAGIC HAVE_FLUIDSYNTH HAVE_LINUXSAMPLER HAVE_PROJECTM HAVE_X11 \ | |||||
| HAVE_EXPERIMENTAL_PLUGINS HAVE_ZYN_DEPS HAVE_ZYN_UI_DEPS | |||||
| HAVE_DGL HAVE_LIBLO HAVE_LIBMAGIC HAVE_FLUIDSYNTH HAVE_PROJECTM HAVE_X11 \ | |||||
| HAVE_ZYN_DEPS HAVE_ZYN_UI_DEPS | |||||
| EXPAND_AS_DEFINED = | EXPAND_AS_DEFINED = | ||||
| SKIP_FUNCTION_MACROS = YES | SKIP_FUNCTION_MACROS = YES | ||||
| #--------------------------------------------------------------------------- | #--------------------------------------------------------------------------- | ||||
| @@ -607,7 +607,7 @@ typedef enum { | |||||
| */ | */ | ||||
| PARAMETER_NULL = -1, | PARAMETER_NULL = -1, | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * Active parameter, boolean type. | * Active parameter, boolean type. | ||||
| * Default is 'false'. | * Default is 'false'. | ||||
| @@ -716,7 +716,7 @@ typedef enum { | |||||
| */ | */ | ||||
| ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED = 6, | ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED = 6, | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * A parameter's MIDI CC has changed. | * A parameter's MIDI CC has changed. | ||||
| * @a pluginId Plugin Id | * @a pluginId Plugin Id | ||||
| @@ -814,7 +814,7 @@ typedef enum { | |||||
| */ | */ | ||||
| ENGINE_CALLBACK_RELOAD_ALL = 19, | ENGINE_CALLBACK_RELOAD_ALL = 19, | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * A patchbay client has been added. | * A patchbay client has been added. | ||||
| * @a pluginId Client Id | * @a pluginId Client Id | ||||
| @@ -1087,7 +1087,7 @@ typedef enum { | |||||
| */ | */ | ||||
| ENGINE_OPTION_FRONTEND_WIN_ID = 17, | ENGINE_OPTION_FRONTEND_WIN_ID = 17, | ||||
| #ifndef CARLA_OS_WIN | |||||
| #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN) | |||||
| /*! | /*! | ||||
| * Set path to wine executable. | * Set path to wine executable. | ||||
| */ | */ | ||||
| @@ -291,6 +291,7 @@ struct CARLA_API EngineTimeInfoBBT { | |||||
| #ifndef DOXYGEN | #ifndef DOXYGEN | ||||
| EngineTimeInfoBBT() noexcept; | EngineTimeInfoBBT() noexcept; | ||||
| EngineTimeInfoBBT(const EngineTimeInfoBBT&) noexcept; | |||||
| #endif | #endif | ||||
| }; | }; | ||||
| @@ -310,6 +311,8 @@ struct CARLA_API EngineTimeInfo { | |||||
| #ifndef DOXYGEN | #ifndef DOXYGEN | ||||
| EngineTimeInfo() noexcept; | EngineTimeInfo() noexcept; | ||||
| EngineTimeInfo(const EngineTimeInfo&) noexcept; | |||||
| EngineTimeInfo& operator=(const EngineTimeInfo&) noexcept; | |||||
| // quick operator, doesn't check all values | // quick operator, doesn't check all values | ||||
| bool operator==(const EngineTimeInfo& timeInfo) const noexcept; | bool operator==(const EngineTimeInfo& timeInfo) const noexcept; | ||||
| @@ -821,7 +824,7 @@ public: | |||||
| */ | */ | ||||
| bool removeAllPlugins(); | bool removeAllPlugins(); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * Rename plugin with id @a id to @a newName. | * Rename plugin with id @a id to @a newName. | ||||
| * Returns the new name, or null if the operation failed. | * Returns the new name, or null if the operation failed. | ||||
| @@ -922,7 +925,7 @@ public: | |||||
| /*! | /*! | ||||
| * Get the current Time information (read-only). | * Get the current Time information (read-only). | ||||
| */ | */ | ||||
| const EngineTimeInfo& getTimeInfo() const noexcept; | |||||
| virtual EngineTimeInfo getTimeInfo() const noexcept; | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Information (peaks) | // Information (peaks) | ||||
| @@ -965,7 +968,7 @@ public: | |||||
| */ | */ | ||||
| void setFileCallback(const FileCallbackFunc func, void* const ptr) noexcept; | void setFileCallback(const FileCallbackFunc func, void* const ptr) noexcept; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Patchbay | // Patchbay | ||||
| @@ -1036,6 +1039,13 @@ public: | |||||
| */ | */ | ||||
| bool setAboutToClose() noexcept; | bool setAboutToClose() noexcept; | ||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | |||||
| * TODO. | |||||
| */ | |||||
| bool isLoadingProject() const noexcept; | |||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Options | // Options | ||||
| @@ -1052,7 +1062,6 @@ public: | |||||
| * Check if OSC controller is registered. | * Check if OSC controller is registered. | ||||
| */ | */ | ||||
| bool isOscControlRegistered() const noexcept; | bool isOscControlRegistered() const noexcept; | ||||
| #endif | |||||
| /*! | /*! | ||||
| * Idle OSC. | * Idle OSC. | ||||
| @@ -1068,6 +1077,7 @@ public: | |||||
| * Get OSC UDP server path. | * Get OSC UDP server path. | ||||
| */ | */ | ||||
| const char* getOscServerPathUDP() const noexcept; | const char* getOscServerPathUDP() const noexcept; | ||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Helper functions | // Helper functions | ||||
| @@ -1078,7 +1088,7 @@ public: | |||||
| */ | */ | ||||
| EngineEvent* getInternalEventBuffer(const bool isInput) const noexcept; | EngineEvent* getInternalEventBuffer(const bool isInput) const noexcept; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * Virtual functions for handling external graph ports. | * Virtual functions for handling external graph ports. | ||||
| */ | */ | ||||
| @@ -1142,7 +1152,7 @@ protected: | |||||
| */ | */ | ||||
| bool loadProjectInternal(water::XmlDocument& xmlDoc); | bool loadProjectInternal(water::XmlDocument& xmlDoc); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Patchbay stuff | // Patchbay stuff | ||||
| @@ -612,13 +612,22 @@ CARLA_EXPORT const ParameterRanges* carla_get_parameter_ranges(uint pluginId, ui | |||||
| CARLA_EXPORT const MidiProgramData* carla_get_midi_program_data(uint pluginId, uint32_t midiProgramId); | CARLA_EXPORT const MidiProgramData* carla_get_midi_program_data(uint pluginId, uint32_t midiProgramId); | ||||
| /*! | /*! | ||||
| * Get a plugin's custom data. | |||||
| * Get a plugin's custom data, using index. | |||||
| * @param pluginId Plugin | * @param pluginId Plugin | ||||
| * @param customDataId Custom data index | * @param customDataId Custom data index | ||||
| * @see carla_get_custom_data_count() | * @see carla_get_custom_data_count() | ||||
| */ | */ | ||||
| CARLA_EXPORT const CustomData* carla_get_custom_data(uint pluginId, uint32_t customDataId); | CARLA_EXPORT const CustomData* carla_get_custom_data(uint pluginId, uint32_t customDataId); | ||||
| /*! | |||||
| * Get a plugin's custom data value, using type and key. | |||||
| * @param pluginId Plugin | |||||
| * @param type Custom data type | |||||
| * @param key Custom data key | |||||
| * @see carla_get_custom_data_count() | |||||
| */ | |||||
| CARLA_EXPORT const char* carla_get_custom_data_value(uint pluginId, const char* type, const char* key); | |||||
| /*! | /*! | ||||
| * Get a plugin's chunk data. | * Get a plugin's chunk data. | ||||
| * @param pluginId Plugin | * @param pluginId Plugin | ||||
| @@ -106,7 +106,7 @@ const char* carla_get_library_filename() | |||||
| if (ret.isEmpty()) | if (ret.isEmpty()) | ||||
| { | { | ||||
| using namespace water; | |||||
| using water::File; | |||||
| ret = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName().toRawUTF8(); | ret = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName().toRawUTF8(); | ||||
| } | } | ||||
| @@ -121,7 +121,7 @@ const char* carla_get_library_folder() | |||||
| if (ret.isEmpty()) | if (ret.isEmpty()) | ||||
| { | { | ||||
| using namespace water; | |||||
| using water::File; | |||||
| ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8(); | ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8(); | ||||
| } | } | ||||
| @@ -463,7 +463,7 @@ public: | |||||
| */ | */ | ||||
| void setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept; | void setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * Set the plugin's dry/wet signal value to @a value. | * Set the plugin's dry/wet signal value to @a value. | ||||
| * @a value must be between 0.0 and 1.0. | * @a value must be between 0.0 and 1.0. | ||||
| @@ -749,7 +749,7 @@ public: | |||||
| */ | */ | ||||
| void sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback); | void sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| /*! | /*! | ||||
| * Send all midi notes off to the host callback. | * Send all midi notes off to the host callback. | ||||
| * This doesn't send the actual MIDI All-Notes-Off event, but 128 note-offs instead (IFF ctrlChannel is valid). | * This doesn't send the actual MIDI All-Notes-Off event, but 128 note-offs instead (IFF ctrlChannel is valid). | ||||
| @@ -98,39 +98,73 @@ typedef void (*void_func)(void); | |||||
| class ThreadSafeFFTW | class ThreadSafeFFTW | ||||
| { | { | ||||
| public: | public: | ||||
| struct Deinitializer { | |||||
| Deinitializer(ThreadSafeFFTW& s) | |||||
| : tsfftw(s) {} | |||||
| ~Deinitializer() | |||||
| { | |||||
| tsfftw.deinit(); | |||||
| } | |||||
| ThreadSafeFFTW& tsfftw; | |||||
| }; | |||||
| ThreadSafeFFTW() | ThreadSafeFFTW() | ||||
| : libfftw3(lib_open("libfftw3_threads.so.3")), | |||||
| libfftw3f(lib_open("libfftw3f_threads.so.3")), | |||||
| libfftw3l(lib_open("libfftw3l_threads.so.3")), | |||||
| libfftw3q(lib_open("libfftw3q_threads.so.3")) | |||||
| : libfftw3(nullptr), | |||||
| libfftw3f(nullptr), | |||||
| libfftw3l(nullptr), | |||||
| libfftw3q(nullptr) {} | |||||
| ~ThreadSafeFFTW() | |||||
| { | { | ||||
| if (libfftw3 != nullptr) | |||||
| CARLA_SAFE_ASSERT(libfftw3 == nullptr); | |||||
| } | |||||
| void init() | |||||
| { | |||||
| if ((libfftw3 = lib_open("libfftw3_threads.so.3")) != nullptr) | |||||
| if (const void_func func = lib_symbol<void_func>(libfftw3, "fftw_make_planner_thread_safe")) | if (const void_func func = lib_symbol<void_func>(libfftw3, "fftw_make_planner_thread_safe")) | ||||
| func(); | func(); | ||||
| if (libfftw3f != nullptr) | |||||
| if ((libfftw3f = lib_open("libfftw3f_threads.so.3")) != nullptr) | |||||
| if (const void_func func = lib_symbol<void_func>(libfftw3f, "fftwf_make_planner_thread_safe")) | if (const void_func func = lib_symbol<void_func>(libfftw3f, "fftwf_make_planner_thread_safe")) | ||||
| func(); | func(); | ||||
| if (libfftw3l != nullptr) | |||||
| if ((libfftw3l = lib_open("libfftw3l_threads.so.3")) != nullptr) | |||||
| if (const void_func func = lib_symbol<void_func>(libfftw3l, "fftwl_make_planner_thread_safe")) | if (const void_func func = lib_symbol<void_func>(libfftw3l, "fftwl_make_planner_thread_safe")) | ||||
| func(); | func(); | ||||
| if (libfftw3q != nullptr) | |||||
| if ((libfftw3q = lib_open("libfftw3q_threads.so.3")) != nullptr) | |||||
| if (const void_func func = lib_symbol<void_func>(libfftw3q, "fftwq_make_planner_thread_safe")) | if (const void_func func = lib_symbol<void_func>(libfftw3q, "fftwq_make_planner_thread_safe")) | ||||
| func(); | func(); | ||||
| } | } | ||||
| ~ThreadSafeFFTW() | |||||
| void deinit() | |||||
| { | { | ||||
| if (libfftw3 != nullptr) | if (libfftw3 != nullptr) | ||||
| { | |||||
| lib_close(libfftw3); | lib_close(libfftw3); | ||||
| libfftw3 = nullptr; | |||||
| } | |||||
| if (libfftw3f != nullptr) | if (libfftw3f != nullptr) | ||||
| { | |||||
| lib_close(libfftw3f); | lib_close(libfftw3f); | ||||
| libfftw3f = nullptr; | |||||
| } | |||||
| if (libfftw3l != nullptr) | if (libfftw3l != nullptr) | ||||
| { | |||||
| lib_close(libfftw3l); | lib_close(libfftw3l); | ||||
| libfftw3l = nullptr; | |||||
| } | |||||
| if (libfftw3q != nullptr) | if (libfftw3q != nullptr) | ||||
| { | |||||
| lib_close(libfftw3q); | lib_close(libfftw3q); | ||||
| libfftw3q = nullptr; | |||||
| } | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -139,6 +173,8 @@ private: | |||||
| lib_t libfftw3l; | lib_t libfftw3l; | ||||
| lib_t libfftw3q; | lib_t libfftw3q; | ||||
| }; | }; | ||||
| static ThreadSafeFFTW sThreadSafeFFTW; | |||||
| #endif | #endif | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -173,7 +209,7 @@ const char* const* carla_get_engine_driver_device_names(uint index) | |||||
| const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name) | const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | |||||
| CARLA_SAFE_ASSERT_RETURN(name != nullptr, nullptr); | |||||
| static EngineDriverDeviceInfo retDevInfo; | static EngineDriverDeviceInfo retDevInfo; | ||||
| static const uint32_t nullBufferSizes[] = { 0 }; | static const uint32_t nullBufferSizes[] = { 0 }; | ||||
| @@ -349,9 +385,6 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||||
| #ifdef CARLA_OS_WIN | #ifdef CARLA_OS_WIN | ||||
| carla_setenv("WINEASIO_CLIENT_NAME", clientName); | carla_setenv("WINEASIO_CLIENT_NAME", clientName); | ||||
| #endif | #endif | ||||
| #ifdef CARLA_OS_UNIX | |||||
| static const ThreadSafeFFTW tsfftw; | |||||
| #endif | |||||
| ScopedPointer<CarlaEngine> engine(CarlaEngine::newDriverByName(driverName)); | ScopedPointer<CarlaEngine> engine(CarlaEngine::newDriverByName(driverName)); | ||||
| @@ -375,6 +408,9 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| if (gStandalone.logThreadEnabled && std::getenv("CARLA_LOGS_DISABLED") == nullptr) | if (gStandalone.logThreadEnabled && std::getenv("CARLA_LOGS_DISABLED") == nullptr) | ||||
| gStandalone.logThread.init(); | gStandalone.logThread.init(); | ||||
| #endif | |||||
| #ifdef CARLA_OS_UNIX | |||||
| sThreadSafeFFTW.init(); | |||||
| #endif | #endif | ||||
| gStandalone.lastError = "No error"; | gStandalone.lastError = "No error"; | ||||
| gStandalone.engine = engine.release(); | gStandalone.engine = engine.release(); | ||||
| @@ -432,6 +468,10 @@ bool carla_engine_close() | |||||
| CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(gStandalone.engine != nullptr, "Engine is not initialized", false); | CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(gStandalone.engine != nullptr, "Engine is not initialized", false); | ||||
| #ifdef CARLA_OS_UNIX | |||||
| const ThreadSafeFFTW::Deinitializer tsfftwde(sThreadSafeFFTW); | |||||
| #endif | |||||
| ScopedPointer<CarlaEngine> engine(gStandalone.engine); | ScopedPointer<CarlaEngine> engine(gStandalone.engine); | ||||
| gStandalone.engine = nullptr; | gStandalone.engine = nullptr; | ||||
| @@ -1324,6 +1364,40 @@ const CustomData* carla_get_custom_data(uint pluginId, uint32_t customDataId) | |||||
| return &retCustomData; | return &retCustomData; | ||||
| } | } | ||||
| const char* carla_get_custom_data_value(uint pluginId, const char* type, const char* key) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0', gNullCharPtr); | |||||
| CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', gNullCharPtr); | |||||
| CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, gNullCharPtr); | |||||
| CarlaPlugin* const plugin(gStandalone.engine->getPlugin(pluginId)); | |||||
| CARLA_SAFE_ASSERT_RETURN(plugin != nullptr, gNullCharPtr); | |||||
| carla_debug("carla_get_custom_data_value(%i, %s, %s)", pluginId, type, key); | |||||
| const uint32_t count = plugin->getCustomDataCount(); | |||||
| if (count == 0) | |||||
| return gNullCharPtr; | |||||
| static CarlaString customDataValue; | |||||
| for (uint32_t i=0; i<count; ++i) | |||||
| { | |||||
| const CustomData& pluginCustomData(plugin->getCustomData(i)); | |||||
| if (std::strcmp(pluginCustomData.type, type) != 0) | |||||
| continue; | |||||
| if (std::strcmp(pluginCustomData.key, key) != 0) | |||||
| continue; | |||||
| customDataValue = pluginCustomData.value; | |||||
| return customDataValue.buffer(); | |||||
| } | |||||
| return gNullCharPtr; | |||||
| } | |||||
| const char* carla_get_chunk_data(uint pluginId) | const char* carla_get_chunk_data(uint pluginId) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, gNullCharPtr); | CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr, gNullCharPtr); | ||||
| @@ -1856,7 +1930,7 @@ const char* carla_get_host_osc_url_tcp() | |||||
| { | { | ||||
| carla_debug("carla_get_host_osc_url_tcp()"); | carla_debug("carla_get_host_osc_url_tcp()"); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (gStandalone.engine == nullptr) | if (gStandalone.engine == nullptr) | ||||
| { | { | ||||
| carla_stderr2("carla_get_host_osc_url_tcp() failed, engine is not running"); | carla_stderr2("carla_get_host_osc_url_tcp() failed, engine is not running"); | ||||
| @@ -1874,7 +1948,7 @@ const char* carla_get_host_osc_url_udp() | |||||
| { | { | ||||
| carla_debug("carla_get_host_osc_url_udp()"); | carla_debug("carla_get_host_osc_url_udp()"); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (gStandalone.engine == nullptr) | if (gStandalone.engine == nullptr) | ||||
| { | { | ||||
| carla_stderr2("carla_get_host_osc_url_udp() failed, engine is not running"); | carla_stderr2("carla_get_host_osc_url_udp() failed, engine is not running"); | ||||
| @@ -1895,6 +1969,7 @@ const char* carla_get_host_osc_url_udp() | |||||
| #undef CARLA_PLUGIN_UI_CLASS_PREFIX | #undef CARLA_PLUGIN_UI_CLASS_PREFIX | ||||
| #include "CarlaDssiUtils.cpp" | #include "CarlaDssiUtils.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| #include "CarlaPatchbayUtils.cpp" | #include "CarlaPatchbayUtils.cpp" | ||||
| #include "CarlaPipeUtils.cpp" | #include "CarlaPipeUtils.cpp" | ||||
| #include "CarlaStateUtils.cpp" | #include "CarlaStateUtils.cpp" | ||||
| @@ -1,837 +0,0 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaNative.h" | |||||
| #include "CarlaBackendUtils.hpp" | |||||
| #include "CarlaLv2Utils.hpp" | |||||
| #include "CarlaPipeUtils.hpp" | |||||
| #include "CarlaThread.hpp" | |||||
| #include "LinkedList.hpp" | |||||
| #include "water/files/File.h" | |||||
| #ifdef CARLA_OS_MAC | |||||
| # import <Cocoa/Cocoa.h> | |||||
| #endif | |||||
| #ifndef CARLA_UTILS_CACHED_PLUGINS_ONLY | |||||
| # include "rtaudio/RtAudio.h" | |||||
| # include "rtmidi/RtMidi.h" | |||||
| # ifdef HAVE_X11 | |||||
| # include <X11/Xlib.h> | |||||
| # endif | |||||
| #endif | |||||
| #include "../native-plugins/_data.all.cpp" | |||||
| namespace CB = CarlaBackend; | |||||
| static const char* const gNullCharPtr = ""; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| _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) {} | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(ptype == CB::PLUGIN_INTERNAL || ptype == CB::PLUGIN_LV2, 0); | |||||
| carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype)); | |||||
| switch (ptype) | |||||
| { | |||||
| case CB::PLUGIN_INTERNAL: { | |||||
| uint32_t count = 0; | |||||
| carla_get_native_plugins_data(&count); | |||||
| return count; | |||||
| } | |||||
| case CB::PLUGIN_LV2: { | |||||
| Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); | |||||
| lv2World.initIfNeeded(pluginPath); | |||||
| return lv2World.getPluginCount(); | |||||
| } | |||||
| 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: { | |||||
| uint32_t count = 0; | |||||
| const NativePluginDescriptor* const descs(carla_get_native_plugins_data(&count)); | |||||
| CARLA_SAFE_ASSERT_BREAK(index < count); | |||||
| CARLA_SAFE_ASSERT_BREAK(descs != nullptr); | |||||
| const NativePluginDescriptor& desc(descs[index]); | |||||
| 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_UI_MAIN_THREAD) | |||||
| info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD; | |||||
| if (desc.hints & NATIVE_PLUGIN_USES_MULTI_PROGS) | |||||
| info.hints |= CB::PLUGIN_USES_MULTI_PROGS; | |||||
| info.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()); | |||||
| // features | |||||
| info.hints = 0x0; | |||||
| if (lilvPlugin.get_uis().size() > 0) | |||||
| 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 (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me)) | |||||
| { | |||||
| if (const char* const name = lilv_node_as_string(nameNode)) | |||||
| sname = name; | |||||
| lilv_node_free(nameNode); | |||||
| } | |||||
| if (const char* const author = lilvPlugin.get_author_name().as_string()) | |||||
| smaker = author; | |||||
| 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; | |||||
| } | |||||
| 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; | |||||
| } | |||||
| #ifndef CARLA_UTILS_CACHED_PLUGINS_ONLY | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| 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>" | |||||
| "<li>VST2 plugin support using VeSTige header by Javier Serrano Polo</li>" | |||||
| // Sample kit libraries | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "<li>FluidSynth library for SF2/3 support</li>" | |||||
| #endif | |||||
| "<li>SFZero module for SFZ support</li>" | |||||
| // misc libs | |||||
| "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</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 v" RTAUDIO_VERSION " and RtMidi v" RTMIDI_VERSION " for native Audio and MIDI support</li>" | |||||
| // Internal plugins | |||||
| "<li>MIDI Sequencer UI code by Perry Nguyen</li>" | |||||
| // External plugins | |||||
| #ifdef HAVE_EXTERNAL_PLUGINS | |||||
| "<li>Nekobi plugin code based on nekobee by Sean Bolton and others</li>" | |||||
| "<li>VectorJuice and WobbleJuice plugin code by Andre Sklenar</li>" | |||||
| # ifdef HAVE_ZYN_DEPS | |||||
| "<li>ZynAddSubFX plugin code by Mark McCurry and Nasca Octavian Paul</li>" | |||||
| # endif | |||||
| #endif // HAVE_EXTERNAL_PLUGINS | |||||
| // end | |||||
| "</ul>"; | |||||
| } | |||||
| return retText; | |||||
| } | |||||
| const char* const* carla_get_supported_file_extensions() | |||||
| { | |||||
| carla_debug("carla_get_supported_file_extensions()"); | |||||
| // NOTE: please keep in sync with CarlaEngine::loadFile!! | |||||
| static const char* const extensions[] = { | |||||
| // Base types | |||||
| "carxp", "carxs", | |||||
| // plugin files and resources | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "sf2", "sf3", | |||||
| #endif | |||||
| #ifdef HAVE_ZYN_DEPS | |||||
| "xmz", "xiz", | |||||
| #endif | |||||
| #if defined(CARLA_OS_MAC) | |||||
| "vst", | |||||
| #else | |||||
| "dll", | |||||
| "so", | |||||
| #endif | |||||
| // Audio files | |||||
| #ifdef HAVE_SNDFILE | |||||
| "aif", "aifc", "aiff", "au", "bwf", "flac", "htk", "iff", "mat4", "mat5", "oga", "ogg", | |||||
| "paf", "pvf", "pvf5", "sd2", "sf", "snd", "svx", "vcc", "w64", "wav", "xi", | |||||
| #endif | |||||
| #ifdef HAVE_FFMPEG | |||||
| "3g2", "3gp", "aac", "ac3", "amr", "ape", "mp2", "mp3", "mpc", "wma", | |||||
| # ifdef HAVE_SNDFILE | |||||
| // FFmpeg without sndfile | |||||
| "flac", "oga", "ogg", "w64", "wav", | |||||
| # endif | |||||
| #endif | |||||
| // MIDI files | |||||
| "mid", "midi", | |||||
| // SFZ | |||||
| "sfz", | |||||
| // terminator | |||||
| nullptr | |||||
| }; | |||||
| return extensions; | |||||
| } | |||||
| const char* const* carla_get_supported_features() | |||||
| { | |||||
| carla_debug("carla_get_supported_features()"); | |||||
| static const char* const features[] = { | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "sf2", | |||||
| #endif | |||||
| #ifdef HAVE_HYLIA | |||||
| "link", | |||||
| #endif | |||||
| #ifdef HAVE_LIBLO | |||||
| "osc", | |||||
| #endif | |||||
| #if defined(HAVE_LIBMAGIC) || defined(CARLA_OS_WIN) | |||||
| "bridges", | |||||
| #endif | |||||
| #ifdef HAVE_PYQT | |||||
| "gui", | |||||
| #endif | |||||
| nullptr | |||||
| }; | |||||
| return features; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void carla_fflush(bool err) | |||||
| { | |||||
| std::fflush(err ? stderr : stdout); | |||||
| } | |||||
| void carla_fputs(bool err, const char* string) | |||||
| { | |||||
| std::fputs(string, err ? stderr : stdout); | |||||
| } | |||||
| void carla_set_process_name(const char* name) | |||||
| { | |||||
| carla_debug("carla_set_process_name(\"%s\")", name); | |||||
| CarlaThread::setCurrentThreadName(name); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| class CarlaPipeClientPlugin : public CarlaPipeClient | |||||
| { | |||||
| public: | |||||
| CarlaPipeClientPlugin(const CarlaPipeCallbackFunc callbackFunc, void* const callbackPtr) noexcept | |||||
| : CarlaPipeClient(), | |||||
| fCallbackFunc(callbackFunc), | |||||
| fCallbackPtr(callbackPtr), | |||||
| fLastReadLine(nullptr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT(fCallbackFunc != nullptr); | |||||
| } | |||||
| ~CarlaPipeClientPlugin() override | |||||
| { | |||||
| if (fLastReadLine != nullptr) | |||||
| { | |||||
| delete[] fLastReadLine; | |||||
| fLastReadLine = nullptr; | |||||
| } | |||||
| } | |||||
| const char* readlineblock(const uint timeout) noexcept | |||||
| { | |||||
| delete[] fLastReadLine; | |||||
| fLastReadLine = CarlaPipeClient::_readlineblock(timeout); | |||||
| return fLastReadLine; | |||||
| } | |||||
| bool msgReceived(const char* const msg) noexcept override | |||||
| { | |||||
| if (fCallbackFunc != nullptr) | |||||
| { | |||||
| try { | |||||
| fCallbackFunc(fCallbackPtr, msg); | |||||
| } CARLA_SAFE_EXCEPTION("msgReceived"); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| const CarlaPipeCallbackFunc fCallbackFunc; | |||||
| void* const fCallbackPtr; | |||||
| const char* fLastReadLine; | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeClientPlugin) | |||||
| }; | |||||
| CarlaPipeClientHandle carla_pipe_client_new(const char* argv[], CarlaPipeCallbackFunc callbackFunc, void* callbackPtr) | |||||
| { | |||||
| carla_debug("carla_pipe_client_new(%p, %p, %p)", argv, callbackFunc, callbackPtr); | |||||
| CarlaPipeClientPlugin* const pipe(new CarlaPipeClientPlugin(callbackFunc, callbackPtr)); | |||||
| if (! pipe->initPipeClient(argv)) | |||||
| { | |||||
| delete pipe; | |||||
| return nullptr; | |||||
| } | |||||
| return pipe; | |||||
| } | |||||
| void carla_pipe_client_idle(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| ((CarlaPipeClientPlugin*)handle)->idlePipe(); | |||||
| } | |||||
| bool carla_pipe_client_is_running(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((CarlaPipeClientPlugin*)handle)->isPipeRunning(); | |||||
| } | |||||
| void carla_pipe_client_lock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| return ((CarlaPipeClientPlugin*)handle)->lockPipe(); | |||||
| } | |||||
| void carla_pipe_client_unlock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| return ((CarlaPipeClientPlugin*)handle)->unlockPipe(); | |||||
| } | |||||
| const char* carla_pipe_client_readlineblock(CarlaPipeClientHandle handle, uint timeout) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); | |||||
| return ((CarlaPipeClientPlugin*)handle)->readlineblock(timeout); | |||||
| } | |||||
| bool carla_pipe_client_write_msg(CarlaPipeClientHandle handle, const char* msg) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((CarlaPipeClientPlugin*)handle)->writeMessage(msg); | |||||
| } | |||||
| bool carla_pipe_client_write_and_fix_msg(CarlaPipeClientHandle handle, const char* msg) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((CarlaPipeClientPlugin*)handle)->writeAndFixMessage(msg); | |||||
| } | |||||
| bool carla_pipe_client_flush(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((CarlaPipeClientPlugin*)handle)->flushMessages(); | |||||
| } | |||||
| bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| CarlaPipeClientPlugin* const pipe((CarlaPipeClientPlugin*)handle); | |||||
| const bool ret(pipe->flushMessages()); | |||||
| pipe->unlockPipe(); | |||||
| return ret; | |||||
| } | |||||
| void carla_pipe_client_destroy(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| carla_debug("carla_pipe_client_destroy(%p)", handle); | |||||
| CarlaPipeClientPlugin* const pipe((CarlaPipeClientPlugin*)handle); | |||||
| pipe->closePipeClient(); | |||||
| delete pipe; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* carla_get_library_filename() | |||||
| { | |||||
| carla_debug("carla_get_library_filename()"); | |||||
| static CarlaString ret; | |||||
| if (ret.isEmpty()) | |||||
| { | |||||
| using water::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 water::File; | |||||
| ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8(); | |||||
| } | |||||
| return ret; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(winId1 != 0,); | |||||
| CARLA_SAFE_ASSERT_RETURN(winId2 != 0,); | |||||
| #ifdef HAVE_X11 | |||||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| XReparentWindow(disp, winId1, winId2, 0, 0); | |||||
| XMapWindow(disp, winId1); | |||||
| XCloseDisplay(disp); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| void carla_x11_move_window(uintptr_t winId, int x, int y) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(winId != 0,); | |||||
| #ifdef HAVE_X11 | |||||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| XMoveWindow(disp, winId, x, y); | |||||
| XCloseDisplay(disp); | |||||
| } | |||||
| #else | |||||
| // unused | |||||
| return; (void)x; (void)y; | |||||
| #endif | |||||
| } | |||||
| int* carla_x11_get_window_pos(uintptr_t winId) | |||||
| { | |||||
| static int pos[2]; | |||||
| if (winId == 0) | |||||
| { | |||||
| pos[0] = 0; | |||||
| pos[1] = 0; | |||||
| } | |||||
| #ifdef HAVE_X11 | |||||
| else if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| int x, y; | |||||
| Window child; | |||||
| XWindowAttributes xwa; | |||||
| XTranslateCoordinates(disp, winId, XRootWindow(disp, 0), 0, 0, &x, &y, &child); | |||||
| XGetWindowAttributes(disp, winId, &xwa); | |||||
| XCloseDisplay(disp); | |||||
| pos[0] = x - xwa.x; | |||||
| pos[1] = y - xwa.y; | |||||
| } | |||||
| #endif | |||||
| else | |||||
| { | |||||
| pos[0] = 0; | |||||
| pos[1] = 0; | |||||
| } | |||||
| return pos; | |||||
| } | |||||
| int carla_cocoa_get_window(void* nsViewPtr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(nsViewPtr != nullptr, 0); | |||||
| #ifdef CARLA_OS_MAC | |||||
| NSView* nsView = (NSView*)nsViewPtr; | |||||
| return [[nsView window] windowNumber]; | |||||
| #else | |||||
| return 0; | |||||
| #endif | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #include "CarlaPipeUtils.cpp" | |||||
| #if !(defined(DEBUG) || defined(BUILDING_CARLA_FOR_WINDOWS)) | |||||
| # include "water/misc/Time.cpp" | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #endif // CARLA_UTILS_CACHED_PLUGINS_ONLY | |||||
| @@ -49,6 +49,14 @@ typedef void (*CarlaPipeCallbackFunc)(void* ptr, const char* msg); | |||||
| * @see carla_get_cached_plugin_info() | * @see carla_get_cached_plugin_info() | ||||
| */ | */ | ||||
| typedef struct _CarlaCachedPluginInfo { | typedef struct _CarlaCachedPluginInfo { | ||||
| /*! | |||||
| * Wherever the data in this struct is valid. | |||||
| * For performance reasons, plugins are only checked on request, | |||||
| * and as such, the count vs number of really valid plugins might not match. | |||||
| * Use this field to skip on plugins which cannot be loaded in Carla. | |||||
| */ | |||||
| bool valid; | |||||
| /*! | /*! | ||||
| * Plugin category. | * Plugin category. | ||||
| */ | */ | ||||
| @@ -141,7 +149,7 @@ CARLA_EXPORT const char* const* carla_get_supported_features(); | |||||
| /*! | /*! | ||||
| * Get how many cached plugins are available. | * Get how many cached plugins are available. | ||||
| * Internal, LV2 and AU plugin formats are cached and need to be discovered via this function. | |||||
| * Internal and LV2 plugin formats are cached and need to be discovered via this function. | |||||
| * Do not call this for any other plugin formats. | * Do not call this for any other plugin formats. | ||||
| */ | */ | ||||
| CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); | CARLA_EXPORT uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath); | ||||
| @@ -13,12 +13,8 @@ OBJS_standalone = \ | |||||
| $(OBJDIR)/CarlaStandalone.cpp.o \ | $(OBJDIR)/CarlaStandalone.cpp.o \ | ||||
| $(OBJDIR)/CarlaStandaloneNSM.cpp.o | $(OBJDIR)/CarlaStandaloneNSM.cpp.o | ||||
| OBJS_utils = \ | |||||
| $(OBJDIR)/CarlaUtils.cpp.o | |||||
| TARGETS = \ | TARGETS = \ | ||||
| $(BINDIR)/libcarla_standalone2$(LIB_EXT) \ | |||||
| $(BINDIR)/libcarla_utils$(LIB_EXT) | |||||
| $(BINDIR)/libcarla_standalone2$(LIB_EXT) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -44,9 +40,6 @@ endif | |||||
| STANDALONE_LIBS += $(MODULEDIR)/rtaudio.a | STANDALONE_LIBS += $(MODULEDIR)/rtaudio.a | ||||
| STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a | STANDALONE_LIBS += $(MODULEDIR)/rtmidi.a | ||||
| UTILS_LIBS += $(MODULEDIR)/lilv.a | |||||
| UTILS_LIBS += $(MODULEDIR)/water.files.a | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| STANDALONE_LINK_FLAGS = $(JACKBRIDGE_LIBS) | STANDALONE_LINK_FLAGS = $(JACKBRIDGE_LIBS) | ||||
| @@ -61,30 +54,20 @@ STANDALONE_LINK_FLAGS += $(RTMIDI_LIBS) | |||||
| STANDALONE_LINK_FLAGS += $(LIBLO_LIBS) | STANDALONE_LINK_FLAGS += $(LIBLO_LIBS) | ||||
| STANDALONE_LINK_FLAGS += $(MAGIC_LIBS) | STANDALONE_LINK_FLAGS += $(MAGIC_LIBS) | ||||
| STANDALONE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | STANDALONE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | ||||
| STANDALONE_LINK_FLAGS += $(LINUXSAMPLER_LIBS) | |||||
| STANDALONE_LINK_FLAGS += $(X11_LIBS) | STANDALONE_LINK_FLAGS += $(X11_LIBS) | ||||
| UTILS_LINK_FLAGS += $(LILV_LIBS) | |||||
| UTILS_LINK_FLAGS += $(WATER_LIBS) | |||||
| ifeq ($(HAVE_X11),true) | |||||
| UTILS_LINK_FLAGS += $(X11_LIBS) | |||||
| endif | |||||
| ifneq ($(HAIKU),true) | |||||
| UTILS_LINK_FLAGS += -lpthread | |||||
| endif | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| all: $(TARGETS) | all: $(TARGETS) | ||||
| $(MAKE) -C utils | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| clean: | clean: | ||||
| rm -f $(OBJS_standalone) $(OBJS_utils) $(TARGETS) | |||||
| rm -f $(OBJS_standalone) $(TARGETS) | |||||
| $(MAKE) clean -C engine | $(MAKE) clean -C engine | ||||
| $(MAKE) clean -C plugin | $(MAKE) clean -C plugin | ||||
| $(MAKE) clean -C utils | |||||
| debug: | debug: | ||||
| $(MAKE) DEBUG=true | $(MAKE) DEBUG=true | ||||
| @@ -99,11 +82,6 @@ $(BINDIR)/libcarla_standalone2$(LIB_EXT): $(OBJS_standalone) $(STANDALONE_LIBS) | |||||
| @echo "Linking libcarla_standalone2$(LIB_EXT)" | @echo "Linking libcarla_standalone2$(LIB_EXT)" | ||||
| @$(CXX) $(OBJS_standalone) $(LIBS_START) $(STANDALONE_LIBS) $(LIBS_END) $(LINK_FLAGS) $(STANDALONE_LINK_FLAGS) $(SHARED) -o $@ | @$(CXX) $(OBJS_standalone) $(LIBS_START) $(STANDALONE_LIBS) $(LIBS_END) $(LINK_FLAGS) $(STANDALONE_LINK_FLAGS) $(SHARED) -o $@ | ||||
| $(BINDIR)/libcarla_utils$(LIB_EXT): $(OBJS_utils) $(UTILS_LIBS) | |||||
| -@mkdir -p $(BINDIR) | |||||
| @echo "Linking libcarla_utils$(LIB_EXT)" | |||||
| @$(CXX) $(OBJS_utils) $(LIBS_START) $(UTILS_LIBS) $(LIBS_END) $(LINK_FLAGS) $(UTILS_LINK_FLAGS) $(SHARED) -o $@ | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| @@ -111,11 +89,6 @@ $(OBJDIR)/CarlaStandalone.cpp.o: CarlaStandalone.cpp | |||||
| -@mkdir -p $(OBJDIR) | -@mkdir -p $(OBJDIR) | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | ||||
| $(OBJDIR)/CarlaUtils.cpp.o: CarlaUtils.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||||
| endif | endif | ||||
| $(OBJDIR)/%.cpp.o: %.cpp | $(OBJDIR)/%.cpp.o: %.cpp | ||||
| @@ -124,6 +97,5 @@ $(OBJDIR)/%.cpp.o: %.cpp | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
| -include $(OBJS_standalone:%.o=%.d) | -include $(OBJS_standalone:%.o=%.d) | ||||
| -include $(OBJS_utils:%.o=%.d) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -118,7 +118,7 @@ const char* const* CarlaEngine::getDriverDeviceNames(const uint index2) | |||||
| if (jackbridge_is_ok() && index-- == 0) | if (jackbridge_is_ok() && index-- == 0) | ||||
| { | { | ||||
| static const char* ret[3] = { "Auto-Connect OFF", "Auto-Connect ON", nullptr }; | |||||
| static const char* ret[3] = { "Auto-Connect ON", "Auto-Connect OFF", nullptr }; | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -142,10 +142,9 @@ const EngineDriverDeviceInfo* CarlaEngine::getDriverDeviceInfo(const uint index2 | |||||
| if (jackbridge_is_ok() && index-- == 0) | if (jackbridge_is_ok() && index-- == 0) | ||||
| { | { | ||||
| static uint32_t bufSizes[11] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 }; | |||||
| static EngineDriverDeviceInfo devInfo; | static EngineDriverDeviceInfo devInfo; | ||||
| devInfo.hints = ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE; | devInfo.hints = ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE; | ||||
| devInfo.bufferSizes = bufSizes; | |||||
| devInfo.bufferSizes = nullptr; | |||||
| devInfo.sampleRates = nullptr; | devInfo.sampleRates = nullptr; | ||||
| return &devInfo; | return &devInfo; | ||||
| } | } | ||||
| @@ -285,7 +284,7 @@ void CarlaEngine::idle() noexcept | |||||
| } | } | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| pData->osc.idle(); | pData->osc.idle(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -303,7 +302,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| const void* const extra, const uint options) | const void* const extra, const uint options) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId <= pData->maxPluginNumber, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId <= pData->maxPluginNumber, "Invalid engine internal data"); | ||||
| #endif | #endif | ||||
| @@ -315,7 +314,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| uint id; | uint id; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CarlaPlugin* oldPlugin = nullptr; | CarlaPlugin* oldPlugin = nullptr; | ||||
| if (pData->nextPluginId < pData->curPluginCount) | if (pData->nextPluginId < pData->curPluginCount) | ||||
| @@ -338,7 +337,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| return false; | return false; | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins[id].plugin == nullptr, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins[id].plugin == nullptr, "Invalid engine internal data"); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -486,7 +485,6 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| plugin->reload(); | plugin->reload(); | ||||
| #ifndef BUILD_BRIDGE | |||||
| bool canRun = true; | bool canRun = true; | ||||
| /**/ if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | /**/ if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | ||||
| @@ -517,11 +515,6 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| return false; | return false; | ||||
| } | } | ||||
| # ifdef HAVE_LIBLO | |||||
| plugin->registerToOscClient(); | |||||
| # endif | |||||
| #endif | |||||
| EnginePluginData& pluginData(pData->plugins[id]); | EnginePluginData& pluginData(pData->plugins[id]); | ||||
| pluginData.plugin = plugin; | pluginData.plugin = plugin; | ||||
| pluginData.insPeak[0] = 0.0f; | pluginData.insPeak[0] = 0.0f; | ||||
| @@ -529,7 +522,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| pluginData.outsPeak[0] = 0.0f; | pluginData.outsPeak[0] = 0.0f; | ||||
| pluginData.outsPeak[1] = 0.0f; | pluginData.outsPeak[1] = 0.0f; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (oldPlugin != nullptr) | if (oldPlugin != nullptr) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT(! pData->loadingProject); | CARLA_SAFE_ASSERT(! pData->loadingProject); | ||||
| @@ -559,18 +552,24 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||||
| else if (! pData->loadingProject) | else if (! pData->loadingProject) | ||||
| #endif | #endif | ||||
| { | { | ||||
| plugin->setActive(true, true, false); | |||||
| plugin->setEnabled(true); | plugin->setEnabled(true); | ||||
| ++pData->curPluginCount; | ++pData->curPluginCount; | ||||
| callback(ENGINE_CALLBACK_PLUGIN_ADDED, id, 0, 0, 0.0f, plugin->getName()); | callback(ENGINE_CALLBACK_PLUGIN_ADDED, id, 0, 0, 0.0f, plugin->getName()); | ||||
| #ifndef BUILD_BRIDGE | |||||
| if (getType() != kEngineTypeBridge) | |||||
| plugin->setActive(true, false, true); | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| pData->graph.addPlugin(plugin); | pData->graph.addPlugin(plugin); | ||||
| #endif | #endif | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| plugin->registerToOscClient(); | |||||
| #endif | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -582,7 +581,7 @@ bool CarlaEngine::addPlugin(const PluginType ptype, const char* const filename, | |||||
| bool CarlaEngine::removePlugin(const uint id) | bool CarlaEngine::removePlugin(const uint id) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->curPluginCount != 0, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->curPluginCount != 0, "Invalid engine internal data"); | ||||
| #endif | #endif | ||||
| @@ -597,7 +596,7 @@ bool CarlaEngine::removePlugin(const uint id) | |||||
| const ScopedThreadStopper sts(this); | const ScopedThreadStopper sts(this); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| pData->graph.removePlugin(plugin); | pData->graph.removePlugin(plugin); | ||||
| @@ -612,7 +611,7 @@ bool CarlaEngine::removePlugin(const uint id) | |||||
| } | } | ||||
| */ | */ | ||||
| # ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (isOscControlRegistered()) | if (isOscControlRegistered()) | ||||
| oscSend_control_remove_plugin(id); | oscSend_control_remove_plugin(id); | ||||
| # endif | # endif | ||||
| @@ -630,7 +629,7 @@ bool CarlaEngine::removePlugin(const uint id) | |||||
| bool CarlaEngine::removeAllPlugins() | bool CarlaEngine::removeAllPlugins() | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins != nullptr, "Invalid engine internal data"); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId == pData->maxPluginNumber, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextPluginId == pData->maxPluginNumber, "Invalid engine internal data"); | ||||
| #endif | #endif | ||||
| @@ -644,11 +643,11 @@ bool CarlaEngine::removeAllPlugins() | |||||
| const uint curPluginCount(pData->curPluginCount); | const uint curPluginCount(pData->curPluginCount); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| pData->graph.removeAllPlugins(); | pData->graph.removeAllPlugins(); | ||||
| # ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (isOscControlRegistered()) | if (isOscControlRegistered()) | ||||
| { | { | ||||
| for (uint i=0; i < curPluginCount; ++i) | for (uint i=0; i < curPluginCount; ++i) | ||||
| @@ -682,7 +681,7 @@ bool CarlaEngine::removeAllPlugins() | |||||
| return true; | return true; | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| const char* CarlaEngine::renamePlugin(const uint id, const char* const newName) | const char* CarlaEngine::renamePlugin(const uint id, const char* const newName) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | CARLA_SAFE_ASSERT_RETURN_ERRN(pData->isIdling == 0, "An operation is still being processed, please wait for it to finish"); | ||||
| @@ -810,7 +809,7 @@ bool CarlaEngine::switchPlugins(const uint idA, const uint idB) noexcept | |||||
| CarlaPlugin* CarlaEngine::getPlugin(const uint id) const noexcept | CarlaPlugin* CarlaEngine::getPlugin(const uint id) const noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(pData->plugins != nullptr, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERRN(pData->plugins != nullptr, "Invalid engine internal data"); | ||||
| CARLA_SAFE_ASSERT_RETURN_ERRN(pData->curPluginCount != 0, "Invalid engine internal data"); | CARLA_SAFE_ASSERT_RETURN_ERRN(pData->curPluginCount != 0, "Invalid engine internal data"); | ||||
| #endif | #endif | ||||
| @@ -1127,7 +1126,7 @@ const EngineOptions& CarlaEngine::getOptions() const noexcept | |||||
| return pData->options; | return pData->options; | ||||
| } | } | ||||
| const EngineTimeInfo& CarlaEngine::getTimeInfo() const noexcept | |||||
| EngineTimeInfo CarlaEngine::getTimeInfo() const noexcept | |||||
| { | { | ||||
| return pData->timeInfo; | return pData->timeInfo; | ||||
| } | } | ||||
| @@ -1171,11 +1170,11 @@ float CarlaEngine::getOutputPeak(const uint pluginId, const bool isLeft) const n | |||||
| void CarlaEngine::callback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr) noexcept | void CarlaEngine::callback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr) noexcept | ||||
| { | { | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| if (action != ENGINE_CALLBACK_IDLE) | |||||
| if (action != ENGINE_CALLBACK_IDLE && action != ENGINE_CALLBACK_NOTE_ON && action != ENGINE_CALLBACK_NOTE_OFF) | |||||
| carla_debug("CarlaEngine::callback(%i:%s, %i, %i, %i, %f, \"%s\")", action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr); | carla_debug("CarlaEngine::callback(%i:%s, %i, %i, %i, %f, \"%s\")", action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr); | ||||
| #endif | #endif | ||||
| #ifdef BUILD_BRIDGE | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->isIdling) | if (pData->isIdling) | ||||
| #else | #else | ||||
| if (pData->isIdling && action != ENGINE_CALLBACK_PATCHBAY_CLIENT_DATA_CHANGED) | if (pData->isIdling && action != ENGINE_CALLBACK_PATCHBAY_CLIENT_DATA_CHANGED) | ||||
| @@ -1301,6 +1300,13 @@ bool CarlaEngine::setAboutToClose() noexcept | |||||
| return (pData->isIdling == 0); | return (pData->isIdling == 0); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool CarlaEngine::isLoadingProject() const noexcept | |||||
| { | |||||
| return pData->loadingProject; | |||||
| } | |||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Global options | // Global options | ||||
| @@ -1363,7 +1369,7 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||||
| break; | break; | ||||
| case ENGINE_OPTION_PREFER_PLUGIN_BRIDGES: | case ENGINE_OPTION_PREFER_PLUGIN_BRIDGES: | ||||
| #ifdef BUILD_BRIDGE | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN(value == 0,); | CARLA_SAFE_ASSERT_RETURN(value == 0,); | ||||
| #else | #else | ||||
| CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,); | CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,); | ||||
| @@ -1518,7 +1524,7 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||||
| pData->options.frontendWinId = static_cast<uintptr_t>(winId); | pData->options.frontendWinId = static_cast<uintptr_t>(winId); | ||||
| } break; | } break; | ||||
| #ifndef CARLA_OS_WIN | |||||
| #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN) | |||||
| case ENGINE_OPTION_WINE_EXECUTABLE: | case ENGINE_OPTION_WINE_EXECUTABLE: | ||||
| CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',); | CARLA_SAFE_ASSERT_RETURN(valueStr != nullptr && valueStr[0] != '\0',); | ||||
| @@ -1563,30 +1569,42 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||||
| } | } | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #ifndef BUILD_BRIDGE | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // OSC Stuff | // OSC Stuff | ||||
| # ifndef BUILD_BRIDGE | |||||
| bool CarlaEngine::isOscControlRegistered() const noexcept | bool CarlaEngine::isOscControlRegistered() const noexcept | ||||
| { | { | ||||
| # ifdef HAVE_LIBLO | |||||
| return pData->osc.isControlRegistered(); | return pData->osc.isControlRegistered(); | ||||
| } | |||||
| # else | |||||
| return false; | |||||
| # endif | # endif | ||||
| } | |||||
| void CarlaEngine::idleOsc() const noexcept | void CarlaEngine::idleOsc() const noexcept | ||||
| { | { | ||||
| # ifdef HAVE_LIBLO | |||||
| pData->osc.idle(); | pData->osc.idle(); | ||||
| # endif | |||||
| } | } | ||||
| const char* CarlaEngine::getOscServerPathTCP() const noexcept | const char* CarlaEngine::getOscServerPathTCP() const noexcept | ||||
| { | { | ||||
| # ifdef HAVE_LIBLO | |||||
| return pData->osc.getServerPathTCP(); | return pData->osc.getServerPathTCP(); | ||||
| # else | |||||
| return nullptr; | |||||
| # endif | |||||
| } | } | ||||
| const char* CarlaEngine::getOscServerPathUDP() const noexcept | const char* CarlaEngine::getOscServerPathUDP() const noexcept | ||||
| { | { | ||||
| # ifdef HAVE_LIBLO | |||||
| return pData->osc.getServerPathUDP(); | return pData->osc.getServerPathUDP(); | ||||
| # else | |||||
| return nullptr; | |||||
| # endif | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -1605,7 +1623,7 @@ void CarlaEngine::bufferSizeChanged(const uint32_t newBufferSize) | |||||
| { | { | ||||
| carla_debug("CarlaEngine::bufferSizeChanged(%i)", newBufferSize); | carla_debug("CarlaEngine::bufferSizeChanged(%i)", newBufferSize); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | ||||
| pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| { | { | ||||
| @@ -1630,7 +1648,7 @@ void CarlaEngine::sampleRateChanged(const double newSampleRate) | |||||
| { | { | ||||
| carla_debug("CarlaEngine::sampleRateChanged(%g)", newSampleRate); | carla_debug("CarlaEngine::sampleRateChanged(%g)", newSampleRate); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | ||||
| pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| { | { | ||||
| @@ -1655,7 +1673,7 @@ void CarlaEngine::offlineModeChanged(const bool isOfflineNow) | |||||
| { | { | ||||
| carla_debug("CarlaEngine::offlineModeChanged(%s)", bool2str(isOfflineNow)); | carla_debug("CarlaEngine::offlineModeChanged(%s)", bool2str(isOfflineNow)); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | ||||
| pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| { | { | ||||
| @@ -1691,7 +1709,7 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons | |||||
| if (plugin != nullptr && plugin->isEnabled()) | if (plugin != nullptr && plugin->isEnabled()) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // deactivate bridge client-side ping check, since some plugins block during save | // deactivate bridge client-side ping check, since some plugins block during save | ||||
| if (plugin->getHints() & PLUGIN_IS_BRIDGE) | if (plugin->getHints() & PLUGIN_IS_BRIDGE) | ||||
| plugin->setCustomData(CUSTOM_DATA_TYPE_STRING, "__CarlaPingOnOff__", "false", false); | plugin->setCustomData(CUSTOM_DATA_TYPE_STRING, "__CarlaPingOnOff__", "false", false); | ||||
| @@ -1771,7 +1789,7 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons | |||||
| } | } | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // tell bridges we're done saving | // tell bridges we're done saving | ||||
| for (uint i=0; i < pData->curPluginCount; ++i) | for (uint i=0; i < pData->curPluginCount; ++i) | ||||
| { | { | ||||
| @@ -1935,7 +1953,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||||
| return false; | return false; | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| const ScopedValueSetter<bool> _svs(pData->loadingProject, true, false); | const ScopedValueSetter<bool> _svs(pData->loadingProject, true, false); | ||||
| #endif | #endif | ||||
| @@ -2033,7 +2051,16 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||||
| } | } | ||||
| } | } | ||||
| CARLA_SAFE_ASSERT_CONTINUE(option != -1); | |||||
| if (option == -1) | |||||
| { | |||||
| // check old stuff, unhandled now | |||||
| if (tag == "GIG_PATH") | |||||
| continue; | |||||
| // hmm something is wrong.. | |||||
| carla_stderr2("CarlaEngine::loadProjectInternal() - Unhandled option '%s'", tag.toRawUTF8()); | |||||
| continue; | |||||
| } | |||||
| setOption(static_cast<EngineOption>(option), value, valueStr); | setOption(static_cast<EngineOption>(option), value, valueStr); | ||||
| } | } | ||||
| @@ -2206,7 +2233,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||||
| if (addPlugin(getBinaryTypeFromFile(stateSave.binary), ptype, stateSave.binary, | if (addPlugin(getBinaryTypeFromFile(stateSave.binary), ptype, stateSave.binary, | ||||
| stateSave.name, stateSave.label, stateSave.uniqueId, extraStuff, stateSave.options)) | stateSave.name, stateSave.label, stateSave.uniqueId, extraStuff, stateSave.options)) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| const uint pluginId = pData->curPluginCount; | const uint pluginId = pData->curPluginCount; | ||||
| #else | #else | ||||
| const uint pluginId = 0; | const uint pluginId = 0; | ||||
| @@ -2229,16 +2256,12 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||||
| * When project is loading we do not enable the plugin right away, | * When project is loading we do not enable the plugin right away, | ||||
| * as we want to load state first. | * as we want to load state first. | ||||
| */ | */ | ||||
| #ifdef BUILD_BRIDGE | |||||
| plugin->setActive(true, true, false); | |||||
| #else | |||||
| ++pData->curPluginCount; | |||||
| #endif | |||||
| plugin->setEnabled(true); | plugin->setEnabled(true); | ||||
| ++pData->curPluginCount; | |||||
| callback(ENGINE_CALLBACK_PLUGIN_ADDED, pluginId, 0, 0, 0.0f, plugin->getName()); | callback(ENGINE_CALLBACK_PLUGIN_ADDED, pluginId, 0, 0, 0.0f, plugin->getName()); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| pData->graph.addPlugin(plugin); | pData->graph.addPlugin(plugin); | ||||
| #endif | #endif | ||||
| @@ -2258,7 +2281,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||||
| return true; | return true; | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // tell bridges we're done loading | // tell bridges we're done loading | ||||
| for (uint i=0; i < pData->curPluginCount; ++i) | for (uint i=0; i < pData->curPluginCount; ++i) | ||||
| { | { | ||||
| @@ -190,7 +190,7 @@ public: | |||||
| shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || | shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || | ||||
| shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | ||||
| { | { | ||||
| carla_stderr2("CarlaJackAppClient: data size mismatch"); | |||||
| carla_stderr2("CarlaEngineBridge: data size mismatch"); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -713,7 +713,7 @@ public: | |||||
| const float value(fShmNonRtClientControl.readFloat()); | const float value(fShmNonRtClientControl.readFloat()); | ||||
| if (plugin != nullptr && plugin->isEnabled()) | if (plugin != nullptr && plugin->isEnabled()) | ||||
| plugin->setParameterValue(index, value, true, false, false); | |||||
| plugin->setParameterValue(index, value, false, false, false); | |||||
| break; | break; | ||||
| } | } | ||||
| @@ -1411,14 +1411,6 @@ CARLA_BACKEND_END_NAMESPACE | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #if defined(CARLA_OS_WIN) && ! defined(__WINE__) | |||||
| extern "C" __declspec (dllexport) | |||||
| #else | |||||
| extern "C" __attribute__ ((visibility("default"))) | |||||
| #endif | |||||
| void carla_register_native_plugin_carla(); | |||||
| void carla_register_native_plugin_carla(){} | |||||
| #include "CarlaBridgeUtils.cpp" | #include "CarlaBridgeUtils.cpp" | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -304,6 +304,17 @@ EngineTimeInfoBBT::EngineTimeInfoBBT() noexcept | |||||
| ticksPerBeat(0.0), | ticksPerBeat(0.0), | ||||
| beatsPerMinute(0.0) {} | beatsPerMinute(0.0) {} | ||||
| EngineTimeInfoBBT::EngineTimeInfoBBT(const EngineTimeInfoBBT& bbt) noexcept | |||||
| : valid(bbt.valid), | |||||
| bar(bbt.bar), | |||||
| beat(bbt.beat), | |||||
| tick(bbt.tick), | |||||
| barStartTick(bbt.barStartTick), | |||||
| beatsPerBar(bbt.beatsPerBar), | |||||
| beatType(bbt.beatType), | |||||
| ticksPerBeat(bbt.ticksPerBeat), | |||||
| beatsPerMinute(bbt.beatsPerMinute) {} | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // EngineTimeInfo | // EngineTimeInfo | ||||
| @@ -321,6 +332,30 @@ void EngineTimeInfo::clear() noexcept | |||||
| carla_zeroStruct(bbt); | carla_zeroStruct(bbt); | ||||
| } | } | ||||
| EngineTimeInfo::EngineTimeInfo(const EngineTimeInfo& info) noexcept | |||||
| : playing(info.playing), | |||||
| frame(info.frame), | |||||
| usecs(info.usecs), | |||||
| bbt(info.bbt) {} | |||||
| EngineTimeInfo& EngineTimeInfo::operator=(const EngineTimeInfo& info) noexcept | |||||
| { | |||||
| playing = info.playing; | |||||
| frame = info.frame; | |||||
| usecs = info.usecs; | |||||
| bbt.valid = info.bbt.valid; | |||||
| bbt.bar = info.bbt.bar; | |||||
| bbt.tick = info.bbt.tick; | |||||
| bbt.tick = info.bbt.tick; | |||||
| bbt.barStartTick = info.bbt.barStartTick; | |||||
| bbt.beatsPerBar = info.bbt.beatsPerBar; | |||||
| bbt.beatType = info.bbt.beatType; | |||||
| bbt.ticksPerBeat = info.bbt.ticksPerBeat; | |||||
| bbt.beatsPerMinute = info.bbt.beatsPerMinute; | |||||
| return *this; | |||||
| } | |||||
| bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept | bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept | ||||
| { | { | ||||
| if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.bbt.valid != bbt.valid) | if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.bbt.valid != bbt.valid) | ||||
| @@ -176,10 +176,11 @@ void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept | |||||
| double ticktmp; | double ticktmp; | ||||
| timeInfo.usecs = 0; | |||||
| if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | ||||
| { | |||||
| timeInfo.usecs = 0; | |||||
| timeInfo.frame = nextFrame; | timeInfo.frame = nextFrame; | ||||
| } | |||||
| if (needsReset) | if (needsReset) | ||||
| { | { | ||||
| @@ -256,74 +257,19 @@ void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),); | CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),); | ||||
| CARLA_SAFE_ASSERT_RETURN(newFrames > 0,); | CARLA_SAFE_ASSERT_RETURN(newFrames > 0,); | ||||
| double ticktmp; | |||||
| if (needsReset) | |||||
| { | |||||
| pos->valid = JackPositionBBT; | |||||
| pos->beat_type = 4.0f; | |||||
| pos->ticks_per_beat = kTicksPerBeat; | |||||
| double abs_beat, abs_tick; | |||||
| #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE) | |||||
| if (hylia.enabled) | |||||
| { | |||||
| if (hylia.timeInfo.beat >= 0.0) | |||||
| { | |||||
| abs_beat = hylia.timeInfo.beat; | |||||
| abs_tick = abs_beat * kTicksPerBeat; | |||||
| } | |||||
| else | |||||
| { | |||||
| abs_beat = 0.0; | |||||
| abs_tick = 0.0; | |||||
| timeInfo.playing = false; | |||||
| } | |||||
| } | |||||
| else | |||||
| #endif | |||||
| { | |||||
| const double min = static_cast<double>(pos->frame) / (sampleRate * 60.0); | |||||
| abs_beat = min * beatsPerMinute; | |||||
| abs_tick = abs_beat * kTicksPerBeat; | |||||
| } | |||||
| const double bar = std::floor(abs_beat / beatsPerBar); | |||||
| const double beat = std::floor(std::fmod(abs_beat, beatsPerBar)); | |||||
| pos->bar = static_cast<int32_t>(bar) + 1; | |||||
| pos->beat = static_cast<int32_t>(beat) + 1; | |||||
| pos->bar_start_tick = ((bar * beatsPerBar) + beat) * kTicksPerBeat; | |||||
| ticktmp = abs_tick - pos->bar_start_tick; | |||||
| } | |||||
| else if (timeInfo.playing) | |||||
| { | |||||
| ticktmp = tick + (newFrames * kTicksPerBeat * beatsPerMinute / (sampleRate * 60.0)); | |||||
| while (ticktmp >= kTicksPerBeat) | |||||
| { | |||||
| ticktmp -= kTicksPerBeat; | |||||
| if (++pos->beat > beatsPerBar) | |||||
| { | |||||
| ++pos->bar; | |||||
| pos->beat = 1; | |||||
| pos->bar_start_tick += beatsPerBar * kTicksPerBeat; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| ticktmp = tick; | |||||
| } | |||||
| pos->beats_per_bar = static_cast<float>(beatsPerBar); | |||||
| CARLA_SAFE_ASSERT(transportMode == ENGINE_TRANSPORT_MODE_JACK); | |||||
| fillEngineTimeInfo(newFrames); | |||||
| pos->valid = JackPositionBBT; | |||||
| pos->bar = timeInfo.bbt.bar; | |||||
| pos->beat = timeInfo.bbt.beat; | |||||
| pos->tick = static_cast<int32_t>(tick + 0.5); | |||||
| pos->bar_start_tick = timeInfo.bbt.barStartTick; | |||||
| pos->beats_per_bar = timeInfo.bbt.beatsPerBar; | |||||
| pos->beat_type = timeInfo.bbt.beatType; | |||||
| pos->ticks_per_beat = kTicksPerBeat; | |||||
| pos->beats_per_minute = beatsPerMinute; | pos->beats_per_minute = beatsPerMinute; | ||||
| pos->tick = ticktmp; | |||||
| tick = ticktmp; | |||||
| } | } | ||||
| void EngineInternalTime::preProcess(const uint32_t numFrames) | void EngineInternalTime::preProcess(const uint32_t numFrames) | ||||
| @@ -418,7 +364,7 @@ void EngineNextAction::clearAndReset() noexcept | |||||
| CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept | CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept | ||||
| : thread(engine), | : thread(engine), | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| osc(engine), | osc(engine), | ||||
| oscData(nullptr), | oscData(nullptr), | ||||
| #endif | #endif | ||||
| @@ -426,7 +372,7 @@ CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept | |||||
| callbackPtr(nullptr), | callbackPtr(nullptr), | ||||
| fileCallback(nullptr), | fileCallback(nullptr), | ||||
| fileCallbackPtr(nullptr), | fileCallbackPtr(nullptr), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| loadingProject(false), | loadingProject(false), | ||||
| #endif | #endif | ||||
| hints(0x0), | hints(0x0), | ||||
| @@ -442,17 +388,17 @@ CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept | |||||
| name(), | name(), | ||||
| options(), | options(), | ||||
| timeInfo(), | timeInfo(), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| plugins(nullptr), | plugins(nullptr), | ||||
| #endif | #endif | ||||
| events(), | events(), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| graph(engine), | graph(engine), | ||||
| #endif | #endif | ||||
| time(timeInfo, options.transportMode), | time(timeInfo, options.transportMode), | ||||
| nextAction() | nextAction() | ||||
| { | { | ||||
| #ifdef BUILD_BRIDGE | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| carla_zeroStructs(plugins, 1); | carla_zeroStructs(plugins, 1); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -463,7 +409,7 @@ CarlaEngine::ProtectedData::~ProtectedData() noexcept | |||||
| CARLA_SAFE_ASSERT(maxPluginNumber == 0); | CARLA_SAFE_ASSERT(maxPluginNumber == 0); | ||||
| CARLA_SAFE_ASSERT(nextPluginId == 0); | CARLA_SAFE_ASSERT(nextPluginId == 0); | ||||
| CARLA_SAFE_ASSERT(isIdling == 0); | CARLA_SAFE_ASSERT(isIdling == 0); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT(plugins == nullptr); | CARLA_SAFE_ASSERT(plugins == nullptr); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -473,13 +419,13 @@ CarlaEngine::ProtectedData::~ProtectedData() noexcept | |||||
| bool CarlaEngine::ProtectedData::init(const char* const clientName) | bool CarlaEngine::ProtectedData::init(const char* const clientName) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)"); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(oscData == nullptr, "Invalid engine internal data (err #2)"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(oscData == nullptr, "Invalid engine internal data (err #2)"); | ||||
| #endif | #endif | ||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)"); | ||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.out == nullptr, "Invalid engine internal data (err #5)"); | ||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(clientName != nullptr && clientName[0] != '\0', "Invalid client name"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)"); | CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(plugins == nullptr, "Invalid engine internal data (err #3)"); | ||||
| #endif | #endif | ||||
| @@ -525,14 +471,12 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName) | |||||
| timeInfo.clear(); | timeInfo.clear(); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| osc.init(clientName); | osc.init(clientName); | ||||
| # ifndef BUILD_BRIDGE | |||||
| oscData = osc.getControlData(); | oscData = osc.getControlData(); | ||||
| # endif | |||||
| #endif | #endif | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| plugins = new EnginePluginData[maxPluginNumber]; | plugins = new EnginePluginData[maxPluginNumber]; | ||||
| carla_zeroStructs(plugins, maxPluginNumber); | carla_zeroStructs(plugins, maxPluginNumber); | ||||
| #endif | #endif | ||||
| @@ -546,7 +490,7 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName) | |||||
| void CarlaEngine::ProtectedData::close() | void CarlaEngine::ProtectedData::close() | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT(name.isNotEmpty()); | CARLA_SAFE_ASSERT(name.isNotEmpty()); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT(plugins != nullptr); | CARLA_SAFE_ASSERT(plugins != nullptr); | ||||
| CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber); | CARLA_SAFE_ASSERT(nextPluginId == maxPluginNumber); | ||||
| #endif | #endif | ||||
| @@ -556,7 +500,7 @@ void CarlaEngine::ProtectedData::close() | |||||
| thread.stopThread(500); | thread.stopThread(500); | ||||
| nextAction.clearAndReset(); | nextAction.clearAndReset(); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| osc.close(); | osc.close(); | ||||
| oscData = nullptr; | oscData = nullptr; | ||||
| #endif | #endif | ||||
| @@ -566,7 +510,7 @@ void CarlaEngine::ProtectedData::close() | |||||
| maxPluginNumber = 0; | maxPluginNumber = 0; | ||||
| nextPluginId = 0; | nextPluginId = 0; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (plugins != nullptr) | if (plugins != nullptr) | ||||
| { | { | ||||
| delete[] plugins; | delete[] plugins; | ||||
| @@ -595,7 +539,7 @@ void CarlaEngine::ProtectedData::initTime(const char* const features) | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept | void CarlaEngine::ProtectedData::doPluginRemove(const uint pluginId) noexcept | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,); | CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,); | ||||
| @@ -656,7 +600,7 @@ void CarlaEngine::ProtectedData::doNextPluginAction() noexcept | |||||
| const EnginePostAction opcode = nextAction.opcode; | const EnginePostAction opcode = nextAction.opcode; | ||||
| const bool needsPost = nextAction.needsPost; | const bool needsPost = nextAction.needsPost; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| const uint pluginId = nextAction.pluginId; | const uint pluginId = nextAction.pluginId; | ||||
| const uint value = nextAction.value; | const uint value = nextAction.value; | ||||
| #endif | #endif | ||||
| @@ -675,7 +619,7 @@ void CarlaEngine::ProtectedData::doNextPluginAction() noexcept | |||||
| case kEnginePostActionZeroCount: | case kEnginePostActionZeroCount: | ||||
| curPluginCount = 0; | curPluginCount = 0; | ||||
| break; | break; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| case kEnginePostActionRemovePlugin: | case kEnginePostActionRemovePlugin: | ||||
| doPluginRemove(pluginId); | doPluginRemove(pluginId); | ||||
| break; | break; | ||||
| @@ -21,7 +21,7 @@ | |||||
| #include "CarlaEngineThread.hpp" | #include "CarlaEngineThread.hpp" | ||||
| #include "CarlaEngineUtils.hpp" | #include "CarlaEngineUtils.hpp" | ||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| #ifndef BUILD_BRIDGE | |||||
| # include "CarlaEngineOsc.hpp" | # include "CarlaEngineOsc.hpp" | ||||
| # include "hylia/hylia.h" | # include "hylia/hylia.h" | ||||
| #endif | #endif | ||||
| @@ -57,7 +57,7 @@ struct EngineInternalEvents { | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalEvents) | CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalEvents) | ||||
| }; | }; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // InternalGraph | // InternalGraph | ||||
| @@ -111,7 +111,7 @@ private: | |||||
| CARLA_PREVENT_HEAP_ALLOCATION | CARLA_PREVENT_HEAP_ALLOCATION | ||||
| CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalGraph) | CARLA_DECLARE_NON_COPY_STRUCT(EngineInternalGraph) | ||||
| }; | }; | ||||
| #endif | |||||
| #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // InternalTime | // InternalTime | ||||
| @@ -170,7 +170,7 @@ private: | |||||
| enum EnginePostAction { | enum EnginePostAction { | ||||
| kEnginePostActionNull = 0, | kEnginePostActionNull = 0, | ||||
| kEnginePostActionZeroCount, // set curPluginCount to 0 | kEnginePostActionZeroCount, // set curPluginCount to 0 | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| kEnginePostActionRemovePlugin, // remove a plugin | kEnginePostActionRemovePlugin, // remove a plugin | ||||
| kEnginePostActionSwitchPlugins // switch between 2 plugins | kEnginePostActionSwitchPlugins // switch between 2 plugins | ||||
| #endif | #endif | ||||
| @@ -209,13 +209,9 @@ struct EnginePluginData { | |||||
| struct CarlaEngine::ProtectedData { | struct CarlaEngine::ProtectedData { | ||||
| CarlaEngineThread thread; | CarlaEngineThread thread; | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| CarlaEngineOsc osc; | CarlaEngineOsc osc; | ||||
| # ifdef BUILD_BRIDGE | |||||
| CarlaOscData* oscData; | |||||
| # else | |||||
| const CarlaOscData* oscData; | const CarlaOscData* oscData; | ||||
| # endif | |||||
| #endif | #endif | ||||
| EngineCallbackFunc callback; | EngineCallbackFunc callback; | ||||
| @@ -224,7 +220,7 @@ struct CarlaEngine::ProtectedData { | |||||
| FileCallbackFunc fileCallback; | FileCallbackFunc fileCallback; | ||||
| void* fileCallbackPtr; | void* fileCallbackPtr; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool loadingProject; | bool loadingProject; | ||||
| #endif | #endif | ||||
| @@ -244,14 +240,14 @@ struct CarlaEngine::ProtectedData { | |||||
| EngineOptions options; | EngineOptions options; | ||||
| EngineTimeInfo timeInfo; | EngineTimeInfo timeInfo; | ||||
| #ifdef BUILD_BRIDGE | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| EnginePluginData plugins[1]; | EnginePluginData plugins[1]; | ||||
| #else | #else | ||||
| EnginePluginData* plugins; | EnginePluginData* plugins; | ||||
| #endif | #endif | ||||
| EngineInternalEvents events; | EngineInternalEvents events; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| EngineInternalGraph graph; | EngineInternalGraph graph; | ||||
| #endif | #endif | ||||
| EngineInternalTime time; | EngineInternalTime time; | ||||
| @@ -811,6 +811,7 @@ public: | |||||
| fIsRunning(false) | fIsRunning(false) | ||||
| #else | #else | ||||
| fTimebaseMaster(false), | fTimebaseMaster(false), | ||||
| fTimebaseRolling(false), | |||||
| fUsedGroups(), | fUsedGroups(), | ||||
| fUsedPorts(), | fUsedPorts(), | ||||
| fUsedConnections(), | fUsedConnections(), | ||||
| @@ -950,8 +951,12 @@ public: | |||||
| jackbridge_set_process_callback(fClient, carla_jack_process_callback, this); | jackbridge_set_process_callback(fClient, carla_jack_process_callback, this); | ||||
| jackbridge_on_shutdown(fClient, carla_jack_shutdown_callback, this); | jackbridge_on_shutdown(fClient, carla_jack_shutdown_callback, this); | ||||
| fTimebaseRolling = false; | |||||
| if (opts.transportMode == ENGINE_TRANSPORT_MODE_JACK) | if (opts.transportMode == ENGINE_TRANSPORT_MODE_JACK) | ||||
| fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this); | fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this); | ||||
| else | |||||
| fTimebaseMaster = false; | |||||
| if (opts.processMode != ENGINE_PROCESS_MODE_PATCHBAY) | if (opts.processMode != ENGINE_PROCESS_MODE_PATCHBAY) | ||||
| initJackPatchbay(jackClientName); | initJackPatchbay(jackClientName); | ||||
| @@ -984,6 +989,45 @@ public: | |||||
| if (jackbridge_activate(fClient)) | if (jackbridge_activate(fClient)) | ||||
| { | { | ||||
| if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | |||||
| opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||||
| { | |||||
| if (pData->options.audioDevice != nullptr && | |||||
| std::strcmp(pData->options.audioDevice, "Auto-Connect ON") == 0 && | |||||
| std::getenv("LADISH_APP_NAME") == nullptr && | |||||
| std::getenv("NSM_URL") == nullptr) | |||||
| { | |||||
| char strBuf[STR_MAX]; | |||||
| strBuf[STR_MAX-1] = '\0'; | |||||
| if (jackbridge_port_by_name(fClient, "system:capture_1") != nullptr) | |||||
| { | |||||
| std::snprintf(strBuf, STR_MAX-2, "%s:audio-in1", jackClientName); | |||||
| jackbridge_connect(fClient, "system:capture_1", strBuf); | |||||
| std::snprintf(strBuf, STR_MAX-2, "%s:audio-in2", jackClientName); | |||||
| if (jackbridge_port_by_name(fClient, "system:capture_2") != nullptr) | |||||
| jackbridge_connect(fClient, "system:capture_2", strBuf); | |||||
| else | |||||
| jackbridge_connect(fClient, "system:capture_1", strBuf); | |||||
| } | |||||
| if (jackbridge_port_by_name(fClient, "system:playback_1") != nullptr) | |||||
| { | |||||
| std::snprintf(strBuf, STR_MAX-2, "%s:audio-out1", jackClientName); | |||||
| jackbridge_connect(fClient, strBuf, "system:playback_1"); | |||||
| std::snprintf(strBuf, STR_MAX-2, "%s:audio-out2", jackClientName); | |||||
| if (jackbridge_port_by_name(fClient, "system:playback_2") != nullptr) | |||||
| jackbridge_connect(fClient, strBuf, "system:playback_2"); | |||||
| else | |||||
| jackbridge_connect(fClient, strBuf, "system:playback_1"); | |||||
| } | |||||
| } | |||||
| } | |||||
| startThread(); | startThread(); | ||||
| callback(ENGINE_CALLBACK_ENGINE_STARTED, 0, | callback(ENGINE_CALLBACK_ENGINE_STARTED, 0, | ||||
| opts.processMode, opts.transportMode, | opts.processMode, opts.transportMode, | ||||
| @@ -992,7 +1036,8 @@ public: | |||||
| return true; | return true; | ||||
| } | } | ||||
| if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||||
| if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || | |||||
| opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||||
| { | { | ||||
| pData->graph.destroy(); | pData->graph.destroy(); | ||||
| } | } | ||||
| @@ -1084,6 +1129,55 @@ public: | |||||
| return "JACK"; | return "JACK"; | ||||
| } | } | ||||
| EngineTimeInfo getTimeInfo() const noexcept override | |||||
| { | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) | |||||
| return CarlaEngine::getTimeInfo(); | |||||
| if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS) | |||||
| return CarlaEngine::getTimeInfo(); | |||||
| jack_position_t jpos; | |||||
| // invalidate | |||||
| jpos.unique_1 = 1; | |||||
| jpos.unique_2 = 2; | |||||
| EngineTimeInfo timeInfo; | |||||
| const bool playing = jackbridge_transport_query(fClient, &jpos) == JackTransportRolling; | |||||
| if (jpos.unique_1 != jpos.unique_2) | |||||
| { | |||||
| timeInfo.playing = false; | |||||
| timeInfo.frame = 0; | |||||
| timeInfo.usecs = 0; | |||||
| timeInfo.bbt.valid = false; | |||||
| return timeInfo; | |||||
| } | |||||
| timeInfo.playing = playing; | |||||
| timeInfo.frame = jpos.frame; | |||||
| timeInfo.usecs = jpos.usecs; | |||||
| if (jpos.valid & JackPositionBBT) | |||||
| { | |||||
| timeInfo.bbt.valid = true; | |||||
| timeInfo.bbt.bar = jpos.bar; | |||||
| timeInfo.bbt.beat = jpos.beat; | |||||
| timeInfo.bbt.tick = jpos.tick; | |||||
| timeInfo.bbt.barStartTick = jpos.bar_start_tick; | |||||
| timeInfo.bbt.beatsPerBar = jpos.beats_per_bar; | |||||
| timeInfo.bbt.beatType = jpos.beat_type; | |||||
| timeInfo.bbt.ticksPerBeat = jpos.ticks_per_beat; | |||||
| timeInfo.bbt.beatsPerMinute = jpos.beats_per_minute; | |||||
| } | |||||
| else | |||||
| { | |||||
| timeInfo.bbt.valid = false; | |||||
| } | |||||
| return timeInfo; | |||||
| } | |||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| void setOption(const EngineOption option, const int value, const char* const valueStr) noexcept override | void setOption(const EngineOption option, const int value, const char* const valueStr) noexcept override | ||||
| { | { | ||||
| @@ -1390,7 +1484,7 @@ public: | |||||
| void transportPlay() noexcept override | void transportPlay() noexcept override | ||||
| { | { | ||||
| if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) | |||||
| return CarlaEngine::transportPlay(); | return CarlaEngine::transportPlay(); | ||||
| if (fClient != nullptr) | if (fClient != nullptr) | ||||
| @@ -1410,7 +1504,7 @@ public: | |||||
| void transportPause() noexcept override | void transportPause() noexcept override | ||||
| { | { | ||||
| if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) | |||||
| return CarlaEngine::transportPause(); | return CarlaEngine::transportPause(); | ||||
| if (fClient != nullptr) | if (fClient != nullptr) | ||||
| @@ -1423,9 +1517,10 @@ public: | |||||
| void transportBPM(const double bpm) noexcept override | void transportBPM(const double bpm) noexcept override | ||||
| { | { | ||||
| CarlaEngine::transportBPM(bpm); | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK || fTimebaseMaster) | |||||
| return CarlaEngine::transportBPM(bpm); | |||||
| if (fClient == nullptr || fTimebaseMaster) | |||||
| if (fClient == nullptr) | |||||
| return; | return; | ||||
| jack_position_t jpos; | jack_position_t jpos; | ||||
| @@ -1448,7 +1543,7 @@ public: | |||||
| void transportRelocate(const uint64_t frame) noexcept override | void transportRelocate(const uint64_t frame) noexcept override | ||||
| { | { | ||||
| if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_INTERNAL) | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) | |||||
| return CarlaEngine::transportRelocate(frame); | return CarlaEngine::transportRelocate(frame); | ||||
| if (fClient != nullptr) | if (fClient != nullptr) | ||||
| @@ -1555,57 +1650,12 @@ protected: | |||||
| offlineModeChanged(isFreewheel); | offlineModeChanged(isFreewheel); | ||||
| } | } | ||||
| void saveTransportInfo() | |||||
| { | |||||
| if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK) | |||||
| return; | |||||
| jack_position_t jpos; | |||||
| // invalidate | |||||
| jpos.unique_1 = 1; | |||||
| jpos.unique_2 = 2; | |||||
| pData->timeInfo.playing = (jackbridge_transport_query(fClient, &jpos) == JackTransportRolling); | |||||
| if (jpos.unique_1 == jpos.unique_2) | |||||
| { | |||||
| pData->timeInfo.frame = jpos.frame; | |||||
| pData->timeInfo.usecs = jpos.usecs; | |||||
| if (jpos.valid & JackPositionBBT) | |||||
| { | |||||
| pData->timeInfo.bbt.valid = true; | |||||
| pData->timeInfo.bbt.bar = jpos.bar; | |||||
| pData->timeInfo.bbt.beat = jpos.beat; | |||||
| pData->timeInfo.bbt.tick = jpos.tick; | |||||
| pData->timeInfo.bbt.barStartTick = jpos.bar_start_tick; | |||||
| pData->timeInfo.bbt.beatsPerBar = jpos.beats_per_bar; | |||||
| pData->timeInfo.bbt.beatType = jpos.beat_type; | |||||
| pData->timeInfo.bbt.ticksPerBeat = jpos.ticks_per_beat; | |||||
| pData->timeInfo.bbt.beatsPerMinute = jpos.beats_per_minute; | |||||
| } | |||||
| else | |||||
| { | |||||
| pData->timeInfo.bbt.valid = false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| pData->timeInfo.frame = 0; | |||||
| pData->timeInfo.usecs = 0; | |||||
| pData->timeInfo.bbt.valid = false; | |||||
| } | |||||
| } | |||||
| void handleJackProcessCallback(const uint32_t nframes) | void handleJackProcessCallback(const uint32_t nframes) | ||||
| { | { | ||||
| const PendingRtEventsRunner prt(this, nframes); | const PendingRtEventsRunner prt(this, nframes); | ||||
| CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,); | CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,); | ||||
| saveTransportInfo(); | |||||
| #ifdef BUILD_BRIDGE | #ifdef BUILD_BRIDGE | ||||
| CarlaPlugin* const plugin(pData->plugins[0].plugin); | CarlaPlugin* const plugin(pData->plugins[0].plugin); | ||||
| @@ -1781,6 +1831,17 @@ protected: | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (fTimebaseMaster) | |||||
| { | |||||
| const bool playing = jackbridge_transport_query(fClient, nullptr) == JackTransportRolling; | |||||
| if (fTimebaseRolling != playing) | |||||
| { | |||||
| fTimebaseRolling = playing; | |||||
| pData->timeInfo.playing = playing; | |||||
| } | |||||
| } | |||||
| #endif // ! BUILD_BRIDGE | #endif // ! BUILD_BRIDGE | ||||
| } | } | ||||
| @@ -1795,6 +1856,9 @@ protected: | |||||
| if (new_pos) | if (new_pos) | ||||
| pData->time.setNeedsReset(); | pData->time.setNeedsReset(); | ||||
| pData->timeInfo.playing = fTimebaseRolling; | |||||
| pData->timeInfo.frame = pos->frame; | |||||
| pData->timeInfo.usecs = pos->usecs; | |||||
| pData->time.fillJackTimeInfo(pos, nframes); | pData->time.fillJackTimeInfo(pos, nframes); | ||||
| } | } | ||||
| @@ -2053,6 +2117,8 @@ private: | |||||
| jack_port_t* fRackPorts[kRackPortCount]; | jack_port_t* fRackPorts[kRackPortCount]; | ||||
| bool fTimebaseMaster; | bool fTimebaseMaster; | ||||
| bool fTimebaseRolling; | |||||
| PatchbayGroupList fUsedGroups; | PatchbayGroupList fUsedGroups; | ||||
| PatchbayPortList fUsedPorts; | PatchbayPortList fUsedPorts; | ||||
| PatchbayConnectionList fUsedConnections; | PatchbayConnectionList fUsedConnections; | ||||
| @@ -2484,15 +2550,15 @@ private: | |||||
| handlePtr->handleJackFreewheelCallback(bool(starting)); | handlePtr->handleJackFreewheelCallback(bool(starting)); | ||||
| } | } | ||||
| static int JACKBRIDGE_API carla_jack_process_callback(jack_nframes_t nframes, void* arg) __attribute__((annotate("realtime"))) | |||||
| static void JACKBRIDGE_API carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg) | |||||
| { | { | ||||
| handlePtr->handleJackProcessCallback(nframes); | |||||
| return 0; | |||||
| handlePtr->handleJackLatencyCallback(mode); | |||||
| } | } | ||||
| static void JACKBRIDGE_API carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg) | |||||
| static int JACKBRIDGE_API carla_jack_process_callback(jack_nframes_t nframes, void* arg) __attribute__((annotate("realtime"))) | |||||
| { | { | ||||
| handlePtr->handleJackLatencyCallback(mode); | |||||
| handlePtr->handleJackProcessCallback(nframes); | |||||
| return 0; | |||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| @@ -2565,7 +2631,6 @@ private: | |||||
| if (plugin->tryLock(engine->fFreewheel)) | if (plugin->tryLock(engine->fFreewheel)) | ||||
| { | { | ||||
| plugin->initBuffers(); | plugin->initBuffers(); | ||||
| engine->saveTransportInfo(); | |||||
| engine->processPlugin(plugin, nframes); | engine->processPlugin(plugin, nframes); | ||||
| plugin->unlock(); | plugin->unlock(); | ||||
| } | } | ||||
| @@ -17,8 +17,8 @@ | |||||
| #include "CarlaDefines.h" | #include "CarlaDefines.h" | ||||
| #ifdef BUILD_BRIDGE | |||||
| # error This file should not be compiled if building bridge | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| # error This file should not be compiled if building alternative-arch bridges | |||||
| #endif | #endif | ||||
| #include "CarlaEngineInternal.hpp" | #include "CarlaEngineInternal.hpp" | ||||
| @@ -1165,7 +1165,7 @@ protected: | |||||
| const CarlaMutexLocker cml(fUiServer.getPipeLock()); | const CarlaMutexLocker cml(fUiServer.getPipeLock()); | ||||
| #ifdef HAVE_LIBLO | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (! fUiServer.writeAndFixMessage("osc-urls")) | if (! fUiServer.writeAndFixMessage("osc-urls")) | ||||
| return; | return; | ||||
| if (! fUiServer.writeAndFixMessage(pData->osc.getServerPathTCP())) | if (! fUiServer.writeAndFixMessage(pData->osc.getServerPathTCP())) | ||||
| @@ -2348,6 +2348,7 @@ CARLA_BACKEND_END_NAMESPACE | |||||
| #include "CarlaHostCommon.cpp" | #include "CarlaHostCommon.cpp" | ||||
| #include "CarlaPluginUI.cpp" | #include "CarlaPluginUI.cpp" | ||||
| #include "CarlaDssiUtils.cpp" | #include "CarlaDssiUtils.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| #include "CarlaPatchbayUtils.cpp" | #include "CarlaPatchbayUtils.cpp" | ||||
| #include "CarlaPipeUtils.cpp" | #include "CarlaPipeUtils.cpp" | ||||
| #include "CarlaStateUtils.cpp" | #include "CarlaStateUtils.cpp" | ||||
| @@ -1193,7 +1193,34 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint index | |||||
| if (index >= gRtAudioApis.size()) | if (index >= gRtAudioApis.size()) | ||||
| return nullptr; | return nullptr; | ||||
| static EngineDriverDeviceInfo devInfo = { 0x0, nullptr, nullptr }; | |||||
| static uint32_t dummyBufferSizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 }; | |||||
| static double dummySampleRates[] = { 22050.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, 0.0 }; | |||||
| // reset | |||||
| devInfo.hints = 0x0; | |||||
| // cleanup | |||||
| if (devInfo.bufferSizes != nullptr && devInfo.bufferSizes != dummyBufferSizes) | |||||
| { | |||||
| delete[] devInfo.bufferSizes; | |||||
| devInfo.bufferSizes = nullptr; | |||||
| } | |||||
| if (devInfo.sampleRates != nullptr && devInfo.sampleRates != dummySampleRates) | |||||
| { | |||||
| delete[] devInfo.sampleRates; | |||||
| devInfo.sampleRates = nullptr; | |||||
| } | |||||
| const RtAudio::Api& api(gRtAudioApis[index]); | const RtAudio::Api& api(gRtAudioApis[index]); | ||||
| if (api == RtAudio::UNIX_JACK) | |||||
| { | |||||
| devInfo.bufferSizes = nullptr; | |||||
| devInfo.sampleRates = nullptr; | |||||
| return &devInfo; | |||||
| } | |||||
| RtAudio::DeviceInfo rtAudioDevInfo; | RtAudio::DeviceInfo rtAudioDevInfo; | ||||
| try { | try { | ||||
| @@ -1214,25 +1241,10 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint index | |||||
| } | } | ||||
| if (i == devCount) | if (i == devCount) | ||||
| return nullptr; | |||||
| rtAudioDevInfo = rtAudio.getDeviceInfo(rtAudio.getDefaultOutputDevice()); | |||||
| } CARLA_SAFE_EXCEPTION_RETURN("RtAudio device discovery", nullptr); | } CARLA_SAFE_EXCEPTION_RETURN("RtAudio device discovery", nullptr); | ||||
| static EngineDriverDeviceInfo devInfo = { 0x0, nullptr, nullptr }; | |||||
| static uint32_t dummyBufferSizes[] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 }; | |||||
| static double dummySampleRates[] = { 22050.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, 0.0 }; | |||||
| // reset | |||||
| devInfo.hints = 0x0; | |||||
| devInfo.bufferSizes = dummyBufferSizes; | |||||
| // cleanup | |||||
| if (devInfo.sampleRates != nullptr && devInfo.sampleRates != dummySampleRates) | |||||
| { | |||||
| delete[] devInfo.sampleRates; | |||||
| devInfo.sampleRates = nullptr; | |||||
| } | |||||
| // a few APIs can do triple buffer | // a few APIs can do triple buffer | ||||
| switch (api) | switch (api) | ||||
| { | { | ||||
| @@ -1245,13 +1257,16 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint index | |||||
| break; | break; | ||||
| } | } | ||||
| // always use default buffer sizes | |||||
| devInfo.bufferSizes = dummyBufferSizes; | |||||
| // valid sample rates | // valid sample rates | ||||
| if (const size_t sampleRatesCount = rtAudioDevInfo.sampleRates.size()) | if (const size_t sampleRatesCount = rtAudioDevInfo.sampleRates.size()) | ||||
| { | { | ||||
| double* const sampleRates(new double[sampleRatesCount+1]); | double* const sampleRates(new double[sampleRatesCount+1]); | ||||
| for (size_t j=0; j < sampleRatesCount; ++j) | |||||
| sampleRates[j] = rtAudioDevInfo.sampleRates[j]; | |||||
| for (size_t i=0; i < sampleRatesCount; ++i) | |||||
| sampleRates[i] = rtAudioDevInfo.sampleRates[i]; | |||||
| sampleRates[sampleRatesCount] = 0.0; | sampleRates[sampleRatesCount] = 0.0; | ||||
| devInfo.sampleRates = sampleRates; | devInfo.sampleRates = sampleRates; | ||||
| @@ -41,21 +41,17 @@ CarlaEngineThread::~CarlaEngineThread() noexcept | |||||
| void CarlaEngineThread::run() noexcept | void CarlaEngineThread::run() noexcept | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(kEngine != nullptr,); | CARLA_SAFE_ASSERT_RETURN(kEngine != nullptr,); | ||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT(kEngine->isRunning()); | |||||
| #endif | |||||
| carla_debug("CarlaEngineThread::run()"); | carla_debug("CarlaEngineThread::run()"); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| const bool isPlugin(kEngine->getType() == kEngineTypePlugin); | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| const bool kIsPlugin(kEngine->getType() == kEngineTypePlugin); | |||||
| #endif | #endif | ||||
| float value; | float value; | ||||
| #ifdef BUILD_BRIDGE | |||||
| for (; ! shouldThreadExit();) | |||||
| #else | |||||
| for (; kEngine->isRunning() && ! shouldThreadExit();) | |||||
| #endif | |||||
| // thread must do something... | |||||
| CARLA_SAFE_ASSERT_RETURN(kEngine->getType() == kEngineTypeBridge || kEngine->isRunning(),); | |||||
| for (; (kEngine->getType() == kEngineTypeBridge || kEngine->isRunning()) && ! shouldThreadExit();) | |||||
| { | { | ||||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | ||||
| const bool oscRegisted = kEngine->isOscControlRegistered(); | const bool oscRegisted = kEngine->isOscControlRegistered(); | ||||
| @@ -63,8 +59,8 @@ void CarlaEngineThread::run() noexcept | |||||
| const bool oscRegisted = false; | const bool oscRegisted = false; | ||||
| #endif | #endif | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| if (isPlugin) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (kIsPlugin) | |||||
| kEngine->idleOsc(); | kEngine->idleOsc(); | ||||
| #endif | #endif | ||||
| @@ -15,11 +15,15 @@ OBJS = \ | |||||
| $(OBJDIR)/CarlaEngineData.cpp.o \ | $(OBJDIR)/CarlaEngineData.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineGraph.cpp.o \ | $(OBJDIR)/CarlaEngineGraph.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineInternal.cpp.o \ | $(OBJDIR)/CarlaEngineInternal.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineOsc.cpp.o \ | |||||
| $(OBJDIR)/CarlaEngineOscSend.cpp.o \ | |||||
| $(OBJDIR)/CarlaEnginePorts.cpp.o \ | $(OBJDIR)/CarlaEnginePorts.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineThread.cpp.o | $(OBJDIR)/CarlaEngineThread.cpp.o | ||||
| ifeq ($(HAVE_LIBLO),true) | |||||
| OBJS += \ | |||||
| $(OBJDIR)/CarlaEngineOsc.cpp.o \ | |||||
| $(OBJDIR)/CarlaEngineOscSend.cpp.o | |||||
| endif | |||||
| OBJSa = $(OBJS) \ | OBJSa = $(OBJS) \ | ||||
| $(OBJDIR)/CarlaEngineJack.cpp.o \ | $(OBJDIR)/CarlaEngineJack.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineNative.cpp.o \ | $(OBJDIR)/CarlaEngineNative.cpp.o \ | ||||
| @@ -356,7 +356,7 @@ void CarlaPlugin::getParameterScalePointLabel(const uint32_t parameterId, const | |||||
| float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept | float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f); | CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f); | ||||
| switch (parameterId) | switch (parameterId) | ||||
| @@ -498,14 +498,14 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||||
| pData->stateSave.name = carla_strdup(pData->name); | pData->stateSave.name = carla_strdup(pData->name); | ||||
| pData->stateSave.label = carla_strdup(strBuf); | pData->stateSave.label = carla_strdup(strBuf); | ||||
| pData->stateSave.uniqueId = getUniqueId(); | pData->stateSave.uniqueId = getUniqueId(); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->stateSave.options = pData->options; | pData->stateSave.options = pData->options; | ||||
| #endif | #endif | ||||
| if (pData->filename != nullptr) | if (pData->filename != nullptr) | ||||
| pData->stateSave.binary = carla_strdup(pData->filename); | pData->stateSave.binary = carla_strdup(pData->filename); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
| // Internals | // Internals | ||||
| @@ -578,7 +578,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave) | |||||
| stateParameter->dummy = dummy; | stateParameter->dummy = dummy; | ||||
| stateParameter->index = paramData.index; | stateParameter->index = paramData.index; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| stateParameter->midiCC = paramData.midiCC; | stateParameter->midiCC = paramData.midiCC; | ||||
| stateParameter->midiChannel = paramData.midiChannel; | stateParameter->midiChannel = paramData.midiChannel; | ||||
| #endif | #endif | ||||
| @@ -794,7 +794,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||||
| setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true); | setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| setParameterMidiCC(static_cast<uint32_t>(index), stateParameter->midiCC, true, true); | setParameterMidiCC(static_cast<uint32_t>(index), stateParameter->midiCC, true, true); | ||||
| setParameterMidiChannel(static_cast<uint32_t>(index), stateParameter->midiChannel, true, true); | setParameterMidiChannel(static_cast<uint32_t>(index), stateParameter->midiChannel, true, true); | ||||
| #endif | #endif | ||||
| @@ -867,7 +867,7 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||||
| #endif | #endif | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
| // Part 6 - set internal stuff | // Part 6 - set internal stuff | ||||
| @@ -888,9 +888,10 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave) | |||||
| setPanning(stateSave.panning, true, true); | setPanning(stateSave.panning, true, true); | ||||
| setCtrlChannel(stateSave.ctrlChannel, true, true); | setCtrlChannel(stateSave.ctrlChannel, true, true); | ||||
| setActive(stateSave.active, true, true); | setActive(stateSave.active, true, true); | ||||
| #endif | |||||
| pData->engine->callback(ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0.0f, nullptr); | |||||
| if (! pData->engine->isLoadingProject()) | |||||
| pData->engine->callback(ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0.0f, nullptr); | |||||
| #endif | |||||
| } | } | ||||
| bool CarlaPlugin::saveStateToFile(const char* const filename) | bool CarlaPlugin::saveStateToFile(const char* const filename) | ||||
| @@ -1270,7 +1271,7 @@ void CarlaPlugin::setOption(const uint option, const bool yesNo, const bool send | |||||
| else | else | ||||
| pData->options &= ~option; | pData->options &= ~option; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_OPTION_CHANGED, pData->id, static_cast<int>(option), yesNo ? 1 : 0, 0.0f, nullptr); | pData->engine->callback(ENGINE_CALLBACK_OPTION_CHANGED, pData->id, static_cast<int>(option), yesNo ? 1 : 0, 0.0f, nullptr); | ||||
| #else | #else | ||||
| @@ -1295,9 +1296,11 @@ void CarlaPlugin::setEnabled(const bool yesNo) noexcept | |||||
| void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| #endif | |||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| if (pData->active == active) | if (pData->active == active) | ||||
| return; | return; | ||||
| @@ -1313,25 +1316,27 @@ void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool se | |||||
| pData->active = active; | pData->active = active; | ||||
| #ifndef BUILD_BRIDGE | |||||
| const float value(active ? 1.0f : 0.0f); | |||||
| const float value = active ? 1.0f : 0.0f; | |||||
| # ifdef HAVE_LIBLO | |||||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_ACTIVE, value); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_ACTIVE, value); | ||||
| # endif | |||||
| #endif | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_ACTIVE, 0, value, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_ACTIVE, 0, value, nullptr); | ||||
| #endif | #endif | ||||
| // may be unused | |||||
| return; (void)sendOsc; (void)sendCallback; | |||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f); | CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f); | ||||
| const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value)); | const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value)); | ||||
| @@ -1341,20 +1346,22 @@ void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool se | |||||
| pData->postProc.dryWet = fixedValue; | pData->postProc.dryWet = fixedValue; | ||||
| #ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_DRYWET, fixedValue); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_DRYWET, fixedValue); | ||||
| #endif | |||||
| # endif | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_DRYWET, 0, fixedValue, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_DRYWET, 0, fixedValue, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f); | CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f); | ||||
| const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value)); | const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value)); | ||||
| @@ -1364,20 +1371,22 @@ void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool se | |||||
| pData->postProc.volume = fixedValue; | pData->postProc.volume = fixedValue; | ||||
| #ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_VOLUME, fixedValue); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_VOLUME, fixedValue); | ||||
| #endif | |||||
| # endif | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_VOLUME, 0, fixedValue, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_VOLUME, 0, fixedValue, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | ||||
| const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | ||||
| @@ -1387,20 +1396,22 @@ void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bo | |||||
| pData->postProc.balanceLeft = fixedValue; | pData->postProc.balanceLeft = fixedValue; | ||||
| #ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_BALANCE_LEFT, fixedValue); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_BALANCE_LEFT, fixedValue); | ||||
| #endif | |||||
| # endif | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_BALANCE_LEFT, 0, fixedValue, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_BALANCE_LEFT, 0, fixedValue, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | ||||
| const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | ||||
| @@ -1410,20 +1421,22 @@ void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const b | |||||
| pData->postProc.balanceRight = fixedValue; | pData->postProc.balanceRight = fixedValue; | ||||
| #ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_BALANCE_RIGHT, fixedValue); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_BALANCE_RIGHT, fixedValue); | ||||
| #endif | |||||
| # endif | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_BALANCE_RIGHT, 0, fixedValue, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_BALANCE_RIGHT, 0, fixedValue, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f); | ||||
| const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value)); | ||||
| @@ -1433,16 +1446,13 @@ void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool s | |||||
| pData->postProc.panning = fixedValue; | pData->postProc.panning = fixedValue; | ||||
| #ifdef HAVE_LIBLO | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_PANNING, fixedValue); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_PANNING, fixedValue); | ||||
| #endif | |||||
| # endif | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_PANNING, 0, fixedValue, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_PANNING, 0, fixedValue, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setDryWetRT(const float value) noexcept | void CarlaPlugin::setDryWetRT(const float value) noexcept | ||||
| @@ -1508,13 +1518,15 @@ void CarlaPlugin::setPanningRT(const float value) noexcept | |||||
| pData->postProc.panning = fixedValue; | pData->postProc.panning = fixedValue; | ||||
| } | } | ||||
| #endif // ! BUILD_BRIDGE | |||||
| #endif // ! BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| #endif | |||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,); | CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,); | ||||
| if (pData->ctrlChannel == channel) | if (pData->ctrlChannel == channel) | ||||
| @@ -1522,20 +1534,17 @@ void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const | |||||
| pData->ctrlChannel = channel; | pData->ctrlChannel = channel; | ||||
| #ifndef BUILD_BRIDGE | |||||
| const float channelf(channel); | |||||
| const float channelf = static_cast<float>(channel); | |||||
| # ifdef HAVE_LIBLO | |||||
| #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_CTRL_CHANNEL, channelf); | pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_CTRL_CHANNEL, channelf); | ||||
| # endif | |||||
| #endif | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_CTRL_CHANNEL, 0, channelf, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_CTRL_CHANNEL, 0, channelf, nullptr); | ||||
| #endif | #endif | ||||
| // may be unused | |||||
| return; (void)sendOsc; (void)sendCallback; | |||||
| } | } | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -1543,6 +1552,11 @@ void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const | |||||
| void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendGui && !sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | ||||
| if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0) | if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0) | ||||
| @@ -1555,9 +1569,6 @@ void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float valu | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(parameterId), 0, value, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, static_cast<int>(parameterId), 0, value, nullptr); | ||||
| // may be unused | |||||
| return; (void)sendOsc; | |||||
| } | } | ||||
| void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value) noexcept | void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value) noexcept | ||||
| @@ -1567,7 +1578,7 @@ void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float va | |||||
| void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,); | CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,); | ||||
| switch (rindex) | switch (rindex) | ||||
| @@ -1603,16 +1614,18 @@ void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float | |||||
| void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| #endif | |||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | ||||
| CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,); | CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,); | ||||
| pData->param.data[parameterId].midiChannel = channel; | pData->param.data[parameterId].midiChannel = channel; | ||||
| #ifndef BUILD_BRIDGE | |||||
| # ifdef HAVE_LIBLO | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_midi_channel(pData->id, parameterId, channel); | pData->engine->oscSend_control_set_parameter_midi_channel(pData->id, parameterId, channel); | ||||
| # endif | # endif | ||||
| @@ -1620,23 +1633,22 @@ void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED, pData->id, static_cast<int>(parameterId), channel, 0.0f, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED, pData->id, static_cast<int>(parameterId), channel, 0.0f, nullptr); | ||||
| #endif | #endif | ||||
| // may be unused | |||||
| return; (void)sendOsc; (void)sendCallback; | |||||
| } | } | ||||
| void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t cc, const bool sendOsc, const bool sendCallback) noexcept | void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t cc, const bool sendOsc, const bool sendCallback) noexcept | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| #endif | |||||
| if (pData->bridged) { | |||||
| CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,); | |||||
| } else { | |||||
| CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT | |||||
| } | |||||
| CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | ||||
| CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,); | CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,); | ||||
| pData->param.data[parameterId].midiCC = cc; | pData->param.data[parameterId].midiCC = cc; | ||||
| #ifndef BUILD_BRIDGE | |||||
| # ifdef HAVE_LIBLO | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| # if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||||
| if (sendOsc && pData->engine->isOscControlRegistered()) | if (sendOsc && pData->engine->isOscControlRegistered()) | ||||
| pData->engine->oscSend_control_set_parameter_midi_cc(pData->id, parameterId, cc); | pData->engine->oscSend_control_set_parameter_midi_cc(pData->id, parameterId, cc); | ||||
| # endif | # endif | ||||
| @@ -1644,9 +1656,6 @@ void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t c | |||||
| if (sendCallback) | if (sendCallback) | ||||
| pData->engine->callback(ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED, pData->id, static_cast<int>(parameterId), cc, 0.0f, nullptr); | pData->engine->callback(ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED, pData->id, static_cast<int>(parameterId), cc, 0.0f, nullptr); | ||||
| #endif | #endif | ||||
| // may be unused | |||||
| return; (void)sendOsc; (void)sendCallback; | |||||
| } | } | ||||
| void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool) | void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool) | ||||
| @@ -2278,7 +2287,7 @@ void CarlaPlugin::sendMidiSingleNote(const uint8_t channel, const uint8_t note, | |||||
| return; (void)sendOsc; | return; (void)sendOsc; | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void CarlaPlugin::sendMidiAllNotesOffToCallback() | void CarlaPlugin::sendMidiAllNotesOffToCallback() | ||||
| { | { | ||||
| if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS) | if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS) | ||||
| @@ -2357,7 +2366,7 @@ void CarlaPlugin::uiIdle() | |||||
| pData->postUiEvents.data.clear(); | pData->postUiEvents.data.clear(); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (pData->transientTryCounter == 0) | if (pData->transientTryCounter == 0) | ||||
| return; | return; | ||||
| if (++pData->transientTryCounter % 10 != 0) | if (++pData->transientTryCounter % 10 != 0) | ||||
| @@ -2555,7 +2564,7 @@ CarlaPlugin::ScopedSingleProcessLocker::~ScopedSingleProcessLocker() noexcept | |||||
| if (! fBlock) | if (! fBlock) | ||||
| return; | return; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (fPlugin->pData->singleMutex.wasTryLockCalled()) | if (fPlugin->pData->singleMutex.wasTryLockCalled()) | ||||
| fPlugin->pData->needsReset = true; | fPlugin->pData->needsReset = true; | ||||
| #endif | #endif | ||||
| @@ -397,7 +397,7 @@ public: | |||||
| { | { | ||||
| carla_debug("CarlaPluginBridge::~CarlaPluginBridge()"); | carla_debug("CarlaPluginBridge::~CarlaPluginBridge()"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // close UI | // close UI | ||||
| if (pData->hints & PLUGIN_HAS_CUSTOM_UI) | if (pData->hints & PLUGIN_HAS_CUSTOM_UI) | ||||
| pData->transientTryCounter = 0; | pData->transientTryCounter = 0; | ||||
| @@ -877,7 +877,7 @@ public: | |||||
| fShmNonRtClientControl.commitWrite(); | fShmNonRtClientControl.commitWrite(); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (yesNo) | if (yesNo) | ||||
| { | { | ||||
| pData->tryTransient(); | pData->tryTransient(); | ||||
| @@ -1185,7 +1185,7 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
| // Event Input (System) | // Event Input (System) | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool allNotesOffSent = false; | bool allNotesOffSent = false; | ||||
| #endif | #endif | ||||
| @@ -1208,7 +1208,7 @@ public: | |||||
| break; | break; | ||||
| case kEngineControlEventTypeParameter: | case kEngineControlEventTypeParameter: | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -1295,7 +1295,7 @@ public: | |||||
| case kEngineControlEventTypeAllNotesOff: | case kEngineControlEventTypeAllNotesOff: | ||||
| if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | ||||
| { | { | ||||
| allNotesOffSent = true; | allNotesOffSent = true; | ||||
| @@ -1467,7 +1467,7 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // TimeInfo | // TimeInfo | ||||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||||
| const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); | |||||
| BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | ||||
| bridgeTimeInfo.playing = timeInfo.playing; | bridgeTimeInfo.playing = timeInfo.playing; | ||||
| @@ -1509,7 +1509,7 @@ public: | |||||
| for (uint32_t i=0; i < fInfo.aOuts; ++i) | for (uint32_t i=0; i < fInfo.aOuts; ++i) | ||||
| carla_copyFloats(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), frames); | carla_copyFloats(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), frames); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| @@ -1531,11 +1531,13 @@ public: | |||||
| for (uint32_t k=0; k < frames; ++k) | for (uint32_t k=0; k < frames; ++k) | ||||
| { | { | ||||
| # ifndef BUILD_BRIDGE | |||||
| if (k < pData->latency.frames) | if (k < pData->latency.frames) | ||||
| bufValue = pData->latency.buffers[c][k]; | bufValue = pData->latency.buffers[c][k]; | ||||
| else if (pData->latency.frames < frames) | else if (pData->latency.frames < frames) | ||||
| bufValue = audioIn[c][k-pData->latency.frames]; | bufValue = audioIn[c][k-pData->latency.frames]; | ||||
| else | else | ||||
| # endif | |||||
| bufValue = audioIn[c][k]; | bufValue = audioIn[c][k]; | ||||
| audioOut[i][k] = (audioOut[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | audioOut[i][k] = (audioOut[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | ||||
| @@ -1583,6 +1585,7 @@ public: | |||||
| } // End of Post-processing | } // End of Post-processing | ||||
| # ifndef BUILD_BRIDGE | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Save latency values for next callback | // Save latency values for next callback | ||||
| @@ -1609,8 +1612,8 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endif // BUILD_BRIDGE | |||||
| # endif | |||||
| #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| @@ -1762,7 +1765,7 @@ public: | |||||
| { | { | ||||
| const PluginBridgeNonRtServerOpcode opcode(fShmNonRtServerControl.readOpcode()); | const PluginBridgeNonRtServerOpcode opcode(fShmNonRtServerControl.readOpcode()); | ||||
| #ifdef DEBUG | #ifdef DEBUG | ||||
| if (opcode != kPluginBridgeNonRtServerPong) { | |||||
| if (opcode != kPluginBridgeNonRtServerPong && opcode != kPluginBridgeNonRtServerParameterValue2) { | |||||
| carla_debug("CarlaPluginBridge::handleNonRtData() - got opcode: %s", PluginBridgeNonRtServerOpcode2str(opcode)); | carla_debug("CarlaPluginBridge::handleNonRtData() - got opcode: %s", PluginBridgeNonRtServerOpcode2str(opcode)); | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -1832,21 +1835,11 @@ public: | |||||
| case kPluginBridgeNonRtServerAudioCount: { | case kPluginBridgeNonRtServerAudioCount: { | ||||
| // uint/ins, uint/outs | // uint/ins, uint/outs | ||||
| fInfo.clear(); | |||||
| fInfo.aIns = fShmNonRtServerControl.readUInt(); | fInfo.aIns = fShmNonRtServerControl.readUInt(); | ||||
| fInfo.aOuts = fShmNonRtServerControl.readUInt(); | fInfo.aOuts = fShmNonRtServerControl.readUInt(); | ||||
| if (fInfo.aInNames != nullptr) | |||||
| { | |||||
| delete[] fInfo.aInNames; | |||||
| fInfo.aInNames = nullptr; | |||||
| } | |||||
| if (fInfo.aOutNames != nullptr) | |||||
| { | |||||
| delete[] fInfo.aOutNames; | |||||
| fInfo.aOutNames = nullptr; | |||||
| } | |||||
| if (fInfo.aIns > 0) | if (fInfo.aIns > 0) | ||||
| { | { | ||||
| fInfo.aInNames = new const char*[fInfo.aIns]; | fInfo.aInNames = new const char*[fInfo.aIns]; | ||||
| @@ -2224,7 +2217,7 @@ public: | |||||
| break; | break; | ||||
| case kPluginBridgeNonRtServerUiClosed: | case kPluginBridgeNonRtServerUiClosed: | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->transientTryCounter = 0; | pData->transientTryCounter = 0; | ||||
| #endif | #endif | ||||
| pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | ||||
| @@ -2522,6 +2515,38 @@ private: | |||||
| aOutNames(nullptr), | aOutNames(nullptr), | ||||
| chunk() {} | chunk() {} | ||||
| ~Info() | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| void clear() | |||||
| { | |||||
| if (aInNames != nullptr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_INT(aIns > 0, aIns); | |||||
| for (uint32_t i=0; i<aIns; ++i) | |||||
| delete[] aInNames[i]; | |||||
| delete[] aInNames; | |||||
| aInNames = nullptr; | |||||
| } | |||||
| if (aOutNames != nullptr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_INT(aOuts > 0, aOuts); | |||||
| for (uint32_t i=0; i<aOuts; ++i) | |||||
| delete[] aOutNames[i]; | |||||
| delete[] aOutNames; | |||||
| aOutNames = nullptr; | |||||
| } | |||||
| aIns = aOuts = 0; | |||||
| } | |||||
| CARLA_DECLARE_NON_COPY_STRUCT(Info) | CARLA_DECLARE_NON_COPY_STRUCT(Info) | ||||
| } fInfo; | } fInfo; | ||||
| @@ -21,7 +21,7 @@ | |||||
| #include "CarlaDssiUtils.hpp" | #include "CarlaDssiUtils.hpp" | ||||
| #include "CarlaMathUtils.hpp" | #include "CarlaMathUtils.hpp" | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| # include "CarlaOscUtils.hpp" | # include "CarlaOscUtils.hpp" | ||||
| # include "CarlaPipeUtils.hpp" | # include "CarlaPipeUtils.hpp" | ||||
| # include "CarlaThread.hpp" | # include "CarlaThread.hpp" | ||||
| @@ -63,7 +63,7 @@ CARLA_BACKEND_START_NAMESPACE | |||||
| static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr }; | static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr }; | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| class CarlaThreadDSSIUI : public CarlaThread | class CarlaThreadDSSIUI : public CarlaThread | ||||
| @@ -283,7 +283,7 @@ public: | |||||
| fForcedStereoOut(false), | fForcedStereoOut(false), | ||||
| fNeedsFixedBuffers(false), | fNeedsFixedBuffers(false), | ||||
| fUsesCustomData(false) | fUsesCustomData(false) | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| , fOscData(), | , fOscData(), | ||||
| fThreadUI(engine, this, fOscData), | fThreadUI(engine, this, fOscData), | ||||
| fUiFilename(nullptr) | fUiFilename(nullptr) | ||||
| @@ -298,7 +298,7 @@ public: | |||||
| { | { | ||||
| carla_debug("CarlaPluginDSSI::~CarlaPluginDSSI()"); | carla_debug("CarlaPluginDSSI::~CarlaPluginDSSI()"); | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| // close UI | // close UI | ||||
| if (fUiFilename != nullptr) | if (fUiFilename != nullptr) | ||||
| { | { | ||||
| @@ -594,7 +594,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (sendGui && fOscData.target != nullptr) | if (sendGui && fOscData.target != nullptr) | ||||
| osc_send_configure(fOscData, key, value); | osc_send_configure(fOscData, key, value); | ||||
| #endif | #endif | ||||
| @@ -684,7 +684,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Set ui stuff | // Set ui stuff | ||||
| @@ -1083,7 +1083,7 @@ public: | |||||
| if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties)) | if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties)) | ||||
| pData->hints |= PLUGIN_IS_RTSAFE; | pData->hints |= PLUGIN_IS_RTSAFE; | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| if (fUiFilename != nullptr) | if (fUiFilename != nullptr) | ||||
| pData->hints |= PLUGIN_HAS_CUSTOM_UI; | pData->hints |= PLUGIN_HAS_CUSTOM_UI; | ||||
| #endif | #endif | ||||
| @@ -2184,7 +2184,7 @@ public: | |||||
| carla_debug("CarlaPluginDSSI::clearBuffers() - end"); | carla_debug("CarlaPluginDSSI::clearBuffers() - end"); | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // OSC stuff | // OSC stuff | ||||
| @@ -2443,7 +2443,7 @@ public: | |||||
| osc_send_midi(fOscData, midiData); | osc_send_midi(fOscData, midiData); | ||||
| #endif | #endif | ||||
| } | } | ||||
| #endif // HAVE_LIBLO && !BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| #endif // HAVE_LIBLO && !BUILD_BRIDGE | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -2452,7 +2452,7 @@ public: | |||||
| return fDssiDescriptor; | return fDssiDescriptor; | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| uintptr_t getUiBridgeProcessId() const noexcept override | uintptr_t getUiBridgeProcessId() const noexcept override | ||||
| { | { | ||||
| return fThreadUI.getProcessId(); | return fThreadUI.getProcessId(); | ||||
| @@ -2652,7 +2652,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| // --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
| // check for gui | // check for gui | ||||
| @@ -2718,7 +2718,7 @@ private: | |||||
| bool fNeedsFixedBuffers; | bool fNeedsFixedBuffers; | ||||
| bool fUsesCustomData; | bool fUsesCustomData; | ||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||||
| CarlaOscData fOscData; | CarlaOscData fOscData; | ||||
| CarlaThreadDSSIUI fThreadUI; | CarlaThreadDSSIUI fThreadUI; | ||||
| const char* fUiFilename; | const char* fUiFilename; | ||||
| @@ -572,7 +572,7 @@ void CarlaPlugin::ProtectedData::PostUiEvents::clear() noexcept | |||||
| mutex.unlock(); | mutex.unlock(); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // ProtectedData::PostProc | // ProtectedData::PostProc | ||||
| @@ -594,13 +594,14 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx | |||||
| options(0x0), | options(0x0), | ||||
| nodeId(0), | nodeId(0), | ||||
| active(false), | active(false), | ||||
| bridged(eng->getType() == kEngineTypeBridge), | |||||
| enabled(false), | enabled(false), | ||||
| needsReset(false), | needsReset(false), | ||||
| lib(nullptr), | lib(nullptr), | ||||
| uiLib(nullptr), | uiLib(nullptr), | ||||
| ctrlChannel(0), | ctrlChannel(0), | ||||
| extraHints(0x0), | extraHints(0x0), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| transientTryCounter(0), | transientTryCounter(0), | ||||
| transientFirstTry(true), | transientFirstTry(true), | ||||
| #endif | #endif | ||||
| @@ -623,7 +624,7 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx | |||||
| latency(), | latency(), | ||||
| postRtEvents(), | postRtEvents(), | ||||
| postUiEvents() | postUiEvents() | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| , postProc() | , postProc() | ||||
| #endif | #endif | ||||
| {} | {} | ||||
| @@ -631,7 +632,7 @@ CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx | |||||
| CarlaPlugin::ProtectedData::~ProtectedData() noexcept | CarlaPlugin::ProtectedData::~ProtectedData() noexcept | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT(! (active && needsReset)); | CARLA_SAFE_ASSERT(! (active && needsReset)); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| CARLA_SAFE_ASSERT(transientTryCounter == 0); | CARLA_SAFE_ASSERT(transientTryCounter == 0); | ||||
| #endif | #endif | ||||
| @@ -714,10 +715,10 @@ CarlaPlugin::ProtectedData::~ProtectedData() noexcept | |||||
| masterMutex.unlock(); | masterMutex.unlock(); | ||||
| singleMutex.unlock(); | singleMutex.unlock(); | ||||
| CARLA_SAFE_ASSERT(uiLib == nullptr); | |||||
| if (lib != nullptr) | if (lib != nullptr) | ||||
| libClose(); | libClose(); | ||||
| CARLA_SAFE_ASSERT(uiLib == nullptr); | |||||
| } | } | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -793,7 +794,7 @@ bool CarlaPlugin::ProtectedData::uiLibClose() noexcept | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void CarlaPlugin::ProtectedData::tryTransient() noexcept | void CarlaPlugin::ProtectedData::tryTransient() noexcept | ||||
| { | { | ||||
| if (engine->getOptions().frontendWinId != 0) | if (engine->getOptions().frontendWinId != 0) | ||||
| @@ -217,6 +217,7 @@ struct CarlaPlugin::ProtectedData { | |||||
| uint32_t nodeId; | uint32_t nodeId; | ||||
| bool active; | bool active; | ||||
| bool bridged; | |||||
| bool enabled; | bool enabled; | ||||
| bool needsReset; | bool needsReset; | ||||
| @@ -226,7 +227,7 @@ struct CarlaPlugin::ProtectedData { | |||||
| // misc | // misc | ||||
| int8_t ctrlChannel; | int8_t ctrlChannel; | ||||
| uint extraHints; | uint extraHints; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| uint transientTryCounter; | uint transientTryCounter; | ||||
| bool transientFirstTry; | bool transientFirstTry; | ||||
| #endif | #endif | ||||
| @@ -328,7 +329,7 @@ struct CarlaPlugin::ProtectedData { | |||||
| } postUiEvents; | } postUiEvents; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| struct PostProc { | struct PostProc { | ||||
| float dryWet; | float dryWet; | ||||
| float volume; | float volume; | ||||
| @@ -383,7 +384,7 @@ struct CarlaPlugin::ProtectedData { | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Misc | // Misc | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| void tryTransient() noexcept; | void tryTransient() noexcept; | ||||
| #endif | #endif | ||||
| void updateParameterValues(CarlaPlugin* const plugin, const bool sendOsc, const bool sendCallback, const bool useDefault) noexcept; | void updateParameterValues(CarlaPlugin* const plugin, const bool sendOsc, const bool sendCallback, const bool useDefault) noexcept; | ||||
| @@ -221,7 +221,7 @@ public: | |||||
| { | { | ||||
| carla_debug("CarlaPluginJack::~CarlaPluginJack()"); | carla_debug("CarlaPluginJack::~CarlaPluginJack()"); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // close UI | // close UI | ||||
| if (pData->hints & PLUGIN_HAS_CUSTOM_UI) | if (pData->hints & PLUGIN_HAS_CUSTOM_UI) | ||||
| pData->transientTryCounter = 0; | pData->transientTryCounter = 0; | ||||
| @@ -690,7 +690,7 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
| // Event Input (System) | // Event Input (System) | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool allNotesOffSent = false; | bool allNotesOffSent = false; | ||||
| #endif | #endif | ||||
| for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) | for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i) | ||||
| @@ -712,7 +712,7 @@ public: | |||||
| break; | break; | ||||
| case kEngineControlEventTypeParameter: | case kEngineControlEventTypeParameter: | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -793,7 +793,7 @@ public: | |||||
| case kEngineControlEventTypeAllNotesOff: | case kEngineControlEventTypeAllNotesOff: | ||||
| if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | ||||
| { | { | ||||
| allNotesOffSent = true; | allNotesOffSent = true; | ||||
| @@ -940,7 +940,7 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // TimeInfo | // TimeInfo | ||||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||||
| const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); | |||||
| BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | ||||
| bridgeTimeInfo.playing = timeInfo.playing; | bridgeTimeInfo.playing = timeInfo.playing; | ||||
| @@ -988,7 +988,7 @@ public: | |||||
| for (uint32_t i=0; i < fInfo.aOuts; ++i) | for (uint32_t i=0; i < fInfo.aOuts; ++i) | ||||
| carla_copyFloats(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), frames); | carla_copyFloats(audioOut[i], fShmAudioPool.data + ((i + fInfo.aIns) * frames), frames); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| @@ -1311,7 +1311,7 @@ public: | |||||
| // FIXME dryWet broken | // FIXME dryWet broken | ||||
| pData->hints = PLUGIN_IS_BRIDGE | PLUGIN_OPTION_FIXED_BUFFERS; | pData->hints = PLUGIN_IS_BRIDGE | PLUGIN_OPTION_FIXED_BUFFERS; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->hints |= /*PLUGIN_CAN_DRYWET |*/ PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE; | pData->hints |= /*PLUGIN_CAN_DRYWET |*/ PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE; | ||||
| #endif | #endif | ||||
| //fInfo.optionsAvailable = optionAv; | //fInfo.optionsAvailable = optionAv; | ||||
| @@ -776,7 +776,7 @@ public: | |||||
| if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties)) | if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties)) | ||||
| pData->hints |= PLUGIN_IS_RTSAFE; | pData->hints |= PLUGIN_IS_RTSAFE; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | ||||
| pData->hints |= PLUGIN_CAN_DRYWET; | pData->hints |= PLUGIN_CAN_DRYWET; | ||||
| @@ -971,7 +971,7 @@ public: | |||||
| break; | break; | ||||
| case kEngineControlEventTypeParameter: { | case kEngineControlEventTypeParameter: { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -1194,7 +1194,7 @@ public: | |||||
| carla_copyFloats(fAudioOutBuffers[1], fExtraStereoBuffer[1], frames); | carla_copyFloats(fAudioOutBuffers[1], fExtraStereoBuffer[1], frames); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| @@ -1215,11 +1215,13 @@ public: | |||||
| for (uint32_t k=0; k < frames; ++k) | for (uint32_t k=0; k < frames; ++k) | ||||
| { | { | ||||
| # ifndef BUILD_BRIDGE | |||||
| if (k < pData->latency.frames) | if (k < pData->latency.frames) | ||||
| bufValue = pData->latency.buffers[c][k]; | bufValue = pData->latency.buffers[c][k]; | ||||
| else if (pData->latency.frames < frames) | else if (pData->latency.frames < frames) | ||||
| bufValue = fAudioInBuffers[c][k-pData->latency.frames]; | bufValue = fAudioInBuffers[c][k-pData->latency.frames]; | ||||
| else | else | ||||
| # endif | |||||
| bufValue = fAudioInBuffers[c][k]; | bufValue = fAudioInBuffers[c][k]; | ||||
| fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | ||||
| @@ -1266,6 +1268,7 @@ public: | |||||
| } // End of Post-processing | } // End of Post-processing | ||||
| # ifndef BUILD_BRIDGE | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Save latency values for next callback | // Save latency values for next callback | ||||
| @@ -1294,8 +1297,8 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #else // BUILD_BRIDGE | |||||
| # endif | |||||
| #else // BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | for (uint32_t i=0; i < pData->audioOut.count; ++i) | ||||
| { | { | ||||
| for (uint32_t k=0; k < frames; ++k) | for (uint32_t k=0; k < frames; ++k) | ||||
| @@ -1274,7 +1274,7 @@ public: | |||||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (! yesNo) | if (! yesNo) | ||||
| pData->transientTryCounter = 0; | pData->transientTryCounter = 0; | ||||
| #endif | #endif | ||||
| @@ -1486,7 +1486,7 @@ public: | |||||
| else if (fExt.uishow != nullptr) | else if (fExt.uishow != nullptr) | ||||
| { | { | ||||
| fExt.uishow->show(fUI.handle); | fExt.uishow->show(fUI.handle); | ||||
| # ifndef BUILD_BRIDGE | |||||
| # ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->tryTransient(); | pData->tryTransient(); | ||||
| # endif | # endif | ||||
| } | } | ||||
| @@ -1495,7 +1495,7 @@ public: | |||||
| #endif | #endif | ||||
| { | { | ||||
| LV2_EXTERNAL_UI_SHOW((LV2_External_UI_Widget*)fUI.widget); | LV2_EXTERNAL_UI_SHOW((LV2_External_UI_Widget*)fUI.widget); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->tryTransient(); | pData->tryTransient(); | ||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -1570,7 +1570,7 @@ public: | |||||
| fPipeServer.stopPipeServer(2000); | fPipeServer.stopPipeServer(2000); | ||||
| // fall through | // fall through | ||||
| case CarlaPipeServerLV2::UiCrashed: | case CarlaPipeServerLV2::UiCrashed: | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| pData->transientTryCounter = 0; | pData->transientTryCounter = 0; | ||||
| #endif | #endif | ||||
| pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | ||||
| @@ -2779,7 +2779,7 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // TimeInfo | // TimeInfo | ||||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||||
| const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); | |||||
| if (fFirstActive || fLastTimeInfo != timeInfo) | if (fFirstActive || fLastTimeInfo != timeInfo) | ||||
| { | { | ||||
| @@ -3023,7 +3023,7 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
| // Event Input (System) | // Event Input (System) | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool allNotesOffSent = false; | bool allNotesOffSent = false; | ||||
| #endif | #endif | ||||
| bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; | bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; | ||||
| @@ -3121,7 +3121,7 @@ public: | |||||
| break; | break; | ||||
| case kEngineControlEventTypeParameter: { | case kEngineControlEventTypeParameter: { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -3306,7 +3306,7 @@ public: | |||||
| case kEngineControlEventTypeAllNotesOff: | case kEngineControlEventTypeAllNotesOff: | ||||
| if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | ||||
| { | { | ||||
| allNotesOffSent = true; | allNotesOffSent = true; | ||||
| @@ -3503,7 +3503,7 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Control Output | // Control Output | ||||
| @@ -3642,7 +3642,7 @@ public: | |||||
| pData->postRtEvents.trySplice(); | pData->postRtEvents.trySplice(); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| @@ -3663,11 +3663,13 @@ public: | |||||
| for (uint32_t k=0; k < frames; ++k) | for (uint32_t k=0; k < frames; ++k) | ||||
| { | { | ||||
| # ifndef BUILD_BRIDGE | |||||
| if (k < pData->latency.frames) | if (k < pData->latency.frames) | ||||
| bufValue = pData->latency.buffers[c][k]; | bufValue = pData->latency.buffers[c][k]; | ||||
| else if (pData->latency.frames < frames) | else if (pData->latency.frames < frames) | ||||
| bufValue = fAudioInBuffers[c][k-pData->latency.frames]; | bufValue = fAudioInBuffers[c][k-pData->latency.frames]; | ||||
| else | else | ||||
| # endif | |||||
| bufValue = fAudioInBuffers[c][k]; | bufValue = fAudioInBuffers[c][k]; | ||||
| fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet)); | ||||
| @@ -3713,6 +3715,7 @@ public: | |||||
| } | } | ||||
| } // End of Post-processing | } // End of Post-processing | ||||
| # ifndef BUILD_BRIDGE | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Save latency values for next callback | // Save latency values for next callback | ||||
| @@ -3741,8 +3744,8 @@ public: | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #else // BUILD_BRIDGE | |||||
| # endif | |||||
| #else // BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| for (uint32_t i=0; i < pData->audioOut.count; ++i) | for (uint32_t i=0; i < pData->audioOut.count; ++i) | ||||
| { | { | ||||
| for (uint32_t k=0; k < frames; ++k) | for (uint32_t k=0; k < frames; ++k) | ||||
| @@ -4853,7 +4856,7 @@ public: | |||||
| { | { | ||||
| if (pData->param.data[i].rindex == rindex) | if (pData->param.data[i].rindex == rindex) | ||||
| { | { | ||||
| setParameterValue(i, paramValue, true, true, true); | |||||
| setParameterValueRT(i, paramValue); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| @@ -5287,7 +5290,7 @@ public: | |||||
| #if defined(LV2_UIS_ONLY_BRIDGES) | #if defined(LV2_UIS_ONLY_BRIDGES) | ||||
| const bool preferUiBridges = true; | const bool preferUiBridges = true; | ||||
| #elif defined(BUILD_BRIDGE) | |||||
| #elif defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| const bool preferUiBridges = false; | const bool preferUiBridges = false; | ||||
| #else | #else | ||||
| const bool preferUiBridges = pData->engine->getOptions().preferUiBridges; | const bool preferUiBridges = pData->engine->getOptions().preferUiBridges; | ||||
| @@ -5383,7 +5386,7 @@ public: | |||||
| else if (iExt >= 0) | else if (iExt >= 0) | ||||
| iFinal = iExt; | iFinal = iExt; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (iFinal < 0) | if (iFinal < 0) | ||||
| #endif | #endif | ||||
| { | { | ||||
| @@ -5459,7 +5462,7 @@ public: | |||||
| iFinal == eCocoa || | iFinal == eCocoa || | ||||
| iFinal == eWindows || | iFinal == eWindows || | ||||
| iFinal == eX11) | iFinal == eX11) | ||||
| #ifdef BUILD_BRIDGE | |||||
| #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| && ! hasShowInterface | && ! hasShowInterface | ||||
| #endif | #endif | ||||
| ) | ) | ||||
| @@ -6273,7 +6276,7 @@ private: | |||||
| static void carla_lv2_inline_display_queue_draw(LV2_Inline_Display_Handle handle) | static void carla_lv2_inline_display_queue_draw(LV2_Inline_Display_Handle handle) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | ||||
| carla_debug("carla_lv2_inline_display_queue_draw(%p)", handle); | |||||
| // carla_debug("carla_lv2_inline_display_queue_draw(%p)", handle); | |||||
| ((CarlaPluginLV2*)handle)->handleInlineDisplayQueueRedraw(); | ((CarlaPluginLV2*)handle)->handleInlineDisplayQueueRedraw(); | ||||
| } | } | ||||
| @@ -708,7 +708,7 @@ public: | |||||
| CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',); | CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',); | ||||
| CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',); | ||||
| CARLA_SAFE_ASSERT_RETURN(value != nullptr,); | CARLA_SAFE_ASSERT_RETURN(value != nullptr,); | ||||
| carla_debug("CarlaPluginNative::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui)); | |||||
| carla_debug("CarlaPluginNative::setCustomData(%s, %s, ..., %s)", type, key, bool2str(sendGui)); | |||||
| if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) | if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0) | ||||
| return CarlaPlugin::setCustomData(type, key, value, sendGui); | return CarlaPlugin::setCustomData(type, key, value, sendGui); | ||||
| @@ -1537,7 +1537,7 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Set TimeInfo | // Set TimeInfo | ||||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||||
| const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); | |||||
| fTimeInfo.playing = timeInfo.playing; | fTimeInfo.playing = timeInfo.playing; | ||||
| fTimeInfo.frame = timeInfo.frame; | fTimeInfo.frame = timeInfo.frame; | ||||
| @@ -1563,6 +1563,39 @@ public: | |||||
| fTimeInfo.bbt.valid = false; | fTimeInfo.bbt.valid = false; | ||||
| } | } | ||||
| #if 0 | |||||
| // This test code has proven to be quite useful | |||||
| // So I am leaving it behind, I might need it again.. | |||||
| if (pData->id == 1) | |||||
| { | |||||
| static int64_t last_frame = timeInfo.frame; | |||||
| static int64_t last_dev_frame = 0; | |||||
| static double last_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick; | |||||
| static double last_dev_val = 0.0; | |||||
| int64_t cur_frame = timeInfo.frame; | |||||
| int64_t cur_dev_frame = cur_frame - last_frame; | |||||
| double cur_val = timeInfo.bbt.barStartTick + ((timeInfo.bbt.beat-1) * timeInfo.bbt.ticksPerBeat) + timeInfo.bbt.tick; | |||||
| double cur_dev_val = cur_val - last_val; | |||||
| if (std::abs(last_dev_val - cur_dev_val) >= 0.0001 || last_dev_frame != cur_dev_frame) | |||||
| { | |||||
| carla_stdout("currently %u at %u => %f : DEV1: %li : DEV2: %f", | |||||
| frames, | |||||
| timeInfo.frame, | |||||
| cur_val, | |||||
| cur_dev_frame, | |||||
| cur_dev_val); | |||||
| } | |||||
| last_val = cur_val; | |||||
| last_dev_val = cur_dev_val; | |||||
| last_frame = cur_frame; | |||||
| last_dev_frame = cur_dev_frame; | |||||
| } | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Event Input and Processing | // Event Input and Processing | ||||
| @@ -363,7 +363,7 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
| // Event Input (System) | // Event Input (System) | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool allNotesOffSent = false; | bool allNotesOffSent = false; | ||||
| #endif | #endif | ||||
| uint32_t timeOffset = 0; | uint32_t timeOffset = 0; | ||||
| @@ -404,7 +404,7 @@ public: | |||||
| case kEngineControlEventTypeParameter: | case kEngineControlEventTypeParameter: | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -493,7 +493,7 @@ public: | |||||
| case kEngineControlEventTypeAllNotesOff: | case kEngineControlEventTypeAllNotesOff: | ||||
| if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | ||||
| { | { | ||||
| allNotesOffSent = true; | allNotesOffSent = true; | ||||
| @@ -583,13 +583,13 @@ public: | |||||
| fSynth.renderVoices(audioOutBuffer, timeOffset, frames); | fSynth.renderVoices(audioOutBuffer, timeOffset, frames); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| { | { | ||||
| const bool doVolume = carla_isNotEqual(pData->postProc.volume, 1.0f); | const bool doVolume = carla_isNotEqual(pData->postProc.volume, 1.0f); | ||||
| const bool doBalance = carla_isNotEqual(pData->postProc.balanceLeft, -1.0f) || carla_isNotEqual(pData->postProc.balanceRight, 1.0f); | |||||
| //const bool doBalance = carla_isNotEqual(pData->postProc.balanceLeft, -1.0f) || carla_isNotEqual(pData->postProc.balanceRight, 1.0f); | |||||
| float* outBufferL = audioOutBuffer.getWritePointer(0, timeOffset); | float* outBufferL = audioOutBuffer.getWritePointer(0, timeOffset); | ||||
| float* outBufferR = audioOutBuffer.getWritePointer(1, timeOffset); | float* outBufferR = audioOutBuffer.getWritePointer(1, timeOffset); | ||||
| @@ -481,14 +481,16 @@ public: | |||||
| const char* msg = nullptr; | const char* msg = nullptr; | ||||
| const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | const uintptr_t frontendWinId(pData->engine->getOptions().frontendWinId); | ||||
| #if defined(CARLA_OS_MAC) && defined(CARLA_OS_64BIT) | |||||
| #if defined(CARLA_OS_MAC) | |||||
| fUI.window = CarlaPluginUI::newCocoa(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newCocoa(this, frontendWinId, false); | ||||
| #elif defined(CARLA_OS_WIN) | #elif defined(CARLA_OS_WIN) | ||||
| fUI.window = CarlaPluginUI::newWindows(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newWindows(this, frontendWinId, false); | ||||
| #elif defined(HAVE_X11) | #elif defined(HAVE_X11) | ||||
| fUI.window = CarlaPluginUI::newX11(this, frontendWinId, false); | fUI.window = CarlaPluginUI::newX11(this, frontendWinId, false); | ||||
| #else | #else | ||||
| msg = "Unknown UI type"; | |||||
| msg = "Unsupported UI type"; | |||||
| // unused | |||||
| (void)frontendWinId; | |||||
| #endif | #endif | ||||
| if (fUI.window == nullptr) | if (fUI.window == nullptr) | ||||
| @@ -862,7 +864,13 @@ public: | |||||
| if (fEffect->flags & effFlagsHasEditor) | if (fEffect->flags & effFlagsHasEditor) | ||||
| { | { | ||||
| pData->hints |= PLUGIN_HAS_CUSTOM_UI; | |||||
| #ifndef CARLA_OS_64BIT | |||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosViewAsConfig")) & 0xffff0000) == 0xbeef0000) | |||||
| #endif | |||||
| { | |||||
| pData->hints |= PLUGIN_HAS_CUSTOM_UI; | |||||
| } | |||||
| pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD; | pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD; | ||||
| } | } | ||||
| @@ -872,7 +880,7 @@ public: | |||||
| if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) | if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) | ||||
| pData->hints |= PLUGIN_CAN_PROCESS_REPLACING; | pData->hints |= PLUGIN_CAN_PROCESS_REPLACING; | ||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosExtensions"), 0.0f)) == 0xbeef0000) | |||||
| if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>("hasCockosExtensions"))) == 0xbeef0000) | |||||
| pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; | pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; | ||||
| if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | if (aOuts > 0 && (aIns == aOuts || aIns == 1)) | ||||
| @@ -1113,7 +1121,7 @@ public: | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Set TimeInfo | // Set TimeInfo | ||||
| const EngineTimeInfo& timeInfo(pData->engine->getTimeInfo()); | |||||
| const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); | |||||
| fTimeInfo.flags = kVstTransportChanged; | fTimeInfo.flags = kVstTransportChanged; | ||||
| @@ -1205,7 +1213,7 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------- | ||||
| // Event Input (System) | // Event Input (System) | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool allNotesOffSent = false; | bool allNotesOffSent = false; | ||||
| #endif | #endif | ||||
| bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; | bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0; | ||||
| @@ -1258,7 +1266,7 @@ public: | |||||
| break; | break; | ||||
| case kEngineControlEventTypeParameter: { | case kEngineControlEventTypeParameter: { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // Control backend stuff | // Control backend stuff | ||||
| if (event.channel == pData->ctrlChannel) | if (event.channel == pData->ctrlChannel) | ||||
| { | { | ||||
| @@ -1417,7 +1425,7 @@ public: | |||||
| case kEngineControlEventTypeAllNotesOff: | case kEngineControlEventTypeAllNotesOff: | ||||
| if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | ||||
| { | { | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | if (event.channel == pData->ctrlChannel && ! allNotesOffSent) | ||||
| { | { | ||||
| allNotesOffSent = true; | allNotesOffSent = true; | ||||
| @@ -1608,7 +1616,7 @@ public: | |||||
| fIsProcessing = false; | fIsProcessing = false; | ||||
| fTimeInfo.samplePos += frames; | fTimeInfo.samplePos += frames; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // -------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------- | ||||
| // Post-processing (dry/wet, volume and balance) | // Post-processing (dry/wet, volume and balance) | ||||
| @@ -2085,7 +2093,9 @@ protected: | |||||
| } | } | ||||
| } | } | ||||
| pData->engine->callback(ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0.0f, nullptr); | |||||
| if (! fIsInitializing) | |||||
| pData->engine->callback(ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0.0f, nullptr); | |||||
| ret = 1; | ret = 1; | ||||
| break; | break; | ||||
| @@ -2357,9 +2367,6 @@ public: | |||||
| } | } | ||||
| return true; | return true; | ||||
| // unused | |||||
| (void)uniqueId; | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -0,0 +1,576 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaNative.h" | |||||
| #include "CarlaString.hpp" | |||||
| #include "CarlaLv2Utils.hpp" | |||||
| #ifdef DEBUG | |||||
| # include "CarlaBackendUtils.hpp" | |||||
| #endif | |||||
| #include "water/containers/Array.h" | |||||
| #include "water/files/File.h" | |||||
| namespace CB = CarlaBackend; | |||||
| using water::Array; | |||||
| using water::File; | |||||
| using water::String; | |||||
| using water::StringArray; | |||||
| static const char* const gNullCharPtr = ""; | |||||
| static bool isCachedPluginType(const CB::PluginType ptype) | |||||
| { | |||||
| switch (ptype) | |||||
| { | |||||
| case CB::PLUGIN_INTERNAL: | |||||
| case CB::PLUGIN_LV2: | |||||
| case CB::PLUGIN_SFZ: | |||||
| return true; | |||||
| default: | |||||
| return false; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept | |||||
| : valid(false), | |||||
| 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 Array<File> gSFZs; | |||||
| void findSFZsIfNeeded(const char* const sfzPaths) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(sfzPaths != nullptr && sfzPaths[0] != '\0',); | |||||
| static bool needsInit = true; | |||||
| if (! needsInit) | |||||
| return; | |||||
| needsInit = false; | |||||
| const StringArray splitPaths(StringArray::fromTokens(sfzPaths, CARLA_OS_SPLIT_STR, "")); | |||||
| for (String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it) | |||||
| { | |||||
| Array<File> results; | |||||
| if (File(*it).findChildFiles(results, File::findFiles|File::ignoreHiddenFiles, true, "*.sfz") > 0) | |||||
| gSFZs.addArray(results); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const CarlaCachedPluginInfo* get_cached_plugin_internal(const NativePluginDescriptor& desc) | |||||
| { | |||||
| static CarlaCachedPluginInfo info; | |||||
| 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_UI_MAIN_THREAD) | |||||
| info.hints |= CB::PLUGIN_NEEDS_UI_MAIN_THREAD; | |||||
| if (desc.hints & NATIVE_PLUGIN_USES_MULTI_PROGS) | |||||
| info.hints |= CB::PLUGIN_USES_MULTI_PROGS; | |||||
| info.valid = true; | |||||
| info.audioIns = desc.audioIns; | |||||
| info.audioOuts = desc.audioOuts; | |||||
| info.midiIns = desc.midiIns; | |||||
| info.midiOuts = desc.midiOuts; | |||||
| info.parameterIns = desc.paramIns; | |||||
| info.parameterOuts = desc.paramOuts; | |||||
| info.name = desc.name; | |||||
| info.label = desc.label; | |||||
| info.maker = desc.maker; | |||||
| info.copyright = desc.copyright; | |||||
| return &info; | |||||
| } | |||||
| const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2World, Lilv::Plugin& lilvPlugin) | |||||
| { | |||||
| static CarlaCachedPluginInfo info; | |||||
| info.valid = false; | |||||
| bool supported = true; | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| // text data | |||||
| { | |||||
| static CarlaString suri, sname, smaker, slicense; | |||||
| suri.clear(); sname.clear(); smaker.clear(); slicense.clear(); | |||||
| suri = lilvPlugin.get_uri().as_uri(); | |||||
| if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me)) | |||||
| { | |||||
| if (const char* const name = lilv_node_as_string(nameNode)) | |||||
| sname = name; | |||||
| lilv_node_free(nameNode); | |||||
| } | |||||
| if (const char* const author = lilvPlugin.get_author_name().as_string()) | |||||
| smaker = author; | |||||
| 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.buffer(); | |||||
| info.label = suri.buffer(); | |||||
| info.maker = smaker.buffer(); | |||||
| info.copyright = slicense.buffer(); | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| // features | |||||
| info.hints = 0x0; | |||||
| if (lilvPlugin.get_uis().size() > 0) | |||||
| info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; | |||||
| { | |||||
| Lilv::Nodes lilvRequiredFeatureNodes(lilvPlugin.get_required_features()); | |||||
| LILV_FOREACH(nodes, it, lilvRequiredFeatureNodes) | |||||
| { | |||||
| Lilv::Node lilvFeatureNode(lilvRequiredFeatureNodes.get(it)); | |||||
| const char* const featureURI(lilvFeatureNode.as_uri()); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr); | |||||
| if (! is_lv2_feature_supported(featureURI)) | |||||
| { | |||||
| if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0 | |||||
| || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0) | |||||
| { | |||||
| // we give a warning about this below | |||||
| continue; | |||||
| } | |||||
| supported = false; | |||||
| carla_stderr("LV2 plugin '%s' requires unsupported feature '%s'", info.label, featureURI); | |||||
| } | |||||
| } | |||||
| lilv_nodes_free(const_cast<LilvNodes*>(lilvRequiredFeatureNodes.me)); | |||||
| } | |||||
| { | |||||
| Lilv::Nodes lilvSupportedFeatureNodes(lilvPlugin.get_supported_features()); | |||||
| LILV_FOREACH(nodes, it, lilvSupportedFeatureNodes) | |||||
| { | |||||
| Lilv::Node lilvFeatureNode(lilvSupportedFeatureNodes.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; | |||||
| } | |||||
| else if (std::strcmp(featureURI, LV2_DATA_ACCESS_URI) == 0 | |||||
| || std::strcmp(featureURI, LV2_INSTANCE_ACCESS_URI) == 0) | |||||
| { | |||||
| carla_stderr("LV2 plugin '%s' DSP wants UI feature '%s', ignoring this", info.label, featureURI); | |||||
| } | |||||
| } | |||||
| lilv_nodes_free(const_cast<LilvNodes*>(lilvSupportedFeatureNodes.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 | |||||
| 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 | |||||
| { | |||||
| const LilvNode* const symbolNode = lilvPort.get_symbol(); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode)); | |||||
| const char* const symbol = lilv_node_as_string(symbolNode); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr); | |||||
| carla_stderr("LV2 plugin '%s' port '%s' is neither input or output", info.label, symbol); | |||||
| 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); | |||||
| } | |||||
| else | |||||
| { | |||||
| const LilvNode* const symbolNode = lilvPort.get_symbol(); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(symbolNode != nullptr && lilv_node_is_string(symbolNode)); | |||||
| const char* const symbol = lilv_node_as_string(symbolNode); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr); | |||||
| supported = false; | |||||
| carla_stderr("LV2 plugin '%s' port '%s' is required but has unsupported type", info.label, symbol); | |||||
| } | |||||
| } | |||||
| if (supported) | |||||
| info.valid = true; | |||||
| return &info; | |||||
| } | |||||
| const CarlaCachedPluginInfo* get_cached_plugin_sfz(const File file) | |||||
| { | |||||
| static CarlaCachedPluginInfo info; | |||||
| static CarlaString name, filename; | |||||
| name = file.getFileNameWithoutExtension().toRawUTF8(); | |||||
| name.replace('_',' '); | |||||
| filename = file.getFullPathName().toRawUTF8(); | |||||
| info.category = CB::PLUGIN_CATEGORY_SYNTH; | |||||
| info.hints = CB::PLUGIN_IS_SYNTH; | |||||
| // CB::PLUGIN_IS_RTSAFE | |||||
| info.valid = true; | |||||
| info.audioIns = 0; | |||||
| info.audioOuts = 2; | |||||
| info.midiIns = 1; | |||||
| info.midiOuts = 0; | |||||
| info.parameterIns = 0; | |||||
| info.parameterOuts = 1; | |||||
| info.name = name.buffer(); | |||||
| info.label = filename.buffer(); | |||||
| info.maker = gNullCharPtr; | |||||
| info.copyright = gNullCharPtr; | |||||
| return &info; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| uint carla_get_cached_plugin_count(CB::PluginType ptype, const char* pluginPath) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(isCachedPluginType(ptype), 0); | |||||
| carla_debug("carla_get_cached_plugin_count(%i:%s, %s)", ptype, CB::PluginType2Str(ptype), pluginPath); | |||||
| switch (ptype) | |||||
| { | |||||
| case CB::PLUGIN_INTERNAL: { | |||||
| uint32_t count = 0; | |||||
| carla_get_native_plugins_data(&count); | |||||
| return count; | |||||
| } | |||||
| case CB::PLUGIN_LV2: { | |||||
| Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); | |||||
| lv2World.initIfNeeded(pluginPath); | |||||
| return lv2World.getPluginCount(); | |||||
| } | |||||
| case CB::PLUGIN_SFZ: { | |||||
| findSFZsIfNeeded(pluginPath); | |||||
| return gSFZs.size(); | |||||
| } | |||||
| default: | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype, uint index) | |||||
| { | |||||
| carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index); | |||||
| switch (ptype) | |||||
| { | |||||
| case CB::PLUGIN_INTERNAL: { | |||||
| uint32_t count = 0; | |||||
| const NativePluginDescriptor* const descs(carla_get_native_plugins_data(&count)); | |||||
| CARLA_SAFE_ASSERT_BREAK(index < count); | |||||
| CARLA_SAFE_ASSERT_BREAK(descs != nullptr); | |||||
| const NativePluginDescriptor& desc(descs[index]); | |||||
| return get_cached_plugin_internal(desc); | |||||
| } | |||||
| case CB::PLUGIN_LV2: { | |||||
| Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); | |||||
| const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index)); | |||||
| CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr); | |||||
| Lilv::Plugin lilvPlugin(cPlugin); | |||||
| CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri()); | |||||
| return get_cached_plugin_lv2(lv2World, lilvPlugin); | |||||
| } | |||||
| case CB::PLUGIN_SFZ: { | |||||
| CARLA_SAFE_ASSERT_BREAK(index < static_cast<uint>(gSFZs.size())); | |||||
| return get_cached_plugin_sfz(gSFZs.getUnchecked(index)); | |||||
| } | |||||
| default: | |||||
| break; | |||||
| } | |||||
| static CarlaCachedPluginInfo info; | |||||
| return &info; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #include "../native-plugins/_data.all.cpp" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,158 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaString.hpp" | |||||
| #include "rtaudio/RtAudio.h" | |||||
| #include "rtmidi/RtMidi.h" | |||||
| #include "water/files/File.h" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| 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>" | |||||
| "<li>VST2 plugin support using VeSTige header by Javier Serrano Polo</li>" | |||||
| // Sample kit libraries | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "<li>FluidSynth library for SF2/3 support</li>" | |||||
| #endif | |||||
| "<li>SFZero module for SFZ support</li>" | |||||
| // misc libs | |||||
| "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</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 v" RTAUDIO_VERSION " and RtMidi v" RTMIDI_VERSION " for native Audio and MIDI support</li>" | |||||
| // Internal plugins | |||||
| "<li>MIDI Sequencer UI code by Perry Nguyen</li>" | |||||
| // External plugins | |||||
| #ifdef HAVE_EXTERNAL_PLUGINS | |||||
| "<li>Nekobi plugin code based on nekobee by Sean Bolton and others</li>" | |||||
| "<li>VectorJuice and WobbleJuice plugin code by Andre Sklenar</li>" | |||||
| # ifdef HAVE_ZYN_DEPS | |||||
| "<li>ZynAddSubFX plugin code by Mark McCurry and Nasca Octavian Paul</li>" | |||||
| # endif | |||||
| #endif // HAVE_EXTERNAL_PLUGINS | |||||
| // end | |||||
| "</ul>"; | |||||
| } | |||||
| return retText; | |||||
| } | |||||
| const char* const* carla_get_supported_file_extensions() | |||||
| { | |||||
| carla_debug("carla_get_supported_file_extensions()"); | |||||
| // NOTE: please keep in sync with CarlaEngine::loadFile!! | |||||
| static const char* const extensions[] = { | |||||
| // Base types | |||||
| "carxp", "carxs", | |||||
| // plugin files and resources | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "sf2", "sf3", | |||||
| #endif | |||||
| #ifdef HAVE_ZYN_DEPS | |||||
| "xmz", "xiz", | |||||
| #endif | |||||
| #if defined(CARLA_OS_MAC) | |||||
| "vst", | |||||
| #else | |||||
| "dll", | |||||
| "so", | |||||
| #endif | |||||
| // Audio files | |||||
| #ifdef HAVE_SNDFILE | |||||
| "aif", "aifc", "aiff", "au", "bwf", "flac", "htk", "iff", "mat4", "mat5", "oga", "ogg", | |||||
| "paf", "pvf", "pvf5", "sd2", "sf", "snd", "svx", "vcc", "w64", "wav", "xi", | |||||
| #endif | |||||
| #ifdef HAVE_FFMPEG | |||||
| "3g2", "3gp", "aac", "ac3", "amr", "ape", "mp2", "mp3", "mpc", "wma", | |||||
| # ifdef HAVE_SNDFILE | |||||
| // FFmpeg without sndfile | |||||
| "flac", "oga", "ogg", "w64", "wav", | |||||
| # endif | |||||
| #endif | |||||
| // MIDI files | |||||
| "mid", "midi", | |||||
| // SFZ | |||||
| "sfz", | |||||
| // terminator | |||||
| nullptr | |||||
| }; | |||||
| return extensions; | |||||
| } | |||||
| const char* const* carla_get_supported_features() | |||||
| { | |||||
| carla_debug("carla_get_supported_features()"); | |||||
| static const char* const features[] = { | |||||
| #ifdef HAVE_FLUIDSYNTH | |||||
| "sf2", | |||||
| #endif | |||||
| #ifdef HAVE_HYLIA | |||||
| "link", | |||||
| #endif | |||||
| #ifdef HAVE_LIBLO | |||||
| "osc", | |||||
| #endif | |||||
| #if defined(HAVE_LIBMAGIC) || defined(CARLA_OS_WIN) | |||||
| "bridges", | |||||
| #endif | |||||
| #ifdef HAVE_PYQT | |||||
| "gui", | |||||
| #endif | |||||
| nullptr | |||||
| }; | |||||
| return features; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #include "../CarlaHostCommon.cpp" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,72 @@ | |||||
| #!/usr/bin/make -f | |||||
| # Makefile for carla-plugin # | |||||
| # ------------------------- # | |||||
| # Created by falkTX | |||||
| # | |||||
| CWD=../.. | |||||
| include ../Makefile.mk | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| OBJS = \ | |||||
| $(OBJDIR)/CachedPlugins.cpp.o \ | |||||
| $(OBJDIR)/Information.cpp.o \ | |||||
| $(OBJDIR)/PipeClient.cpp.o \ | |||||
| $(OBJDIR)/System.cpp.o \ | |||||
| $(OBJDIR)/Windows.cpp.o | |||||
| TARGETS = $(BINDIR)/libcarla_utils$(LIB_EXT) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| LIBS = $(MODULEDIR)/lilv.a | |||||
| LIBS += $(MODULEDIR)/water.files.a | |||||
| LINK_FLAGS += $(LILV_LIBS) | |||||
| LINK_FLAGS += $(WATER_LIBS) | |||||
| ifeq ($(HAVE_X11),true) | |||||
| LINK_FLAGS += $(X11_LIBS) | |||||
| endif | |||||
| ifneq ($(HAIKU),true) | |||||
| LINK_FLAGS += -lpthread | |||||
| endif | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| all: $(TARGETS) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| clean: | |||||
| rm -f $(OBJS) $(TARGETS) | |||||
| debug: | |||||
| $(MAKE) DEBUG=true | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| $(BINDIR)/libcarla_utils$(LIB_EXT): $(OBJS) $(LIBS) | |||||
| -@mkdir -p $(BINDIR) | |||||
| @echo "Linking libcarla_utils$(LIB_EXT)" | |||||
| @$(CXX) $(OBJS) $(LIBS_START) $(LIBS) $(LIBS_END) $(LINK_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| ifeq ($(MACOS),true) | |||||
| $(OBJDIR)/Windows.cpp.o: Windows.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | |||||
| endif | |||||
| $(OBJDIR)/%.cpp.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
| -include $(OBJS:%.o=%.d) | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,169 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaPipeUtils.hpp" | |||||
| namespace CB = CarlaBackend; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| class ExposedCarlaPipeClient : public CarlaPipeClient | |||||
| { | |||||
| public: | |||||
| ExposedCarlaPipeClient(const CarlaPipeCallbackFunc callbackFunc, void* const callbackPtr) noexcept | |||||
| : CarlaPipeClient(), | |||||
| fCallbackFunc(callbackFunc), | |||||
| fCallbackPtr(callbackPtr), | |||||
| fLastReadLine(nullptr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT(fCallbackFunc != nullptr); | |||||
| } | |||||
| ~ExposedCarlaPipeClient() override | |||||
| { | |||||
| if (fLastReadLine != nullptr) | |||||
| { | |||||
| delete[] fLastReadLine; | |||||
| fLastReadLine = nullptr; | |||||
| } | |||||
| } | |||||
| const char* readlineblock(const uint timeout) noexcept | |||||
| { | |||||
| delete[] fLastReadLine; | |||||
| fLastReadLine = CarlaPipeClient::_readlineblock(timeout); | |||||
| return fLastReadLine; | |||||
| } | |||||
| bool msgReceived(const char* const msg) noexcept override | |||||
| { | |||||
| if (fCallbackFunc != nullptr) | |||||
| { | |||||
| try { | |||||
| fCallbackFunc(fCallbackPtr, msg); | |||||
| } CARLA_SAFE_EXCEPTION("msgReceived"); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| private: | |||||
| const CarlaPipeCallbackFunc fCallbackFunc; | |||||
| void* const fCallbackPtr; | |||||
| const char* fLastReadLine; | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExposedCarlaPipeClient) | |||||
| }; | |||||
| CarlaPipeClientHandle carla_pipe_client_new(const char* argv[], CarlaPipeCallbackFunc callbackFunc, void* callbackPtr) | |||||
| { | |||||
| carla_debug("carla_pipe_client_new(%p, %p, %p)", argv, callbackFunc, callbackPtr); | |||||
| ExposedCarlaPipeClient* const pipe = new ExposedCarlaPipeClient(callbackFunc, callbackPtr); | |||||
| if (! pipe->initPipeClient(argv)) | |||||
| { | |||||
| delete pipe; | |||||
| return nullptr; | |||||
| } | |||||
| return pipe; | |||||
| } | |||||
| void carla_pipe_client_idle(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| ((ExposedCarlaPipeClient*)handle)->idlePipe(); | |||||
| } | |||||
| bool carla_pipe_client_is_running(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((ExposedCarlaPipeClient*)handle)->isPipeRunning(); | |||||
| } | |||||
| void carla_pipe_client_lock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| return ((ExposedCarlaPipeClient*)handle)->lockPipe(); | |||||
| } | |||||
| void carla_pipe_client_unlock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| return ((ExposedCarlaPipeClient*)handle)->unlockPipe(); | |||||
| } | |||||
| const char* carla_pipe_client_readlineblock(CarlaPipeClientHandle handle, uint timeout) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); | |||||
| return ((ExposedCarlaPipeClient*)handle)->readlineblock(timeout); | |||||
| } | |||||
| bool carla_pipe_client_write_msg(CarlaPipeClientHandle handle, const char* msg) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((ExposedCarlaPipeClient*)handle)->writeMessage(msg); | |||||
| } | |||||
| bool carla_pipe_client_write_and_fix_msg(CarlaPipeClientHandle handle, const char* msg) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((ExposedCarlaPipeClient*)handle)->writeAndFixMessage(msg); | |||||
| } | |||||
| bool carla_pipe_client_flush(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| return ((ExposedCarlaPipeClient*)handle)->flushMessages(); | |||||
| } | |||||
| bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||||
| ExposedCarlaPipeClient* const pipe = (ExposedCarlaPipeClient*)handle; | |||||
| const bool ret = pipe->flushMessages(); | |||||
| pipe->unlockPipe(); | |||||
| return ret; | |||||
| } | |||||
| void carla_pipe_client_destroy(CarlaPipeClientHandle handle) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||||
| carla_debug("carla_pipe_client_destroy(%p)", handle); | |||||
| ExposedCarlaPipeClient* const pipe = (ExposedCarlaPipeClient*)handle; | |||||
| pipe->closePipeClient(); | |||||
| delete pipe; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| #include "CarlaPipeUtils.cpp" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,41 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaThread.hpp" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void carla_fflush(bool err) | |||||
| { | |||||
| std::fflush(err ? stderr : stdout); | |||||
| } | |||||
| void carla_fputs(bool err, const char* string) | |||||
| { | |||||
| std::fputs(string, err ? stderr : stdout); | |||||
| } | |||||
| void carla_set_process_name(const char* name) | |||||
| { | |||||
| carla_debug("carla_set_process_name(\"%s\")", name); | |||||
| CarlaThread::setCurrentThreadName(name); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,108 @@ | |||||
| /* | |||||
| * Carla Plugin Host | |||||
| * Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "CarlaUtils.h" | |||||
| #include "CarlaUtils.hpp" | |||||
| #ifdef CARLA_OS_MAC | |||||
| # import <Cocoa/Cocoa.h> | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| # include <X11/Xlib.h> | |||||
| #endif | |||||
| namespace CB = CarlaBackend; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void carla_x11_reparent_window(uintptr_t winId1, uintptr_t winId2) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(winId1 != 0,); | |||||
| CARLA_SAFE_ASSERT_RETURN(winId2 != 0,); | |||||
| #ifdef HAVE_X11 | |||||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| XReparentWindow(disp, winId1, winId2, 0, 0); | |||||
| XMapWindow(disp, winId1); | |||||
| XCloseDisplay(disp); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| void carla_x11_move_window(uintptr_t winId, int x, int y) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(winId != 0,); | |||||
| #ifdef HAVE_X11 | |||||
| if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| XMoveWindow(disp, winId, x, y); | |||||
| XCloseDisplay(disp); | |||||
| } | |||||
| #else | |||||
| // unused | |||||
| return; (void)x; (void)y; | |||||
| #endif | |||||
| } | |||||
| int* carla_x11_get_window_pos(uintptr_t winId) | |||||
| { | |||||
| static int pos[2]; | |||||
| if (winId == 0) | |||||
| { | |||||
| pos[0] = 0; | |||||
| pos[1] = 0; | |||||
| } | |||||
| #ifdef HAVE_X11 | |||||
| else if (::Display* const disp = XOpenDisplay(nullptr)) | |||||
| { | |||||
| int x, y; | |||||
| Window child; | |||||
| XWindowAttributes xwa; | |||||
| XTranslateCoordinates(disp, winId, XRootWindow(disp, 0), 0, 0, &x, &y, &child); | |||||
| XGetWindowAttributes(disp, winId, &xwa); | |||||
| XCloseDisplay(disp); | |||||
| pos[0] = x - xwa.x; | |||||
| pos[1] = y - xwa.y; | |||||
| } | |||||
| #endif | |||||
| else | |||||
| { | |||||
| pos[0] = 0; | |||||
| pos[1] = 0; | |||||
| } | |||||
| return pos; | |||||
| } | |||||
| int carla_cocoa_get_window(void* nsViewPtr) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(nsViewPtr != nullptr, 0); | |||||
| #ifdef CARLA_OS_MAC | |||||
| NSView* const nsView = (NSView*)nsViewPtr; | |||||
| return [[nsView window] windowNumber]; | |||||
| #else | |||||
| return 0; | |||||
| #endif | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -40,7 +40,7 @@ public: | |||||
| CarlaEngineSingleLV2(const double sampleRate, | CarlaEngineSingleLV2(const double sampleRate, | ||||
| const char* const bundlePath, | const char* const bundlePath, | ||||
| const LV2_Feature* const* const features) | const LV2_Feature* const* const features) | ||||
| : Lv2PluginBaseClass(sampleRate, features), | |||||
| : Lv2PluginBaseClass<EngineTimeInfo>(sampleRate, features), | |||||
| fPlugin(nullptr), | fPlugin(nullptr), | ||||
| fUiName() | fUiName() | ||||
| { | { | ||||
| @@ -93,6 +93,7 @@ public: | |||||
| CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | ||||
| CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),); | CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),); | ||||
| fPorts.hasUI = false; | |||||
| fPorts.usesTime = true; | fPorts.usesTime = true; | ||||
| fPorts.numAudioIns = fPlugin->getAudioInCount(); | fPorts.numAudioIns = fPlugin->getAudioInCount(); | ||||
| fPorts.numAudioOuts = fPlugin->getAudioOutCount(); | fPorts.numAudioOuts = fPlugin->getAudioOutCount(); | ||||
| @@ -479,10 +480,10 @@ private: | |||||
| CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(midiData != nullptr, false); | ||||
| CARLA_SAFE_ASSERT_RETURN(midiSize > 0, false); | CARLA_SAFE_ASSERT_RETURN(midiSize > 0, false); | ||||
| LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); | |||||
| LV2_Atom_Sequence* const seq(fPorts.eventsOut[port]); | |||||
| CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | ||||
| Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||||
| Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||||
| if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset) | if (sizeof(LV2_Atom_Event) + midiSize > mData.capacity - mData.offset) | ||||
| return false; | return false; | ||||
| @@ -68,14 +68,11 @@ LINK_FLAGS += $(X11_LIBS) | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------- | ||||
| NATIVE_BUILD_FLAGS = $(NATIVE_PLUGINS_FLAGS) $(LIBLO_FLAGS) | NATIVE_BUILD_FLAGS = $(NATIVE_PLUGINS_FLAGS) $(LIBLO_FLAGS) | ||||
| NATIVE_LINK_FLAGS = $(LIBLO_LIBS) | |||||
| # NATIVE_LINK_FLAGS = $(LIBLO_LIBS) | |||||
| NATIVE_BUILD_FLAGS += $(FLUIDSYNTH_FLAGS) | NATIVE_BUILD_FLAGS += $(FLUIDSYNTH_FLAGS) | ||||
| NATIVE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | NATIVE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | ||||
| NATIVE_BUILD_FLAGS += $(LINUXSAMPLER_FLAGS) | |||||
| NATIVE_LINK_FLAGS += $(LINUXSAMPLER_LIBS) | |||||
| NATIVE_LINK_FLAGS += $(FFMPEG_LIBS) | NATIVE_LINK_FLAGS += $(FFMPEG_LIBS) | ||||
| NATIVE_LINK_FLAGS += $(MAGIC_LIBS) | NATIVE_LINK_FLAGS += $(MAGIC_LIBS) | ||||
| NATIVE_LINK_FLAGS += $(SNDFILE_LIBS) | NATIVE_LINK_FLAGS += $(SNDFILE_LIBS) | ||||
| @@ -95,8 +92,9 @@ OBJS_native = \ | |||||
| $(OBJDIR)/CarlaEngine.cpp.o \ | $(OBJDIR)/CarlaEngine.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineClient.cpp.o \ | $(OBJDIR)/CarlaEngineClient.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineData.cpp.o \ | $(OBJDIR)/CarlaEngineData.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineGraph.cpp.o \ | |||||
| $(OBJDIR)/CarlaEngineInternal.cpp.o \ | $(OBJDIR)/CarlaEngineInternal.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineOsc.cpp.o \ | |||||
| $(OBJDIR)/CarlaEngineNative.cpp.o \ | |||||
| $(OBJDIR)/CarlaEngineOscSend.cpp.o \ | $(OBJDIR)/CarlaEngineOscSend.cpp.o \ | ||||
| $(OBJDIR)/CarlaEnginePorts.cpp.o \ | $(OBJDIR)/CarlaEnginePorts.cpp.o \ | ||||
| $(OBJDIR)/CarlaEngineThread.cpp.o \ | $(OBJDIR)/CarlaEngineThread.cpp.o \ | ||||
| @@ -351,8 +351,4 @@ CARLA_BRIDGE_UI_END_NAMESPACE | |||||
| #include "CarlaPipeUtils.cpp" | #include "CarlaPipeUtils.cpp" | ||||
| #if !(defined(DEBUG) || defined(BUILDING_CARLA_FOR_WINDOWS)) | |||||
| # include "water/misc/Time.cpp" | |||||
| #endif | |||||
| // --------------------------------------------------------------------- | // --------------------------------------------------------------------- | ||||
| @@ -226,5 +226,6 @@ CARLA_BRIDGE_UI_END_NAMESPACE | |||||
| #define CARLA_PLUGIN_UI_CLASS_PREFIX ToolkitNative | #define CARLA_PLUGIN_UI_CLASS_PREFIX ToolkitNative | ||||
| #include "CarlaPluginUI.cpp" | #include "CarlaPluginUI.cpp" | ||||
| #include "CarlaMacUtils.cpp" | |||||
| // ------------------------------------------------------------------------- | // ------------------------------------------------------------------------- | ||||
| @@ -0,0 +1,64 @@ | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | |||||
| # Carla plugin host | |||||
| # Copyright (C) 2011-2018 Filipe Coelho <falktx@falktx.com> | |||||
| # | |||||
| # This program is free software; you can redistribute it and/or | |||||
| # modify it under the terms of the GNU General Public License as | |||||
| # published by the Free Software Foundation; either version 2 of | |||||
| # the License, or any later version. | |||||
| # | |||||
| # This program is distributed in the hope that it will be useful, | |||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | |||||
| # | |||||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| # Imports (Custom Stuff) | |||||
| from carla_backend_qtweb import CarlaHostQtWeb | |||||
| from carla_host import ( | |||||
| CarlaApplication, | |||||
| HostWindow, | |||||
| setUpSignals, | |||||
| initHost, | |||||
| loadHostSettings, | |||||
| ) | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| # Main | |||||
| if __name__ == '__main__': | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # App initialization | |||||
| app = CarlaApplication("Carla2-REST") | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # Set-up custom signal handling | |||||
| setUpSignals() | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # Init host backend | |||||
| host = initHost("Carla-REST", None, False, False, False, CarlaHostQtWeb) | |||||
| loadHostSettings(host) | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # Create GUI | |||||
| gui = HostWindow(host, True) | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # Show GUI | |||||
| gui.show() | |||||
| # ------------------------------------------------------------------------------------------------------------------ | |||||
| # App-Loop | |||||
| app.exit_exec() | |||||
| @@ -17,7 +17,6 @@ DEFINES += REAL_BUILD | |||||
| DEFINES += HAVE_LIBLO | DEFINES += HAVE_LIBLO | ||||
| DEFINES += HAVE_LIBMAGIC | DEFINES += HAVE_LIBMAGIC | ||||
| DEFINES += HAVE_FLUIDSYNTH | DEFINES += HAVE_FLUIDSYNTH | ||||
| DEFINES += HAVE_LINUXSAMPLER | |||||
| DEFINES += HAVE_ZYN_DEPS | DEFINES += HAVE_ZYN_DEPS | ||||
| DEFINES += HAVE_ZYN_UI_DEPS | DEFINES += HAVE_ZYN_UI_DEPS | ||||
| @@ -1241,6 +1241,7 @@ class CarlaHostMeta(object): | |||||
| # info about this host object | # info about this host object | ||||
| self.isControl = False | self.isControl = False | ||||
| self.isPlugin = False | self.isPlugin = False | ||||
| self.isRemote = False | |||||
| self.nsmOK = False | self.nsmOK = False | ||||
| # settings | # settings | ||||
| @@ -1571,7 +1572,7 @@ class CarlaHostMeta(object): | |||||
| def get_midi_program_data(self, pluginId, midiProgramId): | def get_midi_program_data(self, pluginId, midiProgramId): | ||||
| raise NotImplementedError | raise NotImplementedError | ||||
| # Get a plugin's custom data. | |||||
| # Get a plugin's custom data, using index. | |||||
| # @param pluginId Plugin | # @param pluginId Plugin | ||||
| # @param customDataId Custom data index | # @param customDataId Custom data index | ||||
| # @see carla_get_custom_data_count() | # @see carla_get_custom_data_count() | ||||
| @@ -1579,6 +1580,15 @@ class CarlaHostMeta(object): | |||||
| def get_custom_data(self, pluginId, customDataId): | def get_custom_data(self, pluginId, customDataId): | ||||
| raise NotImplementedError | raise NotImplementedError | ||||
| # Get a plugin's custom data value, using type and key. | |||||
| # @param pluginId Plugin | |||||
| # @param type Custom data type | |||||
| # @param key Custom data key | |||||
| # @see carla_get_custom_data_count() | |||||
| @abstractmethod | |||||
| def get_custom_data_value(self, pluginId, type_, key): | |||||
| raise NotImplementedError | |||||
| # Get a plugin's chunk data. | # Get a plugin's chunk data. | ||||
| # @param pluginId Plugin | # @param pluginId Plugin | ||||
| # @see PLUGIN_OPTION_USE_CHUNKS | # @see PLUGIN_OPTION_USE_CHUNKS | ||||
| @@ -1881,6 +1891,7 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| CarlaHostMeta.__init__(self) | CarlaHostMeta.__init__(self) | ||||
| self.fEngineCallback = None | self.fEngineCallback = None | ||||
| self.fFileCallback = None | |||||
| self.fEngineRunning = False | self.fEngineRunning = False | ||||
| def get_engine_driver_count(self): | def get_engine_driver_count(self): | ||||
| @@ -1911,7 +1922,7 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| return | return | ||||
| def is_engine_running(self): | def is_engine_running(self): | ||||
| return False | |||||
| return self.fEngineRunning | |||||
| def set_engine_about_to_close(self): | def set_engine_about_to_close(self): | ||||
| return True | return True | ||||
| @@ -1923,7 +1934,7 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| return | return | ||||
| def set_file_callback(self, func): | def set_file_callback(self, func): | ||||
| return | |||||
| self.fFileCallback = func | |||||
| def load_file(self, filename): | def load_file(self, filename): | ||||
| return False | return False | ||||
| @@ -2027,6 +2038,9 @@ class CarlaHostNull(CarlaHostMeta): | |||||
| def get_custom_data(self, pluginId, customDataId): | def get_custom_data(self, pluginId, customDataId): | ||||
| return PyCustomData | return PyCustomData | ||||
| def get_custom_data_value(self, pluginId, type_, key): | |||||
| return "" | |||||
| def get_chunk_data(self, pluginId): | def get_chunk_data(self, pluginId): | ||||
| return "" | return "" | ||||
| @@ -2309,6 +2323,9 @@ class CarlaHostDLL(CarlaHostMeta): | |||||
| self.lib.carla_get_custom_data.argtypes = [c_uint, c_uint32] | self.lib.carla_get_custom_data.argtypes = [c_uint, c_uint32] | ||||
| self.lib.carla_get_custom_data.restype = POINTER(CustomData) | self.lib.carla_get_custom_data.restype = POINTER(CustomData) | ||||
| self.lib.carla_get_custom_data_value.argtypes = [c_uint, c_char_p, c_char_p] | |||||
| self.lib.carla_get_custom_data_value.restype = c_char_p | |||||
| self.lib.carla_get_chunk_data.argtypes = [c_uint] | self.lib.carla_get_chunk_data.argtypes = [c_uint] | ||||
| self.lib.carla_get_chunk_data.restype = c_char_p | self.lib.carla_get_chunk_data.restype = c_char_p | ||||
| @@ -2586,6 +2603,9 @@ class CarlaHostDLL(CarlaHostMeta): | |||||
| def get_custom_data(self, pluginId, customDataId): | def get_custom_data(self, pluginId, customDataId): | ||||
| return structToDict(self.lib.carla_get_custom_data(pluginId, customDataId).contents) | return structToDict(self.lib.carla_get_custom_data(pluginId, customDataId).contents) | ||||
| def get_custom_data_value(self, pluginId, type_, key): | |||||
| return charPtrToString(self.lib.carla_get_custom_data_value(pluginId, type_.encode("utf-8"), key.encode("utf-8"))) | |||||
| def get_chunk_data(self, pluginId): | def get_chunk_data(self, pluginId): | ||||
| return charPtrToString(self.lib.carla_get_chunk_data(pluginId)) | return charPtrToString(self.lib.carla_get_chunk_data(pluginId)) | ||||
| @@ -2884,7 +2904,10 @@ class CarlaHostPlugin(CarlaHostMeta): | |||||
| return self.sendMsgAndSetError(["replace_plugin", pluginId]) | return self.sendMsgAndSetError(["replace_plugin", pluginId]) | ||||
| def switch_plugins(self, pluginIdA, pluginIdB): | def switch_plugins(self, pluginIdA, pluginIdB): | ||||
| return self.sendMsgAndSetError(["switch_plugins", pluginIdA, pluginIdB]) | |||||
| ret = self.sendMsgAndSetError(["switch_plugins", pluginIdA, pluginIdB]) | |||||
| if ret: | |||||
| self._switchPlugins(pluginIdA, pluginIdB) | |||||
| return ret | |||||
| def load_plugin_state(self, pluginId, filename): | def load_plugin_state(self, pluginId, filename): | ||||
| return self.sendMsgAndSetError(["load_plugin_state", pluginId, filename]) | return self.sendMsgAndSetError(["load_plugin_state", pluginId, filename]) | ||||
| @@ -2926,6 +2949,12 @@ class CarlaHostPlugin(CarlaHostMeta): | |||||
| def get_custom_data(self, pluginId, customDataId): | def get_custom_data(self, pluginId, customDataId): | ||||
| return self.fPluginsInfo[pluginId].customData[customDataId] | return self.fPluginsInfo[pluginId].customData[customDataId] | ||||
| def get_custom_data_value(self, pluginId, type_, key): | |||||
| for customData in self.fPluginsInfo[pluginId].customData: | |||||
| if customData['type'] == type_ and customData['key'] == key: | |||||
| return customData['value'] | |||||
| return "" | |||||
| def get_chunk_data(self, pluginId): | def get_chunk_data(self, pluginId): | ||||
| return "" | return "" | ||||
| @@ -3242,4 +3271,9 @@ class CarlaHostPlugin(CarlaHostMeta): | |||||
| def _set_peaks(self, pluginId, in1, in2, out1, out2): | def _set_peaks(self, pluginId, in1, in2, out1, out2): | ||||
| self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2] | self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2] | ||||
| def _switchPlugins(self, pluginIdA, pluginIdB): | |||||
| tmp = self.fPluginsInfo[pluginIdA] | |||||
| self.fPluginsInfo[pluginIdA] = self.fPluginsInfo[pluginIdB] | |||||
| self.fPluginsInfo[pluginIdB] = tmp | |||||
| # ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
| @@ -0,0 +1,568 @@ | |||||
| #!/usr/bin/env python3 | |||||
| # -*- coding: utf-8 -*- | |||||
| # Carla Backend code (Web stuff) | |||||
| # Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| # | |||||
| # This program is free software; you can redistribute it and/or | |||||
| # modify it under the terms of the GNU General Public License as | |||||
| # published by the Free Software Foundation; either version 2 of | |||||
| # the License, or any later version. | |||||
| # | |||||
| # This program is distributed in the hope that it will be useful, | |||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| # GNU General Public License for more details. | |||||
| # | |||||
| # For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Imports (Global) | |||||
| import requests | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Imports (Custom) | |||||
| from carla_backend_qt import * | |||||
| import os | |||||
| from time import sleep | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Iterates over the content of a file-like object line-by-line. | |||||
| # Based on code by Lars Kellogg-Stedman, see https://github.com/requests/requests/issues/2433 | |||||
| def iterate_stream_nonblock(stream, chunk_size=1024): | |||||
| pending = None | |||||
| while True: | |||||
| try: | |||||
| chunk = os.read(stream.raw.fileno(), chunk_size) | |||||
| except BlockingIOError: | |||||
| break | |||||
| if not chunk: | |||||
| break | |||||
| if pending is not None: | |||||
| chunk = pending + chunk | |||||
| pending = None | |||||
| lines = chunk.splitlines() | |||||
| if lines and lines[-1]: | |||||
| pending = lines.pop() | |||||
| for line in lines: | |||||
| yield line | |||||
| if not pending: | |||||
| break | |||||
| if pending: | |||||
| yield pending | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| def create_stream(baseurl): | |||||
| stream = requests.get("{}/stream".format(baseurl), stream=True, timeout=0.1) | |||||
| if stream.encoding is None: | |||||
| stream.encoding = 'utf-8' | |||||
| return stream | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Carla Host object for connecting to the REST API backend | |||||
| class CarlaHostQtWeb(CarlaHostQtNull): | |||||
| def __init__(self): | |||||
| CarlaHostQtNull.__init__(self) | |||||
| self.baseurl = "http://localhost:2228" | |||||
| self.stream = create_stream(self.baseurl) | |||||
| self.isRemote = True | |||||
| def get_engine_driver_count(self): | |||||
| # FIXME | |||||
| return int(requests.get("{}/get_engine_driver_count".format(self.baseurl)).text) - 1 | |||||
| def get_engine_driver_name(self, index): | |||||
| return requests.get("{}/get_engine_driver_name".format(self.baseurl), params={ | |||||
| 'index': index, | |||||
| }).text | |||||
| def get_engine_driver_device_names(self, index): | |||||
| return requests.get("{}/get_engine_driver_device_names".format(self.baseurl), params={ | |||||
| 'index': index, | |||||
| }).text.split("\n") | |||||
| def get_engine_driver_device_info(self, index, name): | |||||
| return requests.get("{}/get_engine_driver_device_info".format(self.baseurl), params={ | |||||
| 'index': index, | |||||
| 'name': name, | |||||
| }).json() | |||||
| def engine_init(self, driverName, clientName): | |||||
| return bool(int(requests.get("{}/engine_init".format(self.baseurl), params={ | |||||
| 'driverName': driverName, | |||||
| 'clientName': clientName, | |||||
| }).text)) | |||||
| def engine_close(self): | |||||
| return bool(int(requests.get("{}/engine_close".format(self.baseurl)).text)) | |||||
| def engine_idle(self): | |||||
| closed = False | |||||
| stream = self.stream | |||||
| for line in iterate_stream_nonblock(stream): | |||||
| line = line.decode('utf-8', errors='ignore') | |||||
| if line.startswith("Carla: "): | |||||
| if self.fEngineCallback is None: | |||||
| continue | |||||
| # split values from line | |||||
| action, pluginId, value1, value2, value3, valueStr = line[7:].split(" ",5) | |||||
| # convert to proper types | |||||
| action = int(action) | |||||
| pluginId = int(pluginId) | |||||
| value1 = int(value1) | |||||
| value2 = int(value2) | |||||
| value3 = float(value3) | |||||
| # pass to callback | |||||
| self.fEngineCallback(None, action, pluginId, value1, value2, value3, valueStr) | |||||
| elif line == "Connection: close": | |||||
| if not closed: | |||||
| self.stream = create_stream(self.baseurl) | |||||
| closed = True | |||||
| if closed: | |||||
| stream.close() | |||||
| def is_engine_running(self): | |||||
| try: | |||||
| return bool(int(requests.get("{}/is_engine_running".format(self.baseurl)).text)) | |||||
| except requests.exceptions.ConnectionError: | |||||
| if self.fEngineCallback is None: | |||||
| self.fEngineCallback(None, ENGINE_CALLBACK_QUIT, 0, 0, 0, 0.0, "") | |||||
| def set_engine_about_to_close(self): | |||||
| return bool(int(requests.get("{}/set_engine_about_to_close".format(self.baseurl)).text)) | |||||
| def set_engine_option(self, option, value, valueStr): | |||||
| requests.get("{}/set_engine_option".format(self.baseurl), params={ | |||||
| 'option': option, | |||||
| 'value': value, | |||||
| 'valueStr': valueStr, | |||||
| }) | |||||
| def load_file(self, filename): | |||||
| return bool(int(requests.get("{}/load_file".format(self.baseurl), params={ | |||||
| 'filename': filename, | |||||
| }).text)) | |||||
| def load_project(self, filename): | |||||
| return bool(int(requests.get("{}/load_project".format(self.baseurl), params={ | |||||
| 'filename': filename, | |||||
| }).text)) | |||||
| def save_project(self, filename): | |||||
| return bool(int(requests.get("{}/save_project".format(self.baseurl), params={ | |||||
| 'filename': filename, | |||||
| }).text)) | |||||
| def patchbay_connect(self, groupIdA, portIdA, groupIdB, portIdB): | |||||
| return bool(int(requests.get("{}/patchbay_connect".format(self.baseurl), params={ | |||||
| 'groupIdA': groupIdA, | |||||
| 'portIdA': portIdA, | |||||
| 'groupIdB': groupIdB, | |||||
| 'portIdB': portIdB, | |||||
| }).text)) | |||||
| def patchbay_disconnect(self, connectionId): | |||||
| return bool(int(requests.get("{}/patchbay_disconnect".format(self.baseurl), params={ | |||||
| 'connectionId': connectionId, | |||||
| }).text)) | |||||
| def patchbay_refresh(self, external): | |||||
| return bool(int(requests.get("{}/patchbay_refresh".format(self.baseurl), params={ | |||||
| 'external': external, | |||||
| }).text)) | |||||
| def transport_play(self): | |||||
| requests.get("{}/transport_play".format(self.baseurl)) | |||||
| def transport_pause(self): | |||||
| requests.get("{}/transport_pause".format(self.baseurl)) | |||||
| def transport_bpm(self, bpm): | |||||
| requests.get("{}/transport_bpm".format(self.baseurl), params={ | |||||
| 'bpm': bpm, | |||||
| }) | |||||
| def transport_relocate(self, frame): | |||||
| requests.get("{}/transport_relocate".format(self.baseurl), params={ | |||||
| 'frame': frame, | |||||
| }) | |||||
| def get_current_transport_frame(self): | |||||
| return int(requests.get("{}/get_current_transport_frame".format(self.baseurl)).text) | |||||
| def get_transport_info(self): | |||||
| return requests.get("{}/get_transport_info".format(self.baseurl)).json() | |||||
| def get_current_plugin_count(self): | |||||
| return int(requests.get("{}/get_current_plugin_count".format(self.baseurl)).text) | |||||
| def get_max_plugin_number(self): | |||||
| return int(requests.get("{}/get_max_plugin_number".format(self.baseurl)).text) | |||||
| def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr, options): | |||||
| return bool(int(requests.get("{}/add_plugin".format(self.baseurl), params={ | |||||
| 'btype': btype, | |||||
| 'ptype': ptype, | |||||
| 'filename': filename, | |||||
| 'name': name, | |||||
| 'label': label, | |||||
| 'uniqueId': uniqueId, | |||||
| 'options': options, | |||||
| }).text)) | |||||
| def remove_plugin(self, pluginId): | |||||
| return bool(int(requests.get("{}/remove_plugin".format(self.baseurl), params={ | |||||
| 'filename': pluginId, | |||||
| }).text)) | |||||
| def remove_all_plugins(self): | |||||
| return bool(int(requests.get("{}/remove_all_plugins".format(self.baseurl)).text)) | |||||
| def rename_plugin(self, pluginId, newName): | |||||
| return requests.get("{}/rename_plugin".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'newName': newName, | |||||
| }).text | |||||
| def clone_plugin(self, pluginId): | |||||
| return bool(int(requests.get("{}/clone_plugin".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text)) | |||||
| def replace_plugin(self, pluginId): | |||||
| return bool(int(requests.get("{}/replace_plugin".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text)) | |||||
| def switch_plugins(self, pluginIdA, pluginIdB): | |||||
| return bool(int(requests.get("{}/switch_plugins".format(self.baseurl), params={ | |||||
| 'pluginIdA': pluginIdA, | |||||
| 'pluginIdB': pluginIdB, | |||||
| }).text)) | |||||
| def load_plugin_state(self, pluginId, filename): | |||||
| return bool(int(requests.get("{}/load_plugin_state".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'filename': filename, | |||||
| }).text)) | |||||
| def save_plugin_state(self, pluginId, filename): | |||||
| return bool(int(requests.get("{}/save_plugin_state".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'filename': filename, | |||||
| }).text)) | |||||
| def export_plugin_lv2(self, pluginId, lv2path): | |||||
| return bool(int(requests.get("{}/export_plugin_lv2".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'lv2path': lv2path, | |||||
| }).text)) | |||||
| def get_plugin_info(self, pluginId): | |||||
| return requests.get("{}/get_plugin_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).json() | |||||
| def get_audio_port_count_info(self, pluginId): | |||||
| return requests.get("{}/get_audio_port_count_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).json() | |||||
| def get_midi_port_count_info(self, pluginId): | |||||
| return requests.get("{}/get_midi_port_count_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).json() | |||||
| def get_parameter_count_info(self, pluginId): | |||||
| return requests.get("{}/get_parameter_count_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).json() | |||||
| def get_parameter_info(self, pluginId, parameterId): | |||||
| return requests.get("{}/get_parameter_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).json() | |||||
| def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId): | |||||
| return requests.get("{}/get_parameter_scalepoint_info".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| 'scalePointId': scalePointId, | |||||
| }).json() | |||||
| def get_parameter_data(self, pluginId, parameterId): | |||||
| return requests.get("{}/get_parameter_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).json() | |||||
| def get_parameter_ranges(self, pluginId, parameterId): | |||||
| return requests.get("{}/get_parameter_ranges".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).json() | |||||
| def get_midi_program_data(self, pluginId, midiProgramId): | |||||
| return requests.get("{}/get_midi_program_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'midiProgramId': midiProgramId, | |||||
| }).json() | |||||
| def get_custom_data(self, pluginId, customDataId): | |||||
| return requests.get("{}/get_custom_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'customDataId': customDataId, | |||||
| }).json() | |||||
| def get_custom_data_value(self, pluginId, type_, key): | |||||
| return requests.get("{}/get_custom_data_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'type_': type_, | |||||
| 'key': key, | |||||
| }).text | |||||
| def get_chunk_data(self, pluginId): | |||||
| return requests.get("{}/get_chunk_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text | |||||
| def get_parameter_count(self, pluginId): | |||||
| return int(requests.get("{}/get_parameter_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_program_count(self, pluginId): | |||||
| return int(requests.get("{}/get_program_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_midi_program_count(self, pluginId): | |||||
| return int(requests.get("{}/get_midi_program_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_custom_data_count(self, pluginId): | |||||
| return int(requests.get("{}/get_custom_data_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_parameter_text(self, pluginId, parameterId): | |||||
| return requests.get("{}/get_parameter_text".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).text | |||||
| def get_program_name(self, pluginId, programId): | |||||
| return requests.get("{}/get_program_name".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'programId': programId, | |||||
| }).text | |||||
| def get_midi_program_name(self, pluginId, midiProgramId): | |||||
| return requests.get("{}/get_midi_program_name".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'midiProgramId': midiProgramId, | |||||
| }).text | |||||
| def get_real_plugin_name(self, pluginId): | |||||
| return requests.get("{}/get_real_plugin_name".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text | |||||
| def get_current_program_index(self, pluginId): | |||||
| return int(requests.get("{}/get_custom_data_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_current_midi_program_index(self, pluginId): | |||||
| return int(requests.get("{}/get_custom_data_count".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }).text) | |||||
| def get_default_parameter_value(self, pluginId, parameterId): | |||||
| return float(requests.get("{}/get_default_parameter_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).text) | |||||
| def get_current_parameter_value(self, pluginId, parameterId): | |||||
| return float(requests.get("{}/get_current_parameter_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).text) | |||||
| def get_internal_parameter_value(self, pluginId, parameterId): | |||||
| return float(requests.get("{}/get_internal_parameter_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| }).text) | |||||
| def get_input_peak_value(self, pluginId, isLeft): | |||||
| return float(requests.get("{}/get_input_peak_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'isLeft': isLeft, | |||||
| }).text) | |||||
| def get_output_peak_value(self, pluginId, isLeft): | |||||
| return float(requests.get("{}/get_output_peak_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'isLeft': isLeft, | |||||
| }).text) | |||||
| def set_option(self, pluginId, option, yesNo): | |||||
| requests.get("{}/set_option".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'option': option, | |||||
| 'yesNo': yesNo, | |||||
| }) | |||||
| def set_active(self, pluginId, onOff): | |||||
| requests.get("{}/set_active".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'onOff': onOff, | |||||
| }) | |||||
| def set_drywet(self, pluginId, value): | |||||
| requests.get("{}/set_drywet".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_volume(self, pluginId, value): | |||||
| requests.get("{}/set_volume".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_balance_left(self, pluginId, value): | |||||
| requests.get("{}/set_balance_left".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_balance_right(self, pluginId, value): | |||||
| requests.get("{}/set_balance_right".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_panning(self, pluginId, value): | |||||
| requests.get("{}/set_panning".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_ctrl_channel(self, pluginId, channel): | |||||
| requests.get("{}/set_ctrl_channel".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'channel': channel, | |||||
| }) | |||||
| def set_parameter_value(self, pluginId, parameterId, value): | |||||
| requests.get("{}/set_parameter_value".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_parameter_midi_channel(self, pluginId, parameterId, channel): | |||||
| requests.get("{}/set_parameter_midi_channel".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| 'channel': channel, | |||||
| }) | |||||
| def set_parameter_midi_cc(self, pluginId, parameterId, cc): | |||||
| requests.get("{}/set_parameter_midi_cc".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'parameterId': parameterId, | |||||
| 'cc': cc, | |||||
| }) | |||||
| def set_program(self, pluginId, programId): | |||||
| requests.get("{}/set_program".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }) | |||||
| def set_midi_program(self, pluginId, midiProgramId): | |||||
| requests.get("{}/set_midi_program".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'midiProgramId': midiProgramId, | |||||
| }) | |||||
| def set_custom_data(self, pluginId, type_, key, value): | |||||
| requests.get("{}/set_custom_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'type': type_, | |||||
| 'key': key, | |||||
| 'value': value, | |||||
| }) | |||||
| def set_chunk_data(self, pluginId, chunkData): | |||||
| requests.get("{}/set_chunk_data".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'chunkData': chunkData, | |||||
| }) | |||||
| def prepare_for_save(self, pluginId): | |||||
| requests.get("{}/prepare_for_save".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }) | |||||
| def reset_parameters(self, pluginId): | |||||
| requests.get("{}/reset_parameters".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }) | |||||
| def randomize_parameters(self, pluginId): | |||||
| requests.get("{}/randomize_parameters".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| }) | |||||
| def send_midi_note(self, pluginId, channel, note, velocity): | |||||
| requests.get("{}/send_midi_note".format(self.baseurl), params={ | |||||
| 'pluginId': pluginId, | |||||
| 'channel': channel, | |||||
| 'note': note, | |||||
| 'velocity': velocity, | |||||
| }) | |||||
| def get_buffer_size(self): | |||||
| return int(requests.get("{}/get_buffer_size".format(self.baseurl)).text) | |||||
| def get_sample_rate(self): | |||||
| return float(requests.get("{}/get_sample_rate".format(self.baseurl)).text) | |||||
| def get_last_error(self): | |||||
| return requests.get("{}/get_last_error".format(self.baseurl)).text | |||||
| def get_host_osc_url_tcp(self): | |||||
| return requests.get("{}/get_host_osc_url_tcp".format(self.baseurl)).text | |||||
| def get_host_osc_url_udp(self): | |||||
| return requests.get("{}/get_host_osc_url_udp".format(self.baseurl)).text | |||||
| @@ -28,11 +28,11 @@ from copy import deepcopy | |||||
| from subprocess import Popen, PIPE | from subprocess import Popen, PIPE | ||||
| if config_UseQt5: | if config_UseQt5: | ||||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QThread, QSettings | |||||
| from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QTableWidgetItem | |||||
| from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QEventLoop, QThread, QSettings | |||||
| from PyQt5.QtWidgets import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem | |||||
| else: | else: | ||||
| from PyQt4.QtCore import pyqtSignal, pyqtSlot, Qt, QThread, QSettings | |||||
| from PyQt4.QtGui import QDialog, QDialogButtonBox, QTableWidgetItem | |||||
| from PyQt4.QtCore import pyqtSignal, pyqtSlot, Qt, QEventLoop, QThread, QSettings | |||||
| from PyQt4.QtGui import QApplication, QDialog, QDialogButtonBox, QTableWidgetItem | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------- | ||||
| # Imports (Custom) | # Imports (Custom) | ||||
| @@ -117,8 +117,6 @@ def findFilenames(filePath, stype): | |||||
| if stype == "sf2": | if stype == "sf2": | ||||
| extensions = (".sf2",".sf3",) | extensions = (".sf2",".sf3",) | ||||
| elif stype == "sfz": | |||||
| extensions = (".sfz",) | |||||
| else: | else: | ||||
| return [] | return [] | ||||
| @@ -131,10 +129,11 @@ def findFilenames(filePath, stype): | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------- | ||||
| # Plugin Query | # Plugin Query | ||||
| PLUGIN_QUERY_API_VERSION = 7 | |||||
| PLUGIN_QUERY_API_VERSION = 8 | |||||
| PyPluginInfo = { | PyPluginInfo = { | ||||
| 'API': PLUGIN_QUERY_API_VERSION, | 'API': PLUGIN_QUERY_API_VERSION, | ||||
| 'valid': False, | |||||
| 'build': BINARY_NONE, | 'build': BINARY_NONE, | ||||
| 'type': PLUGIN_NONE, | 'type': PLUGIN_NONE, | ||||
| 'hints': 0x0, | 'hints': 0x0, | ||||
| @@ -316,8 +315,6 @@ def killDiscovery(): | |||||
| gDiscoveryProcess.kill() | gDiscoveryProcess.kill() | ||||
| def checkPluginCached(desc, ptype): | def checkPluginCached(desc, ptype): | ||||
| plugins = [] | |||||
| pinfo = deepcopy(PyPluginInfo) | pinfo = deepcopy(PyPluginInfo) | ||||
| pinfo['build'] = BINARY_NATIVE | pinfo['build'] = BINARY_NATIVE | ||||
| pinfo['type'] = ptype | pinfo['type'] = ptype | ||||
| @@ -335,9 +332,7 @@ def checkPluginCached(desc, ptype): | |||||
| pinfo['parameters.ins'] = desc['parameterIns'] | pinfo['parameters.ins'] = desc['parameterIns'] | ||||
| pinfo['parameters.outs'] = desc['parameterOuts'] | pinfo['parameters.outs'] = desc['parameterOuts'] | ||||
| plugins.append(pinfo) | |||||
| return plugins | |||||
| return pinfo | |||||
| def checkPluginLADSPA(filename, tool, wineSettings=None): | def checkPluginLADSPA(filename, tool, wineSettings=None): | ||||
| return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, wineSettings) | return runCarlaDiscovery(PLUGIN_LADSPA, "LADSPA", filename, tool, wineSettings) | ||||
| @@ -407,13 +402,6 @@ class SearchPluginsThread(QThread): | |||||
| self.fLastCheckValue = 0 | self.fLastCheckValue = 0 | ||||
| self.fSomethingChanged = False | self.fSomethingChanged = False | ||||
| self.fLadspaPlugins = [] | |||||
| self.fDssiPlugins = [] | |||||
| self.fLv2Plugins = [] | |||||
| self.fVst2Plugins = [] | |||||
| self.fAuPlugins = [] | |||||
| self.fKitPlugins = [] | |||||
| # ------------------------------------------------------------- | # ------------------------------------------------------------- | ||||
| def hasSomethingChanged(self): | def hasSomethingChanged(self): | ||||
| @@ -438,7 +426,7 @@ class SearchPluginsThread(QThread): | |||||
| self.fContinueChecking = False | self.fContinueChecking = False | ||||
| def run(self): | def run(self): | ||||
| settingsDB = QSettings("falkTX", "CarlaPlugins3") | |||||
| settingsDB = QSettings("falkTX", "CarlaPlugins4") | |||||
| self.fContinueChecking = True | self.fContinueChecking = True | ||||
| self.fCurCount = 0 | self.fCurCount = 0 | ||||
| @@ -466,20 +454,24 @@ class SearchPluginsThread(QThread): | |||||
| if self.fCheckWin64: | if self.fCheckWin64: | ||||
| self.fCurCount += pluginCount | self.fCurCount += pluginCount | ||||
| # Special case for LV2, only "search" for native plugins | |||||
| # Special case for cached plugins, only "search" for native plugins (does not need tool) | |||||
| if self.fCheckLV2: | if self.fCheckLV2: | ||||
| if self.fCheckNative: | if self.fCheckNative: | ||||
| self.fCurCount += 1 | self.fCurCount += 1 | ||||
| else: | else: | ||||
| self.fCheckLV2 = False | self.fCheckLV2 = False | ||||
| if self.fCheckSFZ: | |||||
| if self.fCheckNative: | |||||
| self.fCurCount += 1 | |||||
| else: | |||||
| self.fCheckSFZ = False | |||||
| # Special case for Sound Kits, only search native | # Special case for Sound Kits, only search native | ||||
| if self.fCheckNative and self.fToolNative: | if self.fCheckNative and self.fToolNative: | ||||
| if self.fCheckSF2: self.fCurCount += 1 | if self.fCheckSF2: self.fCurCount += 1 | ||||
| if self.fCheckSFZ: self.fCurCount += 1 | |||||
| else: | else: | ||||
| self.fCheckSF2 = False | self.fCheckSF2 = False | ||||
| self.fCheckSFZ = False | |||||
| if self.fCurCount == 0: | if self.fCurCount == 0: | ||||
| return | return | ||||
| @@ -515,28 +507,28 @@ class SearchPluginsThread(QThread): | |||||
| rdfPadValue = self.fCurPercentValue * checkValue | rdfPadValue = self.fCurPercentValue * checkValue | ||||
| if self.fCheckNative: | if self.fCheckNative: | ||||
| self._checkLADSPA(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/LADSPA_native", self.fLadspaPlugins) | |||||
| plugins = self._checkLADSPA(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/LADSPA_native", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix32: | if self.fCheckPosix32: | ||||
| self._checkLADSPA(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/LADSPA_posix32", self.fLadspaPlugins) | |||||
| plugins = self._checkLADSPA(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/LADSPA_posix32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix64: | if self.fCheckPosix64: | ||||
| self._checkLADSPA(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/LADSPA_posix64", self.fLadspaPlugins) | |||||
| plugins = self._checkLADSPA(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/LADSPA_posix64", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin32: | if self.fCheckWin32: | ||||
| self._checkLADSPA("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/LADSPA_win32", self.fLadspaPlugins) | |||||
| plugins = self._checkLADSPA("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/LADSPA_win32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin64: | if self.fCheckWin64: | ||||
| self._checkLADSPA("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/LADSPA_win64", self.fLadspaPlugins) | |||||
| plugins = self._checkLADSPA("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/LADSPA_win64", plugins) | |||||
| settingsDB.sync() | settingsDB.sync() | ||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| @@ -560,62 +552,63 @@ class SearchPluginsThread(QThread): | |||||
| if self.fCheckDSSI: | if self.fCheckDSSI: | ||||
| if self.fCheckNative: | if self.fCheckNative: | ||||
| self._checkDSSI(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/DSSI_native", self.fDssiPlugins) | |||||
| plugins = self._checkDSSI(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/DSSI_native", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix32: | if self.fCheckPosix32: | ||||
| self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/DSSI_posix32", self.fDssiPlugins) | |||||
| plugins = self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/DSSI_posix32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix64: | if self.fCheckPosix64: | ||||
| self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/DSSI_posix64", self.fDssiPlugins) | |||||
| plugins = self._checkDSSI(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/DSSI_posix64", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin32: | if self.fCheckWin32: | ||||
| self._checkDSSI("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/DSSI_win32", self.fDssiPlugins) | |||||
| plugins = self._checkDSSI("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/DSSI_win32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin64: | if self.fCheckWin64: | ||||
| self._checkDSSI("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/DSSI_win64", self.fDssiPlugins) | |||||
| plugins = self._checkDSSI("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/DSSI_win64", plugins) | |||||
| settingsDB.sync() | settingsDB.sync() | ||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckLV2: | if self.fCheckLV2: | ||||
| self._checkLv2Cached() | |||||
| settingsDB.setValue("Plugins/LV2", self.fLv2Plugins) | |||||
| plugins = self._checkLv2Cached() | |||||
| settingsDB.setValue("Plugins/LV2", plugins) | |||||
| settingsDB.sync() | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckVST2: | if self.fCheckVST2: | ||||
| if self.fCheckNative: | if self.fCheckNative: | ||||
| self._checkVST2(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/VST2_native", self.fVstPlugins) | |||||
| plugins = self._checkVST2(OS, self.fToolNative) | |||||
| settingsDB.setValue("Plugins/VST2_native", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix32: | if self.fCheckPosix32: | ||||
| self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/VST2_posix32", self.fVstPlugins) | |||||
| plugins = self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix32")) | |||||
| settingsDB.setValue("Plugins/VST2_posix32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckPosix64: | if self.fCheckPosix64: | ||||
| self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/VST2_posix64", self.fVstPlugins) | |||||
| plugins = self._checkVST2(OS, os.path.join(self.fPathBinaries, "carla-discovery-posix64")) | |||||
| settingsDB.setValue("Plugins/VST2_posix64", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin32: | if self.fCheckWin32: | ||||
| self._checkVST2("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/VST2_win32", self.fVstPlugins) | |||||
| plugins = self._checkVST2("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win32.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/VST2_win32", plugins) | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckWin64: | if self.fCheckWin64: | ||||
| self._checkVST2("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/VST2_win64", self.fVstPlugins) | |||||
| plugins = self._checkVST2("WINDOWS", os.path.join(self.fPathBinaries, "carla-discovery-win64.exe"), not WINDOWS) | |||||
| settingsDB.setValue("Plugins/VST2_win64", plugins) | |||||
| if not self.fContinueChecking: return | |||||
| settingsDB.sync() | settingsDB.sync() | ||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| @@ -625,23 +618,19 @@ class SearchPluginsThread(QThread): | |||||
| SF2_PATH = toList(settings.value(CARLA_KEY_PATHS_SF2, CARLA_DEFAULT_SF2_PATH)) | SF2_PATH = toList(settings.value(CARLA_KEY_PATHS_SF2, CARLA_DEFAULT_SF2_PATH)) | ||||
| del settings | del settings | ||||
| self._checkKIT(SF2_PATH, "sf2") | |||||
| settingsDB.setValue("Plugins/SF2", self.fKitPlugins) | |||||
| kits = self._checkKIT(SF2_PATH, "sf2") | |||||
| settingsDB.setValue("Plugins/SF2", kits) | |||||
| settingsDB.sync() | |||||
| if not self.fContinueChecking: return | if not self.fContinueChecking: return | ||||
| if self.fCheckSFZ: | if self.fCheckSFZ: | ||||
| settings = QSettings("falkTX", "Carla2") | |||||
| SFZ_PATH = toList(settings.value(CARLA_KEY_PATHS_SFZ, CARLA_DEFAULT_SFZ_PATH)) | |||||
| del settings | |||||
| self._checkKIT(SFZ_PATH, "sfz") | |||||
| settingsDB.setValue("Plugins/SFZ", self.fKitPlugins) | |||||
| settingsDB.sync() | |||||
| kits = self._checkSfzCached() | |||||
| settingsDB.setValue("Plugins/SFZ", kits) | |||||
| settingsDB.sync() | |||||
| def _checkLADSPA(self, OS, tool, isWine=False): | def _checkLADSPA(self, OS, tool, isWine=False): | ||||
| ladspaBinaries = [] | ladspaBinaries = [] | ||||
| self.fLadspaPlugins = [] | |||||
| ladspaPlugins = [] | |||||
| self._pluginLook(self.fLastCheckValue, "LADSPA plugins...") | self._pluginLook(self.fLastCheckValue, "LADSPA plugins...") | ||||
| @@ -657,7 +646,8 @@ class SearchPluginsThread(QThread): | |||||
| ladspaBinaries.sort() | ladspaBinaries.sort() | ||||
| if not self.fContinueChecking: return | |||||
| if not self.fContinueChecking: | |||||
| return ladspaPlugins | |||||
| for i in range(len(ladspaBinaries)): | for i in range(len(ladspaBinaries)): | ||||
| ladspa = ladspaBinaries[i] | ladspa = ladspaBinaries[i] | ||||
| @@ -666,15 +656,17 @@ class SearchPluginsThread(QThread): | |||||
| plugins = checkPluginLADSPA(ladspa, tool, self.fWineSettings if isWine else None) | plugins = checkPluginLADSPA(ladspa, tool, self.fWineSettings if isWine else None) | ||||
| if plugins: | if plugins: | ||||
| self.fLadspaPlugins.append(plugins) | |||||
| ladspaPlugins.append(plugins) | |||||
| if not self.fContinueChecking: break | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | self.fLastCheckValue += self.fCurPercentValue | ||||
| return ladspaPlugins | |||||
| def _checkDSSI(self, OS, tool, isWine=False): | def _checkDSSI(self, OS, tool, isWine=False): | ||||
| dssiBinaries = [] | dssiBinaries = [] | ||||
| self.fDssiPlugins = [] | |||||
| dssiPlugins = [] | |||||
| self._pluginLook(self.fLastCheckValue, "DSSI plugins...") | self._pluginLook(self.fLastCheckValue, "DSSI plugins...") | ||||
| @@ -690,7 +682,8 @@ class SearchPluginsThread(QThread): | |||||
| dssiBinaries.sort() | dssiBinaries.sort() | ||||
| if not self.fContinueChecking: return | |||||
| if not self.fContinueChecking: | |||||
| return dssiPlugins | |||||
| for i in range(len(dssiBinaries)): | for i in range(len(dssiBinaries)): | ||||
| dssi = dssiBinaries[i] | dssi = dssiBinaries[i] | ||||
| @@ -699,15 +692,17 @@ class SearchPluginsThread(QThread): | |||||
| plugins = checkPluginDSSI(dssi, tool, self.fWineSettings if isWine else None) | plugins = checkPluginDSSI(dssi, tool, self.fWineSettings if isWine else None) | ||||
| if plugins: | if plugins: | ||||
| self.fDssiPlugins.append(plugins) | |||||
| dssiPlugins.append(plugins) | |||||
| if not self.fContinueChecking: break | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | self.fLastCheckValue += self.fCurPercentValue | ||||
| return dssiPlugins | |||||
| def _checkVST2(self, OS, tool, isWine=False): | def _checkVST2(self, OS, tool, isWine=False): | ||||
| vst2Binaries = [] | vst2Binaries = [] | ||||
| self.fVstPlugins = [] | |||||
| vstPlugins = [] | |||||
| if MACOS and not isWine: | if MACOS and not isWine: | ||||
| self._pluginLook(self.fLastCheckValue, "VST2 bundles...") | self._pluginLook(self.fLastCheckValue, "VST2 bundles...") | ||||
| @@ -729,7 +724,8 @@ class SearchPluginsThread(QThread): | |||||
| vst2Binaries.sort() | vst2Binaries.sort() | ||||
| if not self.fContinueChecking: return | |||||
| if not self.fContinueChecking: | |||||
| return vstPlugins | |||||
| for i in range(len(vst2Binaries)): | for i in range(len(vst2Binaries)): | ||||
| vst2 = vst2Binaries[i] | vst2 = vst2Binaries[i] | ||||
| @@ -738,15 +734,17 @@ class SearchPluginsThread(QThread): | |||||
| plugins = checkPluginVST2(vst2, tool, self.fWineSettings if isWine else None) | plugins = checkPluginVST2(vst2, tool, self.fWineSettings if isWine else None) | ||||
| if plugins: | if plugins: | ||||
| self.fVstPlugins.append(plugins) | |||||
| vstPlugins.append(plugins) | |||||
| if not self.fContinueChecking: break | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | self.fLastCheckValue += self.fCurPercentValue | ||||
| return vstPlugins | |||||
| def _checkKIT(self, kitPATH, kitExtension): | def _checkKIT(self, kitPATH, kitExtension): | ||||
| kitFiles = [] | kitFiles = [] | ||||
| self.fKitPlugins = [] | |||||
| kitPlugins = [] | |||||
| for iPATH in kitPATH: | for iPATH in kitPATH: | ||||
| files = findFilenames(iPATH, kitExtension) | files = findFilenames(iPATH, kitExtension) | ||||
| @@ -756,7 +754,8 @@ class SearchPluginsThread(QThread): | |||||
| kitFiles.sort() | kitFiles.sort() | ||||
| if not self.fContinueChecking: return | |||||
| if not self.fContinueChecking: | |||||
| return kitPlugins | |||||
| for i in range(len(kitFiles)): | for i in range(len(kitFiles)): | ||||
| kit = kitFiles[i] | kit = kitFiles[i] | ||||
| @@ -765,31 +764,30 @@ class SearchPluginsThread(QThread): | |||||
| if kitExtension == "sf2": | if kitExtension == "sf2": | ||||
| plugins = checkFileSF2(kit, self.fToolNative) | plugins = checkFileSF2(kit, self.fToolNative) | ||||
| elif kitExtension == "sfz": | |||||
| plugins = checkFileSFZ(kit, self.fToolNative) | |||||
| else: | else: | ||||
| plugins = None | plugins = None | ||||
| if plugins: | if plugins: | ||||
| self.fKitPlugins.append(plugins) | |||||
| kitPlugins.append(plugins) | |||||
| if not self.fContinueChecking: break | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | self.fLastCheckValue += self.fCurPercentValue | ||||
| return kitPlugins | |||||
| def _checkLv2Cached(self): | def _checkLv2Cached(self): | ||||
| settings = QSettings("falkTX", "Carla2") | settings = QSettings("falkTX", "Carla2") | ||||
| PLUG_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH))) | PLUG_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH))) | ||||
| del settings | del settings | ||||
| self.fLv2Plugins = [] | |||||
| PLUG_LIST = self.fLv2Plugins | |||||
| lv2Plugins = [] | |||||
| self._pluginLook(self.fLastCheckValue, "LV2 plugins...") | self._pluginLook(self.fLastCheckValue, "LV2 plugins...") | ||||
| count = gCarla.utils.get_cached_plugin_count(PLUGIN_LV2, PLUG_PATH) | count = gCarla.utils.get_cached_plugin_count(PLUGIN_LV2, PLUG_PATH) | ||||
| if not self.fContinueChecking: return | |||||
| if not self.fContinueChecking: | |||||
| return lv2Plugins | |||||
| for i in range(count): | for i in range(count): | ||||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_LV2, i) | descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_LV2, i) | ||||
| @@ -797,14 +795,46 @@ class SearchPluginsThread(QThread): | |||||
| percent = ( float(i) / count ) * self.fCurPercentValue | percent = ( float(i) / count ) * self.fCurPercentValue | ||||
| self._pluginLook(self.fLastCheckValue + percent, descInfo['label']) | self._pluginLook(self.fLastCheckValue + percent, descInfo['label']) | ||||
| plugins = checkPluginCached(descInfo, PLUGIN_LV2) | |||||
| if not descInfo['valid']: | |||||
| continue | |||||
| lv2Plugins.append(checkPluginCached(descInfo, PLUGIN_LV2)) | |||||
| if plugins: | |||||
| PLUG_LIST.append(plugins) | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | |||||
| return lv2Plugins | |||||
| def _checkSfzCached(self): | |||||
| settings = QSettings("falkTX", "Carla2") | |||||
| PLUG_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_SFZ, CARLA_DEFAULT_SFZ_PATH))) | |||||
| del settings | |||||
| sfzKits = [] | |||||
| self._pluginLook(self.fLastCheckValue, "SFZ kits...") | |||||
| count = gCarla.utils.get_cached_plugin_count(PLUGIN_SFZ, PLUG_PATH) | |||||
| if not self.fContinueChecking: | |||||
| return sfzKits | |||||
| for i in range(count): | |||||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_SFZ, i) | |||||
| percent = ( float(i) / count ) * self.fCurPercentValue | |||||
| self._pluginLook(self.fLastCheckValue + percent, descInfo['label']) | |||||
| if not descInfo['valid']: | |||||
| continue | |||||
| if not self.fContinueChecking: break | |||||
| sfzKits.append(checkPluginCached(descInfo, PLUGIN_SFZ)) | |||||
| if not self.fContinueChecking: | |||||
| break | |||||
| self.fLastCheckValue += self.fCurPercentValue | self.fLastCheckValue += self.fCurPercentValue | ||||
| return sfzKits | |||||
| def _pluginLook(self, percent, plugin): | def _pluginLook(self, percent, plugin): | ||||
| self.pluginLook.emit(percent, plugin) | self.pluginLook.emit(percent, plugin) | ||||
| @@ -1388,9 +1418,7 @@ class PluginDatabaseW(QDialog): | |||||
| rowCount = self.ui.tableWidget.rowCount() | rowCount = self.ui.tableWidget.rowCount() | ||||
| for i in range(rowCount): | |||||
| self.ui.tableWidget.showRow(i) | |||||
| for i in range(self.fLastTableIndex): | |||||
| plugin = self.ui.tableWidget.item(i, 0).data(Qt.UserRole) | plugin = self.ui.tableWidget.item(i, 0).data(Qt.UserRole) | ||||
| aIns = plugin['audio.ins'] | aIns = plugin['audio.ins'] | ||||
| aOuts = plugin['audio.outs'] | aOuts = plugin['audio.outs'] | ||||
| @@ -1449,6 +1477,8 @@ class PluginDatabaseW(QDialog): | |||||
| text in self.ui.tableWidget.item(i, 3).text().lower() or | text in self.ui.tableWidget.item(i, 3).text().lower() or | ||||
| text in self.ui.tableWidget.item(i, 13).text().lower())): | text in self.ui.tableWidget.item(i, 13).text().lower())): | ||||
| self.ui.tableWidget.hideRow(i) | self.ui.tableWidget.hideRow(i) | ||||
| else: | |||||
| self.ui.tableWidget.showRow(i) | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| @@ -1492,7 +1522,6 @@ class PluginDatabaseW(QDialog): | |||||
| bridgeText = self.tr("Yes (%s)" % typeText) | bridgeText = self.tr("Yes (%s)" % typeText) | ||||
| self.ui.tableWidget.insertRow(index) | |||||
| self.ui.tableWidget.setItem(index, 0, QTableWidgetItem(str(plugin['name']))) | self.ui.tableWidget.setItem(index, 0, QTableWidgetItem(str(plugin['name']))) | ||||
| self.ui.tableWidget.setItem(index, 1, QTableWidgetItem(str(plugin['label']))) | self.ui.tableWidget.setItem(index, 1, QTableWidgetItem(str(plugin['label']))) | ||||
| self.ui.tableWidget.setItem(index, 2, QTableWidgetItem(str(plugin['maker']))) | self.ui.tableWidget.setItem(index, 2, QTableWidgetItem(str(plugin['maker']))) | ||||
| @@ -1512,89 +1541,80 @@ class PluginDatabaseW(QDialog): | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| def _reAddPlugins(self): | |||||
| settingsDB = QSettings("falkTX", "CarlaPlugins3") | |||||
| for x in range(self.ui.tableWidget.rowCount()): | |||||
| self.ui.tableWidget.removeRow(0) | |||||
| self.fLastTableIndex = 0 | |||||
| self.ui.tableWidget.setSortingEnabled(False) | |||||
| internalCount = 0 | |||||
| ladspaCount = 0 | |||||
| dssiCount = 0 | |||||
| lv2Count = 0 | |||||
| vstCount = 0 | |||||
| kitCount = 0 | |||||
| def _reAddInternalHelper(self, settingsDB, ptype, path): | |||||
| if ptype == PLUGIN_INTERNAL: | |||||
| ptypeStr = "Internal" | |||||
| ptypeStrTr = self.tr("Internal") | |||||
| elif ptype == PLUGIN_LV2: | |||||
| ptypeStr = "LV2" | |||||
| ptypeStrTr = ptypeStr | |||||
| elif ptype == PLUGIN_SFZ: | |||||
| ptypeStr = "SFZ" | |||||
| ptypeStrTr = ptypeStr | |||||
| else: | |||||
| return 0 | |||||
| settings = QSettings("falkTX", "Carla2") | |||||
| LV2_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH))) | |||||
| del settings | |||||
| #qApp = QApplication.instance() | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| # Cached plugins (Internal) | |||||
| plugins = toList(settingsDB.value("Plugins/" + ptypeStr, [])) | |||||
| pluginCount = settingsDB.value("PluginCount/" + ptypeStr, 0, type=int) | |||||
| internalPlugins = toList(settingsDB.value("Plugins/Internal", [])) | |||||
| pluginCountNew = gCarla.utils.get_cached_plugin_count(ptype, path) | |||||
| for plugins in internalPlugins: | |||||
| internalCount += len(plugins) | |||||
| if pluginCountNew != pluginCount or (len(plugins) > 0 and plugins[0]['API'] != PLUGIN_QUERY_API_VERSION): | |||||
| plugins = [] | |||||
| pluginCount = pluginCountNew | |||||
| internalCountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_INTERNAL, "") | |||||
| QApplication.processEvents(QEventLoop.ExcludeUserInputEvents, 50) | |||||
| if internalCountNew != internalCount or (len(internalPlugins) > 0 and | |||||
| len(internalPlugins[0]) > 0 and | |||||
| internalPlugins[0][0]['API'] != PLUGIN_QUERY_API_VERSION): | |||||
| internalCount = internalCountNew | |||||
| internalPlugins = [] | |||||
| for i in range(pluginCountNew): | |||||
| descInfo = gCarla.utils.get_cached_plugin_info(ptype, i) | |||||
| for i in range(internalCountNew): | |||||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_INTERNAL, i) | |||||
| plugins = checkPluginCached(descInfo, PLUGIN_INTERNAL) | |||||
| if not descInfo['valid']: | |||||
| continue | |||||
| if plugins: | |||||
| internalPlugins.append(plugins) | |||||
| info = checkPluginCached(descInfo, ptype) | |||||
| settingsDB.setValue("Plugins/Internal", internalPlugins) | |||||
| if ptype == PLUGIN_SFZ: | |||||
| info['filename'] = info['label'] | |||||
| info['label'] = info['name'] | |||||
| for plugins in internalPlugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, self.tr("Internal")) | |||||
| plugins.append(info) | |||||
| del internalCountNew | |||||
| del internalPlugins | |||||
| if i % 50 == 0: | |||||
| QApplication.processEvents(QEventLoop.ExcludeUserInputEvents, 50) | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| # Cached plugins (LV2) | |||||
| settingsDB.setValue("Plugins/" + ptypeStr, plugins) | |||||
| settingsDB.setValue("PluginCount/" + ptypeStr, pluginCount) | |||||
| lv2Plugins = toList(settingsDB.value("Plugins/LV2", [])) | |||||
| # prepare rows in advance | |||||
| self.ui.tableWidget.setRowCount(self.fLastTableIndex + len(plugins)) | |||||
| for plugins in lv2Plugins: | |||||
| lv2Count += len(plugins) | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, ptypeStrTr) | |||||
| lv2CountNew = gCarla.utils.get_cached_plugin_count(PLUGIN_LV2, LV2_PATH) | |||||
| return pluginCount | |||||
| if lv2CountNew != lv2Count or (len(lv2Plugins) > 0 and | |||||
| len(lv2Plugins[0]) > 0 and | |||||
| lv2Plugins[0][0]['API'] != PLUGIN_QUERY_API_VERSION): | |||||
| lv2Count = lv2CountNew | |||||
| lv2Plugins = [] | |||||
| def _reAddPlugins(self): | |||||
| settingsDB = QSettings("falkTX", "CarlaPlugins4") | |||||
| for i in range(lv2CountNew): | |||||
| descInfo = gCarla.utils.get_cached_plugin_info(PLUGIN_LV2, i) | |||||
| plugins = checkPluginCached(descInfo, PLUGIN_LV2) | |||||
| for x in range(self.ui.tableWidget.rowCount()): | |||||
| self.ui.tableWidget.removeRow(0) | |||||
| if plugins: | |||||
| lv2Plugins.append(plugins) | |||||
| self.fLastTableIndex = 0 | |||||
| self.ui.tableWidget.setSortingEnabled(False) | |||||
| settingsDB.setValue("Plugins/LV2", lv2Plugins) | |||||
| settings = QSettings("falkTX", "Carla2") | |||||
| LV2_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_LV2, CARLA_DEFAULT_LV2_PATH))) | |||||
| SFZ_PATH = splitter.join(toList(settings.value(CARLA_KEY_PATHS_SFZ, CARLA_DEFAULT_SFZ_PATH))) | |||||
| del settings | |||||
| for plugins in lv2Plugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "LV2") | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| # plugins handled through backend | |||||
| del lv2CountNew | |||||
| del lv2Plugins | |||||
| internalCount = self._reAddInternalHelper(settingsDB, PLUGIN_INTERNAL, "") | |||||
| lv2Count = self._reAddInternalHelper(settingsDB, PLUGIN_LV2, LV2_PATH) | |||||
| sfzCount = self._reAddInternalHelper(settingsDB, PLUGIN_SFZ, SFZ_PATH) | |||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| # LADSPA | # LADSPA | ||||
| @@ -1606,13 +1626,6 @@ class PluginDatabaseW(QDialog): | |||||
| ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win32", [])) | ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win32", [])) | ||||
| ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win64", [])) | ladspaPlugins += toList(settingsDB.value("Plugins/LADSPA_win64", [])) | ||||
| for plugins in ladspaPlugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "LADSPA") | |||||
| ladspaCount += 1 | |||||
| del ladspaPlugins | |||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| # DSSI | # DSSI | ||||
| @@ -1623,13 +1636,6 @@ class PluginDatabaseW(QDialog): | |||||
| dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win32", [])) | dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win32", [])) | ||||
| dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win64", [])) | dssiPlugins += toList(settingsDB.value("Plugins/DSSI_win64", [])) | ||||
| for plugins in dssiPlugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "DSSI") | |||||
| dssiCount += 1 | |||||
| del dssiPlugins | |||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| # VST2 | # VST2 | ||||
| @@ -1640,43 +1646,58 @@ class PluginDatabaseW(QDialog): | |||||
| vst2Plugins += toList(settingsDB.value("Plugins/VST2_win32", [])) | vst2Plugins += toList(settingsDB.value("Plugins/VST2_win32", [])) | ||||
| vst2Plugins += toList(settingsDB.value("Plugins/VST2_win64", [])) | vst2Plugins += toList(settingsDB.value("Plugins/VST2_win64", [])) | ||||
| for plugins in vst2Plugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "VST2") | |||||
| vstCount += 1 | |||||
| del vst2Plugins | |||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| # Kits | # Kits | ||||
| sf2s = toList(settingsDB.value("Plugins/SF2", [])) | sf2s = toList(settingsDB.value("Plugins/SF2", [])) | ||||
| for sf2 in sf2s: | |||||
| for sf2_i in sf2: | |||||
| self._addPluginToTable(sf2_i, "SF2") | |||||
| kitCount += 1 | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| # count plugins first, so we can create rows in advance | |||||
| del sf2s | |||||
| ladspaCount = 0 | |||||
| dssiCount = 0 | |||||
| vstCount = 0 | |||||
| sf2Count = 0 | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| for plugins in ladspaPlugins: | |||||
| ladspaCount += len(plugins) | |||||
| sfzs = toList(settingsDB.value("Plugins/SFZ", [])) | |||||
| for plugins in dssiPlugins: | |||||
| dssiCount += len(plugins) | |||||
| for sfz in sfzs: | |||||
| for sfz_i in sfz: | |||||
| self._addPluginToTable(sfz_i, "SFZ") | |||||
| kitCount += 1 | |||||
| for plugins in vst2Plugins: | |||||
| vstCount += len(plugins) | |||||
| del sfzs | |||||
| for plugins in sf2s: | |||||
| sf2Count += len(plugins) | |||||
| self.ui.tableWidget.setRowCount(self.fLastTableIndex+ladspaCount+dssiCount+vstCount+sf2Count) | |||||
| self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2 and %i VST plugins, plus %i Sound Kits" % ( | |||||
| internalCount, ladspaCount, dssiCount, lv2Count, vstCount, sf2Count+sfzCount))) | |||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| # now add all plugins to the table | |||||
| self.ui.tableWidget.setSortingEnabled(True) | |||||
| for plugins in ladspaPlugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "LADSPA") | |||||
| self.ui.label.setText(self.tr("Have %i Internal, %i LADSPA, %i DSSI, %i LV2 and %i VST plugins, plus %i Sound Kits" % ( | |||||
| internalCount, ladspaCount, dssiCount, lv2Count, vstCount, kitCount))) | |||||
| for plugins in dssiPlugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "DSSI") | |||||
| for plugins in vst2Plugins: | |||||
| for plugin in plugins: | |||||
| self._addPluginToTable(plugin, "VST2") | |||||
| for sf2 in sf2s: | |||||
| for sf2_i in sf2: | |||||
| self._addPluginToTable(sf2_i, "SF2") | |||||
| # ---------------------------------------------------------------------------------------------------- | |||||
| self.ui.tableWidget.setSortingEnabled(True) | |||||
| self._checkFilters() | self._checkFilters() | ||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| @@ -27,11 +27,11 @@ from carla_config import * | |||||
| import json | import json | ||||
| if config_UseQt5: | if config_UseQt5: | ||||
| from PyQt5.QtCore import qCritical, QFileInfo, QModelIndex, QPointF, QTimer | |||||
| from PyQt5.QtCore import qCritical, QEventLoop, QFileInfo, QModelIndex, QPointF, QTimer | |||||
| from PyQt5.QtGui import QImage, QPalette | from PyQt5.QtGui import QImage, QPalette | ||||
| from PyQt5.QtWidgets import QAction, QApplication, QInputDialog, QFileSystemModel, QListWidgetItem, QMainWindow | from PyQt5.QtWidgets import QAction, QApplication, QInputDialog, QFileSystemModel, QListWidgetItem, QMainWindow | ||||
| else: | else: | ||||
| from PyQt4.QtCore import qCritical, QFileInfo, QModelIndex, QPointF, QTimer | |||||
| from PyQt4.QtCore import qCritical, QEventLoop, QFileInfo, QModelIndex, QPointF, QTimer | |||||
| from PyQt4.QtGui import QImage, QPalette | from PyQt4.QtGui import QImage, QPalette | ||||
| from PyQt4.QtGui import QAction, QApplication, QInputDialog, QFileSystemModel, QListWidgetItem, QMainWindow | from PyQt4.QtGui import QAction, QApplication, QInputDialog, QFileSystemModel, QListWidgetItem, QMainWindow | ||||
| @@ -338,9 +338,6 @@ class HostWindow(QMainWindow): | |||||
| self.ui.dsb_transport_bpm.setEnabled(False) | self.ui.dsb_transport_bpm.setEnabled(False) | ||||
| self.ui.dsb_transport_bpm.setReadOnly(True) | self.ui.dsb_transport_bpm.setReadOnly(True) | ||||
| if MACOS: # FIXME | |||||
| self.ui.cb_transport_link.setEnabled(False) | |||||
| self.ui.w_transport.setEnabled(False) | self.ui.w_transport.setEnabled(False) | ||||
| # ---------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------- | ||||
| @@ -548,7 +545,7 @@ class HostWindow(QMainWindow): | |||||
| self.ui.cb_transport_link.setVisible(False) | self.ui.cb_transport_link.setVisible(False) | ||||
| # Plugin needs to have timers always running so it receives messages | # Plugin needs to have timers always running so it receives messages | ||||
| if self.host.isPlugin: | |||||
| if self.host.isPlugin or self.host.isRemote: | |||||
| self.startTimers() | self.startTimers() | ||||
| # Qt needs this so it properly creates & resizes the canvas | # Qt needs this so it properly creates & resizes the canvas | ||||
| @@ -1544,6 +1541,8 @@ class HostWindow(QMainWindow): | |||||
| settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value()) | settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value()) | ||||
| settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value()) | settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value()) | ||||
| settings.setValue(CARLA_KEY_ENGINE_TRANSPORT_MODE, self.host.transportMode) | |||||
| def loadSettings(self, firstTime): | def loadSettings(self, firstTime): | ||||
| settings = QSettings() | settings = QSettings() | ||||
| @@ -1618,17 +1617,6 @@ class HostWindow(QMainWindow): | |||||
| else: | else: | ||||
| self.ui.act_add_jack.setVisible(False) | self.ui.act_add_jack.setVisible(False) | ||||
| if not (self.host.isControl or self.host.isPlugin): | |||||
| if self.ui.cb_transport_jack.isChecked(): | |||||
| transportMode = ENGINE_TRANSPORT_MODE_JACK | |||||
| else: | |||||
| transportMode = ENGINE_TRANSPORT_MODE_INTERNAL | |||||
| transportExtra = ":link:" if self.ui.cb_transport_link.isChecked() else "" | |||||
| self.enableTransport(transportMode != ENGINE_TRANSPORT_MODE_DISABLED) | |||||
| self.host.transportMode = transportMode | |||||
| self.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, transportMode, transportExtra) | |||||
| self.fMiniCanvasUpdateTimeout = 1000 if self.fSavedSettings[CARLA_KEY_CANVAS_FANCY_EYE_CANDY] else 0 | self.fMiniCanvasUpdateTimeout = 1000 if self.fSavedSettings[CARLA_KEY_CANVAS_FANCY_EYE_CANDY] else 0 | ||||
| setEngineSettings(self.host) | setEngineSettings(self.host) | ||||
| @@ -1871,6 +1859,7 @@ class HostWindow(QMainWindow): | |||||
| return | return | ||||
| mode = ENGINE_TRANSPORT_MODE_JACK if clicked else ENGINE_TRANSPORT_MODE_INTERNAL | mode = ENGINE_TRANSPORT_MODE_JACK if clicked else ENGINE_TRANSPORT_MODE_INTERNAL | ||||
| extra = ":link:" if self.ui.cb_transport_link.isChecked() else "" | extra = ":link:" if self.ui.cb_transport_link.isChecked() else "" | ||||
| self.host.transportMode = mode | |||||
| self.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, mode, extra) | self.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, mode, extra) | ||||
| @pyqtSlot(bool) | @pyqtSlot(bool) | ||||
| @@ -1879,6 +1868,7 @@ class HostWindow(QMainWindow): | |||||
| return | return | ||||
| mode = ENGINE_TRANSPORT_MODE_JACK if self.ui.cb_transport_jack.isChecked() else ENGINE_TRANSPORT_MODE_INTERNAL | mode = ENGINE_TRANSPORT_MODE_JACK if self.ui.cb_transport_jack.isChecked() else ENGINE_TRANSPORT_MODE_INTERNAL | ||||
| extra = ":link:" if clicked else "" | extra = ":link:" if clicked else "" | ||||
| self.host.transportMode = mode | |||||
| self.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, mode, extra) | self.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, mode, extra) | ||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| @@ -1948,14 +1938,10 @@ class HostWindow(QMainWindow): | |||||
| wasCompacted = pitem.isCompacted() | wasCompacted = pitem.isCompacted() | ||||
| isCompacted = wasCompacted | isCompacted = wasCompacted | ||||
| for i in range(self.host.get_custom_data_count(pluginId)): | |||||
| cdata = self.host.get_custom_data(pluginId, i) | |||||
| if cdata['type'] == CUSTOM_DATA_TYPE_PROPERTY and cdata['key'] == "CarlaSkinIsCompacted": | |||||
| isCompacted = bool(cdata['value'] == "true") | |||||
| break | |||||
| else: | |||||
| check = self.host.get_custom_data_value(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaSkinIsCompacted") | |||||
| if not check: | |||||
| return | return | ||||
| isCompacted = bool(check == "true") | |||||
| if wasCompacted == isCompacted: | if wasCompacted == isCompacted: | ||||
| return | return | ||||
| @@ -2529,7 +2515,7 @@ def engineCallback(host, action, pluginId, value1, value2, value3, valueStr): | |||||
| elif action == ENGINE_CALLBACK_NSM: | elif action == ENGINE_CALLBACK_NSM: | ||||
| host.NSMCallback.emit(value1, value2, valueStr) | host.NSMCallback.emit(value1, value2, valueStr) | ||||
| elif action == ENGINE_CALLBACK_IDLE: | elif action == ENGINE_CALLBACK_IDLE: | ||||
| QApplication.instance().processEvents() | |||||
| QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) | |||||
| elif action == ENGINE_CALLBACK_INFO: | elif action == ENGINE_CALLBACK_INFO: | ||||
| host.InfoCallback.emit(valueStr) | host.InfoCallback.emit(valueStr) | ||||
| elif action == ENGINE_CALLBACK_ERROR: | elif action == ENGINE_CALLBACK_ERROR: | ||||
| @@ -2774,15 +2760,15 @@ def setHostSettings(host): | |||||
| host.set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, host.preferPluginBridges, "") | host.set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, host.preferPluginBridges, "") | ||||
| host.set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES, host.preferUIBridges, "") | host.set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES, host.preferUIBridges, "") | ||||
| host.set_engine_option(ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR, host.preventBadBehaviour, "") | host.set_engine_option(ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR, host.preventBadBehaviour, "") | ||||
| host.set_engine_option(ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT, host.showLogs, "") | |||||
| host.set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT, host.uiBridgesTimeout, "") | host.set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT, host.uiBridgesTimeout, "") | ||||
| host.set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP, host.uisAlwaysOnTop, "") | host.set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP, host.uisAlwaysOnTop, "") | ||||
| if host.isPlugin or host.is_engine_running(): | |||||
| if host.isPlugin or host.isRemote or host.is_engine_running(): | |||||
| return | return | ||||
| host.set_engine_option(ENGINE_OPTION_PROCESS_MODE, host.nextProcessMode, "") | host.set_engine_option(ENGINE_OPTION_PROCESS_MODE, host.nextProcessMode, "") | ||||
| host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, host.transportMode, "") | host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, host.transportMode, "") | ||||
| host.set_engine_option(ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT, host.showLogs, "") | |||||
| # ------------------------------------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------------------------------------ | ||||
| # Set Engine settings according to carla preferences. Returns selected audio driver. | # Set Engine settings according to carla preferences. Returns selected audio driver. | ||||
| @@ -2882,9 +2868,11 @@ def setEngineSettings(host): | |||||
| # Only setup audio things if engine is not running | # Only setup audio things if engine is not running | ||||
| if not host.is_engine_running(): | if not host.is_engine_running(): | ||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice) | host.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice) | ||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "") | |||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "") | |||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_TRIPLE_BUFFER, audioTripleBuffer, "") | |||||
| if not audioDriver.startswith("JACK"): | |||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "") | |||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "") | |||||
| host.set_engine_option(ENGINE_OPTION_AUDIO_TRIPLE_BUFFER, audioTripleBuffer, "") | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| # fix things if needed | # fix things if needed | ||||
| @@ -52,6 +52,8 @@ SAMPLE_RATE_LIST = (22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000) | |||||
| # Driver Settings | # Driver Settings | ||||
| class DriverSettingsW(QDialog): | class DriverSettingsW(QDialog): | ||||
| AUTOMATIC_OPTION = "(Auto)" | |||||
| def __init__(self, parent, host, driverIndex, driverName): | def __init__(self, parent, host, driverIndex, driverName): | ||||
| QDialog.__init__(self, parent) | QDialog.__init__(self, parent) | ||||
| self.host = host | self.host = host | ||||
| @@ -130,9 +132,17 @@ class DriverSettingsW(QDialog): | |||||
| def slot_saveSettings(self): | def slot_saveSettings(self): | ||||
| settings = QSettings("falkTX", "Carla2") | settings = QSettings("falkTX", "Carla2") | ||||
| bufferSize = self.ui.cb_buffersize.currentText() | |||||
| sampleRate = self.ui.cb_samplerate.currentText() | |||||
| if bufferSize == self.AUTOMATIC_OPTION: | |||||
| bufferSize = "0" | |||||
| if sampleRate == self.AUTOMATIC_OPTION: | |||||
| sampleRate = "0" | |||||
| settings.setValue("%s%s/Device" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_device.currentText()) | settings.setValue("%s%s/Device" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_device.currentText()) | ||||
| settings.setValue("%s%s/BufferSize" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_buffersize.currentText()) | |||||
| settings.setValue("%s%s/SampleRate" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_samplerate.currentText()) | |||||
| settings.setValue("%s%s/BufferSize" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), bufferSize) | |||||
| settings.setValue("%s%s/SampleRate" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), sampleRate) | |||||
| settings.setValue("%s%s/TripleBuffer" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_triple_buffer.isChecked()) | settings.setValue("%s%s/TripleBuffer" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_triple_buffer.isChecked()) | ||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| @@ -147,34 +157,39 @@ class DriverSettingsW(QDialog): | |||||
| self.ui.cb_buffersize.clear() | self.ui.cb_buffersize.clear() | ||||
| self.ui.cb_samplerate.clear() | self.ui.cb_samplerate.clear() | ||||
| if deviceName: | |||||
| driverDeviceInfo = self.host.get_engine_driver_device_info(self.fDriverIndex, deviceName) | |||||
| driverDeviceHints = driverDeviceInfo['hints'] | |||||
| self.fBufferSizes = driverDeviceInfo['bufferSizes'] | |||||
| self.fSampleRates = driverDeviceInfo['sampleRates'] | |||||
| else: | |||||
| driverDeviceHints = 0x0 | |||||
| self.fBufferSizes = BUFFER_SIZE_LIST | |||||
| self.fSampleRates = SAMPLE_RATE_LIST | |||||
| driverDeviceInfo = self.host.get_engine_driver_device_info(self.fDriverIndex, deviceName) | |||||
| driverDeviceHints = driverDeviceInfo['hints'] | |||||
| self.fBufferSizes = driverDeviceInfo['bufferSizes'] | |||||
| self.fSampleRates = driverDeviceInfo['sampleRates'] | |||||
| if driverDeviceHints & ENGINE_DRIVER_DEVICE_CAN_TRIPLE_BUFFER: | if driverDeviceHints & ENGINE_DRIVER_DEVICE_CAN_TRIPLE_BUFFER: | ||||
| self.ui.cb_triple_buffer.setEnabled(True) | self.ui.cb_triple_buffer.setEnabled(True) | ||||
| else: | else: | ||||
| self.ui.cb_triple_buffer.setEnabled(False) | self.ui.cb_triple_buffer.setEnabled(False) | ||||
| for bsize in self.fBufferSizes: | |||||
| sbsize = str(bsize) | |||||
| self.ui.cb_buffersize.addItem(sbsize) | |||||
| if len(self.fBufferSizes) > 0: | |||||
| for bsize in self.fBufferSizes: | |||||
| sbsize = str(bsize) | |||||
| self.ui.cb_buffersize.addItem(sbsize) | |||||
| if oldBufferSize == sbsize: | |||||
| self.ui.cb_buffersize.setCurrentIndex(self.ui.cb_buffersize.count()-1) | |||||
| if oldBufferSize == sbsize: | |||||
| self.ui.cb_buffersize.setCurrentIndex(self.ui.cb_buffersize.count()-1) | |||||
| for srate in self.fSampleRates: | |||||
| ssrate = str(int(srate)) | |||||
| self.ui.cb_samplerate.addItem(ssrate) | |||||
| else: | |||||
| self.ui.cb_buffersize.addItem(self.AUTOMATIC_OPTION) | |||||
| self.ui.cb_buffersize.setCurrentIndex(0) | |||||
| if len(self.fSampleRates) > 0: | |||||
| for srate in self.fSampleRates: | |||||
| ssrate = str(int(srate)) | |||||
| self.ui.cb_samplerate.addItem(ssrate) | |||||
| if oldSampleRate == ssrate: | |||||
| self.ui.cb_samplerate.setCurrentIndex(self.ui.cb_samplerate.count()-1) | |||||
| if oldSampleRate == ssrate: | |||||
| self.ui.cb_samplerate.setCurrentIndex(self.ui.cb_samplerate.count()-1) | |||||
| else: | |||||
| self.ui.cb_samplerate.addItem(self.AUTOMATIC_OPTION) | |||||
| self.ui.cb_samplerate.setCurrentIndex(0) | |||||
| # -------------------------------------------------------------------------------------------------------- | # -------------------------------------------------------------------------------------------------------- | ||||
| @@ -281,19 +296,6 @@ class CarlaSettingsW(QDialog): | |||||
| self.ui.ch_exp_prevent_bad_behaviour.setVisible(False) | self.ui.ch_exp_prevent_bad_behaviour.setVisible(False) | ||||
| self.ui.lw_page.hideRow(self.TAB_INDEX_WINE) | self.ui.lw_page.hideRow(self.TAB_INDEX_WINE) | ||||
| if not MACOS: | |||||
| self.ui.label_engine_ui_bridges_mac_note.setVisible(False) | |||||
| # FIXME, pipes on win32 not working, and mis-behaving on macOS | |||||
| if MACOS or WINDOWS: | |||||
| self.ui.ch_engine_prefer_ui_bridges.setChecked(False) | |||||
| self.ui.ch_engine_prefer_ui_bridges.setEnabled(False) | |||||
| self.ui.ch_engine_prefer_ui_bridges.setVisible(False) | |||||
| self.ui.label_engine_ui_bridges_timeout.setEnabled(False) | |||||
| self.ui.label_engine_ui_bridges_timeout.setVisible(False) | |||||
| self.ui.sb_engine_ui_bridges_timeout.setEnabled(False) | |||||
| self.ui.sb_engine_ui_bridges_timeout.setVisible(False) | |||||
| # FIXME, not implemented yet | # FIXME, not implemented yet | ||||
| self.ui.ch_engine_uis_always_on_top.hide() | self.ui.ch_engine_uis_always_on_top.hide() | ||||
| @@ -415,10 +417,10 @@ class CarlaSettingsW(QDialog): | |||||
| if audioDriver == "JACK": | if audioDriver == "JACK": | ||||
| self.ui.sw_engine_process_mode.setCurrentIndex(0) | self.ui.sw_engine_process_mode.setCurrentIndex(0) | ||||
| self.ui.tb_engine_driver_config.setEnabled(False) | |||||
| else: | else: | ||||
| self.ui.sw_engine_process_mode.setCurrentIndex(1) | self.ui.sw_engine_process_mode.setCurrentIndex(1) | ||||
| self.ui.tb_engine_driver_config.setEnabled(self.host.audioDriverForced is None and not self.host.isPlugin) | |||||
| self.ui.tb_engine_driver_config.setEnabled(self.host.audioDriverForced is None and not self.host.isPlugin) | |||||
| self.ui.cb_engine_process_mode_jack.setCurrentIndex(self.host.nextProcessMode) | self.ui.cb_engine_process_mode_jack.setCurrentIndex(self.host.nextProcessMode) | ||||
| @@ -866,10 +868,8 @@ class CarlaSettingsW(QDialog): | |||||
| def slot_engineAudioDriverChanged(self): | def slot_engineAudioDriverChanged(self): | ||||
| if self.ui.cb_engine_audio_driver.currentText() == "JACK": | if self.ui.cb_engine_audio_driver.currentText() == "JACK": | ||||
| self.ui.sw_engine_process_mode.setCurrentIndex(0) | self.ui.sw_engine_process_mode.setCurrentIndex(0) | ||||
| self.ui.tb_engine_driver_config.setEnabled(False) | |||||
| else: | else: | ||||
| self.ui.sw_engine_process_mode.setCurrentIndex(1) | self.ui.sw_engine_process_mode.setCurrentIndex(1) | ||||
| self.ui.tb_engine_driver_config.setEnabled(True) | |||||
| @pyqtSlot() | @pyqtSlot() | ||||
| def slot_showAudioDriverSettings(self): | def slot_showAudioDriverSettings(self): | ||||
| @@ -273,7 +273,7 @@ CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING = False | |||||
| # Engine | # Engine | ||||
| CARLA_DEFAULT_FORCE_STEREO = False | CARLA_DEFAULT_FORCE_STEREO = False | ||||
| CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False | CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False | ||||
| CARLA_DEFAULT_PREFER_UI_BRIDGES = bool(not (MACOS or WINDOWS)) | |||||
| CARLA_DEFAULT_PREFER_UI_BRIDGES = True | |||||
| CARLA_DEFAULT_MANAGE_UIS = True | CARLA_DEFAULT_MANAGE_UIS = True | ||||
| CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False | CARLA_DEFAULT_UIS_ALWAYS_ON_TOP = False | ||||
| CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS | CARLA_DEFAULT_MAX_PARAMETERS = MAX_DEFAULT_PARAMETERS | ||||
| @@ -90,6 +90,12 @@ CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_p) | |||||
| # @see carla_get_cached_plugin_info() | # @see carla_get_cached_plugin_info() | ||||
| class CarlaCachedPluginInfo(Structure): | class CarlaCachedPluginInfo(Structure): | ||||
| _fields_ = [ | _fields_ = [ | ||||
| # Wherever the data in this struct is valid. | |||||
| # For performance reasons, plugins are only checked on request, | |||||
| # and as such, the count vs number of really valid plugins might not match. | |||||
| # Use this field to skip on plugins which cannot be loaded in Carla. | |||||
| ("valid", c_bool), | |||||
| # Plugin category. | # Plugin category. | ||||
| ("category", c_enum), | ("category", c_enum), | ||||
| @@ -133,6 +139,7 @@ class CarlaCachedPluginInfo(Structure): | |||||
| # @see CarlaCachedPluginInfo | # @see CarlaCachedPluginInfo | ||||
| PyCarlaCachedPluginInfo = { | PyCarlaCachedPluginInfo = { | ||||
| 'valid': False, | |||||
| 'category': PLUGIN_CATEGORY_NONE, | 'category': PLUGIN_CATEGORY_NONE, | ||||
| 'hints': 0x0, | 'hints': 0x0, | ||||
| 'audioIns': 0, | 'audioIns': 0, | ||||
| @@ -270,6 +277,8 @@ class CarlaUtils(object): | |||||
| return charPtrPtrToStringList(self.lib.carla_get_supported_features()) | return charPtrPtrToStringList(self.lib.carla_get_supported_features()) | ||||
| # Get how many internal plugins are available. | # Get how many internal plugins are available. | ||||
| # Internal and LV2 plugin formats are cached and need to be discovered via this function. | |||||
| # Do not call this for any other plugin formats. | |||||
| def get_cached_plugin_count(self, ptype, pluginPath): | def get_cached_plugin_count(self, ptype, pluginPath): | ||||
| return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) | return int(self.lib.carla_get_cached_plugin_count(ptype, pluginPath.encode("utf-8"))) | ||||
| @@ -34,8 +34,8 @@ ifeq ($(MACOS),true) | |||||
| BUILD_CXX_FLAGS += -ObjC++ | BUILD_CXX_FLAGS += -ObjC++ | ||||
| endif | endif | ||||
| 32BIT_FLAGS += -DBUILD_BRIDGE | |||||
| 64BIT_FLAGS += -DBUILD_BRIDGE | |||||
| 32BIT_FLAGS += -DBUILD_BRIDGE -DBUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| 64BIT_FLAGS += -DBUILD_BRIDGE -DBUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -47,11 +47,6 @@ NATIVE_BUILD_FLAGS += $(FLUIDSYNTH_FLAGS) | |||||
| NATIVE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | NATIVE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | ||||
| endif | endif | ||||
| ifeq ($(HAVE_LINUXSAMPLER),true) | |||||
| NATIVE_BUILD_FLAGS += $(LINUXSAMPLER_FLAGS) | |||||
| NATIVE_LINK_FLAGS += $(LINUXSAMPLER_LIBS) | |||||
| endif | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| LIBS_native = $(MODULEDIR)/lilv.a | LIBS_native = $(MODULEDIR)/lilv.a | ||||
| @@ -61,11 +56,7 @@ LIBS_win32 = $(MODULEDIR)/lilv.win32.a | |||||
| LIBS_win64 = $(MODULEDIR)/lilv.win64.a | LIBS_win64 = $(MODULEDIR)/lilv.win64.a | ||||
| LINK_FLAGS += $(LILV_LIBS) | LINK_FLAGS += $(LILV_LIBS) | ||||
| LIBS_native += $(MODULEDIR)/water.a | |||||
| LIBS_posix32 += $(MODULEDIR)/water.posix32.a | |||||
| LIBS_posix64 += $(MODULEDIR)/water.posix64.a | |||||
| LIBS_win32 += $(MODULEDIR)/water.win32.a | |||||
| LIBS_win64 += $(MODULEDIR)/water.win64.a | |||||
| LIBS_native += $(MODULEDIR)/water.files.a | |||||
| LINK_FLAGS += $(WATER_LIBS) | LINK_FLAGS += $(WATER_LIBS) | ||||
| LINK_FLAGS += $(LIBDL_LIBS) | LINK_FLAGS += $(LIBDL_LIBS) | ||||
| @@ -26,7 +26,6 @@ | |||||
| #endif | #endif | ||||
| #include "CarlaLadspaUtils.hpp" | #include "CarlaLadspaUtils.hpp" | ||||
| #include "CarlaDssiUtils.cpp" | |||||
| #include "CarlaLv2Utils.hpp" | #include "CarlaLv2Utils.hpp" | ||||
| #include "CarlaVstUtils.hpp" | #include "CarlaVstUtils.hpp" | ||||
| @@ -40,12 +39,13 @@ | |||||
| #include <iostream> | #include <iostream> | ||||
| #include "water/files/File.h" | |||||
| #include "water/text/StringArray.h" | |||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| # define CARLA_UTILS_CACHED_PLUGINS_ONLY | |||||
| # include "CarlaUtils.cpp" | |||||
| # include "water/files/File.h" | |||||
| # include "water/text/StringArray.h" | |||||
| # include "CarlaDssiUtils.cpp" | |||||
| # include "../backend/utils/CachedPlugins.cpp" | |||||
| #else | |||||
| # include "CarlaDssiUtils.hpp" | |||||
| #endif | #endif | ||||
| #define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl; | #define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl; | ||||
| @@ -270,9 +270,43 @@ static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t | |||||
| // ------------------------------ Plugin Checks ----------------------------- | // ------------------------------ Plugin Checks ----------------------------- | ||||
| #ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
| static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo) | |||||
| { | |||||
| if (! pinfo->valid) | |||||
| return; | |||||
| DISCOVERY_OUT("init", "-----------"); | |||||
| DISCOVERY_OUT("build", BINARY_NATIVE); | |||||
| DISCOVERY_OUT("hints", pinfo->hints); | |||||
| DISCOVERY_OUT("name", pinfo->name); | |||||
| DISCOVERY_OUT("maker", pinfo->maker); | |||||
| DISCOVERY_OUT("label", pinfo->label); | |||||
| DISCOVERY_OUT("audio.ins", pinfo->audioIns); | |||||
| DISCOVERY_OUT("audio.outs", pinfo->audioOuts); | |||||
| DISCOVERY_OUT("midi.ins", pinfo->midiIns); | |||||
| DISCOVERY_OUT("midi.outs", pinfo->midiOuts); | |||||
| DISCOVERY_OUT("parameters.ins", pinfo->parameterIns); | |||||
| DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts); | |||||
| DISCOVERY_OUT("end", "------------"); | |||||
| } | |||||
| static void do_cached_check(const PluginType type) | static void do_cached_check(const PluginType type) | ||||
| { | { | ||||
| const char* const plugPath = (type == PLUGIN_LV2) ? std::getenv("LV2_PATH") : nullptr; | |||||
| const char* plugPath; | |||||
| switch (type) | |||||
| { | |||||
| case PLUGIN_LV2: | |||||
| plugPath = std::getenv("LV2_PATH"); | |||||
| break; | |||||
| case PLUGIN_SFZ: | |||||
| plugPath = std::getenv("SFZ_PATH"); | |||||
| break; | |||||
| default: | |||||
| plugPath = nullptr; | |||||
| break; | |||||
| } | |||||
| const uint count = carla_get_cached_plugin_count(type, plugPath); | const uint count = carla_get_cached_plugin_count(type, plugPath); | ||||
| for (uint i=0; i<count; ++i) | for (uint i=0; i<count; ++i) | ||||
| @@ -280,19 +314,7 @@ static void do_cached_check(const PluginType type) | |||||
| const CarlaCachedPluginInfo* pinfo(carla_get_cached_plugin_info(type, i)); | const CarlaCachedPluginInfo* pinfo(carla_get_cached_plugin_info(type, i)); | ||||
| CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr); | ||||
| DISCOVERY_OUT("init", "-----------"); | |||||
| DISCOVERY_OUT("build", BINARY_NATIVE); | |||||
| DISCOVERY_OUT("hints", pinfo->hints); | |||||
| DISCOVERY_OUT("name", pinfo->name); | |||||
| DISCOVERY_OUT("maker", pinfo->maker); | |||||
| DISCOVERY_OUT("label", pinfo->label); | |||||
| DISCOVERY_OUT("audio.ins", pinfo->audioIns); | |||||
| DISCOVERY_OUT("audio.outs", pinfo->audioOuts); | |||||
| DISCOVERY_OUT("midi.ins", pinfo->midiIns); | |||||
| DISCOVERY_OUT("midi.outs", pinfo->midiOuts); | |||||
| DISCOVERY_OUT("parameters.ins", pinfo->parameterIns); | |||||
| DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts); | |||||
| DISCOVERY_OUT("end", "------------"); | |||||
| print_cached_plugin(pinfo); | |||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -674,11 +696,13 @@ static void do_dssi_check(lib_t& libHandle, const char* const filename, const bo | |||||
| if (midiIns > 0 && audioIns == 0 && audioOuts > 0) | if (midiIns > 0 && audioIns == 0 && audioOuts > 0) | ||||
| hints |= PLUGIN_IS_SYNTH; | hints |= PLUGIN_IS_SYNTH; | ||||
| #ifndef BUILD_BRIDGE | |||||
| if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label)) | if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label)) | ||||
| { | { | ||||
| hints |= PLUGIN_HAS_CUSTOM_UI; | hints |= PLUGIN_HAS_CUSTOM_UI; | ||||
| delete[] ui; | delete[] ui; | ||||
| } | } | ||||
| #endif | |||||
| if (doInit) | if (doInit) | ||||
| { | { | ||||
| @@ -828,6 +852,7 @@ static void do_dssi_check(lib_t& libHandle, const char* const filename, const bo | |||||
| } | } | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| static void do_lv2_check(const char* const bundle, const bool doInit) | static void do_lv2_check(const char* const bundle, const bool doInit) | ||||
| { | { | ||||
| Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); | Lv2WorldClass& lv2World(Lv2WorldClass::getInstance()); | ||||
| @@ -866,17 +891,18 @@ static void do_lv2_check(const char* const bundle, const bool doInit) | |||||
| // Get & check every plugin-instance | // Get & check every plugin-instance | ||||
| for (int i=0, count=URIs.size(); i < count; ++i) | for (int i=0, count=URIs.size(); i < count; ++i) | ||||
| { | { | ||||
| const LV2_RDF_Descriptor* const rdfDescriptor(lv2_rdf_new(URIs[i].toRawUTF8(), false)); | |||||
| const char* const URI = URIs[i].toRawUTF8(); | |||||
| ScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false)); | |||||
| if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr) | if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr) | ||||
| { | { | ||||
| DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URIs[i].toRawUTF8() << "'"); | |||||
| DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'"); | |||||
| continue; | continue; | ||||
| } | } | ||||
| if (doInit) | if (doInit) | ||||
| { | { | ||||
| // test if DLL is loadable, twice | |||||
| // test if lib is loadable, twice | |||||
| const lib_t libHandle1 = lib_open(rdfDescriptor->Binary); | const lib_t libHandle1 = lib_open(rdfDescriptor->Binary); | ||||
| if (libHandle1 == nullptr) | if (libHandle1 == nullptr) | ||||
| @@ -900,139 +926,16 @@ static void do_lv2_check(const char* const bundle, const bool doInit) | |||||
| lib_close(libHandle2); | lib_close(libHandle2); | ||||
| } | } | ||||
| // test if we support all required ports and features | |||||
| { | |||||
| bool supported = true; | |||||
| for (uint32_t j=0; j < rdfDescriptor->PortCount && supported; ++j) | |||||
| { | |||||
| const LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[j]); | |||||
| if (is_lv2_port_supported(rdfPort->Types)) | |||||
| { | |||||
| pass(); | |||||
| } | |||||
| else if (! LV2_IS_PORT_OPTIONAL(rdfPort->Properties)) | |||||
| { | |||||
| DISCOVERY_OUT("error", "Plugin '" << rdfDescriptor->URI << "' requires a non-supported port type (portName: '" << rdfPort->Name << "')"); | |||||
| supported = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| for (uint32_t j=0; j < rdfDescriptor->FeatureCount && supported; ++j) | |||||
| { | |||||
| const LV2_RDF_Feature& feature(rdfDescriptor->Features[j]); | |||||
| if (std::strcmp(feature.URI, LV2_DATA_ACCESS_URI) == 0 || std::strcmp(feature.URI, LV2_INSTANCE_ACCESS_URI) == 0) | |||||
| { | |||||
| DISCOVERY_OUT("warning", "Plugin '" << rdfDescriptor->URI << "' DSP wants UI feature '" << feature.URI << "', ignoring this"); | |||||
| } | |||||
| else if (feature.Required && ! is_lv2_feature_supported(feature.URI)) | |||||
| { | |||||
| DISCOVERY_OUT("error", "Plugin '" << rdfDescriptor->URI << "' requires a non-supported feature '" << feature.URI << "'"); | |||||
| supported = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (! supported) | |||||
| { | |||||
| delete rdfDescriptor; | |||||
| continue; | |||||
| } | |||||
| } | |||||
| uint hints = 0x0; | |||||
| int audioIns = 0; | |||||
| int audioOuts = 0; | |||||
| int midiIns = 0; | |||||
| int midiOuts = 0; | |||||
| int parametersIns = 0; | |||||
| int parametersOuts = 0; | |||||
| for (uint32_t j=0; j < rdfDescriptor->FeatureCount; ++j) | |||||
| { | |||||
| const LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[j]); | |||||
| if (std::strcmp(rdfFeature->URI, LV2_CORE__hardRTCapable) == 0) | |||||
| hints |= PLUGIN_IS_RTSAFE; | |||||
| } | |||||
| for (uint32_t j=0; j < rdfDescriptor->PortCount; ++j) | |||||
| { | |||||
| const LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[j]); | |||||
| if (LV2_IS_PORT_AUDIO(rdfPort->Types)) | |||||
| { | |||||
| if (LV2_IS_PORT_INPUT(rdfPort->Types)) | |||||
| audioIns += 1; | |||||
| else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) | |||||
| audioOuts += 1; | |||||
| } | |||||
| else if (LV2_IS_PORT_CONTROL(rdfPort->Types)) | |||||
| { | |||||
| if (LV2_IS_PORT_DESIGNATION_LATENCY(rdfPort->Designation)) | |||||
| { | |||||
| pass(); | |||||
| } | |||||
| else if (LV2_IS_PORT_DESIGNATION_SAMPLE_RATE(rdfPort->Designation)) | |||||
| { | |||||
| pass(); | |||||
| } | |||||
| else if (LV2_IS_PORT_DESIGNATION_FREEWHEELING(rdfPort->Designation)) | |||||
| { | |||||
| pass(); | |||||
| } | |||||
| else if (LV2_IS_PORT_DESIGNATION_TIME(rdfPort->Designation)) | |||||
| { | |||||
| pass(); | |||||
| } | |||||
| else | |||||
| { | |||||
| if (LV2_IS_PORT_INPUT(rdfPort->Types)) | |||||
| parametersIns += 1; | |||||
| else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) | |||||
| parametersOuts += 1; | |||||
| } | |||||
| } | |||||
| else if (LV2_PORT_SUPPORTS_MIDI_EVENT(rdfPort->Types)) | |||||
| { | |||||
| if (LV2_IS_PORT_INPUT(rdfPort->Types)) | |||||
| midiIns += 1; | |||||
| else if (LV2_IS_PORT_OUTPUT(rdfPort->Types)) | |||||
| midiOuts += 1; | |||||
| } | |||||
| } | |||||
| if (LV2_IS_INSTRUMENT(rdfDescriptor->Type[0], rdfDescriptor->Type[1])) | |||||
| hints |= PLUGIN_IS_SYNTH; | |||||
| if (rdfDescriptor->UICount > 0) | |||||
| hints |= PLUGIN_HAS_CUSTOM_UI; | |||||
| DISCOVERY_OUT("init", "-----------"); | |||||
| DISCOVERY_OUT("build", BINARY_NATIVE); | |||||
| DISCOVERY_OUT("hints", hints); | |||||
| const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI)); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr); | |||||
| if (rdfDescriptor->Name != nullptr) | |||||
| DISCOVERY_OUT("name", rdfDescriptor->Name); | |||||
| if (rdfDescriptor->Author != nullptr) | |||||
| DISCOVERY_OUT("maker", rdfDescriptor->Author); | |||||
| Lilv::Plugin lilvPlugin(cPlugin); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri()); | |||||
| DISCOVERY_OUT("uri", rdfDescriptor->URI); | |||||
| DISCOVERY_OUT("uniqueId", rdfDescriptor->UniqueID); | |||||
| DISCOVERY_OUT("audio.ins", audioIns); | |||||
| DISCOVERY_OUT("audio.outs", audioOuts); | |||||
| DISCOVERY_OUT("midi.ins", midiIns); | |||||
| DISCOVERY_OUT("midi.outs", midiOuts); | |||||
| DISCOVERY_OUT("parameters.ins", parametersIns); | |||||
| DISCOVERY_OUT("parameters.outs", parametersOuts); | |||||
| DISCOVERY_OUT("end", "------------"); | |||||
| delete rdfDescriptor; | |||||
| print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin)); | |||||
| } | } | ||||
| } | } | ||||
| #endif | |||||
| static void do_vst_check(lib_t& libHandle, const char* const filename, const bool doInit) | static void do_vst_check(lib_t& libHandle, const char* const filename, const bool doInit) | ||||
| { | { | ||||
| @@ -1040,7 +943,7 @@ static void do_vst_check(lib_t& libHandle, const char* const filename, const boo | |||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| CFBundleRef bundleRef = nullptr; | CFBundleRef bundleRef = nullptr; | ||||
| CFBundleRefNum resFileId; | |||||
| CFBundleRefNum resFileId = 0; | |||||
| if (libHandle == nullptr) | if (libHandle == nullptr) | ||||
| { | { | ||||
| @@ -1476,18 +1379,16 @@ int main(int argc, char* argv[]) | |||||
| break; | break; | ||||
| } | } | ||||
| if (type != PLUGIN_SF2 && type != PLUGIN_SFZ) | |||||
| if (type != PLUGIN_SF2 && filenameCheck.contains("fluidsynth", true)) | |||||
| { | { | ||||
| if (filenameCheck.contains("fluidsynth", true)) | |||||
| { | |||||
| DISCOVERY_OUT("info", "skipping fluidsynth based plugin"); | |||||
| return 0; | |||||
| } | |||||
| DISCOVERY_OUT("info", "skipping fluidsynth based plugin"); | |||||
| return 0; | |||||
| } | |||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| if (type == PLUGIN_VST2 && (filenameCheck.endsWith(".vst") || filenameCheck.endsWith(".vst/"))) | |||||
| openLib = false; | |||||
| if (type == PLUGIN_VST2 && (filenameCheck.endsWith(".vst") || filenameCheck.endsWith(".vst/"))) | |||||
| openLib = false; | |||||
| #endif | #endif | ||||
| } | |||||
| if (openLib) | if (openLib) | ||||
| { | { | ||||
| @@ -1540,9 +1441,11 @@ int main(int argc, char* argv[]) | |||||
| case PLUGIN_DSSI: | case PLUGIN_DSSI: | ||||
| do_dssi_check(handle, filename, doInit); | do_dssi_check(handle, filename, doInit); | ||||
| break; | break; | ||||
| #ifndef BUILD_BRIDGE | |||||
| case PLUGIN_LV2: | case PLUGIN_LV2: | ||||
| do_lv2_check(filename, doInit); | do_lv2_check(filename, doInit); | ||||
| break; | break; | ||||
| #endif | |||||
| case PLUGIN_VST2: | case PLUGIN_VST2: | ||||
| do_vst_check(handle, filename, doInit); | do_vst_check(handle, filename, doInit); | ||||
| break; | break; | ||||
| @@ -200,7 +200,8 @@ class ExternalUI(object): | |||||
| line2 = "%.10f" % line | line2 = "%.10f" % line | ||||
| else: | else: | ||||
| print("unknown data type to send:", type(line)) | print("unknown data type to send:", type(line)) | ||||
| return False | |||||
| hasError = True | |||||
| break | |||||
| if not gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n"): | if not gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n"): | ||||
| hasError = True | hasError = True | ||||
| @@ -863,7 +863,7 @@ float NanoVG::textBounds(float x, float y, const char* string, const char* end, | |||||
| if (fContext == nullptr) return 0.0f; | if (fContext == nullptr) return 0.0f; | ||||
| DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f); | DISTRHO_SAFE_ASSERT_RETURN(string != nullptr && string[0] != '\0', 0.0f); | ||||
| float b[4]; | |||||
| float b[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||||
| const float ret = nvgTextBounds(fContext, x, y, string, end, b); | const float ret = nvgTextBounds(fContext, x, y, string, end, b); | ||||
| bounds = Rectangle<float>(b[0], b[1], b[2] - b[0], b[3] - b[1]); | bounds = Rectangle<float>(b[0], b[1], b[2] - b[0], b[3] - b[1]); | ||||
| return ret; | return ret; | ||||
| @@ -396,6 +396,7 @@ struct Window::PrivateData { | |||||
| #elif defined(DISTRHO_OS_MAC) | #elif defined(DISTRHO_OS_MAC) | ||||
| if (mWindow != nullptr) | if (mWindow != nullptr) | ||||
| [mWindow makeKeyWindow]; | [mWindow makeKeyWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| #else | #else | ||||
| XRaiseWindow(xDisplay, xWindow); | XRaiseWindow(xDisplay, xWindow); | ||||
| XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | XSetInputFocus(xDisplay, xWindow, RevertToPointerRoot, CurrentTime); | ||||
| @@ -1226,7 +1226,7 @@ float fonsDrawText(FONScontext* stash, | |||||
| const char* str, const char* end) | const char* str, const char* end) | ||||
| { | { | ||||
| FONSstate* state = fons__getState(stash); | FONSstate* state = fons__getState(stash); | ||||
| unsigned int codepoint; | |||||
| unsigned int codepoint = 0; | |||||
| unsigned int utf8state = 0; | unsigned int utf8state = 0; | ||||
| FONSglyph* glyph = NULL; | FONSglyph* glyph = NULL; | ||||
| FONSquad q; | FONSquad q; | ||||
| @@ -1411,7 +1411,7 @@ float fonsTextBounds(FONScontext* stash, | |||||
| float* bounds) | float* bounds) | ||||
| { | { | ||||
| FONSstate* state = fons__getState(stash); | FONSstate* state = fons__getState(stash); | ||||
| unsigned int codepoint; | |||||
| unsigned int codepoint = 0; | |||||
| unsigned int utf8state = 0; | unsigned int utf8state = 0; | ||||
| FONSquad q; | FONSquad q; | ||||
| FONSglyph* glyph = NULL; | FONSglyph* glyph = NULL; | ||||
| @@ -2218,8 +2218,10 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||||
| } | } | ||||
| } | } | ||||
| // auto-connect "device" is #1 | |||||
| shouldAutoconnect_ = device == 0; | |||||
| // auto-connect-off "device" is at index 1 | |||||
| shouldAutoconnect_ = (device != 1 && | |||||
| std::getenv("LADISH_APP_NAME") == nullptr && | |||||
| std::getenv("NSM_URL") == nullptr); | |||||
| // Setup the buffer conversion information structure. We don't use | // Setup the buffer conversion information structure. We don't use | ||||
| // buffers to do channel offsets, so we override that parameter | // buffers to do channel offsets, so we override that parameter | ||||
| @@ -516,7 +516,7 @@ const char *Reader::readPathInto(water::String *pathOut, const char *pIn, const | |||||
| int Reader::keyValue(const water::String &str) | int Reader::keyValue(const water::String &str) | ||||
| { | { | ||||
| auto chars = str.toRawUTF8(); | |||||
| const char* const chars = str.toRawUTF8(); | |||||
| char c = chars[0]; | char c = chars[0]; | ||||
| @@ -123,7 +123,7 @@ Region *Sound::regionAt(int index) { return regions_[index]; } | |||||
| water::String Sound::dump() | water::String Sound::dump() | ||||
| { | { | ||||
| water::String info; | water::String info; | ||||
| auto &errors = getErrors(); | |||||
| const water::StringArray& errors = getErrors(); | |||||
| if (errors.size() > 0) | if (errors.size() > 0) | ||||
| { | { | ||||
| info << errors.size() << " errors: \n"; | info << errors.size() << " errors: \n"; | ||||
| @@ -135,7 +135,7 @@ water::String Sound::dump() | |||||
| info << "no errors.\n\n"; | info << "no errors.\n\n"; | ||||
| } | } | ||||
| auto &warnings = getWarnings(); | |||||
| const water::StringArray& warnings = getWarnings(); | |||||
| if (warnings.size() > 0) | if (warnings.size() > 0) | ||||
| { | { | ||||
| info << warnings.size() << " warnings: \n"; | info << warnings.size() << " warnings: \n"; | ||||
| @@ -21,6 +21,7 @@ | |||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| # include "text/String.h" | # include "text/String.h" | ||||
| # import <Foundation/NSAutoreleasePool.h> | |||||
| # import <Foundation/NSString.h> | # import <Foundation/NSString.h> | ||||
| #endif | #endif | ||||
| @@ -90,6 +91,15 @@ NSString* waterStringToNS (const String& s) | |||||
| { | { | ||||
| return [NSString stringWithUTF8String: s.toUTF8()]; | return [NSString stringWithUTF8String: s.toUTF8()]; | ||||
| } | } | ||||
| class AutoNSAutoreleasePool { | |||||
| public: | |||||
| AutoNSAutoreleasePool() : pool([NSAutoreleasePool new]) {} | |||||
| ~AutoNSAutoreleasePool() { [pool drain]; } | |||||
| private: | |||||
| NSAutoreleasePool* const pool; | |||||
| }; | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -69,6 +69,7 @@ public: | |||||
| @param other the array to copy | @param other the array to copy | ||||
| */ | */ | ||||
| Array (const Array<ElementType>& other) noexcept | Array (const Array<ElementType>& other) noexcept | ||||
| : numUsed (0) | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (other.numUsed),); | CARLA_SAFE_ASSERT_RETURN(data.setAllocatedSize (other.numUsed),); | ||||
| numUsed = other.numUsed; | numUsed = other.numUsed; | ||||
| @@ -1392,9 +1392,7 @@ static NSString* getFileLink (const String& path) | |||||
| bool File::isSymbolicLink() const | bool File::isSymbolicLink() const | ||||
| { | { | ||||
| // FIXME | |||||
| return false; | |||||
| //return getFileLink (fullPath) != nil; | |||||
| return getFileLink (fullPath) != nil; | |||||
| } | } | ||||
| File File::getLinkedTarget() const | File File::getLinkedTarget() const | ||||
| @@ -1407,62 +1405,62 @@ File File::getLinkedTarget() const | |||||
| bool File::copyInternal (const File& dest) const | bool File::copyInternal (const File& dest) const | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| NSFileManager* fm = [NSFileManager defaultManager]; | |||||
| return [fm fileExistsAtPath: waterStringToNS (fullPath)] | |||||
| #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 | |||||
| && [fm copyItemAtPath: waterStringToNS (fullPath) | |||||
| toPath: waterStringToNS (dest.getFullPathName()) | |||||
| error: nil]; | |||||
| #else | |||||
| && [fm copyPath: waterStringToNS (fullPath) | |||||
| toPath: waterStringToNS (dest.getFullPathName()) | |||||
| handler: nil]; | |||||
| #endif | |||||
| } | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| NSFileManager* fm = [NSFileManager defaultManager]; | |||||
| return [fm fileExistsAtPath: waterStringToNS (fullPath)] | |||||
| #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 | |||||
| && [fm copyItemAtPath: waterStringToNS (fullPath) | |||||
| toPath: waterStringToNS (dest.getFullPathName()) | |||||
| error: nil]; | |||||
| #else | |||||
| && [fm copyPath: waterStringToNS (fullPath) | |||||
| toPath: waterStringToNS (dest.getFullPathName()) | |||||
| handler: nil]; | |||||
| #endif | |||||
| } | } | ||||
| File File::getSpecialLocation (const SpecialLocationType type) | File File::getSpecialLocation (const SpecialLocationType type) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| String resultPath; | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| switch (type) | |||||
| { | |||||
| case userHomeDirectory: resultPath = nsStringToWater (NSHomeDirectory()); break; | |||||
| String resultPath; | |||||
| case tempDirectory: | |||||
| { | |||||
| File tmp ("~/Library/Caches/" + water_getExecutableFile().getFileNameWithoutExtension()); | |||||
| tmp.createDirectory(); | |||||
| return File (tmp.getFullPathName()); | |||||
| } | |||||
| switch (type) | |||||
| { | |||||
| case userHomeDirectory: | |||||
| resultPath = nsStringToWater (NSHomeDirectory()); | |||||
| break; | |||||
| case currentExecutableFile: | |||||
| return water_getExecutableFile(); | |||||
| case tempDirectory: | |||||
| { | |||||
| File tmp ("~/Library/Caches/" + water_getExecutableFile().getFileNameWithoutExtension()); | |||||
| tmp.createDirectory(); | |||||
| return File (tmp.getFullPathName()); | |||||
| } | |||||
| case hostApplicationPath: | |||||
| { | |||||
| unsigned int size = 8192; | |||||
| HeapBlock<char> buffer; | |||||
| buffer.calloc (size + 8); | |||||
| case currentExecutableFile: | |||||
| return water_getExecutableFile(); | |||||
| _NSGetExecutablePath (buffer.getData(), &size); | |||||
| return File (String::fromUTF8 (buffer, (int) size)); | |||||
| } | |||||
| case hostApplicationPath: | |||||
| { | |||||
| unsigned int size = 8192; | |||||
| HeapBlock<char> buffer; | |||||
| buffer.calloc (size + 8); | |||||
| default: | |||||
| jassertfalse; // unknown type? | |||||
| break; | |||||
| _NSGetExecutablePath (buffer.getData(), &size); | |||||
| return File (String::fromUTF8 (buffer, (int) size)); | |||||
| } | } | ||||
| if (resultPath.isNotEmpty()) | |||||
| return File (resultPath.convertToPrecomposedUnicode()); | |||||
| default: | |||||
| jassertfalse; // unknown type? | |||||
| break; | |||||
| } | } | ||||
| if (resultPath.isNotEmpty()) | |||||
| return File (resultPath.convertToPrecomposedUnicode()); | |||||
| return File(); | return File(); | ||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -1474,10 +1472,9 @@ public: | |||||
| wildCard (wildCard_), | wildCard (wildCard_), | ||||
| enumerator (nil) | enumerator (nil) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: waterStringToNS (directory.getFullPathName())] retain]; | |||||
| } | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: waterStringToNS (directory.getFullPathName())] retain]; | |||||
| } | } | ||||
| ~Pimpl() | ~Pimpl() | ||||
| @@ -1489,30 +1486,29 @@ public: | |||||
| bool* const isDir, int64* const fileSize, | bool* const isDir, int64* const fileSize, | ||||
| Time* const modTime, Time* const creationTime, bool* const isReadOnly) | Time* const modTime, Time* const creationTime, bool* const isReadOnly) | ||||
| { | { | ||||
| //@autoreleasepool | |||||
| { | |||||
| const char* wildcardUTF8 = nullptr; | |||||
| const AutoNSAutoreleasePool arpool; | |||||
| for (;;) | |||||
| { | |||||
| NSString* file; | |||||
| if (enumerator == nil || (file = [enumerator nextObject]) == nil) | |||||
| return false; | |||||
| const char* wildcardUTF8 = nullptr; | |||||
| [enumerator skipDescendents]; | |||||
| filenameFound = nsStringToWater (file).convertToPrecomposedUnicode(); | |||||
| for (;;) | |||||
| { | |||||
| NSString* file; | |||||
| if (enumerator == nil || (file = [enumerator nextObject]) == nil) | |||||
| return false; | |||||
| if (wildcardUTF8 == nullptr) | |||||
| wildcardUTF8 = wildCard.toUTF8(); | |||||
| [enumerator skipDescendents]; | |||||
| filenameFound = nsStringToWater (file).convertToPrecomposedUnicode(); | |||||
| if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0) | |||||
| continue; | |||||
| if (wildcardUTF8 == nullptr) | |||||
| wildcardUTF8 = wildCard.toUTF8(); | |||||
| const String fullPath (parentDir + filenameFound); | |||||
| updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly); | |||||
| if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0) | |||||
| continue; | |||||
| return true; | |||||
| } | |||||
| const String fullPath (parentDir + filenameFound); | |||||
| updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly); | |||||
| return true; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| /* | /* | ||||
| * Cross-platform C++ library for Carla, based on Juce v4 | * Cross-platform C++ library for Carla, based on Juce v4 | ||||
| * Copyright (C) 2015 ROLI Ltd. | * Copyright (C) 2015 ROLI Ltd. | ||||
| * Copyright (C) 2017 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2017-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -36,20 +36,20 @@ HINSTANCE water_getCurrentModuleInstanceHandle() noexcept | |||||
| } | } | ||||
| #include "files/DirectoryIterator.cpp" | |||||
| #include "files/File.cpp" | #include "files/File.cpp" | ||||
| #include "misc/Result.cpp" | #include "misc/Result.cpp" | ||||
| #include "misc/Time.cpp" | |||||
| #include "text/CharacterFunctions.cpp" | #include "text/CharacterFunctions.cpp" | ||||
| #include "text/StringArray.cpp" | #include "text/StringArray.cpp" | ||||
| #include "text/String.cpp" | #include "text/String.cpp" | ||||
| #if defined(DEBUG) || defined(BUILDING_CARLA_FOR_WINDOWS) | #if defined(DEBUG) || defined(BUILDING_CARLA_FOR_WINDOWS) | ||||
| # include "files/DirectoryIterator.cpp" | |||||
| # include "files/FileInputStream.cpp" | # include "files/FileInputStream.cpp" | ||||
| # include "files/FileOutputStream.cpp" | # include "files/FileOutputStream.cpp" | ||||
| # include "files/TemporaryFile.cpp" | # include "files/TemporaryFile.cpp" | ||||
| # include "maths/Random.cpp" | # include "maths/Random.cpp" | ||||
| # include "memory/MemoryBlock.cpp" | # include "memory/MemoryBlock.cpp" | ||||
| # include "misc/Time.cpp" | |||||
| # include "streams/InputStream.cpp" | # include "streams/InputStream.cpp" | ||||
| # include "streams/MemoryOutputStream.cpp" | # include "streams/MemoryOutputStream.cpp" | ||||
| # include "streams/OutputStream.cpp" | # include "streams/OutputStream.cpp" | ||||
| @@ -68,20 +68,18 @@ void carla_register_all_native_plugins(void) | |||||
| // Audio file | // Audio file | ||||
| carla_register_native_plugin_audiofile(); | carla_register_native_plugin_audiofile(); | ||||
| // MIDI file and sequencer | |||||
| // MIDI file | |||||
| carla_register_native_plugin_midifile(); | carla_register_native_plugin_midifile(); | ||||
| #ifdef HAVE_PYQT | |||||
| carla_register_native_plugin_midipattern(); | |||||
| #endif | |||||
| // Carla | |||||
| #ifdef HAVE_PYQT | #ifdef HAVE_PYQT | ||||
| // Carla | |||||
| carla_register_native_plugin_carla(); | carla_register_native_plugin_carla(); | ||||
| #endif | |||||
| // External-UI plugins | // External-UI plugins | ||||
| carla_register_native_plugin_bigmeter(); | carla_register_native_plugin_bigmeter(); | ||||
| carla_register_native_plugin_midipattern(); | |||||
| carla_register_native_plugin_notes(); | carla_register_native_plugin_notes(); | ||||
| #endif // HAVE_PYQT | |||||
| #ifdef HAVE_EXTERNAL_PLUGINS | #ifdef HAVE_EXTERNAL_PLUGINS | ||||
| // Experimental plugins | // Experimental plugins | ||||
| @@ -57,16 +57,14 @@ void carla_register_all_native_plugins(void) | |||||
| carla_register_native_plugin_miditranspose(); | carla_register_native_plugin_miditranspose(); | ||||
| #ifdef HAVE_PYQT | #ifdef HAVE_PYQT | ||||
| // MIDI sequencer | |||||
| carla_register_native_plugin_midipattern(); | |||||
| // Carla | // Carla | ||||
| carla_register_native_plugin_carla(); | carla_register_native_plugin_carla(); | ||||
| #endif | |||||
| // External-UI plugins | // External-UI plugins | ||||
| carla_register_native_plugin_bigmeter(); | carla_register_native_plugin_bigmeter(); | ||||
| carla_register_native_plugin_midipattern(); | |||||
| carla_register_native_plugin_notes(); | carla_register_native_plugin_notes(); | ||||
| #endif | |||||
| } | } | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -338,7 +338,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||||
| /* copyright */ "GNU GPL v2+", | /* copyright */ "GNU GPL v2+", | ||||
| DESCFUNCS | DESCFUNCS | ||||
| }, | }, | ||||
| #endif | |||||
| #endif // HAVE_PYQT | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| // External-UI plugins | // External-UI plugins | ||||
| @@ -379,7 +379,7 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||||
| /* copyright */ "GNU GPL v2+", | /* copyright */ "GNU GPL v2+", | ||||
| DESCFUNCS | DESCFUNCS | ||||
| }, | }, | ||||
| #endif | |||||
| #endif // HAVE_PYQT | |||||
| }; | }; | ||||
| @@ -41,8 +41,8 @@ struct AudioFilePool { | |||||
| size(0) {} | size(0) {} | ||||
| #else | #else | ||||
| AudioFilePool() | AudioFilePool() | ||||
| : startFrame(0), | |||||
| sampleRate(0), | |||||
| : sampleRate(0), | |||||
| startFrame(0), | |||||
| size(0) | size(0) | ||||
| { | { | ||||
| buffer[0] = buffer[1] = nullptr; | buffer[0] = buffer[1] = nullptr; | ||||
| @@ -74,6 +74,9 @@ class PluginHost(CarlaHostQtPlugin): | |||||
| self.fExternalUI.idleExternalUI() | self.fExternalUI.idleExternalUI() | ||||
| def is_engine_running(self): | def is_engine_running(self): | ||||
| if self.fExternalUI is None: | |||||
| return False | |||||
| return self.fExternalUI.isRunning() | return self.fExternalUI.isRunning() | ||||
| def set_engine_about_to_close(self): | def set_engine_about_to_close(self): | ||||
| @@ -32,18 +32,10 @@ ifeq ($(HAVE_FLUIDSYNTH),true) | |||||
| BUILD_CXX_FLAGS += $(FLUIDSYNTH_FLAGS) | BUILD_CXX_FLAGS += $(FLUIDSYNTH_FLAGS) | ||||
| endif | endif | ||||
| ifeq ($(HAVE_LINUXSAMPLER),true) | |||||
| BUILD_CXX_FLAGS += $(LINUXSAMPLER_FLAGS) | |||||
| endif | |||||
| ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
| BUILD_CXX_FLAGS += $(X11_FLAGS) | BUILD_CXX_FLAGS += $(X11_FLAGS) | ||||
| endif | endif | ||||
| ifeq ($(CARLA_ZYN_COMPAT),true) | |||||
| BUILD_CXX_FLAGS += -DCARLA_ZYN_LV2_EXPORTED | |||||
| endif | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| # Libs | # Libs | ||||
| @@ -78,21 +70,34 @@ LINK_FLAGS += $(NATIVE_PLUGINS_LIBS) | |||||
| LINK_FLAGS += $(FLUIDSYNTH_LIBS) | LINK_FLAGS += $(FLUIDSYNTH_LIBS) | ||||
| LINK_FLAGS += $(LIBLO_LIBS) | LINK_FLAGS += $(LIBLO_LIBS) | ||||
| LINK_FLAGS += $(LINUXSAMPLER_LIBS) | |||||
| LINK_FLAGS += $(MAGIC_LIBS) | LINK_FLAGS += $(MAGIC_LIBS) | ||||
| LINK_FLAGS += $(X11_LIBS) | LINK_FLAGS += $(X11_LIBS) | ||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| # NOTE: this assumes only LV2 version will be built | |||||
| SHARED += -Wl,-exported_symbol,_lv2_descriptor | |||||
| SHARED += -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_LV2_UI = -Wl,-exported_symbol,_lv2ui_descriptor | |||||
| SYMBOLS_VST = # TODO | |||||
| endif | endif | ||||
| # ---------------------------------------------------------------------------------------------------------------------------- | |||||
| # ... | |||||
| LIBS_ui = $(MODULEDIR)/water.a | |||||
| # ---------------------------------------------------------------------------------------------------------------------------- | # ---------------------------------------------------------------------------------------------------------------------------- | ||||
| TARGETS = \ | TARGETS = \ | ||||
| $(BINDIR)/carla.lv2/carla$(LIB_EXT) \ | |||||
| $(BINDIR)/carla.lv2/carla$(LIB_EXT) | |||||
| ifeq ($(HAVE_PYQT),true) | |||||
| TARGETS += \ | |||||
| $(BINDIR)/carla.lv2/carla-ui$(LIB_EXT) | |||||
| endif | |||||
| ifneq ($(CROSS_COMPILING),true) | |||||
| TARGETS += \ | |||||
| $(BINDIR)/carla.lv2/manifest.ttl | $(BINDIR)/carla.lv2/manifest.ttl | ||||
| endif | |||||
| ifeq ($(LINUX),true) | ifeq ($(LINUX),true) | ||||
| ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
| @@ -127,7 +132,12 @@ debug: | |||||
| $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | $(BINDIR)/carla.lv2/carla$(LIB_EXT): $(OBJDIR)/carla-lv2.cpp.o $(LIBS) | ||||
| -@mkdir -p $(BINDIR)/carla.lv2 | -@mkdir -p $(BINDIR)/carla.lv2 | ||||
| @echo "Linking carla.lv2/carla$(LIB_EXT)" | @echo "Linking carla.lv2/carla$(LIB_EXT)" | ||||
| @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(LINK_FLAGS) -o $@ | |||||
| @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(SYMBOLS_LV2) $(LINK_FLAGS) -o $@ | |||||
| $(BINDIR)/carla.lv2/carla-ui$(LIB_EXT): $(OBJDIR)/carla-lv2-ui.cpp.o $(LIBS_ui) | |||||
| -@mkdir -p $(BINDIR)/carla.lv2 | |||||
| @echo "Linking carla.lv2/carla-ui$(LIB_EXT)" | |||||
| @$(CXX) $< $(LIBS_START) $(LIBS_ui) $(LIBS_END) $(SHARED) $(SYMBOLS_LV2_UI) $(LINK_FLAGS) -o $@ | |||||
| $(BINDIR)/CarlaRack$(LIB_EXT): $(OBJDIR)/carla-vst.cpp.rack-syn.o $(LIBS) | $(BINDIR)/CarlaRack$(LIB_EXT): $(OBJDIR)/carla-vst.cpp.rack-syn.o $(LIBS) | ||||
| -@mkdir -p $(BINDIR) | -@mkdir -p $(BINDIR) | ||||
| @@ -166,6 +176,11 @@ $(OBJDIR)/carla-lv2.cpp.o: carla-lv2.cpp | |||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
| $(OBJDIR)/carla-lv2-ui.cpp.o: carla-lv2-ui.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/carla-vst.cpp.rack-fx.o: carla-vst.cpp | $(OBJDIR)/carla-vst.cpp.rack-fx.o: carla-vst.cpp | ||||
| -@mkdir -p $(OBJDIR) | -@mkdir -p $(OBJDIR) | ||||
| @echo "Compiling $< (RackFX)" | @echo "Compiling $< (RackFX)" | ||||
| @@ -76,21 +76,7 @@ struct PluginListManager { | |||||
| std::strcmp(desc->label, "carlapatchbay16" ) == 0 || | std::strcmp(desc->label, "carlapatchbay16" ) == 0 || | ||||
| std::strcmp(desc->label, "carlapatchbay32" ) == 0 || | std::strcmp(desc->label, "carlapatchbay32" ) == 0 || | ||||
| std::strcmp(desc->label, "bigmeter" ) == 0 || | std::strcmp(desc->label, "bigmeter" ) == 0 || | ||||
| std::strcmp(desc->label, "notes" ) == 0 || | |||||
| #ifdef CARLA_ZYN_LV2_EXPORTED | |||||
| std::strcmp(desc->label, "zynalienwah" ) == 0 || | |||||
| std::strcmp(desc->label, "zynchorus" ) == 0 || | |||||
| std::strcmp(desc->label, "zyndistortion" ) == 0 || | |||||
| std::strcmp(desc->label, "zyndynamicfilter") == 0 || | |||||
| std::strcmp(desc->label, "zynecho" ) == 0 || | |||||
| std::strcmp(desc->label, "zynphaser" ) == 0 || | |||||
| std::strcmp(desc->label, "zynreverb" ) == 0 || | |||||
| std::strcmp(desc->label, "zynaddsubfx" ) == 0 || | |||||
| #endif | |||||
| std::strcmp(desc->label, "at1" ) == 0 || | |||||
| std::strcmp(desc->label, "bls1" ) == 0 || | |||||
| std::strcmp(desc->label, "rev1-ambisonic" ) == 0 || | |||||
| std::strcmp(desc->label, "rev1-stereo" ) == 0) | |||||
| std::strcmp(desc->label, "notes" ) == 0) | |||||
| { | { | ||||
| descs.append(desc); | descs.append(desc); | ||||
| } | } | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * Carla Native Plugins | * Carla Native Plugins | ||||
| * Copyright (C) 2013-2017 Filipe Coelho <falktx@falktx.com> | |||||
| * Copyright (C) 2013-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | * | ||||
| * This program is free software; you can redistribute it and/or | * This program is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU General Public License as | * modify it under the terms of the GNU General Public License as | ||||
| @@ -30,6 +30,7 @@ | |||||
| #include "lv2/ui.h" | #include "lv2/ui.h" | ||||
| #include "lv2/units.h" | #include "lv2/units.h" | ||||
| #include "lv2/urid.h" | #include "lv2/urid.h" | ||||
| #include "lv2/worker.h" | |||||
| #include "lv2/lv2_external_ui.h" | #include "lv2/lv2_external_ui.h" | ||||
| #include "lv2/lv2_programs.h" | #include "lv2/lv2_programs.h" | ||||
| @@ -66,13 +67,14 @@ static const String nameToSymbol(const String& name, const uint32_t portIndex) | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (std::isdigit(trimmedName[0])) | |||||
| symbol += "_"; | |||||
| for (int i=0; i < trimmedName.length(); ++i) | for (int i=0; i < trimmedName.length(); ++i) | ||||
| { | { | ||||
| const water_uchar c = trimmedName[i]; | const water_uchar c = trimmedName[i]; | ||||
| if (i == 0 && std::isdigit(c)) | |||||
| symbol += "_"; | |||||
| else if (std::isalpha(c) || std::isdigit(c)) | |||||
| if (std::isalpha(c) || std::isdigit(c)) | |||||
| symbol += c; | symbol += c; | ||||
| else | else | ||||
| symbol += "_"; | symbol += "_"; | ||||
| @@ -135,7 +137,8 @@ static void writeManifestFile(PluginListManager& plm) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // UI | // UI | ||||
| #ifdef CARLA_OS_LINUX | |||||
| #ifdef HAVE_PYQT | |||||
| # if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| text += "<http://kxstudio.sf.net/carla/ui-embed>\n"; | text += "<http://kxstudio.sf.net/carla/ui-embed>\n"; | ||||
| text += " a <" LV2_UI__X11UI "> ;\n"; | text += " a <" LV2_UI__X11UI "> ;\n"; | ||||
| text += " ui:binary <carla" PLUGIN_EXT "> ;\n"; | text += " ui:binary <carla" PLUGIN_EXT "> ;\n"; | ||||
| @@ -146,7 +149,7 @@ static void writeManifestFile(PluginListManager& plm) | |||||
| text += " <" LV2_UI__resize "> ;\n"; | text += " <" LV2_UI__resize "> ;\n"; | ||||
| text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | ||||
| text += "\n"; | text += "\n"; | ||||
| #endif | |||||
| # endif | |||||
| text += "<http://kxstudio.sf.net/carla/ui-ext>\n"; | text += "<http://kxstudio.sf.net/carla/ui-ext>\n"; | ||||
| text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; | text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; | ||||
| @@ -156,6 +159,15 @@ static void writeManifestFile(PluginListManager& plm) | |||||
| text += " <" LV2_PROGRAMS__UIInterface "> ;\n"; | text += " <" LV2_PROGRAMS__UIInterface "> ;\n"; | ||||
| text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\n"; | text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> ;\n"; | ||||
| text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | text += " opts:supportedOption <" LV2_PARAMETERS__sampleRate "> .\n"; | ||||
| text += "\n"; | |||||
| text += "<http://kxstudio.sf.net/carla/ui-bridge-ext>\n"; | |||||
| text += " a <" LV2_EXTERNAL_UI__Widget "> ;\n"; | |||||
| text += " ui:binary <carla-ui" PLUGIN_EXT "> ;\n"; | |||||
| text += " lv2:extensionData <" LV2_UI__idleInterface "> ,\n"; | |||||
| text += " <" LV2_UI__showInterface "> ,\n"; | |||||
| text += " <" LV2_PROGRAMS__UIInterface "> .\n"; | |||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // Write file now | // Write file now | ||||
| @@ -292,6 +304,9 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | if (pluginDesc->category != NATIVE_PLUGIN_CATEGORY_SYNTH) | ||||
| text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; | text += " lv2:extensionData <" LV2_PROGRAMS__Interface "> ;\n"; | ||||
| if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | |||||
| text += " lv2:extensionData <" LV2_WORKER__interface "> ;\n"; | |||||
| text += "\n"; | text += "\n"; | ||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| @@ -305,46 +320,56 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // UIs | // UIs | ||||
| #ifdef HAVE_PYQT | |||||
| if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | if (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) | ||||
| { | { | ||||
| #ifdef CARLA_OS_LINUX | |||||
| # if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| if (std::strncmp(pluginDesc->label, "carla", 5) == 0) | if (std::strncmp(pluginDesc->label, "carla", 5) == 0) | ||||
| { | { | ||||
| text += " ui:ui <http://kxstudio.sf.net/carla/ui-embed> ,\n"; | text += " ui:ui <http://kxstudio.sf.net/carla/ui-embed> ,\n"; | ||||
| text += " <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | |||||
| text += " <http://kxstudio.sf.net/carla/ui-ext> ,\n"; | |||||
| text += " <http://kxstudio.sf.net/carla/ui-bridge-ext> ;\n"; | |||||
| } | } | ||||
| else | else | ||||
| #endif | |||||
| # endif | |||||
| { | { | ||||
| text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ;\n"; | |||||
| text += " ui:ui <http://kxstudio.sf.net/carla/ui-ext> ,\n"; | |||||
| text += " <http://kxstudio.sf.net/carla/ui-bridge-ext> ;\n"; | |||||
| } | } | ||||
| text += "\n"; | text += "\n"; | ||||
| } | } | ||||
| #endif | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // First MIDI/Time port | |||||
| // First input MIDI/Time/UI port | |||||
| if (pluginDesc->midiIns > 0 || (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0) | |||||
| const bool hasEventInPort = (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0 || (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
| if (pluginDesc->midiIns > 0 || hasEventInPort) | |||||
| { | { | ||||
| text += " lv2:port [\n"; | text += " lv2:port [\n"; | ||||
| text += " a lv2:InputPort, atom:AtomPort ;\n"; | text += " a lv2:InputPort, atom:AtomPort ;\n"; | ||||
| text += " atom:bufferType atom:Sequence ;\n"; | text += " atom:bufferType atom:Sequence ;\n"; | ||||
| if (pluginDesc->midiIns > 0 && (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) != 0) | |||||
| if (pluginDesc->midiIns > 0 && hasEventInPort) | |||||
| { | { | ||||
| text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; | text += " atom:supports <" LV2_MIDI__MidiEvent "> ,\n"; | ||||
| text += " <" LV2_TIME__Position "> ;\n"; | text += " <" LV2_TIME__Position "> ;\n"; | ||||
| } | } | ||||
| else if (pluginDesc->midiIns > 0) | else if (pluginDesc->midiIns > 0) | ||||
| { | |||||
| text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | ||||
| } | |||||
| else | else | ||||
| { | |||||
| text += " atom:supports <" LV2_TIME__Position "> ;\n"; | text += " atom:supports <" LV2_TIME__Position "> ;\n"; | ||||
| } | |||||
| text += " lv2:designation lv2:control ;\n"; | text += " lv2:designation lv2:control ;\n"; | ||||
| text += " lv2:index " + String(portIndex++) + " ;\n"; | text += " lv2:index " + String(portIndex++) + " ;\n"; | ||||
| if (pluginDesc->hints & NATIVE_PLUGIN_USES_TIME) | |||||
| if (hasEventInPort) | |||||
| { | { | ||||
| if (pluginDesc->midiIns > 1) | if (pluginDesc->midiIns > 1) | ||||
| { | { | ||||
| @@ -395,6 +420,52 @@ static void writePluginFile(const NativePluginDescriptor* const pluginDesc) | |||||
| text += " ] , [\n"; | text += " ] , [\n"; | ||||
| } | } | ||||
| // ------------------------------------------------------------------- | |||||
| // First output MIDI/UI port | |||||
| const bool hasEventOutPort = (pluginDesc->hints & NATIVE_PLUGIN_HAS_UI) != 0; | |||||
| if (pluginDesc->midiIns > 0 || hasEventOutPort) | |||||
| { | |||||
| text += " lv2:port [\n"; | |||||
| text += " a lv2:OutputPort, atom:AtomPort ;\n"; | |||||
| text += " atom:bufferType atom:Sequence ;\n"; | |||||
| if (pluginDesc->midiOuts > 0) | |||||
| text += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||||
| text += " lv2:index " + String(portIndex++) + " ;\n"; | |||||
| if (hasEventOutPort) | |||||
| { | |||||
| if (pluginDesc->midiOuts > 1) | |||||
| { | |||||
| text += " lv2:symbol \"lv2_events_out_1\" ;\n"; | |||||
| text += " lv2:name \"Events Input #1\" ;\n"; | |||||
| } | |||||
| else | |||||
| { | |||||
| text += " lv2:symbol \"lv2_events_out\" ;\n"; | |||||
| text += " lv2:name \"Events Output\" ;\n"; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (pluginDesc->midiOuts > 1) | |||||
| { | |||||
| text += " lv2:symbol \"lv2_midi_out_" + String(portIndex+1) + "\" ;\n"; | |||||
| text += " lv2:name \"MIDI Output #" + String(portIndex+1) + "\" ;\n"; | |||||
| } | |||||
| else | |||||
| { | |||||
| text += " lv2:symbol \"lv2_midi_out\" ;\n"; | |||||
| text += " lv2:name \"MIDI Output\" ;\n"; | |||||
| } | |||||
| } | |||||
| text += " ] ;\n\n"; | |||||
| } | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| // MIDI outputs | // MIDI outputs | ||||
| @@ -0,0 +1,440 @@ | |||||
| /* | |||||
| * Carla Native Plugins | |||||
| * Copyright (C) 2013-2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #ifndef HAVE_PYQT | |||||
| # error This file should not be built | |||||
| #endif | |||||
| #include "CarlaLv2Utils.hpp" | |||||
| #include "CarlaPipeUtils.hpp" | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| class NativePluginUI : public LV2_External_UI_Widget_Compat | |||||
| { | |||||
| public: | |||||
| NativePluginUI(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
| LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
| : fUridMap(nullptr), | |||||
| fUridUnmap(nullptr), | |||||
| fUridTranser(0), | |||||
| fUridTranser2(0), | |||||
| fUI() | |||||
| { | |||||
| run = extui_run; | |||||
| show = extui_show; | |||||
| hide = extui_hide; | |||||
| fUI.writeFunction = writeFunction; | |||||
| fUI.controller = controller; | |||||
| const LV2_URID_Map* uridMap = nullptr; | |||||
| const LV2_URID_Unmap* uridUnmap = nullptr; | |||||
| for (int i=0; features[i] != nullptr; ++i) | |||||
| { | |||||
| /**/ if (std::strcmp(features[i]->URI, LV2_URID__map) == 0) | |||||
| uridMap = (const LV2_URID_Map*)features[i]->data; | |||||
| else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0) | |||||
| uridUnmap = (const LV2_URID_Unmap*)features[i]->data; | |||||
| } | |||||
| if (uridMap == nullptr) | |||||
| { | |||||
| carla_stderr("Host doesn't provide urid-map feature"); | |||||
| return; | |||||
| } | |||||
| fUridMap = uridMap; | |||||
| fUridUnmap = uridUnmap; | |||||
| fUridTranser = uridMap->map(uridMap->handle, LV2_ATOM__eventTransfer); | |||||
| fUridTranser2 = uridMap->map(uridMap->handle, "urn:carla:transmitEv"); | |||||
| // --------------------------------------------------------------- | |||||
| // see if the host supports external-ui | |||||
| for (int i=0; features[i] != nullptr; ++i) | |||||
| { | |||||
| if (std::strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host) == 0 || | |||||
| std::strcmp(features[i]->URI, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0) | |||||
| { | |||||
| fUI.host = (const LV2_External_UI_Host*)features[i]->data; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (fUI.host != nullptr) | |||||
| { | |||||
| fUI.name = carla_strdup(fUI.host->plugin_human_id); | |||||
| *widget = (LV2_External_UI_Widget_Compat*)this; | |||||
| return; | |||||
| } | |||||
| // --------------------------------------------------------------- | |||||
| // no external-ui support, use showInterface | |||||
| for (int i=0; features[i] != nullptr; ++i) | |||||
| { | |||||
| if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) != 0) | |||||
| continue; | |||||
| const LV2_Options_Option* const options((const LV2_Options_Option*)features[i]->data); | |||||
| CARLA_SAFE_ASSERT_BREAK(options != nullptr); | |||||
| for (int j=0; options[j].key != 0; ++j) | |||||
| { | |||||
| if (options[j].key != uridMap->map(uridMap->handle, LV2_UI__windowTitle)) | |||||
| continue; | |||||
| const char* const title((const char*)options[j].value); | |||||
| CARLA_SAFE_ASSERT_BREAK(title != nullptr && title[0] != '\0'); | |||||
| fUI.name = carla_strdup(title); | |||||
| break; | |||||
| } | |||||
| break; | |||||
| } | |||||
| if (fUI.name == nullptr) | |||||
| fUI.name = carla_strdup("Carla"); | |||||
| *widget = nullptr; | |||||
| } | |||||
| ~NativePluginUI() | |||||
| { | |||||
| if (fUI.isVisible) | |||||
| writeAtomMessage("quit"); | |||||
| fUI.host = nullptr; | |||||
| fUI.writeFunction = nullptr; | |||||
| fUI.controller = nullptr; | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,); | |||||
| if (format == 0) | |||||
| { | |||||
| char msg[128]; | |||||
| const float* const valuePtr = (const float*)buffer; | |||||
| { | |||||
| const ScopedLocale csl; | |||||
| std::snprintf(msg, 127, "control %u %f", portIndex, *valuePtr); | |||||
| } | |||||
| msg[127] = '\0'; | |||||
| writeAtomMessage(msg); | |||||
| return; | |||||
| } | |||||
| if (format == fUridTranser) | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(bufferSize > sizeof(LV2_Atom),); | |||||
| const LV2_Atom* const atom = (const LV2_Atom*)buffer; | |||||
| if (atom->type == fUridTranser2) | |||||
| { | |||||
| const char* const msg = (const char*)(atom + 1); | |||||
| if (std::strcmp(msg, "quit") == 0) | |||||
| { | |||||
| handleUiClosed(); | |||||
| } | |||||
| return; | |||||
| } | |||||
| } | |||||
| if (fUridUnmap != nullptr) | |||||
| { | |||||
| carla_stdout("lv2ui_port_event %u %u %u:%s %p", | |||||
| portIndex, bufferSize, format, fUridUnmap->unmap(fUridUnmap->handle, format), buffer); | |||||
| } | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| void lv2ui_select_program(uint32_t bank, uint32_t program) const | |||||
| { | |||||
| char msg[128]; | |||||
| std::snprintf(msg, 127, "program %u %u", bank, program); | |||||
| msg[127] = '\0'; | |||||
| writeAtomMessage(msg); | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| int lv2ui_idle() const | |||||
| { | |||||
| if (! fUI.isVisible) | |||||
| return 1; | |||||
| handleUiRun(); | |||||
| return 0; | |||||
| } | |||||
| int lv2ui_show() | |||||
| { | |||||
| handleUiShow(); | |||||
| return 0; | |||||
| } | |||||
| int lv2ui_hide() | |||||
| { | |||||
| handleUiHide(); | |||||
| return 0; | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| protected: | |||||
| void handleUiShow() | |||||
| { | |||||
| writeAtomMessage("show"); | |||||
| fUI.isVisible = true; | |||||
| } | |||||
| void handleUiHide() | |||||
| { | |||||
| if (fUI.isVisible) | |||||
| { | |||||
| fUI.isVisible = false; | |||||
| writeAtomMessage("hide"); | |||||
| } | |||||
| } | |||||
| void handleUiRun() const | |||||
| { | |||||
| if (fUI.isVisible) | |||||
| writeAtomMessage("idle"); | |||||
| } | |||||
| void handleUiClosed() | |||||
| { | |||||
| fUI.isVisible = false; | |||||
| if (fUI.host != nullptr && fUI.host->ui_closed != nullptr && fUI.controller != nullptr) | |||||
| fUI.host->ui_closed(fUI.controller); | |||||
| fUI.host = nullptr; | |||||
| fUI.writeFunction = nullptr; | |||||
| fUI.controller = nullptr; | |||||
| } | |||||
| bool writeAtomMessage(const char* const msg) const | |||||
| { | |||||
| CARLA_SAFE_ASSERT_RETURN(fUI.writeFunction != nullptr, false); | |||||
| CARLA_SAFE_ASSERT_RETURN(fUridTranser2 != 0, false); | |||||
| carla_debug("writeAtomMessage(%s)", msg); | |||||
| const size_t msgSize = std::strlen(msg)+1; | |||||
| const size_t atomSize = sizeof(LV2_Atom) + msgSize; | |||||
| if (atomSize <= 128) | |||||
| { | |||||
| char atomBuf[atomSize]; | |||||
| carla_zeroChars(atomBuf, atomSize); | |||||
| LV2_Atom* const atom = (LV2_Atom*)atomBuf; | |||||
| atom->size = msgSize; | |||||
| atom->type = fUridTranser2; | |||||
| std::memcpy(atomBuf+sizeof(LV2_Atom), msg, msgSize); | |||||
| fUI.writeFunction(fUI.controller, 0, atomSize, fUridTranser, atomBuf); | |||||
| } | |||||
| else | |||||
| { | |||||
| char* const atomBuf = new char[atomSize]; | |||||
| carla_zeroChars(atomBuf, atomSize); | |||||
| LV2_Atom* const atom = (LV2_Atom*)atomBuf; | |||||
| atom->size = msgSize; | |||||
| atom->type = fUridTranser2; | |||||
| std::memcpy(atomBuf+sizeof(LV2_Atom), msg, msgSize); | |||||
| fUI.writeFunction(fUI.controller, 0, atomSize, fUridTranser, atomBuf); | |||||
| delete[] atomBuf; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| private: | |||||
| const LV2_URID_Map* fUridMap; | |||||
| const LV2_URID_Unmap* fUridUnmap; | |||||
| LV2_URID fUridTranser, fUridTranser2; | |||||
| struct UI { | |||||
| const LV2_External_UI_Host* host; | |||||
| LV2UI_Write_Function writeFunction; | |||||
| LV2UI_Controller controller; | |||||
| const char* name; | |||||
| bool isVisible; | |||||
| UI() | |||||
| : host(nullptr), | |||||
| writeFunction(nullptr), | |||||
| controller(nullptr), | |||||
| name(nullptr), | |||||
| isVisible(false) {} | |||||
| ~UI() | |||||
| { | |||||
| if (name != nullptr) | |||||
| { | |||||
| delete[] name; | |||||
| name = nullptr; | |||||
| } | |||||
| } | |||||
| } fUI; | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| #define handlePtr ((NativePluginUI*)handle) | |||||
| static void extui_run(LV2_External_UI_Widget_Compat* handle) | |||||
| { | |||||
| handlePtr->handleUiRun(); | |||||
| } | |||||
| static void extui_show(LV2_External_UI_Widget_Compat* handle) | |||||
| { | |||||
| carla_debug("extui_show(%p)", handle); | |||||
| handlePtr->handleUiShow(); | |||||
| } | |||||
| static void extui_hide(LV2_External_UI_Widget_Compat* handle) | |||||
| { | |||||
| carla_debug("extui_hide(%p)", handle); | |||||
| handlePtr->handleUiHide(); | |||||
| } | |||||
| #undef handlePtr | |||||
| // ------------------------------------------------------------------- | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePluginUI) | |||||
| }; | |||||
| // ----------------------------------------------------------------------- | |||||
| // LV2 UI descriptor functions | |||||
| static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*, | |||||
| LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | |||||
| LV2UI_Widget* widget, const LV2_Feature* const* features) | |||||
| { | |||||
| carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | |||||
| NativePluginUI* const ui = new NativePluginUI(writeFunction, controller, widget, features); | |||||
| // TODO: check ok | |||||
| return (LV2UI_Handle)ui; | |||||
| } | |||||
| #define uiPtr ((NativePluginUI*)ui) | |||||
| static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | |||||
| { | |||||
| carla_debug("lv2ui_port_event(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer); | |||||
| uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | |||||
| } | |||||
| static void lv2ui_cleanup(LV2UI_Handle ui) | |||||
| { | |||||
| carla_debug("lv2ui_cleanup(%p)", ui); | |||||
| delete uiPtr; | |||||
| } | |||||
| static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program) | |||||
| { | |||||
| carla_debug("lv2ui_select_program(%p, %i, %i)", ui, bank, program); | |||||
| uiPtr->lv2ui_select_program(bank, program); | |||||
| } | |||||
| static int lv2ui_idle(LV2UI_Handle ui) | |||||
| { | |||||
| return uiPtr->lv2ui_idle(); | |||||
| } | |||||
| static int lv2ui_show(LV2UI_Handle ui) | |||||
| { | |||||
| carla_debug("lv2ui_show(%p)", ui); | |||||
| return uiPtr->lv2ui_show(); | |||||
| } | |||||
| static int lv2ui_hide(LV2UI_Handle ui) | |||||
| { | |||||
| carla_debug("lv2ui_hide(%p)", ui); | |||||
| return uiPtr->lv2ui_hide(); | |||||
| } | |||||
| static const void* lv2ui_extension_data(const char* uri) | |||||
| { | |||||
| carla_stdout("lv2ui_extension_data(\"%s\")", uri); | |||||
| static const LV2UI_Idle_Interface uiidle = { lv2ui_idle }; | |||||
| static const LV2UI_Show_Interface uishow = { lv2ui_show, lv2ui_hide }; | |||||
| static const LV2_Programs_UI_Interface uiprograms = { lv2ui_select_program }; | |||||
| if (std::strcmp(uri, LV2_UI__idleInterface) == 0) | |||||
| return &uiidle; | |||||
| if (std::strcmp(uri, LV2_UI__showInterface) == 0) | |||||
| return &uishow; | |||||
| if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0) | |||||
| return &uiprograms; | |||||
| return nullptr; | |||||
| } | |||||
| #undef uiPtr | |||||
| // ----------------------------------------------------------------------- | |||||
| // Startup code | |||||
| CARLA_EXPORT | |||||
| const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||||
| { | |||||
| carla_debug("lv2ui_descriptor(%i)", index); | |||||
| static const LV2UI_Descriptor lv2UiExtDesc = { | |||||
| /* URI */ "http://kxstudio.sf.net/carla/ui-bridge-ext", | |||||
| /* instantiate */ lv2ui_instantiate, | |||||
| /* cleanup */ lv2ui_cleanup, | |||||
| /* port_event */ lv2ui_port_event, | |||||
| /* extension_data */ lv2ui_extension_data | |||||
| }; | |||||
| return (index == 0) ? &lv2UiExtDesc : nullptr; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| #include "CarlaPipeUtils.cpp" | |||||
| // ----------------------------------------------------------------------- | |||||
| @@ -34,14 +34,15 @@ public: | |||||
| const double sampleRate, | const double sampleRate, | ||||
| const char* const bundlePath, | const char* const bundlePath, | ||||
| const LV2_Feature* const* const features) | const LV2_Feature* const* const features) | ||||
| : Lv2PluginBaseClass(sampleRate, features), | |||||
| : Lv2PluginBaseClass<NativeTimeInfo>(sampleRate, features), | |||||
| fHandle(nullptr), | fHandle(nullptr), | ||||
| fHost(), | fHost(), | ||||
| fDescriptor(desc), | fDescriptor(desc), | ||||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | #ifdef CARLA_PROPER_CPP11_SUPPORT | ||||
| fProgramDesc({0, 0, nullptr}), | fProgramDesc({0, 0, nullptr}), | ||||
| #endif | #endif | ||||
| fMidiEventCount(0) | |||||
| fMidiEventCount(0), | |||||
| fWorkerUISignal(0) | |||||
| { | { | ||||
| carla_zeroStruct(fHost); | carla_zeroStruct(fHost); | ||||
| @@ -104,6 +105,7 @@ public: | |||||
| fHandle = fDescriptor->instantiate(&fHost); | fHandle = fDescriptor->instantiate(&fHost); | ||||
| CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false); | ||||
| fPorts.hasUI = fDescriptor->hints & NATIVE_PLUGIN_HAS_UI; | |||||
| fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME; | fPorts.usesTime = fDescriptor->hints & NATIVE_PLUGIN_USES_TIME; | ||||
| fPorts.numAudioIns = fDescriptor->audioIns; | fPorts.numAudioIns = fDescriptor->audioIns; | ||||
| fPorts.numAudioOuts = fDescriptor->audioOuts; | fPorts.numAudioOuts = fDescriptor->audioOuts; | ||||
| @@ -198,6 +200,25 @@ public: | |||||
| { | { | ||||
| if (event == nullptr) | if (event == nullptr) | ||||
| continue; | continue; | ||||
| if (event->body.type == fURIs.uiEvents && fWorkerUISignal != -1) | |||||
| { | |||||
| if (fWorker != nullptr) | |||||
| { | |||||
| // worker is supported by the host, we can continue | |||||
| fWorkerUISignal = 1; | |||||
| const char* const msg((const char*)(event + 1)); | |||||
| const size_t msgSize = std::strlen(msg); | |||||
| fWorker->schedule_work(fWorker->handle, msgSize+1, msg); | |||||
| } | |||||
| else | |||||
| { | |||||
| // worker is not supported, cancel | |||||
| fWorkerUISignal = -1; | |||||
| } | |||||
| continue; | |||||
| } | |||||
| if (event->body.type != fURIs.midiEvent) | if (event->body.type != fURIs.midiEvent) | ||||
| continue; | continue; | ||||
| if (event->body.size > 4) | if (event->body.size > 4) | ||||
| @@ -230,6 +251,31 @@ public: | |||||
| const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | const_cast<float**>(fPorts.audioIns), fPorts.audioOuts, frames, | ||||
| fMidiEvents, fMidiEventCount); | fMidiEvents, fMidiEventCount); | ||||
| if (fWorkerUISignal == -1 && fPorts.hasUI) | |||||
| { | |||||
| const char* const msg = "quit"; | |||||
| const size_t msgSize = 5; | |||||
| LV2_Atom_Sequence* const seq(fPorts.eventsOut[0]); | |||||
| Ports::EventsOutData& mData(fPorts.eventsOutData[0]); | |||||
| if (sizeof(LV2_Atom_Event) + msgSize <= mData.capacity - mData.offset) | |||||
| { | |||||
| LV2_Atom_Event* const aev = (LV2_Atom_Event*)(LV2_ATOM_CONTENTS(LV2_Atom_Sequence, seq) + mData.offset); | |||||
| aev->time.frames = 0; | |||||
| aev->body.size = msgSize; | |||||
| aev->body.type = fURIs.uiEvents; | |||||
| std::memcpy(LV2_ATOM_BODY(&aev->body), msg, msgSize); | |||||
| const uint32_t size = lv2_atom_pad_size(static_cast<uint32_t>(sizeof(LV2_Atom_Event) + msgSize)); | |||||
| mData.offset += size; | |||||
| seq->atom.size += size; | |||||
| fWorkerUISignal = 0; | |||||
| } | |||||
| } | |||||
| lv2_post_run(frames); | lv2_post_run(frames); | ||||
| updateParameterOutputs(); | updateParameterOutputs(); | ||||
| } | } | ||||
| @@ -321,6 +367,42 @@ public: | |||||
| // ---------------------------------------------------------------------------------------------------------------- | // ---------------------------------------------------------------------------------------------------------------- | ||||
| LV2_Worker_Status lv2_work(LV2_Worker_Respond_Function, LV2_Worker_Respond_Handle, uint32_t, const void* data) | |||||
| { | |||||
| const char* const msg = (const char*)data; | |||||
| /**/ if (std::strcmp(msg, "show") == 0) | |||||
| { | |||||
| handleUiShow(); | |||||
| } | |||||
| else if (std::strcmp(msg, "hide") == 0) | |||||
| { | |||||
| handleUiHide(); | |||||
| } | |||||
| else if (std::strcmp(msg, "idle") == 0) | |||||
| { | |||||
| handleUiRun(); | |||||
| } | |||||
| else if (std::strcmp(msg, "quit") == 0) | |||||
| { | |||||
| handleUiRun(); | |||||
| } | |||||
| else | |||||
| { | |||||
| carla_stdout("lv2_work unknown msg '%s'", msg); | |||||
| return LV2_WORKER_ERR_UNKNOWN; | |||||
| } | |||||
| return LV2_WORKER_SUCCESS; | |||||
| } | |||||
| LV2_Worker_Status lv2_work_resp(uint32_t /*size*/, const void* /*body*/) | |||||
| { | |||||
| return LV2_WORKER_SUCCESS; | |||||
| } | |||||
| // ---------------------------------------------------------------------------------------------------------------- | |||||
| void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | ||||
| LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | ||||
| { | { | ||||
| @@ -334,7 +416,7 @@ public: | |||||
| fHost.uiName = nullptr; | fHost.uiName = nullptr; | ||||
| } | } | ||||
| #ifdef CARLA_OS_LINUX | |||||
| #if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| // --------------------------------------------------------------- | // --------------------------------------------------------------- | ||||
| // show embed UI if needed | // show embed UI if needed | ||||
| @@ -437,6 +519,10 @@ public: | |||||
| fHost.uiName = carla_strdup(fDescriptor->name); | fHost.uiName = carla_strdup(fDescriptor->name); | ||||
| *widget = nullptr; | *widget = nullptr; | ||||
| return; | |||||
| // maybe be unused | |||||
| (void)isEmbed; | |||||
| } | } | ||||
| void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const | void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const | ||||
| @@ -523,10 +609,10 @@ protected: | |||||
| const uint8_t port(event->port); | const uint8_t port(event->port); | ||||
| CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false); | CARLA_SAFE_ASSERT_RETURN(port < fPorts.numMidiOuts, false); | ||||
| LV2_Atom_Sequence* const seq(fPorts.midiOuts[port]); | |||||
| LV2_Atom_Sequence* const seq(fPorts.eventsOut[port]); | |||||
| CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | CARLA_SAFE_ASSERT_RETURN(seq != nullptr, false); | ||||
| Ports::MidiOutData& mData(fPorts.midiOutData[port]); | |||||
| Ports::EventsOutData& mData(fPorts.eventsOutData[port]); | |||||
| if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) | if (sizeof(LV2_Atom_Event) + event->size > mData.capacity - mData.offset) | ||||
| return false; | return false; | ||||
| @@ -547,8 +633,11 @@ protected: | |||||
| void handleUiParameterChanged(const uint32_t index, const float value) const | void handleUiParameterChanged(const uint32_t index, const float value) const | ||||
| { | { | ||||
| if (fUI.writeFunction != nullptr && fUI.controller != nullptr) | |||||
| fUI.writeFunction(fUI.controller, index+fPorts.indexOffset, sizeof(float), 0, &value); | |||||
| if (fWorkerUISignal) | |||||
| { | |||||
| } | |||||
| else if (fUI.writeFunction != nullptr && fUI.controller != nullptr) | |||||
| fUI.writeFunction(fUI.controller, index+fPorts.indexOffset, sizeof(float), 0, &value); | |||||
| } | } | ||||
| void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const | void handleUiCustomDataChanged(const char* const /*key*/, const char* const /*value*/) const | ||||
| @@ -558,13 +647,17 @@ protected: | |||||
| void handleUiClosed() | void handleUiClosed() | ||||
| { | { | ||||
| fUI.isVisible = false; | |||||
| if (fWorkerUISignal) | |||||
| fWorkerUISignal = -1; | |||||
| if (fUI.host != nullptr && fUI.host->ui_closed != nullptr && fUI.controller != nullptr) | if (fUI.host != nullptr && fUI.host->ui_closed != nullptr && fUI.controller != nullptr) | ||||
| fUI.host->ui_closed(fUI.controller); | fUI.host->ui_closed(fUI.controller); | ||||
| fUI.host = nullptr; | fUI.host = nullptr; | ||||
| fUI.writeFunction = nullptr; | fUI.writeFunction = nullptr; | ||||
| fUI.controller = nullptr; | fUI.controller = nullptr; | ||||
| fUI.isVisible = false; | |||||
| } | } | ||||
| const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const | const char* handleUiOpenFile(const bool /*isDir*/, const char* const /*title*/, const char* const /*filter*/) const | ||||
| @@ -639,6 +732,8 @@ private: | |||||
| uint32_t fMidiEventCount; | uint32_t fMidiEventCount; | ||||
| NativeMidiEvent fMidiEvents[kMaxMidiEvents]; | NativeMidiEvent fMidiEvents[kMaxMidiEvents]; | ||||
| int fWorkerUISignal; | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| #define handlePtr ((NativePlugin*)handle) | #define handlePtr ((NativePlugin*)handle) | ||||
| @@ -823,6 +918,18 @@ static LV2_State_Status lv2_restore(LV2_Handle instance, LV2_State_Retrieve_Func | |||||
| return instancePtr->lv2_restore(retrieve, handle, flags, features); | return instancePtr->lv2_restore(retrieve, handle, flags, features); | ||||
| } | } | ||||
| static LV2_Worker_Status lv2_work(LV2_Handle instance, LV2_Worker_Respond_Function respond, LV2_Worker_Respond_Handle handle, uint32_t size, const void* data) | |||||
| { | |||||
| carla_debug("work(%p, %p, %p, %u, %p)", instance, respond, handle, size, data); | |||||
| return instancePtr->lv2_work(respond, handle, size, data); | |||||
| } | |||||
| LV2_Worker_Status lv2_work_resp(LV2_Handle instance, uint32_t size, const void* body) | |||||
| { | |||||
| carla_debug("work_resp(%p, %u, %p)", instance, size, body); | |||||
| return instancePtr->lv2_work_resp(size, body); | |||||
| } | |||||
| static const void* lv2_extension_data(const char* uri) | static const void* lv2_extension_data(const char* uri) | ||||
| { | { | ||||
| carla_debug("lv2_extension_data(\"%s\")", uri); | carla_debug("lv2_extension_data(\"%s\")", uri); | ||||
| @@ -830,6 +937,7 @@ static const void* lv2_extension_data(const char* uri) | |||||
| static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; | static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options }; | ||||
| static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program }; | static const LV2_Programs_Interface programs = { lv2_get_program, lv2_select_program }; | ||||
| static const LV2_State_Interface state = { lv2_save, lv2_restore }; | static const LV2_State_Interface state = { lv2_save, lv2_restore }; | ||||
| static const LV2_Worker_Interface worker = { lv2_work, lv2_work_resp, nullptr }; | |||||
| if (std::strcmp(uri, LV2_OPTIONS__interface) == 0) | if (std::strcmp(uri, LV2_OPTIONS__interface) == 0) | ||||
| return &options; | return &options; | ||||
| @@ -837,12 +945,15 @@ static const void* lv2_extension_data(const char* uri) | |||||
| return &programs; | return &programs; | ||||
| if (std::strcmp(uri, LV2_STATE__interface) == 0) | if (std::strcmp(uri, LV2_STATE__interface) == 0) | ||||
| return &state; | return &state; | ||||
| if (std::strcmp(uri, LV2_WORKER__interface) == 0) | |||||
| return &worker; | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| #undef instancePtr | #undef instancePtr | ||||
| #ifdef HAVE_PYQT | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // LV2 UI descriptor functions | // LV2 UI descriptor functions | ||||
| @@ -850,9 +961,9 @@ static LV2UI_Handle lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_ | |||||
| LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | LV2UI_Widget* widget, const LV2_Feature* const* features, const bool isEmbed) | ||||
| { | { | ||||
| carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features); | ||||
| #ifndef CARLA_OS_LINUX | |||||
| # if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| CARLA_SAFE_ASSERT_RETURN(! isEmbed, nullptr); | CARLA_SAFE_ASSERT_RETURN(! isEmbed, nullptr); | ||||
| #endif | |||||
| # endif | |||||
| NativePlugin* plugin = nullptr; | NativePlugin* plugin = nullptr; | ||||
| @@ -876,14 +987,14 @@ static LV2UI_Handle lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_ | |||||
| return (LV2UI_Handle)plugin; | return (LV2UI_Handle)plugin; | ||||
| } | } | ||||
| #ifdef CARLA_OS_LINUX | |||||
| # if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| static LV2UI_Handle lv2ui_instantiate_embed(const LV2UI_Descriptor*, const char*, const char*, | static LV2UI_Handle lv2ui_instantiate_embed(const LV2UI_Descriptor*, const char*, const char*, | ||||
| LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | ||||
| LV2UI_Widget* widget, const LV2_Feature* const* features) | LV2UI_Widget* widget, const LV2_Feature* const* features) | ||||
| { | { | ||||
| return lv2ui_instantiate(writeFunction, controller, widget, features, true); | return lv2ui_instantiate(writeFunction, controller, widget, features, true); | ||||
| } | } | ||||
| #endif | |||||
| # endif | |||||
| static LV2UI_Handle lv2ui_instantiate_external(const LV2UI_Descriptor*, const char*, const char*, | static LV2UI_Handle lv2ui_instantiate_external(const LV2UI_Descriptor*, const char*, const char*, | ||||
| LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | LV2UI_Write_Function writeFunction, LV2UI_Controller controller, | ||||
| @@ -896,7 +1007,7 @@ static LV2UI_Handle lv2ui_instantiate_external(const LV2UI_Descriptor*, const ch | |||||
| static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) | ||||
| { | { | ||||
| carla_debug("lv2ui_port_event(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer); | |||||
| carla_debug("lv2ui_port_eventxx(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer); | |||||
| uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | ||||
| } | } | ||||
| @@ -946,6 +1057,7 @@ static const void* lv2ui_extension_data(const char* uri) | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| #endif | |||||
| #undef uiPtr | #undef uiPtr | ||||
| @@ -1002,12 +1114,13 @@ const LV2_Descriptor* lv2_descriptor(uint32_t index) | |||||
| return lv2Desc; | return lv2Desc; | ||||
| } | } | ||||
| #ifdef HAVE_PYQT | |||||
| CARLA_EXPORT | CARLA_EXPORT | ||||
| const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | ||||
| { | { | ||||
| carla_debug("lv2ui_descriptor(%i)", index); | carla_debug("lv2ui_descriptor(%i)", index); | ||||
| #ifdef CARLA_OS_LINUX | |||||
| #if defined(CARLA_OS_LINUX) && defined(HAVE_X11) | |||||
| static const LV2UI_Descriptor lv2UiEmbedDesc = { | static const LV2UI_Descriptor lv2UiEmbedDesc = { | ||||
| /* URI */ "http://kxstudio.sf.net/carla/ui-embed", | /* URI */ "http://kxstudio.sf.net/carla/ui-embed", | ||||
| /* instantiate */ lv2ui_instantiate_embed, | /* instantiate */ lv2ui_instantiate_embed, | ||||
| @@ -1032,5 +1145,6 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||||
| return (index == 0) ? &lv2UiExtDesc : nullptr; | return (index == 0) ? &lv2UiExtDesc : nullptr; | ||||
| } | } | ||||
| #endif | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -0,0 +1,63 @@ | |||||
| #!/usr/bin/make -f | |||||
| # Makefile for carla-interposer # | |||||
| # ----------------------------- # | |||||
| # Created by falkTX | |||||
| # | |||||
| CWD=.. | |||||
| include $(CWD)/Makefile.mk | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| BINDIR := $(CWD)/../bin | |||||
| ifeq ($(DEBUG),true) | |||||
| OBJDIR := $(CWD)/../build/interposer/Debug | |||||
| MODULEDIR := $(CWD)/../build/modules/Debug | |||||
| else | |||||
| OBJDIR := $(CWD)/../build/interposer/Release | |||||
| MODULEDIR := $(CWD)/../build/modules/Release | |||||
| endif | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| BUILD_CXX_FLAGS += -I$(CWD) -I$(CWD)/backend -I$(CWD)/includes -I$(CWD)/modules -I$(CWD)/utils | |||||
| LINK_FLAGS += -L$(BINDIR) -lcarla_standalone2 -lcarla_utils -lrestbed -lpthread -Wl,-rpath=$(shell realpath $(CWD)/../bin) | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| OBJS = $(OBJDIR)/rest-server.cpp.o $(OBJDIR)/buffers.cpp.o | |||||
| TARGETS = $(BINDIR)/carla-rest-server | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| all: $(TARGETS) | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| clean: | |||||
| rm -f $(OBJDIR)/*.o $(TARGETS) | |||||
| debug: | |||||
| $(MAKE) DEBUG=true | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| $(BINDIR)/carla-rest-server: $(OBJS) | |||||
| -@mkdir -p $(BINDIR) | |||||
| @echo "Linking carla-rest-server" | |||||
| @$(CXX) $^ $(LINK_FLAGS) -o $@ | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| $(OBJDIR)/%.cpp.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| -include $(OBJS:%.o=%.d) | |||||
| # ---------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,312 @@ | |||||
| /* | |||||
| * Carla REST API Server | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "buffers.hpp" | |||||
| #include "CarlaMathUtils.hpp" | |||||
| #include <cstdio> | |||||
| #include <cstring> | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| enum { | |||||
| kJsonBufSize = 4095, | |||||
| kStrBufSize = 1023, | |||||
| kSizeBufSize = 31, | |||||
| }; | |||||
| // static buffer to return json | |||||
| // NOTE size is never checked for json, the buffer is big enough in order to assume it all always fits | |||||
| static char jsonBuf[kJsonBufSize+1]; | |||||
| // static buffer to return size | |||||
| static char sizeBuf[kSizeBufSize+1]; | |||||
| // static buffer to return regular strings | |||||
| static char strBuf[kStrBufSize+1]; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* size_buf(const char* const buf) | |||||
| { | |||||
| const std::size_t size = std::strlen(buf); | |||||
| std::snprintf(sizeBuf, kSizeBufSize, P_SIZE, size); | |||||
| sizeBuf[kSizeBufSize] = '\0'; | |||||
| return sizeBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* str_buf_bool(const bool value) | |||||
| { | |||||
| strBuf[0] = value ? '1' : '0'; | |||||
| strBuf[1] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* str_buf_float(const double value) | |||||
| { | |||||
| std::snprintf(strBuf, kStrBufSize, "%f", value); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_float_array(const double* const values, const char sep) | |||||
| { | |||||
| std::size_t bytesRead = 0; | |||||
| char tmpBuf[32]; | |||||
| for (int i=0; carla_isNotZero(values[i]) && bytesRead < kStrBufSize; ++i) | |||||
| { | |||||
| std::snprintf(tmpBuf, 31, "%f", values[i]); | |||||
| tmpBuf[31] = '\0'; | |||||
| const std::size_t size = std::strlen(tmpBuf); | |||||
| if (bytesRead + size > kStrBufSize) | |||||
| break; | |||||
| std::strncpy(strBuf+bytesRead, tmpBuf, kStrBufSize - bytesRead); | |||||
| bytesRead += size; | |||||
| strBuf[bytesRead] = sep; | |||||
| bytesRead += 1; | |||||
| } | |||||
| strBuf[bytesRead > 0 ? bytesRead-1 : 0] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* str_buf_string(const char* const string) | |||||
| { | |||||
| std::strncpy(strBuf, string, kStrBufSize); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_string_array(const char* const* const array) | |||||
| { | |||||
| std::size_t bytesRead = 0; | |||||
| for (int i=0; array[i] != nullptr && bytesRead < kStrBufSize; ++i) | |||||
| { | |||||
| const std::size_t size = std::strlen(array[i]); | |||||
| if (bytesRead + size > kStrBufSize) | |||||
| break; | |||||
| std::strncpy(strBuf+bytesRead, array[i], kStrBufSize - bytesRead); | |||||
| bytesRead += size; | |||||
| strBuf[bytesRead] = '\n'; | |||||
| bytesRead += 1; | |||||
| } | |||||
| strBuf[bytesRead > 0 ? bytesRead-1 : 0] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_string_quoted(const char* const string) | |||||
| { | |||||
| const std::size_t size = std::strlen(string); | |||||
| char* strBufPtr = strBuf; | |||||
| *strBufPtr++ = '"'; | |||||
| for (std::size_t i=0, bytesWritten=0; i < size && bytesWritten < kStrBufSize-1; ++i) | |||||
| { | |||||
| switch (string[i]) | |||||
| { | |||||
| case '"': | |||||
| case '\\': | |||||
| *strBufPtr++ = '\\'; | |||||
| ++bytesWritten; | |||||
| break; | |||||
| case '\n': | |||||
| *strBufPtr++ = '\\'; | |||||
| *strBufPtr++ = 'n';; | |||||
| bytesWritten += 2; | |||||
| continue; | |||||
| case '\f': | |||||
| *strBufPtr++ = '\\'; | |||||
| *strBufPtr++ = 'f';; | |||||
| bytesWritten += 2; | |||||
| continue; | |||||
| } | |||||
| *strBufPtr++ = string[i]; | |||||
| ++bytesWritten; | |||||
| } | |||||
| *strBufPtr++ = '"'; | |||||
| *strBufPtr++ = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| const char* str_buf_int(const int value) | |||||
| { | |||||
| std::snprintf(strBuf, kStrBufSize, "%i", value); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_int64(const int64_t value) | |||||
| { | |||||
| std::snprintf(strBuf, kStrBufSize, P_INT64, value); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_uint(const uint value) | |||||
| { | |||||
| std::snprintf(strBuf, kStrBufSize, "%u", value); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_uint64(const uint64_t value) | |||||
| { | |||||
| std::snprintf(strBuf, kStrBufSize, P_UINT64, value); | |||||
| strBuf[kStrBufSize] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| const char* str_buf_uint_array(const uint* const values, const char sep) | |||||
| { | |||||
| std::size_t bytesRead = 0; | |||||
| char tmpBuf[32]; | |||||
| for (int i=0; values[i] != 0 && bytesRead < kStrBufSize; ++i) | |||||
| { | |||||
| std::snprintf(tmpBuf, 31, "%u", values[i]); | |||||
| tmpBuf[31] = '\0'; | |||||
| const std::size_t size = std::strlen(tmpBuf); | |||||
| if (bytesRead + size > kStrBufSize) | |||||
| break; | |||||
| std::strncpy(strBuf+bytesRead, tmpBuf, kStrBufSize - bytesRead); | |||||
| bytesRead += size; | |||||
| strBuf[bytesRead] = sep; | |||||
| bytesRead += 1; | |||||
| } | |||||
| strBuf[bytesRead > 0 ? bytesRead-1 : 0] = '\0'; | |||||
| return strBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| char* json_buf_start() | |||||
| { | |||||
| std::strcpy(jsonBuf, "{"); | |||||
| return jsonBuf + 1; | |||||
| } | |||||
| char* json_buf_add(char* jsonBufPtr, const char* const key, const char* const valueBuf) | |||||
| { | |||||
| if (jsonBufPtr != jsonBuf+1) | |||||
| *jsonBufPtr++ = ','; | |||||
| *jsonBufPtr++ = '"'; | |||||
| std::strcpy(jsonBufPtr, key); | |||||
| jsonBufPtr += std::strlen(key); | |||||
| *jsonBufPtr++ = '"'; | |||||
| *jsonBufPtr++ = ':'; | |||||
| std::strcpy(jsonBufPtr, valueBuf); | |||||
| jsonBufPtr += std::strlen(valueBuf); | |||||
| return jsonBufPtr; | |||||
| } | |||||
| template <typename T, typename Fn> | |||||
| char* json_buf_add_fn(char* jsonBufPtr, const char* const key, const T value, const Fn fn) | |||||
| { | |||||
| return json_buf_add(jsonBufPtr, key, fn(value)); | |||||
| } | |||||
| template <typename T, typename Fn> | |||||
| char* json_buf_add_fn_array(char* jsonBufPtr, const char* const key, const T value, const Fn fn) | |||||
| { | |||||
| return json_buf_add(jsonBufPtr, key, fn(value, ',')); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| char* json_buf_add_bool(char* jsonBufPtr, const char* const key, const bool value) | |||||
| { | |||||
| static const char* const kTrue = "true"; | |||||
| static const char* const kFalse = "false"; | |||||
| return json_buf_add_fn(jsonBufPtr, key, value ? kTrue : kFalse, str_buf_string); | |||||
| } | |||||
| char* json_buf_add_float(char* jsonBufPtr, const char* const key, const double value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_float); | |||||
| } | |||||
| char* json_buf_add_float_array(char* jsonBufPtr, const char* const key, const double* const values) | |||||
| { | |||||
| return json_buf_add_fn_array(jsonBufPtr, key, values, str_buf_float_array); | |||||
| } | |||||
| char* json_buf_add_string(char* jsonBufPtr, const char* const key, const char* const value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_string_quoted); | |||||
| } | |||||
| char* json_buf_add_int(char* jsonBufPtr, const char* const key, const int value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_int); | |||||
| } | |||||
| char* json_buf_add_int64(char* jsonBufPtr, const char* const key, const int64_t value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_int64); | |||||
| } | |||||
| char* json_buf_add_uint(char* jsonBufPtr, const char* const key, const uint value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_uint); | |||||
| } | |||||
| char* json_buf_add_uint_array(char* jsonBufPtr, const char* const key, const uint* const values) | |||||
| { | |||||
| return json_buf_add_fn_array(jsonBufPtr, key, values, str_buf_uint_array); | |||||
| } | |||||
| char* json_buf_add_uint64(char* jsonBufPtr, const char* const key, const uint64_t value) | |||||
| { | |||||
| return json_buf_add_fn(jsonBufPtr, key, value, str_buf_uint64); | |||||
| } | |||||
| const char* json_buf_end(char* jsonBufPtr) | |||||
| { | |||||
| *jsonBufPtr++ = '}'; | |||||
| *jsonBufPtr++ = '\0'; | |||||
| return jsonBuf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,58 @@ | |||||
| /* | |||||
| * Carla REST API Server | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #ifndef REST_BUFFERS_HPP_INCLUDED | |||||
| #define REST_BUFFERS_HPP_INCLUDED | |||||
| #include "CarlaDefines.h" | |||||
| #ifdef CARLA_PROPER_CPP11_SUPPORT | |||||
| # include <cstdint> | |||||
| #else | |||||
| # include <stdint.h> | |||||
| #endif | |||||
| // size buf | |||||
| const char* size_buf(const char* const buf); | |||||
| // base types | |||||
| const char* str_buf_bool(const bool value); | |||||
| const char* str_buf_float(const double value); | |||||
| const char* str_buf_float_array(const double* const values, const char sep = '\n'); | |||||
| const char* str_buf_string(const char* const string); | |||||
| const char* str_buf_string_array(const char* const* const array); | |||||
| const char* str_buf_string_quoted(const char* const string); | |||||
| const char* str_buf_int(const int value); | |||||
| const char* str_buf_int64(const int64_t value); | |||||
| const char* str_buf_uint(const uint value); | |||||
| const char* str_buf_uint64(const uint64_t value); | |||||
| const char* str_buf_uint_array(const uint* const values, const char sep = '\n'); | |||||
| // json | |||||
| char* json_buf_start(); | |||||
| char* json_buf_add_bool(char* jsonBufPtr, const char* const key, const bool value); | |||||
| char* json_buf_add_float(char* jsonBufPtr, const char* const key, const double value); | |||||
| char* json_buf_add_float_array(char* jsonBufPtr, const char* const key, const double* const values); | |||||
| char* json_buf_add_string(char* jsonBufPtr, const char* const key, const char* const value); | |||||
| char* json_buf_add_int(char* jsonBufPtr, const char* const key, const int value); | |||||
| char* json_buf_add_int64(char* jsonBufPtr, const char* const key, const int64_t value); | |||||
| char* json_buf_add_uint(char* jsonBufPtr, const char* const key, const uint value); | |||||
| char* json_buf_add_uint64(char* jsonBufPtr, const char* const key, const uint64_t value); | |||||
| char* json_buf_add_uint_array(char* jsonBufPtr, const char* const key, const uint* const values); | |||||
| const char* json_buf_end(char* jsonBufPtr); | |||||
| #endif // REST_BUFFERS_HPP_INCLUDED | |||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * Carla REST API Server | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #include "common.hpp" | |||||
| #include "CarlaUtils.h" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void handle_carla_get_complete_license_text(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const char* const buf = str_buf_string(carla_get_complete_license_text()); | |||||
| session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||||
| } | |||||
| void handle_carla_get_supported_file_extensions(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const char* const buf = str_buf_string_array(carla_get_supported_file_extensions()); | |||||
| session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||||
| } | |||||
| void handle_carla_get_supported_features(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const char* const buf = str_buf_string_array(carla_get_supported_features()); | |||||
| session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||||
| } | |||||
| void handle_carla_get_cached_plugin_count(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const std::shared_ptr<const Request> request = session->get_request(); | |||||
| const int ptype = std::atoi(request->get_query_parameter("ptype").c_str()); | |||||
| CARLA_SAFE_ASSERT_RETURN(ptype >= PLUGIN_NONE && ptype <= PLUGIN_JACK,) | |||||
| const std::string pluginPath = request->get_query_parameter("pluginPath"); | |||||
| const char* const buf = str_buf_uint(carla_get_cached_plugin_count(static_cast<PluginType>(ptype), | |||||
| pluginPath.c_str())); | |||||
| session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||||
| } | |||||
| void handle_carla_get_cached_plugin_info(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const std::shared_ptr<const Request> request = session->get_request(); | |||||
| const int ptype = std::atoi(request->get_query_parameter("ptype").c_str()); | |||||
| CARLA_SAFE_ASSERT_RETURN(ptype >= PLUGIN_NONE && ptype <= PLUGIN_JACK,) | |||||
| const int index = std::atoi(request->get_query_parameter("index").c_str()); | |||||
| CARLA_SAFE_ASSERT_RETURN(index >= 0 /*&& index < INT_MAX*/,) | |||||
| const CarlaCachedPluginInfo* const info = carla_get_cached_plugin_info(static_cast<PluginType>(ptype), | |||||
| static_cast<uint>(index)); | |||||
| char* jsonBuf; | |||||
| jsonBuf = json_buf_start(); | |||||
| jsonBuf = json_buf_add_bool(jsonBuf, "valid", info->valid); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "category", info->category); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "hints", info->hints); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "audioIns", info->audioIns); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "audioOuts", info->audioOuts); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "midiIns", info->midiIns); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "midiOuts", info->midiOuts); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "parameterIns", info->parameterIns); | |||||
| jsonBuf = json_buf_add_uint(jsonBuf, "parameterOuts", info->parameterOuts); | |||||
| jsonBuf = json_buf_add_string(jsonBuf, "name", info->name); | |||||
| jsonBuf = json_buf_add_string(jsonBuf, "label", info->label); | |||||
| jsonBuf = json_buf_add_string(jsonBuf, "maker", info->maker); | |||||
| jsonBuf = json_buf_add_string(jsonBuf, "copyright", info->copyright); | |||||
| const char* const buf = json_buf_end(jsonBuf); | |||||
| session->close(OK, buf, { { "Content-Length", size_buf(buf) } } ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -0,0 +1,40 @@ | |||||
| /* | |||||
| * Carla REST API Server | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #ifndef REST_COMMON_HPP_INCLUDED | |||||
| #define REST_COMMON_HPP_INCLUDED | |||||
| #include "buffers.hpp" | |||||
| #include "CarlaBackend.h" | |||||
| #include "CarlaUtils.hpp" | |||||
| #include <restbed> | |||||
| using restbed::Request; | |||||
| using restbed::Resource; | |||||
| using restbed::Service; | |||||
| using restbed::Session; | |||||
| using restbed::Settings; | |||||
| using restbed::BAD_REQUEST; | |||||
| using restbed::OK; | |||||
| CARLA_BACKEND_USE_NAMESPACE; | |||||
| void send_server_side_message(const char* const message); | |||||
| #endif // REST_COMMON_HPP_INCLUDED | |||||
| @@ -0,0 +1,247 @@ | |||||
| /* | |||||
| * Carla REST API Server | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| /* NOTE | |||||
| * Even though Carla is GPL, restbed if AGPL. | |||||
| * As such, the resulting binary will be AGPL. | |||||
| * Take this into consideration before deploying it to any servers. | |||||
| */ | |||||
| #include "common.hpp" | |||||
| #include "carla-host.cpp" | |||||
| #include "carla-utils.cpp" | |||||
| #include "CarlaMutex.hpp" | |||||
| #include "CarlaStringList.hpp" | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| std::vector<std::shared_ptr<Session>> gSessions; | |||||
| CarlaStringList gSessionMessages; | |||||
| CarlaMutex gSessionMessagesMutex; | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| void send_server_side_message(const char* const message) | |||||
| { | |||||
| const CarlaMutexLocker cml(gSessionMessagesMutex); | |||||
| gSessionMessages.append(message); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| static void register_server_side_handler(const std::shared_ptr<Session> session) | |||||
| { | |||||
| const auto headers = std::multimap<std::string, std::string> { | |||||
| { "Connection", "keep-alive" }, | |||||
| { "Cache-Control", "no-cache" }, | |||||
| { "Content-Type", "text/event-stream" }, | |||||
| { "Access-Control-Allow-Origin", "*" } //Only required for demo purposes. | |||||
| }; | |||||
| session->yield(OK, headers, [](const std::shared_ptr<Session> rsession) { | |||||
| gSessions.push_back(rsession); | |||||
| }); | |||||
| } | |||||
| static void event_stream_handler(void) | |||||
| { | |||||
| static bool firstInit = true; | |||||
| if (firstInit) | |||||
| { | |||||
| firstInit = false; | |||||
| carla_stdout("Carla REST-API Server started"); | |||||
| } | |||||
| gSessions.erase( | |||||
| std::remove_if(gSessions.begin(), gSessions.end(), | |||||
| [](const std::shared_ptr<Session> &a) { | |||||
| return a->is_closed(); | |||||
| }), | |||||
| gSessions.end()); | |||||
| CarlaStringList messages; | |||||
| { | |||||
| const CarlaMutexLocker cml(gSessionMessagesMutex); | |||||
| if (gSessionMessages.count() > 0) | |||||
| gSessionMessages.moveTo(messages); | |||||
| } | |||||
| for (auto message : messages) | |||||
| { | |||||
| // std::puts(message); | |||||
| for (auto session : gSessions) | |||||
| session->yield(OK, message); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| static void make_resource(Service& service, | |||||
| const char* const path, | |||||
| const std::function<void (const std::shared_ptr<Session>)>& callback) | |||||
| { | |||||
| std::shared_ptr<Resource> resource = std::make_shared<Resource>(); | |||||
| resource->set_path(path); | |||||
| resource->set_method_handler("GET", callback); | |||||
| service.publish(resource); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| int main(int, const char**) | |||||
| { | |||||
| Service service; | |||||
| // server-side messages | |||||
| { | |||||
| std::shared_ptr<Resource> resource = std::make_shared<Resource>(); | |||||
| resource->set_path("/stream"); | |||||
| resource->set_method_handler("GET", register_server_side_handler); | |||||
| service.publish(resource); | |||||
| } | |||||
| // carla-host | |||||
| make_resource(service, "/get_engine_driver_count", handle_carla_get_engine_driver_count); | |||||
| make_resource(service, "/get_engine_driver_name", handle_carla_get_engine_driver_name); | |||||
| make_resource(service, "/get_engine_driver_device_names", handle_carla_get_engine_driver_device_names); | |||||
| make_resource(service, "/get_engine_driver_device_info", handle_carla_get_engine_driver_device_info); | |||||
| make_resource(service, "/engine_init", handle_carla_engine_init); | |||||
| make_resource(service, "/engine_close", handle_carla_engine_close); | |||||
| make_resource(service, "/is_engine_running", handle_carla_is_engine_running); | |||||
| make_resource(service, "/set_engine_about_to_close", handle_carla_set_engine_about_to_close); | |||||
| make_resource(service, "/set_engine_option", handle_carla_set_engine_option); | |||||
| make_resource(service, "/load_file", handle_carla_load_file); | |||||
| make_resource(service, "/load_project", handle_carla_load_project); | |||||
| make_resource(service, "/save_project", handle_carla_save_project); | |||||
| make_resource(service, "/patchbay_connect", handle_carla_patchbay_connect); | |||||
| make_resource(service, "/patchbay_disconnect", handle_carla_patchbay_disconnect); | |||||
| make_resource(service, "/patchbay_refresh", handle_carla_patchbay_refresh); | |||||
| make_resource(service, "/transport_play", handle_carla_transport_play); | |||||
| make_resource(service, "/transport_pause", handle_carla_transport_pause); | |||||
| make_resource(service, "/transport_bpm", handle_carla_transport_bpm); | |||||
| make_resource(service, "/transport_relocate", handle_carla_transport_relocate); | |||||
| make_resource(service, "/get_current_transport_frame", handle_carla_get_current_transport_frame); | |||||
| make_resource(service, "/get_transport_info", handle_carla_get_transport_info); | |||||
| make_resource(service, "/get_current_plugin_count", handle_carla_get_current_plugin_count); | |||||
| make_resource(service, "/get_max_plugin_number", handle_carla_get_max_plugin_number); | |||||
| make_resource(service, "/add_plugin", handle_carla_add_plugin); | |||||
| make_resource(service, "/remove_plugin", handle_carla_remove_plugin); | |||||
| make_resource(service, "/remove_all_plugins", handle_carla_remove_all_plugins); | |||||
| make_resource(service, "/rename_plugin", handle_carla_rename_plugin); | |||||
| make_resource(service, "/clone_plugin", handle_carla_clone_plugin); | |||||
| make_resource(service, "/replace_plugin", handle_carla_replace_plugin); | |||||
| make_resource(service, "/switch_plugins", handle_carla_switch_plugins); | |||||
| make_resource(service, "/load_plugin_state", handle_carla_load_plugin_state); | |||||
| make_resource(service, "/save_plugin_state", handle_carla_save_plugin_state); | |||||
| make_resource(service, "/export_plugin_lv2", handle_carla_export_plugin_lv2); | |||||
| make_resource(service, "/get_plugin_info", handle_carla_get_plugin_info); | |||||
| make_resource(service, "/get_audio_port_count_info", handle_carla_get_audio_port_count_info); | |||||
| make_resource(service, "/get_midi_port_count_info", handle_carla_get_midi_port_count_info); | |||||
| make_resource(service, "/get_parameter_count_info", handle_carla_get_parameter_count_info); | |||||
| make_resource(service, "/get_parameter_info", handle_carla_get_parameter_info); | |||||
| make_resource(service, "/get_parameter_scalepoint_info", handle_carla_get_parameter_scalepoint_info); | |||||
| make_resource(service, "/get_parameter_data", handle_carla_get_parameter_data); | |||||
| make_resource(service, "/get_parameter_ranges", handle_carla_get_parameter_ranges); | |||||
| make_resource(service, "/get_midi_program_data", handle_carla_get_midi_program_data); | |||||
| make_resource(service, "/get_custom_data", handle_carla_get_custom_data); | |||||
| make_resource(service, "/get_custom_data_value", handle_carla_get_custom_data_value); | |||||
| make_resource(service, "/get_chunk_data", handle_carla_get_chunk_data); | |||||
| make_resource(service, "/get_parameter_count", handle_carla_get_parameter_count); | |||||
| make_resource(service, "/get_program_count", handle_carla_get_program_count); | |||||
| make_resource(service, "/get_midi_program_count", handle_carla_get_midi_program_count); | |||||
| make_resource(service, "/get_custom_data_count", handle_carla_get_custom_data_count); | |||||
| make_resource(service, "/get_parameter_text", handle_carla_get_parameter_text); | |||||
| make_resource(service, "/get_program_name", handle_carla_get_program_name); | |||||
| make_resource(service, "/get_midi_program_name", handle_carla_get_midi_program_name); | |||||
| make_resource(service, "/get_real_plugin_name", handle_carla_get_real_plugin_name); | |||||
| make_resource(service, "/get_current_program_index", handle_carla_get_current_program_index); | |||||
| make_resource(service, "/get_current_midi_program_index", handle_carla_get_current_midi_program_index); | |||||
| make_resource(service, "/get_default_parameter_value", handle_carla_get_default_parameter_value); | |||||
| make_resource(service, "/get_current_parameter_value", handle_carla_get_current_parameter_value); | |||||
| make_resource(service, "/get_internal_parameter_value", handle_carla_get_internal_parameter_value); | |||||
| make_resource(service, "/get_input_peak_value", handle_carla_get_input_peak_value); | |||||
| make_resource(service, "/get_output_peak_value", handle_carla_get_output_peak_value); | |||||
| make_resource(service, "/set_active", handle_carla_set_active); | |||||
| make_resource(service, "/set_drywet", handle_carla_set_drywet); | |||||
| make_resource(service, "/set_volume", handle_carla_set_volume); | |||||
| make_resource(service, "/set_balance_left", handle_carla_set_balance_left); | |||||
| make_resource(service, "/set_balance_right", handle_carla_set_balance_right); | |||||
| make_resource(service, "/set_panning", handle_carla_set_panning); | |||||
| make_resource(service, "/set_ctrl_channel", handle_carla_set_ctrl_channel); | |||||
| make_resource(service, "/set_option", handle_carla_set_option); | |||||
| make_resource(service, "/set_parameter_value", handle_carla_set_parameter_value); | |||||
| make_resource(service, "/set_parameter_midi_channel", handle_carla_set_parameter_midi_channel); | |||||
| make_resource(service, "/set_parameter_midi_cc", handle_carla_set_parameter_midi_cc); | |||||
| make_resource(service, "/set_program", handle_carla_set_program); | |||||
| make_resource(service, "/set_midi_program", handle_carla_set_midi_program); | |||||
| make_resource(service, "/set_custom_data", handle_carla_set_custom_data); | |||||
| make_resource(service, "/set_chunk_data", handle_carla_set_chunk_data); | |||||
| make_resource(service, "/prepare_for_save", handle_carla_prepare_for_save); | |||||
| make_resource(service, "/reset_parameters", handle_carla_reset_parameters); | |||||
| make_resource(service, "/randomize_parameters", handle_carla_randomize_parameters); | |||||
| make_resource(service, "/send_midi_note", handle_carla_send_midi_note); | |||||
| make_resource(service, "/get_buffer_size", handle_carla_get_buffer_size); | |||||
| make_resource(service, "/get_sample_rate", handle_carla_get_sample_rate); | |||||
| make_resource(service, "/get_last_error", handle_carla_get_last_error); | |||||
| make_resource(service, "/get_host_osc_url_tcp", handle_carla_get_host_osc_url_tcp); | |||||
| make_resource(service, "/get_host_osc_url_udp", handle_carla_get_host_osc_url_udp); | |||||
| // carla-utils | |||||
| make_resource(service, "/get_complete_license_text", handle_carla_get_complete_license_text); | |||||
| make_resource(service, "/get_supported_file_extensions", handle_carla_get_supported_file_extensions); | |||||
| make_resource(service, "/get_supported_features", handle_carla_get_supported_features); | |||||
| make_resource(service, "/get_cached_plugin_count", handle_carla_get_cached_plugin_count); | |||||
| make_resource(service, "/get_cached_plugin_info", handle_carla_get_cached_plugin_info); | |||||
| // schedule events | |||||
| service.schedule(engine_idle_handler); // FIXME, crashes on fast times, but we need ~30Hz for OSC.. | |||||
| service.schedule(event_stream_handler, std::chrono::milliseconds(500)); | |||||
| std::shared_ptr<Settings> settings = std::make_shared<Settings>(); | |||||
| settings->set_port(2228); | |||||
| settings->set_default_header("Connection", "close"); | |||||
| service.start(settings); | |||||
| return 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -163,7 +163,7 @@ const char* InternalParameterIndex2Str(const InternalParameterIndex index) noexc | |||||
| { | { | ||||
| case PARAMETER_NULL: | case PARAMETER_NULL: | ||||
| return "PARAMETER_NULL"; | return "PARAMETER_NULL"; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| case PARAMETER_ACTIVE: | case PARAMETER_ACTIVE: | ||||
| return "PARAMETER_ACTIVE"; | return "PARAMETER_ACTIVE"; | ||||
| case PARAMETER_DRYWET: | case PARAMETER_DRYWET: | ||||
| @@ -206,7 +206,7 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept | |||||
| return "ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED"; | return "ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED"; | ||||
| case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: | case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: | ||||
| return "ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED"; | return "ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED"; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| case ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: | case ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: | ||||
| return "ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED"; | return "ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED"; | ||||
| case ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: | case ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: | ||||
| @@ -234,7 +234,7 @@ const char* EngineCallbackOpcode2Str(const EngineCallbackOpcode opcode) noexcept | |||||
| return "ENGINE_CALLBACK_RELOAD_PROGRAMS"; | return "ENGINE_CALLBACK_RELOAD_PROGRAMS"; | ||||
| case ENGINE_CALLBACK_RELOAD_ALL: | case ENGINE_CALLBACK_RELOAD_ALL: | ||||
| return "ENGINE_CALLBACK_RELOAD_ALL"; | return "ENGINE_CALLBACK_RELOAD_ALL"; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| case ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED: | case ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED: | ||||
| return "ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED"; | return "ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED"; | ||||
| case ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED: | case ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED: | ||||
| @@ -325,7 +325,7 @@ const char* EngineOption2Str(const EngineOption option) noexcept | |||||
| return "ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR"; | return "ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR"; | ||||
| case ENGINE_OPTION_FRONTEND_WIN_ID: | case ENGINE_OPTION_FRONTEND_WIN_ID: | ||||
| return "ENGINE_OPTION_FRONTEND_WIN_ID"; | return "ENGINE_OPTION_FRONTEND_WIN_ID"; | ||||
| #ifndef CARLA_OS_WIN | |||||
| #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN) | |||||
| case ENGINE_OPTION_WINE_EXECUTABLE: | case ENGINE_OPTION_WINE_EXECUTABLE: | ||||
| return "ENGINE_OPTION_WINE_EXECUTABLE"; | return "ENGINE_OPTION_WINE_EXECUTABLE"; | ||||
| case ENGINE_OPTION_WINE_AUTO_PREFIX: | case ENGINE_OPTION_WINE_AUTO_PREFIX: | ||||
| @@ -25,6 +25,9 @@ | |||||
| #ifdef HAVE_LIBMAGIC | #ifdef HAVE_LIBMAGIC | ||||
| # include <magic.h> | # include <magic.h> | ||||
| # ifdef CARLA_OS_MAC | |||||
| # include "CarlaMacUtils.hpp" | |||||
| # endif | |||||
| #endif | #endif | ||||
| CARLA_BACKEND_START_NAMESPACE | CARLA_BACKEND_START_NAMESPACE | ||||
| @@ -95,6 +98,26 @@ BinaryType getBinaryTypeFromFile(const char* const filename) | |||||
| ? BINARY_POSIX64 | ? BINARY_POSIX64 | ||||
| : BINARY_POSIX32; | : BINARY_POSIX32; | ||||
| # ifdef CARLA_OS_MAC | |||||
| if (std::strcmp(output, "directory") == 0) | |||||
| if (const char* const binary = findBinaryInBundle(filename)) | |||||
| return getBinaryTypeFromFile(binary); | |||||
| if (std::strstr(output, "Mach-O universal binary") != nullptr) | |||||
| { | |||||
| // This is tricky, binary actually contains multiple architectures | |||||
| // We just assume what architectures are more important, and check for them first | |||||
| if (std::strstr(output, "x86_64") != nullptr) | |||||
| return BINARY_POSIX64; | |||||
| if (std::strstr(output, "i386")) | |||||
| return BINARY_POSIX32; | |||||
| if (std::strstr(output, "ppc")) | |||||
| return BINARY_OTHER; | |||||
| } | |||||
| carla_stdout("getBinaryTypeFromFile(\"%s\") - have output:\n%s", filename, output); | |||||
| # endif | |||||
| return BINARY_NATIVE; | return BINARY_NATIVE; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -134,12 +134,13 @@ struct BridgeSemaphore { | |||||
| }; | }; | ||||
| }; | }; | ||||
| // needs to be 64bit aligned | |||||
| // NOTE: needs to be 64bit aligned | |||||
| struct BridgeTimeInfo { | struct BridgeTimeInfo { | ||||
| uint64_t playing; | uint64_t playing; | ||||
| uint64_t frame; | uint64_t frame; | ||||
| uint64_t usecs; | uint64_t usecs; | ||||
| uint32_t validFlags; | uint32_t validFlags; | ||||
| uint32_t unused; | |||||
| // bbt | // bbt | ||||
| int32_t bar, beat; | int32_t bar, beat; | ||||
| float beatsPerBar, beatType; | float beatsPerBar, beatType; | ||||
| @@ -104,6 +104,9 @@ public: | |||||
| lib.filename = dfilename; | lib.filename = dfilename; | ||||
| lib.count = 1; | lib.count = 1; | ||||
| lib.canDelete = canDelete; | lib.canDelete = canDelete; | ||||
| #ifdef BUILD_BRIDGE | |||||
| lib.canDelete = true; | |||||
| #endif | |||||
| if (fLibs.append(lib)) | if (fLibs.append(lib)) | ||||
| return libPtr; | return libPtr; | ||||
| @@ -554,6 +554,7 @@ public: | |||||
| fBufferSize(0), | fBufferSize(0), | ||||
| fSampleRate(sampleRate), | fSampleRate(sampleRate), | ||||
| fUridMap(nullptr), | fUridMap(nullptr), | ||||
| fWorker(nullptr), | |||||
| fTimeInfo(), | fTimeInfo(), | ||||
| fLastPositionData(), | fLastPositionData(), | ||||
| fURIs(), | fURIs(), | ||||
| @@ -572,20 +573,23 @@ public: | |||||
| const LV2_Options_Option* options = nullptr; | const LV2_Options_Option* options = nullptr; | ||||
| const LV2_URID_Map* uridMap = nullptr; | const LV2_URID_Map* uridMap = nullptr; | ||||
| const LV2_URID_Unmap* uridUnmap = nullptr; | const LV2_URID_Unmap* uridUnmap = nullptr; | ||||
| const LV2_Worker_Schedule* worker = nullptr; | |||||
| for (int i=0; features[i] != nullptr; ++i) | for (int i=0; features[i] != nullptr; ++i) | ||||
| { | { | ||||
| if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0) | |||||
| /**/ if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0) | |||||
| options = (const LV2_Options_Option*)features[i]->data; | options = (const LV2_Options_Option*)features[i]->data; | ||||
| else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0) | else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0) | ||||
| uridMap = (const LV2_URID_Map*)features[i]->data; | uridMap = (const LV2_URID_Map*)features[i]->data; | ||||
| else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0) | else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0) | ||||
| uridUnmap = (const LV2_URID_Unmap*)features[i]->data; | uridUnmap = (const LV2_URID_Unmap*)features[i]->data; | ||||
| else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0) | |||||
| worker = (const LV2_Worker_Schedule*)features[i]->data; | |||||
| } | } | ||||
| if (options == nullptr || uridMap == nullptr) | if (options == nullptr || uridMap == nullptr) | ||||
| { | { | ||||
| carla_stderr("Host doesn't provide option or urid-map features"); | |||||
| carla_stderr("Host doesn't provide option and urid-map features"); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -640,6 +644,8 @@ public: | |||||
| fUridMap = uridMap; | fUridMap = uridMap; | ||||
| fURIs.map(uridMap); | fURIs.map(uridMap); | ||||
| fWorker = worker; | |||||
| carla_zeroStruct(fTimeInfo); | carla_zeroStruct(fTimeInfo); | ||||
| carla_zeroStruct(fLastPositionData); | carla_zeroStruct(fLastPositionData); | ||||
| } | } | ||||
| @@ -929,15 +935,15 @@ public: | |||||
| return false; | return false; | ||||
| // init midi out data | // init midi out data | ||||
| if (fPorts.numMidiOuts > 0) | |||||
| if (fPorts.numMidiOuts > 0 || fPorts.hasUI) | |||||
| { | { | ||||
| for (uint32_t i=0; i<fPorts.numMidiOuts; ++i) | for (uint32_t i=0; i<fPorts.numMidiOuts; ++i) | ||||
| { | { | ||||
| LV2_Atom_Sequence* const seq(fPorts.midiOuts[i]); | |||||
| LV2_Atom_Sequence* const seq(fPorts.eventsOut[i]); | |||||
| CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr); | CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr); | ||||
| fPorts.midiOutData[i].capacity = seq->atom.size; | |||||
| fPorts.midiOutData[i].offset = 0; | |||||
| fPorts.eventsOutData[i].capacity = seq->atom.size; | |||||
| fPorts.eventsOutData[i].offset = 0; | |||||
| seq->atom.size = sizeof(LV2_Atom_Sequence_Body); | seq->atom.size = sizeof(LV2_Atom_Sequence_Body); | ||||
| seq->atom.type = fURIs.atomSequence; | seq->atom.type = fURIs.atomSequence; | ||||
| @@ -1140,6 +1146,7 @@ protected: | |||||
| // LV2 host features | // LV2 host features | ||||
| const LV2_URID_Map* fUridMap; | const LV2_URID_Map* fUridMap; | ||||
| const LV2_Worker_Schedule* fWorker; | |||||
| // Time info stuff | // Time info stuff | ||||
| TimeInfoStruct fTimeInfo; | TimeInfoStruct fTimeInfo; | ||||
| @@ -1184,11 +1191,11 @@ protected: | |||||
| // Port stuff | // Port stuff | ||||
| struct Ports { | struct Ports { | ||||
| // need to save current state | // need to save current state | ||||
| struct MidiOutData { | |||||
| struct EventsOutData { | |||||
| uint32_t capacity; | uint32_t capacity; | ||||
| uint32_t offset; | uint32_t offset; | ||||
| MidiOutData() | |||||
| EventsOutData() | |||||
| : capacity(0), | : capacity(0), | ||||
| offset(0) {} | offset(0) {} | ||||
| }; | }; | ||||
| @@ -1200,12 +1207,13 @@ protected: | |||||
| uint32_t numMidiIns; | uint32_t numMidiIns; | ||||
| uint32_t numMidiOuts; | uint32_t numMidiOuts; | ||||
| uint32_t numParams; | uint32_t numParams; | ||||
| bool hasUI; | |||||
| bool usesTime; | bool usesTime; | ||||
| // port buffers | // port buffers | ||||
| const LV2_Atom_Sequence** eventsIn; | const LV2_Atom_Sequence** eventsIn; | ||||
| /* */ LV2_Atom_Sequence** midiOuts; | |||||
| /* */ MidiOutData* midiOutData; | |||||
| /* */ LV2_Atom_Sequence** eventsOut; | |||||
| /* */ EventsOutData* eventsOutData; | |||||
| const float** audioIns; | const float** audioIns; | ||||
| /* */ float** audioOuts; | /* */ float** audioOuts; | ||||
| /* */ float* freewheel; | /* */ float* freewheel; | ||||
| @@ -1222,10 +1230,11 @@ protected: | |||||
| numMidiIns(0), | numMidiIns(0), | ||||
| numMidiOuts(0), | numMidiOuts(0), | ||||
| numParams(0), | numParams(0), | ||||
| hasUI(false), | |||||
| usesTime(false), | usesTime(false), | ||||
| eventsIn(nullptr), | eventsIn(nullptr), | ||||
| midiOuts(nullptr), | |||||
| midiOutData(nullptr), | |||||
| eventsOut(nullptr), | |||||
| eventsOutData(nullptr), | |||||
| audioIns(nullptr), | audioIns(nullptr), | ||||
| audioOuts(nullptr), | audioOuts(nullptr), | ||||
| freewheel(nullptr), | freewheel(nullptr), | ||||
| @@ -1241,16 +1250,16 @@ protected: | |||||
| eventsIn = nullptr; | eventsIn = nullptr; | ||||
| } | } | ||||
| if (midiOuts != nullptr) | |||||
| if (eventsOut != nullptr) | |||||
| { | { | ||||
| delete[] midiOuts; | |||||
| midiOuts = nullptr; | |||||
| delete[] eventsOut; | |||||
| eventsOut = nullptr; | |||||
| } | } | ||||
| if (midiOutData != nullptr) | |||||
| if (eventsOutData != nullptr) | |||||
| { | { | ||||
| delete[] midiOutData; | |||||
| midiOutData = nullptr; | |||||
| delete[] eventsOutData; | |||||
| eventsOutData = nullptr; | |||||
| } | } | ||||
| if (audioIns != nullptr) | if (audioIns != nullptr) | ||||
| @@ -1294,7 +1303,7 @@ protected: | |||||
| for (uint32_t i=0; i < numMidiIns; ++i) | for (uint32_t i=0; i < numMidiIns; ++i) | ||||
| eventsIn[i] = nullptr; | eventsIn[i] = nullptr; | ||||
| } | } | ||||
| else if (usesTime) | |||||
| else if (usesTime || hasUI) | |||||
| { | { | ||||
| eventsIn = new const LV2_Atom_Sequence*[1]; | eventsIn = new const LV2_Atom_Sequence*[1]; | ||||
| eventsIn[0] = nullptr; | eventsIn[0] = nullptr; | ||||
| @@ -1302,11 +1311,16 @@ protected: | |||||
| if (numMidiOuts > 0) | if (numMidiOuts > 0) | ||||
| { | { | ||||
| midiOuts = new LV2_Atom_Sequence*[numMidiOuts]; | |||||
| midiOutData = new MidiOutData[numMidiOuts]; | |||||
| eventsOut = new LV2_Atom_Sequence*[numMidiOuts]; | |||||
| eventsOutData = new EventsOutData[numMidiOuts]; | |||||
| for (uint32_t i=0; i < numMidiOuts; ++i) | for (uint32_t i=0; i < numMidiOuts; ++i) | ||||
| midiOuts[i] = nullptr; | |||||
| eventsOut[i] = nullptr; | |||||
| } | |||||
| else if (hasUI) | |||||
| { | |||||
| eventsOut = new LV2_Atom_Sequence*[1]; | |||||
| eventsOut[0] = nullptr; | |||||
| } | } | ||||
| if (numAudioIns > 0) | if (numAudioIns > 0) | ||||
| @@ -1338,9 +1352,11 @@ protected: | |||||
| // NOTE: need to be filled in by the parent class | // NOTE: need to be filled in by the parent class | ||||
| } | } | ||||
| indexOffset = numAudioIns + numAudioOuts + numMidiOuts; | |||||
| // 1 event port for time if no midi input is used | |||||
| indexOffset += numMidiIns > 0 ? numMidiIns : (usesTime ? 1 : 0); | |||||
| indexOffset = numAudioIns + numAudioOuts; | |||||
| // 1 event port for time or ui if no midi input is used | |||||
| indexOffset += numMidiIns > 0 ? numMidiIns : ((usesTime || hasUI) ? 1 : 0); | |||||
| // 1 event port for ui if no midi output is used | |||||
| indexOffset += numMidiOuts > 0 ? numMidiOuts : (hasUI ? 1 : 0); | |||||
| // 1 extra for freewheel port | // 1 extra for freewheel port | ||||
| indexOffset += 1; | indexOffset += 1; | ||||
| } | } | ||||
| @@ -1349,7 +1365,7 @@ protected: | |||||
| { | { | ||||
| uint32_t index = 0; | uint32_t index = 0; | ||||
| if (numMidiIns > 0 || usesTime) | |||||
| if (numMidiIns > 0 || usesTime || hasUI) | |||||
| { | { | ||||
| if (port == index++) | if (port == index++) | ||||
| { | { | ||||
| @@ -1367,11 +1383,20 @@ protected: | |||||
| } | } | ||||
| } | } | ||||
| for (uint32_t i=0; i < numMidiOuts; ++i) | |||||
| if (numMidiOuts > 0 || hasUI) | |||||
| { | |||||
| if (port == index++) | |||||
| { | |||||
| eventsOut[0] = (LV2_Atom_Sequence*)dataLocation; | |||||
| return; | |||||
| } | |||||
| } | |||||
| for (uint32_t i=1; i < numMidiOuts; ++i) | |||||
| { | { | ||||
| if (port == index++) | if (port == index++) | ||||
| { | { | ||||
| midiOuts[i] = (LV2_Atom_Sequence*)dataLocation; | |||||
| eventsOut[i] = (LV2_Atom_Sequence*)dataLocation; | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| @@ -1433,6 +1458,7 @@ protected: | |||||
| LV2_URID timeFrame; | LV2_URID timeFrame; | ||||
| LV2_URID timeSpeed; | LV2_URID timeSpeed; | ||||
| LV2_URID timeTicksPerBeat; | LV2_URID timeTicksPerBeat; | ||||
| LV2_URID uiEvents; | |||||
| URIDs() | URIDs() | ||||
| : atomBlank(0), | : atomBlank(0), | ||||
| @@ -1452,7 +1478,8 @@ protected: | |||||
| timeBeatUnit(0), | timeBeatUnit(0), | ||||
| timeFrame(0), | timeFrame(0), | ||||
| timeSpeed(0), | timeSpeed(0), | ||||
| timeTicksPerBeat(0) {} | |||||
| timeTicksPerBeat(0), | |||||
| uiEvents(0) {} | |||||
| void map(const LV2_URID_Map* const uridMap) | void map(const LV2_URID_Map* const uridMap) | ||||
| { | { | ||||
| @@ -1474,6 +1501,7 @@ protected: | |||||
| timeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar); | timeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar); | ||||
| timeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute); | timeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute); | ||||
| timeTicksPerBeat = uridMap->map(uridMap->handle, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat); | timeTicksPerBeat = uridMap->map(uridMap->handle, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat); | ||||
| uiEvents = uridMap->map(uridMap->handle, "urn:carla:transmitEv"); | |||||
| } | } | ||||
| } fURIs; | } fURIs; | ||||
| @@ -0,0 +1,72 @@ | |||||
| /* | |||||
| * Carla macOS utils | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #ifdef CARLA_OS_MAC | |||||
| #include "CarlaMacUtils.hpp" | |||||
| #include "CarlaString.hpp" | |||||
| #import <Foundation/Foundation.h> | |||||
| CARLA_BACKEND_START_NAMESPACE | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| const char* findBinaryInBundle(const char* const bundleDir) | |||||
| { | |||||
| const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)bundleDir, (CFIndex)strlen(bundleDir), true); | |||||
| CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr, nullptr); | |||||
| const CFBundleRef bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(bundleRef != nullptr, nullptr); | |||||
| const CFURLRef exeRef = CFBundleCopyExecutableURL(bundleRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(exeRef != nullptr, nullptr); | |||||
| const CFURLRef absoluteURL = CFURLCopyAbsoluteURL(exeRef); | |||||
| CARLA_SAFE_ASSERT_RETURN(absoluteURL != nullptr, nullptr); | |||||
| const NSString* strRef = (NSString*)CFURLCopyFileSystemPath(absoluteURL, nil); | |||||
| CARLA_SAFE_ASSERT_RETURN(strRef != nullptr, nullptr); | |||||
| static CarlaString ret; | |||||
| ret = [strRef UTF8String]; | |||||
| CFRelease(absoluteURL); | |||||
| CFRelease(exeRef); | |||||
| CFRelease(bundleRef); | |||||
| CFRelease(urlRef); | |||||
| return ret.buffer(); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| AutoNSAutoreleasePool::AutoNSAutoreleasePool() | |||||
| : pool([NSAutoreleasePool new]) {} | |||||
| AutoNSAutoreleasePool::~AutoNSAutoreleasePool() | |||||
| { | |||||
| NSAutoreleasePool* rpool = (NSAutoreleasePool*)pool; | |||||
| [rpool drain]; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| CARLA_BACKEND_END_NAMESPACE | |||||
| #endif // CARLA_OS_MAC | |||||
| @@ -0,0 +1,52 @@ | |||||
| /* | |||||
| * Carla macOS utils | |||||
| * Copyright (C) 2018 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * This program is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU General Public License as | |||||
| * published by the Free Software Foundation; either version 2 of | |||||
| * the License, or any later version. | |||||
| * | |||||
| * This program is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
| * GNU General Public License for more details. | |||||
| * | |||||
| * For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
| */ | |||||
| #ifndef CARLA_MAC_UTILS_HPP_INCLUDED | |||||
| #define CARLA_MAC_UTILS_HPP_INCLUDED | |||||
| #ifndef CARLA_OS_MAC | |||||
| # error wrong include | |||||
| #endif | |||||
| #include "CarlaBackend.h" | |||||
| CARLA_BACKEND_START_NAMESPACE | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| /* | |||||
| * ... | |||||
| */ | |||||
| const char* findBinaryInBundle(const char* const bundleDir); | |||||
| /* | |||||
| * ... | |||||
| */ | |||||
| class AutoNSAutoreleasePool { | |||||
| public: | |||||
| AutoNSAutoreleasePool(); | |||||
| ~AutoNSAutoreleasePool(); | |||||
| private: | |||||
| void* const pool; | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| CARLA_BACKEND_END_NAMESPACE | |||||
| #endif // CARLA_MAC_UTILS_HPP_INCLUDED | |||||
| @@ -166,7 +166,9 @@ struct ConnectionToId { | |||||
| void clear() noexcept | void clear() noexcept | ||||
| { | { | ||||
| id = 0; | |||||
| // needed for apple GCC4.2 | |||||
| this->id = 0; | |||||
| groupA = 0; | groupA = 0; | ||||
| portA = 0; | portA = 0; | ||||
| groupB = 0; | groupB = 0; | ||||
| @@ -175,7 +177,9 @@ struct ConnectionToId { | |||||
| void setData(const uint i, const uint gA, const uint pA, const uint gB, const uint pB) noexcept | void setData(const uint i, const uint gA, const uint pA, const uint gB, const uint pB) noexcept | ||||
| { | { | ||||
| id = i; | |||||
| // needed for apple GCC4.2 | |||||
| this->id = i; | |||||
| groupA = gA; | groupA = gA; | ||||
| portA = pA; | portA = pA; | ||||
| groupB = gB; | groupB = gB; | ||||
| @@ -937,14 +937,20 @@ bool CarlaPipeCommon::flushMessages() const noexcept | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(pData->pipeSend != INVALID_PIPE_VALUE, false); | CARLA_SAFE_ASSERT_RETURN(pData->pipeSend != INVALID_PIPE_VALUE, false); | ||||
| #if 0 // def CARLA_OS_WIN | |||||
| #if defined(CARLA_OS_LINUX) || defined(CARLA_OS_GNU_HURD) | |||||
| // the only call that seems to do something | |||||
| return ::syncfs(pData->pipeSend) == 0; | |||||
| #elif defined(CARLA_OS_WIN) | |||||
| // FIXME causes issues | |||||
| return true; | |||||
| try { | try { | ||||
| return (::FlushFileBuffers(pData->pipeSend) != FALSE); | return (::FlushFileBuffers(pData->pipeSend) != FALSE); | ||||
| } CARLA_SAFE_EXCEPTION_RETURN("CarlaPipeCommon::writeMsgBuffer", false); | } CARLA_SAFE_EXCEPTION_RETURN("CarlaPipeCommon::writeMsgBuffer", false); | ||||
| #endif | |||||
| // nothing to do | |||||
| #else | |||||
| // unsupported | |||||
| return true; | return true; | ||||
| #endif | |||||
| } | } | ||||
| @@ -1242,6 +1248,22 @@ const char* CarlaPipeCommon::_readlineblock(const uint32_t timeOutMilliseconds) | |||||
| carla_msleep(5); | carla_msleep(5); | ||||
| } | } | ||||
| if (std::getenv("CARLA_VALGRIND_TEST") != nullptr) | |||||
| { | |||||
| const uint32_t timeoutEnd2(water::Time::getMillisecondCounter() + 1000); | |||||
| for (;;) | |||||
| { | |||||
| if (const char* const msg = _readline()) | |||||
| return msg; | |||||
| if (water::Time::getMillisecondCounter() >= timeoutEnd2) | |||||
| break; | |||||
| carla_msleep(100); | |||||
| } | |||||
| } | |||||
| carla_stderr("readlineblock timed out"); | carla_stderr("readlineblock timed out"); | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| @@ -23,9 +23,11 @@ | |||||
| # include <X11/Xatom.h> | # include <X11/Xatom.h> | ||||
| # include <X11/Xlib.h> | # include <X11/Xlib.h> | ||||
| # include <X11/Xutil.h> | # include <X11/Xutil.h> | ||||
| # include "CarlaPluginUI_X11Icon.hpp" | |||||
| #endif | #endif | ||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| # include "CarlaMacUtils.hpp" | |||||
| # import <Cocoa/Cocoa.h> | # import <Cocoa/Cocoa.h> | ||||
| #endif | #endif | ||||
| @@ -41,8 +43,6 @@ | |||||
| // X11 | // X11 | ||||
| #ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
| # include "CarlaPluginUI_X11Icon.hpp" | |||||
| typedef void (*EventProcPtr)(XEvent* ev); | typedef void (*EventProcPtr)(XEvent* ev); | ||||
| static const uint X11Key_Escape = 9; | static const uint X11Key_Escape = 9; | ||||
| @@ -363,7 +363,9 @@ private: | |||||
| #ifdef CARLA_OS_MAC | #ifdef CARLA_OS_MAC | ||||
| #ifdef BUILD_BRIDGE | |||||
| #if defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||||
| # define CarlaPluginWindow CARLA_JOIN_MACRO(CarlaPluginWindowBridgedArch, CARLA_PLUGIN_UI_CLASS_PREFIX) | |||||
| #elif defined(BUILD_BRIDGE) | |||||
| # define CarlaPluginWindow CARLA_JOIN_MACRO(CarlaPluginWindowBridged, CARLA_PLUGIN_UI_CLASS_PREFIX) | # define CarlaPluginWindow CARLA_JOIN_MACRO(CarlaPluginWindowBridged, CARLA_PLUGIN_UI_CLASS_PREFIX) | ||||
| #else | #else | ||||
| # define CarlaPluginWindow CARLA_JOIN_MACRO(CarlaPluginWindow, CARLA_PLUGIN_UI_CLASS_PREFIX) | # define CarlaPluginWindow CARLA_JOIN_MACRO(CarlaPluginWindow, CARLA_PLUGIN_UI_CLASS_PREFIX) | ||||
| @@ -373,15 +375,16 @@ private: | |||||
| { | { | ||||
| @public | @public | ||||
| CarlaPluginUI::Callback* callback; | CarlaPluginUI::Callback* callback; | ||||
| NSView* view; | |||||
| } | } | ||||
| - (id) initWithContentRect:(NSRect)contentRect | - (id) initWithContentRect:(NSRect)contentRect | ||||
| styleMask:(unsigned int)aStyle | styleMask:(unsigned int)aStyle | ||||
| backing:(NSBackingStoreType)bufferingType | backing:(NSBackingStoreType)bufferingType | ||||
| defer:(BOOL)flag; | defer:(BOOL)flag; | ||||
| - (void) setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v; | |||||
| - (void) setCallback:(CarlaPluginUI::Callback*)cb; | |||||
| - (BOOL) acceptsFirstResponder; | |||||
| - (BOOL) canBecomeKeyWindow; | - (BOOL) canBecomeKeyWindow; | ||||
| - (BOOL) canBecomeMainWindow; | |||||
| - (BOOL) windowShouldClose:(id)sender; | - (BOOL) windowShouldClose:(id)sender; | ||||
| - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize; | - (NSSize) windowWillResize:(NSWindow*)sender toSize:(NSSize)frameSize; | ||||
| @end | @end | ||||
| @@ -394,17 +397,17 @@ private: | |||||
| defer:(BOOL)flag | defer:(BOOL)flag | ||||
| { | { | ||||
| callback = nil; | callback = nil; | ||||
| view = nil; | |||||
| NSWindow* result = [super initWithContentRect:contentRect | NSWindow* result = [super initWithContentRect:contentRect | ||||
| styleMask:(NSClosableWindowMask | | styleMask:(NSClosableWindowMask | | ||||
| NSTitledWindowMask | | NSTitledWindowMask | | ||||
| NSResizableWindowMask) | NSResizableWindowMask) | ||||
| backing:NSBackingStoreBuffered defer:NO]; | |||||
| backing:NSBackingStoreBuffered | |||||
| defer:YES]; | |||||
| [result setAcceptsMouseMovedEvents:YES]; | |||||
| [result setContentSize:NSMakeSize(1, 1)]; | |||||
| [result setIsVisible:NO]; | [result setIsVisible:NO]; | ||||
| [result setAcceptsMouseMovedEvents:YES]; | |||||
| [result setContentSize:NSMakeSize(18, 100)]; | |||||
| return (CarlaPluginWindow*)result; | return (CarlaPluginWindow*)result; | ||||
| @@ -412,10 +415,14 @@ private: | |||||
| (void)aStyle; (void)bufferingType; (void)flag; | (void)aStyle; (void)bufferingType; (void)flag; | ||||
| } | } | ||||
| - (void)setup:(CarlaPluginUI::Callback*)cb view:(NSView*)v | |||||
| - (void)setCallback:(CarlaPluginUI::Callback*)cb | |||||
| { | { | ||||
| callback = cb; | callback = cb; | ||||
| view = v; | |||||
| } | |||||
| - (BOOL)acceptsFirstResponder | |||||
| { | |||||
| return YES; | |||||
| } | } | ||||
| - (BOOL)canBecomeKeyWindow | - (BOOL)canBecomeKeyWindow | ||||
| @@ -423,12 +430,17 @@ private: | |||||
| return YES; | return YES; | ||||
| } | } | ||||
| - (BOOL)canBecomeMainWindow | |||||
| { | |||||
| return NO; | |||||
| } | |||||
| - (BOOL)windowShouldClose:(id)sender | - (BOOL)windowShouldClose:(id)sender | ||||
| { | { | ||||
| if (callback != nil) | if (callback != nil) | ||||
| callback->handlePluginUIClosed(); | callback->handlePluginUIClosed(); | ||||
| return NO; | |||||
| return YES; | |||||
| // unused | // unused | ||||
| (void)sender; | (void)sender; | ||||
| @@ -453,20 +465,22 @@ public: | |||||
| CocoaPluginUI(Callback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | CocoaPluginUI(Callback* const cb, const uintptr_t parentId, const bool isResizable) noexcept | ||||
| : CarlaPluginUI(cb, isResizable), | : CarlaPluginUI(cb, isResizable), | ||||
| fView(nullptr), | fView(nullptr), | ||||
| fWindow(0) | |||||
| fWindow(nullptr) | |||||
| { | { | ||||
| [NSAutoreleasePool new]; | |||||
| [NSApplication sharedApplication]; | |||||
| carla_debug("CocoaPluginUI::CocoaPluginUI(%p, " P_UINTPTR, "%s)", cb, parentId, bool2str(isResizable)); | |||||
| const CarlaBackend::AutoNSAutoreleasePool arp; | |||||
| fView = [NSView new]; | |||||
| fView = [[NSView new]retain]; | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,) | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,) | ||||
| [fView setHidden:YES]; | |||||
| if (isResizable) | if (isResizable) | ||||
| [fView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | [fView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; | ||||
| fWindow = [[CarlaPluginWindow new]retain]; | fWindow = [[CarlaPluginWindow new]retain]; | ||||
| if (fWindow == 0) | |||||
| if (fWindow == nullptr) | |||||
| { | { | ||||
| [fView release]; | [fView release]; | ||||
| fView = nullptr; | fView = nullptr; | ||||
| @@ -476,12 +490,10 @@ public: | |||||
| if (! isResizable) | if (! isResizable) | ||||
| [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | ||||
| [fWindow setup:cb view:fView]; | |||||
| [fWindow setCallback:cb]; | |||||
| [fWindow setContentView:fView]; | [fWindow setContentView:fView]; | ||||
| [fWindow makeFirstResponder:fView]; | [fWindow makeFirstResponder:fView]; | ||||
| [fWindow makeKeyAndOrderFront:fWindow]; | [fWindow makeKeyAndOrderFront:fWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| [fWindow center]; | [fWindow center]; | ||||
| if (parentId != 0) | if (parentId != 0) | ||||
| @@ -490,9 +502,11 @@ public: | |||||
| ~CocoaPluginUI() override | ~CocoaPluginUI() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::~CocoaPluginUI()"); | |||||
| if (fView == nullptr) | if (fView == nullptr) | ||||
| return; | return; | ||||
| [fView removeFromSuperview]; | |||||
| [fWindow close]; | [fWindow close]; | ||||
| [fView release]; | [fView release]; | ||||
| [fWindow release]; | [fWindow release]; | ||||
| @@ -500,6 +514,7 @@ public: | |||||
| void show() override | void show() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::show()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fView setHidden:NO]; | [fView setHidden:NO]; | ||||
| @@ -508,6 +523,7 @@ public: | |||||
| void hide() override | void hide() override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::hide()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fWindow setIsVisible:NO]; | [fWindow setIsVisible:NO]; | ||||
| @@ -516,18 +532,22 @@ public: | |||||
| void idle() override | void idle() override | ||||
| { | { | ||||
| // carla_debug("CocoaPluginUI::idle()"); | |||||
| } | } | ||||
| void focus() override | void focus() override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::focus()"); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| [fWindow makeKeyWindow]; | [fWindow makeKeyWindow]; | ||||
| [NSApp activateIgnoringOtherApps:YES]; | |||||
| } | } | ||||
| void setSize(const uint width, const uint height, const bool forceUpdate) override | void setSize(const uint width, const uint height, const bool forceUpdate) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setSize(%u, %u, %s)", width, height, bool2str(forceUpdate)); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fView != nullptr,); | ||||
| [fView setFrame:NSMakeRect(0, 0, width, height)]; | [fView setFrame:NSMakeRect(0, 0, width, height)]; | ||||
| @@ -547,11 +567,18 @@ public: | |||||
| [fWindow setContentMaxSize:size]; | [fWindow setContentMaxSize:size]; | ||||
| [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | [[fWindow standardWindowButton:NSWindowZoomButton] setHidden:YES]; | ||||
| } | } | ||||
| if (forceUpdate) | |||||
| { | |||||
| // FIXME, not enough | |||||
| [fView setNeedsDisplay:YES]; | |||||
| } | |||||
| } | } | ||||
| void setTitle(const char* const title) override | void setTitle(const char* const title) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setTitle(\"%s\")", title); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| NSString* titleString = [[NSString alloc] | NSString* titleString = [[NSString alloc] | ||||
| initWithBytes:title | initWithBytes:title | ||||
| @@ -563,7 +590,8 @@ public: | |||||
| void setTransientWinId(const uintptr_t winId) override | void setTransientWinId(const uintptr_t winId) override | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != 0,); | |||||
| carla_debug("CocoaPluginUI::setTransientWinId(" P_UINTPTR ")", winId); | |||||
| CARLA_SAFE_ASSERT_RETURN(fWindow != nullptr,); | |||||
| NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId]; | NSWindow* const parentWindow = [NSApp windowWithWindowNumber:winId]; | ||||
| CARLA_SAFE_ASSERT_RETURN(parentWindow != nullptr,); | CARLA_SAFE_ASSERT_RETURN(parentWindow != nullptr,); | ||||
| @@ -572,24 +600,27 @@ public: | |||||
| ordered:NSWindowAbove]; | ordered:NSWindowAbove]; | ||||
| } | } | ||||
| void setChildWindow(void* const winId) override | |||||
| void setChildWindow(void* const window) override | |||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(winId != nullptr,); | |||||
| carla_debug("CocoaPluginUI::setChildWindow(%p)", window); | |||||
| CARLA_SAFE_ASSERT_RETURN(window != nullptr,); | |||||
| } | } | ||||
| void* getPtr() const noexcept override | void* getPtr() const noexcept override | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::getPtr()"); | |||||
| return (void*)fView; | return (void*)fView; | ||||
| } | } | ||||
| void* getDisplay() const noexcept | void* getDisplay() const noexcept | ||||
| { | { | ||||
| carla_debug("CocoaPluginUI::getDisplay()"); | |||||
| return (void*)fWindow; | return (void*)fWindow; | ||||
| } | } | ||||
| private: | private: | ||||
| NSView* fView; | |||||
| id fWindow; | |||||
| NSView* fView; | |||||
| CarlaPluginWindow* fWindow; | |||||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CocoaPluginUI) | ||||
| }; | }; | ||||
| @@ -853,7 +884,7 @@ LRESULT CALLBACK wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||||
| // ----------------------------------------------------- | // ----------------------------------------------------- | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool CarlaPluginUI::tryTransientWinIdMatch(const uintptr_t pid, const char* const uiTitle, const uintptr_t winId, const bool centerUI) | bool CarlaPluginUI::tryTransientWinIdMatch(const uintptr_t pid, const char* const uiTitle, const uintptr_t winId, const bool centerUI) | ||||
| { | { | ||||
| CARLA_SAFE_ASSERT_RETURN(uiTitle != nullptr && uiTitle[0] != '\0', true); | CARLA_SAFE_ASSERT_RETURN(uiTitle != nullptr && uiTitle[0] != '\0', true); | ||||
| @@ -1068,14 +1099,25 @@ bool CarlaPluginUI::tryTransientWinIdMatch(const uintptr_t pid, const char* cons | |||||
| int windowToMap, windowWithPID = 0, windowWithNameAndPID = 0; | int windowToMap, windowWithPID = 0, windowWithNameAndPID = 0; | ||||
| for (NSDictionary* const entry in windowList) | |||||
| const NSDictionary* entry; | |||||
| for (entry in windowList) | |||||
| { | { | ||||
| // FIXME: is this needed? is old version safe? | |||||
| #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 | |||||
| if ([entry[(id)kCGWindowSharingState] intValue] == kCGWindowSharingNone) | if ([entry[(id)kCGWindowSharingState] intValue] == kCGWindowSharingNone) | ||||
| continue; | continue; | ||||
| NSString* const windowName = entry[(id)kCGWindowName]; | NSString* const windowName = entry[(id)kCGWindowName]; | ||||
| int const windowNumber = [entry[(id)kCGWindowNumber] intValue]; | int const windowNumber = [entry[(id)kCGWindowNumber] intValue]; | ||||
| uintptr_t const windowPID = [entry[(id)kCGWindowOwnerPID] intValue]; | uintptr_t const windowPID = [entry[(id)kCGWindowOwnerPID] intValue]; | ||||
| #else | |||||
| if ([[entry objectForKey:(id)kCGWindowSharingState] intValue] == kCGWindowSharingNone) | |||||
| continue; | |||||
| NSString* const windowName = [entry objectForKey:(id)kCGWindowName]; | |||||
| int const windowNumber = [[entry objectForKey:(id)kCGWindowNumber] intValue]; | |||||
| uintptr_t const windowPID = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue]; | |||||
| #endif | |||||
| if (windowPID != pid) | if (windowPID != pid) | ||||
| continue; | continue; | ||||
| @@ -1141,7 +1183,7 @@ bool CarlaPluginUI::tryTransientWinIdMatch(const uintptr_t pid, const char* cons | |||||
| return true; | return true; | ||||
| (void)pid; (void)centerUI; | (void)pid; (void)centerUI; | ||||
| } | } | ||||
| #endif // BUILD_BRIDGE | |||||
| #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ----------------------------------------------------- | // ----------------------------------------------------- | ||||
| @@ -46,7 +46,7 @@ public: | |||||
| virtual void* getDisplay() const noexcept = 0; | virtual void* getDisplay() const noexcept = 0; | ||||
| #endif | #endif | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| static bool tryTransientWinIdMatch(const uintptr_t pid, const char* const uiTitle, const uintptr_t winId, const bool centerUI); | static bool tryTransientWinIdMatch(const uintptr_t pid, const char* const uiTitle, const uintptr_t winId, const bool centerUI); | ||||
| #endif | #endif | ||||
| @@ -122,7 +122,7 @@ CarlaStateSave::Parameter::Parameter() noexcept | |||||
| index(-1), | index(-1), | ||||
| name(nullptr), | name(nullptr), | ||||
| symbol(nullptr), | symbol(nullptr), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| value(0.0f), | value(0.0f), | ||||
| midiChannel(0), | midiChannel(0), | ||||
| midiCC(-1) {} | midiCC(-1) {} | ||||
| @@ -189,7 +189,7 @@ CarlaStateSave::CarlaStateSave() noexcept | |||||
| binary(nullptr), | binary(nullptr), | ||||
| uniqueId(0), | uniqueId(0), | ||||
| options(0x0), | options(0x0), | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| active(false), | active(false), | ||||
| dryWet(1.0f), | dryWet(1.0f), | ||||
| volume(1.0f), | volume(1.0f), | ||||
| @@ -247,7 +247,7 @@ void CarlaStateSave::clear() noexcept | |||||
| uniqueId = 0; | uniqueId = 0; | ||||
| options = 0x0; | options = 0x0; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| active = false; | active = false; | ||||
| dryWet = 1.0f; | dryWet = 1.0f; | ||||
| volume = 1.0f; | volume = 1.0f; | ||||
| @@ -323,7 +323,7 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) | |||||
| const String& tag(xmlData->getTagName()); | const String& tag(xmlData->getTagName()); | ||||
| const String text(xmlData->getAllSubText().trim()); | const String text(xmlData->getAllSubText().trim()); | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| // ------------------------------------------------------- | // ------------------------------------------------------- | ||||
| // Internal Data | // Internal Data | ||||
| @@ -431,7 +431,7 @@ bool CarlaStateSave::fillFromXmlElement(const XmlElement* const xmlElement) | |||||
| stateParameter->dummy = false; | stateParameter->dummy = false; | ||||
| stateParameter->value = pText.getFloatValue(); | stateParameter->value = pText.getFloatValue(); | ||||
| } | } | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| else if (pTag == "MidiChannel") | else if (pTag == "MidiChannel") | ||||
| { | { | ||||
| const int channel(pText.getIntValue()); | const int channel(pText.getIntValue()); | ||||
| @@ -545,7 +545,7 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||||
| content << " <Data>\n"; | content << " <Data>\n"; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| { | { | ||||
| MemoryOutputStream dataXml; | MemoryOutputStream dataXml; | ||||
| @@ -588,7 +588,7 @@ void CarlaStateSave::dumpToMemoryStream(MemoryOutputStream& content) const | |||||
| if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') | if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0') | ||||
| parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; | parameterXml << " <Symbol>" << xmlSafeString(stateParameter->symbol, true) << "</Symbol>\n"; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| if (stateParameter->midiCC > 0) | if (stateParameter->midiCC > 0) | ||||
| { | { | ||||
| parameterXml << " <MidiCC>" << stateParameter->midiCC << "</MidiCC>\n"; | parameterXml << " <MidiCC>" << stateParameter->midiCC << "</MidiCC>\n"; | ||||
| @@ -34,7 +34,7 @@ struct CarlaStateSave { | |||||
| const char* name; | const char* name; | ||||
| const char* symbol; | const char* symbol; | ||||
| float value; | float value; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| uint8_t midiChannel; | uint8_t midiChannel; | ||||
| int16_t midiCC; | int16_t midiCC; | ||||
| #endif | #endif | ||||
| @@ -70,7 +70,7 @@ struct CarlaStateSave { | |||||
| int64_t uniqueId; | int64_t uniqueId; | ||||
| uint options; | uint options; | ||||
| #ifndef BUILD_BRIDGE | |||||
| #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||||
| bool active; | bool active; | ||||
| float dryWet; | float dryWet; | ||||
| float volume; | float volume; | ||||
| @@ -159,6 +159,7 @@ public: | |||||
| return *this; | return *this; | ||||
| } | } | ||||
| #if 0 | |||||
| T& operator*() noexcept | T& operator*() noexcept | ||||
| { | { | ||||
| static T& fallback(_getFallback()); | static T& fallback(_getFallback()); | ||||
| @@ -168,6 +169,7 @@ public: | |||||
| return data->value; | return data->value; | ||||
| } | } | ||||
| #endif | |||||
| const T& operator*() const noexcept | const T& operator*() const noexcept | ||||
| { | { | ||||
| @@ -180,8 +182,8 @@ public: | |||||
| } | } | ||||
| private: | private: | ||||
| ListHead* fEntry; | |||||
| ListHead* fEntry2; | |||||
| const ListHead* fEntry; | |||||
| const ListHead* fEntry2; | |||||
| static T& _getFallback() | static T& _getFallback() | ||||
| { | { | ||||
| @@ -63,16 +63,10 @@ class RackListItem(QListWidgetItem): | |||||
| self.fWidget = None | self.fWidget = None | ||||
| self.fOptions = { | self.fOptions = { | ||||
| 'compact': False, | |||||
| 'compact': bool(self.host.get_custom_data_value(pluginId, CUSTOM_DATA_TYPE_PROPERTY, "CarlaSkinIsCompacted") == "true"), | |||||
| 'useSkins': useSkins | 'useSkins': useSkins | ||||
| } | } | ||||
| for i in range(self.host.get_custom_data_count(pluginId)): | |||||
| cdata = self.host.get_custom_data(pluginId, i) | |||||
| if cdata['type'] == CUSTOM_DATA_TYPE_PROPERTY and cdata['key'] == "CarlaSkinIsCompacted": | |||||
| self.fOptions['compact'] = bool(cdata['value'] == "true") | |||||
| break | |||||
| self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) | self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled) | ||||
| #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled) | #self.setFlags(Qt.ItemIsSelectable|Qt.ItemIsEnabled|Qt.ItemIsDragEnabled) | ||||