diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..45e913d5 --- /dev/null +++ b/.clang-format @@ -0,0 +1,36 @@ +--- +UseTab: Never +--- +Language: Cpp +AlignAfterOpenBracket: BAS_Align +ConstructorInitializerIndentWidth: 2 +SpaceBeforeParens: ControlStatements +ColumnLimit: 105 +BasedOnStyle: Google +IndentWidth: 2 +AlignAfterOpenBracket: Align +ConstructorInitializerAllOnOneLineOrOnePerLine: true +BreakConstructorInitializers: BeforeComma +BreakBeforeBraces: Allman +ColumnLimit: 105 +SortIncludes: false +NamespaceIndentation: None +ReflowComments: false +AllowShortFunctionsOnASingleLine: None +--- +Language: ObjC +BasedOnStyle: Google +AlignAfterOpenBracket: BAS_Align +ConstructorInitializerIndentWidth: 2 +SpaceBeforeParens: ControlStatements +IndentWidth: 2 +AlignAfterOpenBracket: Align +ConstructorInitializerAllOnOneLineOrOnePerLine: true +BreakConstructorInitializers: BeforeComma +BreakBeforeBraces: Allman +ColumnLimit: 105 +SortIncludes: false +NamespaceIndentation: None +ReflowComments: false +AllowShortFunctionsOnASingleLine: None +... diff --git a/.github/workflows/code-checks.yml b/.github/workflows/code-checks.yml new file mode 100644 index 00000000..e16f9897 --- /dev/null +++ b/.github/workflows/code-checks.yml @@ -0,0 +1,21 @@ +name: Clap Wrapper Format and Code Checks +on: [pull_request] + +defaults: + run: + shell: bash + +jobs: + build-code-checks: + name: code-checks + runs-on: ubuntu-latest + strategy: + fail-fast: true + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Run Code Checks + run: | + cmake -Bbuild -DCLAP_WRAPPER_CODE_CHECKS_ONLY=TRUE + cmake --build build --target clap-wrapper-code-checks diff --git a/CMakeLists.txt b/CMakeLists.txt index b6f68da0..c013117d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ option(CLAP_WRAPPER_WINDOWS_SINGLE_FILE "Build a single fine (rather than folder project(clap-wrapper LANGUAGES C CXX - VERSION 0.0.4 + VERSION 0.5.0 DESCRIPTION "CLAP-as-X wrappers" ) @@ -55,7 +55,11 @@ set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # defines functions relative to this, so needs a cache # variable with the source dir set(CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE STRING "Clap Wrapper Source Location") -include(cmake/enable_sdks.cmake) +if (DEFINED CLAP_WRAPPER_CODE_CHECKS_ONLY) + message(STATUS "clap-wrapper: code checks only; skipping enable sdks") +else() + include(cmake/enable_sdks.cmake) +endif() # automatically build the wrapper only if this is the top level project set(skipbuild FALSE) @@ -64,6 +68,9 @@ if (NOT PROJECT_IS_TOP_LEVEL) set(skipbuild TRUE) endif() endif() +if (DEFINED CLAP_WRAPPER_CODE_CHECKS_ONLY) + set(skipbuild ${CLAP_WRAPPER_CODE_CHECKS_ONLY}) +endif() if (${skipbuild}) message(STATUS "clap-wrapper: Skipping clap wrapper target ejection") @@ -106,3 +113,23 @@ else() endif() endif() endif() + + +add_custom_target(clap-wrapper-code-checks) + +# Clang Format checks +find_program(CLANG_FORMAT_EXE NAMES clang-format) +set(CLANG_FORMAT_DIRS src) +set(CLANG_FORMAT_EXTS cpp h) +foreach(dir ${CLANG_FORMAT_DIRS}) + foreach(ext ${CLANG_FORMAT_EXTS}) + list(APPEND CLANG_FORMAT_GLOBS "':(glob)${dir}/**/*.${ext}'") + endforeach() +endforeach() +add_custom_command(TARGET clap-wrapper-code-checks + POST_BUILD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + COMMAND ${CMAKE_COMMAND} -E echo About to check clang-format using ${CLANG_FORMAT_EXE} + COMMAND git ls-files -- ${CLANG_FORMAT_GLOBS} | xargs ${CLANG_FORMAT_EXE} --dry-run --Werror + ) +# }}} \ No newline at end of file diff --git a/cmake/enable_sdks.cmake b/cmake/enable_sdks.cmake index 0ea09f61..cbf83f5d 100644 --- a/cmake/enable_sdks.cmake +++ b/cmake/enable_sdks.cmake @@ -152,21 +152,17 @@ function(DefineCLAPASVST3Sources) list(REMOVE_ITEM vst3sources "${full_path_test_cpp}") endif() + if(WIN32) - set(os_wrappersources src/detail/os/windows.cpp) + set(os_wrappersources src/detail/vst3/os/windows.cpp) endif() if (APPLE) - set(os_wrappersources - src/detail/clap/mac_helpers.mm - src/detail/os/macos.mm - ) + set(os_wrappersources src/detail/vst3/os/macos.mm) endif() if(UNIX AND NOT APPLE) - set(os_wrappersources - src/detail/os/linux.cpp - ) + set(os_wrappersources src/detail/vst3/os/linux.cpp) endif() set(wrappersources_vst3 @@ -184,12 +180,6 @@ function(DefineCLAPASVST3Sources) src/detail/vst3/process.cpp src/detail/vst3/categories.h src/detail/vst3/categories.cpp - src/detail/sha1.h - src/detail/sha1.cpp - src/detail/clap/fsutil.h - src/detail/clap/fsutil.cpp - src/detail/os/osutil.h - src/detail/clap/automation.h ${os_wrappersources} CACHE STRING "Clap Wrapper Library Sources") @@ -293,27 +283,27 @@ function(target_add_vst3_wrapper) target_sources(${V3_TARGET} PRIVATE ${wrappersources_vst3_entry}) - # the library "vst3-pluginbase-lib" contains all code from the VST3 SDK like the interface definitions + # the library "base-sdk-vst3" contains all code from the VST3 SDK like the interface definitions # and base classes and will be statically linked. This code is shared between all VST3 plugins. # it only needs to be created once. - if (NOT TARGET vst3-pluginbase-lib) + if (NOT TARGET base-sdk-vst3) message(STATUS "clap-wrapper: creating vst3 library with root ${VST3_SDK_ROOT}") - add_library(vst3-pluginbase-lib STATIC ${vst3sources}) - target_include_directories(vst3-pluginbase-lib PUBLIC ${VST3_SDK_ROOT} ${VST3_SDK_ROOT}/public.sdk ${VST3_SDK_ROOT}/pluginterfaces) - target_compile_options(vst3-pluginbase-lib PUBLIC $,-DDEVELOPMENT=1,-DRELEASE=1>) # work through steinbergs alternate choices for these + add_library(base-sdk-vst3 STATIC ${vst3sources}) + target_include_directories(base-sdk-vst3 PUBLIC ${VST3_SDK_ROOT} ${VST3_SDK_ROOT}/public.sdk ${VST3_SDK_ROOT}/pluginterfaces) + target_compile_options(base-sdk-vst3 PUBLIC $,-DDEVELOPMENT=1,-DRELEASE=1>) # work through steinbergs alternate choices for these # The VST3SDK uses sprintf, not snprintf, which macOS flags as deprecated # to move people to snprintf. Silence that warning on the VST3 build if (APPLE) - target_compile_options(vst3-pluginbase-lib PUBLIC -Wno-deprecated-declarations) + target_compile_options(base-sdk-vst3 PUBLIC -Wno-deprecated-declarations) endif() if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") # The VST3 SDK confuses lld and long long int in format statements in some situations it seems - target_compile_options(vst3-pluginbase-lib PUBLIC -Wno-format) + target_compile_options(base-sdk-vst3 PUBLIC -Wno-format) # The SDK also does things like `#warning DEPRECATED No Linux implementation # assert (false && "DEPRECATED No Linux implementation");` for some methods which # generates a cpp warning. Since we won't fix this do - target_compile_options(vst3-pluginbase-lib PUBLIC -Wno-cpp) + target_compile_options(base-sdk-vst3 PUBLIC -Wno-cpp) endif() endif() @@ -329,11 +319,11 @@ function(target_add_vst3_wrapper) add_library(${V3_TARGET}-clap-wrapper-vst3-lib STATIC ${wsv3}) target_include_directories(${V3_TARGET}-clap-wrapper-vst3-lib PRIVATE "${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/include") - target_link_libraries(${V3_TARGET}-clap-wrapper-vst3-lib PUBLIC clap vst3-pluginbase-lib) + target_link_libraries(${V3_TARGET}-clap-wrapper-vst3-lib PUBLIC clap base-sdk-vst3) # clap-wrapper-extensions are PUBLIC, so a clap linking the library can access the clap-wrapper-extensions target_compile_definitions(${V3_TARGET}-clap-wrapper-vst3-lib PUBLIC -D${CLAP_WRAPPER_PLATFORM}=1) - target_link_libraries(${V3_TARGET}-clap-wrapper-vst3-lib PUBLIC clap-wrapper-extensions) + target_link_libraries(${V3_TARGET}-clap-wrapper-vst3-lib PUBLIC clap-wrapper-extensions clap-wrapper-shared-detail) target_compile_options(${V3_TARGET}-clap-wrapper-vst3-lib PRIVATE -DCLAP_SUPPORTS_ALL_NOTE_EXPRESSIONS=$,1,0> @@ -360,7 +350,8 @@ function(target_add_vst3_wrapper) if (APPLE) if ("${V3_BUNDLE_IDENTIFIER}" STREQUAL "") - set(V3_BUNDLE_IDENTIFIER "org.cleveraudio.wrapper.${outidentifier}.vst3") + string(REPLACE "_" "-" repout ${outidentifier}) + set(V3_BUNDLE_IDENTIFIER "org.cleveraudio.wrapper.${repout}.vst3") endif() if ("${CLAP_WRAPPER_BUNDLE_VERSION}" STREQUAL "") @@ -379,7 +370,7 @@ function(target_add_vst3_wrapper) MACOSX_BUNDLE_INFO_PLIST ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/cmake/VST3_Info.plist.in ) if (NOT ${CMAKE_GENERATOR} STREQUAL "Xcode") - add_custom_command(TARGET ${V3_TARGET} POST_BUILD + add_custom_command(TARGET ${V3_TARGET} PRE_BUILD WORKING_DIRECTORY $ COMMAND SetFile -a B "$.$" ) @@ -440,8 +431,8 @@ if (APPLE) message(STATUS "clap-wrapper: AudioUnit SDK location: ${AUDIOUNIT_SDK_ROOT}") set(AUSDK_SRC ${AUDIOUNIT_SDK_ROOT}/src/AudioUnitSDK) - if (NOT TARGET auv2_sdk) - add_library(auv2_sdk STATIC ${AUSDK_SRC}/AUBase.cpp + if (NOT TARGET base-sdk-auv2) + add_library(base-sdk-auv2 STATIC ${AUSDK_SRC}/AUBase.cpp ${AUSDK_SRC}/AUBuffer.cpp ${AUSDK_SRC}/AUBufferAllocator.cpp ${AUSDK_SRC}/AUEffectBase.cpp @@ -454,7 +445,7 @@ if (APPLE) ${AUSDK_SRC}/ComponentBase.cpp ${AUSDK_SRC}/MusicDeviceBase.cpp ) - target_include_directories(auv2_sdk PUBLIC ${AUDIOUNIT_SDK_ROOT}/include) + target_include_directories(base-sdk-auv2 PUBLIC ${AUDIOUNIT_SDK_ROOT}/include) endif() function(target_add_auv2_wrapper) @@ -469,6 +460,8 @@ if (APPLE) SUBTYPE_CODE INSTRUMENT_TYPE + CLAP_TARGET_FOR_CONFIG + MACOS_EMBEDDED_CLAP_LOCATION ) cmake_parse_arguments(AUV2 "" "${oneValueArgs}" "" ${ARGN} ) @@ -477,63 +470,132 @@ if (APPLE) message(FATAL_ERROR "clap-wrapper: target_add_auv2_wrapper requires a target") endif() - if (NOT DEFINED AUV2_OUTPUT_NAME) - message(FATAL_ERROR "clap-wrapper: target_add_auv2_wrapper requires an output name") + if (NOT TARGET ${AUV2_TARGET}) + message(FATAL_ERROR "clap-wrapper: auv2-target must be a target") endif() - if (NOT DEFINED AUV2_MANUFACTURER_NAME) - message(FATAL_ERROR "clap-wrapper: For now please specify AUV2 manufacturer name") + if (NOT DEFINED AUV2_BUNDLE_VERSION) + message(WARNING "clap-wrapper: bundle version not defined. Chosing 1") + set(AUV2_BUNDLE_VERSION 1) endif() - if (NOT DEFINED AUV2_MANUFACTURER_CODE) - message(FATAL_ERROR "clap-wrapper: For now please specify AUV2 manufacturer code (4 chars)") - endif() + # We need a build helper which ejects our config code for info-plist and entry points + set(bhtg ${AUV2_TARGET}-build-helper) + set(bhsc "${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/detail/auv2/build-helper/") + add_executable(${bhtg} ${bhsc}/build-helper.cpp) + target_link_libraries(${bhtg} PRIVATE + clap-wrapper-shared-detail + macos_filesystem_support + "-framework Foundation" + "-framework CoreFoundation" + ) + set(bhtgoutdir "${CMAKE_CURRENT_BINARY_DIR}/${AUV2_TARGET}-build-helper-output") + add_custom_command(TARGET ${bhtg} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E echo "clap-wrapper: auv2 configuration output dir is ${bhtgoutdir}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${bhtgoutdir}" + ) - if (NOT DEFINED AUV2_SUBTYPE_CODE) - message(FATAL_ERROR "clap-wrapper: For now please specify AUV2 subtype code (4 chars)") - endif() + add_dependencies(${AUV2_TARGET} ${bhtg}) - if (NOT DEFINED AUV2_INSTRUMENT_TYPE) - message(WARNING "clap-wrapper: auv2 instrument type not specified. Using aumu") + if (DEFINED AUV2_CLAP_TARGET_FOR_CONFIG) + set(clpt ${AUV2_CLAP_TARGET_FOR_CONFIG}) + message(STATUS "clap-wrapper: building auv2 based on target ${AUV2_CLAP_TARGET_FOR_CONFIG}") + get_property(ton TARGET ${clpt} PROPERTY LIBRARY_OUTPUT_NAME) + set(AUV2_OUTPUT_NAME "${ton}") + set(AUV2_SUBTYPE_CODE "Fooo") set(AUV2_INSTRUMENT_TYPE "aumu") + + add_dependencies(${AUV2_TARGET} ${clpt}) + add_dependencies(${bhtg} ${clpt}) + + add_custom_command( + TARGET ${bhtg} + POST_BUILD + WORKING_DIRECTORY ${bhtgoutdir} + BYPRODUCTS ${bhtgoutdir}/auv2_Info.plist ${bhtgoutdir}/generated_entrypoints.hxx + COMMAND $ --fromclap + "${AUV2_OUTPUT_NAME}" + "$" + "${AUV2_MANUFACTURER_CODE}" "${AUV2_MANUFACTURER_NAME}" + ) + else() + if (NOT DEFINED AUV2_OUTPUT_NAME) + message(FATAL_ERROR "clap-wrapper: target_add_auv2_wrapper requires an output name") + endif() + + if (NOT DEFINED AUV2_SUBTYPE_CODE) + message(FATAL_ERROR "clap-wrapper: For nontarget build specify AUV2 subtype code (4 chars)") + endif() + + if (NOT DEFINED AUV2_MANUFACTURER_NAME) + message(FATAL_ERROR "clap-wrapper: For nontarget build specify AUV2 manufacturer name") + endif() + + if (NOT DEFINED AUV2_MANUFACTURER_CODE) + message(FATAL_ERROR "clap-wrapper: For nontarget build specify AUV2 manufacturer code (4 chars)") + endif() + + if (NOT DEFINED AUV2_INSTRUMENT_TYPE) + message(WARNING "clap-wrapper: auv2 instrument type not specified. Using aumu") + set(AUV2_INSTRUMENT_TYPE "aumu") + endif() + + add_custom_command( + TARGET ${bhtg} + POST_BUILD + WORKING_DIRECTORY ${bhtgoutdir} + BYPRODUCTS ${bhtgoutdir}/auv2_Info.plist ${bhtgoutdir}/generated_entrypoints.hxx + COMMAND $ --explicit + "${AUV2_OUTPUT_NAME}" "${AUV2_BUNDLE_VERSION}" + "${AUV2_INSTRUMENT_TYPE}" "${AUV2_SUBTYPE_CODE}" + "${AUV2_MANUFACTURER_CODE}" "${AUV2_MANUFACTURER_NAME}" + ) + endif() + + string(MAKE_C_IDENTIFIER ${AUV2_OUTPUT_NAME} outidentifier) + + if ("${AUV2_BUNDLE_IDENTIFIER}" STREQUAL "") + string(REPLACE "_" "-" repout ${outidentifier}) + set(AUV2_BUNDLE_IDENTIFIER "org.cleveraudio.wrapper.${repout}.auv2") endif() - set(AUV2_INSTRUMENT_TYPE ${AUV2_INSTRUMENT_TYPE} PARENT_SCOPE) set(AUV2_MANUFACTURER_NAME ${AUV2_MANUFACTURER_NAME} PARENT_SCOPE) set(AUV2_MANUFACTURER_CODE ${AUV2_MANUFACTURER_CODE} PARENT_SCOPE) + configure_file(${bhsc}/auv2_infoplist_top.in + ${bhtgoutdir}/auv2_infoplist_top) + + set(AUV2_INSTRUMENT_TYPE ${AUV2_INSTRUMENT_TYPE} PARENT_SCOPE) set(AUV2_SUBTYPE_CODE ${AUV2_SUBTYPE_CODE} PARENT_SCOPE) message(STATUS "clap-wrapper: Adding AUV2 Wrapper to target ${AUV2_TARGET} generating '${AUV2_OUTPUT_NAME}.component'") - string(MAKE_C_IDENTIFIER ${AUV2_OUTPUT_NAME} outidentifier) - # This is a placeholder dummy until we actually write the AUv2 # Similarly the subordinate library being an interface below # is a placeholder. When we write it we will follow a similar # split trick as for the vst3, mostly (but AUV2 is a bit different # with info.plist and entrypoint-per-instance stuff) - target_sources(${AUV2_TARGET} PRIVATE ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/wrapasauv2.cpp) + target_sources(${AUV2_TARGET} PRIVATE + ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/wrapasauv2.cpp + ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/detail/auv2/auv2_shared.h + ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src/detail/auv2/auv2_base_classes.h + ${bhtgoutdir}/generated_entrypoints.hxx) if (NOT TARGET ${AUV2_TARGET}-clap-wrapper-auv2-lib) # For now make this an interface add_library(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE ) - target_include_directories(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include") - target_link_libraries(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE clap auv2_sdk) + target_include_directories(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE "${bhtgoutdir}" "${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/src") + target_link_libraries(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE clap base-sdk-auv2) # clap-wrapper-extensions are PUBLIC, so a clap linking the library can access the clap-wrapper-extensions target_compile_definitions(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE -D${CLAP_WRAPPER_PLATFORM}=1) - target_link_libraries(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE clap-wrapper-extensions macos_filesystem_support) + target_link_libraries(${AUV2_TARGET}-clap-wrapper-auv2-lib INTERFACE clap-wrapper-extensions clap-wrapper-shared-detail macos_filesystem_support) endif() set_target_properties(${AUV2_TARGET} PROPERTIES LIBRARY_OUTPUT_NAME "${AUV2_OUTPUT_NAME}") target_link_libraries(${AUV2_TARGET} PUBLIC ${AUV2_TARGET}-clap-wrapper-auv2-lib) - if ("${AUV2_BUNDLE_IDENTIFIER}" STREQUAL "") - set(AUV2_BUNDLE_IDENTIFIER "org.cleveraudio.wrapper.${outidentifier}.auv2") - endif() - if ("${CLAP_WRAPPER_BUNDLE_VERSION}" STREQUAL "") set(CLAP_WRAPPER_BUNDLE_VERSION "1.0") endif() @@ -551,10 +613,15 @@ if (APPLE) MACOSX_BUNDLE_BUNDLE_NAME ${AUV2_OUTPUT_NAME} MACOSX_BUNDLE_BUNDLE_VERSION ${AUV2_BUNDLE_VERSION} MACOSX_BUNDLE_SHORT_VERSION_STRING ${AUV2_BUNDLE_VERSION} - MACOSX_BUNDLE_INFO_PLIST ${CLAP_WRAPPER_CMAKE_CURRENT_SOURCE_DIR}/cmake/auv2_Info.plist.in ) + # This is "PRE_BUILD" because the target is created at cmake time and we want to beat xcode signing in order + # it is *not* a MACOSX_BUNDLE_INFO_PLIST since that is a configure not build time concept so doesn't work + # with compile time generated files + add_custom_command(TARGET ${AUV2_TARGET} PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${bhtgoutdir}/auv2_Info.plist $/../Info.plist) + if (NOT ${CMAKE_GENERATOR} STREQUAL "Xcode") - add_custom_command(TARGET ${AUV2_TARGET} POST_BUILD + add_custom_command(TARGET ${AUV2_TARGET} PRE_BUILD WORKING_DIRECTORY $ COMMAND SetFile -a B "$.$") endif() @@ -579,6 +646,30 @@ if ( NOT TARGET clap-wrapper-extensions) target_include_directories(clap-wrapper-extensions INTERFACE include) endif() +add_library(clap-wrapper-shared-detail STATIC + src/detail/sha1.h + src/detail/sha1.cpp + src/detail/clap/fsutil.h + src/detail/clap/fsutil.cpp + src/detail/clap/automation.h + ) +target_compile_options(clap-wrapper-shared-detail PUBLIC -D${CLAP_WRAPPER_PLATFORM}=1) +target_link_libraries(clap-wrapper-shared-detail PUBLIC clap clap-wrapper-extensions) +target_include_directories(clap-wrapper-shared-detail PUBLIC libs/fmt) +target_include_directories(clap-wrapper-shared-detail PUBLIC src) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(clap-wrapper-shared-detail PRIVATE -Wall -Wextra -Wno-unused-parameter -Wpedantic -Werror) +endif() + + +if (APPLE) + target_sources(clap-wrapper-shared-detail PRIVATE + src/detail/clap/mac_helpers.mm + ) + target_link_libraries(clap-wrapper-shared-detail PRIVATE macos_filesystem_support) +endif() + if(${CMAKE_SIZEOF_VOID_P} EQUAL 4) # a 32 bit build is odd enough that it might be an error. Chirp. message(STATUS "clap-wrapper: configured as 32 bit build. Intentional?") diff --git a/include/clapwrapper/auv2.h b/include/clapwrapper/auv2.h new file mode 100644 index 00000000..4f37dcb3 --- /dev/null +++ b/include/clapwrapper/auv2.h @@ -0,0 +1,24 @@ +#pragma once + +#include "clap/private/macros.h" +#include + +static const CLAP_CONSTEXPR char CLAP_PLUGIN_FACTORY_INFO_AUV2[] = + "clap.plugin-factory-info-as-auv2.draft0"; + +typedef struct clap_plugin_info_as_auv2 +{ + char au_type[5]; // the au_type. If empty (best choice) use the features[0] to aumu aufx aumi + char au_subt[5]; // the subtype. If empty (worst choice) we try a bad 32 bit hash of the id +} clap_plugin_info_as_auv2_t; + +typedef struct clap_plugin_factory_as_auv2 +{ + // optional values for the Steinberg::PFactoryInfo structure + const char *manufacturer_code; // your 'manu' field + const char *manufacturer_name; // your manufacturer display name + + // populate information about this particular auv2. Return false if we cannot. + bool(CLAP_ABI *get_auv2_info)(const clap_plugin_factory_as_auv2 *factory, uint32_t index, + clap_plugin_info_as_auv2_t *info); +} clap_plugin_factory_as_auv2_t; \ No newline at end of file diff --git a/libs/fmt/README.md b/libs/fmt/README.md new file mode 100644 index 00000000..f3ebbbac --- /dev/null +++ b/libs/fmt/README.md @@ -0,0 +1,3 @@ +This is a copy of the fmt:: library from github. License is in header files in +the "fmt" directory + diff --git a/src/detail/os/fmt/core.h b/libs/fmt/fmt/core.h similarity index 100% rename from src/detail/os/fmt/core.h rename to libs/fmt/fmt/core.h diff --git a/src/detail/os/fmt/format-inl.h b/libs/fmt/fmt/format-inl.h similarity index 100% rename from src/detail/os/fmt/format-inl.h rename to libs/fmt/fmt/format-inl.h diff --git a/src/detail/os/fmt/format.h b/libs/fmt/fmt/format.h similarity index 100% rename from src/detail/os/fmt/format.h rename to libs/fmt/fmt/format.h diff --git a/src/detail/os/fmt/ranges.h b/libs/fmt/fmt/ranges.h similarity index 100% rename from src/detail/os/fmt/ranges.h rename to libs/fmt/fmt/ranges.h diff --git a/src/clap_proxy.cpp b/src/clap_proxy.cpp index 69ef3910..3559d2db 100644 --- a/src/clap_proxy.cpp +++ b/src/clap_proxy.cpp @@ -10,135 +10,128 @@ namespace Clap { - namespace HostExt - { - static Plugin* self(const clap_host_t* host) - { - return static_cast(host->host_data); - } - - void host_log(const clap_host_t* host, clap_log_severity severity, const char* msg) - { - self(host)->log(severity, msg); - } - - clap_host_log_t log = - { - host_log - }; +namespace HostExt +{ +static Plugin* self(const clap_host_t* host) +{ + return static_cast(host->host_data); +} - void rescan(const clap_host_t* host, clap_param_rescan_flags flags) - { - self(host)->param_rescan(flags); - } +void host_log(const clap_host_t* host, clap_log_severity severity, const char* msg) +{ + self(host)->log(severity, msg); +} - // Clears references to a parameter. - // [main-thread] - void clear(const clap_host_t* host, clap_id param_id, clap_param_clear_flags flags) - { +clap_host_log_t log = {host_log}; - } +void rescan(const clap_host_t* host, clap_param_rescan_flags flags) +{ + self(host)->param_rescan(flags); +} - // Request a parameter flush. - // - // If the plugin is processing, this will result in no action. The process call - // will run normally. If plugin isn't processing, the host will make a subsequent - // call to clap_plugin_params->flush(). As a result, this function is always - // safe to call from a non-audio thread (typically the UI thread on a gesture) - // whether processing is active or not. - // - // This must not be called on the [audio-thread]. - // [thread-safe,!audio-thread] - void request_flush(const clap_host_t* host) - { - self(host)->param_request_flush(); - } - clap_host_params_t params = - { - rescan, clear, request_flush - }; +// Clears references to a parameter. +// [main-thread] +void clear(const clap_host_t* host, clap_id param_id, clap_param_clear_flags flags) +{ +} + +// Request a parameter flush. +// +// If the plugin is processing, this will result in no action. The process call +// will run normally. If plugin isn't processing, the host will make a subsequent +// call to clap_plugin_params->flush(). As a result, this function is always +// safe to call from a non-audio thread (typically the UI thread on a gesture) +// whether processing is active or not. +// +// This must not be called on the [audio-thread]. +// [thread-safe,!audio-thread] +void request_flush(const clap_host_t* host) +{ + self(host)->param_request_flush(); +} +clap_host_params_t params = {rescan, clear, request_flush}; - bool is_main_thread(const clap_host_t* host) - { - return self(host)->is_main_thread(); - } +bool is_main_thread(const clap_host_t* host) +{ + return self(host)->is_main_thread(); +} - // Returns true if "this" thread is one of the audio threads. - // [thread-safe] - bool is_audio_thread(const clap_host_t* host) - { - return self(host)->is_audio_thread(); - } +// Returns true if "this" thread is one of the audio threads. +// [thread-safe] +bool is_audio_thread(const clap_host_t* host) +{ + return self(host)->is_audio_thread(); +} - clap_host_thread_check_t threadcheck = - { - is_main_thread, is_audio_thread - }; +clap_host_thread_check_t threadcheck = {is_main_thread, is_audio_thread}; - static void resize_hints_changed(const clap_host_t* host) - { - self(host)->resize_hints_changed(); - } - static bool request_resize(const clap_host_t* host, uint32_t width, uint32_t height) - { - return self(host)->request_resize(width, height); - } - static bool request_show(const clap_host_t* host) - { - return self(host)->request_show(); - } - static bool request_hide(const clap_host_t* host) - { - return self(host)->request_hide(); - } - static void closed(const clap_host_t* host, bool was_destroyed) - { - self(host)->closed(was_destroyed); - } +static void resize_hints_changed(const clap_host_t* host) +{ + self(host)->resize_hints_changed(); +} +static bool request_resize(const clap_host_t* host, uint32_t width, uint32_t height) +{ + return self(host)->request_resize(width, height); +} +static bool request_show(const clap_host_t* host) +{ + return self(host)->request_show(); +} +static bool request_hide(const clap_host_t* host) +{ + return self(host)->request_hide(); +} +static void closed(const clap_host_t* host, bool was_destroyed) +{ + self(host)->closed(was_destroyed); +} - const clap_host_gui hostgui = { - resize_hints_changed,request_resize,request_show,request_hide,closed }; +const clap_host_gui hostgui = {resize_hints_changed, request_resize, request_show, request_hide, closed}; - const clap_host_timer_support hosttimer = { - /* register_timer */ [](const clap_host_t* host, uint32_t period_ms, clap_id* timer_id) -> bool { return self(host)->register_timer(period_ms, timer_id); }, - /* unregister_timer */ [](const clap_host_t* host, clap_id timer_id) -> bool { return self(host)->unregister_timer(timer_id); } - }; +const clap_host_timer_support hosttimer = { + /* register_timer */ [](const clap_host_t* host, uint32_t period_ms, clap_id* timer_id) -> bool + { return self(host)->register_timer(period_ms, timer_id); }, + /* unregister_timer */ + [](const clap_host_t* host, clap_id timer_id) -> bool + { return self(host)->unregister_timer(timer_id); }}; #if LIN - const clap_host_posix_fd_support hostposixfd = { - [](const clap_host_t *host, int fd, clap_posix_fd_flags_t flags) -> bool { return self(host)->register_fd(fd, flags);}, - [](const clap_host_t *host, int fd, clap_posix_fd_flags_t flags) -> bool { return self(host)->modify_fd(fd, flags);}, - [](const clap_host_t *host, int fd) -> bool { return self(host)->unregister_fd(fd);} - }; +const clap_host_posix_fd_support hostposixfd = { + [](const clap_host_t* host, int fd, clap_posix_fd_flags_t flags) -> bool + { return self(host)->register_fd(fd, flags); }, + [](const clap_host_t* host, int fd, clap_posix_fd_flags_t flags) -> bool + { return self(host)->modify_fd(fd, flags); }, + [](const clap_host_t* host, int fd) -> bool { return self(host)->unregister_fd(fd); }}; #endif - const clap_host_latency latency = { [](const clap_host_t* host) -> void { self(host)->latency_changed(); } }; +const clap_host_latency latency = {[](const clap_host_t* host) -> void + { self(host)->latency_changed(); }}; - static void tail_changed(const clap_host_t* host) - { - self(host)->tail_changed(); - } +static void tail_changed(const clap_host_t* host) +{ + self(host)->tail_changed(); +} - const clap_host_tail tail = { tail_changed }; +const clap_host_tail tail = {tail_changed}; - } +} // namespace HostExt - std::shared_ptr Plugin::createInstance(Clap::Library& library, size_t index, IHost* host) +std::shared_ptr Plugin::createInstance(Clap::Library& library, size_t index, IHost* host) +{ + if (library.plugins.size() > index) { - if (library.plugins.size() > index) - { - auto plug = std::shared_ptr(new Plugin(host)); - auto instance = library._pluginFactory->create_plugin(library._pluginFactory, plug->getClapHostInterface(), library.plugins[index]->id); - plug->connectClap(instance); + auto plug = std::shared_ptr(new Plugin(host)); + auto instance = library._pluginFactory->create_plugin( + library._pluginFactory, plug->getClapHostInterface(), library.plugins[index]->id); + plug->connectClap(instance); - return plug; - } - return nullptr; + return plug; } + return nullptr; +} - Plugin::Plugin(IHost* host) - : _host{ - CLAP_VERSION, +Plugin::Plugin(IHost* host) + : _host{CLAP_VERSION, this, "Clap-As-VST3-Wrapper", "defiant nerd", @@ -147,191 +140,189 @@ namespace Clap Plugin::clapExtension, Plugin::clapRequestRestart, Plugin::clapRequestProcess, - Plugin::clapRequestCallback - } - , _parentHost(host) - { + Plugin::clapRequestCallback} + , _parentHost(host) +{ +} - } +template +void getExtension(const clap_plugin_t* plugin, T& ref, const char* name) +{ + ref = static_cast(plugin->get_extension(plugin, name)); +} - template - void getExtension(const clap_plugin_t* plugin, T& ref, const char* name) - { - ref = static_cast(plugin->get_extension(plugin, name)); - } +void Plugin::connectClap(const clap_plugin_t* clap) +{ + _plugin = clap; - void Plugin::connectClap(const clap_plugin_t* clap) + // initialize the plugin + if (!_plugin->init(_plugin)) { - _plugin = clap; - - // initialize the plugin - if (!_plugin->init(_plugin)) - { - _plugin->destroy(_plugin); - _plugin = nullptr; - return; - } - - // if successful, query the extensions the wrapper might want to use - getExtension(_plugin, _ext._state, CLAP_EXT_STATE); - getExtension(_plugin, _ext._params, CLAP_EXT_PARAMS); - getExtension(_plugin, _ext._audioports, CLAP_EXT_AUDIO_PORTS); - getExtension(_plugin, _ext._noteports, CLAP_EXT_NOTE_PORTS); - getExtension(_plugin, _ext._midimap, CLAP_EXT_MIDI_MAPPINGS); - getExtension(_plugin, _ext._latency, CLAP_EXT_LATENCY); - getExtension(_plugin, _ext._render, CLAP_EXT_RENDER); - getExtension(_plugin, _ext._tail, CLAP_EXT_TAIL); - getExtension(_plugin, _ext._gui, CLAP_EXT_GUI); - getExtension(_plugin, _ext._timer, CLAP_EXT_TIMER_SUPPORT); + _plugin->destroy(_plugin); + _plugin = nullptr; + return; + } + + // if successful, query the extensions the wrapper might want to use + getExtension(_plugin, _ext._state, CLAP_EXT_STATE); + getExtension(_plugin, _ext._params, CLAP_EXT_PARAMS); + getExtension(_plugin, _ext._audioports, CLAP_EXT_AUDIO_PORTS); + getExtension(_plugin, _ext._noteports, CLAP_EXT_NOTE_PORTS); + getExtension(_plugin, _ext._midimap, CLAP_EXT_MIDI_MAPPINGS); + getExtension(_plugin, _ext._latency, CLAP_EXT_LATENCY); + getExtension(_plugin, _ext._render, CLAP_EXT_RENDER); + getExtension(_plugin, _ext._tail, CLAP_EXT_TAIL); + getExtension(_plugin, _ext._gui, CLAP_EXT_GUI); + getExtension(_plugin, _ext._timer, CLAP_EXT_TIMER_SUPPORT); #if LIN - getExtension(_plugin, _ext._posixfd, CLAP_EXT_POSIX_FD_SUPPORT); + getExtension(_plugin, _ext._posixfd, CLAP_EXT_POSIX_FD_SUPPORT); #endif - if (_ext._gui) - { - const char* api; + if (_ext._gui) + { + const char* api; #if WIN - api = CLAP_WINDOW_API_WIN32; + api = CLAP_WINDOW_API_WIN32; #endif #if MAC - api = CLAP_WINDOW_API_COCOA; + api = CLAP_WINDOW_API_COCOA; #endif #if LIN - api = CLAP_WINDOW_API_X11; + api = CLAP_WINDOW_API_X11; #endif - if (!_ext._gui->is_api_supported(_plugin, api, false)) - { - // disable GUI if not win32 - _ext._gui = nullptr; - } - } - } - - Plugin::~Plugin() - { - if (_plugin) + if (!_ext._gui->is_api_supported(_plugin, api, false)) { - _plugin->destroy(_plugin); - _plugin = nullptr; + // disable GUI if not win32 + _ext._gui = nullptr; } - } +} - void Plugin::schnick() +Plugin::~Plugin() +{ + if (_plugin) { - + _plugin->destroy(_plugin); + _plugin = nullptr; } +} +void Plugin::schnick() +{ +} - bool Plugin::initialize() +bool Plugin::initialize() +{ + fprintf(stderr, "Plugin Initialize\n"); + if (_ext._audioports) { - fprintf(stderr, "Plugin Initialize\n"); - if (_ext._audioports) - { - _parentHost->setupAudioBusses(_plugin, _ext._audioports); - } - if (_ext._noteports) - { - _parentHost->setupMIDIBusses(_plugin, _ext._noteports); - } - if (_ext._params) - { - _parentHost->setupParameters(_plugin, _ext._params); - } - return true; + _parentHost->setupAudioBusses(_plugin, _ext._audioports); } - - void Plugin::terminate() + if (_ext._noteports) { - _plugin->destroy(_plugin); - _plugin = nullptr; + _parentHost->setupMIDIBusses(_plugin, _ext._noteports); } - - void Plugin::setSampleRate(double sampleRate) + if (_ext._params) { - _audioSetup.sampleRate = sampleRate; + _parentHost->setupParameters(_plugin, _ext._params); } - void Plugin::setBlockSizes(uint32_t minFrames, uint32_t maxFrames) - { - _audioSetup.minFrames = minFrames; - _audioSetup.maxFrames = maxFrames; - } + _parentHost->setupWrapperSpecifics(_plugin); + return true; +} - bool Plugin::load(const clap_istream_t* stream) - { - if (_ext._state) - { - return _ext._state->load(_plugin, stream); - } - return false; - } +void Plugin::terminate() +{ + _plugin->destroy(_plugin); + _plugin = nullptr; +} - bool Plugin::save(const clap_ostream_t* stream) - { - if (_ext._state) - { - return _ext._state->save(_plugin, stream); - } - return false; - } +void Plugin::setSampleRate(double sampleRate) +{ + _audioSetup.sampleRate = sampleRate; +} - bool Plugin::activate() - { - return _plugin->activate(_plugin, _audioSetup.sampleRate, _audioSetup.minFrames, _audioSetup.maxFrames); - } +void Plugin::setBlockSizes(uint32_t minFrames, uint32_t maxFrames) +{ + _audioSetup.minFrames = minFrames; + _audioSetup.maxFrames = maxFrames; +} - void Plugin::deactivate() +bool Plugin::load(const clap_istream_t* stream) +{ + if (_ext._state) { - _plugin->deactivate(_plugin); + return _ext._state->load(_plugin, stream); } + return false; +} - bool Plugin::start_processing() +bool Plugin::save(const clap_ostream_t* stream) +{ + if (_ext._state) { - auto thisFn = AlwaysAudioThread(); - return _plugin->start_processing(_plugin); + return _ext._state->save(_plugin, stream); } + return false; +} - void Plugin::stop_processing() - { - auto thisFn = AlwaysAudioThread(); - _plugin->stop_processing(_plugin); - } +bool Plugin::activate() +{ + return _plugin->activate(_plugin, _audioSetup.sampleRate, _audioSetup.minFrames, + _audioSetup.maxFrames); +} + +void Plugin::deactivate() +{ + _plugin->deactivate(_plugin); +} - //void Plugin::process(const clap_process_t* data) - //{ - // auto thisFn = AlwaysAudioThread(); - // _plugin->process(_plugin, data); - //} +bool Plugin::start_processing() +{ + auto thisFn = AlwaysAudioThread(); + return _plugin->start_processing(_plugin); +} + +void Plugin::stop_processing() +{ + auto thisFn = AlwaysAudioThread(); + _plugin->stop_processing(_plugin); +} - const clap_plugin_gui_t* Plugin::getUI() +//void Plugin::process(const clap_process_t* data) +//{ +// auto thisFn = AlwaysAudioThread(); +// _plugin->process(_plugin, data); +//} + +const clap_plugin_gui_t* Plugin::getUI() +{ + if (_ext._gui) { - if (_ext._gui) + if (_ext._gui->is_api_supported(_plugin, CLAP_WINDOW_API_WIN32, false)) { - if (_ext._gui->is_api_supported(_plugin, CLAP_WINDOW_API_WIN32, false)) - { - // _ext._g - } + // _ext._g } - return nullptr; } + return nullptr; +} - void Plugin::latency_changed() - { - _parentHost->latency_changed(); - } +void Plugin::latency_changed() +{ + _parentHost->latency_changed(); +} - void Plugin::tail_changed() - { - _parentHost->tail_changed(); - } +void Plugin::tail_changed() +{ + _parentHost->tail_changed(); +} - void Plugin::log(clap_log_severity severity, const char* msg) +void Plugin::log(clap_log_severity severity, const char* msg) +{ + std::string n; + switch (severity) { - std::string n; - switch (severity) - { case CLAP_LOG_DEBUG: n.append("PLUGIN: DEBUG: "); break; @@ -357,134 +348,129 @@ namespace Clap _CrtDbgBreak(); #endif #if MAC - fprintf(stderr,"%s\n",msg); + fprintf(stderr, "%s\n", msg); #endif break; - } - n.append(msg); + } + n.append(msg); #if WIN32 - OutputDebugStringA(n.c_str()); - OutputDebugStringA("\n"); + OutputDebugStringA(n.c_str()); + OutputDebugStringA("\n"); #endif #if MAC - fprintf(stderr,"%s\n",n.c_str()); + fprintf(stderr, "%s\n", n.c_str()); #endif - } +} - bool Plugin::is_main_thread() const - { - return _main_thread_id == std::this_thread::get_id(); - } - - bool Plugin::is_audio_thread() const - { - if (this->_audio_thread_override > 0) - { - return true; - } - return !is_main_thread(); - } +bool Plugin::is_main_thread() const +{ + return _main_thread_id == std::this_thread::get_id(); +} - CLAP_NODISCARD Raise Plugin::AlwaysAudioThread() +bool Plugin::is_audio_thread() const +{ + if (this->_audio_thread_override > 0) { - return Raise(this->_audio_thread_override); + return true; } + return !is_main_thread(); +} +CLAP_NODISCARD Raise Plugin::AlwaysAudioThread() +{ + return Raise(this->_audio_thread_override); +} - void Plugin::param_rescan(clap_param_rescan_flags flags) - { - _parentHost->param_rescan(flags); - } +void Plugin::param_rescan(clap_param_rescan_flags flags) +{ + _parentHost->param_rescan(flags); +} - void Plugin::param_clear(clap_id param, clap_param_clear_flags flags) - { - _parentHost->param_clear(param, flags); - } - void Plugin::param_request_flush() - { - _parentHost->param_request_flush(); - } +void Plugin::param_clear(clap_id param, clap_param_clear_flags flags) +{ + _parentHost->param_clear(param, flags); +} +void Plugin::param_request_flush() +{ + _parentHost->param_request_flush(); +} - // Query an extension. - // [thread-safe] - const void* Plugin::clapExtension(const clap_host* host, const char* extension) - { - if (!strcmp(extension, CLAP_EXT_LOG)) - return &HostExt::log; - if (!strcmp(extension, CLAP_EXT_PARAMS)) - return &HostExt::params; - if (!strcmp(extension, CLAP_EXT_THREAD_CHECK)) - return &HostExt::threadcheck; - if (!strcmp(extension, CLAP_EXT_GUI)) - return &HostExt::hostgui; - if (!strcmp(extension, CLAP_EXT_TIMER_SUPPORT)) - return &HostExt::hosttimer; +// Query an extension. +// [thread-safe] +const void* Plugin::clapExtension(const clap_host* host, const char* extension) +{ + if (!strcmp(extension, CLAP_EXT_LOG)) return &HostExt::log; + if (!strcmp(extension, CLAP_EXT_PARAMS)) return &HostExt::params; + if (!strcmp(extension, CLAP_EXT_THREAD_CHECK)) return &HostExt::threadcheck; + if (!strcmp(extension, CLAP_EXT_GUI)) return &HostExt::hostgui; + if (!strcmp(extension, CLAP_EXT_TIMER_SUPPORT)) return &HostExt::hosttimer; #if LIN - if (!strcmp(extension, CLAP_EXT_POSIX_FD_SUPPORT)) - return &HostExt::hostposixfd; + if (!strcmp(extension, CLAP_EXT_POSIX_FD_SUPPORT)) return &HostExt::hostposixfd; #endif - if (!strcmp(extension, CLAP_EXT_LATENCY)) - return &HostExt::latency; - if (!strcmp(extension, CLAP_EXT_TAIL)) - { - return &HostExt::tail; - } - if (!strcmp(extension, CLAP_EXT_RENDER)) - { - // TODO: implement CLAP_EXT_RENDER - } - - return nullptr; - } - - // Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread. - // [thread-safe] - void Plugin::clapRequestCallback(const clap_host* host) + if (!strcmp(extension, CLAP_EXT_LATENCY)) return &HostExt::latency; + if (!strcmp(extension, CLAP_EXT_TAIL)) { - auto self = static_cast(host->host_data); - self->_parentHost->request_callback(); + return &HostExt::tail; } - - // Request the host to deactivate and then reactivate the plugin. - // The operation may be delayed by the host. - // [thread-safe] - void Plugin::clapRequestRestart(const clap_host* host) + if (!strcmp(extension, CLAP_EXT_RENDER)) { - auto self = static_cast(host->host_data); - self->_parentHost->restartPlugin(); + // TODO: implement CLAP_EXT_RENDER } - // Request the host to activate and start processing the plugin. - // This is useful if you have external IO and need to wake up the plugin from "sleep". - // [thread-safe] - void Plugin::clapRequestProcess(const clap_host* host) - { - // right now, I don't know how to communicate this to the host - // in VST3 you can't force processing... - } + return nullptr; +} - // Registers a periodic timer. +// Request the host to schedule a call to plugin->on_main_thread(plugin) on the main thread. +// [thread-safe] +void Plugin::clapRequestCallback(const clap_host* host) +{ + auto self = static_cast(host->host_data); + self->_parentHost->request_callback(); +} + +// Request the host to deactivate and then reactivate the plugin. +// The operation may be delayed by the host. +// [thread-safe] +void Plugin::clapRequestRestart(const clap_host* host) +{ + auto self = static_cast(host->host_data); + self->_parentHost->restartPlugin(); +} + +// Request the host to activate and start processing the plugin. +// This is useful if you have external IO and need to wake up the plugin from "sleep". +// [thread-safe] +void Plugin::clapRequestProcess(const clap_host* host) +{ + // right now, I don't know how to communicate this to the host + // in VST3 you can't force processing... +} + +// Registers a periodic timer. // The host may adjust the period if it is under a certain threshold. // 30 Hz should be allowed. // [main-thread] - bool Plugin::register_timer(uint32_t period_ms, clap_id* timer_id) - { - return _parentHost->register_timer(period_ms, timer_id); - } - bool Plugin::unregister_timer(clap_id timer_id) - { - return _parentHost->unregister_timer(timer_id); - } +bool Plugin::register_timer(uint32_t period_ms, clap_id* timer_id) +{ + return _parentHost->register_timer(period_ms, timer_id); +} +bool Plugin::unregister_timer(clap_id timer_id) +{ + return _parentHost->unregister_timer(timer_id); +} #if LIN - bool Plugin::register_fd(int fd, clap_posix_fd_flags_t flags) - { - return _parentHost->register_fd(fd, flags); - } - bool Plugin::modify_fd(int fd, clap_posix_fd_flags_t flags) - { - return _parentHost->modify_fd(fd, flags); - } - bool Plugin::unregister_fd(int fd) { return _parentHost->unregister_fd(fd); } +bool Plugin::register_fd(int fd, clap_posix_fd_flags_t flags) +{ + return _parentHost->register_fd(fd, flags); +} +bool Plugin::modify_fd(int fd, clap_posix_fd_flags_t flags) +{ + return _parentHost->modify_fd(fd, flags); +} +bool Plugin::unregister_fd(int fd) +{ + return _parentHost->unregister_fd(fd); +} #endif - } +} // namespace Clap diff --git a/src/clap_proxy.h b/src/clap_proxy.h index b9773ea8..e73a709a 100644 --- a/src/clap_proxy.h +++ b/src/clap_proxy.h @@ -28,195 +28,204 @@ namespace Clap { - class Plugin; - class Raise; +class Plugin; +class Raise; - // the IHost interface is being implemented by the actual wrapper class - class IHost - { - public: - virtual void mark_dirty() = 0; - virtual void restartPlugin() = 0; - virtual void request_callback() = 0; - - virtual void setupWrapperSpecifics(const clap_plugin_t* plugin) = 0; // called when a wrapper could scan for wrapper specific plugins - - virtual void setupAudioBusses(const clap_plugin_t* plugin, const clap_plugin_audio_ports_t* audioports) = 0; // called from initialize() to allow the setup of audio ports - virtual void setupMIDIBusses(const clap_plugin_t* plugin, const clap_plugin_note_ports_t* noteports) = 0; // called from initialize() to allow the setup of MIDI ports - virtual void setupParameters(const clap_plugin_t* plugin, const clap_plugin_params_t* params) = 0; - - virtual void param_rescan(clap_param_rescan_flags flags) = 0; // ext_host_params - virtual void param_clear(clap_id param, clap_param_clear_flags flags) = 0; - virtual void param_request_flush() = 0; - - virtual bool gui_can_resize() = 0; - virtual bool gui_request_resize(uint32_t width, uint32_t height) = 0; - virtual bool gui_request_show() = 0; - virtual bool gui_request_hide() = 0; - - virtual bool register_timer(uint32_t period_ms, clap_id* timer_id) = 0; - virtual bool unregister_timer(clap_id timer_id) = 0; +// the IHost interface is being implemented by the actual wrapper class +class IHost +{ + public: + virtual void mark_dirty() = 0; + virtual void restartPlugin() = 0; + virtual void request_callback() = 0; + + virtual void setupWrapperSpecifics( + const clap_plugin_t* plugin) = 0; // called when a wrapper could scan for wrapper specific plugins + + virtual void setupAudioBusses( + const clap_plugin_t* plugin, + const clap_plugin_audio_ports_t* + audioports) = 0; // called from initialize() to allow the setup of audio ports + virtual void setupMIDIBusses( + const clap_plugin_t* plugin, + const clap_plugin_note_ports_t* + noteports) = 0; // called from initialize() to allow the setup of MIDI ports + virtual void setupParameters(const clap_plugin_t* plugin, const clap_plugin_params_t* params) = 0; + + virtual void param_rescan(clap_param_rescan_flags flags) = 0; // ext_host_params + virtual void param_clear(clap_id param, clap_param_clear_flags flags) = 0; + virtual void param_request_flush() = 0; + + virtual bool gui_can_resize() = 0; + virtual bool gui_request_resize(uint32_t width, uint32_t height) = 0; + virtual bool gui_request_show() = 0; + virtual bool gui_request_hide() = 0; + + virtual bool register_timer(uint32_t period_ms, clap_id* timer_id) = 0; + virtual bool unregister_timer(clap_id timer_id) = 0; #if LIN - virtual bool register_fd(int fd, clap_posix_fd_flags_t flags) = 0; - virtual bool modify_fd(int fd, clap_posix_fd_flags_t flags) = 0; - virtual bool unregister_fd(int fd) = 0; + virtual bool register_fd(int fd, clap_posix_fd_flags_t flags) = 0; + virtual bool modify_fd(int fd, clap_posix_fd_flags_t flags) = 0; + virtual bool unregister_fd(int fd) = 0; #endif - virtual void latency_changed() = 0; + virtual void latency_changed() = 0; - virtual void tail_changed() = 0; + virtual void tail_changed() = 0; +}; - }; +struct ClapPluginExtensions; - struct ClapPluginExtensions; - - struct AudioSetup - { - double sampleRate = 44100.; - uint32_t minFrames = 0; - uint32_t maxFrames = 0; - }; +struct AudioSetup +{ + double sampleRate = 44100.; + uint32_t minFrames = 0; + uint32_t maxFrames = 0; +}; - struct ClapPluginExtensions - { - const clap_plugin_state_t* _state = nullptr; - const clap_plugin_params_t* _params = nullptr; - const clap_plugin_audio_ports_t* _audioports = nullptr; - const clap_plugin_gui_t* _gui = nullptr; - const clap_plugin_note_ports_t* _noteports = nullptr; - const clap_plugin_midi_mappings_t* _midimap = nullptr; - const clap_plugin_latency_t* _latency = nullptr; - const clap_plugin_render_t* _render = nullptr; - const clap_plugin_tail_t* _tail = nullptr; - const clap_plugin_timer_support_t* _timer = nullptr; +struct ClapPluginExtensions +{ + const clap_plugin_state_t* _state = nullptr; + const clap_plugin_params_t* _params = nullptr; + const clap_plugin_audio_ports_t* _audioports = nullptr; + const clap_plugin_gui_t* _gui = nullptr; + const clap_plugin_note_ports_t* _noteports = nullptr; + const clap_plugin_midi_mappings_t* _midimap = nullptr; + const clap_plugin_latency_t* _latency = nullptr; + const clap_plugin_render_t* _render = nullptr; + const clap_plugin_tail_t* _tail = nullptr; + const clap_plugin_timer_support_t* _timer = nullptr; #if LIN - const clap_plugin_posix_fd_support* _posixfd = nullptr; + const clap_plugin_posix_fd_support* _posixfd = nullptr; #endif +}; - }; +class Raise +{ + public: + Raise(std::atomic& counter) : ctx(counter) + { + ++ctx; + } + ~Raise() + { + ctx--; + } + + private: + std::atomic& ctx; +}; + +/// +/// Plugin is the `host` for the CLAP plugin instance +/// and the interface for the VST3 plugin wrapper +/// +class Plugin +{ + public: + static std::shared_ptr createInstance(Clap::Library& library, size_t index, IHost* host); - class Raise + protected: + // only the Clap::Library is allowed to create instances + Plugin(IHost* host); + const clap_host_t* getClapHostInterface() { - public: - Raise(std::atomic& counter) - : ctx(counter) - { - ++ctx; - } - ~Raise() - { - ctx--; - } - private: - std::atomic& ctx; - }; - - /// - /// Plugin is the `host` for the CLAP plugin instance - /// and the interface for the VST3 plugin wrapper - /// - class Plugin + return &_host; + } + void connectClap(const clap_plugin_t* clap); + + public: + Plugin(const Plugin&) = delete; + Plugin(Plugin&&) = delete; + Plugin& operator=(const Plugin&) = delete; + Plugin& operator=(Plugin&&) = delete; + ~Plugin(); + + void schnick(); + bool initialize(); + void terminate(); + void setSampleRate(double sampleRate); + void setBlockSizes(uint32_t minFrames, uint32_t maxFrames); + + bool load(const clap_istream_t* stream); + bool save(const clap_ostream_t* stream); + bool activate(); + void deactivate(); + bool start_processing(); + void stop_processing(); + // void process(const clap_process_t* data); + const clap_plugin_gui_t* getUI(); + + ClapPluginExtensions _ext; + const clap_plugin_t* _plugin = nullptr; + void log(clap_log_severity severity, const char* msg); + + // threadcheck + bool is_main_thread() const; + bool is_audio_thread() const; + + // param + void param_rescan(clap_param_rescan_flags flags); + void param_clear(clap_id param, clap_param_clear_flags flags); + void param_request_flush(); + + // latency + void latency_changed(); + + // tail + void tail_changed(); + + // hostgui + void resize_hints_changed() { - public: - static std::shared_ptr createInstance(Clap::Library& library, size_t index, IHost* host); - protected: - // only the Clap::Library is allowed to create instances - Plugin(IHost* host); - const clap_host_t* getClapHostInterface() { return &_host; } - void connectClap(const clap_plugin_t* clap); - public: - Plugin(const Plugin&) = delete; - Plugin(Plugin&&) = delete; - Plugin& operator=(const Plugin&) = delete; - Plugin& operator=(Plugin&&) = delete; - ~Plugin(); - - void schnick(); - bool initialize(); - void terminate(); - void setSampleRate(double sampleRate); - void setBlockSizes(uint32_t minFrames, uint32_t maxFrames); - - bool load(const clap_istream_t* stream); - bool save(const clap_ostream_t* stream); - bool activate(); - void deactivate(); - bool start_processing(); - void stop_processing(); - // void process(const clap_process_t* data); - const clap_plugin_gui_t* getUI(); - - ClapPluginExtensions _ext; - const clap_plugin_t* _plugin = nullptr; - void log(clap_log_severity severity, const char* msg); - - // threadcheck - bool is_main_thread() const; - bool is_audio_thread() const; - - // param - void param_rescan(clap_param_rescan_flags flags); - void param_clear(clap_id param, clap_param_clear_flags flags); - void param_request_flush(); - - // latency - void latency_changed(); - - // tail - void tail_changed(); - - // hostgui - void resize_hints_changed() - { - } - bool request_resize(uint32_t width, uint32_t height) - { - if (_parentHost->gui_can_resize()) - { - _parentHost->gui_request_resize(width, height); - return true; - } - return false; - } - bool request_show() - { - return _parentHost->gui_request_show(); - } - bool request_hide() + } + bool request_resize(uint32_t width, uint32_t height) + { + if (_parentHost->gui_can_resize()) { - return false; - } - void closed(bool was_destroyed) - { + _parentHost->gui_request_resize(width, height); + return true; } + return false; + } + bool request_show() + { + return _parentHost->gui_request_show(); + } + bool request_hide() + { + return false; + } + void closed(bool was_destroyed) + { + } - // clap_timer support - bool register_timer(uint32_t period_ms, clap_id* timer_id); - bool unregister_timer(clap_id timer_id); + // clap_timer support + bool register_timer(uint32_t period_ms, clap_id* timer_id); + bool unregister_timer(clap_id timer_id); #if LIN - bool register_fd(int fd, clap_posix_fd_flags_t flags); - bool modify_fd(int fd, clap_posix_fd_flags_t flags); - bool unregister_fd(int fd); + bool register_fd(int fd, clap_posix_fd_flags_t flags); + bool modify_fd(int fd, clap_posix_fd_flags_t flags); + bool unregister_fd(int fd); #endif - CLAP_NODISCARD Raise AlwaysAudioThread(); - private: - - static const void* clapExtension(const clap_host* host, const char* extension); - static void clapRequestCallback(const clap_host* host); - static void clapRequestRestart(const clap_host* host); - static void clapRequestProcess(const clap_host* host); - - //static bool clapIsMainThread(const clap_host* host); - //static bool clapIsAudioThread(const clap_host* host); - - - clap_host_t _host; // the host_t structure for the proxy - IHost* _parentHost = nullptr; - const std::thread::id _main_thread_id = std::this_thread::get_id(); - std::atomic _audio_thread_override = 0; - AudioSetup _audioSetup; - }; -} \ No newline at end of file + CLAP_NODISCARD Raise AlwaysAudioThread(); + + private: + static const void* clapExtension(const clap_host* host, const char* extension); + static void clapRequestCallback(const clap_host* host); + static void clapRequestRestart(const clap_host* host); + static void clapRequestProcess(const clap_host* host); + + //static bool clapIsMainThread(const clap_host* host); + //static bool clapIsAudioThread(const clap_host* host); + + clap_host_t _host; // the host_t structure for the proxy + IHost* _parentHost = nullptr; + const std::thread::id _main_thread_id = std::this_thread::get_id(); + std::atomic _audio_thread_override = 0; + AudioSetup _audioSetup; +}; +} // namespace Clap \ No newline at end of file diff --git a/src/detail/auv2/auv2_base_classes.h b/src/detail/auv2/auv2_base_classes.h new file mode 100644 index 00000000..ff3f1d45 --- /dev/null +++ b/src/detail/auv2/auv2_base_classes.h @@ -0,0 +1,82 @@ +/* + * document + */ + +#pragma once + +#include +#include +#include + +#include +#include "auv2_shared.h" +#include + +namespace free_audio::auv2_wrapper +{ + +// ------------------------------------------------------------------------------------------------- + +class ClapWrapper_AUV2_Effect : public ausdk::AUEffectBase +{ + using Base = ausdk::AUEffectBase; + ClapBridge bridge; + + public: + explicit ClapWrapper_AUV2_Effect(const std::string &clapname, const std::string &clapid, int clapidx, + AudioComponentInstance ci) + : Base{ci, true}, bridge(clapname, clapid, clapidx) + { + std::cout << "[clap-wrapper] auv2: creating effect" << std::endl; + std::cout << "[clap-wrapper] auv2: id='" << clapid << "' index=" << clapidx << std::endl; + + bridge.initialize(); + } +}; + +class ClapWrapper_AUV2_NoteEffect : public ausdk::AUMIDIEffectBase +{ + using Base = ausdk::AUMIDIEffectBase; + ClapBridge bridge; + + public: + explicit ClapWrapper_AUV2_NoteEffect(const std::string &clapname, const std::string &clapid, + int clapidx, AudioComponentInstance ci) + : Base{ci, true}, bridge(clapname, clapid, clapidx) + { + std::cout << "[clap-wrapper] auv2: creating note effect" << std::endl; + std::cout << "[clap-wrapper] auv2: id='" << clapid << "' index=" << clapidx << std::endl; + + bridge.initialize(); + } +}; + +// ------------------------------------------------------------------------------------------------- + +class ClapWrapper_AUV2_Instrument : public ausdk::MusicDeviceBase +{ + using Base = ausdk::MusicDeviceBase; + ClapBridge bridge; + + public: + explicit ClapWrapper_AUV2_Instrument(const std::string &clapname, const std::string &clapid, + int clapidx, AudioComponentInstance ci) + : Base{ci, 0, 1}, bridge(clapname, clapid, clapidx) + { + std::cout << "[clap-wrapper] auv2: creating instrument" << std::endl; + std::cout << "[clap-wrapper] auv2: id='" << clapid << "' index=" << clapidx << std::endl; + + bridge.initialize(); + } + + bool StreamFormatWritable(AudioUnitScope, AudioUnitElement) override + { + return true; + } + + bool CanScheduleParameters() const override + { + return false; + } +}; +} // namespace free_audio::auv2_wrapper \ No newline at end of file diff --git a/src/detail/auv2/auv2_shared.h b/src/detail/auv2/auv2_shared.h new file mode 100644 index 00000000..99ce22df --- /dev/null +++ b/src/detail/auv2/auv2_shared.h @@ -0,0 +1,84 @@ + +#pragma once + +#include "detail/clap/fsutil.h" +#include + +namespace free_audio::auv2_wrapper +{ +struct ClapBridge +{ + std::string _clapname; + std::string _clapid; + int _idx; + + Clap::Library _library; + + const clap_plugin_descriptor_t *_desc{nullptr}; + + ClapBridge(const std::string &clapname, const std::string &clapid, int idx) + : _clapname(clapname), _clapid(clapid), _idx(idx) + { + std::cout << "[clap-wraper] auv2: creating clap bridge nm=" << clapname << " id=" << clapid + << " idx=" << idx << std::endl; + } + + void initialize() + { + if (!_library.hasEntryPoint()) + { + if (_clapname.empty()) + { + std::cout << "[ERROR] _clapname (" << _clapname << ") empty and no internal entry point" + << std::endl; + } + bool loaded{false}; + auto csp = Clap::getValidCLAPSearchPaths(); + for (auto &cs : csp) + { + if (fs::is_directory(cs / (_clapname + ".clap"))) + if (_library.load(_clapname.c_str())) + { + std::cout << "[clap-wrapper] auv2 loaded clap from " << cs.u8string() << std::endl; + loaded = true; + break; + } + } + if (!loaded) + { + std::cout << "[ERROR] cannot load clap" << std::endl; + return; + } + } + + if (_clapid.empty()) + { + if (_idx < 0 || _idx >= _library.plugins.size()) + { + std::cout << "[ERROR] cannot load by index" << std::endl; + return; + } + _desc = _library.plugins[_idx]; + } + else + { + for (auto *d : _library.plugins) + { + if (strcmp(d->id, _clapid.c_str()) == 0) + { + _desc = d; + } + } + } + + if (!_desc) + { + std::cout << "[ERROR] cannot determine plugin description" << std::endl; + return; + } + + std::cout << "[clap-wrapper] auv2: Initialized '" << _desc->id << "' / '" << _desc->name << "'" + << std::endl; + } +}; +} // namespace free_audio::auv2_wrapper \ No newline at end of file diff --git a/src/detail/auv2/build-helper/auv2_infoplist_top.in b/src/detail/auv2/build-helper/auv2_infoplist_top.in new file mode 100644 index 00000000..58a4d149 --- /dev/null +++ b/src/detail/auv2/build-helper/auv2_infoplist_top.in @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${AUV2_OUTPUT_NAME} + CFBundleIdentifier + ${AUV2_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${AUV2_OUTPUT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + ${AUV2_BUNDLE_VERSION} + CFBundleSignature + ???? + CFBundleVersion + ${AUV2_BUNDLE_VERSION} + NSPrincipalClass + + NSHighResolutionCapable + diff --git a/src/detail/auv2/build-helper/build-helper.cpp b/src/detail/auv2/build-helper/build-helper.cpp new file mode 100644 index 00000000..06b59521 --- /dev/null +++ b/src/detail/auv2/build-helper/build-helper.cpp @@ -0,0 +1,313 @@ +#include +#include +#include +#include + +#include "detail/clap/fsutil.h" + +#if MACOS_USE_STD_FILESYSTEM +#include +namespace fs = std::filesystem; +#else +#include "ghc/filesystem.hpp" +namespace fs = ghc::filesystem; +#endif + +struct auInfo +{ + std::string name, vers, type, subt, manu, manunm, clapid, desc, clapname; + + const std::string factoryBase{"wrapAsAUV2_inst"}; + + void writePListFragment(std::ostream &of, int idx) const + { + if (!clapid.empty()) + { + of << " \n"; + } + else + { + of << " \n"; + } + of << " \n" + << " name\n" + << " " << manunm << ": " << name << "\n" + << " description\n" + << " " << desc << "\n" + << " factoryFunction\n" + << " " << factoryBase << idx << "Factory" + << "\n" + << " manufacturer\n" + << " " << manu << "\n" + << " subtype\n" + << " " << subt << "\n" + << " type\n" + << " " << type << "\n" + << " version\n" + << " 1\n" + << " sandboxSafe\n" + << " \n" + << " resourceUsage\n" + << " \n" + << " network.client\n" + << " \n" + << " temporary-exception.files.all.read-write\n" + << " \n" + << " \n" + << " \n"; + } +}; + +bool buildUnitsFromClap(const std::string &clapfile, const std::string &clapname, std::string &manu, + std::string &manuName, std::vector &units) +{ + Clap::Library loader; + if (!loader.load(clapfile.c_str())) + { + std::cout << "[ERROR] library.load of clapfile failed" << std::endl; + return false; + } + + int idx{0}; + + if (manu.empty() && loader._pluginFactoryAUv2Info == nullptr) + { + std::cout << "[ERROR] No manufacturer provider and no auv2 info available" << std::endl; + return false; + } + + if (manu.empty()) + { + manu = loader._pluginFactoryAUv2Info->manufacturer_code; + manuName = loader._pluginFactoryAUv2Info->manufacturer_name; + std::cout << " - using factor manufacturer '" << manuName << "' (" << manu << ")" << std::endl; + } + + static const char *encoder = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"; + for (const auto *clapPlug : loader.plugins) + { + auto u = auInfo(); + u.name = clapPlug->name; + u.clapname = clapname; + u.clapid = clapPlug->id; + u.vers = clapPlug->version; + u.desc = clapPlug->description; + + static_assert(sizeof(size_t) == 8); + size_t idHash = std::hash{}(clapPlug->id); + std::string stH; + // We have to make an ascii-representable 4 char string. Here's a way I guess. + for (int i = 0; i < 4; ++i) + { + auto q = idHash & ((1 << 6) - 1); + stH += encoder[q]; + idHash = idHash >> 9; // mix it up a bit + } + + u.subt = stH; + u.manu = manu; + u.manunm = manuName; + + auto f = clapPlug->features[0]; + if (f == nullptr || strcmp(f, CLAP_PLUGIN_FEATURE_INSTRUMENT) == 0) + { + u.type = "aumu"; + } + else if (strcmp(f, CLAP_PLUGIN_FEATURE_AUDIO_EFFECT) == 0) + { + u.type = "aufx"; + } + else if (strcmp(f, CLAP_PLUGIN_FEATURE_NOTE_EFFECT) == 0) + { + u.type = "aumi"; + } + else + { + std::cout << "[WARNING] can't determine instrument type. Using aumu" << std::endl; + u.type = "aumu"; + } + + if (loader._pluginFactoryAUv2Info) + { + clap_plugin_info_as_auv2_t v2inf; + auto res = + loader._pluginFactoryAUv2Info->get_auv2_info(loader._pluginFactoryAUv2Info, idx, &v2inf); + if (v2inf.au_type[0] != 0) + { + u.type = v2inf.au_type; + } + if (v2inf.au_subt[0] != 0) + { + u.subt = v2inf.au_subt; + } + } + + units.push_back(u); + idx++; + } + return true; +} + +int main(int argc, char **argv) +{ + if (argc < 2) return 1; + + std::cout << "clap-wrapper: auv2 configuration tool starting\n"; + + std::vector units; + if (std::string(argv[1]) == "--explicit") + { + if (argc != 8) + { + std::cout << "[ERROR] Configuration incorrect. Got " << argc << " arguments in explicit" + << std::endl; + return 5; + } + int idx = 2; + auInfo u; + u.name = std::string(argv[idx++]); + u.clapname = u.name; + u.vers = std::string(argv[idx++]); + u.type = std::string(argv[idx++]); + u.subt = std::string(argv[idx++]); + u.manu = std::string(argv[idx++]); + u.manunm = std::string(argv[idx++]); + u.desc = u.name + " CLAP to AU Wrapper"; + + std::cout << " - single plugin explicit mode: " << u.name << " (" << u.type << "/" << u.subt << ")" + << std::endl; + units.push_back(u); + } + else if (std::string(argv[1]) == "--fromclap") + { + if (argc < 4) + { + std::cout << "[ERROR] Configuration incorrect. Got " << argc << " arguments in fromclap" + << std::endl; + return 6; + } + int idx = 2; + auto clapname = std::string(argv[idx++]); + auto clapfile = std::string(argv[idx++]); + auto mcode = (idx < argc) ? std::string(argv[idx++]) : std::string(); + auto mname = (idx < argc) ? std::string(argv[idx++]) : std::string(); + + try + { + auto p = fs::path{clapfile}; + // This is a hack for now - we get to the dll + p = p.parent_path().parent_path().parent_path(); + clapfile = p.u8string(); + } + catch (const fs::filesystem_error &e) + { + std::cout << "[ERROR] cant get path " << e.what() << std::endl; + return 3; + } + + std::cout << " - building information from CLAP directly\n" + << " - source clap: '" << clapfile << "'" << std::endl; + + if (!buildUnitsFromClap(clapfile, clapname, mcode, mname, units)) + { + std::cout << "[ERROR] Can't build units from CLAP" << std::endl; + return 4; + } + + if (units.empty()) + { + std::cout << "[ERROR] No units from clap file\n"; + return 5; + } + + std::cout << " - clap file produced " << units.size() << " units" << std::endl; + } + else + { + std::cout << "[ERROR] Unknown Mode : " << argv[1] << std::endl; + return 2; + } + + std::cout << " - generating auv2_Info.plist from auv2_infoplist_top" << std::endl; + std::ifstream intop("auv2_infoplist_top"); + if (!intop.is_open()) + { + std::cerr << "[ERROR] Unable to open pre-generated file auv2_infoplist_top" << std::endl; + return 1; + } + + std::ofstream of("auv2_Info.plist"); + if (!of.is_open()) + { + std::cerr << "[ERROR] Unable to open output file auv2_Info.plist" << std::endl; + } + of << intop.rdbuf(); + + of << " AudioComponents\n \n"; + int idx{0}; + for (const auto &u : units) + { + std::cout << " + " << u.name << " (" << u.type << "/" << u.subt << ") by " << u.manunm << " (" + << u.manu << ")" << std::endl; + u.writePListFragment(of, idx++); + } + of << " \n"; + of << " \n\n"; + of.close(); + std::cout << " - auv2_Info.plist generated" << std::endl; + + std::cout << " - generating generated_entrypoints.hxx" << std::endl; + std::ofstream cppf("generated_entrypoints.hxx"); + if (!cppf.is_open()) + { + std::cout << "[ERROR] Unable to open generated_endpoints.hxx" << std::endl; + return 1; + } + + cppf << "#pragma once\n"; + cppf << "#include \"detail/auv2/auv2_base_classes.h\"\n\n"; + + idx = 0; + for (const auto &u : units) + { + auto on = u.factoryBase + std::to_string(idx); + + auto args = std::string("\"") + u.clapname + "\", \"" + u.clapid + "\", " + std::to_string(idx); + + if (u.type == "aumu") + { + std::cout << " + " << u.name << " entry " << on << " from ClapWrapper_AUV2_Instrument" + << std::endl; + cppf << "struct " << on << " : free_audio::auv2_wrapper::ClapWrapper_AUV2_Instrument {\n" + << " " << on << "(AudioComponentInstance ci) :\n" + << " free_audio::auv2_wrapper::ClapWrapper_AUV2_Instrument(" << args << ", ci) {}" + << "};\n" + << "AUSDK_COMPONENT_ENTRY(ausdk::AUMusicDeviceFactory, " << on << ");\n"; + } + else if (u.type == "aumi") + { + std::cout << " + " << u.name << " entry " << on << " from ClapWrapper_AUV2_NoteEffect" + << std::endl; + cppf << "struct " << on << " : free_audio::auv2_wrapper::ClapWrapper_AUV2_NoteEffect {\n" + << " " << on << "(AudioComponentInstance ci) :\n" + << " free_audio::auv2_wrapper::ClapWrapper_AUV2_NoteEffect(" << args << ", ci) {}" + << "};\n" + << "AUSDK_COMPONENT_ENTRY(ausdk::AUBaseFactory , " << on << ");\n"; + } + else if (u.type == "aufx") + { + std::cout << " + " << u.name << " entry " << on << " from ClapWrapper_AUV2_Effect" << std::endl; + cppf << "struct " << on << " : free_audio::auv2_wrapper::ClapWrapper_AUV2_Effect {\n" + << " " << on << "(AudioComponentInstance ci) :\n" + << " free_audio::auv2_wrapper::ClapWrapper_AUV2_Effect(" << args << ", ci) {}" + << "};\n" + << "AUSDK_COMPONENT_ENTRY(ausdk::AUBaseFactory, " << on << ");\n"; + } + + idx++; + } + cppf.close(); + std::cout << " - generated_entrypoints.hxx generated" << std::endl; + + return 0; +} diff --git a/src/detail/clap/automation.h b/src/detail/clap/automation.h index 1d5c8d81..c6a30179 100644 --- a/src/detail/clap/automation.h +++ b/src/detail/clap/automation.h @@ -4,12 +4,14 @@ namespace Clap { - class IAutomation - { - public: - virtual void onBeginEdit(clap_id id) = 0; - virtual void onPerformEdit(const clap_event_param_value_t* value) = 0; - virtual void onEndEdit(clap_id id) = 0; - virtual ~IAutomation() {} - }; -} \ No newline at end of file +class IAutomation +{ + public: + virtual void onBeginEdit(clap_id id) = 0; + virtual void onPerformEdit(const clap_event_param_value_t* value) = 0; + virtual void onEndEdit(clap_id id) = 0; + virtual ~IAutomation() + { + } +}; +} // namespace Clap \ No newline at end of file diff --git a/src/detail/clap/fsutil.cpp b/src/detail/clap/fsutil.cpp index cb9260e5..d84246b3 100644 --- a/src/detail/clap/fsutil.cpp +++ b/src/detail/clap/fsutil.cpp @@ -24,311 +24,315 @@ #include #endif - namespace Clap { #if WIN - std::string getEnvVariable(const char* varname) - { - char* val; - size_t len; - auto err = _dupenv_s(&val, &len, varname); - if (err) return std::string(); - if (val == nullptr) return std::string(); - std::string result(val); - free(val); - return result; - } +std::string getEnvVariable(const char *varname) +{ + char *val; + size_t len; + auto err = _dupenv_s(&val, &len, varname); + if (err) return std::string(); + if (val == nullptr) return std::string(); + std::string result(val); + free(val); + return result; +} #endif - std::vector getValidCLAPSearchPaths() - { - std::vector res; +std::vector getValidCLAPSearchPaths() +{ + std::vector res; #if MAC - extern std::vector getMacCLAPSearchPaths(); - res = getMacCLAPSearchPaths(); - // getSystemPaths(res); + extern std::vector getMacCLAPSearchPaths(); + res = getMacCLAPSearchPaths(); + // getSystemPaths(res); #endif #if LIN - res.emplace_back("/usr/lib/clap"); - res.emplace_back(fs::path(getenv("HOME")) / fs::path(".clap")); + res.emplace_back("/usr/lib/clap"); + res.emplace_back(fs::path(getenv("HOME")) / fs::path(".clap")); #endif #if WIN + { + // I think this should use SHGetKnownFilderLocation but I don't know windows well enough + auto p = getEnvVariable("COMMONPROGRAMFILES"); + if (!p.empty()) { - // I think this should use SHGetKnownFilderLocation but I don't know windows well enough - auto p = getEnvVariable("COMMONPROGRAMFILES"); - if (!p.empty()) - { - res.emplace_back(fs::path{ p } / "CLAP"); - } - auto q = getEnvVariable("LOCALAPPDATA"); - if (!q.empty()) - { - res.emplace_back(fs::path{ q } / "Programs" / "Common" / "CLAP"); - } + res.emplace_back(fs::path{p} / "CLAP"); } - auto cp = getEnvVariable("CLAP_PATH"); - auto sep = ';'; -#else - std::string cp; - auto p = getenv("CLAP_PATH"); - if (p) + auto q = getEnvVariable("LOCALAPPDATA"); + if (!q.empty()) { - cp = std::string(p); + res.emplace_back(fs::path{q} / "Programs" / "Common" / "CLAP"); } - auto sep = ':'; + } + auto cp = getEnvVariable("CLAP_PATH"); + auto sep = ';'; +#else + std::string cp; + auto p = getenv("CLAP_PATH"); + if (p) + { + cp = std::string(p); + } + auto sep = ':'; #endif - if (cp.empty()) + if (cp.empty()) + { + size_t pos; + while ((pos = cp.find(sep)) != std::string::npos) { - size_t pos; - while ((pos = cp.find(sep)) != std::string::npos) - { - auto item = cp.substr(0, pos); - cp = cp.substr(pos + 1); - res.emplace_back(fs::path{ item }); - } - if (cp.size()) - res.emplace_back(fs::path{ cp }); + auto item = cp.substr(0, pos); + cp = cp.substr(pos + 1); + res.emplace_back(fs::path{item}); } - - return res; + if (cp.size()) res.emplace_back(fs::path{cp}); } - bool Library::load(const char* name) - { + return res; +} + +bool Library::load(const char *name) +{ #if MAC - _pluginEntry = nullptr; + _pluginEntry = nullptr; - auto cs = CFStringCreateWithBytes(kCFAllocatorDefault, (uint8_t *)name, strlen(name), - kCFStringEncodingUTF8, false); - auto bundleURL = - CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cs, kCFURLPOSIXPathStyle, true); + auto cs = CFStringCreateWithBytes(kCFAllocatorDefault, (uint8_t *)name, strlen(name), + kCFStringEncodingUTF8, false); + auto bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cs, kCFURLPOSIXPathStyle, true); - _bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL); - CFRelease(bundleURL); - CFRelease(cs); + _bundle = CFBundleCreate(kCFAllocatorDefault, bundleURL); + CFRelease(bundleURL); + CFRelease(cs); - if (!_bundle) { - return false; - } + if (!_bundle) + { + return false; + } - auto db = CFBundleGetDataPointerForName(_bundle, CFSTR("clap_entry")); + auto db = CFBundleGetDataPointerForName(_bundle, CFSTR("clap_entry")); - _pluginEntry = (const clap_plugin_entry *)db; + _pluginEntry = (const clap_plugin_entry *)db; - setupPluginsFromPluginEntry(name); - return _pluginEntry != nullptr; + setupPluginsFromPluginEntry(name); + return _pluginEntry != nullptr; #endif #if WIN - if (_handle && !_selfcontained) + if (_handle && !_selfcontained) + { + if (_pluginEntry) { - if (_pluginEntry) - { - _pluginEntry->deinit(); - } - FreeLibrary(_handle); + _pluginEntry->deinit(); } - _handle = 0; - _pluginEntry = nullptr; - _handle = LoadLibraryA(name); - if (_handle) + FreeLibrary(_handle); + } + _handle = 0; + _pluginEntry = nullptr; + _handle = LoadLibraryA(name); + if (_handle) + { + if (!getEntryFunction(_handle, name)) { - if (!getEntryFunction(_handle, name)) - { - FreeLibrary(_handle); - _handle = NULL; - } + FreeLibrary(_handle); + _handle = NULL; } + } - return _handle != 0; + return _handle != 0; #endif #if LIN - int *iptr; + int *iptr; - _handle = dlopen(name, RTLD_LOCAL | RTLD_LAZY); - if (!_handle) - return false; + _handle = dlopen(name, RTLD_LOCAL | RTLD_LAZY); + if (!_handle) return false; - iptr = (int *)dlsym(_handle, "clap_entry"); - if (!iptr) - return false; + iptr = (int *)dlsym(_handle, "clap_entry"); + if (!iptr) return false; - _pluginEntry = (const clap_plugin_entry_t *)iptr; - setupPluginsFromPluginEntry(name); - return true; + _pluginEntry = (const clap_plugin_entry_t *)iptr; + setupPluginsFromPluginEntry(name); + return true; #endif +} + +const clap_plugin_info_as_vst3_t *Library::get_vst3_info(uint32_t index) +{ + if (_pluginFactoryVst3Info && _pluginFactoryVst3Info->get_vst3_info) + { + return _pluginFactoryVst3Info->get_vst3_info(_pluginFactoryVst3Info, index); } + return nullptr; +} - const clap_plugin_info_as_vst3_t* Library::get_vst3_info(uint32_t index) +#if WIN +bool Library::getEntryFunction(HMODULE handle, const char *path) +{ + if (handle) { - if (_pluginFactoryVst3Info && _pluginFactoryVst3Info->get_vst3_info) + _pluginEntry = reinterpret_cast(GetProcAddress(handle, "clap_entry")); + if (_pluginEntry) { - return _pluginFactoryVst3Info->get_vst3_info(_pluginFactoryVst3Info, index); + setupPluginsFromPluginEntry(path); } - return nullptr; } + return (_pluginEntry && !plugins.empty()); +} +#endif -#if WIN - bool Library::getEntryFunction(HMODULE handle, const char* path) +void Library::setupPluginsFromPluginEntry(const char *path) +{ + if (clap_version_is_compatible(_pluginEntry->clap_version)) { - if (handle) + if (_pluginEntry->init(path)) { - _pluginEntry = reinterpret_cast(GetProcAddress(handle, "clap_entry")); - if (_pluginEntry) + _pluginFactory = + static_cast(_pluginEntry->get_factory(CLAP_PLUGIN_FACTORY_ID)); + _pluginFactoryVst3Info = static_cast( + _pluginEntry->get_factory(CLAP_PLUGIN_FACTORY_INFO_VST3)); + _pluginFactoryAUv2Info = static_cast( + _pluginEntry->get_factory(CLAP_PLUGIN_FACTORY_INFO_AUV2)); + + // detect plugins that do not check the CLAP_PLUGIN_FACTORY_ID + if ((void *)_pluginFactory == (void *)_pluginFactoryVst3Info) { - setupPluginsFromPluginEntry(path); + _pluginFactoryVst3Info = nullptr; + _pluginFactoryAUv2Info = nullptr; } - } - return (_pluginEntry && !plugins.empty()); - } -#endif - void Library::setupPluginsFromPluginEntry(const char* path) { - if (clap_version_is_compatible(_pluginEntry->clap_version)) { - if (_pluginEntry->init(path)) { - _pluginFactory = - static_cast(_pluginEntry->get_factory(CLAP_PLUGIN_FACTORY_ID)); - _pluginFactoryVst3Info = - static_cast(_pluginEntry->get_factory(CLAP_PLUGIN_FACTORY_INFO_VST3)); - - // detect plugins that do not check the CLAP_PLUGIN_FACTORY_ID - if ((void*)_pluginFactory == (void*)_pluginFactoryVst3Info) - { - _pluginFactoryVst3Info = nullptr; - } - - auto count = _pluginFactory->get_plugin_count(_pluginFactory); - - for (decltype(count) i = 0; i < count; ++i) { - auto desc = _pluginFactory->get_plugin_descriptor(_pluginFactory, i); - if (clap_version_is_compatible(desc->clap_version)) { - plugins.push_back(desc); - } else { - // incompatible - } - } + auto count = _pluginFactory->get_plugin_count(_pluginFactory); + + for (decltype(count) i = 0; i < count; ++i) + { + auto desc = _pluginFactory->get_plugin_descriptor(_pluginFactory, i); + if (clap_version_is_compatible(desc->clap_version)) + { + plugins.push_back(desc); + } + else + { + // incompatible } - } + } + } } +} #if WIN || LIN - // This is a small stub to resolve the self dll. MacOs uses a different approach - // in sharedLibraryBundlePath - static void ffeomwe() {} +// This is a small stub to resolve the self dll. MacOs uses a different approach +// in sharedLibraryBundlePath +static void ffeomwe() +{ +} #endif - Library::Library() - { +Library::Library() +{ #if WIN - static TCHAR modulename[2048]; - HMODULE selfmodule; - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)ffeomwe, &selfmodule)) - { - auto size = GetModuleFileName(selfmodule, modulename, 2048); - (void)size; - } - if (selfmodule) + static TCHAR modulename[2048]; + HMODULE selfmodule; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)ffeomwe, &selfmodule)) + { + auto size = GetModuleFileName(selfmodule, modulename, 2048); + (void)size; + } + if (selfmodule) + { + if (this->getEntryFunction(selfmodule, (const char *)modulename)) { - if (this->getEntryFunction(selfmodule, (const char*)modulename)) - { - _selfcontained = true; - } + _selfcontained = true; } + } #endif #if LIN - Dl_info info; - if (dladdr(reinterpret_cast(&ffeomwe), &info) && - info.dli_fname[0]) + Dl_info info; + if (dladdr(reinterpret_cast(&ffeomwe), &info) && info.dli_fname[0]) + { + auto lhandle = dlopen(info.dli_fname, RTLD_LOCAL | RTLD_LAZY); + if (lhandle) { - auto lhandle = dlopen(info.dli_fname, RTLD_LOCAL | RTLD_LAZY); - if (lhandle) + auto liptr = (int *)dlsym(_handle, "clap_entry"); + if (liptr) { - auto liptr = (int *)dlsym(_handle, "clap_entry"); - if (liptr) - { - _handle = lhandle; // as a result the Library dtor will dlclose me - _pluginEntry = (const clap_plugin_entry_t *)liptr; - _selfcontained = true; + _handle = lhandle; // as a result the Library dtor will dlclose me + _pluginEntry = (const clap_plugin_entry_t *)liptr; + _selfcontained = true; - setupPluginsFromPluginEntry(info.dli_fname); - } + setupPluginsFromPluginEntry(info.dli_fname); } } + } #endif #if MAC - extern fs::path sharedLibraryBundlePath(); - auto selfp = sharedLibraryBundlePath(); - if (!selfp.empty()) + extern fs::path sharedLibraryBundlePath(); + auto selfp = sharedLibraryBundlePath(); + if (!selfp.empty()) + { + std::string name = selfp.u8string(); + CFURLRef bundleUrl = CFURLCreateFromFileSystemRepresentation(0, (const unsigned char *)name.c_str(), + name.size(), true); + if (bundleUrl) { - std::string name = selfp.u8string(); - CFURLRef bundleUrl = CFURLCreateFromFileSystemRepresentation (0, - (const unsigned char*)name.c_str (), - name.size(), true); - if (bundleUrl) + auto pluginBundle = CFBundleCreate(0, bundleUrl); + CFRelease(bundleUrl); + + if (pluginBundle) { - auto pluginBundle = CFBundleCreate(0, bundleUrl); - CFRelease(bundleUrl); + auto db = CFBundleGetDataPointerForName(pluginBundle, CFSTR("clap_entry")); + if (db) + { + _bundle = pluginBundle; + _pluginEntry = (const clap_plugin_entry_t *)db; + _selfcontained = true; - if (pluginBundle) + setupPluginsFromPluginEntry(selfp.u8string().c_str()); + } + else { - auto db = CFBundleGetDataPointerForName(pluginBundle, CFSTR("clap_entry")); - if (db) - { - _bundle = pluginBundle; - _pluginEntry = (const clap_plugin_entry_t *)db; - _selfcontained = true; - - setupPluginsFromPluginEntry(selfp.u8string().c_str()); - } - else - { - CFRelease(pluginBundle); - } + CFRelease(pluginBundle); } } } -#endif - - } +#endif +} - Library::~Library() +Library::~Library() +{ + if (_pluginEntry) { - if (_pluginEntry) - { - _pluginEntry->deinit(); - } + _pluginEntry->deinit(); + } #if MAC - // FIXME keep the bundle ref and free it here - if (_bundle) - { - CFRelease(_bundle); - _bundle = nullptr; - } + // FIXME keep the bundle ref and free it here + if (_bundle) + { + CFRelease(_bundle); + _bundle = nullptr; + } #endif #if LIN - if (_handle) - { - dlclose(_handle); - _handle = nullptr; - } + if (_handle) + { + dlclose(_handle); + _handle = nullptr; + } #endif #if WIN - if (_handle && !_selfcontained) - { - FreeLibrary(_handle); - } -#endif + if (_handle && !_selfcontained) + { + FreeLibrary(_handle); } - +#endif } + +} // namespace Clap diff --git a/src/detail/clap/fsutil.h b/src/detail/clap/fsutil.h index 163ab408..fd1f8c82 100644 --- a/src/detail/clap/fsutil.h +++ b/src/detail/clap/fsutil.h @@ -31,6 +31,7 @@ namespace fs = std::filesystem; #endif #include "clapwrapper/vst3.h" +#include "clapwrapper/auv2.h" #if MAC #include @@ -39,57 +40,55 @@ namespace fs = std::filesystem; namespace Clap { - std::vector getValidCLAPSearchPaths(); - class Plugin; - class IHost; +std::vector getValidCLAPSearchPaths(); +class Plugin; +class IHost; - class Library +class Library +{ + public: + Library(); + ~Library(); + bool load(const char* name); + + const clap_plugin_entry_t* _pluginEntry = nullptr; + const clap_plugin_factory_t* _pluginFactory = nullptr; + const clap_plugin_factory_as_vst3* _pluginFactoryVst3Info = nullptr; + const clap_plugin_factory_as_auv2* _pluginFactoryAUv2Info = nullptr; + std::vector plugins; + const clap_plugin_info_as_vst3_t* get_vst3_info(uint32_t index); + + bool hasEntryPoint() const { - public: - Library(); - ~Library(); - bool load(const char* name); - - const clap_plugin_entry_t* _pluginEntry = nullptr; - const clap_plugin_factory_t* _pluginFactory = nullptr; - const clap_plugin_factory_as_vst3* _pluginFactoryVst3Info = nullptr; - std::vector plugins; - const clap_plugin_info_as_vst3_t* get_vst3_info(uint32_t index); - - bool hasEntryPoint() const { #if WIN - return _handle != 0 || _selfcontained; + return _handle != 0 || _selfcontained; #endif #if MAC - return _bundle != nullptr || _selfcontained; + return _bundle != nullptr || _selfcontained; #endif #if LIN - return _handle != nullptr || _selfcontained; + return _handle != nullptr || _selfcontained; #endif + } - } - - private: + private: #if MAC - CFBundleRef _bundle{nullptr}; + CFBundleRef _bundle{nullptr}; #endif #if LIN - void *_handle{nullptr}; + void* _handle{nullptr}; #endif - #if WIN - HMODULE _handle = 0; - bool getEntryFunction(HMODULE handle, const char* path); + HMODULE _handle = 0; + bool getEntryFunction(HMODULE handle, const char* path); #endif - void setupPluginsFromPluginEntry(const char* p); - bool _selfcontained = false; - }; - -} - + void setupPluginsFromPluginEntry(const char* p); + bool _selfcontained = false; +}; +} // namespace Clap diff --git a/src/detail/clap/mac_helpers.mm b/src/detail/clap/mac_helpers.mm index e547d772..69e5399e 100644 --- a/src/detail/clap/mac_helpers.mm +++ b/src/detail/clap/mac_helpers.mm @@ -23,86 +23,82 @@ Timo Kaluza (defiantnerd) #include - namespace Clap { - fs::path sharedLibraryBundlePath() +fs::path sharedLibraryBundlePath() +{ + Dl_info info; + if (!dladdr(reinterpret_cast(&sharedLibraryBundlePath), &info) || !info.dli_fname[0]) { - Dl_info info; - if (!dladdr(reinterpret_cast(&sharedLibraryBundlePath), &info) || - !info.dli_fname[0]) - { - // If dladdr(3) returns zero, dlerror(3) won't know why either - return {}; - } - try - { - auto res = fs::path{info.dli_fname}; - res = res.parent_path().parent_path(); // this might throw if not in bundle so catch - if (res.filename().u8string() == "Contents" && res.has_parent_path()) - { - // We are properly situated in a bundle in either a MacOS ir an iOS location - return res.parent_path(); - } - } - catch(const fs::filesystem_error &) + // If dladdr(3) returns zero, dlerror(3) won't know why either + return {}; + } + try + { + auto res = fs::path{info.dli_fname}; + res = res.parent_path().parent_path(); // this might throw if not in bundle so catch + if (res.filename().u8string() == "Contents" && res.has_parent_path()) { - // oh well + // We are properly situated in a bundle in either a MacOS ir an iOS location + return res.parent_path(); } - return {}; } + catch (const fs::filesystem_error &) + { + // oh well + } + return {}; +} - std::vector getMacCLAPSearchPaths() { - auto res = std::vector(); +std::vector getMacCLAPSearchPaths() +{ + auto res = std::vector(); - auto bundlePath = sharedLibraryBundlePath(); - if (!bundlePath.empty()) - { - std::string name = bundlePath.u8string(); - CFURLRef bundleUrl = CFURLCreateFromFileSystemRepresentation (0, - (const unsigned char*)name.c_str (), - name.size(), true); - if (bundleUrl) - { - auto pluginBundle = CFBundleCreate (0, bundleUrl); - CFRelease (bundleUrl); + auto bundlePath = sharedLibraryBundlePath(); + if (!bundlePath.empty()) + { + std::string name = bundlePath.u8string(); + CFURLRef bundleUrl = CFURLCreateFromFileSystemRepresentation(0, (const unsigned char *)name.c_str(), + name.size(), true); + if (bundleUrl) + { + auto pluginBundle = CFBundleCreate(0, bundleUrl); + CFRelease(bundleUrl); - if (pluginBundle) - { - auto pluginFoldersUrl = CFBundleCopyBuiltInPlugInsURL(pluginBundle); + if (pluginBundle) + { + auto pluginFoldersUrl = CFBundleCopyBuiltInPlugInsURL(pluginBundle); - if (pluginFoldersUrl) - { - // Remember CFURL and NSURL are toll free bridged - auto *ns = (NSURL *)pluginFoldersUrl; - auto pp = fs::path{[ns fileSystemRepresentation]}; - res.push_back(pp); - CFRelease(pluginFoldersUrl); - } - CFRelease(pluginBundle); - } - } + if (pluginFoldersUrl) + { + // Remember CFURL and NSURL are toll free bridged + auto *ns = (NSURL *)pluginFoldersUrl; + auto pp = fs::path{[ns fileSystemRepresentation]}; + res.push_back(pp); + CFRelease(pluginFoldersUrl); + } + CFRelease(pluginBundle); } + } + } - auto *fileManager = [NSFileManager defaultManager]; - auto *userLibURLs = [fileManager URLsForDirectory:NSLibraryDirectory - inDomains:NSUserDomainMask]; - auto *sysLibURLs = [fileManager URLsForDirectory:NSLibraryDirectory - inDomains:NSLocalDomainMask]; + auto *fileManager = [NSFileManager defaultManager]; + auto *userLibURLs = [fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSUserDomainMask]; + auto *sysLibURLs = [fileManager URLsForDirectory:NSLibraryDirectory inDomains:NSLocalDomainMask]; - if (userLibURLs) { - auto *u = [userLibURLs objectAtIndex:0]; - auto p = - fs::path{[u fileSystemRepresentation]} / "Audio" / "Plug-Ins" / "CLAP"; - res.push_back(p); - } + if (userLibURLs) + { + auto *u = [userLibURLs objectAtIndex:0]; + auto p = fs::path{[u fileSystemRepresentation]} / "Audio" / "Plug-Ins" / "CLAP"; + res.push_back(p); + } - if (sysLibURLs) { - auto *u = [sysLibURLs objectAtIndex:0]; - auto p = - fs::path{[u fileSystemRepresentation]} / "Audio" / "Plug-Ins" / "CLAP"; - res.push_back(p); - } - return res; - } + if (sysLibURLs) + { + auto *u = [sysLibURLs objectAtIndex:0]; + auto p = fs::path{[u fileSystemRepresentation]} / "Audio" / "Plug-Ins" / "CLAP"; + res.push_back(p); + } + return res; +} } \ No newline at end of file diff --git a/src/detail/os/macos.mm b/src/detail/os/macos.mm deleted file mode 100644 index 945410f1..00000000 --- a/src/detail/os/macos.mm +++ /dev/null @@ -1,159 +0,0 @@ -#define NOMINMAX 1 - -/** -* the macos helper -* -* provides services for all plugin instances regarding macos -* - global timer object -* - dispatch to UI thread -* - get the bundle name -* -*/ - -#include -#include "public.sdk/source/main/moduleinit.h" -#include "osutil.h" -#include -#if MACOS_USE_STD_FILESYSTEM -#include -namespace fs = std::filesystem; -#else -#include "ghc/filesystem.hpp" -namespace fs = ghc::filesystem; -#endif -#include - -namespace os -{ - void log(const char* text) - { - NSLog(@"%s", text); - } - - class MacOSHelper - { - public: - void init(); - void terminate(); - void attach(IPlugObject* plugobject); - void detach(IPlugObject* plugobject); - private: - static void timerCallback(CFRunLoopTimerRef t, void* info); - void executeDefered(); - CFRunLoopTimerRef _timer = nullptr; - std::vector _plugs; - } gMacOSHelper; - - static Steinberg::ModuleInitializer createMessageWindow([] { gMacOSHelper.init(); }); - static Steinberg::ModuleTerminator dropMessageWindow([] { gMacOSHelper.terminate(); }); - - void MacOSHelper::init() - { - - } - - void MacOSHelper::terminate() - { - - } - - void MacOSHelper::executeDefered() - { - for (auto p : _plugs) - { - p->onIdle(); - } - } - - void MacOSHelper::timerCallback(CFRunLoopTimerRef t, void* info) - { - auto self = static_cast(info); - self->executeDefered(); - } - - static float kIntervall = 10.f; - - void MacOSHelper::attach(IPlugObject* plugobject) - { - if ( _plugs.empty() ) - { - CFRunLoopTimerContext context = {}; - context.info = this; - _timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + (kIntervall * 0.001f), kIntervall * 0.001f, 0, 0, timerCallback, &context); - if (_timer) - CFRunLoopAddTimer(CFRunLoopGetCurrent(), _timer, kCFRunLoopCommonModes); - } - _plugs.push_back(plugobject); - } - - void MacOSHelper::detach(IPlugObject * plugobject) - { - _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); - if ( _plugs.empty() ) - { - if (_timer) - { - CFRunLoopTimerInvalidate(_timer); - CFRelease(_timer); - } - _timer = nullptr; - } - } - -} - -// the dummy class so we can use NSBundle bundleForClass -@interface clapwrapper_dummy_object_to_trick_the_os : NSObject -- (void) fun; -@end - -@implementation clapwrapper_dummy_object_to_trick_the_os -- (void) fun{} -@end - -namespace os -{ - // [UI Thread] - void attach(IPlugObject* plugobject) - { - gMacOSHelper.attach(plugobject); - } - - // [UI Thread] - void detach(IPlugObject* plugobject) - { - gMacOSHelper.detach(plugobject); - } - - uint64_t getTickInMS() - { - return (::clock() * 1000) / CLOCKS_PER_SEC; - } - - std::string getParentFolderName() - { - NSString* identifier = [[NSBundle bundleForClass:[clapwrapper_dummy_object_to_trick_the_os class]] bundlePath]; - fs::path n = [identifier UTF8String]; - if (n.has_parent_path()) - { - auto p = n.parent_path(); - if (p.has_filename()) - { - return p.filename().u8string(); - } - } - - return std::string(); - } - - std::string getBinaryName() - { - // this is useless - // NSString* identifier = [[NSBundle mainBundle] bundleIdentifier]; - - // this is needed: - NSString* identifier = [[NSBundle bundleForClass:[clapwrapper_dummy_object_to_trick_the_os class]] bundlePath]; - fs::path k = [identifier UTF8String]; - return k.stem(); - } -} diff --git a/src/detail/os/osutil.h b/src/detail/os/osutil.h deleted file mode 100644 index 6c30b94e..00000000 --- a/src/detail/os/osutil.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once - -/* - a minimalistic OS layer - -*/ - -#include -#include -#define FMT_HEADER_ONLY 1 -#include "fmt/format.h" -#include "fmt/ranges.h" - - -namespace os -{ - class IPlugObject - { - public: - virtual void onIdle() = 0; - virtual ~IPlugObject() {} - }; - void attach(IPlugObject* plugobject); - void detach(IPlugObject* plugobject); - uint64_t getTickInMS(); - std::string getParentFolderName(); - std::string getBinaryName(); - - void log(const char* text); - - template - void log(const char* format_str, Args&&... args) { - fmt::memory_buffer buf; - fmt::format_to(std::back_inserter(buf), format_str, args...); - buf.push_back(0); - log((const char*)buf.data()); - }; -} - -#ifndef CLAP_WRAPPER_LOGLEVEL -#define CLAP_WRAPPER_LOGLEVEL 2 -#endif - -#if (CLAP_WRAPPER_LOGLEVEL == 0) -#define LOGINFO(...) (void(0)) -#define LOGDETAIL(...) (void(0)) -#endif - -#if (CLAP_WRAPPER_LOGLEVEL == 1) -#define LOGINFO os::log -#define LOGDETAIL(...) (void(0)) -#endif - -#if (CLAP_WRAPPER_LOGLEVEL == 2) -#define LOGINFO os::log -#define LOGDETAIL os::log -#endif - -namespace util -{ - - template - class fixedqueue - { - public: - inline void push(const T& val) - { - push(&val); - } - inline void push(const T* val) - { - _elements[_head] = *val; - _head = (_head + 1) % Q; - } - inline bool pop(T& out) - { - if (_head == _tail) - { - return false; - } - out = _elements[_tail]; - _tail = (_tail + 1) % Q; - return true; - } - private: - T _elements[Q] = { }; - std::atomic_uint32_t _head = 0u; - std::atomic_uint32_t _tail = 0u; - }; -}; \ No newline at end of file diff --git a/src/detail/os/windows.cpp b/src/detail/os/windows.cpp deleted file mode 100644 index 7d8975fa..00000000 --- a/src/detail/os/windows.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#define NOMINMAX 1 - -/** -* the windows helper -* -* provides services for all plugin instances regarding Windows -* - global timer object -* - dispatch to UI thread -* -*/ - -#include -#include -#include "public.sdk/source/main/moduleinit.h" -#include "osutil.h" -#include - -// from dllmain.cpp of the VST3 SDK -extern HINSTANCE ghInst; - -namespace os -{ - - void log(const char* text) - { - OutputDebugStringA(text); - OutputDebugStringA("\n"); - - } - - class WindowsHelper - { - public: - void init(); - void terminate(); - void attach(IPlugObject* plugobject); - void detach(IPlugObject* plugobject); - private: - void executeDefered(); - static LRESULT Wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - HWND _msgWin = 0; - UINT_PTR _timer = 0; - std::vector _plugs; - } gWindowsHelper; - - static Steinberg::ModuleInitializer createMessageWindow([] { gWindowsHelper.init(); }); - static Steinberg::ModuleTerminator dropMessageWindow([] { gWindowsHelper.terminate(); }); - - static char* getModuleNameA() - { - static char modulename[2048]; - HMODULE selfmodule; - if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)getModuleNameA, &selfmodule)) - { - auto size = GetModuleFileNameA(selfmodule, modulename, 2048); - } - return modulename; - } - - static TCHAR* getModuleName() - { - static TCHAR modulename[2048]; - HMODULE selfmodule; - if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)getModuleName, &selfmodule)) - { - auto size = GetModuleFileName(selfmodule, modulename, 2048); - } - return modulename; - } - - std::string getParentFolderName() - { - std::filesystem::path n = getModuleNameA(); - if (n.has_parent_path()) - { - auto p = n.parent_path(); - if (p.has_filename()) - { - return p.filename().u8string(); - } - } - - return std::string(); - } - - std::string getBinaryName() - { - std::filesystem::path n = getModuleNameA(); - if (n.has_filename()) - { - return n.stem().u8string(); - } - return std::string(); - } - - - LRESULT WindowsHelper::Wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - { - switch (msg) - { - case WM_USER + 1: - return 1; - break; - case WM_TIMER: - gWindowsHelper.executeDefered(); - return 1; - break; - default: - return ::DefWindowProc(hwnd, msg, wParam, lParam); - } - } - - void WindowsHelper::init() - { - auto modulename = getModuleName(); - WNDCLASSEX wc; - memset(&wc, 0, sizeof(wc)); - wc.cbSize = sizeof(wc); - wc.hInstance = ghInst; - wc.lpfnWndProc = (WNDPROC)&Wndproc; - wc.lpszClassName = modulename; - auto a = RegisterClassEx(&wc); - - _msgWin = ::CreateWindowEx(0, modulename, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0); - ::SetWindowLongW(_msgWin, GWLP_WNDPROC, (LONG_PTR)&Wndproc); - _timer = ::SetTimer(_msgWin, 0, 20, NULL); - } - - void WindowsHelper::terminate() - { - ::KillTimer(_msgWin, _timer); - ::DestroyWindow(_msgWin); - ::UnregisterClass(getModuleName(), ghInst); - } - - void WindowsHelper::executeDefered() - { - for (auto&& p : _plugs) p->onIdle(); - } - - void WindowsHelper::attach(IPlugObject* plugobject) - { - _plugs.push_back(plugobject); - } - - void WindowsHelper::detach(IPlugObject * plugobject) - { - _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); - } - - // [UI Thread] - void attach(IPlugObject* plugobject) - { - gWindowsHelper.attach(plugobject); - } - - // [UI Thread] - void detach(IPlugObject* plugobject) - { - gWindowsHelper.detach(plugobject); - } - - uint64_t getTickInMS() - { - return GetTickCount64(); - } -} diff --git a/src/detail/sha1.cpp b/src/detail/sha1.cpp index 59511dc7..79cdd2ff 100644 --- a/src/detail/sha1.cpp +++ b/src/detail/sha1.cpp @@ -4,362 +4,338 @@ #include #include - static constexpr bool isBigEndian = false; namespace Crypto { - class Sha1 +class Sha1 +{ + public: + Sha1() { - public: - Sha1() { reset(); } - Sha1(const unsigned char* message_array, size_t length) - { - reset(); - input(message_array, length); - } - void input(const unsigned char* message_array, size_t length); - struct sha1hash hash(); - private: - void reset(); - void processMessageBlock(); - void padmessage(); - inline uint32_t circularShift(int bits, uint32_t word) - { - return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32 - bits)); - } + reset(); + } + Sha1(const unsigned char* message_array, size_t length) + { + reset(); + input(message_array, length); + } + void input(const unsigned char* message_array, size_t length); + struct sha1hash hash(); + + private: + void reset(); + void processMessageBlock(); + void padmessage(); + inline uint32_t circularShift(int bits, uint32_t word) + { + return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32 - bits)); + } - unsigned H[5] = // Message digest buffers - { - 0x67452301, - 0xEFCDAB89, - 0x98BADCFE, - 0x10325476, - 0xC3D2E1F0 - }; + unsigned H[5] = // Message digest buffers + {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0}; - uint32_t _lengthLow = 0; // Message length in bits - uint32_t _length_high = 0; // Message length in bits + uint32_t _lengthLow = 0; // Message length in bits + uint32_t _length_high = 0; // Message length in bits - unsigned char _messageBlock[64] = { 0 }; // 512-bit message blocks - int _messageBlockIndex = 0; // Index into message block array + unsigned char _messageBlock[64] = {0}; // 512-bit message blocks + int _messageBlockIndex = 0; // Index into message block array - bool _computed = false; // Is the digest computed? - bool _corrupted = false; // Is the message digest corruped? + bool _computed = false; // Is the digest computed? + bool _corrupted = false; // Is the message digest corruped? +}; - }; +void Sha1::reset() +{ + _lengthLow = 0; + _length_high = 0; + _messageBlockIndex = 0; + + H[0] = 0x67452301; + H[1] = 0xEFCDAB89; + H[2] = 0x98BADCFE; + H[3] = 0x10325476; + H[4] = 0xC3D2E1F0; + + _computed = false; + _corrupted = false; +} - void Sha1::reset() +void Sha1::input(const unsigned char* message_array, size_t length) +{ + if (length == 0) { - _lengthLow = 0; - _length_high = 0; - _messageBlockIndex = 0; - - H[0] = 0x67452301; - H[1] = 0xEFCDAB89; - H[2] = 0x98BADCFE; - H[3] = 0x10325476; - H[4] = 0xC3D2E1F0; - - _computed = false; - _corrupted = false; + return; } - void Sha1::input(const unsigned char* message_array, size_t length) + if (_computed || _corrupted) { - if (length == 0) - { - return; - } + _corrupted = true; + return; + } - if (_computed || _corrupted) - { - _corrupted = true; - return; - } + if (_messageBlockIndex >= 64) + { + return; + } - if (_messageBlockIndex >= 64) - { - return; - } + while (length-- && !_corrupted) + { + _messageBlock[_messageBlockIndex++] = (*message_array & 0xFF); - while (length-- && !_corrupted) + _lengthLow += 8; + _lengthLow &= 0xFFFFFFFF; // Force it to 32 bits + if (_lengthLow == 0) { - _messageBlock[_messageBlockIndex++] = (*message_array & 0xFF); - - _lengthLow += 8; - _lengthLow &= 0xFFFFFFFF; // Force it to 32 bits - if (_lengthLow == 0) + _length_high++; + _length_high &= 0xFFFFFFFF; // Force it to 32 bits + if (_length_high == 0) { - _length_high++; - _length_high &= 0xFFFFFFFF; // Force it to 32 bits - if (_length_high == 0) - { - _corrupted = true; // Message is too long - } - } - - if (_messageBlockIndex == 64) - { - processMessageBlock(); + _corrupted = true; // Message is too long } + } - message_array++; + if (_messageBlockIndex == 64) + { + processMessageBlock(); } + + message_array++; } +} - void Sha1::processMessageBlock() - { - const unsigned K[] = { // Constants defined for SHA-1 - 0x5A827999, - 0x6ED9EBA1, - 0x8F1BBCDC, - 0xCA62C1D6 - }; - int t; // Loop counter - unsigned temp; // Temporary word value - unsigned W[80]; // Word sequence - unsigned A, B, C, D, E; // Word buffers - - /* +void Sha1::processMessageBlock() +{ + const unsigned K[] = {// Constants defined for SHA-1 + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; + int t; // Loop counter + unsigned temp; // Temporary word value + unsigned W[80]; // Word sequence + unsigned A, B, C, D, E; // Word buffers + + /* * Initialize the first 16 words in the array W */ - for (t = 0; t < 16; t++) - { - W[t] = ((unsigned)_messageBlock[t * 4]) << 24; - W[t] |= ((unsigned)_messageBlock[t * 4 + 1]) << 16; - W[t] |= ((unsigned)_messageBlock[t * 4 + 2]) << 8; - W[t] |= ((unsigned)_messageBlock[t * 4 + 3]); - } + for (t = 0; t < 16; t++) + { + W[t] = ((unsigned)_messageBlock[t * 4]) << 24; + W[t] |= ((unsigned)_messageBlock[t * 4 + 1]) << 16; + W[t] |= ((unsigned)_messageBlock[t * 4 + 2]) << 8; + W[t] |= ((unsigned)_messageBlock[t * 4 + 3]); + } - for (t = 16; t < 80; t++) - { - W[t] = circularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); - } + for (t = 16; t < 80; t++) + { + W[t] = circularShift(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + } - A = H[0]; - B = H[1]; - C = H[2]; - D = H[3]; - E = H[4]; + A = H[0]; + B = H[1]; + C = H[2]; + D = H[3]; + E = H[4]; - for (t = 0; t < 20; t++) - { - temp = circularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = circularShift(30, B); - B = A; - A = temp; - } + for (t = 0; t < 20; t++) + { + temp = circularShift(5, A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = circularShift(30, B); + B = A; + A = temp; + } - for (t = 20; t < 40; t++) - { - temp = circularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = circularShift(30, B); - B = A; - A = temp; - } + for (t = 20; t < 40; t++) + { + temp = circularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = circularShift(30, B); + B = A; + A = temp; + } - for (t = 40; t < 60; t++) - { - temp = circularShift(5, A) + - ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = circularShift(30, B); - B = A; - A = temp; - } + for (t = 40; t < 60; t++) + { + temp = circularShift(5, A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = circularShift(30, B); + B = A; + A = temp; + } - for (t = 60; t < 80; t++) - { - temp = circularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; - temp &= 0xFFFFFFFF; - E = D; - D = C; - C = circularShift(30, B); - B = A; - A = temp; - } + for (t = 60; t < 80; t++) + { + temp = circularShift(5, A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = circularShift(30, B); + B = A; + A = temp; + } - H[0] = (H[0] + A) & 0xFFFFFFFF; - H[1] = (H[1] + B) & 0xFFFFFFFF; - H[2] = (H[2] + C) & 0xFFFFFFFF; - H[3] = (H[3] + D) & 0xFFFFFFFF; - H[4] = (H[4] + E) & 0xFFFFFFFF; + H[0] = (H[0] + A) & 0xFFFFFFFF; + H[1] = (H[1] + B) & 0xFFFFFFFF; + H[2] = (H[2] + C) & 0xFFFFFFFF; + H[3] = (H[3] + D) & 0xFFFFFFFF; + H[4] = (H[4] + E) & 0xFFFFFFFF; - _messageBlockIndex = 0; - } + _messageBlockIndex = 0; +} - void Sha1::padmessage() - { - /* +void Sha1::padmessage() +{ + /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second block. */ - if (_messageBlockIndex > 55) + if (_messageBlockIndex > 55) + { + _messageBlock[_messageBlockIndex++] = 0x80; + while (_messageBlockIndex < 64) { - _messageBlock[_messageBlockIndex++] = 0x80; - while (_messageBlockIndex < 64) - { - _messageBlock[_messageBlockIndex++] = 0; - } + _messageBlock[_messageBlockIndex++] = 0; + } - processMessageBlock(); + processMessageBlock(); - while (_messageBlockIndex < 56) - { - _messageBlock[_messageBlockIndex++] = 0; - } + while (_messageBlockIndex < 56) + { + _messageBlock[_messageBlockIndex++] = 0; } - else + } + else + { + _messageBlock[_messageBlockIndex++] = 0x80; + while (_messageBlockIndex < 56) { - _messageBlock[_messageBlockIndex++] = 0x80; - while (_messageBlockIndex < 56) - { - _messageBlock[_messageBlockIndex++] = 0; - } - + _messageBlock[_messageBlockIndex++] = 0; } + } - /* + /* * Store the message length as the last 8 octets */ - _messageBlock[56] = (_length_high >> 24) & 0xFF; - _messageBlock[57] = (_length_high >> 16) & 0xFF; - _messageBlock[58] = (_length_high >> 8) & 0xFF; - _messageBlock[59] = (_length_high) & 0xFF; - _messageBlock[60] = (_lengthLow >> 24) & 0xFF; - _messageBlock[61] = (_lengthLow >> 16) & 0xFF; - _messageBlock[62] = (_lengthLow >> 8) & 0xFF; - _messageBlock[63] = (_lengthLow) & 0xFF; - - processMessageBlock(); - } + _messageBlock[56] = (_length_high >> 24) & 0xFF; + _messageBlock[57] = (_length_high >> 16) & 0xFF; + _messageBlock[58] = (_length_high >> 8) & 0xFF; + _messageBlock[59] = (_length_high)&0xFF; + _messageBlock[60] = (_lengthLow >> 24) & 0xFF; + _messageBlock[61] = (_lengthLow >> 16) & 0xFF; + _messageBlock[62] = (_lengthLow >> 8) & 0xFF; + _messageBlock[63] = (_lengthLow)&0xFF; + + processMessageBlock(); +} - struct sha1hash Sha1::hash() - { - padmessage(); +struct sha1hash Sha1::hash() +{ + padmessage(); - struct sha1hash r; - int i = 0; + struct sha1hash r; + int i = 0; - r.bytes[i++] = (H[0] >> 24) & 0xFF; - r.bytes[i++] = (H[0] >> 16) & 0xFF; - r.bytes[i++] = (H[0] >> 8) & 0xFF; - r.bytes[i++] = (H[0]) & 0xFF; + r.bytes[i++] = (H[0] >> 24) & 0xFF; + r.bytes[i++] = (H[0] >> 16) & 0xFF; + r.bytes[i++] = (H[0] >> 8) & 0xFF; + r.bytes[i++] = (H[0]) & 0xFF; - r.bytes[i++] = (H[1] >> 24) & 0xFF; - r.bytes[i++] = (H[1] >> 16) & 0xFF; - r.bytes[i++] = (H[1] >> 8) & 0xFF; - r.bytes[i++] = (H[1]) & 0xFF; + r.bytes[i++] = (H[1] >> 24) & 0xFF; + r.bytes[i++] = (H[1] >> 16) & 0xFF; + r.bytes[i++] = (H[1] >> 8) & 0xFF; + r.bytes[i++] = (H[1]) & 0xFF; - r.bytes[i++] = (H[2] >> 24) & 0xFF; - r.bytes[i++] = (H[2] >> 16) & 0xFF; - r.bytes[i++] = (H[2] >> 8) & 0xFF; - r.bytes[i++] = (H[2]) & 0xFF; + r.bytes[i++] = (H[2] >> 24) & 0xFF; + r.bytes[i++] = (H[2] >> 16) & 0xFF; + r.bytes[i++] = (H[2] >> 8) & 0xFF; + r.bytes[i++] = (H[2]) & 0xFF; - r.bytes[i++] = (H[3] >> 24) & 0xFF; - r.bytes[i++] = (H[3] >> 16) & 0xFF; - r.bytes[i++] = (H[3] >> 8) & 0xFF; - r.bytes[i++] = (H[3]) & 0xFF; + r.bytes[i++] = (H[3] >> 24) & 0xFF; + r.bytes[i++] = (H[3] >> 16) & 0xFF; + r.bytes[i++] = (H[3] >> 8) & 0xFF; + r.bytes[i++] = (H[3]) & 0xFF; - r.bytes[i++] = (H[4] >> 24) & 0xFF; - r.bytes[i++] = (H[4] >> 16) & 0xFF; - r.bytes[i++] = (H[4] >> 8) & 0xFF; - r.bytes[i++] = (H[4]) & 0xFF; + r.bytes[i++] = (H[4] >> 24) & 0xFF; + r.bytes[i++] = (H[4] >> 16) & 0xFF; + r.bytes[i++] = (H[4] >> 8) & 0xFF; + r.bytes[i++] = (H[4]) & 0xFF; - reset(); + reset(); - return r; - } + return r; +} +struct sha1hash sha1(const char* text, size_t len) +{ + Sha1 x((const unsigned char*)(text), len); + return x.hash(); +} - struct sha1hash sha1(const char* text, size_t len) +uint32_t swapOrder32(uint32_t n) +{ + if (!isBigEndian) { - Sha1 x((const unsigned char*)(text), len); - return x.hash(); + return ((n >> 24) & 0x000000FF) | ((n >> 8) & 0x0000FF00) | ((n << 8) & 0x00FF0000) | + ((n << 24) & 0xFF000000); } - - uint32_t swapOrder32(uint32_t n) + else { - if (!isBigEndian) - { - return - ((n >> 24) & 0x000000FF) | - ((n >> 8) & 0x0000FF00) | - ((n << 8) & 0x00FF0000) | - ((n << 24) & 0xFF000000); - } - else - { - return n; - } + return n; } +} - uint16_t swapOrder16(uint16_t n) +uint16_t swapOrder16(uint16_t n) +{ + if (!isBigEndian) { - if (!isBigEndian) - { - return - ((n >> 8) & 0x00FF) | - ((n << 8) & 0xFF00); - } - return n; + return ((n >> 8) & 0x00FF) | ((n << 8) & 0xFF00); } + return n; +} - /* Name string is a fully-qualified domain name */ - uuid_object NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ - 0x6ba7b810, - 0x9dad, - 0x11d1, - 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } - }; - - uuid_object create_sha1_guid_from_name(const char* name, size_t namelen) - { +/* Name string is a fully-qualified domain name */ +uuid_object NameSpace_DNS = {/* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ + 0x6ba7b810, 0x9dad, 0x11d1, + 0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; - uuid_object uuid; +uuid_object create_sha1_guid_from_name(const char* name, size_t namelen) +{ + uuid_object uuid; - /*put name space ID in network byte order so it hashes the same + /*put name space ID in network byte order so it hashes the same no matter what endian machine we're on */ - // namespace DNS - uuid_object net_nsid = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ - 0x6ba7b810, - 0x9dad, - 0x11d1, - 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } - }; - - net_nsid.time_low = swapOrder32(net_nsid.time_low); - net_nsid.time_mid = swapOrder16(net_nsid.time_mid); - net_nsid.time_hi_and_version = swapOrder16(net_nsid.time_hi_and_version); - - Sha1 c; - c.input((const uint8_t*)&net_nsid, sizeof(net_nsid)); - c.input((const uint8_t*)name, namelen); - auto hash = c.hash(); - - /* convert UUID to local byte order */ - memcpy(&uuid, hash.bytes, sizeof(uuid)); - uuid.time_low = swapOrder32(uuid.time_low); - uuid.time_mid = swapOrder16(uuid.time_mid); - uuid.time_hi_and_version = swapOrder16(uuid.time_hi_and_version); - - const auto v = 5; - /* put in the variant and version bits */ - uuid.time_hi_and_version &= 0x0FFF; - uuid.time_hi_and_version |= (v << 12); - uuid.clock_seq_hi_and_reserved &= 0x3F; - uuid.clock_seq_hi_and_reserved |= 0x80; - - return uuid; - } + // namespace DNS + uuid_object net_nsid = {/* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ + 0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + + net_nsid.time_low = swapOrder32(net_nsid.time_low); + net_nsid.time_mid = swapOrder16(net_nsid.time_mid); + net_nsid.time_hi_and_version = swapOrder16(net_nsid.time_hi_and_version); + + Sha1 c; + c.input((const uint8_t*)&net_nsid, sizeof(net_nsid)); + c.input((const uint8_t*)name, namelen); + auto hash = c.hash(); + + /* convert UUID to local byte order */ + memcpy(&uuid, hash.bytes, sizeof(uuid)); + uuid.time_low = swapOrder32(uuid.time_low); + uuid.time_mid = swapOrder16(uuid.time_mid); + uuid.time_hi_and_version = swapOrder16(uuid.time_hi_and_version); + + const auto v = 5; + /* put in the variant and version bits */ + uuid.time_hi_and_version &= 0x0FFF; + uuid.time_hi_and_version |= (v << 12); + uuid.clock_seq_hi_and_reserved &= 0x3F; + uuid.clock_seq_hi_and_reserved |= 0x80; + + return uuid; } +} // namespace Crypto diff --git a/src/detail/sha1.h b/src/detail/sha1.h index e1914bfc..1d9218e1 100644 --- a/src/detail/sha1.h +++ b/src/detail/sha1.h @@ -6,25 +6,23 @@ namespace Crypto { - struct sha1hash - { - uint8_t bytes[20]; - }; - - struct sha1hash sha1(const char* text, size_t len); - - typedef struct uuid_object_ { - uint32_t time_low; - uint16_t time_mid; - uint16_t time_hi_and_version; - uint8_t clock_seq_hi_and_reserved; - uint8_t clock_seq_low; - uint8_t node[6]; - } uuid_object; +struct sha1hash +{ + uint8_t bytes[20]; +}; - uuid_object create_sha1_guid_from_name(const char* name, size_t namelen); - -} +struct sha1hash sha1(const char* text, size_t len); +typedef struct uuid_object_ +{ + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} uuid_object; +uuid_object create_sha1_guid_from_name(const char* name, size_t namelen); +} // namespace Crypto diff --git a/src/detail/vst3/categories.cpp b/src/detail/vst3/categories.cpp index 4d0d6291..0fcf75d7 100644 --- a/src/detail/vst3/categories.cpp +++ b/src/detail/vst3/categories.cpp @@ -48,6 +48,7 @@ using namespace Steinberg; using namespace Steinberg::Vst; +// clang-format off static const struct _translate { const char* clapattribute; @@ -104,6 +105,7 @@ static const struct _translate {nullptr, nullptr} }; +// clang-format on std::string clapCategoriesToVST3(const char* const* clap_categories) { @@ -129,8 +131,8 @@ std::string clapCategoriesToVST3(const char* const* clap_categories) { r2.push_back(i); } - } - + } + std::string result; for (auto& i : r2) { @@ -147,5 +149,4 @@ std::string clapCategoriesToVST3(const char* const* clap_categories) } result.pop_back(); return result; - } \ No newline at end of file diff --git a/src/detail/os/linux.cpp b/src/detail/vst3/os/linux.cpp similarity index 57% rename from src/detail/os/linux.cpp rename to src/detail/vst3/os/linux.cpp index 6e7c269a..e38f61c1 100644 --- a/src/detail/os/linux.cpp +++ b/src/detail/vst3/os/linux.cpp @@ -17,25 +17,25 @@ namespace os { - void log(const char* text) - { - fprintf(stderr, "%s\n", text); - } +void log(const char* text) +{ + fprintf(stderr, "%s\n", text); +} - class LinuxHelper - { - public: - void init(); - void terminate(); - void attach(IPlugObject* plugobject); - void detach(IPlugObject* plugobject); +class LinuxHelper +{ + public: + void init(); + void terminate(); + void attach(IPlugObject* plugobject); + void detach(IPlugObject* plugobject); - private: - void executeDefered(); - std::vector _plugs; - } gLinuxHelper; + private: + void executeDefered(); + std::vector _plugs; +} gLinuxHelper; - #if 0 +#if 0 class WindowsHelper { public: @@ -52,8 +52,8 @@ namespace os } gWindowsHelper; #endif - static Steinberg::ModuleInitializer createMessageWindow([] { gLinuxHelper.init(); }); - static Steinberg::ModuleTerminator dropMessageWindow([] { gLinuxHelper.terminate(); }); +static Steinberg::ModuleInitializer createMessageWindow([] { gLinuxHelper.init(); }); +static Steinberg::ModuleTerminator dropMessageWindow([] { gLinuxHelper.terminate(); }); #if 0 static char* getModuleNameA() @@ -79,40 +79,40 @@ namespace os } #endif - static std::string getModuleName() - { - Dl_info info; - if ( dladdr((void*)getModuleName,&info) ) - { - return info.dli_fname; - } - return nullptr; - } - - std::string getParentFolderName() - { - std::filesystem::path n = getModuleName(); - if (n.has_parent_path()) - { - auto p = n.parent_path(); - if (p.has_filename()) - { - return p.filename().u8string(); - } - } +static std::string getModuleName() +{ + Dl_info info; + if (dladdr((void*)getModuleName, &info)) + { + return info.dli_fname; + } + return nullptr; +} - return std::string(); - } +std::string getParentFolderName() +{ + std::filesystem::path n = getModuleName(); + if (n.has_parent_path()) + { + auto p = n.parent_path(); + if (p.has_filename()) + { + return p.filename().u8string(); + } + } + + return std::string(); +} - std::string getBinaryName() - { - std::filesystem::path n = getModuleName(); - if (n.has_filename()) - { - return n.stem().u8string(); - } - return std::string(); - } +std::string getBinaryName() +{ + std::filesystem::path n = getModuleName(); + if (n.has_filename()) + { + return n.stem().u8string(); + } + return std::string(); +} #if 0 LRESULT WindowsHelper::Wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -155,52 +155,49 @@ namespace os } #endif - void LinuxHelper::init() - { - - } - - void LinuxHelper::terminate() - { - - } +void LinuxHelper::init() +{ +} - void LinuxHelper::executeDefered() - { - for (auto p : _plugs) - { - p->onIdle(); - } - } - void LinuxHelper::attach(IPlugObject* plugobject) - { - _plugs.push_back(plugobject); - } +void LinuxHelper::terminate() +{ +} - void LinuxHelper::detach(IPlugObject * plugobject) - { - _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); - } +void LinuxHelper::executeDefered() +{ + for (auto p : _plugs) + { + if (p) p->onIdle(); + } +} +void LinuxHelper::attach(IPlugObject* plugobject) +{ + _plugs.push_back(plugobject); +} +void LinuxHelper::detach(IPlugObject* plugobject) +{ + _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); } +} // namespace os + namespace os { - // [UI Thread] - void attach(IPlugObject* plugobject) - { - gLinuxHelper.attach(plugobject); - } - - // [UI Thread] - void detach(IPlugObject* plugobject) - { - gLinuxHelper.detach(plugobject); - } +// [UI Thread] +void attach(IPlugObject* plugobject) +{ + gLinuxHelper.attach(plugobject); +} - uint64_t getTickInMS() - { - return clock(); - } +// [UI Thread] +void detach(IPlugObject* plugobject) +{ + gLinuxHelper.detach(plugobject); } +uint64_t getTickInMS() +{ + return clock(); +} +} // namespace os diff --git a/src/detail/vst3/os/macos.mm b/src/detail/vst3/os/macos.mm new file mode 100644 index 00000000..6080e119 --- /dev/null +++ b/src/detail/vst3/os/macos.mm @@ -0,0 +1,163 @@ +#define NOMINMAX 1 + +/** +* the macos helper +* +* provides services for all plugin instances regarding macos +* - global timer object +* - dispatch to UI thread +* - get the bundle name +* +*/ + +#include +#include "public.sdk/source/main/moduleinit.h" +#include "osutil.h" +#include +#if MACOS_USE_STD_FILESYSTEM +#include +namespace fs = std::filesystem; +#else +#include "ghc/filesystem.hpp" +namespace fs = ghc::filesystem; +#endif +#include + +namespace os +{ +void log(const char* text) +{ + NSLog(@"%s", text); +} + +class MacOSHelper +{ + public: + void init(); + void terminate(); + void attach(IPlugObject* plugobject); + void detach(IPlugObject* plugobject); + + private: + static void timerCallback(CFRunLoopTimerRef t, void* info); + void executeDefered(); + CFRunLoopTimerRef _timer = nullptr; + std::vector _plugs; +} gMacOSHelper; + +static Steinberg::ModuleInitializer createMessageWindow([] { gMacOSHelper.init(); }); +static Steinberg::ModuleTerminator dropMessageWindow([] { gMacOSHelper.terminate(); }); + +void MacOSHelper::init() +{ +} + +void MacOSHelper::terminate() +{ +} + +void MacOSHelper::executeDefered() +{ + for (auto p : _plugs) + { + if (p) p->onIdle(); + } +} + +void MacOSHelper::timerCallback(CFRunLoopTimerRef t, void* info) +{ + auto self = static_cast(info); + self->executeDefered(); +} + +static float kIntervall = 10.f; + +void MacOSHelper::attach(IPlugObject* plugobject) +{ + if (_plugs.empty()) + { + CFRunLoopTimerContext context = {}; + context.info = this; + _timer = + CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + (kIntervall * 0.001f), + kIntervall * 0.001f, 0, 0, timerCallback, &context); + if (_timer) CFRunLoopAddTimer(CFRunLoopGetCurrent(), _timer, kCFRunLoopCommonModes); + } + _plugs.push_back(plugobject); +} + +void MacOSHelper::detach(IPlugObject* plugobject) +{ + _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); + if (_plugs.empty()) + { + if (_timer) + { + CFRunLoopTimerInvalidate(_timer); + CFRelease(_timer); + } + _timer = nullptr; + } +} + +} + +// the dummy class so we can use NSBundle bundleForClass +@interface clapwrapper_dummy_object_to_trick_the_os : NSObject +- (void)fun; +@end + +@implementation clapwrapper_dummy_object_to_trick_the_os +- (void)fun +{ +} +@end + +namespace os +{ +// [UI Thread] +void attach(IPlugObject* plugobject) +{ + gMacOSHelper.attach(plugobject); +} + +// [UI Thread] +void detach(IPlugObject* plugobject) +{ + gMacOSHelper.detach(plugobject); +} + +uint64_t getTickInMS() +{ + return (::clock() * 1000) / CLOCKS_PER_SEC; +} + +std::string getParentFolderName() +{ + NSString* identifier = + [[NSBundle bundleForClass:[clapwrapper_dummy_object_to_trick_the_os class]] bundlePath]; + fs::path n = [identifier UTF8String]; + if (n.has_parent_path()) + { + auto p = n.parent_path(); + if (p.has_filename()) + { + return p.filename().u8string(); + } + } + + return std::string(); +} + +std::string getBinaryName() +{ + // this is useless + // NSString* identifier = [[NSBundle mainBundle] bundleIdentifier]; + + // this is needed: + NSString* identifier = + [[NSBundle bundleForClass:[clapwrapper_dummy_object_to_trick_the_os class]] bundlePath]; + fs::path k = [identifier UTF8String]; + return k.stem(); +} +} diff --git a/src/detail/vst3/os/osutil.h b/src/detail/vst3/os/osutil.h new file mode 100644 index 00000000..c1d2572b --- /dev/null +++ b/src/detail/vst3/os/osutil.h @@ -0,0 +1,93 @@ +#pragma once + +/* + a minimalistic OS layer + +*/ + +#include +#include +#define FMT_HEADER_ONLY 1 +#include "fmt/format.h" +#include "fmt/ranges.h" + +namespace os +{ +class IPlugObject +{ + public: + virtual void onIdle() = 0; + virtual ~IPlugObject() + { + } +}; +void attach(IPlugObject* plugobject); +void detach(IPlugObject* plugobject); +uint64_t getTickInMS(); +std::string getParentFolderName(); +std::string getBinaryName(); + +void log(const char* text); + +template +void log(const char* format_str, Args&&... args) +{ + fmt::memory_buffer buf; + fmt::format_to(std::back_inserter(buf), format_str, args...); + buf.push_back(0); + log((const char*)buf.data()); +}; +} // namespace os + +#ifndef CLAP_WRAPPER_LOGLEVEL +#define CLAP_WRAPPER_LOGLEVEL 2 +#endif + +#if (CLAP_WRAPPER_LOGLEVEL == 0) +#define LOGINFO(...) (void(0)) +#define LOGDETAIL(...) (void(0)) +#endif + +#if (CLAP_WRAPPER_LOGLEVEL == 1) +#define LOGINFO os::log +#define LOGDETAIL(...) (void(0)) +#endif + +#if (CLAP_WRAPPER_LOGLEVEL == 2) +#define LOGINFO os::log +#define LOGDETAIL os::log +#endif + +namespace util +{ + +template +class fixedqueue +{ + public: + inline void push(const T& val) + { + push(&val); + } + inline void push(const T* val) + { + _elements[_head] = *val; + _head = (_head + 1) % Q; + } + inline bool pop(T& out) + { + if (_head == _tail) + { + return false; + } + out = _elements[_tail]; + _tail = (_tail + 1) % Q; + return true; + } + + private: + T _elements[Q] = {}; + std::atomic_uint32_t _head = 0u; + std::atomic_uint32_t _tail = 0u; +}; +}; // namespace util \ No newline at end of file diff --git a/src/detail/vst3/os/windows.cpp b/src/detail/vst3/os/windows.cpp new file mode 100644 index 00000000..9d9c5a5d --- /dev/null +++ b/src/detail/vst3/os/windows.cpp @@ -0,0 +1,169 @@ +#define NOMINMAX 1 + +/** +* the windows helper +* +* provides services for all plugin instances regarding Windows +* - global timer object +* - dispatch to UI thread +* +*/ + +#include +#include +#include "public.sdk/source/main/moduleinit.h" +#include "osutil.h" +#include + +// from dllmain.cpp of the VST3 SDK +extern HINSTANCE ghInst; + +namespace os +{ + +void log(const char* text) +{ + OutputDebugStringA(text); + OutputDebugStringA("\n"); +} + +class WindowsHelper +{ + public: + void init(); + void terminate(); + void attach(IPlugObject* plugobject); + void detach(IPlugObject* plugobject); + + private: + void executeDefered(); + static LRESULT Wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + HWND _msgWin = 0; + UINT_PTR _timer = 0; + std::vector _plugs; +} gWindowsHelper; + +static Steinberg::ModuleInitializer createMessageWindow([] { gWindowsHelper.init(); }); +static Steinberg::ModuleTerminator dropMessageWindow([] { gWindowsHelper.terminate(); }); + +static char* getModuleNameA() +{ + static char modulename[2048]; + HMODULE selfmodule; + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCSTR)getModuleNameA, &selfmodule)) + { + auto size = GetModuleFileNameA(selfmodule, modulename, 2048); + } + return modulename; +} + +static TCHAR* getModuleName() +{ + static TCHAR modulename[2048]; + HMODULE selfmodule; + if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)getModuleName, &selfmodule)) + { + auto size = GetModuleFileName(selfmodule, modulename, 2048); + } + return modulename; +} + +std::string getParentFolderName() +{ + std::filesystem::path n = getModuleNameA(); + if (n.has_parent_path()) + { + auto p = n.parent_path(); + if (p.has_filename()) + { + return p.filename().u8string(); + } + } + + return std::string(); +} + +std::string getBinaryName() +{ + std::filesystem::path n = getModuleNameA(); + if (n.has_filename()) + { + return n.stem().u8string(); + } + return std::string(); +} + +LRESULT WindowsHelper::Wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_USER + 1: + return 1; + break; + case WM_TIMER: + gWindowsHelper.executeDefered(); + return 1; + break; + default: + return ::DefWindowProc(hwnd, msg, wParam, lParam); + } +} + +void WindowsHelper::init() +{ + auto modulename = getModuleName(); + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(wc); + wc.hInstance = ghInst; + wc.lpfnWndProc = (WNDPROC)&Wndproc; + wc.lpszClassName = modulename; + auto a = RegisterClassEx(&wc); + + _msgWin = ::CreateWindowEx(0, modulename, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, 0); + ::SetWindowLongW(_msgWin, GWLP_WNDPROC, (LONG_PTR)&Wndproc); + _timer = ::SetTimer(_msgWin, 0, 20, NULL); +} + +void WindowsHelper::terminate() +{ + ::KillTimer(_msgWin, _timer); + ::DestroyWindow(_msgWin); + ::UnregisterClass(getModuleName(), ghInst); +} + +void WindowsHelper::executeDefered() +{ + for (auto&& p : _plugs) + { + if (p) p->onIdle(); + } +} + +void WindowsHelper::attach(IPlugObject* plugobject) +{ + _plugs.push_back(plugobject); +} + +void WindowsHelper::detach(IPlugObject* plugobject) +{ + _plugs.erase(std::remove(_plugs.begin(), _plugs.end(), plugobject), _plugs.end()); +} + +// [UI Thread] +void attach(IPlugObject* plugobject) +{ + gWindowsHelper.attach(plugobject); +} + +// [UI Thread] +void detach(IPlugObject* plugobject) +{ + gWindowsHelper.detach(plugobject); +} + +uint64_t getTickInMS() +{ + return GetTickCount64(); +} +} // namespace os diff --git a/src/detail/vst3/parameter.cpp b/src/detail/vst3/parameter.cpp index 28395932..f8ac0efc 100644 --- a/src/detail/vst3/parameter.cpp +++ b/src/detail/vst3/parameter.cpp @@ -5,30 +5,32 @@ using namespace Steinberg; -Vst3Parameter::Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, const clap_param_info_t* clapinfo) -: Steinberg::Vst::Parameter(vst3info) -, id(clapinfo->id) -, cookie(clapinfo->cookie) -, min_value(clapinfo->min_value) -, max_value(clapinfo->max_value) +Vst3Parameter::Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, + const clap_param_info_t* clapinfo) + : Steinberg::Vst::Parameter(vst3info) + , id(clapinfo->id) + , cookie(clapinfo->cookie) + , min_value(clapinfo->min_value) + , max_value(clapinfo->max_value) { - // + // } -Vst3Parameter::Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, uint8_t bus, uint8_t channel, uint8_t cc) - : Steinberg::Vst::Parameter(vst3info) - , id(vst3info.id) - , cookie(nullptr) - , min_value(0) - , max_value(127) - , isMidi(true) - , channel(channel) - , controller(cc) +Vst3Parameter::Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, uint8_t bus, uint8_t channel, + uint8_t cc) + : Steinberg::Vst::Parameter(vst3info) + , id(vst3info.id) + , cookie(nullptr) + , min_value(0) + , max_value(127) + , isMidi(true) + , channel(channel) + , controller(cc) { - if (cc == Vst::ControllerNumbers::kPitchBend) - { - max_value = 16383; - } + if (cc == Vst::ControllerNumbers::kPitchBend) + { + max_value = 16383; + } } Vst3Parameter::~Vst3Parameter() { @@ -36,11 +38,11 @@ Vst3Parameter::~Vst3Parameter() bool Vst3Parameter::setNormalized(Steinberg::Vst::ParamValue v) { - if (isMidi && info.flags & Steinberg::Vst::ParameterInfo::kIsProgramChange) - { - return true; - } - return super::setNormalized(v); + if (isMidi && info.flags & Steinberg::Vst::ParameterInfo::kIsProgramChange) + { + return true; + } + return super::setNormalized(v); } #if 0 @@ -55,43 +57,45 @@ bool Vst3Parameter::fromString(const Steinberg::Vst::TChar* string, Steinberg::V } #endif -Vst3Parameter* Vst3Parameter::create(const clap_param_info_t* info, std::function getUnitId) +Vst3Parameter* Vst3Parameter::create( + const clap_param_info_t* info, + std::function getUnitId) { - Vst::ParameterInfo v; - - v.id = info->id & 0x7FFFFFFF; // why ever SMTG does not want the highest bit to be set - - // the long name might contain the module name - // this will change when we split the module to units - std::string fullname; - Vst::UnitID unit = 0; - - // if there is a module name and a lambda - if (info->module[0] != 0 && getUnitId) - { - unit = getUnitId(info->module); - fullname = info->name; - } - else - { - if (!fullname.empty()) - { - fullname.append("/"); - } - fullname.append(info->name); - if (fullname.size() >= str16BufferSize(v.title)) - { - fullname = info->name; - } - } - - str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); - // TODO: string shrink algorithm shortening the string a bit - str8ToStr16(v.shortTitle, info->name, str16BufferSize(v.shortTitle)); - v.units[0] = 0; // unfortunately, CLAP has no unit for parameter values - v.unitId = unit; - - /* + Vst::ParameterInfo v; + + v.id = info->id & 0x7FFFFFFF; // why ever SMTG does not want the highest bit to be set + + // the long name might contain the module name + // this will change when we split the module to units + std::string fullname; + Vst::UnitID unit = 0; + + // if there is a module name and a lambda + if (info->module[0] != 0 && getUnitId) + { + unit = getUnitId(info->module); + fullname = info->name; + } + else + { + if (!fullname.empty()) + { + fullname.append("/"); + } + fullname.append(info->name); + if (fullname.size() >= str16BufferSize(v.title)) + { + fullname = info->name; + } + } + + str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); + // TODO: string shrink algorithm shortening the string a bit + str8ToStr16(v.shortTitle, info->name, str16BufferSize(v.shortTitle)); + v.units[0] = 0; // unfortunately, CLAP has no unit for parameter values + v.unitId = unit; + + /* In the VST3 SDK the normalized value [0, 1] to discrete value and its inverse function discrete value to normalized value is defined like this: Normalize: @@ -99,74 +103,74 @@ Vst3Parameter* Vst3Parameter::create(const clap_param_info_t* info, std::functio Denormalize : int discreteValue = min (stepCount, normalized * (stepCount + 1)); - */ - - v.flags = Vst::ParameterInfo::kNoFlags - | ((info->flags & CLAP_PARAM_IS_HIDDEN) ? Vst::ParameterInfo::kIsHidden : 0) - | ((info->flags & CLAP_PARAM_IS_BYPASS) ? Vst::ParameterInfo::kIsBypass : 0) - | ((info->flags & CLAP_PARAM_IS_AUTOMATABLE) ? Vst::ParameterInfo::kCanAutomate : 0) - | ((info->flags & CLAP_PARAM_IS_READONLY) ? Vst::ParameterInfo::kIsReadOnly : 0) - // | ((info->flags & CLAP_PARAM_IS_READONLY) ? Vst::ParameterInfo::kIsReadOnly : 0) - ; - - auto param_range = (info->max_value - info->min_value); - - v.defaultNormalizedValue = (info->default_value-info->min_value) / param_range; - if (info->flags & CLAP_PARAM_IS_STEPPED) - { - auto steps = param_range + 1; - v.stepCount = steps; - } - else - v.stepCount = 0; - - auto result = new Vst3Parameter(v, info); - result->addRef(); // ParameterContainer doesn't add the ref -> but we don't have copies - return result; + */ + + v.flags = Vst::ParameterInfo::kNoFlags | + ((info->flags & CLAP_PARAM_IS_HIDDEN) ? Vst::ParameterInfo::kIsHidden : 0) | + ((info->flags & CLAP_PARAM_IS_BYPASS) ? Vst::ParameterInfo::kIsBypass : 0) | + ((info->flags & CLAP_PARAM_IS_AUTOMATABLE) ? Vst::ParameterInfo::kCanAutomate : 0) | + ((info->flags & CLAP_PARAM_IS_READONLY) ? Vst::ParameterInfo::kIsReadOnly : 0) + // | ((info->flags & CLAP_PARAM_IS_READONLY) ? Vst::ParameterInfo::kIsReadOnly : 0) + ; + + auto param_range = (info->max_value - info->min_value); + + v.defaultNormalizedValue = (info->default_value - info->min_value) / param_range; + if (info->flags & CLAP_PARAM_IS_STEPPED) + { + auto steps = param_range + 1; + v.stepCount = steps; + } + else + v.stepCount = 0; + + auto result = new Vst3Parameter(v, info); + result->addRef(); // ParameterContainer doesn't add the ref -> but we don't have copies + return result; } Vst3Parameter* Vst3Parameter::create(uint8_t bus, uint8_t channel, uint8_t cc, Vst::ParamID id) { - Vst::ParameterInfo v; - - v.id = id; - - auto name = "controller"; - // the long name might contain the module name - // this will change when we split the module to units - std::string fullname("MIDI"); - if (!fullname.empty()) - { - fullname.append("/"); - } - fullname.append("controller"); - if (fullname.size() >= str16BufferSize(v.title)) - { - fullname = "controller"; - } - str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); - // TODO: string shrink algorithm shortening the string a bit - str8ToStr16(v.shortTitle, name, str16BufferSize(v.shortTitle)); - v.units[0] = 0; // unfortunately, CLAP has no unit for parameter values - v.unitId = channel+1; - - v.defaultNormalizedValue = 0; - v.flags = Vst::ParameterInfo::kNoFlags; - if (cc == Vst::ControllerNumbers::kCtrlProgramChange) - { - v.flags |= Vst::ParameterInfo::kIsProgramChange; - v.stepCount = 128; - } - - v.defaultNormalizedValue = 0; - v.stepCount = 128; - - if (cc == Vst::ControllerNumbers::kPitchBend) - { - v.stepCount = 16384; - } - - auto result = new Vst3Parameter(v,bus, channel, cc); - result->addRef(); // ParameterContainer doesn't add the ref -> but we don't have copies - return result; + Vst::ParameterInfo v; + + v.id = id; + + auto name = "controller"; + // the long name might contain the module name + // this will change when we split the module to units + std::string fullname("MIDI"); + if (!fullname.empty()) + { + fullname.append("/"); + } + fullname.append("controller"); + if (fullname.size() >= str16BufferSize(v.title)) + { + fullname = "controller"; + } + str8ToStr16(v.title, fullname.c_str(), str16BufferSize(v.title)); + // TODO: string shrink algorithm shortening the string a bit + str8ToStr16(v.shortTitle, name, str16BufferSize(v.shortTitle)); + v.units[0] = 0; // unfortunately, CLAP has no unit for parameter values + v.unitId = channel + 1; + + v.defaultNormalizedValue = 0; + v.flags = Vst::ParameterInfo::kNoFlags; + if (cc == Vst::ControllerNumbers::kCtrlProgramChange) + { + v.flags |= Vst::ParameterInfo::kIsProgramChange; + v.stepCount = 128; + } + + v.defaultNormalizedValue = 0; + v.stepCount = 128; + + if (cc == Vst::ControllerNumbers::kPitchBend) + { + v.stepCount = 16384; + } + + auto result = new Vst3Parameter(v, bus, channel, cc); + result->addRef(); // ParameterContainer doesn't add the ref -> but we don't have copies + return result; } diff --git a/src/detail/vst3/parameter.h b/src/detail/vst3/parameter.h index 96246fd0..bcc9cc0f 100644 --- a/src/detail/vst3/parameter.h +++ b/src/detail/vst3/parameter.h @@ -29,10 +29,12 @@ class Vst3Parameter : public Steinberg::Vst::Parameter { using super = Steinberg::Vst::Parameter; -protected: + + protected: Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, const clap_param_info_t* clapinfo); Vst3Parameter(const Steinberg::Vst::ParameterInfo& vst3info, uint8_t bus, uint8_t channel, uint8_t cc); -public: + + public: virtual ~Vst3Parameter(); bool setNormalized(Steinberg::Vst::ParamValue v) override; @@ -55,16 +57,16 @@ class Vst3Parameter : public Steinberg::Vst::Parameter { return (clapvalue - min_value) / (max_value - min_value); } - static Vst3Parameter* create(const clap_param_info_t* info, std::function getUnitId); + static Vst3Parameter* create(const clap_param_info_t* info, + std::function getUnitId); static Vst3Parameter* create(uint8_t bus, uint8_t channel, uint8_t cc, Steinberg::Vst::ParamID id); // copies from the clap_param_info_t clap_id id = 0; void* cookie = nullptr; - double min_value; // minimum plain value - double max_value; // maximum plain value + double min_value; // minimum plain value + double max_value; // maximum plain value // or it was MIDI bool isMidi = false; uint8_t channel = 0; uint8_t controller = 0; - }; diff --git a/src/detail/vst3/plugview.cpp b/src/detail/vst3/plugview.cpp index 8f3e73bf..8a4de8c0 100644 --- a/src/detail/vst3/plugview.cpp +++ b/src/detail/vst3/plugview.cpp @@ -3,8 +3,8 @@ // #include #include -WrappedView::WrappedView(const clap_plugin_t* plugin, const clap_plugin_gui_t* gui, std::function onDestroy, - std::function onRunLoopAvailable) +WrappedView::WrappedView(const clap_plugin_t* plugin, const clap_plugin_gui_t* gui, + std::function onDestroy, std::function onRunLoopAvailable) : IPlugView() , FObject() , _plugin(plugin) @@ -12,7 +12,6 @@ WrappedView::WrappedView(const clap_plugin_t* plugin, const clap_plugin_gui_t* g , _onDestroy(onDestroy) , _onRunLoopAvailable(onRunLoopAvailable) { - } WrappedView::~WrappedView() @@ -28,19 +27,18 @@ void WrappedView::ensure_ui() { if (!_created) { - const char* api{nullptr}; + const char* api{nullptr}; #if MAC - api = CLAP_WINDOW_API_COCOA; + api = CLAP_WINDOW_API_COCOA; #endif #if WIN - api = CLAP_WINDOW_API_WIN32; + api = CLAP_WINDOW_API_WIN32; #endif #if LIN - api = CLAP_WINDOW_API_X11; + api = CLAP_WINDOW_API_X11; #endif - if (_extgui->is_api_supported(_plugin, api, false)) - _extgui->create(_plugin, api, false); + if (_extgui->is_api_supported(_plugin, api, false)) _extgui->create(_plugin, api, false); _created = true; } @@ -58,16 +56,14 @@ void WrappedView::drop_ui() tresult PLUGIN_API WrappedView::isPlatformTypeSupported(FIDString type) { - static struct vst3_and_clap_match_types_t{ + static struct vst3_and_clap_match_types_t + { const char* VST3; const char* CLAP; - } platformTypeMatches[] = - { - { kPlatformTypeHWND, CLAP_WINDOW_API_WIN32}, - { kPlatformTypeNSView, CLAP_WINDOW_API_COCOA }, - { kPlatformTypeX11EmbedWindowID, CLAP_WINDOW_API_X11}, - { nullptr, nullptr } - }; + } platformTypeMatches[] = {{kPlatformTypeHWND, CLAP_WINDOW_API_WIN32}, + {kPlatformTypeNSView, CLAP_WINDOW_API_COCOA}, + {kPlatformTypeX11EmbedWindowID, CLAP_WINDOW_API_X11}, + {nullptr, nullptr}}; auto* n = platformTypeMatches; while (n->VST3 && n->CLAP) { @@ -87,16 +83,15 @@ tresult PLUGIN_API WrappedView::isPlatformTypeSupported(FIDString type) tresult PLUGIN_API WrappedView::attached(void* parent, FIDString type) { #if WIN - _window = { CLAP_WINDOW_API_WIN32, { parent } }; + _window = {CLAP_WINDOW_API_WIN32, {parent}}; #endif #if MAC - _window = { CLAP_WINDOW_API_COCOA, { parent } }; + _window = {CLAP_WINDOW_API_COCOA, {parent}}; #endif - #if LIN - _window = { CLAP_WINDOW_API_X11, { parent } }; + _window = {CLAP_WINDOW_API_X11, {parent}}; #endif ensure_ui(); @@ -108,10 +103,10 @@ tresult PLUGIN_API WrappedView::attached(void* parent, FIDString type) uint32_t h = _rect.getHeight(); if (_extgui->adjust_size(_plugin, &w, &h)) { - _rect.right = _rect.left + w +1; - _rect.bottom = _rect.top + h +1; + _rect.right = _rect.left + w + 1; + _rect.bottom = _rect.top + h + 1; } - _extgui->set_size(_plugin, w , h); + _extgui->set_size(_plugin, w, h); } _extgui->show(_plugin); return kResultOk; @@ -135,7 +130,7 @@ tresult PLUGIN_API WrappedView::onKeyDown(char16 key, int16 keyCode, int16 modif } tresult PLUGIN_API WrappedView::onKeyUp(char16 key, int16 keyCode, int16 modifiers) -{ +{ return kResultOk; } @@ -185,11 +180,10 @@ tresult PLUGIN_API WrappedView::onSize(ViewRect* newSize) { return kResultFalse; } - } return kResultOk; } - + return kResultFalse; } @@ -205,8 +199,8 @@ tresult PLUGIN_API WrappedView::setFrame(IPlugFrame* frame) _plugFrame = frame; #if LIN - if (_plugFrame->queryInterface(Steinberg::Linux::IRunLoop::iid, - (void **)&_runLoop) == Steinberg::kResultOk && + if (_plugFrame->queryInterface(Steinberg::Linux::IRunLoop::iid, (void**)&_runLoop) == + Steinberg::kResultOk && _onRunLoopAvailable) { _onRunLoopAvailable(); diff --git a/src/detail/vst3/plugview.h b/src/detail/vst3/plugview.h index 03e16758..9f8e77c4 100644 --- a/src/detail/vst3/plugview.h +++ b/src/detail/vst3/plugview.h @@ -16,95 +16,96 @@ using namespace Steinberg; class WrappedView : public Steinberg::IPlugView, public Steinberg::FObject { + public: + WrappedView(const clap_plugin_t* plugin, const clap_plugin_gui_t* gui, std::function onDestroy, + std::function onRunLoopAvailable); + ~WrappedView(); -public: + // IPlugView interface + tresult PLUGIN_API isPlatformTypeSupported(FIDString type) override; - WrappedView(const clap_plugin_t* plugin, const clap_plugin_gui_t* gui, std::function onDestroy, std::function onRunLoopAvailable); - ~WrappedView(); - - - // IPlugView interface - tresult PLUGIN_API isPlatformTypeSupported(FIDString type) override; - - /** The parent window of the view has been created, the (platform) representation of the view + /** The parent window of the view has been created, the (platform) representation of the view should now be created as well. Note that the parent is owned by the caller and you are not allowed to alter it in any way other than adding your own views. Note that in this call the plug-in could call a IPlugFrame::resizeView ()! \param parent : platform handle of the parent window or view \param type : \ref platformUIType which should be created */ - tresult PLUGIN_API attached(void* parent, FIDString type) override; + tresult PLUGIN_API attached(void* parent, FIDString type) override; - /** The parent window of the view is about to be destroyed. + /** The parent window of the view is about to be destroyed. You have to remove all your own views from the parent window or view. */ - tresult PLUGIN_API removed() override; + tresult PLUGIN_API removed() override; - /** Handling of mouse wheel. */ - tresult PLUGIN_API onWheel(float distance) override; + /** Handling of mouse wheel. */ + tresult PLUGIN_API onWheel(float distance) override; - /** Handling of keyboard events : Key Down. + /** Handling of keyboard events : Key Down. \param key : unicode code of key \param keyCode : virtual keycode for non ascii keys - see \ref VirtualKeyCodes in keycodes.h \param modifiers : any combination of modifiers - see \ref KeyModifier in keycodes.h \return kResultTrue if the key is handled, otherwise kResultFalse. \n Please note that kResultTrue must only be returned if the key has really been handled. Otherwise key command handling of the host might be blocked! */ - tresult PLUGIN_API onKeyDown(char16 key, int16 keyCode, int16 modifiers) override; + tresult PLUGIN_API onKeyDown(char16 key, int16 keyCode, int16 modifiers) override; - /** Handling of keyboard events : Key Up. + /** Handling of keyboard events : Key Up. \param key : unicode code of key \param keyCode : virtual keycode for non ascii keys - see \ref VirtualKeyCodes in keycodes.h \param modifiers : any combination of KeyModifier - see \ref KeyModifier in keycodes.h \return kResultTrue if the key is handled, otherwise return kResultFalse. */ - tresult PLUGIN_API onKeyUp(char16 key, int16 keyCode, int16 modifiers) override; + tresult PLUGIN_API onKeyUp(char16 key, int16 keyCode, int16 modifiers) override; - /** Returns the size of the platform representation of the view. */ - tresult PLUGIN_API getSize(ViewRect* size) override; + /** Returns the size of the platform representation of the view. */ + tresult PLUGIN_API getSize(ViewRect* size) override; - /** Resizes the platform representation of the view to the given rect. Note that if the plug-in + /** Resizes the platform representation of the view to the given rect. Note that if the plug-in * requests a resize (IPlugFrame::resizeView ()) onSize has to be called afterward. */ - tresult PLUGIN_API onSize(ViewRect* newSize) override; + tresult PLUGIN_API onSize(ViewRect* newSize) override; - /** Focus changed message. */ - tresult PLUGIN_API onFocus(TBool state) override; + /** Focus changed message. */ + tresult PLUGIN_API onFocus(TBool state) override; - /** Sets IPlugFrame object to allow the plug-in to inform the host about resizing. */ - tresult PLUGIN_API setFrame(IPlugFrame* frame) override; + /** Sets IPlugFrame object to allow the plug-in to inform the host about resizing. */ + tresult PLUGIN_API setFrame(IPlugFrame* frame) override; - /** Is view sizable by user. */ - tresult PLUGIN_API canResize() override; + /** Is view sizable by user. */ + tresult PLUGIN_API canResize() override; - /** On live resize this is called to check if the view can be resized to the given rect, if not + /** On live resize this is called to check if the view can be resized to the given rect, if not * adjust the rect to the allowed size. */ - tresult PLUGIN_API checkSizeConstraint(ViewRect* rect) override; + tresult PLUGIN_API checkSizeConstraint(ViewRect* rect) override; - //---Interface------ - OBJ_METHODS(WrappedView, FObject) - DEFINE_INTERFACES - DEF_INTERFACE(IPlugView) - END_DEFINE_INTERFACES(FObject) - REFCOUNT_METHODS(FObject) + //---Interface------ + OBJ_METHODS(WrappedView, FObject) + DEFINE_INTERFACES + DEF_INTERFACE(IPlugView) + END_DEFINE_INTERFACES(FObject) + REFCOUNT_METHODS(FObject) // wrapper needed interfaces - bool request_resize(uint32_t width, uint32_t height); - -private: - void ensure_ui(); - void drop_ui(); - const clap_plugin_t* _plugin = nullptr; - const clap_plugin_gui_t* _extgui = nullptr; - std::function _onDestroy = nullptr, _onRunLoopAvailable = nullptr; - clap_window_t _window = { nullptr, { nullptr } }; - IPlugFrame* _plugFrame = nullptr; - ViewRect _rect = {0,0,0,0}; - bool _created = false; - bool _attached = false; + bool request_resize(uint32_t width, uint32_t height); + + private: + void ensure_ui(); + void drop_ui(); + const clap_plugin_t* _plugin = nullptr; + const clap_plugin_gui_t* _extgui = nullptr; + std::function _onDestroy = nullptr, _onRunLoopAvailable = nullptr; + clap_window_t _window = {nullptr, {nullptr}}; + IPlugFrame* _plugFrame = nullptr; + ViewRect _rect = {0, 0, 0, 0}; + bool _created = false; + bool _attached = false; #if LIN -public: - Steinberg::Linux::IRunLoop *getRunLoop() { return _runLoop; } -private: - Steinberg::Linux::IRunLoop *_runLoop = nullptr; + public: + Steinberg::Linux::IRunLoop* getRunLoop() + { + return _runLoop; + } + + private: + Steinberg::Linux::IRunLoop* _runLoop = nullptr; #endif - }; \ No newline at end of file diff --git a/src/detail/vst3/process.cpp b/src/detail/vst3/process.cpp index c0763ecb..cdf1f034 100644 --- a/src/detail/vst3/process.cpp +++ b/src/detail/vst3/process.cpp @@ -10,124 +10,123 @@ #include #include "../clap/automation.h" - namespace Clap { - using namespace Steinberg; - - void ProcessAdapter::setupProcessing(const clap_plugin_t* plugin, const clap_plugin_params_t* ext_params, - Vst::BusList& audioinputs, Vst::BusList& audiooutputs, - uint32_t numSamples, size_t numEventInputs, size_t numEventOutputs, - Steinberg::Vst::ParameterContainer& params, Steinberg::Vst::IComponentHandler* componenthandler, - IAutomation* automation, bool enablePolyPressure, bool supportsTuningNoteExpression) - { - _plugin = plugin; - _ext_params = ext_params; - _audioinputs = &audioinputs; - _audiooutputs = &audiooutputs; +using namespace Steinberg; + +void ProcessAdapter::setupProcessing(const clap_plugin_t* plugin, const clap_plugin_params_t* ext_params, + Vst::BusList& audioinputs, Vst::BusList& audiooutputs, + uint32_t numSamples, size_t numEventInputs, size_t numEventOutputs, + Steinberg::Vst::ParameterContainer& params, + Steinberg::Vst::IComponentHandler* componenthandler, + IAutomation* automation, bool enablePolyPressure, + bool supportsTuningNoteExpression) +{ + _plugin = plugin; + _ext_params = ext_params; + _audioinputs = &audioinputs; + _audiooutputs = &audiooutputs; - parameters = ¶ms; - _componentHandler = componenthandler; - _automation = automation; + parameters = ¶ms; + _componentHandler = componenthandler; + _automation = automation; - if (numSamples > 0) - { - delete[] _silent_input; - _silent_input = new float[numSamples]; + if (numSamples > 0) + { + delete[] _silent_input; + _silent_input = new float[numSamples]; - delete[] _silent_output; - _silent_output = new float[numSamples]; - } + delete[] _silent_output; + _silent_output = new float[numSamples]; + } - auto numInputs = _audioinputs->size(); - auto numOutputs = _audiooutputs->size(); + auto numInputs = (uint32_t)_audioinputs->size(); + auto numOutputs = (uint32_t)_audiooutputs->size(); - _processData.audio_inputs_count = numInputs; - delete[] _input_ports; - _input_ports = nullptr; + _processData.audio_inputs_count = numInputs; + delete[] _input_ports; + _input_ports = nullptr; - if ( numInputs > 0) + if (numInputs > 0) + { + _input_ports = new clap_audio_buffer_t[numInputs]; + for (auto i = 0U; i < numInputs; ++i) { - _input_ports = new clap_audio_buffer_t[numInputs]; - for (auto i = 0U; i < numInputs; ++i) + clap_audio_buffer_t& bus = _input_ports[i]; + Vst::BusInfo info; + if (_audioinputs->at(i)->getInfo(info)) { - clap_audio_buffer_t& bus = _input_ports[i]; - Vst::BusInfo info; - if (_audioinputs->at(i)->getInfo(info)) - { - bus.channel_count = info.channelCount; - bus.constant_mask = 0; - bus.latency = 0; - bus.data64 = 0; - bus.data32 = 0; - } + bus.channel_count = info.channelCount; + bus.constant_mask = 0; + bus.latency = 0; + bus.data64 = 0; + bus.data32 = 0; } - _processData.audio_inputs = _input_ports; } - else - { - _processData.audio_inputs = nullptr; - } - - _processData.audio_outputs_count = numOutputs; - delete[] _output_ports; - _output_ports = nullptr; + _processData.audio_inputs = _input_ports; + } + else + { + _processData.audio_inputs = nullptr; + } + _processData.audio_outputs_count = numOutputs; + delete[] _output_ports; + _output_ports = nullptr; - if (numOutputs > 0) + if (numOutputs > 0) + { + _output_ports = new clap_audio_buffer_t[numOutputs]; + for (auto i = 0U; i < numOutputs; ++i) { - _output_ports = new clap_audio_buffer_t[numOutputs]; - for (auto i = 0U; i < numOutputs; ++i) + clap_audio_buffer_t& bus = _output_ports[i]; + Vst::BusInfo info; + if (_audiooutputs->at(i)->getInfo(info)) { - clap_audio_buffer_t& bus = _output_ports[i]; - Vst::BusInfo info; - if (_audiooutputs->at(i)->getInfo(info)) - { - bus.channel_count = info.channelCount; - bus.constant_mask = 0; - bus.latency = 0; - bus.data64 = 0; - bus.data32 = 0; - } + bus.channel_count = info.channelCount; + bus.constant_mask = 0; + bus.latency = 0; + bus.data64 = 0; + bus.data32 = 0; } - _processData.audio_outputs = _output_ports; } - else - { - _processData.audio_outputs = nullptr; - } - - _processData.in_events = &_in_events; - _processData.out_events = &_out_events; + _processData.audio_outputs = _output_ports; + } + else + { + _processData.audio_outputs = nullptr; + } - _processData.transport = &_transport; + _processData.in_events = &_in_events; + _processData.out_events = &_out_events; - _in_events.ctx = this; - _in_events.size = input_events_size; - _in_events.get = input_events_get; + _processData.transport = &_transport; - _out_events.ctx = this; - _out_events.try_push = output_events_try_push; + _in_events.ctx = this; + _in_events.size = input_events_size; + _in_events.get = input_events_get; - _events.clear(); - _events.reserve(256); - _eventindices.clear(); - _eventindices.reserve(_events.capacity()); + _out_events.ctx = this; + _out_events.try_push = output_events_try_push; - _out_events.ctx = this; + _events.clear(); + _events.reserve(256); + _eventindices.clear(); + _eventindices.reserve(_events.capacity()); - _gesturedParameters.reserve(32); + _out_events.ctx = this; - _activeNotes.reserve(64); + _gesturedParameters.reserve(32); - _supportsPolyPressure = enablePolyPressure; - _supportsTuningNoteExpression = supportsTuningNoteExpression; + _activeNotes.reserve(64); - } + _supportsPolyPressure = enablePolyPressure; + _supportsTuningNoteExpression = supportsTuningNoteExpression; +} - void ProcessAdapter::activateAudioBus(Steinberg::Vst::BusDirection dir, int32 index, TBool state) - { - /* +void ProcessAdapter::activateAudioBus(Steinberg::Vst::BusDirection dir, int32 index, TBool state) +{ + /* if (dir == Vst::kInput) { auto& map = _bogus_buffers->_in_channelmap[index]; @@ -145,62 +144,67 @@ namespace Clap _bogus_buffers->_active_mask_out &= ~map._bitmap; } */ - } - - inline clap_beattime doubleToBeatTime(double t) - { - return std::round(t * CLAP_BEATTIME_FACTOR); - } +} - inline clap_sectime doubleToSecTime(double t) - { - return round(t * CLAP_SECTIME_FACTOR); - } +inline clap_beattime doubleToBeatTime(double t) +{ + return std::round(t * CLAP_BEATTIME_FACTOR); +} +inline clap_sectime doubleToSecTime(double t) +{ + return round(t * CLAP_SECTIME_FACTOR); +} - void ProcessAdapter::flush() +void ProcessAdapter::flush() +{ + // minimal processing if _ext_params is existent + if (_ext_params) { - // minimal processing if _ext_params is existent - if (_ext_params) - { - _events.clear(); - _eventindices.clear(); + _events.clear(); + _eventindices.clear(); - // sortEventIndices(); call only if there would be any input event - _ext_params->flush(_plugin, _processData.in_events, _processData.out_events); - } + // sortEventIndices(); call only if there would be any input event + _ext_params->flush(_plugin, _processData.in_events, _processData.out_events); } +} - // this converts the ProcessContext data from VST to CLAP - void ProcessAdapter::process(Steinberg::Vst::ProcessData& data) +// this converts the ProcessContext data from VST to CLAP +void ProcessAdapter::process(Steinberg::Vst::ProcessData& data) +{ + // remember the ProcessData pointer during process + _vstdata = &data; + + /// convert timing + _transport.header = {sizeof(_transport), 0, CLAP_CORE_EVENT_SPACE_ID, CLAP_EVENT_TRANSPORT, 0}; + + _transport.flags = 0; + if (_vstdata->processContext) { - // remember the ProcessData pointer during process - _vstdata = &data; - - /// convert timing - _transport.header = { - sizeof(_transport), - 0, - CLAP_CORE_EVENT_SPACE_ID, - CLAP_EVENT_TRANSPORT, - 0 - }; - - _transport.flags = 0; - if (_vstdata->processContext) - { - // converting the flags - _transport.flags |= 0 + // converting the flags + _transport.flags |= + 0 // kPlaying = 1 << 1, ///< currently playing - | ((_vstdata->processContext->state & Vst::ProcessContext::kPlaying) ? CLAP_TRANSPORT_IS_PLAYING : 0) + | ((_vstdata->processContext->state & Vst::ProcessContext::kPlaying) ? CLAP_TRANSPORT_IS_PLAYING + : 0) // kRecording = 1 << 3, ///< currently recording - | ((_vstdata->processContext->state & Vst::ProcessContext::kRecording) ? CLAP_TRANSPORT_IS_RECORDING : 0) + | ((_vstdata->processContext->state & Vst::ProcessContext::kRecording) + ? CLAP_TRANSPORT_IS_RECORDING + : 0) // kCycleActive = 1 << 2, ///< cycle is active - | ((_vstdata->processContext->state & Vst::ProcessContext::kCycleActive) ? CLAP_TRANSPORT_IS_LOOP_ACTIVE : 0) + | ((_vstdata->processContext->state & Vst::ProcessContext::kCycleActive) + ? CLAP_TRANSPORT_IS_LOOP_ACTIVE + : 0) // kTempoValid = 1 << 10, ///< tempo contains valid information - | ((_vstdata->processContext->state & Vst::ProcessContext::kTempoValid) ? CLAP_TRANSPORT_HAS_TEMPO : 0) - | ((_vstdata->processContext->state & Vst::ProcessContext::kBarPositionValid) ? CLAP_TRANSPORT_HAS_BEATS_TIMELINE : 0) - | ((_vstdata->processContext->state & Vst::ProcessContext::kTimeSigValid) ? CLAP_TRANSPORT_HAS_TIME_SIGNATURE : 0) + | + ((_vstdata->processContext->state & Vst::ProcessContext::kTempoValid) ? CLAP_TRANSPORT_HAS_TEMPO + : 0) | + ((_vstdata->processContext->state & Vst::ProcessContext::kBarPositionValid) + ? CLAP_TRANSPORT_HAS_BEATS_TIMELINE + : 0) | + ((_vstdata->processContext->state & Vst::ProcessContext::kTimeSigValid) + ? CLAP_TRANSPORT_HAS_TIME_SIGNATURE + : 0) // the rest of the flags has no meaning to CLAP // kSystemTimeValid = 1 << 8, ///< systemTime contains valid information @@ -215,87 +219,100 @@ namespace Clap // kChordValid = 1 << 18, ///< chord contains valid information // // kSmpteValid = 1 << 14, ///< smpteOffset and frameRate contain valid information - ; + _transport.song_pos_beats = 0; + _transport.song_pos_seconds = 0; + + if ((_vstdata->processContext->state & Vst::ProcessContext::kProjectTimeMusicValid)) + { _transport.song_pos_beats = doubleToBeatTime(_vstdata->processContext->projectTimeMusic); - _transport.song_pos_seconds = 0; + } + _transport.tempo = 120; + _transport.tempo_inc = 0; + if ((_vstdata->processContext->state & Vst::ProcessContext::kTempoValid)) + { _transport.tempo = _vstdata->processContext->tempo; - _transport.tempo_inc = 0; + } + + _transport.loop_start_beats = 0; + _transport.loop_end_beats = 0; + _transport.loop_start_seconds = 0; + _transport.loop_end_seconds = 0; + if ((_vstdata->processContext->state & Vst::ProcessContext::kCycleValid)) + { _transport.loop_start_beats = doubleToBeatTime(_vstdata->processContext->cycleStartMusic); _transport.loop_end_beats = doubleToBeatTime(_vstdata->processContext->cycleEndMusic); - _transport.loop_start_seconds = 0; - _transport.loop_end_seconds = 0; - - _transport.bar_start = 0; - _transport.bar_number = 0; + } - if ((_vstdata->processContext->state & Vst::ProcessContext::kTimeSigValid)) - { - _transport.tsig_num = _vstdata->processContext->timeSigNumerator; - _transport.tsig_denom = _vstdata->processContext->timeSigDenominator; - } - else - { - _transport.tsig_num = 4; - _transport.tsig_denom = 4; - } + _transport.tsig_num = 4; + _transport.tsig_denom = 4; + if ((_vstdata->processContext->state & Vst::ProcessContext::kTimeSigValid)) + { + _transport.tsig_num = _vstdata->processContext->timeSigNumerator; + _transport.tsig_denom = _vstdata->processContext->timeSigDenominator; + } - _transport.bar_number = _vstdata->processContext->barPositionMusic; - _processData.steady_time = _vstdata->processContext->projectTimeSamples; + _transport.bar_start = 0; + _transport.bar_number = 0; + if ((_vstdata->processContext->state & Vst::ProcessContext::kBarPositionValid)) + { + _transport.bar_start = _vstdata->processContext->barPositionMusic * CLAP_BEATTIME_FACTOR; } + _processData.steady_time = _vstdata->processContext->projectTimeSamples; + } - // setting up transport - _processData.frames_count = _vstdata->numSamples; + // setting up transport + _processData.frames_count = _vstdata->numSamples; - // always clear - _events.clear(); - _eventindices.clear(); + // always clear + _events.clear(); + _eventindices.clear(); - processInputEvents(_vstdata->inputEvents); + processInputEvents(_vstdata->inputEvents); - if (_vstdata->inputParameterChanges) + if (_vstdata->inputParameterChanges) + { + auto numPevent = _vstdata->inputParameterChanges->getParameterCount(); + for (decltype(numPevent) i = 0; i < numPevent; ++i) { - auto numPevent = _vstdata->inputParameterChanges->getParameterCount(); - for (decltype(numPevent) i = 0; i < numPevent; ++i) - { - auto k = _vstdata->inputParameterChanges->getParameterData(i); + auto k = _vstdata->inputParameterChanges->getParameterData(i); - // get the Vst3Parameter - auto paramid = k->getParameterId(); + // get the Vst3Parameter + auto paramid = k->getParameterId(); - // if a parameter is currently edited by a user, we are not allowed to send this back to the CLAP. - // this is a fundamental difference between VST3 and CLAP - if (std::find(_gesturedParameters.begin(), _gesturedParameters.end(), paramid) != _gesturedParameters.end()) - { - continue; - } + // if a parameter is currently edited by a user, we are not allowed to send this back to the CLAP. + // this is a fundamental difference between VST3 and CLAP + if (std::find(_gesturedParameters.begin(), _gesturedParameters.end(), paramid) != + _gesturedParameters.end()) + { + continue; + } - auto param = (Vst3Parameter*)parameters->getParameter(paramid); - if (param) + auto param = (Vst3Parameter*)parameters->getParameter(paramid); + if (param) + { + if (param->isMidi) { - if (param->isMidi) - { + auto nums = k->getPointCount(); - auto nums = k->getPointCount(); - - Vst::ParamValue value; - int32 offset; - if (k->getPoint(nums - 1, offset, value) == kResultOk) + Vst::ParamValue value; + int32 offset; + if (k->getPoint(nums - 1, offset, value) == kResultOk) + { + // create MIDI event + clap_multi_event_t n; + n.param.header.type = CLAP_EVENT_MIDI; + n.param.header.flags = 0; + n.param.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.param.header.time = offset; + n.param.header.size = sizeof(clap_event_midi_t); + n.midi.port_index = 0; + + switch (param->controller) { - // create MIDI event - clap_multi_event_t n; - n.param.header.type = CLAP_EVENT_MIDI; - n.param.header.flags = 0; - n.param.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.param.header.time = offset; - n.param.header.size = sizeof(clap_event_midi_t); - n.midi.port_index = 0; - - switch (param->controller) - { case Vst::ControllerNumbers::kAfterTouch: n.midi.data[0] = 0xD0 | param->channel; n.midi.data[1] = param->asClapValue(value); @@ -304,9 +321,9 @@ namespace Clap case Vst::ControllerNumbers::kPitchBend: { auto val = (uint16_t)param->asClapValue(value); - n.midi.data[0] = 0xE0 | param->channel; // $Ec - n.midi.data[1] = (val & 0x7F); // LSB - n.midi.data[2] = (val >> 7) & 0x7F; // MSB + n.midi.data[0] = 0xE0 | param->channel; // $Ec + n.midi.data[1] = (val & 0x7F); // LSB + n.midi.data[2] = (val >> 7) & 0x7F; // MSB } break; default: @@ -314,271 +331,272 @@ namespace Clap n.midi.data[1] = param->controller; n.midi.data[2] = param->asClapValue(value); break; - } - - _eventindices.push_back(_events.size()); - _events.push_back(n); } - } - else - { - auto nums = k->getPointCount(); - Vst::ParamValue value; - int32 offset; - if (k->getPoint(nums - 1, offset, value) == kResultOk) - { - clap_multi_event_t n; - n.param.header.type = CLAP_EVENT_PARAM_VALUE; - n.param.header.flags = 0; - n.param.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.param.header.time = offset; - n.param.header.size = sizeof(clap_event_param_value); - n.param.param_id = param->id; - n.param.cookie = param->cookie; - - // nothing note specific - n.param.note_id = -1; // always global - n.param.port_index = -1; - n.param.channel = -1; - n.param.key = -1; - - n.param.value = param->asClapValue(value); - _eventindices.push_back(_events.size()); - _events.push_back(n); - } + _eventindices.push_back(_events.size()); + _events.push_back(n); } } + else + { + auto nums = k->getPointCount(); + Vst::ParamValue value; + int32 offset; + if (k->getPoint(nums - 1, offset, value) == kResultOk) + { + clap_multi_event_t n; + n.param.header.type = CLAP_EVENT_PARAM_VALUE; + n.param.header.flags = 0; + n.param.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.param.header.time = offset; + n.param.header.size = sizeof(clap_event_param_value); + n.param.param_id = param->id; + n.param.cookie = param->cookie; + + // nothing note specific + n.param.note_id = -1; // always global + n.param.port_index = -1; + n.param.channel = -1; + n.param.key = -1; + + n.param.value = param->asClapValue(value); + _eventindices.push_back(_events.size()); + _events.push_back(n); + } + } } } + } - sortEventIndices(); + sortEventIndices(); - bool doProcess = true; + bool doProcess = true; - if (_vstdata->numSamples > 0 ) + if (_vstdata->numSamples > 0) + { + // setting the buffers + auto inbusses = _audioinputs->size(); + for (auto i = 0U; i < inbusses; ++i) { - // setting the buffers - auto inbusses = _audioinputs->size(); - for (auto i = 0U; i < inbusses; ++i) - { - if (_vstdata->inputs[i].numChannels > 0) - _input_ports[i].data32 = _vstdata->inputs[i].channelBuffers32; - else - doProcess = false; - } + if (_vstdata->inputs[i].numChannels > 0) + _input_ports[i].data32 = _vstdata->inputs[i].channelBuffers32; + else + doProcess = false; + } - auto outbusses = _audiooutputs->size(); - for (auto i = 0U; i < outbusses; ++i) - { - if (_vstdata->outputs[i].numChannels > 0) - _output_ports[i].data32 = _vstdata->outputs[i].channelBuffers32; - else - doProcess = false; - } - if (doProcess) - _plugin->process(_plugin, &_processData); + auto outbusses = _audiooutputs->size(); + for (auto i = 0U; i < outbusses; ++i) + { + if (_vstdata->outputs[i].numChannels > 0) + _output_ports[i].data32 = _vstdata->outputs[i].channelBuffers32; else - { - if (_ext_params) - { - _ext_params->flush(_plugin, _processData.in_events, _processData.out_events); - } - } + doProcess = false; } + if (doProcess) + _plugin->process(_plugin, &_processData); else { if (_ext_params) { _ext_params->flush(_plugin, _processData.in_events, _processData.out_events); } - else - { - // something was now very very wrong here.. - } } - - processOutputParams(data); - - _vstdata = nullptr; - } - - void ProcessAdapter::processOutputParams(Steinberg::Vst::ProcessData& data) - { - - } - - uint32_t ProcessAdapter::input_events_size(const struct clap_input_events* list) - { - auto self = static_cast(list->ctx); - return self->_events.size(); - // return self->_vstdata->inputEvents->getEventCount(); } - - // returns the pointer to an event in the list. The index accessed is not the position in the event list itself - // since all events indices were sorted by timestamp - const clap_event_header_t* ProcessAdapter::input_events_get(const struct clap_input_events* list, uint32_t index) + else { - auto self = static_cast(list->ctx); - if (self->_events.size() > index) + if (_ext_params) { - // we can safely return the note.header also for other event types - // since they are at the same memory address - auto realindex = self->_eventindices[index]; - return &(self->_events[realindex].header); + _ext_params->flush(_plugin, _processData.in_events, _processData.out_events); + } + else + { + // something was now very very wrong here.. } - return nullptr; } - bool ProcessAdapter::output_events_try_push(const struct clap_output_events* list, const clap_event_header_t* event) - { - auto self = static_cast(list->ctx); - // mainly used for CLAP_EVENT_NOTE_CHOKE and CLAP_EVENT_NOTE_END - // but also for parameter changes - return self->enqueueOutputEvent(event); - } + processOutputParams(data); + + _vstdata = nullptr; +} + +void ProcessAdapter::processOutputParams(Steinberg::Vst::ProcessData& data) +{ +} + +uint32_t ProcessAdapter::input_events_size(const struct clap_input_events* list) +{ + auto self = static_cast(list->ctx); + return (uint32_t)self->_events.size(); + // return self->_vstdata->inputEvents->getEventCount(); +} - void ProcessAdapter::sortEventIndices() +// returns the pointer to an event in the list. The index accessed is not the position in the event list itself +// since all events indices were sorted by timestamp +const clap_event_header_t* ProcessAdapter::input_events_get(const struct clap_input_events* list, + uint32_t index) +{ + auto self = static_cast(list->ctx); + if (self->_events.size() > index) { - // just sorting the index - std::sort(_eventindices.begin(), _eventindices.end(), [&](size_t const& a, size_t const& b) - { - return _events[a].header.time < _events[b].header.time; - } - ); + // we can safely return the note.header also for other event types + // since they are at the same memory address + auto realindex = self->_eventindices[index]; + return &(self->_events[realindex].header); } + return nullptr; +} + +bool ProcessAdapter::output_events_try_push(const struct clap_output_events* list, + const clap_event_header_t* event) +{ + auto self = static_cast(list->ctx); + // mainly used for CLAP_EVENT_NOTE_CHOKE and CLAP_EVENT_NOTE_END + // but also for parameter changes + return self->enqueueOutputEvent(event); +} + +void ProcessAdapter::sortEventIndices() +{ + // just sorting the index + std::sort(_eventindices.begin(), _eventindices.end(), + [&](size_t const& a, size_t const& b) + { return _events[a].header.time < _events[b].header.time; }); +} - void ProcessAdapter::processInputEvents(Steinberg::Vst::IEventList* eventlist) +void ProcessAdapter::processInputEvents(Steinberg::Vst::IEventList* eventlist) +{ + if (eventlist) { - if (eventlist) + Vst::Event vstevent; + auto numev = eventlist->getEventCount(); + for (decltype(numev) i = 0; i < numev; ++i) { - Vst::Event vstevent; - auto numev = eventlist->getEventCount(); - for (decltype(numev) i = 0; i < numev; ++i) + if (eventlist->getEvent(i, vstevent) == kResultOk) { - if (eventlist->getEvent(i, vstevent) == kResultOk) + if (vstevent.type == Vst::Event::kNoteOnEvent) { - if (vstevent.type == Vst::Event::kNoteOnEvent) + clap_multi_event_t n; + n.note.header.type = CLAP_EVENT_NOTE_ON; + n.note.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; + n.note.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.note.header.time = vstevent.sampleOffset; + n.note.header.size = sizeof(clap_event_note); + n.note.channel = vstevent.noteOn.channel; + n.note.note_id = vstevent.noteOn.noteId; + n.note.port_index = 0; + n.note.velocity = vstevent.noteOn.velocity; + n.note.key = vstevent.noteOn.pitch; + _eventindices.push_back(_events.size()); + _events.push_back(n); + addToActiveNotes(&n.note); + + // CLAP doesn't support note-on retuning but does support note expressions so + // convert but only if your target clap supports note expressions + if (_supportsTuningNoteExpression && vstevent.noteOn.tuning != 0) { clap_multi_event_t n; - n.note.header.type = CLAP_EVENT_NOTE_ON; - n.note.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; - n.note.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.note.header.time = vstevent.sampleOffset; - n.note.header.size = sizeof(clap_event_note); - n.note.channel = vstevent.noteOn.channel; - n.note.note_id = vstevent.noteOn.noteId; - n.note.port_index = 0; - n.note.velocity = vstevent.noteOn.velocity; - n.note.key = vstevent.noteOn.pitch; + n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; + n.noteexpression.header.flags = + (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; + n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.noteexpression.header.time = vstevent.sampleOffset; + n.noteexpression.header.size = sizeof(clap_event_note_expression); + n.noteexpression.note_id = vstevent.noteExpressionValue.noteId; + n.noteexpression.port_index = 0; + n.noteexpression.key = vstevent.noteOn.pitch; + n.noteexpression.channel = vstevent.noteOn.channel; + n.noteexpression.note_id = vstevent.noteOn.noteId; + n.noteexpression.value = vstevent.noteExpressionValue.value; + + // VST3 Tuning is float in cents. We are in semitones. So + n.noteexpression.value = vstevent.noteOn.tuning * 0.01; + n.noteexpression.expression_id = CLAP_NOTE_EXPRESSION_TUNING; _eventindices.push_back(_events.size()); _events.push_back(n); - addToActiveNotes(&n.note); - - // CLAP doesn't support note-on retuning but does support note expressions so - // convert but only if your target clap supports note expressions - if (_supportsTuningNoteExpression && vstevent.noteOn.tuning != 0) - { - clap_multi_event_t n; - n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; - n.noteexpression.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; - n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.noteexpression.header.time = vstevent.sampleOffset; - n.noteexpression.header.size = sizeof(clap_event_note_expression); - n.noteexpression.note_id = vstevent.noteExpressionValue.noteId; - n.noteexpression.port_index = 0; - n.noteexpression.key = vstevent.noteOn.pitch; - n.noteexpression.channel = vstevent.noteOn.channel; - n.noteexpression.note_id = vstevent.noteOn.noteId; - n.noteexpression.value = vstevent.noteExpressionValue.value; - - // VST3 Tuning is float in cents. We are in semitones. So - n.noteexpression.value = vstevent.noteOn.tuning * 0.01; - n.noteexpression.expression_id = CLAP_NOTE_EXPRESSION_TUNING; - _eventindices.push_back(_events.size()); - _events.push_back(n); - } } - if (vstevent.type == Vst::Event::kNoteOffEvent) + } + if (vstevent.type == Vst::Event::kNoteOffEvent) + { + clap_multi_event_t n; + n.note.header.type = CLAP_EVENT_NOTE_OFF; + n.note.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; + n.note.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.note.header.time = vstevent.sampleOffset; + n.note.header.size = sizeof(clap_event_note); + n.note.channel = vstevent.noteOff.channel; + n.note.note_id = vstevent.noteOff.noteId; + n.note.port_index = 0; + n.note.velocity = vstevent.noteOff.velocity; + n.note.key = vstevent.noteOff.pitch; + _eventindices.push_back(_events.size()); + _events.push_back(n); + } + if (vstevent.type == Vst::Event::kDataEvent) + { + clap_multi_event_t n; + if (vstevent.data.type == Vst::DataEvent::DataTypes::kMidiSysEx) { - clap_multi_event_t n; - n.note.header.type = CLAP_EVENT_NOTE_OFF; - n.note.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; - n.note.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.note.header.time = vstevent.sampleOffset; - n.note.header.size = sizeof(clap_event_note); - n.note.channel = vstevent.noteOff.channel; - n.note.note_id = vstevent.noteOff.noteId; - n.note.port_index = 0; - n.note.velocity = vstevent.noteOff.velocity; - n.note.key = vstevent.noteOff.pitch; + n.sysex.buffer = vstevent.data.bytes; + n.sysex.size = vstevent.data.size; + n.sysex.port_index = 0; + n.sysex.header.type = CLAP_EVENT_MIDI_SYSEX; + n.sysex.header.flags = vstevent.flags & Vst::Event::kIsLive ? CLAP_EVENT_IS_LIVE : 0; + n.sysex.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.sysex.header.time = vstevent.sampleOffset; + n.sysex.header.size = sizeof(n.sysex); _eventindices.push_back(_events.size()); _events.push_back(n); } - if (vstevent.type == Vst::Event::kDataEvent) + else { - clap_multi_event_t n; - if (vstevent.data.type == Vst::DataEvent::DataTypes::kMidiSysEx) - { - n.sysex.buffer = vstevent.data.bytes; - n.sysex.size = vstevent.data.size; - n.sysex.port_index = 0; - n.sysex.header.type = CLAP_EVENT_MIDI_SYSEX; - n.sysex.header.flags = vstevent.flags & Vst::Event::kIsLive ? CLAP_EVENT_IS_LIVE : 0; - n.sysex.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.sysex.header.time = vstevent.sampleOffset; - n.sysex.header.size = sizeof(n.sysex); - _eventindices.push_back(_events.size()); - _events.push_back(n); - } - else - { - // there are no other event types yet - } + // there are no other event types yet } - if (_supportsPolyPressure && vstevent.type == Vst::Event::kPolyPressureEvent) + } + if (_supportsPolyPressure && vstevent.type == Vst::Event::kPolyPressureEvent) + { + clap_multi_event_t n; + n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; + n.noteexpression.header.flags = + (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; + n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.noteexpression.header.time = vstevent.sampleOffset; + n.noteexpression.header.size = sizeof(clap_event_note_expression); + n.noteexpression.note_id = vstevent.polyPressure.noteId; + for (auto& i : _activeNotes) { - clap_multi_event_t n; - n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; - n.noteexpression.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; - n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.noteexpression.header.time = vstevent.sampleOffset; - n.noteexpression.header.size = sizeof(clap_event_note_expression); - n.noteexpression.note_id = vstevent.polyPressure.noteId; - for (auto& i : _activeNotes) + if (i.used && i.note_id == vstevent.polyPressure.noteId) { - if (i.used && i.note_id == vstevent.polyPressure.noteId) - { - n.noteexpression.expression_id = CLAP_NOTE_EXPRESSION_PRESSURE; - n.noteexpression.port_index = i.port_index; - n.noteexpression.key = i.key; // should be the same as vstevent.polyPressure.pitch - n.noteexpression.channel = i.channel; - n.noteexpression.value = vstevent.polyPressure.pressure; - } + n.noteexpression.expression_id = CLAP_NOTE_EXPRESSION_PRESSURE; + n.noteexpression.port_index = i.port_index; + n.noteexpression.key = i.key; // should be the same as vstevent.polyPressure.pitch + n.noteexpression.channel = i.channel; + n.noteexpression.value = vstevent.polyPressure.pressure; } - _eventindices.push_back(_events.size()); - _events.push_back(n); } - if (vstevent.type == Vst::Event::kNoteExpressionValueEvent) + _eventindices.push_back(_events.size()); + _events.push_back(n); + } + if (vstevent.type == Vst::Event::kNoteExpressionValueEvent) + { + clap_multi_event_t n; + n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; + n.noteexpression.header.flags = + (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; + n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; + n.noteexpression.header.time = vstevent.sampleOffset; + n.noteexpression.header.size = sizeof(clap_event_note_expression); + n.noteexpression.note_id = vstevent.noteExpressionValue.noteId; + for (auto& i : _activeNotes) { - clap_multi_event_t n; - n.noteexpression.header.type = CLAP_EVENT_NOTE_EXPRESSION; - n.noteexpression.header.flags = (vstevent.flags & Vst::Event::kIsLive) ? CLAP_EVENT_IS_LIVE : 0; - n.noteexpression.header.space_id = CLAP_CORE_EVENT_SPACE_ID; - n.noteexpression.header.time = vstevent.sampleOffset; - n.noteexpression.header.size = sizeof(clap_event_note_expression); - n.noteexpression.note_id = vstevent.noteExpressionValue.noteId; - for (auto& i : _activeNotes) + if (i.used && i.note_id == vstevent.noteExpressionValue.noteId) { - if (i.used && i.note_id == vstevent.noteExpressionValue.noteId) + n.noteexpression.port_index = i.port_index; + n.noteexpression.key = i.key; + n.noteexpression.channel = i.channel; + n.noteexpression.value = vstevent.noteExpressionValue.value; + switch (vstevent.noteExpressionValue.typeId) { - n.noteexpression.port_index = i.port_index; - n.noteexpression.key = i.key; - n.noteexpression.channel = i.channel; - n.noteexpression.value = vstevent.noteExpressionValue.value; - switch (vstevent.noteExpressionValue.typeId) - { case Vst::NoteExpressionTypeIDs::kVolumeTypeID: n.noteexpression.expression_id = CLAP_NOTE_EXPRESSION_VOLUME; break; @@ -601,24 +619,24 @@ namespace Clap break; default: continue; - } - _eventindices.push_back(_events.size()); - _events.push_back(n); } + _eventindices.push_back(_events.size()); + _events.push_back(n); } } } } } } +} - bool ProcessAdapter::enqueueOutputEvent(const clap_event_header_t* event) +bool ProcessAdapter::enqueueOutputEvent(const clap_event_header_t* event) +{ + switch (event->type) { - switch (event->type) - { case CLAP_EVENT_NOTE_ON: { - auto nevt = reinterpret_cast(event); + auto nevt = reinterpret_cast(event); Steinberg::Vst::Event oe{}; oe.type = Steinberg::Vst::Event::kNoteOnEvent; @@ -628,16 +646,15 @@ namespace Clap oe.noteOn.length = 0; oe.noteOn.tuning = 0.0f; oe.noteOn.noteId = nevt->note_id; - oe.busIndex = 0; // FIXME - multi-out midi still needs work + oe.busIndex = 0; // FIXME - multi-out midi still needs work oe.sampleOffset = nevt->header.time; - if (_vstdata && _vstdata->outputEvents) - _vstdata->outputEvents->addEvent(oe); + if (_vstdata && _vstdata->outputEvents) _vstdata->outputEvents->addEvent(oe); } return true; case CLAP_EVENT_NOTE_OFF: { - auto nevt = reinterpret_cast(event); + auto nevt = reinterpret_cast(event); Steinberg::Vst::Event oe{}; oe.type = Steinberg::Vst::Event::kNoteOffEvent; @@ -647,12 +664,10 @@ namespace Clap oe.noteOn.length = 0; oe.noteOff.tuning = 0.0f; oe.noteOff.noteId = nevt->note_id; - oe.busIndex = 0; // FIXME - multi-out midi still needs work + oe.busIndex = 0; // FIXME - multi-out midi still needs work oe.sampleOffset = nevt->header.time; - - if (_vstdata && _vstdata->outputEvents) - _vstdata->outputEvents->addEvent(oe); + if (_vstdata && _vstdata->outputEvents) _vstdata->outputEvents->addEvent(oe); } return true; case CLAP_EVENT_NOTE_END: @@ -673,7 +688,8 @@ namespace Clap // if the parameter is marked as being edited in the UI, pass the value // to the queue so it can be given to the IComponentHandler - if (std::find(_gesturedParameters.begin(), _gesturedParameters.end(), param_id) != _gesturedParameters.end()) + if (std::find(_gesturedParameters.begin(), _gesturedParameters.end(), param_id) != + _gesturedParameters.end()) { _automation->onPerformEdit(ev); } @@ -692,37 +708,36 @@ namespace Clap Steinberg::int32 index2 = 0; list->addPoint(ev->header.time, param->asVst3Value(ev->value), index2); } - } } - return true; - break; + return true; + break; case CLAP_EVENT_PARAM_MOD: return true; break; case CLAP_EVENT_PARAM_GESTURE_BEGIN: - { - auto ev = (clap_event_param_gesture*)event; - auto param = (Vst3Parameter*)this->parameters->getParameter(ev->param_id & 0x7FFFFFFF); - _gesturedParameters.push_back(param->getInfo().id); - _automation->onBeginEdit(param->getInfo().id); - } + { + auto ev = (clap_event_param_gesture*)event; + auto param = (Vst3Parameter*)this->parameters->getParameter(ev->param_id & 0x7FFFFFFF); + _gesturedParameters.push_back(param->getInfo().id); + _automation->onBeginEdit(param->getInfo().id); + } return true; break; case CLAP_EVENT_PARAM_GESTURE_END: - { - auto ev = (clap_event_param_gesture*)event; - auto param = (Vst3Parameter*)this->parameters->getParameter(ev->param_id & 0x7FFFFFFF); + { + auto ev = (clap_event_param_gesture*)event; + auto param = (Vst3Parameter*)this->parameters->getParameter(ev->param_id & 0x7FFFFFFF); - auto n = std::remove(_gesturedParameters.begin(), _gesturedParameters.end(), param->getInfo().id); - if (n != _gesturedParameters.end()) - { - _gesturedParameters.erase(n, _gesturedParameters.end()); - _automation->onEndEdit(param->getInfo().id); - } + auto n = std::remove(_gesturedParameters.begin(), _gesturedParameters.end(), param->getInfo().id); + if (n != _gesturedParameters.end()) + { + _gesturedParameters.erase(n, _gesturedParameters.end()); + _automation->onEndEdit(param->getInfo().id); } + } return true; break; @@ -733,40 +748,37 @@ namespace Clap break; default: break; - } - return false; } + return false; +} - void ProcessAdapter::addToActiveNotes(const clap_event_note* note) +void ProcessAdapter::addToActiveNotes(const clap_event_note* note) +{ + for (auto& i : _activeNotes) { - for (auto& i : _activeNotes) + if (!i.used) { - if (!i.used) - { - i.note_id = note->note_id; - i.port_index = note->port_index; - i.channel = note->channel; - i.key = note->key; - i.used = true; - return; - } + i.note_id = note->note_id; + i.port_index = note->port_index; + i.channel = note->channel; + i.key = note->key; + i.used = true; + return; } - _activeNotes.push_back({true,note->note_id, note->port_index, note->channel, note->key}); } + _activeNotes.push_back({true, note->note_id, note->port_index, note->channel, note->key}); +} - void ProcessAdapter::removeFromActiveNotes(const clap_event_note * note) +void ProcessAdapter::removeFromActiveNotes(const clap_event_note* note) +{ + for (auto& i : _activeNotes) { - for (auto& i : _activeNotes) + if (i.used && i.port_index == note->port_index && i.channel == note->channel && + i.note_id == note->note_id) { - if (i.used - && i.port_index == note->port_index - && i.channel == note->channel - && i.note_id == note->note_id) - { - i.used = false; - } + i.used = false; } } - - } + +} // namespace Clap diff --git a/src/detail/vst3/process.h b/src/detail/vst3/process.h index 41d4bd83..ab1ff457 100644 --- a/src/detail/vst3/process.h +++ b/src/detail/vst3/process.h @@ -35,18 +35,18 @@ namespace Clap { - class ProcessAdapter - { - public: - typedef union clap_multi_event - { - clap_event_header_t header; - clap_event_note_t note; - clap_event_midi_t midi; - clap_event_midi_sysex_t sysex; - clap_event_param_value_t param; - clap_event_note_expression_t noteexpression; - } clap_multi_event_t; +class ProcessAdapter +{ + public: + typedef union clap_multi_event + { + clap_event_header_t header; + clap_event_note_t note; + clap_event_midi_t midi; + clap_event_midi_sysex_t sysex; + clap_event_param_value_t param; + clap_event_note_expression_t noteexpression; + } clap_multi_event_t; #if 0 // the bitly helpers. These names conflict with macOS params.h but are @@ -63,73 +63,76 @@ namespace Clap } #endif - void setupProcessing(const clap_plugin_t* plugin, const clap_plugin_params_t* ext_params, - Steinberg::Vst::BusList& numInputs, Steinberg::Vst::BusList& numOutputs, - uint32_t numSamples, size_t numEventInputs, size_t numEventOutputs, - Steinberg::Vst::ParameterContainer& params, Steinberg::Vst::IComponentHandler* componenthandler, - IAutomation* automation, bool enablePolyPressure, bool supportsTuningNoteExpression); - void process(Steinberg::Vst::ProcessData& data); - void flush(); - void processOutputParams(Steinberg::Vst::ProcessData& data); - void activateAudioBus(Steinberg::Vst::BusDirection dir, Steinberg::int32 index, Steinberg::TBool state); - - // C callbacks - static uint32_t input_events_size(const struct clap_input_events* list); - static const clap_event_header_t* input_events_get(const struct clap_input_events* list, uint32_t index); - - static bool output_events_try_push(const struct clap_output_events* list, const clap_event_header_t* event); - private: - void sortEventIndices(); - void processInputEvents(Steinberg::Vst::IEventList* eventlist); - - bool enqueueOutputEvent(const clap_event_header_t* event); - void addToActiveNotes(const clap_event_note* note); - void removeFromActiveNotes(const clap_event_note* note); - - // the plugin - const clap_plugin_t* _plugin = nullptr; - const clap_plugin_params_t* _ext_params = nullptr; - - Steinberg::Vst::ParameterContainer* parameters = nullptr; - Steinberg::Vst::IComponentHandler* _componentHandler = nullptr; - IAutomation* _automation = nullptr; - Steinberg::Vst::BusList* _audioinputs = nullptr; - Steinberg::Vst::BusList* _audiooutputs = nullptr; - - // for automation gestures - std::vector _gesturedParameters; - - // for INoteExpression - struct ActiveNote - { - bool used = false; - int32_t note_id; // -1 if unspecified, otherwise >=0 - int16_t port_index; - int16_t channel; // 0..15 - int16_t key; // 0..127 - }; - std::vector _activeNotes; - - clap_audio_buffer_t* _input_ports = nullptr; - clap_audio_buffer_t* _output_ports = nullptr; - clap_event_transport_t _transport = {}; - clap_input_events_t _in_events = {}; - clap_output_events_t _out_events = {}; - - float* _silent_input = nullptr; - float* _silent_output = nullptr; - - clap_process_t _processData = { -1, 0, &_transport, nullptr, nullptr, 0, 0, &_in_events, &_out_events }; - - - Steinberg::Vst::ProcessData* _vstdata = nullptr; - - std::vector _events; - std::vector _eventindices; - - bool _supportsPolyPressure = false; - bool _supportsTuningNoteExpression = false; - - }; - -} \ No newline at end of file + void setupProcessing(const clap_plugin_t* plugin, const clap_plugin_params_t* ext_params, + Steinberg::Vst::BusList& numInputs, Steinberg::Vst::BusList& numOutputs, + uint32_t numSamples, size_t numEventInputs, size_t numEventOutputs, + Steinberg::Vst::ParameterContainer& params, + Steinberg::Vst::IComponentHandler* componenthandler, IAutomation* automation, + bool enablePolyPressure, bool supportsTuningNoteExpression); + void process(Steinberg::Vst::ProcessData& data); + void flush(); + void processOutputParams(Steinberg::Vst::ProcessData& data); + void activateAudioBus(Steinberg::Vst::BusDirection dir, Steinberg::int32 index, + Steinberg::TBool state); + + // C callbacks + static uint32_t input_events_size(const struct clap_input_events* list); + static const clap_event_header_t* input_events_get(const struct clap_input_events* list, + uint32_t index); + + static bool output_events_try_push(const struct clap_output_events* list, + const clap_event_header_t* event); + + private: + void sortEventIndices(); + void processInputEvents(Steinberg::Vst::IEventList* eventlist); + + bool enqueueOutputEvent(const clap_event_header_t* event); + void addToActiveNotes(const clap_event_note* note); + void removeFromActiveNotes(const clap_event_note* note); + + // the plugin + const clap_plugin_t* _plugin = nullptr; + const clap_plugin_params_t* _ext_params = nullptr; + + Steinberg::Vst::ParameterContainer* parameters = nullptr; + Steinberg::Vst::IComponentHandler* _componentHandler = nullptr; + IAutomation* _automation = nullptr; + Steinberg::Vst::BusList* _audioinputs = nullptr; + Steinberg::Vst::BusList* _audiooutputs = nullptr; + + // for automation gestures + std::vector _gesturedParameters; + + // for INoteExpression + struct ActiveNote + { + bool used = false; + int32_t note_id; // -1 if unspecified, otherwise >=0 + int16_t port_index; + int16_t channel; // 0..15 + int16_t key; // 0..127 + }; + std::vector _activeNotes; + + clap_audio_buffer_t* _input_ports = nullptr; + clap_audio_buffer_t* _output_ports = nullptr; + clap_event_transport_t _transport = {}; + clap_input_events_t _in_events = {}; + clap_output_events_t _out_events = {}; + + float* _silent_input = nullptr; + float* _silent_output = nullptr; + + clap_process_t _processData = {-1, 0, &_transport, nullptr, nullptr, 0, 0, &_in_events, &_out_events}; + + Steinberg::Vst::ProcessData* _vstdata = nullptr; + + std::vector _events; + std::vector _eventindices; + + bool _supportsPolyPressure = false; + bool _supportsTuningNoteExpression = false; +}; + +} // namespace Clap \ No newline at end of file diff --git a/src/detail/vst3/state.h b/src/detail/vst3/state.h index 7a5e4c3d..f1f7755f 100644 --- a/src/detail/vst3/state.h +++ b/src/detail/vst3/state.h @@ -11,32 +11,37 @@ class CLAPVST3StreamAdapter { -public: - CLAPVST3StreamAdapter(Steinberg::IBStream* stream) - : vst_stream(stream) + public: + CLAPVST3StreamAdapter(Steinberg::IBStream* stream) : vst_stream(stream) { } - operator const clap_istream_t* () const { return ∈ } - operator const clap_ostream_t* () const { return &out; } + operator const clap_istream_t*() const + { + return ∈ + } + operator const clap_ostream_t*() const + { + return &out; + } static int64_t read(const struct clap_istream* stream, void* buffer, uint64_t size) { auto self = static_cast(stream->ctx); Steinberg::int32 bytesRead = 0; - if (kResultOk == self->vst_stream->read(buffer, size, &bytesRead)) - return bytesRead; + if (kResultOk == self->vst_stream->read(buffer, (int32)size, &bytesRead)) return bytesRead; return -1; } static int64_t write(const struct clap_ostream* stream, const void* buffer, uint64_t size) { auto self = static_cast(stream->ctx); Steinberg::int32 bytesWritten = 0; - if (kResultOk == self->vst_stream->write(const_cast(buffer), size, &bytesWritten)) + if (kResultOk == self->vst_stream->write(const_cast(buffer), (int32)size, &bytesWritten)) return bytesWritten; return -1; } -private: + + private: Steinberg::IBStream* vst_stream = nullptr; - clap_istream_t in = { this, read }; - clap_ostream_t out = { this, write }; + clap_istream_t in = {this, read}; + clap_ostream_t out = {this, write}; }; diff --git a/src/wrapasauv2.cpp b/src/wrapasauv2.cpp index 17e9ac2b..1505faa9 100644 --- a/src/wrapasauv2.cpp +++ b/src/wrapasauv2.cpp @@ -1,24 +1 @@ -// -// EmptyPlugIns.cpp -// EmptyPlugIns - this is just the empty plugin shell from the SDK for now -// - -#include - -#if !defined(CLAP_AUSDK_BASE_CLASS) -#define CLAP_AUSDK_BASE_CLASS ausdk::MusicDeviceBase -#endif - -struct wrapAsAUV2 : public CLAP_AUSDK_BASE_CLASS -{ - using Base = CLAP_AUSDK_BASE_CLASS; - - wrapAsAUV2(AudioComponentInstance ci) : Base{ci, 1, 1} {} - bool StreamFormatWritable(AudioUnitScope, AudioUnitElement) override { return true; } - bool CanScheduleParameters() const override { return false; } - - - -}; - -AUSDK_COMPONENT_ENTRY(ausdk::AUMusicDeviceFactory, wrapAsAUV2) +#include "generated_entrypoints.hxx" \ No newline at end of file diff --git a/src/wrapasvst3.cpp b/src/wrapasvst3.cpp index 8c9b0ed3..2e081662 100644 --- a/src/wrapasvst3.cpp +++ b/src/wrapasvst3.cpp @@ -16,10 +16,10 @@ #define S16(x) reinterpret_cast(_T(x)) #endif #if MAC -#define S16(x) u ## x +#define S16(x) u##x #endif #if LIN -#define S16(x) u ## x +#define S16(x) u##x #endif struct ClapHostExtensions @@ -28,11 +28,13 @@ struct ClapHostExtensions { return static_cast(host->host_data); } - static void mark_dirty(const clap_host_t* host) { self(host)->mark_dirty(); } - const clap_host_state_t _state = { mark_dirty }; + static void mark_dirty(const clap_host_t* host) + { + self(host)->mark_dirty(); + } + const clap_host_state_t _state = {mark_dirty}; }; - tresult PLUGIN_API ClapAsVst3::initialize(FUnknown* context) { auto result = super::initialize(context); @@ -43,14 +45,13 @@ tresult PLUGIN_API ClapAsVst3::initialize(FUnknown* context) _plugin = Clap::Plugin::createInstance(*_library, _libraryIndex, this); } result = (_plugin->initialize()) ? kResultOk : kResultFalse; - if ( result ) + if (result) { _useIMidiMapping = checkMIDIDialectSupport(); } } if (_plugin) { - } return result; } @@ -69,25 +70,23 @@ tresult PLUGIN_API ClapAsVst3::setActive(TBool state) { if (state) { - if (_active) - return kResultFalse; - if (!_plugin->activate()) - return kResultFalse; + if (_active) return kResultFalse; + if (!_plugin->activate()) return kResultFalse; _active = true; _processAdapter = new Clap::ProcessAdapter(); - - auto supportsnoteexpression = (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_PRESSURE); + + auto supportsnoteexpression = + (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_PRESSURE); // the processAdapter needs to know a few things to intercommunicate between VST3 host and CLAP plugin. - _processAdapter->setupProcessing(_plugin->_plugin, _plugin->_ext._params, - this->audioInputs, this->audioOutputs, - this->_largestBlocksize, - this->eventInputs.size(), this->eventOutputs.size(), - parameters, componentHandler, this, - supportsnoteexpression, _expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_TUNING); + _processAdapter->setupProcessing( + _plugin->_plugin, _plugin->_ext._params, this->audioInputs, this->audioOutputs, + this->_largestBlocksize, this->eventInputs.size(), this->eventOutputs.size(), parameters, + componentHandler, this, supportsnoteexpression, + _expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_TUNING); updateAudioBusses(); - + os::attach(this); } if (!state) @@ -141,14 +140,13 @@ uint32 PLUGIN_API ClapAsVst3::getLatencySamples() uint32 PLUGIN_API ClapAsVst3::getTailSamples() { - // options would be kNoTail, number of samples or kInfiniteTail + // options would be kNoTail, number of samples or kInfiniteTail if (this->_plugin->_ext._tail) { auto tailsize = this->_plugin->_ext._tail->get(_plugin->_plugin); // Any value greater or equal to INT32_MAX implies infinite tail. - if (tailsize >= INT32_MAX) - return Vst::kInfiniteTail; + if (tailsize >= INT32_MAX) return Vst::kInfiniteTail; return tailsize; } return super::getTailSamples(); @@ -193,13 +191,13 @@ tresult PLUGIN_API ClapAsVst3::setProcessing(TBool state) } tresult PLUGIN_API ClapAsVst3::setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, - Vst::SpeakerArrangement* outputs, - int32 numOuts) + Vst::SpeakerArrangement* outputs, int32 numOuts) { return super::setBusArrangements(inputs, numIns, outputs, numOuts); }; -tresult PLUGIN_API ClapAsVst3::getBusArrangement(Vst::BusDirection dir, int32 index, Vst::SpeakerArrangement& arr) +tresult PLUGIN_API ClapAsVst3::getBusArrangement(Vst::BusDirection dir, int32 index, + Vst::SpeakerArrangement& arr) { return super::getBusArrangement(dir, index, arr); } @@ -226,7 +224,7 @@ IPlugView* PLUGIN_API ClapAsVst3::createView(FIDString name) attachTimers(_wrappedview->getRunLoop()); attachPosixFD(_wrappedview->getRunLoop()); #else - (void)this; // silence warning on non-linux + (void)this; // silence warning on non-linux #endif }); return _wrappedview; @@ -234,7 +232,8 @@ IPlugView* PLUGIN_API ClapAsVst3::createView(FIDString name) return nullptr; } -tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::ParamValue valueNormalized, Vst::String128 string) +tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::ParamValue valueNormalized, + Vst::String128 string) { auto param = (Vst3Parameter*)this->getParameterObject(id); auto val = param->asClapValue(valueNormalized); @@ -244,14 +243,15 @@ tresult PLUGIN_API ClapAsVst3::getParamStringByValue(Vst::ParamID id, Vst::Param if (this->_plugin->_ext._params->value_to_text(_plugin->_plugin, param->id, val, outbuf, 127)) { UString wrapper(&string[0], str16BufferSize(Steinberg::Vst::String128)); - - wrapper.assign(outbuf,sizeof(outbuf)); + + wrapper.assign(outbuf, sizeof(outbuf)); return kResultOk; } return super::getParamStringByValue(id, valueNormalized, string); } -tresult PLUGIN_API ClapAsVst3::getParamValueByString(Vst::ParamID id, Vst::TChar* string, Vst::ParamValue& valueNormalized) +tresult PLUGIN_API ClapAsVst3::getParamValueByString(Vst::ParamID id, Vst::TChar* string, + Vst::ParamValue& valueNormalized) { auto param = (Vst3Parameter*)this->getParameterObject(id); Steinberg::String m(string); @@ -264,10 +264,10 @@ tresult PLUGIN_API ClapAsVst3::getParamValueByString(Vst::ParamID id, Vst::TChar return kResultOk; } return Steinberg::kResultFalse; - } -tresult PLUGIN_API ClapAsVst3::activateBus(Vst::MediaType type, Vst::BusDirection dir, int32 index, TBool state) +tresult PLUGIN_API ClapAsVst3::activateBus(Vst::MediaType type, Vst::BusDirection dir, int32 index, + TBool state) { return super::activateBus(type, dir, index, state); } @@ -275,10 +275,11 @@ tresult PLUGIN_API ClapAsVst3::activateBus(Vst::MediaType type, Vst::BusDirectio //----------------------------------------------------------------------------- tresult PLUGIN_API ClapAsVst3::getMidiControllerAssignment(int32 busIndex, int16 channel, - Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id/*out*/) + Vst::CtrlNumber midiControllerNumber, + Vst::ParamID& id /*out*/) { // for my first Event bus and for MIDI channel 0 and for MIDI CC Volume only - if (busIndex == 0 ) // && channel == 0) // && midiControllerNumber == Vst::kCtrlVolume) + if (busIndex == 0) // && channel == 0) // && midiControllerNumber == Vst::kCtrlVolume) { id = _IMidiMappingIDs[channel][midiControllerNumber]; return kResultTrue; @@ -288,7 +289,7 @@ tresult PLUGIN_API ClapAsVst3::getMidiControllerAssignment(int32 busIndex, int16 #if 1 //----from INoteExpressionController------------------------- - /** Returns number of supported note change types for event bus index and channel. */ +/** Returns number of supported note change types for event bus index and channel. */ int32 ClapAsVst3::getNoteExpressionCount(int32 busIndex, int16 channel) { if (busIndex == 0 && channel == 0) @@ -296,11 +297,11 @@ int32 ClapAsVst3::getNoteExpressionCount(int32 busIndex, int16 channel) return _noteExpressions.getNoteExpressionCount(); } return 0; - } /** Returns note change type info. */ -tresult ClapAsVst3::getNoteExpressionInfo(int32 busIndex, int16 channel, int32 noteExpressionIndex, Vst::NoteExpressionTypeInfo& info /*out*/) +tresult ClapAsVst3::getNoteExpressionInfo(int32 busIndex, int16 channel, int32 noteExpressionIndex, + Vst::NoteExpressionTypeInfo& info /*out*/) { if (busIndex == 0 && channel == 0) { @@ -310,15 +311,21 @@ tresult ClapAsVst3::getNoteExpressionInfo(int32 busIndex, int16 channel, int32 n } /** Gets a user readable representation of the normalized note change value. */ -tresult ClapAsVst3::getNoteExpressionStringByValue(int32 busIndex, int16 channel, Vst::NoteExpressionTypeID id, Vst::NoteExpressionValue valueNormalized /*in*/, Vst::String128 string /*out*/) +tresult ClapAsVst3::getNoteExpressionStringByValue(int32 busIndex, int16 channel, + Vst::NoteExpressionTypeID id, + Vst::NoteExpressionValue valueNormalized /*in*/, + Vst::String128 string /*out*/) { return _noteExpressions.getNoteExpressionStringByValue(id, valueNormalized, string); } /** Converts the user readable representation to the normalized note change value. */ -tresult ClapAsVst3::getNoteExpressionValueByString(int32 busIndex, int16 channel, Vst::NoteExpressionTypeID id, const Vst::TChar* string /*in*/, Vst::NoteExpressionValue& valueNormalized /*out*/) +tresult ClapAsVst3::getNoteExpressionValueByString(int32 busIndex, int16 channel, + Vst::NoteExpressionTypeID id, + const Vst::TChar* string /*in*/, + Vst::NoteExpressionValue& valueNormalized /*out*/) { - return _noteExpressions.getNoteExpressionValueByString(id, string, valueNormalized); + return _noteExpressions.getNoteExpressionValueByString(id, string, valueNormalized); } #endif @@ -332,15 +339,13 @@ tresult ClapAsVst3::getNoteExpressionValueByString(int32 busIndex, int16 channel static Vst::SpeakerArrangement speakerArrFromPortType(const char* port_type) { - static const std::pair arrangementmap[] = - { - {CLAP_PORT_MONO, Vst::SpeakerArr::kMono}, - {CLAP_PORT_STEREO, Vst::SpeakerArr::kStereo}, - // {CLAP_PORT_AMBISONIC, Vst::SpeakerArr::kAmbi1stOrderACN} <- we need also CLAP_EXT_AMBISONIC - // {CLAP_PORT_SURROUND, Vst::SpeakerArr::kStereoSurround}, // add when CLAP_EXT_SURROUND is not draft anymore - // TODO: add more PortTypes to Speaker Arrangement - {nullptr,Vst::SpeakerArr::kEmpty} - }; + static const std::pair arrangementmap[] = { + {CLAP_PORT_MONO, Vst::SpeakerArr::kMono}, + {CLAP_PORT_STEREO, Vst::SpeakerArr::kStereo}, + // {CLAP_PORT_AMBISONIC, Vst::SpeakerArr::kAmbi1stOrderACN} <- we need also CLAP_EXT_AMBISONIC + // {CLAP_PORT_SURROUND, Vst::SpeakerArr::kStereoSurround}, // add when CLAP_EXT_SURROUND is not draft anymore + // TODO: add more PortTypes to Speaker Arrangement + {nullptr, Vst::SpeakerArr::kEmpty}}; auto p = &arrangementmap[0]; while (p->first) @@ -370,13 +375,12 @@ void ClapAsVst3::addAudioBusFrom(const clap_audio_port_info_t* info, bool is_inp { addAudioOutput(name16, spk, bustype, Vst::BusInfo::kDefaultActive); } - - } void ClapAsVst3::addMIDIBusFrom(const clap_note_port_info_t* info, uint32_t index, bool is_input) { - if ((info->supported_dialects & CLAP_NOTE_DIALECT_MIDI) || (info->supported_dialects & CLAP_NOTE_DIALECT_CLAP)) + if ((info->supported_dialects & CLAP_NOTE_DIALECT_MIDI) || + (info->supported_dialects & CLAP_NOTE_DIALECT_CLAP)) { auto numchannels = 16; if (_vst3specifics) @@ -399,15 +403,14 @@ void ClapAsVst3::addMIDIBusFrom(const clap_note_port_info_t* info, uint32_t inde void ClapAsVst3::updateAudioBusses() { - for ( auto i = 0U; i < audioInputs.size() ; ++i) + for (auto i = 0U; i < audioInputs.size(); ++i) { - _processAdapter->activateAudioBus(Vst::kInput, i,audioInputs[i]->isActive()); + _processAdapter->activateAudioBus(Vst::kInput, i, audioInputs[i]->isActive()); } for (auto i = 0U; i < audioOutputs.size(); ++i) { _processAdapter->activateAudioBus(Vst::kOutput, i, audioOutputs[i]->isActive()); } - } static std::vector split(const std::string& s, char delimiter) @@ -439,7 +442,7 @@ Vst::UnitID ClapAsVst3::getOrCreateUnitInfo(const char* modulename) // the module name is not yet present as unit, so // we will ensure that it is being created one by one - auto path = split(modulename,'/'); + auto path = split(modulename, '/'); std::string curpath; Vst::UnitID id = Vst::kRootUnitId; // there is already a root element size_t i = 0; @@ -479,7 +482,7 @@ Vst::UnitID ClapAsVst3::getOrCreateUnitInfo(const char* modulename) void ClapAsVst3::setupWrapperSpecifics(const clap_plugin_t* plugin) { - _vst3specifics = (clap_plugin_as_vst3_t*) plugin->get_extension(plugin, CLAP_PLUGIN_AS_VST3); + _vst3specifics = (clap_plugin_as_vst3_t*)plugin->get_extension(plugin, CLAP_PLUGIN_AS_VST3); if (_vst3specifics) { _numMidiChannels = _vst3specifics->getNumMIDIChannels(_plugin->_plugin, 0); @@ -491,26 +494,27 @@ bool ClapAsVst3::checkMIDIDialectSupport() { // check if the plugin supports noteports and if one of the note ports supports MIDI dialect auto noteports = _plugin->_ext._noteports; - if (noteports ) + if (noteports) { auto numMIDIInputs = noteports->count(_plugin->_plugin, true); - for (uint32_t i = 0 ; i < numMIDIInputs ; ++i ) + for (uint32_t i = 0; i < numMIDIInputs; ++i) { clap_note_port_info_t info; - if ( noteports->get(_plugin->_plugin,i,true,&info) ) + if (noteports->get(_plugin->_plugin, i, true, &info)) { - if ( info.supported_dialects & CLAP_NOTE_DIALECT_MIDI ) + if (info.supported_dialects & CLAP_NOTE_DIALECT_MIDI) { return true; } } } } - + return false; } -void ClapAsVst3::setupAudioBusses(const clap_plugin_t* plugin, const clap_plugin_audio_ports_t* audioports) +void ClapAsVst3::setupAudioBusses(const clap_plugin_t* plugin, + const clap_plugin_audio_ports_t* audioports) { if (!audioports) return; auto numAudioInputs = audioports->count(plugin, true); @@ -578,7 +582,8 @@ void ClapAsVst3::setupParameters(const clap_plugin_t* plugin, const clap_plugin_ { Vst::String128 rootname(STR16("root")); - Vst::Unit* newunit = new Vst::Unit(rootname, Vst::kNoParentUnitId, Vst::kRootUnitId); // a new unit without a program list + Vst::Unit* newunit = new Vst::Unit(rootname, Vst::kNoParentUnitId, + Vst::kRootUnitId); // a new unit without a program list addUnit(newunit); } @@ -590,21 +595,19 @@ void ClapAsVst3::setupParameters(const clap_plugin_t* plugin, const clap_plugin_ clap_param_info info; if (params->get_info(plugin, i, &info)) { - auto p = Vst3Parameter::create(&info, [&](const char* modstring) - { - return this->getOrCreateUnitInfo(modstring); - }); + auto p = Vst3Parameter::create( + &info, [&](const char* modstring) { return this->getOrCreateUnitInfo(modstring); }); // auto p = Vst3Parameter::create(&info,nullptr); parameters.addParameter(p); } } - if ( _useIMidiMapping ) + if (_useIMidiMapping) { // find free tags for IMidiMapping Vst::ParamID x = 0xb00000; _IMidiMappingEasy = true; - + for (uint8_t channel = 0; channel < _numMidiChannels; channel++) { for (int i = 0; i < Vst::ControllerNumbers::kCountCtrlNumber; ++i) @@ -624,41 +627,37 @@ void ClapAsVst3::setupParameters(const clap_plugin_t* plugin, const clap_plugin_ } // setting up noteexpression - + if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_VOLUME) - _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kVolumeTypeID, S16("Volume"), S16("Vol"), S16(""), 0, nullptr, 0) - ); + _noteExpressions.addNoteExpressionType(new Vst::NoteExpressionType( + Vst::NoteExpressionTypeIDs::kVolumeTypeID, S16("Volume"), S16("Vol"), S16(""), 0, nullptr, 0)); if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_PAN) - _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kPanTypeID, S16("Panorama"), S16("Pan"), S16(""), 0, nullptr, 0) - ); + _noteExpressions.addNoteExpressionType(new Vst::NoteExpressionType( + Vst::NoteExpressionTypeIDs::kPanTypeID, S16("Panorama"), S16("Pan"), S16(""), 0, nullptr, 0)); if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_TUNING) - _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kTuningTypeID, S16("Tuning"), S16("Tun"), S16(""), 0, nullptr, 0) - ); + _noteExpressions.addNoteExpressionType(new Vst::NoteExpressionType( + Vst::NoteExpressionTypeIDs::kTuningTypeID, S16("Tuning"), S16("Tun"), S16(""), 0, nullptr, 0)); if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_VIBRATO) _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kVibratoTypeID, S16("Vibrato"), S16("Vibr"), S16(""), 0, nullptr, 0) - ); + new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kVibratoTypeID, S16("Vibrato"), + S16("Vibr"), S16(""), 0, nullptr, 0)); if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_EXPRESSION) _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kExpressionTypeID, S16("Expression"), S16("Expr"), S16(""), 0, nullptr, 0) - ); + new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kExpressionTypeID, S16("Expression"), + S16("Expr"), S16(""), 0, nullptr, 0)); if (_expressionmap & clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_BRIGHTNESS) _noteExpressions.addNoteExpressionType( - new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kBrightnessTypeID, S16("Brightness"), S16("Brit"), S16(""), 0, nullptr, 0) - ); + new Vst::NoteExpressionType(Vst::NoteExpressionTypeIDs::kBrightnessTypeID, S16("Brightness"), + S16("Brit"), S16(""), 0, nullptr, 0)); // PRESSURE is handled by IMidiMapping (-> Polypressure) } - void ClapAsVst3::param_rescan(clap_param_rescan_flags flags) { auto vstflags = 0u; @@ -668,8 +667,11 @@ void ClapAsVst3::param_rescan(clap_param_rescan_flags flags) vstflags |= Vst::RestartFlags::kMidiCCAssignmentChanged; } - vstflags |= ((flags & CLAP_PARAM_RESCAN_VALUES) ? (uint32_t)Vst::RestartFlags::kParamValuesChanged : 0u); - vstflags |= ((flags & CLAP_PARAM_RESCAN_INFO) ? Vst::RestartFlags::kParamValuesChanged | Vst::RestartFlags::kParamTitlesChanged : 0u); + vstflags |= + ((flags & CLAP_PARAM_RESCAN_VALUES) ? (uint32_t)Vst::RestartFlags::kParamValuesChanged : 0u); + vstflags |= ((flags & CLAP_PARAM_RESCAN_INFO) + ? Vst::RestartFlags::kParamValuesChanged | Vst::RestartFlags::kParamTitlesChanged + : 0u); if (vstflags != 0) { // update parameter values in our own tree @@ -693,7 +695,6 @@ void ClapAsVst3::param_rescan(clap_param_rescan_flags flags) } this->componentHandler->restartComponent(vstflags); } - } void ClapAsVst3::param_clear(clap_id param, clap_param_clear_flags flags) @@ -719,8 +720,7 @@ bool ClapAsVst3::gui_request_resize(uint32_t width, uint32_t height) bool ClapAsVst3::gui_request_show() { - if (componentHandler2) - return (componentHandler2->requestOpenEditor() == kResultOk); + if (componentHandler2) return (componentHandler2->requestOpenEditor() == kResultOk); return false; } @@ -743,8 +743,7 @@ void ClapAsVst3::tail_changed() void ClapAsVst3::mark_dirty() { - if (componentHandler2) - componentHandler2->setDirty(true); + if (componentHandler2) componentHandler2->setDirty(true); } void ClapAsVst3::request_callback() @@ -753,7 +752,7 @@ void ClapAsVst3::request_callback() } void ClapAsVst3::restartPlugin() -{ +{ if (componentHandler) componentHandler->restartComponent(Vst::RestartFlags::kReloadComponent); } @@ -761,7 +760,6 @@ void ClapAsVst3::onBeginEdit(clap_id id) { // receive beginEdit and pass it to the internal queue _queueToUI.push(beginEvent(id)); - } void ClapAsVst3::onPerformEdit(const clap_event_param_value_t* value) { @@ -771,7 +769,6 @@ void ClapAsVst3::onPerformEdit(const clap_event_param_value_t* value) void ClapAsVst3::onEndEdit(clap_id id) { _queueToUI.push(endEvent(id)); - } // ext-timer @@ -804,8 +801,8 @@ bool ClapAsVst3::register_timer(uint32_t period_ms, clap_id* timer_id) } } // create a new timer object - auto newid = (clap_id)(l+1000); - TimerObject f{ period_ms, os::getTickInMS() + period_ms, newid }; + auto newid = (clap_id)(l + 1000); + TimerObject f{period_ms, os::getTickInMS() + period_ms, newid}; *timer_id = newid; _timersObjects.push_back(f); #if LIN @@ -825,7 +822,7 @@ bool ClapAsVst3::unregister_timer(clap_id timer_id) #if LIN if (to.handler && _iRunLoop) { - _iRunLoop->unregisterTimer(to.handler.get()); + _iRunLoop->unregisterTimer(to.handler.get()); } to.handler.reset(); #endif @@ -843,19 +840,19 @@ void ClapAsVst3::onIdle() { switch (n._type) { - case queueEvent::type_t::editstart: - beginEdit(n._data._id); - break; - case queueEvent::type_t::editvalue: + case queueEvent::type_t::editstart: + beginEdit(n._data._id); + break; + case queueEvent::type_t::editvalue: { auto param = (Vst3Parameter*)(parameters.getParameter(n._data._value.param_id & 0x7FFFFFFF)); auto v = n._data._value.value; performEdit(param->getInfo().id, param->asVst3Value(v)); } break; - case queueEvent::type_t::editend: - endEdit(n._data._id); - break; + case queueEvent::type_t::editend: + endEdit(n._data._id); + break; } } @@ -868,7 +865,8 @@ void ClapAsVst3::onIdle() { // setup a ProcessAdapter just for flush with no audio Clap::ProcessAdapter pa; - pa.setupProcessing(_plugin->_plugin, _plugin->_ext._params, audioInputs, audioOutputs, 0, 0, 0, this->parameters, componentHandler, nullptr, false, false); + pa.setupProcessing(_plugin->_plugin, _plugin->_ext._params, audioInputs, audioOutputs, 0, 0, 0, + this->parameters, componentHandler, nullptr, false, false); pa.flush(); } } @@ -880,23 +878,23 @@ void ClapAsVst3::onIdle() } #if LIN - if (!_iRunLoop) // don't process timers if we have a runloop. - // (but if we don't have a runloop on linux onIdle isn't called - // anyway so consider just not having this at all once we decide - // to do with the no UI case) + if (!_iRunLoop) // don't process timers if we have a runloop. + // (but if we don't have a runloop on linux onIdle isn't called + // anyway so consider just not having this at all once we decide + // to do with the no UI case) #endif { // handling timerobjects auto now = os::getTickInMS(); - for (auto &&to : _timersObjects) + for (auto&& to : _timersObjects) { if (to.period > 0) { - if (to.nexttick < now) - { + if (to.nexttick < now) + { to.nexttick = now + to.period; this->_plugin->_ext._timer->on_timer(_plugin->_plugin, to.timer_id); - } + } } } } @@ -905,13 +903,15 @@ void ClapAsVst3::onIdle() #if LIN struct TimerHandler : Steinberg::Linux::ITimerHandler, public Steinberg::FObject { - ClapAsVst3 *_parent{nullptr}; + ClapAsVst3* _parent{nullptr}; clap_id _timerId{0}; - TimerHandler(ClapAsVst3 *parent, clap_id timerId) - : _parent(parent), _timerId(timerId) + TimerHandler(ClapAsVst3* parent, clap_id timerId) : _parent(parent), _timerId(timerId) + { + } + void PLUGIN_API onTimer() final { + _parent->fireTimer(_timerId); } - void PLUGIN_API onTimer() final { _parent->fireTimer(_timerId); } DELEGATE_REFCOUNT(Steinberg::FObject) DEFINE_INTERFACES DEF_INTERFACE(Steinberg::Linux::ITimerHandler) @@ -920,16 +920,21 @@ struct TimerHandler : Steinberg::Linux::ITimerHandler, public Steinberg::FObject struct IdleHandler : Steinberg::Linux::ITimerHandler, public Steinberg::FObject { - ClapAsVst3 *_parent{nullptr}; - IdleHandler(ClapAsVst3 *parent) : _parent(parent) {} - void PLUGIN_API onTimer() final { _parent->onIdle(); } + ClapAsVst3* _parent{nullptr}; + IdleHandler(ClapAsVst3* parent) : _parent(parent) + { + } + void PLUGIN_API onTimer() final + { + _parent->onIdle(); + } DELEGATE_REFCOUNT(Steinberg::FObject) DEFINE_INTERFACES DEF_INTERFACE(Steinberg::Linux::ITimerHandler) END_DEFINE_INTERFACES(Steinberg::FObject) }; -void ClapAsVst3::attachTimers(Steinberg::Linux::IRunLoop *r) +void ClapAsVst3::attachTimers(Steinberg::Linux::IRunLoop* r) { if (r) { @@ -945,7 +950,7 @@ void ClapAsVst3::attachTimers(Steinberg::Linux::IRunLoop *r) } _iRunLoop->registerTimer(_idleHandler.get(), 30); - for (auto &t : _timersObjects) + for (auto& t : _timersObjects) { if (!t.handler) { @@ -956,7 +961,7 @@ void ClapAsVst3::attachTimers(Steinberg::Linux::IRunLoop *r) } } -void ClapAsVst3::detachTimers(Steinberg::Linux::IRunLoop *r) +void ClapAsVst3::detachTimers(Steinberg::Linux::IRunLoop* r) { if (r && r == _iRunLoop) { @@ -965,7 +970,7 @@ void ClapAsVst3::detachTimers(Steinberg::Linux::IRunLoop *r) _iRunLoop->unregisterTimer(_idleHandler.get()); _idleHandler.reset(); } - for (auto &t : _timersObjects) + for (auto& t : _timersObjects) { if (t.handler) { @@ -990,7 +995,7 @@ bool ClapAsVst3::register_fd(int fd, clap_posix_fd_flags_t flags) bool ClapAsVst3::modify_fd(int fd, clap_posix_fd_flags_t flags) { bool res{false}; - for (auto &p : _posixFDObjects) + for (auto& p : _posixFDObjects) { if (p.fd == fd) { @@ -1027,11 +1032,11 @@ bool ClapAsVst3::unregister_fd(int fd) struct FDHandler : Steinberg::Linux::IEventHandler, public Steinberg::FObject { - ClapAsVst3 *_parent{nullptr}; + ClapAsVst3* _parent{nullptr}; int _fd{0}; clap_posix_fd_flags_t _flags{}; - FDHandler(ClapAsVst3 *parent, int fd, clap_posix_fd_flags_t flags) - : _parent(parent), _fd(fd), _flags(flags) + FDHandler(ClapAsVst3* parent, int fd, clap_posix_fd_flags_t flags) + : _parent(parent), _fd(fd), _flags(flags) { } void PLUGIN_API onFDIsSet(Steinberg::Linux::FileDescriptor) override @@ -1043,13 +1048,13 @@ struct FDHandler : Steinberg::Linux::IEventHandler, public Steinberg::FObject DEF_INTERFACE(Steinberg::Linux::IEventHandler) END_DEFINE_INTERFACES(Steinberg::FObject) }; -void ClapAsVst3::attachPosixFD(Steinberg::Linux::IRunLoop *r) +void ClapAsVst3::attachPosixFD(Steinberg::Linux::IRunLoop* r) { if (r) { _iRunLoop = r; - for (auto &p : _posixFDObjects) + for (auto& p : _posixFDObjects) { if (!p.handler) { @@ -1060,11 +1065,11 @@ void ClapAsVst3::attachPosixFD(Steinberg::Linux::IRunLoop *r) } } -void ClapAsVst3::detachPosixFD(Steinberg::Linux::IRunLoop *r) +void ClapAsVst3::detachPosixFD(Steinberg::Linux::IRunLoop* r) { if (r && r == _iRunLoop) { - for (auto &p : _posixFDObjects) + for (auto& p : _posixFDObjects) { if (p.handler) { diff --git a/src/wrapasvst3.h b/src/wrapasvst3.h index 5403e5d9..579bbf33 100644 --- a/src/wrapasvst3.h +++ b/src/wrapasvst3.h @@ -30,7 +30,7 @@ #endif #include "detail/vst3/plugview.h" -#include "detail/os/osutil.h" +#include "detail/vst3/os/osutil.h" #include "detail/clap/automation.h" #include @@ -39,279 +39,286 @@ using namespace Steinberg; struct ClapHostExtensions; namespace Clap { - class ProcessAdapter; +class ProcessAdapter; } class queueEvent { -public: - typedef enum class type - { - editstart, - editvalue, - editend, - } type_t; - type_t _type; - union - { - clap_id _id; - clap_event_param_value_t _value; - } _data; + public: + typedef enum class type + { + editstart, + editvalue, + editend, + } type_t; + type_t _type; + union + { + clap_id _id; + clap_event_param_value_t _value; + } _data; }; class beginEvent : public queueEvent { -public: - beginEvent(clap_id id) - : queueEvent() - { - this->_type = type::editstart; - _data._id = id; - } + public: + beginEvent(clap_id id) : queueEvent() + { + this->_type = type::editstart; + _data._id = id; + } }; class endEvent : public queueEvent { -public: - endEvent(clap_id id) - : queueEvent() - { - this->_type = type::editend; - _data._id = id; - } + public: + endEvent(clap_id id) : queueEvent() + { + this->_type = type::editend; + _data._id = id; + } }; class valueEvent : public queueEvent { -public: - valueEvent(const clap_event_param_value_t* value) - : queueEvent() - { - _type = type::editvalue; - _data._value = *value; - } + public: + valueEvent(const clap_event_param_value_t* value) : queueEvent() + { + _type = type::editvalue; + _data._value = *value; + } }; -class ClapAsVst3 : public Steinberg::Vst::SingleComponentEffect - , public Steinberg::Vst::IMidiMapping - , public Steinberg::Vst::INoteExpressionController - , public Clap::IHost - , public Clap::IAutomation - , public os::IPlugObject +class ClapAsVst3 : public Steinberg::Vst::SingleComponentEffect, + public Steinberg::Vst::IMidiMapping, + public Steinberg::Vst::INoteExpressionController, + public Clap::IHost, + public Clap::IAutomation, + public os::IPlugObject { -public: - - using super = Steinberg::Vst::SingleComponentEffect; - - static FUnknown* createInstance(void* context); - - ClapAsVst3(Clap::Library* lib, int number, void* context) - : super() - , Steinberg::Vst::IMidiMapping() - , Steinberg::Vst::INoteExpressionController() - , _library(lib) - , _libraryIndex(number) - , _creationcontext(context) {} - - //---from IComponent----------------------- - tresult PLUGIN_API initialize(FUnknown* context) override; - tresult PLUGIN_API terminate() override; - tresult PLUGIN_API setActive(TBool state) override; - tresult PLUGIN_API process(Vst::ProcessData& data) override; - tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override; - tresult PLUGIN_API setState(IBStream* state) override; - tresult PLUGIN_API getState(IBStream* state) override; - uint32 PLUGIN_API getLatencySamples() override; - uint32 PLUGIN_API getTailSamples() override; - tresult PLUGIN_API setupProcessing(Vst::ProcessSetup& newSetup) override; - tresult PLUGIN_API setProcessing(TBool state) override; - tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, - Vst::SpeakerArrangement* outputs, - int32 numOuts) override; - tresult PLUGIN_API getBusArrangement(Vst::BusDirection dir, int32 index, Vst::SpeakerArrangement& arr) override; - tresult PLUGIN_API activateBus(Vst::MediaType type, Vst::BusDirection dir, int32 index, - TBool state) override; - - //----from IEditControllerEx1-------------------------------- - IPlugView* PLUGIN_API createView(FIDString name) override; - /** Gets for a given paramID and normalized value its associated string representation. */ - tresult PLUGIN_API getParamStringByValue(Vst::ParamID id, Vst::ParamValue valueNormalized /*in*/, Vst::String128 string /*out*/) override; - /** Gets for a given paramID and string its normalized value. */ - tresult PLUGIN_API getParamValueByString(Vst::ParamID id, Vst::TChar* string /*in*/, Vst::ParamValue& valueNormalized /*out*/) override; - - //----from IMidiMapping-------------------------------------- - tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, - Vst::CtrlNumber midiControllerNumber, Vst::ParamID& id/*out*/) override; - -#if 1 - //----from INoteExpressionController------------------------- - /** Returns number of supported note change types for event bus index and channel. */ - int32 PLUGIN_API getNoteExpressionCount(int32 busIndex, int16 channel) override; - - /** Returns note change type info. */ - tresult PLUGIN_API getNoteExpressionInfo(int32 busIndex, int16 channel, int32 noteExpressionIndex, Vst::NoteExpressionTypeInfo& info /*out*/) override; + public: + using super = Steinberg::Vst::SingleComponentEffect; + + static FUnknown* createInstance(void* context); + + ClapAsVst3(Clap::Library* lib, int number, void* context) + : super() + , Steinberg::Vst::IMidiMapping() + , Steinberg::Vst::INoteExpressionController() + , _library(lib) + , _libraryIndex(number) + , _creationcontext(context) + { + } - /** Gets a user readable representation of the normalized note change value. */ - tresult PLUGIN_API getNoteExpressionStringByValue(int32 busIndex, int16 channel, Vst::NoteExpressionTypeID id, Vst::NoteExpressionValue valueNormalized /*in*/, Vst::String128 string /*out*/) override; + //---from IComponent----------------------- + tresult PLUGIN_API initialize(FUnknown* context) override; + tresult PLUGIN_API terminate() override; + tresult PLUGIN_API setActive(TBool state) override; + tresult PLUGIN_API process(Vst::ProcessData& data) override; + tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override; + tresult PLUGIN_API setState(IBStream* state) override; + tresult PLUGIN_API getState(IBStream* state) override; + uint32 PLUGIN_API getLatencySamples() override; + uint32 PLUGIN_API getTailSamples() override; + tresult PLUGIN_API setupProcessing(Vst::ProcessSetup& newSetup) override; + tresult PLUGIN_API setProcessing(TBool state) override; + tresult PLUGIN_API setBusArrangements(Vst::SpeakerArrangement* inputs, int32 numIns, + Vst::SpeakerArrangement* outputs, int32 numOuts) override; + tresult PLUGIN_API getBusArrangement(Vst::BusDirection dir, int32 index, + Vst::SpeakerArrangement& arr) override; + tresult PLUGIN_API activateBus(Vst::MediaType type, Vst::BusDirection dir, int32 index, + TBool state) override; + + //----from IEditControllerEx1-------------------------------- + IPlugView* PLUGIN_API createView(FIDString name) override; + /** Gets for a given paramID and normalized value its associated string representation. */ + tresult PLUGIN_API getParamStringByValue(Vst::ParamID id, Vst::ParamValue valueNormalized /*in*/, + Vst::String128 string /*out*/) override; + /** Gets for a given paramID and string its normalized value. */ + tresult PLUGIN_API getParamValueByString(Vst::ParamID id, Vst::TChar* string /*in*/, + Vst::ParamValue& valueNormalized /*out*/) override; + + //----from IMidiMapping-------------------------------------- + tresult PLUGIN_API getMidiControllerAssignment(int32 busIndex, int16 channel, + Vst::CtrlNumber midiControllerNumber, + Vst::ParamID& id /*out*/) override; - /** Converts the user readable representation to the normalized note change value. */ - tresult PLUGIN_API getNoteExpressionValueByString(int32 busIndex, int16 channel, Vst::NoteExpressionTypeID id, const Vst::TChar* string /*in*/, Vst::NoteExpressionValue& valueNormalized /*out*/ ) override; +#if 1 + //----from INoteExpressionController------------------------- + /** Returns number of supported note change types for event bus index and channel. */ + int32 PLUGIN_API getNoteExpressionCount(int32 busIndex, int16 channel) override; + + /** Returns note change type info. */ + tresult PLUGIN_API getNoteExpressionInfo(int32 busIndex, int16 channel, int32 noteExpressionIndex, + Vst::NoteExpressionTypeInfo& info /*out*/) override; + + /** Gets a user readable representation of the normalized note change value. */ + tresult PLUGIN_API getNoteExpressionStringByValue(int32 busIndex, int16 channel, + Vst::NoteExpressionTypeID id, + Vst::NoteExpressionValue valueNormalized /*in*/, + Vst::String128 string /*out*/) override; + + /** Converts the user readable representation to the normalized note change value. */ + tresult PLUGIN_API getNoteExpressionValueByString( + int32 busIndex, int16 channel, Vst::NoteExpressionTypeID id, const Vst::TChar* string /*in*/, + Vst::NoteExpressionValue& valueNormalized /*out*/) override; #endif - //---Interface-------------------------------------------------------------------------- - OBJ_METHODS(ClapAsVst3, SingleComponentEffect) - DEFINE_INTERFACES + //---Interface-------------------------------------------------------------------------- + OBJ_METHODS(ClapAsVst3, SingleComponentEffect) + DEFINE_INTERFACES // since the macro above opens a local function, this code is being executed during QueryInterface() :) - if (::Steinberg::FUnknownPrivate::iidEqual (iid, IMidiMapping::iid)) + if (::Steinberg::FUnknownPrivate::iidEqual(iid, IMidiMapping::iid)) { // when queried for the IMididMapping interface, check if the CLAP supports MIDI dialect on the MIDI Input busses and only return IMidiMapping then - if ( _useIMidiMapping ) { + if (_useIMidiMapping) + { DEF_INTERFACE(IMidiMapping) } } - DEF_INTERFACE(INoteExpressionController) - // tresult PLUGIN_API queryInterface(const TUID iid, void** obj) override; - END_DEFINE_INTERFACES(SingleComponentEffect) - REFCOUNT_METHODS(SingleComponentEffect); - + DEF_INTERFACE(INoteExpressionController) + // tresult PLUGIN_API queryInterface(const TUID iid, void** obj) override; + END_DEFINE_INTERFACES(SingleComponentEffect) + REFCOUNT_METHODS(SingleComponentEffect); + //---Clap::IHost------------------------------------------------------------------------ - //---Clap::IHost------------------------------------------------------------------------ + void setupWrapperSpecifics(const clap_plugin_t* plugin) override; - void setupWrapperSpecifics(const clap_plugin_t* plugin) override; - - void setupAudioBusses(const clap_plugin_t* plugin, const clap_plugin_audio_ports_t* audioports) override; - void setupMIDIBusses(const clap_plugin_t* plugin, const clap_plugin_note_ports_t* noteports) override; + void setupAudioBusses(const clap_plugin_t* plugin, + const clap_plugin_audio_ports_t* audioports) override; + void setupMIDIBusses(const clap_plugin_t* plugin, const clap_plugin_note_ports_t* noteports) override; void setupParameters(const clap_plugin_t* plugin, const clap_plugin_params_t* params) override; - void param_rescan(clap_param_rescan_flags flags) override; - void param_clear(clap_id param, clap_param_clear_flags flags) override; - void param_request_flush() override; - - bool gui_can_resize() override; - bool gui_request_resize(uint32_t width, uint32_t height) override; - bool gui_request_show() override; - bool gui_request_hide() override; + void param_rescan(clap_param_rescan_flags flags) override; + void param_clear(clap_id param, clap_param_clear_flags flags) override; + void param_request_flush() override; - void latency_changed() override; + bool gui_can_resize() override; + bool gui_request_resize(uint32_t width, uint32_t height) override; + bool gui_request_show() override; + bool gui_request_hide() override; - void tail_changed() override; + void latency_changed() override; - void mark_dirty() override; + void tail_changed() override; - void restartPlugin() override; + void mark_dirty() override; - void request_callback() override; + void restartPlugin() override; - // clap_timer support - bool register_timer(uint32_t period_ms, clap_id* timer_id) override; - bool unregister_timer(clap_id timer_id) override; + void request_callback() override; + // clap_timer support + bool register_timer(uint32_t period_ms, clap_id* timer_id) override; + bool unregister_timer(clap_id timer_id) override; #if LIN - bool register_fd(int fd, clap_posix_fd_flags_t flags) override; - bool modify_fd(int fd, clap_posix_fd_flags_t flags) override; - bool unregister_fd(int fd) override; + bool register_fd(int fd, clap_posix_fd_flags_t flags) override; + bool modify_fd(int fd, clap_posix_fd_flags_t flags) override; + bool unregister_fd(int fd) override; #endif + public: + //----from IPlugObject + void onIdle() override; -public: - //----from IPlugObject - void onIdle() override; -private: - - // from Clap::IAutomation - void onBeginEdit(clap_id id) override; - void onPerformEdit(const clap_event_param_value_t* value) override; - void onEndEdit(clap_id id) override; + private: + // from Clap::IAutomation + void onBeginEdit(clap_id id) override; + void onPerformEdit(const clap_event_param_value_t* value) override; + void onEndEdit(clap_id id) override; // information function to enable/disable the IMIDIMapping interface bool checkMIDIDialectSupport(); -private: - // helper functions - void addAudioBusFrom(const clap_audio_port_info_t* info, bool is_input); - void addMIDIBusFrom(const clap_note_port_info_t* info, uint32_t index, bool is_input); - void updateAudioBusses(); - - Vst::UnitID getOrCreateUnitInfo(const char* modulename); - std::map _moduleToUnit; - - Clap::Library* _library = nullptr; - int _libraryIndex = 0; - std::shared_ptr _plugin; - ClapHostExtensions* _hostextensions = nullptr; - clap_plugin_as_vst3_t* _vst3specifics = nullptr; - Clap::ProcessAdapter* _processAdapter = nullptr; - WrappedView* _wrappedview = nullptr; - - void* _creationcontext; // context from the CLAP library - - // plugin state - bool _active = false; - bool _processing = false; - std::mutex _processingLock; - std::atomic_bool _requestedFlush = false; - std::atomic_bool _requestUICallback = false; - - // the queue from audiothread to UI thread - util::fixedqueue _queueToUI; - - // for IMidiMapping + + private: + // helper functions + void addAudioBusFrom(const clap_audio_port_info_t* info, bool is_input); + void addMIDIBusFrom(const clap_note_port_info_t* info, uint32_t index, bool is_input); + void updateAudioBusses(); + + Vst::UnitID getOrCreateUnitInfo(const char* modulename); + std::map _moduleToUnit; + + Clap::Library* _library = nullptr; + int _libraryIndex = 0; + std::shared_ptr _plugin; + ClapHostExtensions* _hostextensions = nullptr; + clap_plugin_as_vst3_t* _vst3specifics = nullptr; + Clap::ProcessAdapter* _processAdapter = nullptr; + WrappedView* _wrappedview = nullptr; + + void* _creationcontext; // context from the CLAP library + + // plugin state + bool _active = false; + bool _processing = false; + std::mutex _processingLock; + std::atomic_bool _requestedFlush = false; + std::atomic_bool _requestUICallback = false; + + // the queue from audiothread to UI thread + util::fixedqueue _queueToUI; + + // for IMidiMapping bool _useIMidiMapping = false; - Vst::ParamID _IMidiMappingIDs[16][Vst::ControllerNumbers::kCountCtrlNumber] = {}; // 16 MappingIDs for 16 Channels - bool _IMidiMappingEasy = true; - uint8_t _numMidiChannels = 16; - uint32_t _largestBlocksize = 0; - - // for timer - struct TimerObject - { - uint32_t period = 0; // if period is 0 the entry is unused (and can be reused) - uint64_t nexttick = 0; - clap_id timer_id = 0; + Vst::ParamID _IMidiMappingIDs[16][Vst::ControllerNumbers::kCountCtrlNumber] = + {}; // 16 MappingIDs for 16 Channels + bool _IMidiMappingEasy = true; + uint8_t _numMidiChannels = 16; + uint32_t _largestBlocksize = 0; + + // for timer + struct TimerObject + { + uint32_t period = 0; // if period is 0 the entry is unused (and can be reused) + uint64_t nexttick = 0; + clap_id timer_id = 0; #if LIN - Steinberg::IPtr handler = nullptr; + Steinberg::IPtr handler = nullptr; #endif - }; - std::vector _timersObjects; + }; + std::vector _timersObjects; #if LIN - Steinberg::IPtr _idleHandler; + Steinberg::IPtr _idleHandler; - void attachTimers(Steinberg::Linux::IRunLoop *); - void detachTimers(Steinberg::Linux::IRunLoop *); - Steinberg::Linux::IRunLoop *_iRunLoop{nullptr}; + void attachTimers(Steinberg::Linux::IRunLoop*); + void detachTimers(Steinberg::Linux::IRunLoop*); + Steinberg::Linux::IRunLoop* _iRunLoop{nullptr}; #endif - #if LIN - // for timer - struct PosixFDObject + // for timer + struct PosixFDObject + { + PosixFDObject(int f, clap_posix_fd_flags_t fl) : fd(f), flags(fl) { - PosixFDObject(int f, clap_posix_fd_flags_t fl) : fd(f), flags(fl) {} - int fd = 0; - clap_posix_fd_flags_t flags = 0; - Steinberg::IPtr handler = nullptr; - }; - std::vector _posixFDObjects; - - void attachPosixFD(Steinberg::Linux::IRunLoop *); - void detachPosixFD(Steinberg::Linux::IRunLoop *); + } + int fd = 0; + clap_posix_fd_flags_t flags = 0; + Steinberg::IPtr handler = nullptr; + }; + std::vector _posixFDObjects; + + void attachPosixFD(Steinberg::Linux::IRunLoop*); + void detachPosixFD(Steinberg::Linux::IRunLoop*); #endif -public: - void fireTimer(clap_id timer_id); - void firePosixFDIsSet(int fd, clap_posix_fd_flags_t flags); -private: + public: + void fireTimer(clap_id timer_id); + void firePosixFDIsSet(int fd, clap_posix_fd_flags_t flags); - // INoteExpression - Vst::NoteExpressionTypeContainer _noteExpressions; + private: + // INoteExpression + Vst::NoteExpressionTypeContainer _noteExpressions; - // add a copiler options for which NE to support - uint32_t _expressionmap = + // add a copiler options for which NE to support + uint32_t _expressionmap = #if CLAP_SUPPORTS_ALL_NOTE_EXPRESSIONS - clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_ALL; + clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_ALL; #else - clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_PRESSURE; + clap_supported_note_expressions::AS_VST3_NOTE_EXPRESSION_PRESSURE; #endif - }; diff --git a/src/wrapasvst3_entry.cpp b/src/wrapasvst3_entry.cpp index 764399bd..56b518a7 100644 --- a/src/wrapasvst3_entry.cpp +++ b/src/wrapasvst3_entry.cpp @@ -65,64 +65,63 @@ using namespace Steinberg::Vst; struct CreationContext { - Clap::Library* lib = nullptr; - int index = 0; - PClassInfo2 classinfo; + Clap::Library* lib = nullptr; + int index = 0; + PClassInfo2 classinfo; }; bool findPlugin(Clap::Library& lib, const std::string& pluginfilename) { - auto parentfolder = os::getParentFolderName(); - auto paths = Clap::getValidCLAPSearchPaths(); - - // Strategy 1: look for a clap with the same name as this binary - for (auto& i : paths) - { - if ( !fs::exists(i) ) - continue; - // try to find it the CLAP folder immediately - auto k1 = i / pluginfilename; - LOGDETAIL("scanning for binary: {}", k1.u8string().c_str()); - - if (fs::exists(k1)) - { - if (lib.load(k1.u8string().c_str())) - { - return true; - } - } - - // Strategy 2: try to locate "CLAP/vendorX/plugY.clap" - derived from "VST3/vendorX/plugY.vst3" - auto k2 = i / parentfolder / pluginfilename; - LOGDETAIL("scanning for binary: {}", k2.u8string().c_str()); - if (fs::exists(k2)) - { - if (lib.load(k2.u8string().c_str())) - { - return true; - } - } - - // Strategy 3: enumerate folders in CLAP folder and try to locate the plugin in any sub folder (only one level) - for (const auto& subdir : fs::directory_iterator(i)) - { - auto k3 = i / subdir / pluginfilename; - LOGDETAIL("scanning for binary: {}", k3.u8string().c_str()); - if (fs::exists(k3)) - { - if (lib.load(k3.u8string().c_str())) - { - return true; - } - } - } - } - - return false; + auto parentfolder = os::getParentFolderName(); + auto paths = Clap::getValidCLAPSearchPaths(); + + // Strategy 1: look for a clap with the same name as this binary + for (auto& i : paths) + { + if (!fs::exists(i)) continue; + // try to find it the CLAP folder immediately + auto k1 = i / pluginfilename; + LOGDETAIL("scanning for binary: {}", k1.u8string().c_str()); + + if (fs::exists(k1)) + { + if (lib.load(k1.u8string().c_str())) + { + return true; + } + } + + // Strategy 2: try to locate "CLAP/vendorX/plugY.clap" - derived from "VST3/vendorX/plugY.vst3" + auto k2 = i / parentfolder / pluginfilename; + LOGDETAIL("scanning for binary: {}", k2.u8string().c_str()); + if (fs::exists(k2)) + { + if (lib.load(k2.u8string().c_str())) + { + return true; + } + } + + // Strategy 3: enumerate folders in CLAP folder and try to locate the plugin in any sub folder (only one level) + for (const auto& subdir : fs::directory_iterator(i)) + { + auto k3 = i / subdir / pluginfilename; + LOGDETAIL("scanning for binary: {}", k3.u8string().c_str()); + if (fs::exists(k3)) + { + if (lib.load(k3.u8string().c_str())) + { + return true; + } + } + } + } + + return false; } -IPluginFactory* GetPluginFactoryEntryPoint() { - +IPluginFactory* GetPluginFactoryEntryPoint() +{ #if _DEBUG // MessageBoxA(NULL,"halt","me",MB_OK); // <- enable this on Windows to get a debug attachment to vstscanner.exe (subprocess of cbse) #endif @@ -131,174 +130,166 @@ IPluginFactory* GetPluginFactoryEntryPoint() { // #pragma comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) #endif - // static IPtr gPluginFactory = nullptr; - static Clap::Library gClapLibrary; - - static std::vector gCreationContexts; - - // if there is no ClapLibrary yet - if (!gClapLibrary._pluginFactory) - { - // if this binary does not already contain a CLAP entrypoint - if (!gClapLibrary.hasEntryPoint()) - { - // try to find a clap which filename stem matches our own - auto kx = os::getParentFolderName(); - auto plugname = os::getBinaryName(); - plugname.append(".clap"); - - if (!findPlugin(gClapLibrary, plugname)) - { - return nullptr; - } - } - else - { - LOGDETAIL("detected entrypoint in this binary"); - } - } - if (gClapLibrary.plugins.empty()) - { - // with no plugins there is nothing to do.. - LOGINFO("no plugin has been found"); - return nullptr; - } - - if (!clap_version_is_compatible(gClapLibrary.plugins[0]->clap_version)) - { - // CLAP version is not compatible -> eject - LOGINFO("CLAP version is not compatible"); - return nullptr; - } - - if (!gPluginFactory) - { - // we need at least one plugin to obtain vendor/name etc. - auto* factoryvendor = gClapLibrary.plugins[0]->vendor; - auto* vendor_url = gClapLibrary.plugins[0]->url; - // TODO: extract the domain and prefix with info@ - auto* contact = "info@"; - - // override for VST3 specifics - if (gClapLibrary._pluginFactoryVst3Info) - { - - LOGDETAIL("detected extension `{}`", CLAP_PLUGIN_FACTORY_INFO_VST3); - auto& v3 = gClapLibrary._pluginFactoryVst3Info; - if (v3->vendor) factoryvendor = v3->vendor; - if (v3->vendor_url) vendor_url = v3->vendor_url; - if (v3->email_contact) contact = v3->email_contact; - } - - static PFactoryInfo factoryInfo( - factoryvendor, - vendor_url, - contact, - Vst::kDefaultFactoryFlags); - - LOGDETAIL("created factory for vendor '{}'", factoryvendor); - - gPluginFactory = new Steinberg::CPluginFactory(factoryInfo); - // resize the classInfo vector - gCreationContexts.clear(); - gCreationContexts.reserve(gClapLibrary.plugins.size()); - int numPlugins = static_cast(gClapLibrary.plugins.size()); - LOGDETAIL("number of plugins in factory: {}", numPlugins); - for (int ctr = 0; ctr < numPlugins; ++ctr) - { - auto& clapdescr = gClapLibrary.plugins[ctr]; - auto vst3info = gClapLibrary.get_vst3_info(ctr); - - LOGDETAIL(" plugin #{}: '{}'", ctr, clapdescr->name); - - std::string n(clapdescr->name); + // static IPtr gPluginFactory = nullptr; + static Clap::Library gClapLibrary; + + static std::vector gCreationContexts; + + // if there is no ClapLibrary yet + if (!gClapLibrary._pluginFactory) + { + // if this binary does not already contain a CLAP entrypoint + if (!gClapLibrary.hasEntryPoint()) + { + // try to find a clap which filename stem matches our own + auto kx = os::getParentFolderName(); + auto plugname = os::getBinaryName(); + plugname.append(".clap"); + + if (!findPlugin(gClapLibrary, plugname)) + { + return nullptr; + } + } + else + { + LOGDETAIL("detected entrypoint in this binary"); + } + } + if (gClapLibrary.plugins.empty()) + { + // with no plugins there is nothing to do.. + LOGINFO("no plugin has been found"); + return nullptr; + } + + if (!clap_version_is_compatible(gClapLibrary.plugins[0]->clap_version)) + { + // CLAP version is not compatible -> eject + LOGINFO("CLAP version is not compatible"); + return nullptr; + } + + if (!gPluginFactory) + { + // we need at least one plugin to obtain vendor/name etc. + auto* factoryvendor = gClapLibrary.plugins[0]->vendor; + auto* vendor_url = gClapLibrary.plugins[0]->url; + // TODO: extract the domain and prefix with info@ + auto* contact = "info@"; + + // override for VST3 specifics + if (gClapLibrary._pluginFactoryVst3Info) + { + LOGDETAIL("detected extension `{}`", CLAP_PLUGIN_FACTORY_INFO_VST3); + auto& v3 = gClapLibrary._pluginFactoryVst3Info; + if (v3->vendor) factoryvendor = v3->vendor; + if (v3->vendor_url) vendor_url = v3->vendor_url; + if (v3->email_contact) contact = v3->email_contact; + } + + static PFactoryInfo factoryInfo(factoryvendor, vendor_url, contact, Vst::kDefaultFactoryFlags); + + LOGDETAIL("created factory for vendor '{}'", factoryvendor); + + gPluginFactory = new Steinberg::CPluginFactory(factoryInfo); + // resize the classInfo vector + gCreationContexts.clear(); + gCreationContexts.reserve(gClapLibrary.plugins.size()); + int numPlugins = static_cast(gClapLibrary.plugins.size()); + LOGDETAIL("number of plugins in factory: {}", numPlugins); + for (int ctr = 0; ctr < numPlugins; ++ctr) + { + auto& clapdescr = gClapLibrary.plugins[ctr]; + auto vst3info = gClapLibrary.get_vst3_info(ctr); + + LOGDETAIL(" plugin #{}: '{}'", ctr, clapdescr->name); + + std::string n(clapdescr->name); #ifdef _DEBUG - n.append(" (CLAP->VST3)"); + n.append(" (CLAP->VST3)"); #endif - auto plugname = n.c_str(); // clapdescr->name; + auto plugname = n.c_str(); // clapdescr->name; - // get vendor ------------------------------------- - auto pluginvendor = clapdescr->vendor; - if (pluginvendor == nullptr || *pluginvendor == 0) pluginvendor = "Unspecified Vendor"; - if (vst3info && vst3info->vendor) - { - LOGDETAIL(" plugin supports extension '{}'", CLAP_PLUGIN_AS_VST3); - pluginvendor = vst3info->vendor; - } + // get vendor ------------------------------------- + auto pluginvendor = clapdescr->vendor; + if (pluginvendor == nullptr || *pluginvendor == 0) pluginvendor = "Unspecified Vendor"; + if (vst3info && vst3info->vendor) + { + LOGDETAIL(" plugin supports extension '{}'", CLAP_PLUGIN_AS_VST3); + pluginvendor = vst3info->vendor; + } - TUID lcid; - Crypto::uuid_object g; + TUID lcid; + Crypto::uuid_object g; #ifdef CLAP_VST3_TUID_STRING - Steinberg::FUID f; - if (f.fromString(CLAP_VST3_TUID_STRING)) - { - memcpy(&g, f.toTUID(), sizeof(TUID)); - memcpy(&lcid, &g, sizeof(TUID)); - } - else + Steinberg::FUID f; + if (f.fromString(CLAP_VST3_TUID_STRING)) + { + memcpy(&g, f.toTUID(), sizeof(TUID)); + memcpy(&lcid, &g, sizeof(TUID)); + } + else #endif - { - // make id or take it from vst3 info -------------- - std::string id(clapdescr->id); - if (vst3info && vst3info->componentId) { - memcpy(&g, vst3info->componentId, sizeof(g)); - } else { - g = Crypto::create_sha1_guid_from_name(id.c_str(), id.size()); - } - - memcpy(&lcid, &g, sizeof(TUID)); - } - - // features ---------------------------------------- - std::string features; - if (vst3info && vst3info->features) - { - features = vst3info->features; - } - else - { - features = clapCategoriesToVST3(clapdescr->features); - } - - -#if CLAP_WRAPPER_LOGLEVEL> 1 - { - const uint8_t * v = reinterpret_cast(&g); - char x[sizeof(g)*2+8]; - char* o = x; - constexpr char hexchar[] = "0123456789ABCDEF"; - for (auto i = 0U ; i < sizeof(g) ; i++) - { - auto n = v[i]; - *o++ = hexchar[(n >> 4) & 0xF]; - *o++ = hexchar[n & 0xF]; - if (!(i % 4)) *o++ = 32; - } - *o++ = 0; - LOGDETAIL("plugin id: {} -> {}", clapdescr->id,x); - } + { + // make id or take it from vst3 info -------------- + std::string id(clapdescr->id); + if (vst3info && vst3info->componentId) + { + memcpy(&g, vst3info->componentId, sizeof(g)); + } + else + { + g = Crypto::create_sha1_guid_from_name(id.c_str(), id.size()); + } + + memcpy(&lcid, &g, sizeof(TUID)); + } + + // features ---------------------------------------- + std::string features; + if (vst3info && vst3info->features) + { + features = vst3info->features; + } + else + { + features = clapCategoriesToVST3(clapdescr->features); + } + +#if CLAP_WRAPPER_LOGLEVEL > 1 + { + const uint8_t* v = reinterpret_cast(&g); + char x[sizeof(g) * 2 + 8]; + char* o = x; + constexpr char hexchar[] = "0123456789ABCDEF"; + for (auto i = 0U; i < sizeof(g); i++) + { + auto n = v[i]; + *o++ = hexchar[(n >> 4) & 0xF]; + *o++ = hexchar[n & 0xF]; + if (!(i % 4)) *o++ = 32; + } + *o++ = 0; + LOGDETAIL("plugin id: {} -> {}", clapdescr->id, x); + } #endif - gCreationContexts.push_back({ &gClapLibrary, ctr, PClassInfo2( - lcid, - PClassInfo::kManyInstances, - kVstAudioEffectClass, - plugname, - 0 /* the only flag is usually Vst:kDistributable, but CLAPs aren't distributable */, - features.c_str(), - pluginvendor, - clapdescr->version, - kVstVersionString) - }); - gPluginFactory->registerClass(&gCreationContexts.back().classinfo, ClapAsVst3::createInstance, &gCreationContexts.back()); - } - - } - else - gPluginFactory->addRef(); - - return gPluginFactory; + gCreationContexts.push_back( + {&gClapLibrary, ctr, + PClassInfo2( + lcid, PClassInfo::kManyInstances, kVstAudioEffectClass, plugname, + 0 /* the only flag is usually Vst:kDistributable, but CLAPs aren't distributable */, + features.c_str(), pluginvendor, clapdescr->version, kVstVersionString)}); + gPluginFactory->registerClass(&gCreationContexts.back().classinfo, ClapAsVst3::createInstance, + &gCreationContexts.back()); + } + } + else + gPluginFactory->addRef(); + + return gPluginFactory; } /* @@ -306,15 +297,14 @@ IPluginFactory* GetPluginFactoryEntryPoint() { * actually, there is always a valid entrypoint, otherwise no factory would have been provided. */ FUnknown* ClapAsVst3::createInstance(void* context) -{ - auto ctx = static_cast(context); - - LOGINFO("creating plugin {} (#{})", ctx->classinfo.name, ctx->index); - if (ctx->lib->hasEntryPoint()) - { - // MessageBoxA(NULL, "halt", "create", MB_OK); - return (IAudioProcessor*)new ClapAsVst3(ctx->lib, ctx->index, context); - } - return nullptr; // this should never happen. - +{ + auto ctx = static_cast(context); + + LOGINFO("creating plugin {} (#{})", ctx->classinfo.name, ctx->index); + if (ctx->lib->hasEntryPoint()) + { + // MessageBoxA(NULL, "halt", "create", MB_OK); + return (IAudioProcessor*)new ClapAsVst3(ctx->lib, ctx->index, context); + } + return nullptr; // this should never happen. } diff --git a/src/wrapasvst3_export_entry.cpp b/src/wrapasvst3_export_entry.cpp index 4583331f..92daaf97 100644 --- a/src/wrapasvst3_export_entry.cpp +++ b/src/wrapasvst3_export_entry.cpp @@ -1,7 +1,8 @@ #include "public.sdk/source/main/pluginfactory.h" -SMTG_EXPORT_SYMBOL Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory() { - extern Steinberg::IPluginFactory *GetPluginFactoryEntryPoint(); - return GetPluginFactoryEntryPoint(); +SMTG_EXPORT_SYMBOL Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory() +{ + extern Steinberg::IPluginFactory* GetPluginFactoryEntryPoint(); + return GetPluginFactoryEntryPoint(); }