| @@ -13,10 +13,9 @@ jobs: | |||
| strategy: | |||
| matrix: | |||
| os: | |||
| # wrong use of AU MIDIPacket | |||
| # - macos-12 | |||
| # - macos-13 | |||
| # - macos-14 | |||
| - macos-13 | |||
| - macos-14 | |||
| - macos-15 | |||
| # webgui failure | |||
| # - ubuntu-20.04 | |||
| - ubuntu-22.04 | |||
| @@ -99,24 +98,59 @@ jobs: | |||
| run: | | |||
| make clean >/dev/null | |||
| make -j ${{ env.JOBS }} | |||
| - name: With OpenGL 3.x | |||
| - name: Without Cairo | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| make -j ${{ env.JOBS }} USE_OPENGL3=true | |||
| - name: Without Cairo | |||
| make -j ${{ env.JOBS }} HAVE_CAIRO=false | |||
| - name: Without OpenGL | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| make -j ${{ env.JOBS }} HAVE_CAIRO=false | |||
| - name: Without OpenGL | |||
| make -j ${{ env.JOBS }} HAVE_OPENGL=false | |||
| - name: With UI_TYPE=cairo | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| make -j ${{ env.JOBS }} HAVE_OPENGL=false | |||
| env UI_TYPE=cairo make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| - name: With UI_TYPE=generic | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| env UI_TYPE=generic make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| - name: With UI_TYPE=gles2 | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| env UI_TYPE=gles2 make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| - name: With UI_TYPE=gles3 | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| env UI_TYPE=gles3 make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| - name: With UI_TYPE=opengl | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| env UI_TYPE=opengl make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| - name: With UI_TYPE=opengl3 | |||
| env: | |||
| CFLAGS: -Werror | |||
| CXXFLAGS: -Werror | |||
| run: | | |||
| make clean >/dev/null | |||
| env UI_TYPE=opengl3 make -j ${{ env.JOBS }} -C examples/Parameters jack | |||
| @@ -8,9 +8,6 @@ on: | |||
| branches: | |||
| - '*' | |||
| env: | |||
| BUILD_TYPE: Release | |||
| jobs: | |||
| ubuntu-22-04: | |||
| strategy: | |||
| @@ -42,11 +39,11 @@ jobs: | |||
| suffix: _24_04 | |||
| target: ${{ matrix.target }} | |||
| macos-12: | |||
| macos-13: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-12 | |||
| runs-on: macos-13 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -54,14 +51,14 @@ jobs: | |||
| - uses: distrho/dpf-cmake-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _12 | |||
| suffix: _13 | |||
| target: ${{ matrix.target }} | |||
| macos-13: | |||
| macos-14: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-13 | |||
| runs-on: macos-14 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -69,14 +66,14 @@ jobs: | |||
| - uses: distrho/dpf-cmake-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _13 | |||
| suffix: _14 | |||
| target: ${{ matrix.target }} | |||
| macos-14: | |||
| macos-15: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-14 | |||
| runs-on: macos-15 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -84,81 +81,64 @@ jobs: | |||
| - uses: distrho/dpf-cmake-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _14 | |||
| suffix: _15 | |||
| target: ${{ matrix.target }} | |||
| cmake_win32: | |||
| runs-on: windows-2019 | |||
| msvc-win32: | |||
| runs-on: windows-2022 | |||
| steps: | |||
| - name: Set environment | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| submodules: recursive | |||
| - name: Configure | |||
| run: | | |||
| echo "release_arch=Win32" >> "${Env:GITHUB_ENV}" | |||
| echo "vcpkg_triplet=x86-windows-static" >> "${Env:GITHUB_ENV}" | |||
| echo "vcpkg_git_commit_id=a3db16a4475b963cacf0260068c497fb72c8f3c0" >> "${Env:GITHUB_ENV}" | |||
| - name: Restore from cache and install vcpkg | |||
| uses: lukka/run-vcpkg@v6 | |||
| cmake -S . -B build -G"Visual Studio 17 2022" -A"Win32" -DCMAKE_BUILD_TYPE="Release" | |||
| - name: Build | |||
| run: cmake --build build --config "Release" -j 2 | |||
| - name: Show built files | |||
| working-directory: build/bin | |||
| run: tree | |||
| - uses: actions/upload-artifact@v4 | |||
| with: | |||
| setupOnly: true | |||
| vcpkgTriplet: ${{env.vcpkg_triplet}} | |||
| vcpkgGitCommitId: ${{env.vcpkg_git_commit_id}} | |||
| #- name: Install packages | |||
| # run: | | |||
| # & "${Env:VCPKG_ROOT}/vcpkg" install "cairo:${Env:vcpkg_triplet}" | |||
| name: msvc-win32 | |||
| path: build/bin/ | |||
| msvc-win64: | |||
| runs-on: windows-2022 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| submodules: recursive | |||
| - name: Create Build Environment | |||
| working-directory: ${{runner.workspace}} | |||
| run: cmake -E make_directory build | |||
| - name: Configure CMake | |||
| working-directory: ${{runner.workspace}}/build | |||
| run: | | |||
| cmake "${Env:GITHUB_WORKSPACE}" -G"Visual Studio 16 2019" -A"${Env:release_arch}" -DCMAKE_BUILD_TYPE="${Env:BUILD_TYPE}" -DVCPKG_TARGET_TRIPLET="${Env:vcpkg_triplet}" -DCMAKE_TOOLCHAIN_FILE="${Env:VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" | |||
| cmake -S . -B build -G"Visual Studio 17 2022" -A"x64" -DCMAKE_BUILD_TYPE="Release" | |||
| - name: Build all | |||
| working-directory: ${{runner.workspace}}/build | |||
| run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2 | |||
| working-directory: build | |||
| run: cmake --build . --config "Release" -j 2 | |||
| - name: Show built files | |||
| working-directory: ${{runner.workspace}}/build/bin | |||
| working-directory: build/bin | |||
| run: tree | |||
| - uses: actions/upload-artifact@v4 | |||
| with: | |||
| name: Win32 artifacts | |||
| path: ${{runner.workspace}}/build/bin/ | |||
| name: msvc-win64 | |||
| path: build/bin/ | |||
| cmake_win64: | |||
| runs-on: windows-2019 | |||
| msvc-arm64: | |||
| runs-on: windows-11-arm | |||
| steps: | |||
| - name: Set environment | |||
| run: | | |||
| echo "release_arch=x64" >> "${Env:GITHUB_ENV}" | |||
| echo "vcpkg_triplet=x64-windows-static" >> "${Env:GITHUB_ENV}" | |||
| echo "vcpkg_git_commit_id=a3db16a4475b963cacf0260068c497fb72c8f3c0" >> "${Env:GITHUB_ENV}" | |||
| - name: Restore from cache and install vcpkg | |||
| uses: lukka/run-vcpkg@v6 | |||
| with: | |||
| setupOnly: true | |||
| vcpkgTriplet: ${{env.vcpkg_triplet}} | |||
| vcpkgGitCommitId: ${{env.vcpkg_git_commit_id}} | |||
| #- name: Install packages | |||
| # run: | | |||
| # & "${Env:VCPKG_ROOT}/vcpkg" install "cairo:${Env:vcpkg_triplet}" | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| submodules: recursive | |||
| - name: Create Build Environment | |||
| working-directory: ${{runner.workspace}} | |||
| run: cmake -E make_directory build | |||
| - name: Configure CMake | |||
| working-directory: ${{runner.workspace}}/build | |||
| run: | | |||
| cmake "${Env:GITHUB_WORKSPACE}" -G"Visual Studio 16 2019" -A"${Env:release_arch}" -DCMAKE_BUILD_TYPE="${Env:BUILD_TYPE}" -DVCPKG_TARGET_TRIPLET="${Env:vcpkg_triplet}" -DCMAKE_TOOLCHAIN_FILE="${Env:VCPKG_INSTALLATION_ROOT}/scripts/buildsystems/vcpkg.cmake" | |||
| cmake -S . -B build -G"Visual Studio 17 2022" -A"ARM64" -DCMAKE_BUILD_TYPE="Release" | |||
| - name: Build all | |||
| working-directory: ${{runner.workspace}}/build | |||
| run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2 | |||
| working-directory: build | |||
| run: cmake --build . --config "Release" -j 2 | |||
| - name: Show built files | |||
| working-directory: ${{runner.workspace}}/build/bin | |||
| working-directory: build/bin | |||
| run: tree | |||
| - uses: actions/upload-artifact@v4 | |||
| with: | |||
| name: Win64 artifacts | |||
| path: ${{runner.workspace}}/build/bin/ | |||
| name: msvc-arm64 | |||
| path: build/bin/ | |||
| @@ -39,11 +39,11 @@ jobs: | |||
| suffix: _24_04 | |||
| target: ${{ matrix.target }} | |||
| macos-12: | |||
| macos-13: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-12 | |||
| runs-on: macos-13 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -51,14 +51,14 @@ jobs: | |||
| - uses: distrho/dpf-makefile-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _12 | |||
| suffix: _13 | |||
| target: ${{ matrix.target }} | |||
| macos-13: | |||
| macos-14: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-13 | |||
| runs-on: macos-14 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -66,14 +66,14 @@ jobs: | |||
| - uses: distrho/dpf-makefile-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _13 | |||
| suffix: _14 | |||
| target: ${{ matrix.target }} | |||
| macos-14: | |||
| macos-15: | |||
| strategy: | |||
| matrix: | |||
| target: [macos-intel, macos-universal, macos-10.15] | |||
| runs-on: macos-14 | |||
| runs-on: macos-15 | |||
| steps: | |||
| - uses: actions/checkout@v4 | |||
| with: | |||
| @@ -81,5 +81,5 @@ jobs: | |||
| - uses: distrho/dpf-makefile-action@v1 | |||
| with: | |||
| dpf_path: . | |||
| suffix: _14 | |||
| suffix: _15 | |||
| target: ${{ matrix.target }} | |||
| @@ -15,8 +15,9 @@ CMakeFiles | |||
| CMakeSettings.json | |||
| cmake_install.cmake | |||
| bin/ | |||
| build/ | |||
| docs/ | |||
| utils/lv2_ttl_generator | |||
| utils/lv2_ttl_generator.dSYM/ | |||
| /bin/ | |||
| /build/ | |||
| /docs/ | |||
| /khronos/ | |||
| /utils/lv2_ttl_generator | |||
| /utils/lv2_ttl_generator.dSYM/ | |||
| @@ -1,10 +1,10 @@ | |||
| # DISTRHO Plugin Framework (DPF) | |||
| # Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||
| # Copyright (C) 2022-2024 Filipe Coelho <falktx@falktx.com> | |||
| # Copyright (C) 2022-2025 Filipe Coelho <falktx@falktx.com> | |||
| # | |||
| # SPDX-License-Identifier: ISC | |||
| cmake_minimum_required(VERSION 3.7) | |||
| cmake_minimum_required(VERSION 3.8...3.31) | |||
| project(DPF) | |||
| @@ -30,19 +30,19 @@ list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") | |||
| include(DPF-plugin) | |||
| if(DPF_LIBRARIES) | |||
| find_package(PkgConfig) | |||
| find_package(PkgConfig QUIET) | |||
| if(PKG_CONFIG_FOUND) | |||
| pkg_check_modules(CAIRO "cairo") | |||
| if(CAIRO_FOUND AND (NOT HAIKU)) | |||
| dpf__add_dgl_cairo(TRUE, TRUE) | |||
| dpf__add_dgl_cairo(TRUE, TRUE, TRUE) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_external(TRUE) | |||
| dpf__add_dgl_opengl(TRUE, TRUE) | |||
| dpf__add_dgl_external(TRUE, TRUE) | |||
| dpf__add_dgl_opengl(TRUE, TRUE, TRUE) | |||
| endif() | |||
| if(DPF_EXAMPLES) | |||
| find_package(PkgConfig) | |||
| find_package(PkgConfig QUIET) | |||
| if(PKG_CONFIG_FOUND) | |||
| pkg_check_modules(CAIRO "cairo") | |||
| if(CAIRO_FOUND AND (NOT HAIKU)) | |||
| @@ -1,4 +1,4 @@ | |||
| Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -12,6 +12,7 @@ all: dgl examples gen | |||
| # needed for some example plugins | |||
| export USE_FILE_BROWSER = true | |||
| export USE_WEB_VIEW = true | |||
| ifneq ($(CROSS_COMPILING),true) | |||
| CAN_GENERATE_TTL = true | |||
| @@ -20,16 +20,14 @@ | |||
| # Tweak `nvgTextBreakLines` to allow space characters | |||
| # FIXME proper details | |||
| # NVG_FONT_TEXTURE_FLAGS=0 | |||
| # FILE_BROWSER_DISABLED=true | |||
| # WINDOWS_ICON_ID=0 | |||
| # USE_GLES2=true | |||
| # USE_GLES3=true | |||
| # USE_OPENGL3=true | |||
| # USE_NANOVG_FBO=true | |||
| # USE_NANOVG_FREETYPE=true | |||
| # NVG_FONT_TEXTURE_FLAGS= | |||
| # WINDOWS_ICON_ID= | |||
| # USE_NANOVG_FBO=false | |||
| # USE_NANOVG_FREETYPE=false | |||
| # USE_FILE_BROWSER=true | |||
| # USE_WEB_VIEW=true | |||
| # USE_GLES2=false | |||
| # USE_GLES3=false | |||
| # USE_WEB_VIEW=false | |||
| # STATIC_BUILD=true | |||
| # Tweak build to be able to generate fully static builds (e.g. skip use of libdl) | |||
| @@ -333,6 +331,10 @@ BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden | |||
| CXXFLAGS += -fvisibility-inlines-hidden | |||
| endif | |||
| ifeq ($(WASM),true) | |||
| LINK_OPTS += -sALLOW_MEMORY_GROWTH | |||
| endif | |||
| ifeq ($(WITH_LTO),true) | |||
| BASE_FLAGS += -fno-strict-aliasing -flto | |||
| LINK_OPTS += -fno-strict-aliasing -flto -Werror=odr | |||
| @@ -469,7 +471,7 @@ endif | |||
| else ifeq ($(WASM),true) | |||
| # wasm builds cannot work using regular desktop OpenGL | |||
| ifeq (,$(USE_GLES2)$(USE_GLES3)) | |||
| ifeq (,$(findstring true,$(USE_GLES2)$(USE_GLES3))) | |||
| USE_GLES2 = true | |||
| endif | |||
| @@ -486,12 +488,10 @@ endif | |||
| else | |||
| ifneq ($(FILE_BROWSER_DISABLED),true) | |||
| ifeq ($(HAVE_DBUS),true) | |||
| ifeq ($(USE_FILE_BROWSER)$(HAVE_DBUS),truetrue) | |||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS | |||
| DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) | |||
| endif | |||
| endif | |||
| ifeq ($(HAVE_X11),true) | |||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | |||
| @@ -544,14 +544,16 @@ else ifeq ($(MACOS),true) | |||
| OPENGL_FLAGS = -DGL_SILENCE_DEPRECATION=1 -Wno-deprecated-declarations | |||
| OPENGL_LIBS = -framework OpenGL | |||
| else ifeq ($(WASM),true) | |||
| ifeq ($(USE_GLES2),true) | |||
| OPENGL_FLAGS = | |||
| ifeq ($(USE_GLES3),true) | |||
| OPENGL_LIBS = -sMIN_WEBGL_VERSION=3 -sMAX_WEBGL_VERSION=3 | |||
| else ifeq ($(USE_GLES2),true) | |||
| OPENGL_LIBS = -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2 | |||
| else | |||
| ifneq ($(USE_GLES3),true) | |||
| OPENGL_LIBS = -sLEGACY_GL_EMULATION -sGL_UNSAFE_OPTS=0 | |||
| endif | |||
| OPENGL_LIBS = -sLEGACY_GL_EMULATION -sGL_UNSAFE_OPTS=0 | |||
| endif | |||
| else ifeq ($(WINDOWS),true) | |||
| OPENGL_FLAGS = | |||
| OPENGL_LIBS = -lopengl32 | |||
| else | |||
| OPENGL_FLAGS = $(shell $(PKG_CONFIG) --cflags gl x11) | |||
| @@ -581,7 +583,7 @@ DGL_FLAGS += -DHAVE_VULKAN | |||
| VULKAN_FLAGS = $(shell $(PKG_CONFIG) --cflags vulkan) | |||
| VULKAN_LIBS = $(shell $(PKG_CONFIG) --libs vulkan) | |||
| ifneq ($(WINDOWS),true) | |||
| ifneq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true) | |||
| VULKAN_LIBS += -ldl | |||
| endif | |||
| @@ -666,13 +668,9 @@ endif | |||
| ifeq ($(USE_GLES2),true) | |||
| BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES2 | |||
| endif | |||
| ifeq ($(USE_GLES3),true) | |||
| else ifeq ($(USE_GLES3),true) | |||
| BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES3 | |||
| endif | |||
| ifeq ($(USE_OPENGL3),true) | |||
| else ifeq ($(USE_OPENGL3),true) | |||
| BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | |||
| endif | |||
| @@ -700,7 +698,7 @@ endif | |||
| # Set app extension | |||
| ifeq ($(WASM),true) | |||
| APP_EXT = .html | |||
| APP_EXT = .js | |||
| else ifeq ($(WINDOWS),true) | |||
| APP_EXT = .exe | |||
| endif | |||
| @@ -838,7 +836,7 @@ features: | |||
| # Extra rules for MOD Audio stuff | |||
| # NOTE: path must be absolute | |||
| MOD_WORKDIR ?= $(HOME)/mod-workdir | |||
| WORKDIR ?= $(HOME)/mod-workdir | |||
| MOD_ENVIRONMENT = \ | |||
| AR=${1}/host/usr/bin/${2}-gcc-ar \ | |||
| CC=${1}/host/usr/bin/${2}-gcc \ | |||
| @@ -858,49 +856,57 @@ MOD_ENVIRONMENT = \ | |||
| MOD_BUILD=true \ | |||
| NOOPT=true | |||
| darkglass-anagram: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/darkglass-anagram,aarch64-modaudio.generic-linux-gnu,aarch64) | |||
| modduo: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) | |||
| modduo-new: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) | |||
| modduox: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) | |||
| modduox-new: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) | |||
| moddwarf: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) | |||
| moddwarf-new: | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) | |||
| modpush: | |||
| tar -C bin -chz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo | |||
| ifneq (,$(findstring darkglass-anagram-,$(MAKECMDGOALS))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/darkglass-anagram,aarch64-modaudio.generic-linux-gnu,aarch64) $(subst darkglass-anagram-,,$(MAKECMDGOALS)) | |||
| endif | |||
| ifneq (,$(findstring modduo-new-,$(MAKECMDGOALS))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) $(subst modduo-new-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm) $(subst modduo-new-,,$(MAKECMDGOALS)) | |||
| else ifneq (,$(findstring modduo-,$(filter-out modduo-new,$(MAKECMDGOALS)))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) $(subst modduo-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm) $(subst modduo-,,$(MAKECMDGOALS)) | |||
| endif | |||
| ifneq (,$(findstring modduox-new-,$(MAKECMDGOALS))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) $(subst modduox-new-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64) $(subst modduox-new-,,$(MAKECMDGOALS)) | |||
| else ifneq (,$(findstring modduox-,$(filter-out modduox-new,$(MAKECMDGOALS)))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64) $(subst modduox-,,$(MAKECMDGOALS)) | |||
| endif | |||
| ifneq (,$(findstring moddwarf-new-,$(MAKECMDGOALS))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) $(subst moddwarf-new-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64) $(subst moddwarf-new-,,$(MAKECMDGOALS)) | |||
| else ifneq (,$(findstring moddwarf-,$(filter-out moddwarf-new,$(MAKECMDGOALS)))) | |||
| $(MAKECMDGOALS): | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) | |||
| $(MAKE) $(call MOD_ENVIRONMENT,$(WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64) $(subst moddwarf-,,$(MAKECMDGOALS)) | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -9,8 +9,8 @@ | |||
| # extra useful variables to define before including this file: | |||
| # - DPF_BUILD_DIR: where to place temporary build files | |||
| # - DPF_TARGET_DIR: where to place final binary files | |||
| # - UI_TYPE: one of cairo, opengl, opengl3 or external, with opengl being default | |||
| # ("generic" is also allowed if only using image widgets) | |||
| # - UI_TYPE: one of cairo, external, gles2, gles3, opengl, opengl3 or webview, with opengl being default | |||
| # ("generic" is also allowed if only using basic DPF classes like image widgets) | |||
| # override the "all" target after including this file to define which plugin formats to build, like so: | |||
| # all: au clap jack lv2_sep vst2 vst3 | |||
| @@ -55,6 +55,10 @@ ifeq ($(UI_TYPE),) | |||
| else ifeq ($(UI_TYPE),cairo) | |||
| else ifeq ($(UI_TYPE),external) | |||
| else ifeq ($(UI_TYPE),generic) | |||
| else ifeq ($(UI_TYPE),gles2) | |||
| USE_GLES2 = true | |||
| else ifeq ($(UI_TYPE),gles3) | |||
| USE_GLES3 = true | |||
| else ifeq ($(UI_TYPE),opengl) | |||
| else ifeq ($(UI_TYPE),opengl3) | |||
| USE_OPENGL3 = true | |||
| @@ -140,7 +144,7 @@ JACK_FLAGS += -sUSE_SDL=2 | |||
| JACK_LIBS += -sUSE_SDL=2 | |||
| JACK_LIBS += -sMAIN_MODULE -ldl | |||
| ifneq ($(FILE_BROWSER_DISABLED),true) | |||
| ifeq ($(USE_FILE_BROWSER),true) | |||
| JACK_LIBS += -sEXPORTED_RUNTIME_METHODS=FS,cwrap | |||
| endif | |||
| @@ -201,8 +205,12 @@ UI_TYPE = none | |||
| endif | |||
| ifeq ($(UI_TYPE),) | |||
| ifeq ($(WASM),true) | |||
| UI_TYPE = gles2 | |||
| else | |||
| UI_TYPE = opengl | |||
| endif | |||
| endif | |||
| ifeq ($(UI_TYPE),generic) | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| @@ -227,6 +235,30 @@ HAVE_DGL = false | |||
| endif | |||
| endif | |||
| ifeq ($(UI_TYPE),gles2) | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| DGL_FLAGS += -DDGL_OPENGL -DHAVE_DGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES2 | |||
| DGL_FLAGS += $(OPENGL_FLAGS) | |||
| DGL_LIBS += $(OPENGL_LIBS) | |||
| DGL_LIB = $(DGL_BUILD_DIR)/libdgl-gles2.a | |||
| HAVE_DGL = true | |||
| else | |||
| HAVE_DGL = false | |||
| endif | |||
| endif | |||
| ifeq ($(UI_TYPE),gles3) | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| DGL_FLAGS += -DDGL_OPENGL -DHAVE_DGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES3 | |||
| DGL_FLAGS += $(OPENGL_FLAGS) | |||
| DGL_LIBS += $(OPENGL_LIBS) | |||
| DGL_LIB = $(DGL_BUILD_DIR)/libdgl-gles3.a | |||
| HAVE_DGL = true | |||
| else | |||
| HAVE_DGL = false | |||
| endif | |||
| endif | |||
| ifeq ($(UI_TYPE),opengl) | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| DGL_FLAGS += -DDGL_OPENGL -DHAVE_DGL | |||
| @@ -241,7 +273,7 @@ endif | |||
| ifeq ($(UI_TYPE),opengl3) | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| DGL_FLAGS += -DDGL_OPENGL -DDGL_USE_OPENGL3 -DHAVE_DGL | |||
| DGL_FLAGS += -DDGL_OPENGL -DHAVE_DGL -DDGL_USE_OPENGL3 | |||
| DGL_FLAGS += $(OPENGL_FLAGS) | |||
| DGL_LIBS += $(OPENGL_LIBS) | |||
| DGL_LIB = $(DGL_BUILD_DIR)/libdgl-opengl3.a | |||
| @@ -340,6 +372,18 @@ ifeq ($(WINDOWS)$(HAVE_DGL),truetrue) | |||
| JACK_LIBS += -Wl,-subsystem,windows | |||
| endif | |||
| ifeq ($(WASM),true) | |||
| MAPI_EXT = -mapi.js | |||
| MAPI_SHARED = \ | |||
| -sEXPORT_NAME="$(MAPI_MODULE_NAME)" \ | |||
| -sEXPORTED_RUNTIME_METHODS=['addFunction','lengthBytesUTF8','stringToUTF8','UTF8ToString'] \ | |||
| -sMAIN_MODULE=2 \ | |||
| -sMODULARIZE=1 | |||
| else | |||
| MAPI_EXT = $(LIB_EXT) | |||
| MAPI_SHARED = $(SHARED) | |||
| endif | |||
| ifeq ($(MACOS_APP_BUNDLE),true) | |||
| jack = $(TARGET_DIR)/$(NAME).app/Contents/MacOS/$(NAME) | |||
| jackfiles = $(TARGET_DIR)/$(NAME).app/Contents/Info.plist | |||
| @@ -347,19 +391,19 @@ else | |||
| jack = $(TARGET_DIR)/$(NAME)$(APP_EXT) | |||
| endif | |||
| ladspa_dsp = $(TARGET_DIR)/$(NAME)-ladspa$(LIB_EXT) | |||
| clap = $(TARGET_DIR)/$(CLAP_FILENAME) | |||
| dssi_dsp = $(TARGET_DIR)/$(NAME)-dssi$(LIB_EXT) | |||
| dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui$(APP_EXT) | |||
| ladspa_dsp = $(TARGET_DIR)/$(NAME)-ladspa$(LIB_EXT) | |||
| lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT) | |||
| lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT) | |||
| lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) | |||
| mapi = $(TARGET_DIR)/$(NAME)$(MAPI_EXT) | |||
| static = $(TARGET_DIR)/$(NAME).a | |||
| vst2 = $(TARGET_DIR)/$(VST2_FILENAME) | |||
| ifneq ($(VST3_FILENAME),) | |||
| vst3 = $(TARGET_DIR)/$(VST3_FILENAME) | |||
| endif | |||
| clap = $(TARGET_DIR)/$(CLAP_FILENAME) | |||
| shared = $(TARGET_DIR)/$(NAME)$(LIB_EXT) | |||
| static = $(TARGET_DIR)/$(NAME).a | |||
| ifeq ($(MACOS),true) | |||
| BUNDLE_RESOURCES = Info.plist PkgInfo Resources/empty.lproj | |||
| @@ -370,6 +414,10 @@ vst3files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/%) | |||
| clapfiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/%) | |||
| endif | |||
| ifeq ($(WASM),true) | |||
| jackfiles += $(TARGET_DIR)/$(NAME).html | |||
| endif | |||
| ifneq ($(HAVE_DGL),true) | |||
| dssi_ui = | |||
| lv2_ui = | |||
| @@ -386,45 +434,45 @@ endif | |||
| ifeq ($(MACOS),true) | |||
| SYMBOLS_AU = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/au.exp | |||
| SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | |||
| SYMBOLS_CLAP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/clap.exp | |||
| SYMBOLS_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp | |||
| SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | |||
| SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp | |||
| SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp | |||
| SYMBOLS_LV2UI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-ui.exp | |||
| SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp | |||
| SYMBOLS_MAPI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/mapi.exp | |||
| SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp | |||
| SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp | |||
| SYMBOLS_CLAP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/clap.exp | |||
| SYMBOLS_SHARED = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/shared.exp | |||
| else ifeq ($(WASM),true) | |||
| SYMBOLS_LADSPA = -sEXPORTED_FUNCTIONS="['ladspa_descriptor']" | |||
| SYMBOLS_CLAP = -sEXPORTED_FUNCTIONS="['clap_entry']" | |||
| SYMBOLS_DSSI = -sEXPORTED_FUNCTIONS="['ladspa_descriptor','dssi_descriptor']" | |||
| SYMBOLS_LADSPA = -sEXPORTED_FUNCTIONS="['ladspa_descriptor']" | |||
| SYMBOLS_LV2 = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl','lv2ui_descriptor']" | |||
| SYMBOLS_LV2DSP = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl']" | |||
| SYMBOLS_LV2UI = -sEXPORTED_FUNCTIONS="['lv2ui_descriptor']" | |||
| SYMBOLS_LV2 = -sEXPORTED_FUNCTIONS="['lv2_descriptor','lv2_generate_ttl','lv2ui_descriptor']" | |||
| SYMBOLS_MAPI = -sEXPORTED_FUNCTIONS="['_mapi_create','_mapi_process','_mapi_set_parameter','_mapi_set_state','_mapi_destroy']" | |||
| SYMBOLS_VST2 = -sEXPORTED_FUNCTIONS="['VSTPluginMain']" | |||
| SYMBOLS_VST3 = -sEXPORTED_FUNCTIONS="['GetPluginFactory','ModuleEntry','ModuleExit']" | |||
| SYMBOLS_CLAP = -sEXPORTED_FUNCTIONS="['clap_entry']" | |||
| SYMBOLS_SHARED = -sEXPORTED_FUNCTIONS="['createSharedPlugin']" | |||
| else ifeq ($(WINDOWS),true) | |||
| SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | |||
| SYMBOLS_CLAP = $(DPF_PATH)/utils/symbols/clap.def | |||
| SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | |||
| SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | |||
| SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | |||
| SYMBOLS_LV2DSP = $(DPF_PATH)/utils/symbols/lv2-dsp.def | |||
| SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def | |||
| SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | |||
| SYMBOLS_MAPI = $(DPF_PATH)/utils/symbols/mapi.def | |||
| SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | |||
| SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | |||
| SYMBOLS_CLAP = $(DPF_PATH)/utils/symbols/clap.def | |||
| SYMBOLS_SHARED = $(DPF_PATH)/utils/symbols/shared.def | |||
| else ifneq ($(DEBUG),true) | |||
| SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | |||
| SYMBOLS_CLAP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/clap.version | |||
| SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | |||
| SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | |||
| SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | |||
| SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version | |||
| SYMBOLS_LV2UI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-ui.version | |||
| SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | |||
| SYMBOLS_MAPI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/mapi.version | |||
| SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version | |||
| SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version | |||
| SYMBOLS_CLAP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/clap.version | |||
| SYMBOLS_SHARED = -Wl,--version-script=$(DPF_PATH)/utils/symbols/shared.version | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -500,6 +548,12 @@ DGL_POSSIBLE_DEPS = \ | |||
| $(DGL_BUILD_DIR)/libdgl-cairo.a: $(DGL_POSSIBLE_DEPS) | |||
| $(MAKE) -C $(DPF_PATH)/dgl cairo | |||
| $(DGL_BUILD_DIR)/libdgl-gles2.a: $(DGL_POSSIBLE_DEPS) | |||
| $(MAKE) -C $(DPF_PATH)/dgl gles2 USE_GLES2=true | |||
| $(DGL_BUILD_DIR)/libdgl-gles3.a: $(DGL_POSSIBLE_DEPS) | |||
| $(MAKE) -C $(DPF_PATH)/dgl gles3 USE_GLES3=true | |||
| $(DGL_BUILD_DIR)/libdgl-opengl.a: $(DGL_POSSIBLE_DEPS) | |||
| $(MAKE) -C $(DPF_PATH)/dgl opengl | |||
| @@ -514,11 +568,21 @@ $(DGL_BUILD_DIR)/libdgl-vulkan.a: $(DGL_POSSIBLE_DEPS) | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| $(BUILD_DIR)/DistrhoPluginMain_%_single_obj.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Compiling DistrhoPluginMain.cpp ($*)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -DDISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT=1 -c -o $@ | |||
| $(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Compiling DistrhoPluginMain.cpp ($*)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | |||
| $(BUILD_DIR)/DistrhoUIMain_%_single_obj.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Compiling DistrhoUIMain.cpp ($*)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -DDISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT=1 -c -o $@ | |||
| $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Compiling DistrhoUIMain.cpp ($*)" | |||
| @@ -534,10 +598,10 @@ $(BUILD_DIR)/DistrhoUI_win32.cpp.o: $(DPF_PATH)/distrho/DistrhoUI_win32.cpp $(EX | |||
| @echo "Compiling DistrhoUI_win32.cpp ($*)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@ | |||
| $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: BUILD_CXX_FLAGS += $(JACK_FLAGS) | |||
| $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||
| $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: BUILD_CXX_FLAGS += $(JACK_FLAGS) | |||
| $(BUILD_DIR)/DistrhoUIMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++ | |||
| $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: BUILD_CXX_FLAGS += $(LIBLO_FLAGS) | |||
| @@ -591,7 +655,7 @@ lv2_dsp: $(lv2_dsp) | |||
| lv2_sep: $(lv2_dsp) $(lv2_ui) | |||
| ifeq ($(HAVE_DGL),true) | |||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2_single_obj.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2_single_obj.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||
| else | |||
| $(lv2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | |||
| endif | |||
| @@ -767,6 +831,16 @@ endif | |||
| @echo "Creating AU component for $(NAME)" | |||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) -framework AudioToolbox -framework AudioUnit -framework CoreFoundation $(SHARED) $(SYMBOLS_AU) -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # MAPI | |||
| mapi: $(mapi) | |||
| $(mapi): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_MAPI.cpp.o | |||
| -@mkdir -p $(shell dirname $@) | |||
| @echo "Creating MAPI for $(NAME)" | |||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(MAPI_SHARED) $(SYMBOLS_MAPI) -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Export | |||
| @@ -779,20 +853,6 @@ endif | |||
| @echo "Creating export tool for $(NAME)" | |||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Shared | |||
| shared: $(shared) | |||
| ifeq ($(HAVE_DGL),true) | |||
| $(shared): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED) | |||
| else | |||
| $(shared): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o | |||
| endif | |||
| -@mkdir -p $(shell dirname $@) | |||
| @echo "Creating shared library for $(NAME)" | |||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_SHARED) -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # Static | |||
| @@ -811,6 +871,8 @@ endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # macOS files | |||
| ifeq ($(MACOS),true) | |||
| $(TARGET_DIR)/%.app/Contents/Info.plist: $(DPF_PATH)/utils/plugin.app/Contents/Info.plist | |||
| -@mkdir -p $(shell dirname $@) | |||
| $(SILENT)sed -e "s/@INFO_PLIST_PROJECT_NAME@/$(NAME)/" $< > $@ | |||
| @@ -827,8 +889,21 @@ $(TARGET_DIR)/%/Resources/empty.lproj: $(DPF_PATH)/utils/plugin.bundle/Contents/ | |||
| -@mkdir -p $(shell dirname $@) | |||
| $(SILENT)cp $< $@ | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # wasm files | |||
| ifeq ($(WASM),true) | |||
| $(TARGET_DIR)/$(NAME).html: $(DPF_PATH)/utils/emscripten.html.in | |||
| -@mkdir -p $(shell dirname $@) | |||
| $(SILENT)sed -e 's|@NAME@|$(NAME)|g' $< > $@ | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| # format-specific files | |||
| # auto-generated format-specific files | |||
| $(TARGET_DIR)/$(NAME).component/Contents/Info.plist: $(BUILD_DIR)/export$(APP_EXT) | |||
| -@mkdir -p $(shell dirname $@) | |||
| @@ -841,26 +916,27 @@ ifneq ($(UI_TYPE),) | |||
| -include $(OBJS_UI:%.o=%.d) | |||
| endif | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_Export.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_LADSPA.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_LV2_single_obj.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_MAPI.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_Export.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoPluginMain_STATIC.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_AU.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_LV2_single_obj.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_AU.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d | |||
| -include $(BUILD_DIR)/DistrhoUIMain_STATIC.cpp.d | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| @@ -31,7 +31,7 @@ Bug reports happen on the [DPF github project](https://github.com/DISTRHO/DPF/is | |||
| Online documentation is available at [https://distrho.github.io/DPF/](https://distrho.github.io/DPF/). | |||
| Online help and discussion about DPF happens in the [kx.studio chat, DPF room](https://chat.kx.studio/channel/dpf). | |||
| Online help and discussion about DPF happens in the [DPF github discussions](https://github.com/DISTRHO/DPF/discussions). | |||
| ## List of plugins made with DPF: | |||
| @@ -78,6 +78,8 @@ include(CMakeParseArguments) | |||
| # the user interface type, can be one of the following: | |||
| # - cairo | |||
| # - external | |||
| # - gles2 | |||
| # - gles3 | |||
| # - opengl (default) | |||
| # - opengl3 | |||
| # - vulkan | |||
| @@ -102,6 +104,12 @@ include(CMakeParseArguments) | |||
| # `NO_SHARED_RESOURCES` | |||
| # do not build DPF shared resources (fonts, etc) | |||
| # | |||
| # `FORCE_NATIVE_AUDIO_FALLBACK` | |||
| # force the JACK/Standalone format to use native audio fallback instead of JACK | |||
| # | |||
| # `SKIP_NATIVE_AUDIO_FALLBACK` | |||
| # force the JACK/Standalone format to always use JACK, skipping native audio fallback | |||
| # | |||
| # `USE_FILE_BROWSER` | |||
| # enable file browser dialog APIs | |||
| # | |||
| @@ -109,7 +117,7 @@ include(CMakeParseArguments) | |||
| # enable web browser view APIs | |||
| # | |||
| function(dpf_add_plugin NAME) | |||
| set(options MONOLITHIC NO_SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| set(options MONOLITHIC NO_SHARED_RESOURCES FORCE_NATIVE_AUDIO_FALLBACK SKIP_NATIVE_AUDIO_FALLBACK USE_FILE_BROWSER USE_WEB_VIEW) | |||
| set(oneValueArgs MODGUI_CLASS_NAME UI_TYPE) | |||
| set(multiValueArgs FILES_COMMON FILES_DSP FILES_UI TARGETS) | |||
| cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | |||
| @@ -121,23 +129,43 @@ function(dpf_add_plugin NAME) | |||
| set(_dgl_library) | |||
| if(_dpf_plugin_FILES_UI) | |||
| if(_dpf_plugin_UI_TYPE STREQUAL "cairo") | |||
| dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-cairo) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "external") | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-external) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "gles2") | |||
| dpf__add_dgl_gles2($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-gles2) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "gles3") | |||
| dpf__add_dgl_gles3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-gles3) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl") | |||
| dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-opengl) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3") | |||
| dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-opengl3) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "vulkan") | |||
| dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-vulkan) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "webview") | |||
| set(_dpf_plugin_USE_WEB_VIEW TRUE) | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>) | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-external) | |||
| else() | |||
| message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}") | |||
| @@ -173,6 +201,9 @@ function(dpf_add_plugin NAME) | |||
| target_compile_definitions("${NAME}" PUBLIC "DISTRHO_PLUGIN_MODGUI_CLASS_NAME=\"${_dpf_plugin_MODGUI_CLASS_NAME}\"") | |||
| endif() | |||
| find_package(Threads) | |||
| target_link_libraries("${NAME}" PUBLIC "${CMAKE_THREAD_LIBS_INIT}") | |||
| if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||
| target_link_libraries("${NAME}" PRIVATE "dl") | |||
| endif() | |||
| @@ -209,7 +240,11 @@ function(dpf_add_plugin NAME) | |||
| ### | |||
| foreach(_target ${_dpf_plugin_TARGETS}) | |||
| if(_target STREQUAL "jack") | |||
| dpf__build_jack("${NAME}" "${_dgl_has_ui}") | |||
| dpf__build_jack("${NAME}" | |||
| "${_dgl_has_ui}" | |||
| "${_dpf_plugin_FORCE_NATIVE_AUDIO_FALLBACK}" | |||
| "${_dpf_plugin_SKIP_NATIVE_AUDIO_FALLBACK}" | |||
| "${_dpf_plugin_USE_FILE_BROWSER}") | |||
| elseif(_target STREQUAL "ladspa") | |||
| dpf__build_ladspa("${NAME}") | |||
| elseif(_target STREQUAL "dssi") | |||
| @@ -234,6 +269,138 @@ function(dpf_add_plugin NAME) | |||
| endforeach() | |||
| endfunction() | |||
| # dpf_add_executable(target <args...>) | |||
| # ------------------------------------------------------------------------------ | |||
| # | |||
| # Add a simple executable built using the DISTRHO Plugin Framework. | |||
| # | |||
| # ------------------------------------------------------------------------------ | |||
| # Arguments: | |||
| # | |||
| # `UI_TYPE` <type> | |||
| # the user interface type, can be one of the following: | |||
| # - cairo | |||
| # - external | |||
| # - gles2 | |||
| # - gles3 | |||
| # - opengl (default) | |||
| # - opengl3 | |||
| # - vulkan | |||
| # - webview | |||
| # | |||
| # `NO_SHARED_RESOURCES` | |||
| # do not build DPF shared resources (fonts, etc) | |||
| # | |||
| # `USE_FILE_BROWSER` | |||
| # enable file browser dialog APIs | |||
| # | |||
| # `USE_WEB_VIEW` | |||
| # enable web browser view APIs | |||
| # | |||
| function(dpf_add_executable NAME) | |||
| set(options NO_SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| set(oneValueArgs UI_TYPE) | |||
| cmake_parse_arguments(_dpf_plugin "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) | |||
| if("${_dpf_plugin_UI_TYPE}" STREQUAL "") | |||
| set(_dpf_plugin_UI_TYPE "opengl") | |||
| endif() | |||
| set(_dgl_library) | |||
| if(_dpf_plugin_UI_TYPE STREQUAL "cairo") | |||
| dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-cairo) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "external") | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-external) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "gles2") | |||
| dpf__add_dgl_gles2($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-gles2) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "gles3") | |||
| dpf__add_dgl_gles3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-gles3) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl") | |||
| dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-opengl) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3") | |||
| dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-opengl3) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "vulkan") | |||
| dpf__add_dgl_vulkan($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> | |||
| $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-vulkan) | |||
| elseif(_dpf_plugin_UI_TYPE STREQUAL "webview") | |||
| set(_dpf_plugin_USE_WEB_VIEW TRUE) | |||
| dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}> | |||
| $<BOOL:${_dpf_plugin_USE_WEB_VIEW}>) | |||
| set(_dgl_library dgl-external) | |||
| else() | |||
| message(FATAL_ERROR "Unrecognized UI type for executable: ${_dpf_plugin_UI_TYPE}") | |||
| endif() | |||
| set(_dgl_has_ui OFF) | |||
| if(_dgl_library) | |||
| set(_dgl_has_ui ON) | |||
| endif() | |||
| dpf__create_dummy_source_list(_no_srcs) | |||
| dpf__add_executable("${NAME}" ${_no_srcs}) | |||
| target_include_directories("${NAME}" PUBLIC "${DPF_ROOT_DIR}/distrho") | |||
| set_target_properties("${NAME}" PROPERTIES | |||
| RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | |||
| OUTPUT_NAME "${NAME}") | |||
| if(EMSCRIPTEN) | |||
| configure_file("${DPF_ROOT_DIR}/utils/emscripten.html.in" | |||
| "${PROJECT_BINARY_DIR}/bin/${NAME}.html" @ONLY) | |||
| target_link_options("${NAME}" | |||
| PRIVATE | |||
| -sEXPORTED_RUNTIME_METHODS=dynCall) | |||
| endif() | |||
| if(_dpf_plugin_USE_FILE_BROWSER) | |||
| target_compile_definitions("${NAME}" PUBLIC "DGL_USE_FILE_BROWSER") | |||
| if(EMSCRIPTEN) | |||
| target_link_options("${NAME}" PRIVATE -sEXPORTED_RUNTIME_METHODS=FS,cwrap) | |||
| endif() | |||
| endif() | |||
| if(_dpf_plugin_USE_WEB_VIEW) | |||
| target_compile_definitions("${NAME}" PUBLIC "DGL_USE_WEB_VIEW") | |||
| endif() | |||
| if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||
| target_link_libraries("${NAME}" PRIVATE "dl") | |||
| endif() | |||
| if(_dgl_library) | |||
| # make sure that all code will see DGL_* definitions | |||
| target_link_libraries("${NAME}" PUBLIC | |||
| "${_dgl_library}" | |||
| "${_dgl_library}-definitions" | |||
| dgl-system-libs-definitions | |||
| dgl-system-libs) | |||
| # extra linkage for linux web view | |||
| if(LINUX AND _dpf_plugin_USE_WEB_VIEW) | |||
| target_link_libraries("${NAME}" PRIVATE "rt") | |||
| endif() | |||
| # add the files containing C++17 or Objective-C classes | |||
| dpf__add_plugin_specific_ui_sources("${NAME}" "${_dpf_plugin_USE_WEB_VIEW}") | |||
| endif() | |||
| endfunction() | |||
| # ------------------------------------------------------------------------------ | |||
| # DPF private functions (prefixed with `dpf__`) | |||
| # ------------------------------------------------------------------------------ | |||
| @@ -247,7 +414,7 @@ endfunction() | |||
| # | |||
| # Add build rules for a JACK/Standalone program. | |||
| # | |||
| function(dpf__build_jack NAME HAS_UI) | |||
| function(dpf__build_jack NAME HAS_UI FORCE_NATIVE_AUDIO_FALLBACK SKIP_NATIVE_AUDIO_FALLBACK USE_FILE_BROWSER) | |||
| dpf__create_dummy_source_list(_no_srcs) | |||
| dpf__add_executable("${NAME}-jack" ${_no_srcs}) | |||
| @@ -258,11 +425,30 @@ function(dpf__build_jack NAME HAS_UI) | |||
| RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | |||
| OUTPUT_NAME "${NAME}") | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_JACK") | |||
| target_compile_definitions("${NAME}-jack" PRIVATE "HAVE_GETTIMEOFDAY") | |||
| if(EMSCRIPTEN) | |||
| configure_file("${DPF_ROOT_DIR}/utils/emscripten.html.in" | |||
| "${PROJECT_BINARY_DIR}/bin/${NAME}.html" @ONLY) | |||
| target_link_options("${NAME}-jack" | |||
| PRIVATE | |||
| -sEXPORTED_RUNTIME_METHODS=dynCall | |||
| $<$<BOOL:${USE_FILE_BROWSER}>:-sEXPORTED_RUNTIME_METHODS=FS,cwrap>) | |||
| endif() | |||
| if(NOT FORCE_NATIVE_AUDIO_FALLBACK) | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_JACK") | |||
| target_compile_definitions("${NAME}-jack" PRIVATE "HAVE_GETTIMEOFDAY") | |||
| endif() | |||
| find_package(PkgConfig) | |||
| pkg_check_modules(SDL2 "sdl2") | |||
| if(SKIP_NATIVE_AUDIO_FALLBACK) | |||
| return() | |||
| endif() | |||
| find_package(PkgConfig QUIET) | |||
| if(PKG_CONFIG_FOUND) | |||
| pkg_check_modules(SDL2 "sdl2") | |||
| else() | |||
| set(SDL2_FOUND FALSE) | |||
| endif() | |||
| if(SDL2_FOUND) | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_SDL2") | |||
| target_include_directories("${NAME}-jack" PRIVATE ${SDL2_STATIC_INCLUDE_DIRS}) | |||
| @@ -272,20 +458,20 @@ function(dpf__build_jack NAME HAS_UI) | |||
| if(APPLE OR WIN32) | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_RTAUDIO") | |||
| elseif(EMSCRIPTEN) | |||
| else() | |||
| find_package(Threads) | |||
| pkg_check_modules(ALSA "alsa") | |||
| pkg_check_modules(PULSEAUDIO "libpulse-simple") | |||
| if(ALSA_FOUND) | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_ALSA") | |||
| target_include_directories("${NAME}-jack" PRIVATE ${ALSA_INCLUDE_DIRS}) | |||
| target_link_libraries("${NAME}-jack" PRIVATE ${ALSA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) | |||
| target_link_libraries("${NAME}-jack" PRIVATE ${ALSA_LIBRARIES}) | |||
| dpf__target_link_directories("${NAME}-jack" "${ALSA_LIBRARY_DIRS}") | |||
| endif() | |||
| if(PULSEAUDIO_FOUND) | |||
| target_compile_definitions("${NAME}" PUBLIC "HAVE_PULSEAUDIO") | |||
| target_include_directories("${NAME}-jack" PRIVATE ${PULSEAUDIO_INCLUDE_DIRS}) | |||
| target_link_libraries("${NAME}-jack" PRIVATE ${PULSEAUDIO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) | |||
| target_link_libraries("${NAME}-jack" PRIVATE ${PULSEAUDIO_LIBRARIES}) | |||
| dpf__target_link_directories("${NAME}-jack" "${PULSEAUDIO_LIBRARY_DIRS}") | |||
| endif() | |||
| if(ALSA_FOUND OR PULSEAUDIO_FOUND) | |||
| @@ -335,8 +521,12 @@ endfunction() | |||
| # Add build rules for a DSSI plugin. | |||
| # | |||
| function(dpf__build_dssi NAME HAS_UI) | |||
| find_package(PkgConfig) | |||
| pkg_check_modules(LIBLO "liblo") | |||
| find_package(PkgConfig QUIET) | |||
| if(PKG_CONFIG_FOUND) | |||
| pkg_check_modules(LIBLO "liblo") | |||
| else() | |||
| set(LIBLO_FOUND FALSE) | |||
| endif() | |||
| if(NOT LIBLO_FOUND) | |||
| dpf__warn_once_only(missing_liblo | |||
| "liblo is not found, skipping the `dssi` plugin targets") | |||
| @@ -392,6 +582,10 @@ function(dpf__build_lv2 NAME HAS_UI MONOLITHIC EXTRA_UI_LINK_OPTS) | |||
| OUTPUT_NAME "${NAME}_dsp" | |||
| PREFIX "") | |||
| # helper property for custom outside handling | |||
| set_target_properties("${NAME}" PROPERTIES | |||
| LV2_BUNDLE "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2") | |||
| if(HAS_UI) | |||
| if(MONOLITHIC) | |||
| dpf__add_ui_main("${NAME}-lv2" "lv2" "${HAS_UI}") | |||
| @@ -423,8 +617,7 @@ function(dpf__build_lv2 NAME HAS_UI MONOLITHIC EXTRA_UI_LINK_OPTS) | |||
| ${CMAKE_CROSSCOMPILING_EMULATOR} | |||
| "$<TARGET_FILE:lv2_ttl_generator>" | |||
| "$<TARGET_FILE:${NAME}-lv2>" | |||
| WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2" | |||
| DEPENDS lv2_ttl_generator) | |||
| WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2") | |||
| endfunction() | |||
| # dpf__build_vst2 | |||
| @@ -485,8 +678,15 @@ function(dpf__determine_vst3_package_architecture OUTPUT_VARIABLE) | |||
| endif() | |||
| # transform the processor name to a format that VST3 recognizes | |||
| # see https://steinbergmedia.github.io/vst3_dev_portal/pages/Technical+Documentation/Locations+Format/Plugin+Format.html | |||
| if(vst3_system_arch MATCHES "^(x86_64|amd64|AMD64|x64|X64)$") | |||
| set(vst3_package_arch "x86_64") | |||
| elseif(vst3_system_arch MATCHES "^(ARM)$") | |||
| set(vst3_package_arch "arm") | |||
| elseif(vst3_system_arch MATCHES "^(ARM64)$") | |||
| set(vst3_package_arch "arm64") | |||
| elseif(vst3_system_arch MATCHES "^(ARM64EC)$") | |||
| set(vst3_package_arch "arm64x") | |||
| elseif(vst3_system_arch MATCHES "^(i.86|x86|X86)$") | |||
| if(WIN32) | |||
| set(vst3_package_arch "x86") | |||
| @@ -619,8 +819,7 @@ function(dpf__build_au NAME HAS_UI) | |||
| add_custom_command(TARGET "${NAME}-au" POST_BUILD | |||
| COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} "$<TARGET_FILE:${NAME}-export>" "${NAME}" | |||
| WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents" | |||
| DEPENDS "${NAME}-export") | |||
| WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents") | |||
| add_dependencies("${NAME}-au" "${NAME}-export") | |||
| @@ -661,12 +860,12 @@ endfunction() | |||
| # | |||
| # Add the Cairo variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER) | |||
| function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-cairo) | |||
| return() | |||
| endif() | |||
| find_package(PkgConfig) | |||
| find_package(PkgConfig REQUIRED) | |||
| pkg_check_modules(CAIRO "cairo" REQUIRED) | |||
| link_directories(${CAIRO_LIBRARY_DIRS}) | |||
| @@ -710,6 +909,21 @@ function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-cairo PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-cairo PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-cairo PRIVATE dgl-system-libs) | |||
| @@ -730,7 +944,7 @@ endfunction() | |||
| # | |||
| # Add the external variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_external USE_FILE_BROWSER) | |||
| function(dpf__add_dgl_external USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-external) | |||
| return() | |||
| endif() | |||
| @@ -770,6 +984,21 @@ function(dpf__add_dgl_external USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-external PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-external PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-external PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_compile_definitions(dgl-external PUBLIC "DGL_NO_SHARED_RESOURCES") | |||
| target_link_libraries(dgl-external PRIVATE dgl-system-libs) | |||
| @@ -781,12 +1010,210 @@ function(dpf__add_dgl_external USE_FILE_BROWSER) | |||
| target_link_libraries(dgl-external PRIVATE dgl-external-definitions "${OPENGL_gl_LIBRARY}") | |||
| endfunction() | |||
| # dpf__add_dgl_gles2 | |||
| # ------------------------------------------------------------------------------ | |||
| # | |||
| # Add the GLESv2 variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_gles2 SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-gles2) | |||
| return() | |||
| endif() | |||
| if(NOT OpenGL_GL_PREFERENCE) | |||
| set(OpenGL_GL_PREFERENCE "LEGACY") | |||
| endif() | |||
| find_package(OpenGL REQUIRED) | |||
| dpf__add_static_library(dgl-gles2 STATIC | |||
| "${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Layout.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/TopLevelWidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Widget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL3.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | |||
| if(SHARED_RESOURCES) | |||
| target_sources(dgl-gles2 PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||
| else() | |||
| target_compile_definitions(dgl-gles2 PUBLIC "DGL_NO_SHARED_RESOURCES") | |||
| endif() | |||
| if(APPLE) | |||
| target_sources(dgl-gles2 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||
| else() | |||
| target_sources(dgl-gles2 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||
| endif() | |||
| target_include_directories(dgl-gles2 PUBLIC | |||
| "${DPF_ROOT_DIR}/dgl") | |||
| target_include_directories(dgl-gles2 PUBLIC | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | |||
| if(APPLE) | |||
| target_compile_definitions(dgl-gles2 PUBLIC "GL_SILENCE_DEPRECATION") | |||
| endif() | |||
| if(USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-gles2 PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-gles2 PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-gles2 PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-gles2 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-gles2 PRIVATE dgl-system-libs) | |||
| target_link_options(dgl-gles2 | |||
| INTERFACE | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sMIN_WEBGL_VERSION=2> | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sMAX_WEBGL_VERSION=2> | |||
| ) | |||
| add_library(dgl-gles2-definitions INTERFACE) | |||
| target_compile_definitions(dgl-gles2-definitions | |||
| INTERFACE | |||
| DGL_USE_OPENGL3 | |||
| DGL_USE_GLES | |||
| DGL_USE_GLES2 | |||
| DGL_OPENGL | |||
| HAVE_OPENGL | |||
| HAVE_DGL | |||
| ) | |||
| target_include_directories(dgl-gles2 PUBLIC "${OPENGL_INCLUDE_DIR}") | |||
| target_link_libraries(dgl-gles2 PRIVATE dgl-gles2-definitions "${OPENGL_gl_LIBRARY}") | |||
| endfunction() | |||
| # dpf__add_dgl_gles3 | |||
| # ------------------------------------------------------------------------------ | |||
| # | |||
| # Add the GLESv3 variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_gles3 SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-gles3) | |||
| return() | |||
| endif() | |||
| if(NOT OpenGL_GL_PREFERENCE) | |||
| set(OpenGL_GL_PREFERENCE "LEGACY") | |||
| endif() | |||
| find_package(OpenGL REQUIRED) | |||
| dpf__add_static_library(dgl-gles3 STATIC | |||
| "${DPF_ROOT_DIR}/dgl/src/Application.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ApplicationPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Color.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/EventHandlers.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Geometry.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ImageBase.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/ImageBaseWidgets.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Layout.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/SubWidget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/SubWidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/TopLevelWidget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/TopLevelWidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Widget.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WidgetPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL3.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | |||
| if(SHARED_RESOURCES) | |||
| target_sources(dgl-gles3 PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||
| else() | |||
| target_compile_definitions(dgl-gles3 PUBLIC "DGL_NO_SHARED_RESOURCES") | |||
| endif() | |||
| if(APPLE) | |||
| target_sources(dgl-gles3 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl.mm") | |||
| else() | |||
| target_sources(dgl-gles3 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl.cpp") | |||
| endif() | |||
| target_include_directories(dgl-gles3 PUBLIC | |||
| "${DPF_ROOT_DIR}/dgl") | |||
| target_include_directories(dgl-gles3 PUBLIC | |||
| "${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include") | |||
| if(APPLE) | |||
| target_compile_definitions(dgl-gles3 PUBLIC "GL_SILENCE_DEPRECATION") | |||
| endif() | |||
| if(USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-gles3 PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-gles3 PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-gles3 PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-gles3 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-gles3 PRIVATE dgl-system-libs) | |||
| target_link_options(dgl-gles3 | |||
| INTERFACE | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sMIN_WEBGL_VERSION=3> | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sMAX_WEBGL_VERSION=3> | |||
| ) | |||
| add_library(dgl-gles3-definitions INTERFACE) | |||
| target_compile_definitions(dgl-gles3-definitions | |||
| INTERFACE | |||
| DGL_USE_OPENGL3 | |||
| DGL_USE_GLES | |||
| DGL_USE_GLES3 | |||
| DGL_OPENGL | |||
| HAVE_OPENGL | |||
| HAVE_DGL | |||
| ) | |||
| target_include_directories(dgl-gles3 PUBLIC "${OPENGL_INCLUDE_DIR}") | |||
| target_link_libraries(dgl-gles3 PRIVATE dgl-gles3-definitions "${OPENGL_gl_LIBRARY}") | |||
| endfunction() | |||
| # dpf__add_dgl_opengl | |||
| # ------------------------------------------------------------------------------ | |||
| # | |||
| # Add the OpenGL variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER) | |||
| function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-opengl) | |||
| return() | |||
| endif() | |||
| @@ -815,6 +1242,7 @@ function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER) | |||
| "${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL2.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | |||
| if(SHARED_RESOURCES) | |||
| target_sources(dgl-opengl PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||
| @@ -841,11 +1269,36 @@ function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-opengl PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-opengl PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-opengl PRIVATE dgl-system-libs) | |||
| target_link_options(dgl-opengl | |||
| INTERFACE | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sLEGACY_GL_EMULATION> | |||
| $<$<BOOL:${EMSCRIPTEN}>:-sGL_UNSAFE_OPTS=0> | |||
| ) | |||
| add_library(dgl-opengl-definitions INTERFACE) | |||
| target_compile_definitions(dgl-opengl-definitions INTERFACE "DGL_OPENGL" "HAVE_OPENGL" "HAVE_DGL") | |||
| target_compile_definitions(dgl-opengl-definitions | |||
| INTERFACE | |||
| DGL_OPENGL | |||
| HAVE_OPENGL | |||
| HAVE_DGL | |||
| ) | |||
| target_include_directories(dgl-opengl PUBLIC "${OPENGL_INCLUDE_DIR}") | |||
| target_link_libraries(dgl-opengl PRIVATE dgl-opengl-definitions "${OPENGL_gl_LIBRARY}") | |||
| @@ -856,7 +1309,7 @@ endfunction() | |||
| # | |||
| # Add the OpenGL3 variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER) | |||
| function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-opengl3) | |||
| return() | |||
| endif() | |||
| @@ -885,6 +1338,7 @@ function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER) | |||
| "${DPF_ROOT_DIR}/dgl/src/Window.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/OpenGL3.cpp" | |||
| "${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp") | |||
| if(SHARED_RESOURCES) | |||
| target_sources(dgl-opengl3 PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp") | |||
| @@ -911,11 +1365,32 @@ function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-opengl3 PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-opengl3 PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-opengl3 PRIVATE dgl-system-libs) | |||
| add_library(dgl-opengl3-definitions INTERFACE) | |||
| target_compile_definitions(dgl-opengl3-definitions INTERFACE "DGL_USE_OPENGL3" "DGL_OPENGL" "HAVE_OPENGL" "HAVE_DGL") | |||
| target_compile_definitions(dgl-opengl3-definitions | |||
| INTERFACE | |||
| DGL_USE_OPENGL3 | |||
| DGL_OPENGL | |||
| HAVE_OPENGL | |||
| HAVE_DGL | |||
| ) | |||
| target_include_directories(dgl-opengl3 PUBLIC "${OPENGL_INCLUDE_DIR}") | |||
| target_link_libraries(dgl-opengl3 PRIVATE dgl-opengl3-definitions "${OPENGL_gl_LIBRARY}") | |||
| @@ -926,7 +1401,7 @@ endfunction() | |||
| # | |||
| # Add the Vulkan variant of DGL, if not already available. | |||
| # | |||
| function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER) | |||
| function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER USE_WEB_VIEW) | |||
| if(TARGET dgl-vulkan) | |||
| return() | |||
| endif() | |||
| @@ -976,6 +1451,21 @@ function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER) | |||
| target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_FILE_BROWSER") | |||
| endif() | |||
| if(USE_WEB_VIEW) | |||
| target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_WEB_VIEW") | |||
| if(APPLE) | |||
| find_library(APPLE_WEBKIT_FRAMEWORK "WebKit") | |||
| target_link_libraries(dgl-vulkan PRIVATE "${APPLE_WEBKIT_FRAMEWORK}") | |||
| elseif(WIN32) | |||
| target_sources(dgl-vulkan PRIVATE | |||
| "${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp") | |||
| set_source_files_properties("${DPF_ROOT_DIR}/dgl/src/WebViewWin32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| endif() | |||
| endif() | |||
| dpf__add_dgl_system_libs() | |||
| target_link_libraries(dgl-vulkan PRIVATE dgl-system-libs) | |||
| @@ -1002,13 +1492,10 @@ function(dpf__add_plugin_specific_ui_sources NAME USE_WEB_VIEW) | |||
| elseif(WIN32 AND USE_WEB_VIEW) | |||
| target_sources("${NAME}" PRIVATE | |||
| "${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp") | |||
| if (MSVC) | |||
| set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp" | |||
| PROPERTIES COMPILE_FLAGS /std:c++17) | |||
| else() | |||
| set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp" | |||
| PROPERTIES COMPILE_FLAGS -std=gnu++17) | |||
| endif() | |||
| set_source_files_properties("${DPF_ROOT_DIR}/distrho/DistrhoUI_win32.cpp" | |||
| PROPERTIES | |||
| COMPILE_FLAGS | |||
| $<IF:$<BOOL:${MSVC}>,/std:c++17,-std=gnu++17>) | |||
| target_link_libraries("${NAME}" PRIVATE "ole32" "uuid") | |||
| endif() | |||
| endfunction() | |||
| @@ -1034,7 +1521,7 @@ function(dpf__add_dgl_system_libs) | |||
| elseif(WIN32) | |||
| target_link_libraries(dgl-system-libs INTERFACE "comdlg32" "dwmapi" "gdi32") | |||
| else() | |||
| find_package(PkgConfig) | |||
| find_package(PkgConfig REQUIRED) | |||
| pkg_check_modules(DBUS "dbus-1") | |||
| if(DBUS_FOUND) | |||
| target_compile_definitions(dgl-system-libs-definitions INTERFACE "HAVE_DBUS") | |||
| @@ -1161,7 +1648,7 @@ function(dpf__set_target_defaults NAME) | |||
| if (CMAKE_COMPILER_IS_GNUCXX) | |||
| target_compile_options("${NAME}" PUBLIC "-fno-gnu-unique") | |||
| endif() | |||
| if ((NOT APPLE) AND (NOT MSVC)) | |||
| if ((NOT APPLE) AND (NOT EMSCRIPTEN) AND (NOT MSVC)) | |||
| target_link_options("${NAME}" PUBLIC "-Wl,--no-undefined") | |||
| endif() | |||
| endfunction() | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -54,6 +54,12 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on) | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_on) | |||
| #else | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_off) | |||
| #endif | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | |||
| #else | |||
| @@ -78,10 +84,26 @@ class DISTRHO_API Application | |||
| { | |||
| public: | |||
| /** | |||
| Constructor. | |||
| Type of application to setup, either "classic" or "modern". | |||
| What this means depends on the OS. | |||
| */ | |||
| enum Type { | |||
| kTypeAuto, | |||
| kTypeClassic, | |||
| kTypeModern, | |||
| }; | |||
| /** | |||
| Constructor for standalone or plugin application. | |||
| */ | |||
| // NOTE: the default value is not yet passed, so we catch where we use this | |||
| Application(bool isStandalone = true); | |||
| Application(bool isStandalone = true, Type type = kTypeAuto); | |||
| /** | |||
| Constructor for a standalone application. | |||
| This specific constructor is required if using web views in standalone applications. | |||
| */ | |||
| Application(int argc, char* argv[]); | |||
| /** | |||
| Destructor. | |||
| @@ -130,6 +152,12 @@ public: | |||
| */ | |||
| double getTime() const; | |||
| /** | |||
| Return the application type, either kTypeClassic or kTypeModern. | |||
| This function never return kTypeAuto. | |||
| */ | |||
| Type getType() const noexcept; | |||
| /** | |||
| Add a callback function to be triggered on every idle cycle. | |||
| You can add more than one, and remove them at anytime with removeIdleCallback(). | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -41,14 +41,18 @@ | |||
| # error typo detected use DGL_USE_FILE_BROWSER instead of DGL_USE_FILEBROWSER | |||
| #endif | |||
| #ifdef DGL_UI_USE_WEBVIEW | |||
| # error typo detected use DGL_UI_USE_WEB_VIEW instead of DGL_UI_USE_WEBVIEW | |||
| #ifdef DGL_USE_WEBVIEW | |||
| # error typo detected use DGL_USE_WEB_VIEW instead of DGL_USE_WEBVIEW | |||
| #endif | |||
| #if defined(DGL_FILE_BROWSER_DISABLED) | |||
| # error DGL_FILE_BROWSER_DISABLED has been replaced by DGL_USE_FILE_BROWSER (opt-in vs opt-out) | |||
| #endif | |||
| #ifndef DGL_ALLOW_DEPRECATED_METHODS | |||
| # define DGL_ALLOW_DEPRECATED_METHODS 1 | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Define namespace | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -165,10 +165,9 @@ private: | |||
| Widget display function. | |||
| Implemented internally to pass context into the drawing function. | |||
| */ | |||
| void onDisplay() override | |||
| void onDisplay() final | |||
| { | |||
| const CairoGraphicsContext& context((const CairoGraphicsContext&)BaseWidget::getGraphicsContext()); | |||
| onCairoDisplay(context); | |||
| onCairoDisplay(static_cast<const CairoGraphicsContext&>(BaseWidget::getGraphicsContext())); | |||
| } | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CairoBaseWidget); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -99,6 +99,11 @@ struct Color { | |||
| */ | |||
| Color invert() const noexcept; | |||
| /** | |||
| Create a new color based on this one but in grayscale (using weighted average). | |||
| */ | |||
| Color asGrayscale() const noexcept; | |||
| /** | |||
| Create a color specified by hue, saturation and lightness. | |||
| Values must in [0..1] range. | |||
| @@ -110,6 +115,17 @@ struct Color { | |||
| */ | |||
| static Color fromHTML(const char* rgb, float alpha = 1.0f) noexcept; | |||
| /** | |||
| Create a color from a RGB unsigned integer. | |||
| Basically doing: | |||
| ``` | |||
| uint8_t red = (color >> 24) & 0xff; | |||
| uint8_t green = (color >> 16) & 0xff; | |||
| uint8_t blue = (color >> 8) & 0xff; | |||
| ``` | |||
| */ | |||
| static Color fromRGB(uint color, float alpha = 1.0f) noexcept; | |||
| /** | |||
| Linearly interpolate this color against another. | |||
| */ | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -63,6 +63,9 @@ public: | |||
| bool isCheckable() const noexcept; | |||
| void setCheckable(bool checkable) noexcept; | |||
| bool isEnabled() const noexcept; | |||
| void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; | |||
| Point<double> getLastClickPosition() const noexcept; | |||
| Point<double> getLastMotionPosition() const noexcept; | |||
| @@ -121,6 +124,9 @@ public: | |||
| KnobEventHandler& operator=(const KnobEventHandler& other); | |||
| virtual ~KnobEventHandler(); | |||
| bool isEnabled() const noexcept; | |||
| void setEnabled(bool enabled, bool appliesToEventInput = true) noexcept; | |||
| // if setStep(1) has been called before, this returns true | |||
| bool isInteger() const noexcept; | |||
| @@ -138,6 +144,9 @@ public: | |||
| // NOTE: value is assumed to be scaled if using log | |||
| void setDefault(float def) noexcept; | |||
| float getMinimum() const noexcept; | |||
| float getMaximum() const noexcept; | |||
| // NOTE: value is assumed to be scaled if using log | |||
| void setRange(float min, float max) noexcept; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -360,25 +360,23 @@ public: | |||
| */ | |||
| bool isNotNull() const noexcept; | |||
| #ifndef DPF_TEST_POINT_CPP | |||
| /** | |||
| Draw this line using the provided graphics context, optionally specifying line width. | |||
| */ | |||
| void draw(const GraphicsContext& context, T width = 1); | |||
| #endif | |||
| Line<T>& operator=(const Line<T>& line) noexcept; | |||
| bool operator==(const Line<T>& line) const noexcept; | |||
| bool operator!=(const Line<T>& line) const noexcept; | |||
| #ifndef DPF_TEST_POINT_CPP | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| /** | |||
| Draw this line using the current OpenGL state.@n | |||
| DEPRECATED Please use draw(const GraphicsContext&) instead. | |||
| */ | |||
| DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||
| void draw(); | |||
| #endif | |||
| #endif | |||
| private: | |||
| Point<T> posStart, posEnd; | |||
| @@ -489,7 +487,7 @@ public: | |||
| bool operator==(const Circle<T>& cir) const noexcept; | |||
| bool operator!=(const Circle<T>& cir) const noexcept; | |||
| #ifndef DPF_TEST_POINT_CPP | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| /** | |||
| Draw this circle using the current OpenGL state.@n | |||
| DEPRECATED Please use draw(const GraphicsContext&) instead. | |||
| @@ -503,7 +501,7 @@ public: | |||
| */ | |||
| DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||
| void drawOutline(); | |||
| #endif | |||
| #endif | |||
| private: | |||
| Point<T> fPos; | |||
| @@ -582,7 +580,7 @@ public: | |||
| bool operator==(const Triangle<T>& tri) const noexcept; | |||
| bool operator!=(const Triangle<T>& tri) const noexcept; | |||
| #ifndef DPF_TEST_POINT_CPP | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| /** | |||
| Draw this triangle using the current OpenGL state.@n | |||
| DEPRECATED Please use draw(const GraphicsContext&) instead. | |||
| @@ -596,7 +594,7 @@ public: | |||
| */ | |||
| DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||
| void drawOutline(); | |||
| #endif | |||
| #endif | |||
| private: | |||
| Point<T> pos1, pos2, pos3; | |||
| @@ -813,6 +811,7 @@ public: | |||
| bool operator==(const Rectangle<T>& size) const noexcept; | |||
| bool operator!=(const Rectangle<T>& size) const noexcept; | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| /** | |||
| Draw this rectangle using the current OpenGL state.@n | |||
| DEPRECATED Please use draw(const GraphicsContext&) instead. | |||
| @@ -826,6 +825,7 @@ public: | |||
| */ | |||
| DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||
| void drawOutline(); | |||
| #endif | |||
| private: | |||
| Point<T> pos; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -17,17 +17,21 @@ | |||
| #ifndef DGL_IMAGE_HPP_INCLUDED | |||
| #define DGL_IMAGE_HPP_INCLUDED | |||
| #ifdef DGL_CAIRO | |||
| #include "Cairo.hpp" | |||
| #if defined(DGL_CAIRO) | |||
| # include "Cairo.hpp" | |||
| #elif defined(DGL_OPENGL) | |||
| # include "OpenGL.hpp" | |||
| #elif defined(DGL_VULKAN) | |||
| # include "Vulkan.hpp" | |||
| #else | |||
| #include "OpenGL.hpp" | |||
| # include "Base.hpp" | |||
| #endif | |||
| START_NAMESPACE_DGL | |||
| #ifdef DGL_CAIRO | |||
| #if defined(DGL_CAIRO) | |||
| typedef CairoImage Image; | |||
| #else | |||
| #elif defined(DGL_OPENGL) | |||
| typedef OpenGLImage Image; | |||
| #endif | |||
| @@ -54,6 +54,10 @@ OBJS_common = \ | |||
| $(BUILD_DIR)/dgl/Window.cpp.o \ | |||
| $(BUILD_DIR)/dgl/WindowPrivateData.cpp.o | |||
| ifeq ($(WINDOWS)$(USE_WEB_VIEW),truetrue) | |||
| OBJS_common += $(BUILD_DIR)/dgl/WebViewWin32.cpp.o | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| OBJS_cairo = $(OBJS_common) \ | |||
| @@ -67,8 +71,35 @@ endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| OBJS_gles2 = $(OBJS_common) \ | |||
| $(BUILD_DIR)/dgl/OpenGL.cpp.gles2.o \ | |||
| $(BUILD_DIR)/dgl/OpenGL3.cpp.gles2.o \ | |||
| $(BUILD_DIR)/dgl/NanoVG.cpp.gles2.o | |||
| ifeq ($(MACOS),true) | |||
| OBJS_gles2 += $(BUILD_DIR)/dgl/pugl.mm.gles2.o | |||
| else | |||
| OBJS_gles2 += $(BUILD_DIR)/dgl/pugl.cpp.gles2.o | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| OBJS_gles3 = $(OBJS_common) \ | |||
| $(BUILD_DIR)/dgl/OpenGL.cpp.gles3.o \ | |||
| $(BUILD_DIR)/dgl/OpenGL3.cpp.gles3.o \ | |||
| $(BUILD_DIR)/dgl/NanoVG.cpp.gles3.o | |||
| ifeq ($(MACOS),true) | |||
| OBJS_gles3 += $(BUILD_DIR)/dgl/pugl.mm.gles3.o | |||
| else | |||
| OBJS_gles3 += $(BUILD_DIR)/dgl/pugl.cpp.gles3.o | |||
| endif | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| OBJS_opengl = $(OBJS_common) \ | |||
| $(BUILD_DIR)/dgl/OpenGL.cpp.opengl.o \ | |||
| $(BUILD_DIR)/dgl/OpenGL2.cpp.opengl.o \ | |||
| $(BUILD_DIR)/dgl/NanoVG.cpp.opengl.o | |||
| ifeq ($(MACOS),true) | |||
| @@ -81,6 +112,7 @@ endif | |||
| OBJS_opengl3 = $(OBJS_common) \ | |||
| $(BUILD_DIR)/dgl/OpenGL.cpp.opengl3.o \ | |||
| $(BUILD_DIR)/dgl/OpenGL3.cpp.opengl3.o \ | |||
| $(BUILD_DIR)/dgl/NanoVG.cpp.opengl3.o | |||
| ifeq ($(MACOS),true) | |||
| @@ -118,7 +150,10 @@ TARGETS += $(BUILD_DIR)/libdgl-cairo.a | |||
| endif | |||
| ifeq ($(HAVE_OPENGL),true) | |||
| TARGETS += $(BUILD_DIR)/libdgl-gles2.a | |||
| TARGETS += $(BUILD_DIR)/libdgl-gles3.a | |||
| TARGETS += $(BUILD_DIR)/libdgl-opengl.a | |||
| TARGETS += $(BUILD_DIR)/libdgl-opengl3.a | |||
| endif | |||
| ifeq ($(HAVE_STUB),true) | |||
| @@ -134,8 +169,15 @@ endif | |||
| all: $(TARGETS) | |||
| cairo: $(BUILD_DIR)/libdgl-cairo.a | |||
| gles2: $(BUILD_DIR)/libdgl-gles2.a | |||
| gles3: $(BUILD_DIR)/libdgl-gles3.a | |||
| ifeq ($(WASM),true) | |||
| opengl: gles2 | |||
| opengl3: gles3 | |||
| else | |||
| opengl: $(BUILD_DIR)/libdgl-opengl.a | |||
| opengl3: $(BUILD_DIR)/libdgl-opengl3.a | |||
| endif | |||
| stub: $(BUILD_DIR)/libdgl-stub.a | |||
| vulkan: $(BUILD_DIR)/libdgl-vulkan.a | |||
| web: $(BUILD_DIR)/libdgl-web.a | |||
| @@ -148,6 +190,18 @@ $(BUILD_DIR)/libdgl-cairo.a: $(OBJS_cairo) | |||
| $(SILENT)rm -f $@ | |||
| $(SILENT)$(AR) crs $@ $^ | |||
| $(BUILD_DIR)/libdgl-gles2.a: $(OBJS_gles2) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Creating libdgl-gles2.a" | |||
| $(SILENT)rm -f $@ | |||
| $(SILENT)$(AR) crs $@ $^ | |||
| $(BUILD_DIR)/libdgl-gles3.a: $(OBJS_gles3) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Creating libdgl-gles3.a" | |||
| $(SILENT)rm -f $@ | |||
| $(SILENT)$(AR) crs $@ $^ | |||
| $(BUILD_DIR)/libdgl-opengl.a: $(OBJS_opengl) | |||
| -@mkdir -p $(BUILD_DIR) | |||
| @echo "Creating libdgl-opengl.a" | |||
| @@ -201,6 +255,11 @@ $(BUILD_DIR)/dgl/pugl.mm.o: src/pugl.mm | |||
| @echo "Compiling $<" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) -c -ObjC++ -o $@ | |||
| $(BUILD_DIR)/dgl/WebViewWin32.cpp.o: src/WebViewWin32.cpp | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $<" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| $(BUILD_DIR)/dgl/%.cpp.cairo.o: src/%.cpp | |||
| @@ -215,6 +274,30 @@ $(BUILD_DIR)/dgl/%.mm.cairo.o: src/%.mm | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| $(BUILD_DIR)/dgl/%.cpp.gles2.o: src/%.cpp | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $< (GLESv2 variant)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES2 -UDGL_USE_GLES3 -c -o $@ | |||
| $(BUILD_DIR)/dgl/%.mm.gles2.o: src/%.mm | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $< (GLESv2 variant)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES2 -UDGL_USE_GLES3 -c -ObjC++ -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| $(BUILD_DIR)/dgl/%.cpp.gles3.o: src/%.cpp | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $< (GLESv3 variant)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES3 -UDGL_USE_GLES2 -c -o $@ | |||
| $(BUILD_DIR)/dgl/%.mm.gles3.o: src/%.mm | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $< (GLESv3 variant)" | |||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(PUGL_EXTRA_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -DDGL_USE_OPENGL3 -DDGL_USE_GLES -DDGL_USE_GLES3 -UDGL_USE_GLES2 -c -ObjC++ -o $@ | |||
| # --------------------------------------------------------------------------------------------------------------------- | |||
| $(BUILD_DIR)/dgl/%.cpp.opengl.o: src/%.cpp | |||
| -@mkdir -p $(BUILD_DIR)/dgl | |||
| @echo "Compiling $< (OpenGL variant)" | |||
| @@ -261,6 +344,8 @@ debug: | |||
| -include $(OBJS_common:%.o=%.d) | |||
| -include $(OBJS_cairo:%.o=%.d) | |||
| -include $(OBJS_gles2:%.o=%.d) | |||
| -include $(OBJS_gles3:%.o=%.d) | |||
| -include $(OBJS_opengl:%.o=%.d) | |||
| -include $(OBJS_opengl3:%.o=%.d) | |||
| -include $(OBJS_stub:%.o=%.d) | |||
| @@ -112,6 +112,11 @@ public: | |||
| */ | |||
| GLuint getTextureHandle() const; | |||
| /** | |||
| Update the image data in-place. | |||
| */ | |||
| void update(const uchar* data); | |||
| private: | |||
| Handle fHandle; | |||
| Size<uint> fSize; | |||
| @@ -53,6 +53,12 @@ | |||
| #ifdef DISTRHO_OS_MAC | |||
| # ifdef DGL_USE_OPENGL3 | |||
| // NOTE GLES with macOS is not supported | |||
| # ifdef DGL_USE_GLES | |||
| # undef DGL_USE_GLES | |||
| # undef DGL_USE_GLES2 | |||
| # undef DGL_USE_GLES3 | |||
| # endif | |||
| # include <OpenGL/gl3.h> | |||
| # include <OpenGL/gl3ext.h> | |||
| # else | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -24,34 +24,131 @@ | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #ifdef DGL_USE_OPENGL3 | |||
| /** | |||
| OpenGL Graphics context. | |||
| OpenGL3 Graphics context. | |||
| This provides access to the program, shaders and uniforms used by the underlying DPF implementation. | |||
| */ | |||
| struct OpenGLGraphicsContext : GraphicsContext | |||
| struct OpenGL3GraphicsContext : GraphicsContext | |||
| { | |||
| #ifdef DGL_USE_OPENGL3 | |||
| #endif | |||
| /** | |||
| The OpenGL3 program used for this context. | |||
| It is activated automatically before any widget onDisplay() is called. | |||
| If changing the current OpenGL program make sure to revert back to this one at the end of your pipeline. | |||
| @code | |||
| // use custom program | |||
| glUseProgram(context.program); | |||
| // custom stuff here | |||
| // revert back | |||
| glUseProgram(context.program); | |||
| @endcode | |||
| */ | |||
| GLuint program; | |||
| /** | |||
| A vec4 uniform used to set the next drawing color. | |||
| @code | |||
| const GLfloat color[4] = { red, green, blue, alpha }; | |||
| glUniform4fv(context.color, 1, color); | |||
| @endcode | |||
| */ | |||
| GLuint color; | |||
| /** | |||
| A vertex shader attribute directly linked to gl_Position. | |||
| Use this to set the bounds for drawing, normalized as -1.0 to +1.0. | |||
| The @a width and @a height provide the total window size for convenience. | |||
| @code | |||
| const GLfloat triangle[] = { x1, y1, x2, y2, x3, y3 }; | |||
| glEnableVertexAttribArray(context.bounds); | |||
| glVertexAttribPointer(context.bounds, 2, GL_FLOAT, GL_FALSE, 0, triangle); | |||
| @endcode | |||
| */ | |||
| GLuint bounds; | |||
| /** | |||
| A vertex shader attribute directly linked to GL_TEXTURE0 map. | |||
| // TODO find the correct wording, map??. | |||
| @code | |||
| const GLfloat map[] = { 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f, 0.f }; | |||
| glEnableVertexAttribArray(context.textureMap); | |||
| glVertexAttribPointer(context.textureMap, 2, GL_FLOAT, GL_FALSE, 0, map); | |||
| @endcode | |||
| */ | |||
| GLuint textureMap; | |||
| /** | |||
| A boolean uniform used to indicate if next drawing should @a texture or @a color. | |||
| Set to 0 for color mode, 1 for texture. | |||
| Default mode is color, if changed make sure to revert to color mode at the end of your pipeline. | |||
| @code | |||
| // setup for drawing based on texture | |||
| glUniform1i(context.usingTexture, 1); | |||
| // bind texture | |||
| glBindTexture(GL_TEXTURE_2D, myTextureId); | |||
| // etc.. | |||
| // glDrawElements or similar | |||
| // unbind texture | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| // etc.. | |||
| // revert to color mode | |||
| glUniform1i(context.usingTexture, 0); | |||
| @endcode | |||
| */ | |||
| GLuint usingTexture; | |||
| /** | |||
| Set of buffers created with glGenBuffers. | |||
| Used internally in DPF to draw generic shapes, can be reused in custom code. | |||
| Unbound by default, make sure to leave them unbound at the end of your pipeline. | |||
| */ | |||
| GLuint buffers[2]; | |||
| /** | |||
| Total width of the window used for this context. | |||
| */ | |||
| uint width; | |||
| /** | |||
| Total height of the window used for this context. | |||
| */ | |||
| uint height; | |||
| }; | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static inline | |||
| ImageFormat asDISTRHOImageFormat(const GLenum format) | |||
| { | |||
| switch (format) | |||
| { | |||
| #ifdef DGL_USE_OPENGL3 | |||
| #if defined(DGL_USE_OPENGL3) && !defined(DGL_USE_GLES2) | |||
| case GL_RED: | |||
| #else | |||
| #else | |||
| case GL_LUMINANCE: | |||
| #endif | |||
| #endif | |||
| return kImageFormatGrayscale; | |||
| #ifndef DGL_USE_GLES | |||
| case GL_BGR: | |||
| return kImageFormatBGR; | |||
| case GL_BGRA: | |||
| return kImageFormatBGRA; | |||
| #endif | |||
| case GL_RGB: | |||
| return kImageFormatRGB; | |||
| case GL_RGBA: | |||
| @@ -69,25 +166,33 @@ GLenum asOpenGLImageFormat(const ImageFormat format) | |||
| case kImageFormatNull: | |||
| break; | |||
| case kImageFormatGrayscale: | |||
| #ifdef DGL_USE_OPENGL3 | |||
| #if defined(DGL_USE_OPENGL3) && !defined(DGL_USE_GLES2) | |||
| return GL_RED; | |||
| #else | |||
| #else | |||
| return GL_LUMINANCE; | |||
| #endif | |||
| #endif | |||
| case kImageFormatBGR: | |||
| #ifndef DGL_USE_GLES | |||
| return GL_BGR; | |||
| #else | |||
| return 0; | |||
| #endif | |||
| case kImageFormatBGRA: | |||
| #ifndef DGL_USE_GLES | |||
| return GL_BGRA; | |||
| #else | |||
| return 0; | |||
| #endif | |||
| case kImageFormatRGB: | |||
| return GL_RGB; | |||
| case kImageFormatRGBA: | |||
| return GL_RGBA; | |||
| } | |||
| return 0x0; | |||
| return 0; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| /** | |||
| OpenGL Image class. | |||
| @@ -144,6 +249,18 @@ public: | |||
| */ | |||
| void drawAt(const GraphicsContext& context, const Point<int>& pos) override; | |||
| #ifdef DGL_USE_GLES | |||
| /** | |||
| Get the image format. | |||
| */ | |||
| ImageFormat getFormat() const noexcept; | |||
| /** | |||
| Get the raw image data. | |||
| */ | |||
| const char* getRawData() const noexcept; | |||
| #endif | |||
| /** | |||
| TODO document this. | |||
| */ | |||
| @@ -157,6 +274,7 @@ public: | |||
| inline void drawAt(const GraphicsContext& context, int x, int y) | |||
| { drawAt(context, Point<int>(x, y)); } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| /** | |||
| Constructor using raw image data, specifying an OpenGL image format. | |||
| @note @a rawData must remain valid for the lifetime of this Image. | |||
| @@ -200,14 +318,19 @@ public: | |||
| */ | |||
| DISTRHO_DEPRECATED | |||
| GLenum getType() const noexcept { return GL_UNSIGNED_BYTE; } | |||
| #endif // DGL_ALLOW_DEPRECATED_METHODS | |||
| private: | |||
| bool setupCalled; | |||
| bool textureInit; | |||
| GLuint textureId; | |||
| #ifdef DGL_USE_GLES | |||
| mutable char* convertedData; | |||
| mutable const char* rawDataLast; | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow; | |||
| typedef ImageBaseButton<OpenGLImage> OpenGLImageButton; | |||
| @@ -215,7 +338,7 @@ typedef ImageBaseKnob<OpenGLImage> OpenGLImageKnob; | |||
| typedef ImageBaseSlider<OpenGLImage> OpenGLImageSlider; | |||
| typedef ImageBaseSwitch<OpenGLImage> OpenGLImageSwitch; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -0,0 +1,28 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef DGL_WEB_VIEW_HPP_INCLUDED | |||
| #define DGL_WEB_VIEW_HPP_INCLUDED | |||
| #include "Base.hpp" | |||
| START_NAMESPACE_DGL | |||
| #include "../distrho/extra/WebViewImpl.hpp" | |||
| END_NAMESPACE_DGL | |||
| #endif // DGL_WEB_VIEW_HPP_INCLUDED | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -23,6 +23,10 @@ | |||
| # include "FileBrowserDialog.hpp" | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| # include "WebView.hpp" | |||
| #endif | |||
| #include <vector> | |||
| #ifdef DISTRHO_NAMESPACE | |||
| @@ -407,6 +411,27 @@ public: | |||
| bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions()); | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| /** | |||
| Create a new web view. | |||
| The web view will be added on top of this window. | |||
| This means it will draw on top of whatever is below it, | |||
| something to take into consideration if mixing regular widgets with web views. | |||
| Provided metrics in @p options must have scale factor pre-applied. | |||
| @p url: The URL to open, assumed to be in encoded form (e.g spaces converted to %20) | |||
| @p options: Extra options, optional | |||
| */ | |||
| bool createWebView(const char* url, const DGL_NAMESPACE::WebViewOptions& options = WebViewOptions()); | |||
| /** | |||
| Evaluate/run JavaScript on the web view. | |||
| */ | |||
| void evaluateJS(const char* js); | |||
| #endif | |||
| /** | |||
| Request repaint of this window, for the entire area. | |||
| */ | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -24,6 +24,11 @@ | |||
| START_NAMESPACE_DGL | |||
| /* define webview start */ | |||
| #if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW) | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // build config sentinels | |||
| @@ -42,6 +47,12 @@ BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on) | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off) | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_on) | |||
| #else | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_web_view_off) | |||
| #endif | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on) | |||
| #else | |||
| @@ -64,6 +75,11 @@ bool dpf_check_build_status() noexcept | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_file_browser_off.ok && | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| fail_to_link_is_mismatch_dgl_use_web_view_on.ok && | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_web_view_off.ok && | |||
| #endif | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok && | |||
| #else | |||
| @@ -82,8 +98,8 @@ static void app_idle(void* const app) | |||
| } | |||
| #endif | |||
| Application::Application(const bool isStandalone) | |||
| : pData(new PrivateData(isStandalone)) | |||
| Application::Application(const bool isStandalone, const Type type) | |||
| : pData(new PrivateData(isStandalone, type)) | |||
| { | |||
| // build config sentinels | |||
| #ifdef DPF_DEBUG | |||
| @@ -96,6 +112,47 @@ Application::Application(const bool isStandalone) | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true; | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| fail_to_link_is_mismatch_dgl_use_web_view_on.ok = true; | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_web_view_off.ok = true; | |||
| #endif | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true; | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_no_shared_resources_off.ok = true; | |||
| #endif | |||
| DISTRHO_SAFE_ASSERT(dpf_check_build_status()); | |||
| } | |||
| Application::Application(int argc, char* argv[]) | |||
| : pData(new PrivateData(true, kTypeAuto)) | |||
| { | |||
| #if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW) | |||
| if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) | |||
| std::exit(dpf_webview_start(argc, argv)); | |||
| #else | |||
| // unused | |||
| (void)argc; | |||
| (void)argv; | |||
| #endif | |||
| // build config sentinels | |||
| #ifdef DPF_DEBUG | |||
| fail_to_link_is_mismatch_dpf_debug_on.ok = true; | |||
| #else | |||
| fail_to_link_is_mismatch_dpf_debug_off.ok = true; | |||
| #endif | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| fail_to_link_is_mismatch_dgl_use_file_browser_on.ok = true; | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_file_browser_off.ok = true; | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| fail_to_link_is_mismatch_dgl_use_web_view_on.ok = true; | |||
| #else | |||
| fail_to_link_is_mismatch_dgl_use_web_view_off.ok = true; | |||
| #endif | |||
| #ifdef DGL_NO_SHARED_RESOURCES | |||
| fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok = true; | |||
| #else | |||
| @@ -156,6 +213,11 @@ double Application::getTime() const | |||
| return pData->getTime(); | |||
| } | |||
| Application::Type Application::getType() const noexcept | |||
| { | |||
| return pData->isModern ? kTypeModern : kTypeClassic; | |||
| } | |||
| void Application::addIdleCallback(IdleCallback* const callback) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -53,13 +53,14 @@ const char* Application::getClassName() const noexcept | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| Application::PrivateData::PrivateData(const bool standalone) | |||
| Application::PrivateData::PrivateData(const bool standalone, const Type type) | |||
| : world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, | |||
| standalone ? PUGL_WORLD_THREADS : 0x0)), | |||
| (standalone ? PUGL_WORLD_THREADS : 0))), | |||
| isModern(false), | |||
| isStandalone(standalone), | |||
| isStarting(true), | |||
| isQuitting(false), | |||
| isQuittingInNextCycle(false), | |||
| isStarting(true), | |||
| needsRepaint(false), | |||
| visibleWindows(0), | |||
| mainThreadHandle(getCurrentThreadHandle()), | |||
| @@ -68,16 +69,11 @@ Application::PrivateData::PrivateData(const bool standalone) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | |||
| #ifdef DGL_USING_SDL | |||
| SDL_Init(SDL_INIT_EVENTS|SDL_INIT_TIMER|SDL_INIT_VIDEO); | |||
| #else | |||
| puglSetWorldHandle(world, this); | |||
| #ifdef __EMSCRIPTEN__ | |||
| puglSetWorldString(world, PUGL_CLASS_NAME, "canvas"); | |||
| #else | |||
| puglSetWorldString(world, PUGL_CLASS_NAME, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); | |||
| #endif | |||
| #endif | |||
| } | |||
| Application::PrivateData::~PrivateData() | |||
| @@ -88,12 +84,8 @@ Application::PrivateData::~PrivateData() | |||
| windows.clear(); | |||
| idleCallbacks.clear(); | |||
| #ifdef DGL_USING_SDL | |||
| SDL_Quit(); | |||
| #else | |||
| if (world != nullptr) | |||
| puglFreeWorld(world); | |||
| #endif | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -51,18 +51,21 @@ struct Application::PrivateData { | |||
| /** Pugl world instance. */ | |||
| PuglWorld* const world; | |||
| /** Whether the applicating uses modern backend, otherwise classic. */ | |||
| const bool isModern; | |||
| /** Whether the application is running as standalone, otherwise it is part of a plugin. */ | |||
| const bool isStandalone; | |||
| /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | |||
| bool isStarting; | |||
| /** Whether the applicating is about to quit, or already stopped. Defaults to false. */ | |||
| bool isQuitting; | |||
| /** Helper for safely close everything from main thread. */ | |||
| bool isQuittingInNextCycle; | |||
| /** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | |||
| bool isStarting; | |||
| /** When true force all windows to be repainted on next idle. */ | |||
| bool needsRepaint; | |||
| @@ -80,7 +83,7 @@ struct Application::PrivateData { | |||
| std::list<DGL_NAMESPACE::IdleCallback*> idleCallbacks; | |||
| /** Constructor and destructor */ | |||
| explicit PrivateData(bool standalone); | |||
| explicit PrivateData(bool standalone, Type type); | |||
| ~PrivateData(); | |||
| /** Flag one window as shown, which increments @a visibleWindows. | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| @@ -32,21 +32,43 @@ | |||
| // templated classes | |||
| #include "ImageBaseWidgets.cpp" | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Check for correct build config | |||
| #ifndef DGL_CAIRO | |||
| # error Build config error, Cairo was NOT requested while building Cairo code | |||
| #endif | |||
| #ifdef DGL_OPENGL | |||
| # error Build config error, OpenGL requested while building Cairo code | |||
| #endif | |||
| #ifdef DGL_VULKAN | |||
| # error Build config error, Vulkan requested while building Cairo code | |||
| #endif | |||
| #ifdef DGL_USE_GLES2 | |||
| # error Build config error, GLESv2 requested while building Cairo code | |||
| #endif | |||
| #ifdef DGL_USE_GLES3 | |||
| # error Build config error, GLESv3 requested while building Cairo code | |||
| #endif | |||
| #ifdef DGL_USE_OPENGL3 | |||
| # error Build config error, OpenGL3 requested while building Cairo code | |||
| #endif | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static void notImplemented(const char* const name) | |||
| { | |||
| d_stderr2("cairo function not implemented: %s", name); | |||
| d_stderr2("Cairo function not implemented: %s", name); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Color | |||
| void Color::setFor(const GraphicsContext& context, const bool includeAlpha) | |||
| { | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| if (includeAlpha) | |||
| cairo_set_source_rgba(handle, red, green, blue, alpha); | |||
| @@ -54,7 +76,7 @@ void Color::setFor(const GraphicsContext& context, const bool includeAlpha) | |||
| cairo_set_source_rgb(handle, red, green, blue); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Line | |||
| template<typename T> | |||
| @@ -63,7 +85,7 @@ void Line<T>::draw(const GraphicsContext& context, const T width) | |||
| DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(width != 0,); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| cairo_set_line_width(handle, width); | |||
| cairo_move_to(handle, posStart.getX(), posStart.getY()); | |||
| @@ -71,11 +93,13 @@ void Line<T>::draw(const GraphicsContext& context, const T width) | |||
| cairo_stroke(handle); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| notImplemented("Line::draw"); | |||
| } | |||
| #endif | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| @@ -129,7 +153,7 @@ static void drawCircle(cairo_t* const handle, | |||
| template<typename T> | |||
| void Circle<T>::draw(const GraphicsContext& context) | |||
| { | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, false); | |||
| } | |||
| @@ -139,12 +163,13 @@ void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| cairo_set_line_width(handle, lineWidth); | |||
| drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| @@ -156,6 +181,7 @@ void Circle<T>::drawOutline() | |||
| { | |||
| notImplemented("Circle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| @@ -190,7 +216,7 @@ static void drawTriangle(cairo_t* const handle, | |||
| template<typename T> | |||
| void Triangle<T>::draw(const GraphicsContext& context) | |||
| { | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| drawTriangle<T>(handle, pos1, pos2, pos3, false); | |||
| } | |||
| @@ -200,12 +226,13 @@ void Triangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| cairo_set_line_width(handle, lineWidth); | |||
| drawTriangle<T>(handle, pos1, pos2, pos3, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| @@ -217,6 +244,7 @@ void Triangle<T>::drawOutline() | |||
| { | |||
| notImplemented("Triangle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| @@ -244,7 +272,7 @@ void Rectangle<T>::draw(const GraphicsContext& context) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(isValid(),); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| drawRectangle(handle, *this, false); | |||
| } | |||
| @@ -255,12 +283,13 @@ void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth | |||
| DISTRHO_SAFE_ASSERT_RETURN(isValid(),); | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| cairo_set_line_width(handle, lineWidth); | |||
| drawRectangle(handle, *this, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| @@ -272,6 +301,7 @@ void Rectangle<T>::drawOutline() | |||
| { | |||
| notImplemented("Rectangle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Rectangle<double>; | |||
| template class Rectangle<float>; | |||
| @@ -516,7 +546,7 @@ void CairoImage::loadFromPNG(const char* const pngData, const uint pngSize) noex | |||
| if (datarefcount != nullptr && --(*datarefcount) == 0) | |||
| std::free(surfacedata); | |||
| else | |||
| datarefcount = (int*)malloc(sizeof(*datarefcount)); | |||
| datarefcount = static_cast<int*>(malloc(sizeof(*datarefcount))); | |||
| surface = newsurface; | |||
| surfacedata = nullptr; // cairo_image_surface_get_data(newsurface); | |||
| @@ -531,7 +561,7 @@ void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(surface != nullptr,); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| cairo_set_source_surface(handle, surface, pos.getX(), pos.getY()); | |||
| cairo_paint(handle); | |||
| @@ -623,7 +653,7 @@ void ImageBaseKnob<CairoImage>::PrivateData::init() | |||
| template <> | |||
| void ImageBaseKnob<CairoImage>::PrivateData::cleanup() | |||
| { | |||
| cairo_surface_destroy((cairo_surface_t*)cairoSurface); | |||
| cairo_surface_destroy(static_cast<cairo_surface_t*>(cairoSurface)); | |||
| cairoSurface = nullptr; | |||
| } | |||
| @@ -672,10 +702,10 @@ template <> | |||
| void ImageBaseKnob<CairoImage>::onDisplay() | |||
| { | |||
| const GraphicsContext& context(getGraphicsContext()); | |||
| cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||
| cairo_t* const handle = static_cast<const CairoGraphicsContext&>(context).handle; | |||
| const double normValue = getNormalizedValue(); | |||
| cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface; | |||
| cairo_surface_t* surface = static_cast<cairo_surface_t*>(pData->cairoSurface); | |||
| if (! pData->isReady) | |||
| { | |||
| @@ -826,15 +856,25 @@ void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, u | |||
| notImplemented("Window::PrivateData::renderToPicture"); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
| void Window::PrivateData::createContextIfNeeded() | |||
| { | |||
| GraphicsContext& context((GraphicsContext&)graphicsContext); | |||
| ((CairoGraphicsContext&)context).handle = (cairo_t*)puglGetContext(view); | |||
| return context; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::destroyContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::startContext() | |||
| { | |||
| reinterpret_cast<CairoGraphicsContext&>(graphicsContext).handle = static_cast<cairo_t*>(puglGetContext(view)); | |||
| } | |||
| void Window::PrivateData::endContext() | |||
| { | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -172,6 +172,14 @@ Color Color::invert() const noexcept | |||
| return color; | |||
| } | |||
| Color Color::asGrayscale() const noexcept | |||
| { | |||
| Color color(*this); | |||
| // values taken from https://goodcalculators.com/rgb-to-grayscale-conversion-calculator/ | |||
| color.red = color.green = color.blue = 0.299f * color.red + 0.587f * color.green + 0.114f * color.blue; | |||
| return color; | |||
| } | |||
| Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) | |||
| { | |||
| float m1, m2; | |||
| @@ -234,6 +242,14 @@ Color Color::fromHTML(const char* rgb, const float alpha) noexcept | |||
| return Color(r, g, b, alpha); | |||
| } | |||
| Color Color::fromRGB(const uint color, const float alpha) noexcept | |||
| { | |||
| return Color(static_cast<int>(color >> 24) & 0xff, | |||
| static_cast<int>(color >> 16) & 0xff, | |||
| static_cast<int>(color >> 8) & 0xff, | |||
| alpha); | |||
| } | |||
| void Color::interpolate(const Color& other, float u) noexcept | |||
| { | |||
| fixRange(u); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -31,6 +31,8 @@ struct ButtonEventHandler::PrivateData { | |||
| int state; | |||
| bool checkable; | |||
| bool checked; | |||
| bool enabled; | |||
| bool enabledInput; | |||
| Point<double> lastClickPos; | |||
| Point<double> lastMotionPos; | |||
| @@ -44,11 +46,16 @@ struct ButtonEventHandler::PrivateData { | |||
| state(kButtonStateDefault), | |||
| checkable(false), | |||
| checked(false), | |||
| enabled(true), | |||
| enabledInput(true), | |||
| lastClickPos(0, 0), | |||
| lastMotionPos(0, 0) {} | |||
| bool mouseEvent(const Widget::MouseEvent& ev) | |||
| { | |||
| if (! enabledInput) | |||
| return false; | |||
| lastClickPos = ev.pos; | |||
| // button was released, handle it now | |||
| @@ -98,12 +105,8 @@ struct ButtonEventHandler::PrivateData { | |||
| bool motionEvent(const Widget::MotionEvent& ev) | |||
| { | |||
| // keep pressed | |||
| if (button != -1) | |||
| { | |||
| lastMotionPos = ev.pos; | |||
| return true; | |||
| } | |||
| if (! enabledInput) | |||
| return false; | |||
| bool ret = false; | |||
| @@ -133,7 +136,7 @@ struct ButtonEventHandler::PrivateData { | |||
| } | |||
| lastMotionPos = ev.pos; | |||
| return ret; | |||
| return ret || button != -1; | |||
| } | |||
| void setActive(const bool active2, const bool sendCallback) noexcept | |||
| @@ -171,6 +174,27 @@ struct ButtonEventHandler::PrivateData { | |||
| } | |||
| } | |||
| void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept | |||
| { | |||
| if (appliesToEventInput) | |||
| enabledInput = enabled2; | |||
| if (enabled == enabled2) | |||
| return; | |||
| // reset temp vars if disabling | |||
| if (! enabled2) | |||
| { | |||
| button = -1; | |||
| state = kButtonStateDefault; | |||
| lastClickPos = Point<double>(); | |||
| lastMotionPos = Point<double>(); | |||
| } | |||
| enabled = enabled2; | |||
| widget->repaint(); | |||
| } | |||
| DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | |||
| }; | |||
| @@ -217,6 +241,16 @@ void ButtonEventHandler::setCheckable(const bool checkable) noexcept | |||
| pData->checkable = checkable; | |||
| } | |||
| bool ButtonEventHandler::isEnabled() const noexcept | |||
| { | |||
| return pData->enabled; | |||
| } | |||
| void ButtonEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept | |||
| { | |||
| pData->setEnabled(enabled, appliesToEventInput); | |||
| } | |||
| Point<double> ButtonEventHandler::getLastClickPosition() const noexcept | |||
| { | |||
| return pData->lastClickPos; | |||
| @@ -281,6 +315,8 @@ struct KnobEventHandler::PrivateData { | |||
| float value; | |||
| float valueDef; | |||
| float valueTmp; | |||
| bool enabled; | |||
| bool enabledInput; | |||
| bool usingDefault; | |||
| bool usingLog; | |||
| Orientation orientation; | |||
| @@ -301,6 +337,8 @@ struct KnobEventHandler::PrivateData { | |||
| value(0.5f), | |||
| valueDef(value), | |||
| valueTmp(value), | |||
| enabled(true), | |||
| enabledInput(true), | |||
| usingDefault(false), | |||
| usingLog(false), | |||
| orientation(Vertical), | |||
| @@ -320,6 +358,8 @@ struct KnobEventHandler::PrivateData { | |||
| value(other->value), | |||
| valueDef(other->valueDef), | |||
| valueTmp(value), | |||
| enabled(other->enabled), | |||
| enabledInput(other->enabledInput), | |||
| usingDefault(other->usingDefault), | |||
| usingLog(other->usingLog), | |||
| orientation(other->orientation), | |||
| @@ -338,6 +378,8 @@ struct KnobEventHandler::PrivateData { | |||
| value = other->value; | |||
| valueDef = other->valueDef; | |||
| valueTmp = value; | |||
| enabled = other->enabled; | |||
| enabledInput = other->enabledInput; | |||
| usingDefault = other->usingDefault; | |||
| usingLog = other->usingLog; | |||
| orientation = other->orientation; | |||
| @@ -363,6 +405,9 @@ struct KnobEventHandler::PrivateData { | |||
| bool mouseEvent(const Widget::MouseEvent& ev, const double scaleFactor) | |||
| { | |||
| if (! enabledInput) | |||
| return false; | |||
| if (ev.button != 1) | |||
| return false; | |||
| @@ -416,6 +461,9 @@ struct KnobEventHandler::PrivateData { | |||
| bool motionEvent(const Widget::MotionEvent& ev, const double scaleFactor) | |||
| { | |||
| if (! enabledInput) | |||
| return false; | |||
| if ((state & kKnobStateDragging) == 0x0) | |||
| return false; | |||
| @@ -501,6 +549,9 @@ struct KnobEventHandler::PrivateData { | |||
| bool scrollEvent(const Widget::ScrollEvent& ev) | |||
| { | |||
| if (! enabledInput) | |||
| return false; | |||
| if (! widget->contains(ev.pos)) | |||
| return false; | |||
| @@ -541,6 +592,28 @@ struct KnobEventHandler::PrivateData { | |||
| return ((usingLog ? invlogscale(value) : value) - minimum) / diff; | |||
| } | |||
| void setEnabled(const bool enabled2, const bool appliesToEventInput) noexcept | |||
| { | |||
| if (appliesToEventInput) | |||
| enabledInput = enabled2; | |||
| if (enabled == enabled2) | |||
| return; | |||
| // reset temp vars if disabling | |||
| if (! enabled2) | |||
| { | |||
| state = kKnobStateDefault; | |||
| lastX = 0.0; | |||
| lastY = 0.0; | |||
| lastClickTime = 0; | |||
| valueTmp = value; | |||
| } | |||
| enabled = enabled2; | |||
| widget->repaint(); | |||
| } | |||
| void setRange(const float min, const float max) noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(max > min,); | |||
| @@ -598,6 +671,16 @@ KnobEventHandler::~KnobEventHandler() | |||
| delete pData; | |||
| } | |||
| bool KnobEventHandler::isEnabled() const noexcept | |||
| { | |||
| return pData->enabled; | |||
| } | |||
| void KnobEventHandler::setEnabled(const bool enabled, const bool appliesToEventInput) noexcept | |||
| { | |||
| pData->setEnabled(enabled, appliesToEventInput); | |||
| } | |||
| bool KnobEventHandler::isInteger() const noexcept | |||
| { | |||
| return d_isEqual(pData->step, 1.f); | |||
| @@ -629,6 +712,16 @@ void KnobEventHandler::setDefault(const float def) noexcept | |||
| pData->usingDefault = true; | |||
| } | |||
| float KnobEventHandler::getMinimum() const noexcept | |||
| { | |||
| return pData->minimum; | |||
| } | |||
| float KnobEventHandler::getMaximum() const noexcept | |||
| { | |||
| return pData->maximum; | |||
| } | |||
| void KnobEventHandler::setRange(const float min, const float max) noexcept | |||
| { | |||
| pData->setRange(min, max); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -26,9 +26,11 @@ typedef std::list<VerticalLayout*>::iterator VerticalLayoutIterator; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| template<> // horizontal | |||
| uint Layout<true>::setAbsolutePos(int x, const int y, const uint padding) | |||
| uint Layout<true>::setAbsolutePos(int x, int y, const uint padding) | |||
| { | |||
| uint maxHeight = 0; | |||
| y += padding; | |||
| x += padding; | |||
| for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it) | |||
| { | |||
| @@ -43,9 +45,11 @@ uint Layout<true>::setAbsolutePos(int x, const int y, const uint padding) | |||
| } | |||
| template<> // vertical | |||
| uint Layout<false>::setAbsolutePos(const int x, int y, const uint padding) | |||
| uint Layout<false>::setAbsolutePos(int x, int y, const uint padding) | |||
| { | |||
| uint maxWidth = 0; | |||
| y += padding; | |||
| x += padding; | |||
| for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it) | |||
| { | |||
| @@ -63,10 +67,10 @@ template<> // horizontal | |||
| void Layout<true>::setSize(const uint width, const uint padding) | |||
| { | |||
| uint maxHeight = 0; | |||
| uint nonFixedWidth = width; | |||
| uint nonFixedWidth = width - padding * 2; | |||
| uint numDynamiclySizedWidgets = 0; | |||
| for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it) | |||
| for (SubWidgetWithSizeHintIterator it = widgets.begin(), end = widgets.end(); it != end; ++it) | |||
| { | |||
| SubWidgetWithSizeHint& s(*it); | |||
| maxHeight = std::max(maxHeight, s.widget->getHeight()); | |||
| @@ -96,7 +100,7 @@ template<> // vertical | |||
| void Layout<false>::setSize(const uint height, const uint padding) | |||
| { | |||
| uint biggestWidth = 0; | |||
| uint nonFixedHeight = height; | |||
| uint nonFixedHeight = height - padding * 2; | |||
| uint numDynamiclySizedWidgets = 0; | |||
| for (SubWidgetWithSizeHintIterator it=widgets.begin(), end=widgets.end(); it != end; ++it) | |||
| @@ -89,6 +89,8 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||
| //#define STB_IMAGE_STATIC | |||
| #if defined(DGL_USE_GLES2) | |||
| # define NANOVG_GLES2_IMPLEMENTATION | |||
| #elif defined(DGL_USE_GLES3) | |||
| # define NANOVG_GLES3_IMPLEMENTATION | |||
| #elif defined(DGL_USE_OPENGL3) | |||
| # define NANOVG_GL3_IMPLEMENTATION | |||
| #else | |||
| @@ -279,6 +281,14 @@ GLuint NanoImage::getTextureHandle() const | |||
| return nvglImageHandle(fHandle.context, fHandle.imageId); | |||
| } | |||
| void NanoImage::update(const uchar* const data) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(fHandle.context != nullptr && fHandle.imageId != 0,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(data != nullptr,); | |||
| nvgUpdateImage(fHandle.context, fHandle.imageId, data); | |||
| } | |||
| void NanoImage::_updateSize() | |||
| { | |||
| int w=0, h=0; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -20,7 +20,6 @@ | |||
| #endif | |||
| #include "../OpenGL.hpp" | |||
| #include "../Color.hpp" | |||
| #include "../ImageWidgets.hpp" | |||
| #include "SubWidgetPrivateData.hpp" | |||
| @@ -28,416 +27,20 @@ | |||
| #include "WidgetPrivateData.hpp" | |||
| #include "WindowPrivateData.hpp" | |||
| // templated classes | |||
| #include "ImageBaseWidgets.cpp" | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| #ifdef DGL_USE_OPENGL3 | |||
| static void notImplemented(const char* const name) | |||
| { | |||
| d_stderr2("OpenGL3 function not implemented: %s", name); | |||
| } | |||
| #else | |||
| # define DGL_USE_COMPAT_OPENGL | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // Color | |||
| void Color::setFor(const GraphicsContext&, const bool includeAlpha) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| if (includeAlpha) | |||
| glColor4f(red, green, blue, alpha); | |||
| else | |||
| glColor3f(red, green, blue); | |||
| #else | |||
| notImplemented("Color::setFor"); | |||
| // unused | |||
| (void)includeAlpha; | |||
| #endif | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // Line | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| template<typename T> | |||
| static void drawLine(const Point<T>& posStart, const Point<T>& posEnd) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); | |||
| glBegin(GL_LINES); | |||
| { | |||
| glVertex2d(posStart.getX(), posStart.getY()); | |||
| glVertex2d(posEnd.getX(), posEnd.getY()); | |||
| } | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| void Line<T>::draw(const GraphicsContext&, const T width) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| DISTRHO_SAFE_ASSERT_RETURN(width != 0,); | |||
| glLineWidth(static_cast<GLfloat>(width)); | |||
| drawLine<T>(posStart, posEnd); | |||
| #else | |||
| notImplemented("Line::draw"); | |||
| #endif | |||
| } | |||
| // deprecated calls | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawLine<T>(posStart, posEnd); | |||
| #else | |||
| notImplemented("Line::draw"); | |||
| #endif | |||
| } | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| template class Line<int>; | |||
| template class Line<uint>; | |||
| template class Line<short>; | |||
| template class Line<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| // Circle | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| template<typename T> | |||
| static void drawCircle(const Point<T>& pos, | |||
| const uint numSegments, | |||
| const float size, | |||
| const float sin, | |||
| const float cos, | |||
| const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); | |||
| const T origx = pos.getX(); | |||
| const T origy = pos.getY(); | |||
| double t, x = size, y = 0.0; | |||
| glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); | |||
| for (uint i=0; i<numSegments; ++i) | |||
| { | |||
| glVertex2d(x + origx, y + origy); | |||
| t = x; | |||
| x = cos * x - sin * y; | |||
| y = sin * t + cos * y; | |||
| } | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| void Circle<T>::draw(const GraphicsContext&) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false); | |||
| #else | |||
| notImplemented("Circle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true); | |||
| #else | |||
| notImplemented("Circle::drawOutline"); | |||
| #endif | |||
| } | |||
| // deprecated calls | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false); | |||
| #else | |||
| notImplemented("Circle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::drawOutline() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true); | |||
| #else | |||
| notImplemented("Circle::drawOutline"); | |||
| #endif | |||
| } | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| template class Circle<int>; | |||
| template class Circle<uint>; | |||
| template class Circle<short>; | |||
| template class Circle<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| // Triangle | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| template<typename T> | |||
| static void drawTriangle(const Point<T>& pos1, | |||
| const Point<T>& pos2, | |||
| const Point<T>& pos3, | |||
| const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); | |||
| glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); | |||
| { | |||
| glVertex2d(pos1.getX(), pos1.getY()); | |||
| glVertex2d(pos2.getX(), pos2.getY()); | |||
| glVertex2d(pos3.getX(), pos3.getY()); | |||
| } | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| void Triangle<T>::draw(const GraphicsContext&) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawTriangle<T>(pos1, pos2, pos3, false); | |||
| #else | |||
| notImplemented("Triangle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawTriangle<T>(pos1, pos2, pos3, true); | |||
| #else | |||
| notImplemented("Triangle::drawOutline"); | |||
| #endif | |||
| } | |||
| // deprecated calls | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawTriangle<T>(pos1, pos2, pos3, false); | |||
| #else | |||
| notImplemented("Triangle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawTriangle<T>(pos1, pos2, pos3, true); | |||
| #else | |||
| notImplemented("Triangle::drawOutline"); | |||
| #endif | |||
| } | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| template class Triangle<int>; | |||
| template class Triangle<uint>; | |||
| template class Triangle<short>; | |||
| template class Triangle<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| // Rectangle | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| template<typename T> | |||
| static void drawRectangle(const Rectangle<T>& rect, const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),); | |||
| glBegin(outline ? GL_LINE_LOOP : GL_QUADS); | |||
| { | |||
| const T x = rect.getX(); | |||
| const T y = rect.getY(); | |||
| const T w = rect.getWidth(); | |||
| const T h = rect.getHeight(); | |||
| glTexCoord2f(0.0f, 0.0f); | |||
| glVertex2d(x, y); | |||
| glTexCoord2f(1.0f, 0.0f); | |||
| glVertex2d(x+w, y); | |||
| glTexCoord2f(1.0f, 1.0f); | |||
| glVertex2d(x+w, y+h); | |||
| glTexCoord2f(0.0f, 1.0f); | |||
| glVertex2d(x, y+h); | |||
| } | |||
| glEnd(); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| void Rectangle<T>::draw(const GraphicsContext&) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawRectangle<T>(*this, false); | |||
| #else | |||
| notImplemented("Rectangle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawRectangle<T>(*this, true); | |||
| #else | |||
| notImplemented("Rectangle::drawOutline"); | |||
| #endif | |||
| } | |||
| // deprecated calls | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawRectangle<T>(*this, false); | |||
| #else | |||
| notImplemented("Rectangle::draw"); | |||
| #endif | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::drawOutline() | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| drawRectangle<T>(*this, true); | |||
| #else | |||
| notImplemented("Rectangle::drawOutline"); | |||
| #endif | |||
| } | |||
| template class Rectangle<double>; | |||
| template class Rectangle<float>; | |||
| template class Rectangle<int>; | |||
| template class Rectangle<uint>; | |||
| template class Rectangle<short>; | |||
| template class Rectangle<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // OpenGLImage | |||
| static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, textureId); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
| static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||
| static_cast<GLsizei>(image.getWidth()), | |||
| static_cast<GLsizei>(image.getHeight()), | |||
| 0, | |||
| asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData()); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled) | |||
| { | |||
| if (textureId == 0 || image.isInvalid()) | |||
| return; | |||
| if (! setupCalled) | |||
| { | |||
| setupOpenGLImage(image, textureId); | |||
| setupCalled = true; | |||
| } | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
| #endif | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, textureId); | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| glBegin(GL_QUADS); | |||
| { | |||
| const int x = pos.getX(); | |||
| const int y = pos.getY(); | |||
| const int w = static_cast<int>(image.getWidth()); | |||
| const int h = static_cast<int>(image.getHeight()); | |||
| glTexCoord2f(0.0f, 0.0f); | |||
| glVertex2d(x, y); | |||
| glTexCoord2f(1.0f, 0.0f); | |||
| glVertex2d(x+w, y); | |||
| glTexCoord2f(1.0f, 1.0f); | |||
| glVertex2d(x+w, y+h); | |||
| glTexCoord2f(0.0f, 1.0f); | |||
| glVertex2d(x, y+h); | |||
| } | |||
| glEnd(); | |||
| #endif | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| OpenGLImage::OpenGLImage() | |||
| : ImageBase(), | |||
| setupCalled(false), | |||
| textureInit(false), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| } | |||
| @@ -446,6 +49,10 @@ OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, co | |||
| setupCalled(false), | |||
| textureInit(true), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| glGenTextures(1, &textureId); | |||
| DISTRHO_SAFE_ASSERT(textureId != 0); | |||
| @@ -456,6 +63,10 @@ OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const Ima | |||
| setupCalled(false), | |||
| textureInit(true), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| glGenTextures(1, &textureId); | |||
| DISTRHO_SAFE_ASSERT(textureId != 0); | |||
| @@ -466,6 +77,10 @@ OpenGLImage::OpenGLImage(const OpenGLImage& image) | |||
| setupCalled(false), | |||
| textureInit(true), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| glGenTextures(1, &textureId); | |||
| DISTRHO_SAFE_ASSERT(textureId != 0); | |||
| @@ -475,6 +90,10 @@ OpenGLImage::~OpenGLImage() | |||
| { | |||
| if (textureId != 0) | |||
| glDeleteTextures(1, &textureId); | |||
| #ifdef DGL_USE_GLES | |||
| std::free(convertedData); | |||
| #endif | |||
| } | |||
| void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept | |||
| @@ -489,11 +108,6 @@ void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, c | |||
| ImageBase::loadFromMemory(rdata, s, fmt); | |||
| } | |||
| void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos) | |||
| { | |||
| drawOpenGLImage(*this, pos, textureId, setupCalled); | |||
| } | |||
| OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept | |||
| { | |||
| rawData = image.rawData; | |||
| @@ -511,12 +125,16 @@ OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept | |||
| return *this; | |||
| } | |||
| // deprecated calls | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt) | |||
| : ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)), | |||
| setupCalled(false), | |||
| textureInit(true), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| glGenTextures(1, &textureId); | |||
| DISTRHO_SAFE_ASSERT(textureId != 0); | |||
| @@ -527,155 +145,17 @@ OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLe | |||
| setupCalled(false), | |||
| textureInit(true), | |||
| textureId(0) | |||
| #ifdef DGL_USE_GLES | |||
| , convertedData(nullptr) | |||
| , rawDataLast(nullptr) | |||
| #endif | |||
| { | |||
| glGenTextures(1, &textureId); | |||
| DISTRHO_SAFE_ASSERT(textureId != 0); | |||
| } | |||
| void OpenGLImage::draw() | |||
| { | |||
| drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled); | |||
| } | |||
| void OpenGLImage::drawAt(const int x, const int y) | |||
| { | |||
| drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled); | |||
| } | |||
| void OpenGLImage::drawAt(const Point<int>& pos) | |||
| { | |||
| drawOpenGLImage(*this, pos, textureId, setupCalled); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // ImageBaseAboutWindow | |||
| #if 0 | |||
| template <> | |||
| void ImageBaseAboutWindow<OpenGLImage>::onDisplay() | |||
| { | |||
| const GraphicsContext& context(getGraphicsContext()); | |||
| img.draw(context); | |||
| } | |||
| #endif | |||
| template class ImageBaseAboutWindow<OpenGLImage>; | |||
| // ----------------------------------------------------------------------- | |||
| // ImageBaseButton | |||
| template class ImageBaseButton<OpenGLImage>; | |||
| // ----------------------------------------------------------------------- | |||
| // ImageBaseKnob | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::PrivateData::init() | |||
| { | |||
| glTextureId = 0; | |||
| glGenTextures(1, &glTextureId); | |||
| } | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup() | |||
| { | |||
| if (glTextureId == 0) | |||
| return; | |||
| glDeleteTextures(1, &glTextureId); | |||
| glTextureId = 0; | |||
| } | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::onDisplay() | |||
| { | |||
| const GraphicsContext& context(getGraphicsContext()); | |||
| const float normValue = getNormalizedValue(); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, pData->glTextureId); | |||
| if (! pData->isReady) | |||
| { | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
| static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| uint imageDataOffset = 0; | |||
| if (pData->rotationAngle == 0) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); | |||
| const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); | |||
| const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); | |||
| // TODO kImageFormatGreyscale | |||
| const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || | |||
| pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); | |||
| /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); | |||
| } | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||
| static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||
| asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset); | |||
| pData->isReady = true; | |||
| } | |||
| const int w = static_cast<int>(getWidth()); | |||
| const int h = static_cast<int>(getHeight()); | |||
| if (pData->rotationAngle != 0) | |||
| { | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| glPushMatrix(); | |||
| #endif | |||
| const int w2 = w/2; | |||
| const int h2 = h/2; | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||
| glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f); | |||
| #endif | |||
| Rectangle<int>(-w2, -h2, w, h).draw(context); | |||
| #ifdef DGL_USE_COMPAT_OPENGL | |||
| glPopMatrix(); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| Rectangle<int>(0, 0, w, h).draw(context); | |||
| } | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| template class ImageBaseKnob<OpenGLImage>; | |||
| // ----------------------------------------------------------------------- | |||
| // ImageBaseSlider | |||
| template class ImageBaseSlider<OpenGLImage>; | |||
| // ----------------------------------------------------------------------- | |||
| // ImageBaseSwitch | |||
| template class ImageBaseSwitch<OpenGLImage>; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||
| { | |||
| @@ -736,7 +216,7 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const | |||
| selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| void TopLevelWidget::PrivateData::display() | |||
| { | |||
| @@ -757,7 +237,7 @@ void TopLevelWidget::PrivateData::display() | |||
| selfw->pData->displaySubWidgets(width, height, window.pData->autoScaleFactor); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| void Window::PrivateData::renderToPicture(const char* const filename, | |||
| const GraphicsContext&, | |||
| @@ -787,13 +267,6 @@ void Window::PrivateData::renderToPicture(const char* const filename, | |||
| fclose(f); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
| { | |||
| return (const GraphicsContext&)graphicsContext; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -0,0 +1,570 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifdef _MSC_VER | |||
| // instantiated template classes whose methods are defined elsewhere | |||
| # pragma warning(disable:4661) | |||
| #endif | |||
| #include "../OpenGL.hpp" | |||
| #include "../Color.hpp" | |||
| #include "../ImageWidgets.hpp" | |||
| // #include "SubWidgetPrivateData.hpp" | |||
| // #include "TopLevelWidgetPrivateData.hpp" | |||
| // #include "WidgetPrivateData.hpp" | |||
| #include "WindowPrivateData.hpp" | |||
| // templated classes | |||
| #include "ImageBaseWidgets.cpp" | |||
| START_NAMESPACE_DGL | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Check for correct build config | |||
| #ifndef DGL_OPENGL | |||
| # error Build config error, OpenGL was NOT requested while building OpenGL2 code | |||
| #endif | |||
| #ifdef DGL_CAIRO | |||
| # error Build config error, Cairo requested while building OpenGL2 code | |||
| #endif | |||
| #ifdef DGL_VULKAN | |||
| # error Build config error, Vulkan requested while building OpenGL2 code | |||
| #endif | |||
| #ifdef DGL_USE_GLES2 | |||
| # error Build config error, GLESv2 requested while building OpenGL2 code | |||
| #endif | |||
| #ifdef DGL_USE_GLES3 | |||
| # error Build config error, GLESv3 requested while building OpenGL2 code | |||
| #endif | |||
| #ifdef DGL_USE_OPENGL3 | |||
| # error Build config error, OpenGL3 requested while building OpenGL2 code | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Color | |||
| void Color::setFor(const GraphicsContext&, const bool includeAlpha) | |||
| { | |||
| if (includeAlpha) | |||
| glColor4f(red, green, blue, alpha); | |||
| else | |||
| glColor3f(red, green, blue); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Line | |||
| template<typename T> | |||
| static void drawLine(const Point<T>& posStart, const Point<T>& posEnd) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); | |||
| glBegin(GL_LINES); | |||
| { | |||
| glVertex2d(posStart.getX(), posStart.getY()); | |||
| glVertex2d(posEnd.getX(), posEnd.getY()); | |||
| } | |||
| glEnd(); | |||
| } | |||
| template<typename T> | |||
| void Line<T>::draw(const GraphicsContext&, const T width) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(width != 0,); | |||
| glLineWidth(static_cast<GLfloat>(width)); | |||
| drawLine<T>(posStart, posEnd); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| drawLine<T>(posStart, posEnd); | |||
| } | |||
| #endif | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| template class Line<int>; | |||
| template class Line<uint>; | |||
| template class Line<short>; | |||
| template class Line<ushort>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Circle | |||
| template<typename T> | |||
| static void drawCircle(const Point<T>& pos, | |||
| const uint numSegments, | |||
| const float size, | |||
| const float sin, | |||
| const float cos, | |||
| const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); | |||
| const double origx = static_cast<double>(pos.getX()); | |||
| const double origy = static_cast<double>(pos.getY()); | |||
| double t; | |||
| double x = size; | |||
| double y = 0.0; | |||
| glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); | |||
| for (uint i = 0; i < numSegments; ++i) | |||
| { | |||
| glVertex2d(x + origx, y + origy); | |||
| t = x; | |||
| x = cos * x - sin * y; | |||
| y = sin * t + cos * y; | |||
| } | |||
| glEnd(); | |||
| } | |||
| template<typename T> | |||
| static void drawCircle(const GraphicsContext&, | |||
| const Point<T>& pos, | |||
| const uint numSegments, | |||
| const float size, | |||
| const float sin, | |||
| const float cos, | |||
| const bool outline) | |||
| { | |||
| drawCircle<T>(pos, numSegments, size, sin, cos, outline); | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::draw(const GraphicsContext& context) | |||
| { | |||
| drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, false); | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| drawCircle<T>(context, fPos, fNumSegments, fSize, fSin, fCos, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false); | |||
| } | |||
| template<typename T> | |||
| void Circle<T>::drawOutline() | |||
| { | |||
| drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true); | |||
| } | |||
| #endif | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| template class Circle<int>; | |||
| template class Circle<uint>; | |||
| template class Circle<short>; | |||
| template class Circle<ushort>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Triangle | |||
| template<typename T> | |||
| static void drawTriangle(const Point<T>& pos1, | |||
| const Point<T>& pos2, | |||
| const Point<T>& pos3, | |||
| const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); | |||
| glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); | |||
| { | |||
| glVertex2d(pos1.getX(), pos1.getY()); | |||
| glVertex2d(pos2.getX(), pos2.getY()); | |||
| glVertex2d(pos3.getX(), pos3.getY()); | |||
| } | |||
| glEnd(); | |||
| } | |||
| template<typename T> | |||
| static void drawTriangle(const GraphicsContext&, | |||
| const Point<T>& pos1, | |||
| const Point<T>& pos2, | |||
| const Point<T>& pos3, | |||
| const bool outline) | |||
| { | |||
| drawTriangle<T>(pos1, pos2, pos3, outline); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::draw(const GraphicsContext&) | |||
| { | |||
| drawTriangle<T>(pos1, pos2, pos3, false); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| drawTriangle<T>(pos1, pos2, pos3, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| drawTriangle<T>(pos1, pos2, pos3, false); | |||
| } | |||
| template<typename T> | |||
| void Triangle<T>::drawOutline() | |||
| { | |||
| drawTriangle<T>(pos1, pos2, pos3, true); | |||
| } | |||
| #endif | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| template class Triangle<int>; | |||
| template class Triangle<uint>; | |||
| template class Triangle<short>; | |||
| template class Triangle<ushort>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Rectangle | |||
| template<typename T> | |||
| static void drawRectangle(const Rectangle<T>& rect, const bool outline) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),); | |||
| glBegin(outline ? GL_LINE_LOOP : GL_QUADS); | |||
| { | |||
| const T x = rect.getX(); | |||
| const T y = rect.getY(); | |||
| const T w = rect.getWidth(); | |||
| const T h = rect.getHeight(); | |||
| glTexCoord2f(0.0f, 0.0f); | |||
| glVertex2d(x, y); | |||
| glTexCoord2f(1.0f, 0.0f); | |||
| glVertex2d(x+w, y); | |||
| glTexCoord2f(1.0f, 1.0f); | |||
| glVertex2d(x+w, y+h); | |||
| glTexCoord2f(0.0f, 1.0f); | |||
| glVertex2d(x, y+h); | |||
| } | |||
| glEnd(); | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::draw(const GraphicsContext& context) | |||
| { | |||
| drawRectangle<T>(*this, false); | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||
| glLineWidth(static_cast<GLfloat>(lineWidth)); | |||
| drawRectangle<T>(*this, true); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| drawRectangle<T>(*this, false); | |||
| } | |||
| template<typename T> | |||
| void Rectangle<T>::drawOutline() | |||
| { | |||
| drawRectangle<T>(*this, true); | |||
| } | |||
| #endif | |||
| template class Rectangle<double>; | |||
| template class Rectangle<float>; | |||
| template class Rectangle<int>; | |||
| template class Rectangle<uint>; | |||
| template class Rectangle<short>; | |||
| template class Rectangle<ushort>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // OpenGLImage | |||
| static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, textureId); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
| static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| glTexImage2D(GL_TEXTURE_2D, | |||
| 0, | |||
| GL_RGBA, | |||
| static_cast<GLsizei>(image.getWidth()), | |||
| static_cast<GLsizei>(image.getHeight()), | |||
| 0, | |||
| asOpenGLImageFormat(image.getFormat()), | |||
| GL_UNSIGNED_BYTE, | |||
| image.getRawData()); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled) | |||
| { | |||
| if (textureId == 0 || image.isInvalid()) | |||
| return; | |||
| if (! setupCalled) | |||
| { | |||
| setupOpenGLImage(image, textureId); | |||
| setupCalled = true; | |||
| } | |||
| glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, textureId); | |||
| glBegin(GL_QUADS); | |||
| { | |||
| const int x = pos.getX(); | |||
| const int y = pos.getY(); | |||
| const int w = static_cast<int>(image.getWidth()); | |||
| const int h = static_cast<int>(image.getHeight()); | |||
| glTexCoord2f(0.0f, 0.0f); | |||
| glVertex2d(x, y); | |||
| glTexCoord2f(1.0f, 0.0f); | |||
| glVertex2d(x+w, y); | |||
| glTexCoord2f(1.0f, 1.0f); | |||
| glVertex2d(x+w, y+h); | |||
| glTexCoord2f(0.0f, 1.0f); | |||
| glVertex2d(x, y+h); | |||
| } | |||
| glEnd(); | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos) | |||
| { | |||
| drawOpenGLImage(*this, pos, textureId, setupCalled); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| void OpenGLImage::draw() | |||
| { | |||
| drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled); | |||
| } | |||
| void OpenGLImage::drawAt(const int x, const int y) | |||
| { | |||
| drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled); | |||
| } | |||
| void OpenGLImage::drawAt(const Point<int>& pos) | |||
| { | |||
| drawOpenGLImage(*this, pos, textureId, setupCalled); | |||
| } | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // ImageBaseAboutWindow | |||
| #if 0 | |||
| template <> | |||
| void ImageBaseAboutWindow<OpenGLImage>::onDisplay() | |||
| { | |||
| const GraphicsContext& context(getGraphicsContext()); | |||
| img.draw(context); | |||
| } | |||
| #endif | |||
| template class ImageBaseAboutWindow<OpenGLImage>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // ImageBaseButton | |||
| template class ImageBaseButton<OpenGLImage>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // ImageBaseKnob | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::PrivateData::init() | |||
| { | |||
| glTextureId = 0; | |||
| glGenTextures(1, &glTextureId); | |||
| } | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup() | |||
| { | |||
| if (glTextureId == 0) | |||
| return; | |||
| glDeleteTextures(1, &glTextureId); | |||
| glTextureId = 0; | |||
| } | |||
| template <> | |||
| void ImageBaseKnob<OpenGLImage>::onDisplay() | |||
| { | |||
| const GraphicsContext& context(getGraphicsContext()); | |||
| const float normValue = getNormalizedValue(); | |||
| glEnable(GL_TEXTURE_2D); | |||
| glBindTexture(GL_TEXTURE_2D, pData->glTextureId); | |||
| if (! pData->isReady) | |||
| { | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
| static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
| glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
| glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
| glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
| uint imageDataOffset = 0; | |||
| if (pData->rotationAngle == 0) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); | |||
| const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); | |||
| const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); | |||
| // TODO kImageFormatGreyscale | |||
| const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || | |||
| pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); | |||
| /* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); | |||
| } | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||
| static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||
| asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset); | |||
| pData->isReady = true; | |||
| } | |||
| const int w = static_cast<int>(getWidth()); | |||
| const int h = static_cast<int>(getHeight()); | |||
| if (pData->rotationAngle != 0) | |||
| { | |||
| glPushMatrix(); | |||
| const int w2 = w/2; | |||
| const int h2 = h/2; | |||
| glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||
| glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f); | |||
| Rectangle<int>(-w2, -h2, w, h).draw(context); | |||
| glPopMatrix(); | |||
| } | |||
| else | |||
| { | |||
| Rectangle<int>(0, 0, w, h).draw(context); | |||
| } | |||
| glBindTexture(GL_TEXTURE_2D, 0); | |||
| glDisable(GL_TEXTURE_2D); | |||
| } | |||
| template class ImageBaseKnob<OpenGLImage>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // ImageBaseSlider | |||
| template class ImageBaseSlider<OpenGLImage>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // ImageBaseSwitch | |||
| template class ImageBaseSwitch<OpenGLImage>; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| void Window::PrivateData::createContextIfNeeded() | |||
| { | |||
| } | |||
| void Window::PrivateData::destroyContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::startContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::endContext() | |||
| { | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DGL | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -14,7 +14,14 @@ | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #include "Color.hpp" | |||
| #ifdef _MSC_VER | |||
| // instantiated template classes whose methods are defined elsewhere | |||
| # pragma warning(disable:4661) | |||
| #endif | |||
| #include "../Color.hpp" | |||
| #include "../ImageBaseWidgets.hpp" | |||
| #include "SubWidgetPrivateData.hpp" | |||
| #include "TopLevelWidgetPrivateData.hpp" | |||
| #include "WidgetPrivateData.hpp" | |||
| @@ -22,11 +29,33 @@ | |||
| START_NAMESPACE_DGL | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Check for correct build config | |||
| #ifdef DGL_CAIRO | |||
| # error Build config error, Cairo requested while building Stub code | |||
| #endif | |||
| #ifdef DGL_OPENGL | |||
| # error Build config error, OpenGL requested while building Stub code | |||
| #endif | |||
| #ifdef DGL_VULKAN | |||
| # error Build config error, Vulkan requested while building Stub code | |||
| #endif | |||
| #ifdef DGL_USE_GLES2 | |||
| # error Build config error, GLESv2 requested while building Stub code | |||
| #endif | |||
| #ifdef DGL_USE_GLES3 | |||
| # error Build config error, GLESv3 requested while building Stub code | |||
| #endif | |||
| #ifdef DGL_USE_OPENGL3 | |||
| # error Build config error, OpenGL3 requested while building Stub code | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static void notImplemented(const char* const name) | |||
| { | |||
| d_stderr2("stub function not implemented: %s", name); | |||
| d_stderr2("Stub function not implemented: %s", name); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -46,11 +75,13 @@ void Line<T>::draw(const GraphicsContext& context, T) | |||
| notImplemented("Line::draw"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| notImplemented("Line::draw"); | |||
| } | |||
| #endif | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| @@ -74,6 +105,7 @@ void Circle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Circle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| @@ -85,6 +117,7 @@ void Circle<T>::drawOutline() | |||
| { | |||
| notImplemented("Circle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| @@ -108,6 +141,7 @@ void Triangle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Triangle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| @@ -119,6 +153,7 @@ void Triangle<T>::drawOutline() | |||
| { | |||
| notImplemented("Triangle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| @@ -142,6 +177,7 @@ void Rectangle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Rectangle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| @@ -153,6 +189,7 @@ void Rectangle<T>::drawOutline() | |||
| { | |||
| notImplemented("Rectangle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Rectangle<double>; | |||
| template class Rectangle<float>; | |||
| @@ -182,10 +219,20 @@ void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, u | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
| void Window::PrivateData::createContextIfNeeded() | |||
| { | |||
| } | |||
| void Window::PrivateData::destroyContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::startContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::endContext() | |||
| { | |||
| GraphicsContext& context((GraphicsContext&)graphicsContext); | |||
| return context; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -14,8 +14,14 @@ | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifdef _MSC_VER | |||
| // instantiated template classes whose methods are defined elsewhere | |||
| # pragma warning(disable:4661) | |||
| #endif | |||
| #include "../Vulkan.hpp" | |||
| #include "../Color.hpp" | |||
| #include "../ImageBaseWidgets.hpp" | |||
| #include "SubWidgetPrivateData.hpp" | |||
| #include "TopLevelWidgetPrivateData.hpp" | |||
| @@ -24,14 +30,36 @@ | |||
| START_NAMESPACE_DGL | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Check for correct build config | |||
| #ifndef DGL_VULKAN | |||
| # error Build config error, Vulkan was NOT requested while building Vulkan code | |||
| #endif | |||
| #ifdef DGL_CAIRO | |||
| # error Build config error, Cairo requested while building Vulkan code | |||
| #endif | |||
| #ifdef DGL_OPENGL | |||
| # error Build config error, OpenGL requested while building Vulkan code | |||
| #endif | |||
| #ifdef DGL_USE_GLES2 | |||
| # error Build config error, GLESv2 requested while building Vulkan code | |||
| #endif | |||
| #ifdef DGL_USE_GLES3 | |||
| # error Build config error, GLESv3 requested while building Vulkan code | |||
| #endif | |||
| #ifdef DGL_USE_OPENGL3 | |||
| # error Build config error, OpenGL3 requested while building Vulkan code | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static void notImplemented(const char* const name) | |||
| { | |||
| d_stderr2("vulkan function not implemented: %s", name); | |||
| d_stderr2("Vulkan function not implemented: %s", name); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Color | |||
| void Color::setFor(const GraphicsContext&, bool) | |||
| @@ -48,11 +76,13 @@ void Line<T>::draw(const GraphicsContext&, T) | |||
| notImplemented("Line::draw"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Line<T>::draw() | |||
| { | |||
| notImplemented("Line::draw"); | |||
| } | |||
| #endif | |||
| template class Line<double>; | |||
| template class Line<float>; | |||
| @@ -76,6 +106,7 @@ void Circle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Circle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Circle<T>::draw() | |||
| { | |||
| @@ -87,6 +118,7 @@ void Circle<T>::drawOutline() | |||
| { | |||
| notImplemented("Circle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Circle<double>; | |||
| template class Circle<float>; | |||
| @@ -110,6 +142,7 @@ void Triangle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Triangle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Triangle<T>::draw() | |||
| { | |||
| @@ -121,6 +154,7 @@ void Triangle<T>::drawOutline() | |||
| { | |||
| notImplemented("Triangle::drawOutline"); | |||
| } | |||
| #endif | |||
| template class Triangle<double>; | |||
| template class Triangle<float>; | |||
| @@ -129,7 +163,6 @@ template class Triangle<uint>; | |||
| template class Triangle<short>; | |||
| template class Triangle<ushort>; | |||
| // ----------------------------------------------------------------------- | |||
| // Rectangle | |||
| @@ -145,11 +178,13 @@ void Rectangle<T>::drawOutline(const GraphicsContext&, T) | |||
| notImplemented("Rectangle::drawOutline"); | |||
| } | |||
| #ifdef DGL_ALLOW_DEPRECATED_METHODS | |||
| template<typename T> | |||
| void Rectangle<T>::draw() | |||
| { | |||
| notImplemented("Rectangle::draw"); | |||
| } | |||
| #endif | |||
| template<typename T> | |||
| void Rectangle<T>::drawOutline() | |||
| @@ -238,9 +273,20 @@ void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, u | |||
| // ----------------------------------------------------------------------- | |||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
| void Window::PrivateData::createContextIfNeeded() | |||
| { | |||
| } | |||
| void Window::PrivateData::destroyContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::startContext() | |||
| { | |||
| } | |||
| void Window::PrivateData::endContext() | |||
| { | |||
| return (const GraphicsContext&)graphicsContext; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -0,0 +1,23 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| // Include CHOC separately because it requires C++17 | |||
| #define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||
| #define WEB_VIEW_NAMESPACE DGL_NAMESPACE | |||
| #define WEB_VIEW_DGL_NAMESPACE | |||
| #include "../WebView.hpp" | |||
| #include "../../distrho/extra/WebViewWin32.hpp" | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -28,7 +28,11 @@ Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win) | |||
| : window(win), | |||
| ppData(nullptr), | |||
| active(window.pData->view != nullptr && puglBackendEnter(window.pData->view)), | |||
| reenter(false) {} | |||
| reenter(false) | |||
| { | |||
| if (active) | |||
| window.pData->createContextIfNeeded(); | |||
| } | |||
| Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transientWin) | |||
| : window(win), | |||
| @@ -40,6 +44,8 @@ Window::ScopedGraphicsContext::ScopedGraphicsContext(Window& win, Window& transi | |||
| { | |||
| puglBackendLeave(ppData->view); | |||
| active = puglBackendEnter(window.pData->view); | |||
| if (active) | |||
| window.pData->createContextIfNeeded(); | |||
| } | |||
| } | |||
| @@ -180,22 +186,22 @@ int Window::getOffsetX() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | |||
| return puglGetFrame(pData->view).x; | |||
| return puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION).x; | |||
| } | |||
| int Window::getOffsetY() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | |||
| return puglGetFrame(pData->view).y; | |||
| return puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION).y; | |||
| } | |||
| Point<int> Window::getOffset() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Point<int>()); | |||
| const PuglRect rect = puglGetFrame(pData->view); | |||
| return Point<int>(rect.x, rect.y); | |||
| const PuglPoint pos = puglGetPositionHint(pData->view, PUGL_CURRENT_POSITION); | |||
| return Point<int>(pos.x, pos.y); | |||
| } | |||
| void Window::setOffsetX(const int x) | |||
| @@ -214,7 +220,7 @@ void Window::setOffset(const int x, const int y) | |||
| DISTRHO_SAFE_ASSERT_RETURN(!pData->isEmbed,); | |||
| if (pData->view != nullptr) | |||
| puglSetPosition(pData->view, x, y); | |||
| puglSetPositionHint(pData->view, PUGL_CURRENT_POSITION, x, y); | |||
| } | |||
| void Window::setOffset(const Point<int>& offset) | |||
| @@ -226,29 +232,28 @@ uint Window::getWidth() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | |||
| const double width = puglGetFrame(pData->view).width; | |||
| DISTRHO_SAFE_ASSERT_RETURN(width > 0.0, 0); | |||
| return static_cast<uint>(width + 0.5); | |||
| const PuglSpan width = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE).width; | |||
| DISTRHO_SAFE_ASSERT(width > 0); | |||
| return width; | |||
| } | |||
| uint Window::getHeight() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, 0); | |||
| const double height = puglGetFrame(pData->view).height; | |||
| DISTRHO_SAFE_ASSERT_RETURN(height > 0.0, 0); | |||
| return static_cast<uint>(height + 0.5); | |||
| const PuglSpan height = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE).height; | |||
| DISTRHO_SAFE_ASSERT(height > 0); | |||
| return height; | |||
| } | |||
| Size<uint> Window::getSize() const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->view != nullptr, Size<uint>()); | |||
| const PuglRect rect = puglGetFrame(pData->view); | |||
| DISTRHO_SAFE_ASSERT_RETURN(rect.width > 0.0, Size<uint>()); | |||
| DISTRHO_SAFE_ASSERT_RETURN(rect.height > 0.0, Size<uint>()); | |||
| return Size<uint>(static_cast<uint>(rect.width + 0.5), | |||
| static_cast<uint>(rect.height + 0.5)); | |||
| const PuglArea size = puglGetSizeHint(pData->view, PUGL_CURRENT_SIZE); | |||
| DISTRHO_SAFE_ASSERT(size.width > 0); | |||
| DISTRHO_SAFE_ASSERT(size.height > 0); | |||
| return Size<uint>(size.width, size.height); | |||
| } | |||
| void Window::setWidth(const uint width) | |||
| @@ -421,6 +426,20 @@ bool Window::openFileBrowser(const FileBrowserOptions& options) | |||
| } | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| bool Window::createWebView(const char* const url, const DGL_NAMESPACE::WebViewOptions& options) | |||
| { | |||
| return pData->createWebView(url, options); | |||
| } | |||
| void Window::evaluateJS(const char* const js) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pData->webViewHandle != nullptr,); | |||
| webViewEvaluateJS(pData->webViewHandle, js); | |||
| } | |||
| #endif | |||
| void Window::repaint() noexcept | |||
| { | |||
| if (pData->view == nullptr) | |||
| @@ -429,7 +448,7 @@ void Window::repaint() noexcept | |||
| if (pData->usesScheduledRepaints) | |||
| pData->appData->needsRepaint = true; | |||
| puglPostRedisplay(pData->view); | |||
| puglObscureView(pData->view); | |||
| } | |||
| void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
| @@ -440,22 +459,22 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||
| if (pData->usesScheduledRepaints) | |||
| pData->appData->needsRepaint = true; | |||
| PuglRect prect = { | |||
| static_cast<PuglCoord>(rect.getX()), | |||
| static_cast<PuglCoord>(rect.getY()), | |||
| static_cast<PuglSpan>(rect.getWidth()), | |||
| static_cast<PuglSpan>(rect.getHeight()), | |||
| }; | |||
| int x = static_cast<int>(rect.getX()); | |||
| int y = static_cast<int>(rect.getY()); | |||
| uint width = rect.getWidth(); | |||
| uint height = rect.getHeight(); | |||
| if (pData->autoScaling) | |||
| { | |||
| const double autoScaleFactor = pData->autoScaleFactor; | |||
| prect.x = static_cast<PuglCoord>(prect.x * autoScaleFactor); | |||
| prect.y = static_cast<PuglCoord>(prect.y * autoScaleFactor); | |||
| prect.width = static_cast<PuglSpan>(prect.width * autoScaleFactor + 0.5); | |||
| prect.height = static_cast<PuglSpan>(prect.height * autoScaleFactor + 0.5); | |||
| x = d_roundToIntPositive(x * autoScaleFactor); | |||
| y = d_roundToIntPositive(y * autoScaleFactor); | |||
| width = d_roundToUnsignedInt(width * autoScaleFactor); | |||
| height = d_roundToUnsignedInt(height * autoScaleFactor); | |||
| } | |||
| puglPostRedisplayRect(pData->view, prect); | |||
| puglObscureRegion(pData->view, x, y, width, height); | |||
| } | |||
| void Window::renderToPicture(const char* const filename) | |||
| @@ -509,8 +528,8 @@ void Window::setGeometryConstraints(uint minimumWidth, | |||
| { | |||
| const Size<uint> size(getSize()); | |||
| setSize(static_cast<uint>(size.getWidth() * scaleFactor + 0.5), | |||
| static_cast<uint>(size.getHeight() * scaleFactor + 0.5)); | |||
| setSize(d_roundToUnsignedInt(size.getWidth() * scaleFactor), | |||
| d_roundToUnsignedInt(size.getHeight() * scaleFactor)); | |||
| } | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -40,13 +40,11 @@ START_NAMESPACE_DGL | |||
| #endif | |||
| #ifdef DGL_DEBUG_EVENTS | |||
| # define DGL_DBG(msg) std::fprintf(stderr, "%s", msg); | |||
| # define DGL_DBGp(...) std::fprintf(stderr, __VA_ARGS__); | |||
| # define DGL_DBGF std::fflush(stderr); | |||
| # define DGL_DBG(msg) d_stdout("%s", msg); | |||
| # define DGL_DBGp(...) d_stdout(__VA_ARGS__); | |||
| #else | |||
| # define DGL_DBG(msg) | |||
| # define DGL_DBGp(...) | |||
| # define DGL_DBGF | |||
| #endif | |||
| #define DEFAULT_WIDTH 640 | |||
| @@ -93,10 +91,10 @@ static PuglView* puglNewViewWithParentWindow(PuglWorld* const world, const uintp | |||
| if (PuglView* const view = puglNewView(world)) | |||
| { | |||
| puglSetParentWindow(view, parentWindowHandle); | |||
| puglSetParent(view, parentWindowHandle); | |||
| if (parentWindowHandle != 0) | |||
| puglSetPosition(view, 0, 0); | |||
| puglSetPositionHint(view, PUGL_DEFAULT_POSITION, 0, 0); | |||
| return view; | |||
| } | |||
| @@ -130,6 +128,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||
| filenameToRenderInto(nullptr), | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| fileBrowserHandle(nullptr), | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| webViewHandle(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| @@ -160,6 +161,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||
| filenameToRenderInto(nullptr), | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| fileBrowserHandle(nullptr), | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| webViewHandle(nullptr), | |||
| #endif | |||
| modal(ppData) | |||
| { | |||
| @@ -192,6 +196,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| filenameToRenderInto(nullptr), | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| fileBrowserHandle(nullptr), | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| webViewHandle(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| @@ -227,6 +234,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||
| filenameToRenderInto(nullptr), | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| fileBrowserHandle(nullptr), | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| webViewHandle(nullptr), | |||
| #endif | |||
| modal() | |||
| { | |||
| @@ -247,6 +257,10 @@ Window::PrivateData::~PrivateData() | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| if (fileBrowserHandle != nullptr) | |||
| fileBrowserClose(fileBrowserHandle); | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| if (webViewHandle != nullptr) | |||
| webViewDestroy(webViewHandle); | |||
| #endif | |||
| puglHide(view); | |||
| appData->oneWindowClosed(); | |||
| @@ -254,6 +268,9 @@ Window::PrivateData::~PrivateData() | |||
| isVisible = false; | |||
| } | |||
| #ifndef DPF_TEST_WINDOW_CPP | |||
| destroyContext(); | |||
| #endif | |||
| puglFreeView(view); | |||
| } | |||
| @@ -286,8 +303,8 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo | |||
| // PUGL_SAMPLES ?? | |||
| puglSetEventFunc(view, puglEventCallback); | |||
| // setting default size triggers system-level calls, do it last | |||
| puglSetSizeHint(view, PUGL_DEFAULT_SIZE, static_cast<PuglSpan>(width), static_cast<PuglSpan>(height)); | |||
| // setting size triggers system-level calls, do it last | |||
| puglSetSizeAndDefault(view, width, height); | |||
| } | |||
| bool Window::PrivateData::initPost() | |||
| @@ -352,10 +369,6 @@ void Window::PrivateData::show() | |||
| isClosed = false; | |||
| appData->oneWindowShown(); | |||
| // FIXME | |||
| // PuglRect rect = puglGetFrame(view); | |||
| // puglSetWindowSize(view, static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | |||
| #if defined(DISTRHO_OS_WINDOWS) | |||
| puglWin32ShowCentered(view); | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| @@ -394,13 +407,21 @@ void Window::PrivateData::hide() | |||
| if (modal.enabled) | |||
| stopModal(); | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| if (fileBrowserHandle != nullptr) | |||
| { | |||
| fileBrowserClose(fileBrowserHandle); | |||
| fileBrowserHandle = nullptr; | |||
| } | |||
| #endif | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| if (webViewHandle != nullptr) | |||
| { | |||
| webViewDestroy(webViewHandle); | |||
| webViewHandle = nullptr; | |||
| } | |||
| #endif | |||
| puglHide(view); | |||
| @@ -431,6 +452,13 @@ void Window::PrivateData::setResizable(const bool resizable) | |||
| puglSetResizable(view, resizable); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||
| { | |||
| return reinterpret_cast<const GraphicsContext&>(graphicsContext); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| void Window::PrivateData::idleCallback() | |||
| @@ -443,6 +471,11 @@ void Window::PrivateData::idleCallback() | |||
| fileBrowserHandle = nullptr; | |||
| } | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| if (webViewHandle != nullptr) | |||
| webViewIdle(webViewHandle); | |||
| #endif | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| @@ -479,7 +512,7 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| // ----------------------------------------------------------------------- | |||
| // file handling | |||
| // file browser dialog | |||
| bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||
| { | |||
| @@ -491,6 +524,8 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||
| if (options2.title == nullptr) | |||
| options2.title = puglGetViewString(view, PUGL_WINDOW_TITLE); | |||
| options2.className = puglGetViewString(view, PUGL_CLASS_NAME); | |||
| fileBrowserHandle = fileBrowserCreate(isEmbed, | |||
| puglGetNativeView(view), | |||
| autoScaling ? autoScaleFactor : scaleFactor, | |||
| @@ -500,12 +535,38 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||
| } | |||
| #endif // DGL_USE_FILE_BROWSER | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| // ----------------------------------------------------------------------- | |||
| // file browser dialog | |||
| bool Window::PrivateData::createWebView(const char* const url, const DGL_NAMESPACE::WebViewOptions& options) | |||
| { | |||
| if (webViewHandle != nullptr) | |||
| webViewDestroy(webViewHandle); | |||
| const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE); | |||
| uint initialWidth = size.width - options.offset.x; | |||
| uint initialHeight = size.height - options.offset.y; | |||
| webViewOffset = Point<int>(options.offset.x, options.offset.y); | |||
| webViewHandle = webViewCreate(url, | |||
| puglGetNativeView(view), | |||
| initialWidth, | |||
| initialHeight, | |||
| autoScaling ? autoScaleFactor : scaleFactor, | |||
| options); | |||
| return webViewHandle != nullptr; | |||
| } | |||
| #endif // DGL_USE_WEB_VIEW | |||
| // ----------------------------------------------------------------------- | |||
| // modal handling | |||
| void Window::PrivateData::startModal() | |||
| { | |||
| DGL_DBG("Window modal loop starting..."); DGL_DBGF; | |||
| DGL_DBG("Window modal loop starting..."); | |||
| DISTRHO_SAFE_ASSERT_RETURN(modal.parent != nullptr, show()); | |||
| // activate modal mode for this window | |||
| @@ -527,7 +588,7 @@ void Window::PrivateData::startModal() | |||
| void Window::PrivateData::stopModal() | |||
| { | |||
| DGL_DBG("Window modal loop stopping..."); DGL_DBGF; | |||
| DGL_DBG("Window modal loop stopping..."); | |||
| // deactivate modal mode | |||
| modal.enabled = false; | |||
| @@ -579,11 +640,15 @@ void Window::PrivateData::runAsModal(const bool blockWait) | |||
| // ----------------------------------------------------------------------- | |||
| // pugl events | |||
| void Window::PrivateData::onPuglConfigure(const double width, const double height) | |||
| void Window::PrivateData::onPuglConfigure(const uint width, const uint height) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_INT2_RETURN(width > 1 && height > 1, width, height,); | |||
| DGL_DBGp("PUGL: onReshape : %f %f\n", width, height); | |||
| DGL_DBGp("PUGL: onReshape : %d %d\n", width, height); | |||
| #ifndef DPF_TEST_WINDOW_CPP | |||
| createContextIfNeeded(); | |||
| #endif | |||
| if (autoScaling) | |||
| { | |||
| @@ -596,8 +661,16 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh | |||
| autoScaleFactor = 1.0; | |||
| } | |||
| const uint uwidth = static_cast<uint>(width / autoScaleFactor + 0.5); | |||
| const uint uheight = static_cast<uint>(height / autoScaleFactor + 0.5); | |||
| const uint uwidth = d_roundToUnsignedInt(width / autoScaleFactor); | |||
| const uint uheight = d_roundToUnsignedInt(height / autoScaleFactor); | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| if (webViewHandle != nullptr) | |||
| webViewResize(webViewHandle, | |||
| uwidth - webViewOffset.getX(), | |||
| uheight - webViewOffset.getY(), | |||
| autoScaling ? autoScaleFactor : scaleFactor); | |||
| #endif | |||
| self->onReshape(uwidth, uheight); | |||
| @@ -619,7 +692,7 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh | |||
| #endif | |||
| // always repaint after a resize | |||
| puglPostRedisplay(view); | |||
| puglObscureView(view); | |||
| } | |||
| void Window::PrivateData::onPuglExpose() | |||
| @@ -629,6 +702,8 @@ void Window::PrivateData::onPuglExpose() | |||
| puglOnDisplayPrepare(view); | |||
| #ifndef DPF_TEST_WINDOW_CPP | |||
| startContext(); | |||
| FOR_EACH_TOP_LEVEL_WIDGET(it) | |||
| { | |||
| TopLevelWidget* const widget(*it); | |||
| @@ -639,11 +714,13 @@ void Window::PrivateData::onPuglExpose() | |||
| if (char* const filename = filenameToRenderInto) | |||
| { | |||
| const PuglRect rect = puglGetFrame(view); | |||
| const PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE); | |||
| filenameToRenderInto = nullptr; | |||
| renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | |||
| renderToPicture(filename, getGraphicsContext(), size.width, size.height); | |||
| std::free(filename); | |||
| } | |||
| endContext(); | |||
| #endif | |||
| } | |||
| @@ -860,7 +937,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| { | |||
| Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); | |||
| #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | |||
| if (event->type != PUGL_TIMER) { | |||
| if (event->type != PUGL_TIMER && event->type != PUGL_EXPOSE && event->type != PUGL_MOTION) { | |||
| printEvent(event, "pugl event: ", true); | |||
| } | |||
| #endif | |||
| @@ -915,7 +992,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| SetClassLongPtr(view->impl->hwnd, GCLP_HICON, (LONG_PTR) LoadIcon(hInstance, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID))); | |||
| #endif | |||
| #ifdef DGL_USING_X11 | |||
| puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone); | |||
| puglX11SetWindowType(view, pData->appData->isStandalone); | |||
| #endif | |||
| } | |||
| break; | |||
| @@ -962,7 +1039,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| Widget::KeyboardEvent ev; | |||
| ev.mod = event->key.state; | |||
| ev.flags = event->key.flags; | |||
| ev.time = static_cast<uint>(event->key.time * 1000.0 + 0.5); | |||
| ev.time = d_roundToUnsignedInt(event->key.time * 1000.0); | |||
| ev.press = event->type == PUGL_KEY_PRESS; | |||
| ev.key = event->key.key; | |||
| ev.keycode = event->key.keycode; | |||
| @@ -985,7 +1062,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| Widget::CharacterInputEvent ev; | |||
| ev.mod = event->text.state; | |||
| ev.flags = event->text.flags; | |||
| ev.time = static_cast<uint>(event->text.time * 1000.0 + 0.5); | |||
| ev.time = d_roundToUnsignedInt(event->text.time * 1000.0); | |||
| ev.keycode = event->text.keycode; | |||
| ev.character = event->text.character; | |||
| std::strncpy(ev.string, event->text.string, sizeof(ev.string)); | |||
| @@ -1008,7 +1085,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| Widget::MouseEvent ev; | |||
| ev.mod = event->button.state; | |||
| ev.flags = event->button.flags; | |||
| ev.time = static_cast<uint>(event->button.time * 1000.0 + 0.5); | |||
| ev.time = d_roundToUnsignedInt(event->button.time * 1000.0); | |||
| ev.button = event->button.button + 1; | |||
| ev.press = event->type == PUGL_BUTTON_PRESS; | |||
| if (pData->autoScaling && 0) | |||
| @@ -1031,7 +1108,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| Widget::MotionEvent ev; | |||
| ev.mod = event->motion.state; | |||
| ev.flags = event->motion.flags; | |||
| ev.time = static_cast<uint>(event->motion.time * 1000.0 + 0.5); | |||
| ev.time = d_roundToUnsignedInt(event->motion.time * 1000.0); | |||
| if (pData->autoScaling && 0) | |||
| { | |||
| const double scaleFactor = pData->autoScaleFactor; | |||
| @@ -1052,7 +1129,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||
| Widget::ScrollEvent ev; | |||
| ev.mod = event->scroll.state; | |||
| ev.flags = event->scroll.flags; | |||
| ev.time = static_cast<uint>(event->scroll.time * 1000.0 + 0.5); | |||
| ev.time = d_roundToUnsignedInt(event->scroll.time * 1000.0); | |||
| if (pData->autoScaling && 0) | |||
| { | |||
| const double scaleFactor = pData->autoScaleFactor; | |||
| @@ -1119,7 +1196,7 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver | |||
| { | |||
| #define FFMT "%6.1f" | |||
| #define PFMT FFMT " " FFMT | |||
| #define PRINT(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) | |||
| #define PRINT(fmt, ...) d_stdout(fmt, __VA_ARGS__), 1 | |||
| switch (event->type) { | |||
| case PUGL_NOTHING: | |||
| @@ -1188,25 +1265,21 @@ static int printEvent(const PuglEvent* event, const char* prefix, const bool ver | |||
| if (verbose) { | |||
| switch (event->type) { | |||
| case PUGL_CREATE: | |||
| return fprintf(stderr, "%sCreate\n", prefix); | |||
| case PUGL_DESTROY: | |||
| return fprintf(stderr, "%sDestroy\n", prefix); | |||
| case PUGL_MAP: | |||
| return fprintf(stderr, "%sMap\n", prefix); | |||
| case PUGL_UNMAP: | |||
| return fprintf(stderr, "%sUnmap\n", prefix); | |||
| case PUGL_UPDATE: | |||
| return 0; // fprintf(stderr, "%sUpdate\n", prefix); | |||
| case PUGL_REALIZE: | |||
| return PRINT("%sRealize\n", prefix); | |||
| case PUGL_UNREALIZE: | |||
| return PRINT("%sUnrealize\n", prefix); | |||
| case PUGL_CONFIGURE: | |||
| return PRINT("%sConfigure " PFMT " " PFMT "\n", | |||
| return PRINT("%sConfigure %d %d %d %d\n", | |||
| prefix, | |||
| event->configure.x, | |||
| event->configure.y, | |||
| event->configure.width, | |||
| event->configure.height); | |||
| case PUGL_UPDATE: | |||
| return 0; // fprintf(stderr, "%sUpdate\n", prefix); | |||
| case PUGL_EXPOSE: | |||
| return PRINT("%sExpose " PFMT " " PFMT "\n", | |||
| return PRINT("%sExpose %d %d %d %d\n", | |||
| prefix, | |||
| event->expose.x, | |||
| event->expose.y, | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -45,7 +45,11 @@ struct Window::PrivateData : IdleCallback { | |||
| PuglView* view; | |||
| /** Reserved space for graphics context. */ | |||
| mutable uint8_t graphicsContext[sizeof(void*)]; | |||
| mutable uint8_t graphicsContext[sizeof(int) * 9]; | |||
| void createContextIfNeeded(); | |||
| void destroyContext(); | |||
| void startContext(); | |||
| void endContext(); | |||
| /** The top-level widgets associated with this Window. */ | |||
| std::list<TopLevelWidget*> topLevelWidgets; | |||
| @@ -95,6 +99,12 @@ struct Window::PrivateData : IdleCallback { | |||
| DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle; | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| /** Handle for web view operations. */ | |||
| DGL_NAMESPACE::WebViewHandle webViewHandle; | |||
| DGL_NAMESPACE::Point<int> webViewOffset; | |||
| #endif | |||
| /** Modal window setup. */ | |||
| struct Modal { | |||
| PrivateData* parent; // parent of this window (so we can become modal) | |||
| @@ -169,10 +179,15 @@ struct Window::PrivateData : IdleCallback { | |||
| bool removeIdleCallback(IdleCallback* callback); | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| // file handling | |||
| // file browser dialog | |||
| bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options); | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| // web view | |||
| bool createWebView(const char* url, const DGL_NAMESPACE::WebViewOptions& options); | |||
| #endif | |||
| static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | |||
| // modal handling | |||
| @@ -181,7 +196,7 @@ struct Window::PrivateData : IdleCallback { | |||
| void runAsModal(bool blockWait); | |||
| // pugl events | |||
| void onPuglConfigure(double width, double height); | |||
| void onPuglConfigure(uint width, uint height); | |||
| void onPuglExpose(); | |||
| void onPuglClose(); | |||
| void onPuglFocus(bool focus, CrossingMode mode); | |||
| @@ -173,7 +173,7 @@ struct GLNVGtexture { | |||
| int width, height; | |||
| int type; | |||
| int flags; | |||
| #if defined NANOVG_GLES2 | |||
| #if defined(NANOVG_GLES2) || defined(NANOVG_GLES3) | |||
| unsigned char* data; | |||
| #endif | |||
| }; | |||
| @@ -813,10 +813,10 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
| switch (type) | |||
| { | |||
| case NVG_TEXTURE_BGR: | |||
| #if NANOVG_GLES2 | |||
| // GLES2 cannot handle GL_BGR, do local conversion to GL_RGB | |||
| #if defined(NANOVG_GLES2) || defined(NANOVG_GLES3) | |||
| // GLES cannot handle GL_BGR, do local conversion to GL_RGB | |||
| tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 3 * w * h); | |||
| for (uint32_t i=0; i<w*h; ++i) | |||
| for (int i = 0; i < w * h; ++i) | |||
| { | |||
| tex->data[i*3+0] = data[i*3+2]; | |||
| tex->data[i*3+1] = data[i*3+1]; | |||
| @@ -829,34 +829,34 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||
| #endif | |||
| break; | |||
| case NVG_TEXTURE_BGRA: | |||
| #if NANOVG_GLES2 | |||
| // GLES2 cannot handle GL_BGRA, do local conversion to GL_RGBA | |||
| #if defined(NANOVG_GLES2) || defined(NANOVG_GLES3) | |||
| // GLES cannot handle GL_BGRA, do local conversion to GL_RGBA | |||
| tex->data = (uint8_t*)malloc(sizeof(uint8_t) * 4 * w * h); | |||
| for (uint32_t i=0; i<w*h; ++i) | |||
| for (int i = 0; i < w * h; ++i) | |||
| { | |||
| tex->data[i*3+0] = data[i*3+3]; | |||
| tex->data[i*3+1] = data[i*3+2]; | |||
| tex->data[i*3+2] = data[i*3+1]; | |||
| tex->data[i*3+3] = data[i*3+0]; | |||
| tex->data[i*4+0] = data[i*4+2]; | |||
| tex->data[i*4+1] = data[i*4+1]; | |||
| tex->data[i*4+2] = data[i*4+0]; | |||
| tex->data[i*4+3] = data[i*4+3]; | |||
| } | |||
| data = tex->data; | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | |||
| #else | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
| #endif | |||
| break; | |||
| case NVG_TEXTURE_RGB: | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| case NVG_TEXTURE_RGBA: | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| default: | |||
| #if defined(NANOVG_GLES2) || defined (NANOVG_GL2) | |||
| #if defined(NANOVG_GL2) || defined(NANOVG_GLES2) | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||
| #elif defined(NANOVG_GLES3) | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); | |||
| #else | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); | |||
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); | |||
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); | |||
| #endif | |||
| break; | |||
| @@ -960,19 +960,23 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w | |||
| switch (tex->type) | |||
| { | |||
| case NVG_TEXTURE_BGR: | |||
| #if !(defined(NANOVG_GLES2) || defined(NANOVG_GLES3)) | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGR, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| case NVG_TEXTURE_BGRA: | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| #endif | |||
| case NVG_TEXTURE_RGB: | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGB, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| case NVG_TEXTURE_BGRA: | |||
| #if !(defined(NANOVG_GLES2) || defined(NANOVG_GLES3)) | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| #endif | |||
| case NVG_TEXTURE_RGBA: | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); | |||
| break; | |||
| default: | |||
| #if defined(NANOVG_GLES2) || defined(NANOVG_GL2) | |||
| #if defined(NANOVG_GL2) || defined(NANOVG_GLES2) | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | |||
| #else | |||
| glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data); | |||
| @@ -1,10 +1,11 @@ | |||
| // Copyright 2012-2022 David Robillard <d@drobilla.net> | |||
| // Copyright 2021-2022 Filipe Coelho <falktx@falktx.com> | |||
| // Copyright 2021-2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: ISC | |||
| #include "wasm.h" | |||
| #include "../pugl-upstream/src/internal.h" | |||
| #include "../pugl-upstream/src/platform.h" | |||
| #include <stdio.h> | |||
| @@ -82,6 +83,73 @@ puglInitViewInternals(PuglWorld* const world) | |||
| return impl; | |||
| } | |||
| PuglStatus | |||
| puglApplySizeHint(PuglView* const view, const PuglSizeHint PUGL_UNUSED(hint)) | |||
| { | |||
| // No fine-grained updates, hints are always recalculated together | |||
| return puglUpdateSizeHints(view); | |||
| } | |||
| PuglStatus | |||
| puglUpdateSizeHints(PuglView* const view) | |||
| { | |||
| const char* const className = view->world->strings[PUGL_CLASS_NAME]; | |||
| if (!view->hints[PUGL_RESIZABLE]) { | |||
| PuglArea size = puglGetSizeHint(view, PUGL_CURRENT_SIZE); | |||
| if (!puglIsValidSize(size.width, size.height)) { | |||
| size = puglGetSizeHint(view, PUGL_DEFAULT_SIZE); | |||
| } | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| var width = parseInt($1 / window.devicePixelRatio); | |||
| var height = parseInt($2 / window.devicePixelRatio); | |||
| canvasWrapper.style.setProperty("min-width", width + 'px'); | |||
| canvasWrapper.style.setProperty("max-width", width + 'px'); | |||
| canvasWrapper.style.setProperty("min-height", height + 'px'); | |||
| canvasWrapper.style.setProperty("max-height", height + 'px'); | |||
| }, className, size.width, size.height); | |||
| } else { | |||
| const PuglArea minSize = view->sizeHints[PUGL_MIN_SIZE]; | |||
| if (puglIsValidArea(minSize)) { | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| canvasWrapper.style.setProperty("min-width", parseInt($1 / window.devicePixelRatio) + 'px'); | |||
| canvasWrapper.style.setProperty("min-height", parseInt($2 / window.devicePixelRatio) + 'px'); | |||
| }, className, minSize.width, minSize.height); | |||
| } else { | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| canvasWrapper.style.removeProperty("min-width"); | |||
| canvasWrapper.style.removeProperty("min-height"); | |||
| }, className); | |||
| } | |||
| const PuglArea maxSize = view->sizeHints[PUGL_MAX_SIZE]; | |||
| if (puglIsValidArea(maxSize)) { | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| canvasWrapper.style.setProperty("max-width", parseInt($1 / window.devicePixelRatio) + 'px'); | |||
| canvasWrapper.style.setProperty("max-height", parseInt($2 / window.devicePixelRatio) + 'px'); | |||
| }, className, maxSize.width, maxSize.height); | |||
| } else { | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| canvasWrapper.style.removeProperty("max-width"); | |||
| canvasWrapper.style.removeProperty("max-height"); | |||
| }, className); | |||
| } | |||
| /* TODO | |||
| const PuglArea minAspect = view->sizeHints[PUGL_MIN_ASPECT]; | |||
| const PuglArea maxAspect = view->sizeHints[PUGL_MAX_ASPECT]; | |||
| const PuglArea fixedAspect = view->sizeHints[PUGL_FIXED_ASPECT]; | |||
| */ | |||
| } | |||
| return PUGL_SUCCESS; | |||
| } | |||
| static PuglStatus | |||
| puglDispatchEventWithContext(PuglView* const view, const PuglEvent* event) | |||
| { | |||
| @@ -729,7 +797,8 @@ puglRealize(PuglView* const view) | |||
| const char* const className = view->world->strings[PUGL_CLASS_NAME]; | |||
| d_stdout("className is %s", className); | |||
| PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; | |||
| const PuglPoint defaultPos = view->positionHints[PUGL_DEFAULT_POSITION]; | |||
| const PuglArea defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE]; | |||
| if (!defaultSize.width || !defaultSize.height) { | |||
| return PUGL_BAD_CONFIGURATION; | |||
| } | |||
| @@ -747,8 +816,8 @@ puglRealize(PuglView* const view) | |||
| puglDispatchSimpleEvent(view, PUGL_REALIZE); | |||
| PuglEvent event = {{PUGL_CONFIGURE, 0}}; | |||
| event.configure.x = view->defaultX; | |||
| event.configure.y = view->defaultY; | |||
| event.configure.x = defaultPos.x; | |||
| event.configure.y = defaultPos.y; | |||
| event.configure.width = defaultSize.width; | |||
| event.configure.height = defaultSize.height; | |||
| puglDispatchEvent(view, &event); | |||
| @@ -760,6 +829,8 @@ puglRealize(PuglView* const view) | |||
| canvasWrapper.style.setProperty("--device-pixel-ratio", window.devicePixelRatio); | |||
| }, className); | |||
| puglUpdateSizeHints(view); | |||
| emscripten_set_canvas_element_size(className, defaultSize.width, defaultSize.height); | |||
| #ifndef PUGL_WASM_NO_KEYBOARD_INPUT | |||
| // emscripten_set_keypress_callback(className, view, false, puglKeyCallback); | |||
| @@ -794,7 +865,7 @@ puglShow(PuglView* const view, PuglShowCommand) | |||
| { | |||
| view->impl->visible = true; | |||
| view->impl->needsRepaint = true; | |||
| return puglPostRedisplay(view); | |||
| return puglObscureView(view); | |||
| } | |||
| PuglStatus | |||
| @@ -884,15 +955,23 @@ puglUpdate(PuglWorld* const world, const double timeout) | |||
| } | |||
| PuglStatus | |||
| puglPostRedisplay(PuglView* const view) | |||
| puglObscureView(PuglView* const view) | |||
| { | |||
| view->impl->needsRepaint = true; | |||
| return PUGL_SUCCESS; | |||
| } | |||
| PuglStatus | |||
| puglPostRedisplayRect(PuglView* const view, const PuglRect rect) | |||
| puglObscureRegion(PuglView* view, | |||
| const int x, | |||
| const int y, | |||
| const unsigned width, | |||
| const unsigned height) | |||
| { | |||
| if (!puglIsValidPosition(x, y) || !puglIsValidSize(width, height)) { | |||
| return PUGL_BAD_PARAMETER; | |||
| } | |||
| view->impl->needsRepaint = true; | |||
| return PUGL_FAILURE; | |||
| } | |||
| @@ -918,13 +997,13 @@ puglViewStringChanged(PuglView*, const PuglStringHint key, const char* const val | |||
| } | |||
| PuglStatus | |||
| puglSetSizeHint(PuglView* const view, | |||
| const PuglSizeHint hint, | |||
| const PuglSpan width, | |||
| const PuglSpan height) | |||
| puglSetWindowSize(PuglView* const view, const unsigned width, const unsigned height) | |||
| { | |||
| view->sizeHints[hint].width = width; | |||
| view->sizeHints[hint].height = height; | |||
| if (view->impl->created) { | |||
| const char* const className = view->world->strings[PUGL_CLASS_NAME]; | |||
| emscripten_set_canvas_element_size(className, width, height); | |||
| } | |||
| return PUGL_SUCCESS; | |||
| } | |||
| @@ -1152,24 +1231,3 @@ puglSetTransientParent(PuglView* const view, const PuglNativeView parent) | |||
| view->transientParent = parent; | |||
| return PUGL_FAILURE; | |||
| } | |||
| PuglStatus | |||
| puglSetPosition(PuglView* const view, const int x, const int y) | |||
| { | |||
| printf("TODO: %s %d\n", __func__, __LINE__); | |||
| if (x > INT16_MAX || y > INT16_MAX) { | |||
| return PUGL_BAD_PARAMETER; | |||
| } | |||
| if (!view->impl->created) { | |||
| // Set defaults to be used when realized | |||
| view->defaultX = x; | |||
| view->defaultY = y; | |||
| return PUGL_SUCCESS; | |||
| } | |||
| view->lastConfigure.x = (PuglCoord)x; | |||
| view->lastConfigure.y = (PuglCoord)y; | |||
| return puglPostRedisplay(view); | |||
| } | |||
| @@ -1 +1 @@ | |||
| Subproject commit 311dd39b15a1603da65769f5eb9cdea5d7e97e19 | |||
| Subproject commit 5e2621d714ddf1cb0f86e852f8ba5dffe04aa3a3 | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -110,16 +110,26 @@ | |||
| # endif | |||
| #endif | |||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||
| #ifdef DGL_USE_FILE_BROWSER | |||
| # define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||
| # define FILE_BROWSER_DIALOG_DGL_NAMESPACE | |||
| # define FILE_BROWSER_DIALOG_NAMESPACE DGL_NAMESPACE | |||
| # define DGL_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||
| START_NAMESPACE_DGL | |||
| # include "../../distrho/extra/FileBrowserDialogImpl.hpp" | |||
| END_NAMESPACE_DGL | |||
| # include "../../distrho/extra/FileBrowserDialogImpl.cpp" | |||
| #endif | |||
| #ifdef DGL_USE_WEB_VIEW | |||
| # define DGL_WEB_VIEW_HPP_INCLUDED | |||
| # define WEB_VIEW_NAMESPACE DGL_NAMESPACE | |||
| # define WEB_VIEW_DGL_NAMESPACE | |||
| START_NAMESPACE_DGL | |||
| # include "../../distrho/extra/WebViewImpl.hpp" | |||
| END_NAMESPACE_DGL | |||
| # include "../../distrho/extra/WebViewImpl.cpp" | |||
| #endif | |||
| #if defined(DGL_USING_X11) && defined(DGL_X11_WINDOW_ICON_NAME) | |||
| extern const ulong* DGL_X11_WINDOW_ICON_NAME; | |||
| #endif | |||
| @@ -240,21 +250,23 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view) | |||
| if (view->backend != nullptr) | |||
| { | |||
| #ifdef DGL_OPENGL | |||
| #if defined(DGL_USE_GLES2) | |||
| puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_ES_API); | |||
| puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE); | |||
| puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); | |||
| #elif defined(DGL_USE_GLES3) | |||
| puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_ES_API); | |||
| puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE); | |||
| puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); | |||
| #elif defined(DGL_USE_OPENGL3) | |||
| puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API); | |||
| puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_CORE_PROFILE); | |||
| puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 3); | |||
| #else | |||
| #elif defined(DGL_OPENGL) | |||
| puglSetViewHint(view, PUGL_CONTEXT_API, PUGL_OPENGL_API); | |||
| puglSetViewHint(view, PUGL_CONTEXT_PROFILE, PUGL_OPENGL_COMPATIBILITY_PROFILE); | |||
| puglSetViewHint(view, PUGL_CONTEXT_VERSION_MAJOR, 2); | |||
| #endif | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| @@ -267,19 +279,20 @@ void puglSetMatchingBackendForCurrentBuild(PuglView* const view) | |||
| void puglRaiseWindow(PuglView* const view) | |||
| { | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| if (NSWindow* const window = view->impl->window ? view->impl->window | |||
| : [view->impl->wrapperView window]) | |||
| [window orderFrontRegardless]; | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| // this does the same as puglShow(view, PUGL_SHOW_FORCE_RAISE) + puglShow(view, PUGL_SHOW_RAISE) | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| NSWindow* const window = [view->impl->wrapperView window]; | |||
| [window orderFrontRegardless]; | |||
| [window orderFront:view->impl->wrapperView]; | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| // nothing | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| SetForegroundWindow(view->impl->hwnd); | |||
| SetActiveWindow(view->impl->hwnd); | |||
| #elif defined(HAVE_X11) | |||
| #elif defined(HAVE_X11) | |||
| XRaiseWindow(view->world->impl->display, view->impl->win); | |||
| #endif | |||
| #endif | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -296,29 +309,31 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co | |||
| view->sizeHints[PUGL_FIXED_ASPECT].height = static_cast<PuglSpan>(height); | |||
| } | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| if (view->impl->window) | |||
| { | |||
| if (const PuglStatus status = updateSizeHint(view, PUGL_MIN_SIZE)) | |||
| return status; | |||
| if (const PuglStatus status = updateSizeHint(view, PUGL_FIXED_ASPECT)) | |||
| if (const PuglStatus status = puglUpdateSizeHints(view)) | |||
| return status; | |||
| } | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| const char* const className = view->world->strings[PUGL_CLASS_NAME]; | |||
| EM_ASM({ | |||
| var canvasWrapper = document.getElementById(UTF8ToString($0)).parentElement; | |||
| canvasWrapper.style.setProperty("min-width", parseInt($1 / window.devicePixelRatio) + 'px'); | |||
| canvasWrapper.style.setProperty("min-height", parseInt($2 / window.devicePixelRatio) + 'px'); | |||
| }, className, width, height); | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| // nothing | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| // nothing | |||
| #elif defined(HAVE_X11) | |||
| #elif defined(HAVE_X11) | |||
| if (view->impl->win) | |||
| { | |||
| if (const PuglStatus status = updateSizeHints(view)) | |||
| if (const PuglStatus status = puglUpdateSizeHints(view)) | |||
| return status; | |||
| XFlush(view->world->impl->display); | |||
| } | |||
| #endif | |||
| #endif | |||
| return PUGL_SUCCESS; | |||
| } | |||
| @@ -330,98 +345,79 @@ void puglSetResizable(PuglView* const view, const bool resizable) | |||
| { | |||
| puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE); | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| if (PuglWindow* const window = view->impl->window) | |||
| { | |||
| const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask) | |||
| | (resizable ? NSResizableWindowMask : 0x0); | |||
| | (resizable ? NSResizableWindowMask : 0); | |||
| [window setStyleMask:style]; | |||
| } | |||
| // FIXME use [view setAutoresizingMask:NSViewNotSizable] ? | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| // nothing | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| puglUpdateSizeHints(view); | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| if (const HWND hwnd = view->impl->hwnd) | |||
| { | |||
| const uint winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | (WS_SIZEBOX | WS_MAXIMIZEBOX) | |||
| : GetWindowLong(hwnd, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX); | |||
| SetWindowLong(hwnd, GWL_STYLE, winFlags); | |||
| } | |||
| #elif defined(HAVE_X11) | |||
| updateSizeHints(view); | |||
| #endif | |||
| #elif defined(HAVE_X11) | |||
| puglUpdateSizeHints(view); | |||
| #endif | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // set window size while also changing default | |||
| PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height) | |||
| PuglStatus puglSetSizeAndDefault(PuglView* const view, const uint width, const uint height) | |||
| { | |||
| if (width > INT16_MAX || height > INT16_MAX) | |||
| return PUGL_BAD_PARAMETER; | |||
| #ifdef DGL_USING_X11 | |||
| // workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118 | |||
| if (view->impl->win && !view->parent && !view->transientParent) | |||
| { | |||
| view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0; | |||
| } | |||
| else | |||
| #endif | |||
| // set default size first | |||
| { | |||
| view->sizeHints[PUGL_DEFAULT_SIZE].width = static_cast<PuglSpan>(width); | |||
| view->sizeHints[PUGL_DEFAULT_SIZE].height = static_cast<PuglSpan>(height); | |||
| } | |||
| view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_CURRENT_SIZE].width = width; | |||
| view->sizeHints[PUGL_DEFAULT_SIZE].height = view->sizeHints[PUGL_CURRENT_SIZE].height = height; | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| #if defined(DISTRHO_OS_HAIKU) | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| // matches upstream pugl | |||
| if (view->impl->wrapperView) | |||
| { | |||
| if (const PuglStatus status = puglSetSize(view, width, height)) | |||
| return status; | |||
| // nothing to do for PUGL_DEFAULT_SIZE hint | |||
| if (const PuglStatus status = puglSetWindowSize(view, width, height)) | |||
| return status; | |||
| } | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| d_stdout("className is %s", view->world->strings[PUGL_CLASS_NAME]); | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| if (const PuglStatus status = puglUpdateSizeHints(view)) | |||
| return status; | |||
| emscripten_set_canvas_element_size(view->world->strings[PUGL_CLASS_NAME], width, height); | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| // matches upstream pugl, except we re-enter context after resize | |||
| if (view->impl->hwnd) | |||
| { | |||
| if (const PuglStatus status = puglSetSize(view, width, height)) | |||
| return status; | |||
| // nothing to do for PUGL_DEFAULT_SIZE hint | |||
| if (const PuglStatus status = puglSetWindowSize(view, width, height)) | |||
| return status; | |||
| // make sure to return context back to ourselves | |||
| puglBackendEnter(view); | |||
| } | |||
| #elif defined(HAVE_X11) | |||
| #elif defined(HAVE_X11) | |||
| // matches upstream pugl, adds flush at the end | |||
| if (view->impl->win) | |||
| { | |||
| if (const PuglStatus status = puglSetSize(view, width, height)) | |||
| if (const PuglStatus status = puglUpdateSizeHints(view)) | |||
| return status; | |||
| // updateSizeHints will use last known size, which is not yet updated | |||
| const PuglSpan lastWidth = view->lastConfigure.width; | |||
| const PuglSpan lastHeight = view->lastConfigure.height; | |||
| view->lastConfigure.width = static_cast<PuglSpan>(width); | |||
| view->lastConfigure.height = static_cast<PuglSpan>(height); | |||
| updateSizeHints(view); | |||
| view->lastConfigure.width = lastWidth; | |||
| view->lastConfigure.height = lastHeight; | |||
| if (const PuglStatus status = puglSetWindowSize(view, width, height)) | |||
| return status; | |||
| // flush size changes | |||
| XFlush(view->world->impl->display); | |||
| } | |||
| #endif | |||
| #endif | |||
| return PUGL_SUCCESS; | |||
| } | |||
| @@ -445,11 +441,12 @@ void puglOnDisplayPrepare(PuglView*) | |||
| void puglFallbackOnResize(PuglView* const view, const uint width, const uint height) | |||
| { | |||
| #ifdef DGL_OPENGL | |||
| #if defined(DGL_USE_OPENGL3) | |||
| glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| #else | |||
| glEnable(GL_BLEND); | |||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
| #ifdef DGL_USE_OPENGL3 | |||
| glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||
| #else | |||
| glMatrixMode(GL_PROJECTION); | |||
| glLoadIdentity(); | |||
| glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0); | |||
| @@ -458,9 +455,10 @@ void puglFallbackOnResize(PuglView* const view, const uint width, const uint hei | |||
| glLoadIdentity(); | |||
| #endif | |||
| #else | |||
| return; | |||
| // unused | |||
| (void)view; | |||
| (void)width; | |||
| (void)height; | |||
| #endif | |||
| } | |||
| @@ -607,55 +605,64 @@ void puglWin32ShowCentered(PuglView* const view) | |||
| PuglStatus puglX11UpdateWithoutExposures(PuglWorld* const world) | |||
| { | |||
| const bool wasDispatchingEvents = world->impl->dispatchingEvents; | |||
| world->impl->dispatchingEvents = true; | |||
| const PuglWorldState startState = world->state; | |||
| world->state = PUGL_WORLD_UPDATING; | |||
| PuglStatus st = PUGL_SUCCESS; | |||
| const double startTime = puglGetTime(world); | |||
| const double endTime = startTime + 0.03; | |||
| const double endTime = startTime + 0.03; | |||
| for (double t = startTime; !st && t < endTime; t = puglGetTime(world)) | |||
| { | |||
| pollX11Socket(world, endTime - t); | |||
| st = dispatchX11Events(world); | |||
| if (!(st = pollX11Socket(world, endTime - t))) | |||
| st = dispatchX11Events(world); | |||
| } | |||
| world->impl->dispatchingEvents = wasDispatchingEvents; | |||
| world->state = startState; | |||
| return st; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // X11 specific, set dialog window type and pid hints | |||
| // X11 specific, set dialog window type | |||
| void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone) | |||
| void puglX11SetWindowType(const PuglView* const view, const bool isStandalone) | |||
| { | |||
| const PuglInternals* const impl = view->impl; | |||
| Display* const display = view->world->impl->display; | |||
| const pid_t pid = getpid(); | |||
| const Atom _nwp = XInternAtom(display, "_NET_WM_PID", False); | |||
| XChangeProperty(display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | |||
| #if defined(DGL_X11_WINDOW_ICON_NAME) && defined(DGL_X11_WINDOW_ICON_SIZE) | |||
| if (isStandalone) | |||
| { | |||
| const Atom _nwi = XInternAtom(display, "_NET_WM_ICON", False); | |||
| XChangeProperty(display, impl->win, _nwi, XA_CARDINAL, 32, PropModeReplace, | |||
| (const uchar*)DGL_X11_WINDOW_ICON_NAME, DGL_X11_WINDOW_ICON_SIZE); | |||
| const Atom NET_WM_ICON = XInternAtom(display, "_NET_WM_ICON", False); | |||
| XChangeProperty(display, | |||
| impl->win, | |||
| NET_WM_ICON, | |||
| XA_CARDINAL, | |||
| 32, | |||
| PropModeReplace, | |||
| reinterpret_cast<const uchar*>(DGL_X11_WINDOW_ICON_NAME), | |||
| DGL_X11_WINDOW_ICON_SIZE); | |||
| } | |||
| #endif | |||
| const Atom _wt = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); | |||
| const Atom NET_WM_WINDOW_TYPE = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); | |||
| Atom _wts[2]; | |||
| int numAtoms = 0; | |||
| Atom windowTypes[2]; | |||
| int numWindowTypes = 0; | |||
| if (! isStandalone) | |||
| _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); | |||
| _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False); | |||
| XChangeProperty(display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms); | |||
| windowTypes[numWindowTypes++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); | |||
| windowTypes[numWindowTypes++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False); | |||
| XChangeProperty(display, | |||
| impl->win, | |||
| NET_WM_WINDOW_TYPE, | |||
| XA_ATOM, | |||
| 32, | |||
| PropModeReplace, | |||
| reinterpret_cast<const uchar*>(&windowTypes), | |||
| numWindowTypes); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -121,8 +121,8 @@ void puglWin32ShowCentered(PuglView* view); | |||
| // X11 specific, update world without triggering exposure events | |||
| PuglStatus puglX11UpdateWithoutExposures(PuglWorld* world); | |||
| // X11 specific, set dialog window type and pid hints | |||
| void puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone); | |||
| // X11 specific, set dialog window type | |||
| void puglX11SetWindowType(const PuglView* view, bool isStandalone); | |||
| #endif | |||
| @@ -202,7 +202,7 @@ static constexpr const uint32_t kStateIsOnlyForUI = 0x20; | |||
| /** | |||
| Parameter designation.@n | |||
| Allows a parameter to be specially designated for a task, like bypass. | |||
| Allows a parameter to be specially designated for a task, like bypass and reset. | |||
| Each designation is unique, there must be only one parameter that uses it.@n | |||
| The use of designated parameters is completely optional. | |||
| @@ -214,13 +214,20 @@ enum ParameterDesignation { | |||
| /** | |||
| Null or unset designation. | |||
| */ | |||
| kParameterDesignationNull = 0, | |||
| kParameterDesignationNull, | |||
| /** | |||
| Bypass designation.@n | |||
| When on (> 0.5f), it means the plugin must run in a bypassed state. | |||
| */ | |||
| kParameterDesignationBypass = 1 | |||
| kParameterDesignationBypass, | |||
| /** | |||
| Reset designation.@n | |||
| When on (> 0.5f), it means the plugin should reset its internal processing state | |||
| (like filters, oscillators, envelopes, lfos, etc) and kill all voices. | |||
| */ | |||
| kParameterDesignationReset, | |||
| }; | |||
| /** | |||
| @@ -234,7 +241,12 @@ namespace ParameterDesignationSymbols { | |||
| static constexpr const char bypass[] = "dpf_bypass"; | |||
| /** | |||
| Bypass designation symbol, inverted for LV2 so it becomes "enabled". | |||
| Reset designation symbol. | |||
| */ | |||
| static constexpr const char reset[] = "dpf_reset"; | |||
| /** | |||
| LV2 bypass designation symbol, inverted for LV2 so it becomes "enabled". | |||
| */ | |||
| static constexpr const char bypass_lv2[] = "lv2_enabled"; | |||
| }; | |||
| @@ -728,6 +740,18 @@ struct Parameter { | |||
| ranges.min = 0.0f; | |||
| ranges.max = 1.0f; | |||
| break; | |||
| case kParameterDesignationReset: | |||
| hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger|kParameterIsTrigger; | |||
| name = "Reset"; | |||
| shortName = "Reset"; | |||
| symbol = ParameterDesignationSymbols::reset; | |||
| unit = ""; | |||
| midiCC = 0; | |||
| groupId = kPortGroupNone; | |||
| ranges.def = 0.0f; | |||
| ranges.min = 0.0f; | |||
| ranges.max = 1.0f; | |||
| break; | |||
| } | |||
| } | |||
| @@ -553,6 +553,12 @@ START_NAMESPACE_DISTRHO | |||
| */ | |||
| #define DISTRHO_PLUGIN_WANT_LATENCY 1 | |||
| /** | |||
| Whether the plugin wants MPE for MIDI input and/or output. | |||
| @note Only AU and CLAP formats implement this at the moment | |||
| */ | |||
| #define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 | |||
| /** | |||
| Whether the plugin wants MIDI input.@n | |||
| This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true. | |||
| @@ -863,6 +869,24 @@ START_NAMESPACE_DISTRHO | |||
| */ | |||
| #define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.effect" | |||
| /** | |||
| Plugin name abbreviation consisting of 2 or 3 characters in uppercase. | |||
| @note This macro is required when building plugins for the Darkglass Anagram unit. | |||
| */ | |||
| #define DISTRHO_PLUGIN_ABBREVIATION "DFX" | |||
| /** | |||
| Path to a in-bundle/local 200x200 PNG image file to be used as the plugin's block image asset when OFF. | |||
| @note This macro is required when building plugins for the Darkglass Anagram unit. | |||
| */ | |||
| #define DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_OFF "anagram-block-off.png" | |||
| /** | |||
| Path to a in-bundle/local 200x200 PNG image file to be used as the plugin's block image asset when ON. | |||
| @note This macro is required when building plugins for the Darkglass Anagram unit. | |||
| */ | |||
| #define DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_ON "anagram-block-on.png" | |||
| /** @} */ | |||
| /* ------------------------------------------------------------------------------------------------------------ | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -29,15 +29,14 @@ | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_LV2) | |||
| # include "src/DistrhoPluginLV2.cpp" | |||
| # include "src/DistrhoPluginLV2export.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_MAPI) | |||
| # include "src/DistrhoPluginMAPI.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST2) | |||
| # include "src/DistrhoPluginVST2.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | |||
| # include "src/DistrhoPluginVST3.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_EXPORT) | |||
| # include "src/DistrhoPluginExport.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) | |||
| DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); | |||
| DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); } | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_STATIC) | |||
| START_NAMESPACE_DISTRHO | |||
| Plugin* createStaticPlugin() { return createPlugin(); } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -39,13 +39,36 @@ const char* getBinaryFilename(); | |||
| /** | |||
| Get a string representation of the current plugin format we are building against.@n | |||
| This can be "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2" or "VST3".@n | |||
| This can be "AudioUnit", "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2", "VST3" or "CLAP".@n | |||
| This string is purely informational and must not be used to tweak plugin behaviour. | |||
| @note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT. | |||
| */ | |||
| const char* getPluginFormatName() noexcept; | |||
| /** | |||
| List of supported OS-specific directories to be used for getSpecialDir. | |||
| */ | |||
| enum SpecialDir { | |||
| /** The user "home" directory */ | |||
| kSpecialDirHome, | |||
| /** Directory intended to store persistent configuration data (in general) */ | |||
| kSpecialDirConfig, | |||
| /** Directory intended to store persistent configuration data for the current plugin */ | |||
| kSpecialDirConfigForPlugin, | |||
| /** Directory intended to store "documents" (in general) */ | |||
| kSpecialDirDocuments, | |||
| /** Directory intended to store "documents" for the current plugin */ | |||
| kSpecialDirDocumentsForPlugin, | |||
| }; | |||
| /** | |||
| Get an OS-specific directory.@n | |||
| Calling this function will ensure the dictory exists on the filesystem.@n | |||
| The returned path always includes a final OS separator. | |||
| */ | |||
| const char* getSpecialDir(SpecialDir dir); | |||
| /** | |||
| Get the path to where resources are stored within the plugin bundle.@n | |||
| Requires a valid plugin bundle path. | |||
| @@ -62,7 +85,13 @@ const char* getPluginFormatName() noexcept; | |||
| The other non-mentioned formats do not support bundles.@n | |||
| @note For CLAP and VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory | |||
| rather than only shipping with the binary (e.g. <myplugin.vst>/myplugin.dll) | |||
| rather than only shipping with the binary, like so: | |||
| @code | |||
| + myplugin.vst/ | |||
| - myplugin.dll | |||
| + resources/ | |||
| - image1.png | |||
| @endcode | |||
| */ | |||
| const char* getResourcePath(const char* bundlePath) noexcept; | |||
| @@ -106,10 +106,11 @@ public: | |||
| The following example code can be use to extract individual colors: | |||
| ``` | |||
| const int red = (bgColor >> 24) & 0xff; | |||
| const int green = (bgColor >> 16) & 0xff; | |||
| const int blue = (bgColor >> 8) & 0xff; | |||
| int red = (bgColor >> 24) & 0xff; | |||
| int green = (bgColor >> 16) & 0xff; | |||
| int blue = (bgColor >> 8) & 0xff; | |||
| ``` | |||
| @see Color::fromRGB | |||
| */ | |||
| uint getBackgroundColor() const noexcept; | |||
| @@ -119,10 +120,11 @@ public: | |||
| The following example code can be use to extract individual colors: | |||
| ``` | |||
| const int red = (fgColor >> 24) & 0xff; | |||
| const int green = (fgColor >> 16) & 0xff; | |||
| const int blue = (fgColor >> 8) & 0xff; | |||
| int red = (fgColor >> 24) & 0xff; | |||
| int green = (fgColor >> 16) & 0xff; | |||
| int blue = (fgColor >> 8) & 0xff; | |||
| ``` | |||
| @see Color::fromRGB | |||
| */ | |||
| uint getForegroundColor() const noexcept; | |||
| @@ -185,7 +187,8 @@ public: | |||
| #if DISTRHO_UI_FILE_BROWSER | |||
| /** | |||
| Open a file browser dialog with this window as transient parent.@n | |||
| A few options can be specified to setup the dialog. | |||
| A few options can be specified to setup the dialog.@n | |||
| The @a DISTRHO_NAMESPACE::FileBrowserOptions::className variable is automatically set in this call. | |||
| If a path is selected, onFileSelected() will be called with the user chosen path. | |||
| If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename. | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -36,7 +36,13 @@ | |||
| # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 0 | |||
| # include "src/DistrhoUIDSSI.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_LV2) | |||
| # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # if defined(DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT) | |||
| # if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # warning Using single/monolithic LV2 target while DISTRHO_PLUGIN_WANT_DIRECT_ACCESS is 0 | |||
| # endif | |||
| # else | |||
| # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # endif | |||
| # include "src/DistrhoUILV2.cpp" | |||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST2) | |||
| # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1 | |||
| @@ -66,11 +72,16 @@ | |||
| # endif | |||
| #endif | |||
| #if defined(DPF_USING_LD_LINUX_WEBVIEW) && !DISTRHO_IS_STANDALONE | |||
| #if defined(DISTRHO_UI_LINUX_WEBVIEW_START) && !DISTRHO_IS_STANDALONE | |||
| int main(int argc, char* argv[]) | |||
| { | |||
| return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | |||
| } | |||
| #elif defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW) && !DISTRHO_IS_STANDALONE | |||
| int main() | |||
| { | |||
| return 0; | |||
| } | |||
| #endif | |||
| #endif | |||
| @@ -22,6 +22,7 @@ | |||
| #if DISTRHO_UI_WEB_VIEW | |||
| # define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||
| # define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE | |||
| # include "extra/WebView.hpp" | |||
| # include "extra/WebViewWin32.hpp" | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -23,6 +23,13 @@ | |||
| # define __STDC_LIMIT_MACROS | |||
| #endif | |||
| #ifdef __WINE__ | |||
| # ifndef NOMINMAX | |||
| # define NOMINMAX | |||
| # endif | |||
| # include <winsock2.h> | |||
| #endif | |||
| #include <cstdarg> | |||
| #include <cstdio> | |||
| #include <cstdlib> | |||
| @@ -86,15 +86,15 @@ bool isBase64Char(const char c) | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static inline | |||
| std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string) | |||
| void d_getChunkFromBase64String_impl(std::vector<uint8_t>& vector, const char* const base64string) | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(base64string != nullptr, std::vector<uint8_t>()); | |||
| vector.clear(); | |||
| DISTRHO_SAFE_ASSERT_RETURN(base64string != nullptr,); | |||
| uint i=0, j=0; | |||
| uint charArray3[3], charArray4[4]; | |||
| std::vector<uint8_t> ret; | |||
| ret.reserve(std::strlen(base64string)*3/4 + 4); | |||
| vector.reserve(std::strlen(base64string)*3/4 + 4); | |||
| for (std::size_t l=0, len=std::strlen(base64string); l<len; ++l) | |||
| { | |||
| @@ -119,7 +119,7 @@ std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string) | |||
| charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
| for (i=0; i<3; ++i) | |||
| ret.push_back(static_cast<uint8_t>(charArray3[i])); | |||
| vector.push_back(static_cast<uint8_t>(charArray3[i])); | |||
| i = 0; | |||
| } | |||
| @@ -138,9 +138,15 @@ std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string) | |||
| charArray3[2] = ((charArray4[2] & 0x3) << 6) + charArray4[3]; | |||
| for (j=0; i>0 && j<i-1; j++) | |||
| ret.push_back(static_cast<uint8_t>(charArray3[j])); | |||
| vector.push_back(static_cast<uint8_t>(charArray3[j])); | |||
| } | |||
| } | |||
| static inline | |||
| std::vector<uint8_t> d_getChunkFromBase64String(const char* const base64string) | |||
| { | |||
| std::vector<uint8_t> ret; | |||
| d_getChunkFromBase64String_impl(ret, base64string); | |||
| return ret; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -30,21 +30,31 @@ | |||
| # include <sys/wait.h> | |||
| #endif | |||
| #if defined(DISTRHO_OS_LINUX) | |||
| # include <sys/prctl.h> | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| # include <dispatch/dispatch.h> | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| class ChildProcess | |||
| { | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| PROCESS_INFORMATION pinfo; | |||
| #else | |||
| pid_t pid; | |||
| #endif | |||
| #ifdef DISTRHO_OS_MAC | |||
| static void _proc_exit_handler(void*) { ::kill(::getpid(), SIGTERM); } | |||
| #endif | |||
| public: | |||
| ChildProcess() | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| : pinfo(CPP_AGGREGATE_INIT(PROCESS_INFORMATION){ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 }) | |||
| #else | |||
| : pid(-1) | |||
| @@ -57,13 +67,13 @@ public: | |||
| stop(); | |||
| } | |||
| #ifdef _WIN32 | |||
| bool start(const char* const args[], const WCHAR* const envp) | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| bool start(const char* const args[], const WCHAR* const envp = nullptr) | |||
| #else | |||
| bool start(const char* const args[], char* const* const envp = nullptr) | |||
| #endif | |||
| { | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| std::string cmd; | |||
| for (uint i = 0; args[i] != nullptr; ++i) | |||
| @@ -109,6 +119,19 @@ public: | |||
| { | |||
| // child process | |||
| case 0: | |||
| #if defined(DISTRHO_OS_LINUX) | |||
| ::prctl(PR_SET_PDEATHSIG, SIGTERM); | |||
| #elif defined(DISTRHO_OS_MAC) | |||
| if (const dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_PROC, | |||
| ::getppid(), | |||
| DISPATCH_PROC_EXIT, | |||
| nullptr)) | |||
| { | |||
| dispatch_source_set_event_handler_f(source, _proc_exit_handler); | |||
| dispatch_resume(source); | |||
| } | |||
| #endif | |||
| if (envp != nullptr) | |||
| execve(args[0], const_cast<char* const*>(args), envp); | |||
| else | |||
| @@ -133,7 +156,7 @@ public: | |||
| const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds; | |||
| bool sendTerminate = true; | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| if (pinfo.hProcess == INVALID_HANDLE_VALUE) | |||
| return; | |||
| @@ -234,7 +257,7 @@ public: | |||
| bool isRunning() | |||
| { | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| if (pinfo.hProcess == INVALID_HANDLE_VALUE) | |||
| return false; | |||
| @@ -267,7 +290,7 @@ public: | |||
| #endif | |||
| } | |||
| #ifndef _WIN32 | |||
| #ifndef DISTRHO_OS_WINDOWS | |||
| void signal(const int sig) | |||
| { | |||
| if (pid > 0) | |||
| @@ -277,7 +300,7 @@ public: | |||
| void terminate() | |||
| { | |||
| #ifdef _WIN32 | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| if (pinfo.hProcess != INVALID_HANDLE_VALUE) | |||
| TerminateProcess(pinfo.hProcess, 15); | |||
| #else | |||
| @@ -0,0 +1,114 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #ifndef DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED | |||
| #define DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED | |||
| #include "String.hpp" | |||
| #include <cstdio> | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| # include <stringapiset.h> | |||
| #else | |||
| # include <cerrno> | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // filesystem related calls | |||
| /* | |||
| * Wrapper around `fopen` call, needed on Windows because its C standard functions use ASCII instead of UTF-8. | |||
| */ | |||
| static inline | |||
| FILE* d_fopen(const char* const pathname, const char* const mode) | |||
| { | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| WCHAR lpathname[MAX_PATH]; | |||
| WCHAR lmode[4]; | |||
| if (MultiByteToWideChar(CP_UTF8, 0, pathname, -1, lpathname, ARRAY_SIZE(lpathname)) != 0 && | |||
| MultiByteToWideChar(CP_UTF8, 0, mode, -1, lmode, ARRAY_SIZE(lmode)) != 0) | |||
| return _wfopen(lpathname, lmode); | |||
| #endif | |||
| return fopen(pathname, mode); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // filesystem related classes | |||
| /** | |||
| Handy class to help write files in a safe way, which does: | |||
| - open pathname + ".tmp" instead of opening a file directly (so partial writes are safe) | |||
| - on close, flush data to disk and rename file to remove ".tmp" | |||
| To use it, create a local variable (on the stack) and call ok() or manually check @a fd variable. | |||
| @code | |||
| if (const SafeFileWriter file("/path/to/file.txt"); file.ok()) | |||
| file.write("Success!"); | |||
| @endcode | |||
| */ | |||
| struct SafeFileWriter | |||
| { | |||
| String filename; | |||
| FILE* const fd; | |||
| /** | |||
| Constructor, opening @a pathname + ".tmp" for writing. | |||
| */ | |||
| SafeFileWriter(const char* const pathname, const char* const mode = "w") | |||
| : filename(pathname), | |||
| fd(d_fopen(filename + ".tmp", mode)) | |||
| { | |||
| #ifndef DISTRHO_OS_WINDOWS | |||
| if (fd == nullptr) | |||
| d_stderr2("failed to open '%s' for writing: %s", pathname, std::strerror(errno)); | |||
| #endif | |||
| } | |||
| /** | |||
| Destructor, will flush file data contents, close and rename file. | |||
| */ | |||
| ~SafeFileWriter() | |||
| { | |||
| if (fd == nullptr) | |||
| return; | |||
| std::fflush(fd); | |||
| std::fclose(fd); | |||
| std::rename(filename + ".tmp", filename); | |||
| } | |||
| /** Check if the file was opened successfully. */ | |||
| inline bool ok() const noexcept | |||
| { | |||
| return fd != nullptr; | |||
| } | |||
| /** Wrapper around `fwrite`, purely for convenience. */ | |||
| inline size_t write(const void* const ptr, const size_t size, const size_t nmemb = 1) const | |||
| { | |||
| return std::fwrite(ptr, size, nmemb, fd); | |||
| } | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| #endif // DISTRHO_FILESYSTEM_UTILS_HPP_INCLUDED | |||
| @@ -537,7 +537,7 @@ public: | |||
| * Commit all previous write operations to the ringbuffer. | |||
| * If a write operation has previously failed, this will reset/invalidate the previous write attempts. | |||
| */ | |||
| bool commitWrite() noexcept | |||
| bool commitWrite(const char* const debugMsg = nullptr) noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false); | |||
| @@ -549,7 +549,11 @@ public: | |||
| } | |||
| // nothing to commit? | |||
| DISTRHO_SAFE_ASSERT_RETURN(buffer->head != buffer->wrtn, false); | |||
| if (debugMsg != nullptr) { | |||
| DISTRHO_CUSTOM_SAFE_ASSERT_RETURN(debugMsg, buffer->head != buffer->wrtn, false); | |||
| } else { | |||
| DISTRHO_SAFE_ASSERT_RETURN(buffer->head != buffer->wrtn, false); | |||
| } | |||
| // all ok | |||
| buffer->head = buffer->wrtn; | |||
| @@ -172,6 +172,11 @@ public: | |||
| /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ | |||
| ObjectType* operator->() const noexcept { return object; } | |||
| //============================================================================== | |||
| /** Removes the current object from this ScopedPointer and deletes it. | |||
| */ | |||
| void reset() noexcept { ObjectType* const o = object; object = nullptr; delete o; } | |||
| //============================================================================== | |||
| /** Removes the current object from this ScopedPointer without deleting it. | |||
| This will return the current object, and set the ScopedPointer to a null pointer. | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -22,6 +22,10 @@ | |||
| #include <algorithm> | |||
| #if __cplusplus >= 201703L | |||
| # include <string_view> | |||
| #endif | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| @@ -49,10 +53,7 @@ public: | |||
| fBufferLen(0), | |||
| fBufferAlloc(false) | |||
| { | |||
| char ch[2]; | |||
| ch[0] = c; | |||
| ch[1] = '\0'; | |||
| const char ch[2] = { c, '\0' }; | |||
| _dup(ch); | |||
| } | |||
| @@ -87,6 +88,19 @@ public: | |||
| _dup(strBuf); | |||
| } | |||
| #if __cplusplus >= 201703L | |||
| /* | |||
| * std::string_view compatible variant. | |||
| */ | |||
| explicit String(const std::string_view& strView) noexcept | |||
| : fBuffer(_null()), | |||
| fBufferLen(0), | |||
| fBufferAlloc(false) | |||
| { | |||
| _dup(strView.data(), strView.size()); | |||
| } | |||
| #endif | |||
| /* | |||
| * Integer. | |||
| */ | |||
| @@ -255,7 +269,7 @@ public: | |||
| /* | |||
| * Get length of the string. | |||
| */ | |||
| std::size_t length() const noexcept | |||
| size_t length() const noexcept | |||
| { | |||
| return fBufferLen; | |||
| } | |||
| @@ -281,7 +295,7 @@ public: | |||
| */ | |||
| bool contains(const char c) const noexcept | |||
| { | |||
| for (std::size_t i=0; i<fBufferLen; ++i) | |||
| for (size_t i=0; i<fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] == c) | |||
| return true; | |||
| @@ -320,7 +334,7 @@ public: | |||
| /* | |||
| * Check if character at 'pos' is a digit. | |||
| */ | |||
| bool isDigit(const std::size_t pos) const noexcept | |||
| bool isDigit(const size_t pos) const noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen, false); | |||
| @@ -344,7 +358,7 @@ public: | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(prefix != nullptr, false); | |||
| const std::size_t prefixLen(std::strlen(prefix)); | |||
| const size_t prefixLen(std::strlen(prefix)); | |||
| if (fBufferLen < prefixLen) | |||
| return false; | |||
| @@ -369,7 +383,7 @@ public: | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(suffix != nullptr, false); | |||
| const std::size_t suffixLen(std::strlen(suffix)); | |||
| const size_t suffixLen(std::strlen(suffix)); | |||
| if (fBufferLen < suffixLen) | |||
| return false; | |||
| @@ -381,7 +395,7 @@ public: | |||
| * Find the first occurrence of character 'c' in the string. | |||
| * Returns "length()" if the character is not found. | |||
| */ | |||
| std::size_t find(const char c, bool* const found = nullptr) const noexcept | |||
| size_t find(const char c, bool* const found = nullptr) const noexcept | |||
| { | |||
| if (fBufferLen == 0 || c == '\0') | |||
| { | |||
| @@ -390,7 +404,7 @@ public: | |||
| return fBufferLen; | |||
| } | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] == c) | |||
| { | |||
| @@ -409,7 +423,7 @@ public: | |||
| * Find the first occurrence of string 'strBuf' in the string. | |||
| * Returns "length()" if the string is not found. | |||
| */ | |||
| std::size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
| size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
| { | |||
| if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0') | |||
| { | |||
| @@ -434,7 +448,7 @@ public: | |||
| if (found != nullptr) | |||
| *found = true; | |||
| return static_cast<std::size_t>(ret); | |||
| return static_cast<size_t>(ret); | |||
| } | |||
| if (found != nullptr) | |||
| @@ -446,7 +460,7 @@ public: | |||
| * Find the last occurrence of character 'c' in the string. | |||
| * Returns "length()" if the character is not found. | |||
| */ | |||
| std::size_t rfind(const char c, bool* const found = nullptr) const noexcept | |||
| size_t rfind(const char c, bool* const found = nullptr) const noexcept | |||
| { | |||
| if (fBufferLen == 0 || c == '\0') | |||
| { | |||
| @@ -455,7 +469,7 @@ public: | |||
| return fBufferLen; | |||
| } | |||
| for (std::size_t i=fBufferLen; i > 0; --i) | |||
| for (size_t i=fBufferLen; i > 0; --i) | |||
| { | |||
| if (fBuffer[i-1] == c) | |||
| { | |||
| @@ -474,7 +488,7 @@ public: | |||
| * Find the last occurrence of string 'strBuf' in the string. | |||
| * Returns "length()" if the string is not found. | |||
| */ | |||
| std::size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
| size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept | |||
| { | |||
| if (found != nullptr) | |||
| *found = false; | |||
| @@ -482,12 +496,12 @@ public: | |||
| if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0') | |||
| return fBufferLen; | |||
| const std::size_t strBufLen(std::strlen(strBuf)); | |||
| const size_t strBufLen(std::strlen(strBuf)); | |||
| std::size_t ret = fBufferLen; | |||
| size_t ret = fBufferLen; | |||
| const char* tmpBuf = fBuffer; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0) | |||
| { | |||
| @@ -518,7 +532,7 @@ public: | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(before != '\0' /* && after != '\0' */, *this); | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] == before) | |||
| fBuffer[i] = after; | |||
| @@ -537,7 +551,7 @@ public: | |||
| if (fBufferLen == 0) | |||
| return *this; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] == c) | |||
| { | |||
| @@ -553,7 +567,7 @@ public: | |||
| /* | |||
| * Truncate the string to size 'n'. | |||
| */ | |||
| String& truncate(const std::size_t n) noexcept | |||
| String& truncate(const size_t n) noexcept | |||
| { | |||
| if (n >= fBufferLen) | |||
| return *this; | |||
| @@ -569,7 +583,7 @@ public: | |||
| */ | |||
| String& toBasic() noexcept | |||
| { | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] >= '0' && fBuffer[i] <= '9') | |||
| continue; | |||
| @@ -593,7 +607,7 @@ public: | |||
| { | |||
| static constexpr const char kCharDiff = 'a' - 'A'; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z') | |||
| fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff); | |||
| @@ -609,7 +623,7 @@ public: | |||
| { | |||
| static constexpr const char kCharDiff = 'a' - 'A'; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z') | |||
| fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff); | |||
| @@ -674,31 +688,28 @@ public: | |||
| // base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html | |||
| // Copyright (C) 2004-2008 René Nyffenegger | |||
| static String asBase64(const void* const data, const std::size_t dataSize) | |||
| static String asBase64(const void* const data, const size_t dataSize) | |||
| { | |||
| static constexpr const char* const kBase64Chars = | |||
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
| "abcdefghijklmnopqrstuvwxyz" | |||
| "0123456789+/"; | |||
| #ifndef _MSC_VER | |||
| const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U); | |||
| #else | |||
| constexpr std::size_t kTmpBufSize = 65536U; | |||
| #endif | |||
| const size_t strBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U); | |||
| char* strBuf = static_cast<char*>(std::malloc(strBufSize)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(strBuf != nullptr, String()); | |||
| strBuf[strBufSize] = '\0'; | |||
| size_t strBufIndex = 0; | |||
| const uchar* bytesToEncode((const uchar*)data); | |||
| const uchar* bytesToEncode = static_cast<const uchar*>(data); | |||
| uint i=0, j=0; | |||
| uint charArray3[3], charArray4[4]; | |||
| char strBuf[kTmpBufSize + 1]; | |||
| strBuf[kTmpBufSize] = '\0'; | |||
| std::size_t strBufIndex = 0; | |||
| String ret; | |||
| for (std::size_t s=0; s<dataSize; ++s) | |||
| for (size_t s = 0; s < dataSize; ++s) | |||
| { | |||
| charArray3[i++] = *(bytesToEncode++); | |||
| @@ -709,10 +720,10 @@ public: | |||
| charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); | |||
| charArray4[3] = charArray3[2] & 0x3f; | |||
| for (i=0; i<4; ++i) | |||
| for (i = 0; i < 4; ++i) | |||
| strBuf[strBufIndex++] = kBase64Chars[charArray4[i]]; | |||
| if (strBufIndex >= kTmpBufSize-7) | |||
| if (strBufIndex >= strBufSize - 7) | |||
| { | |||
| strBuf[strBufIndex] = '\0'; | |||
| strBufIndex = 0; | |||
| @@ -725,7 +736,7 @@ public: | |||
| if (i != 0) | |||
| { | |||
| for (j=i; j<3; ++j) | |||
| for (j = i; j < 3; ++j) | |||
| charArray3[j] = '\0'; | |||
| charArray4[0] = (charArray3[0] & 0xfc) >> 2; | |||
| @@ -733,7 +744,7 @@ public: | |||
| charArray4[2] = ((charArray3[1] & 0x0f) << 2) + ((charArray3[2] & 0xc0) >> 6); | |||
| charArray4[3] = charArray3[2] & 0x3f; | |||
| for (j=0; j<4 && i<3 && j<i+1; ++j) | |||
| for (j = 0; j < 4 && i < 3 && j < i + 1; ++j) | |||
| strBuf[strBufIndex++] = kBase64Chars[charArray4[j]]; | |||
| for (; i++ < 3;) | |||
| @@ -746,6 +757,7 @@ public: | |||
| ret += strBuf; | |||
| } | |||
| std::free(strBuf); | |||
| return ret; | |||
| } | |||
| @@ -764,7 +776,7 @@ public: | |||
| char* newbufptr = newbuf; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| const char c = fBuffer[i]; | |||
| @@ -887,7 +899,7 @@ public: | |||
| char* newbufptr = newbuf; | |||
| for (std::size_t i=0; i < fBufferLen; ++i) | |||
| for (size_t i=0; i < fBufferLen; ++i) | |||
| { | |||
| const char c = fBuffer[i]; | |||
| @@ -943,19 +955,16 @@ public: | |||
| return fBuffer; | |||
| } | |||
| char operator[](const std::size_t pos) const noexcept | |||
| char operator[](const size_t pos) const noexcept | |||
| { | |||
| if (pos < fBufferLen) | |||
| return fBuffer[pos]; | |||
| d_safe_assert("pos < fBufferLen", __FILE__, __LINE__); | |||
| static char fallback; | |||
| fallback = '\0'; | |||
| return fallback; | |||
| return '\0'; | |||
| } | |||
| char& operator[](const std::size_t pos) noexcept | |||
| char& operator[](const size_t pos) noexcept | |||
| { | |||
| if (pos < fBufferLen) | |||
| return fBuffer[pos]; | |||
| @@ -1006,7 +1015,7 @@ public: | |||
| if (strBuf == nullptr || strBuf[0] == '\0') | |||
| return *this; | |||
| const std::size_t strBufLen = std::strlen(strBuf); | |||
| const size_t strBufLen = std::strlen(strBuf); | |||
| // for empty strings, we can just take the appended string as our entire data | |||
| if (isEmpty()) | |||
| @@ -1016,13 +1025,14 @@ public: | |||
| } | |||
| // we have some data ourselves, reallocate to add the new stuff | |||
| char* const newBuf = static_cast<char*>(std::realloc(fBuffer, fBufferLen + strBufLen + 1)); | |||
| char* const newBuf = static_cast<char*>(std::realloc(fBufferAlloc ? fBuffer : nullptr, fBufferLen + strBufLen + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, *this); | |||
| std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1); | |||
| fBuffer = newBuf; | |||
| fBufferLen += strBufLen; | |||
| fBufferAlloc = true; | |||
| return *this; | |||
| } | |||
| @@ -1039,8 +1049,8 @@ public: | |||
| if (isEmpty()) | |||
| return String(strBuf); | |||
| const std::size_t strBufLen = std::strlen(strBuf); | |||
| const std::size_t newBufSize = fBufferLen + strBufLen; | |||
| const size_t strBufLen = std::strlen(strBuf); | |||
| const size_t newBufSize = fBufferLen + strBufLen; | |||
| char* const newBuf = static_cast<char*>(std::malloc(newBufSize + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||
| @@ -1065,7 +1075,7 @@ public: | |||
| private: | |||
| char* fBuffer; // the actual string buffer | |||
| std::size_t fBufferLen; // string length | |||
| size_t fBufferLen; // string length | |||
| bool fBufferAlloc; // wherever the buffer is allocated, not using _null() | |||
| /* | |||
| @@ -1086,7 +1096,7 @@ private: | |||
| * - Allocates string only if 'strBuf' is not null and new string contents are different | |||
| * - If 'strBuf' is null, 'size' must be 0 | |||
| */ | |||
| void _dup(const char* const strBuf, const std::size_t size = 0) noexcept | |||
| void _dup(const char* const strBuf, const size_t size = 0) noexcept | |||
| { | |||
| if (strBuf != nullptr) | |||
| { | |||
| @@ -1143,9 +1153,9 @@ String operator+(const String& strBefore, const char* const strBufAfter) noexcep | |||
| if (strBefore.isEmpty()) | |||
| return String(strBufAfter); | |||
| const std::size_t strBeforeLen = strBefore.length(); | |||
| const std::size_t strBufAfterLen = std::strlen(strBufAfter); | |||
| const std::size_t newBufSize = strBeforeLen + strBufAfterLen; | |||
| const size_t strBeforeLen = strBefore.length(); | |||
| const size_t strBufAfterLen = std::strlen(strBufAfter); | |||
| const size_t newBufSize = strBeforeLen + strBufAfterLen; | |||
| char* const newBuf = static_cast<char*>(malloc(newBufSize + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||
| @@ -1163,9 +1173,9 @@ String operator+(const char* const strBufBefore, const String& strAfter) noexcep | |||
| if (strBufBefore == nullptr || strBufBefore[0] == '\0') | |||
| return strAfter; | |||
| const std::size_t strBufBeforeLen = std::strlen(strBufBefore); | |||
| const std::size_t strAfterLen = strAfter.length(); | |||
| const std::size_t newBufSize = strBufBeforeLen + strAfterLen; | |||
| const size_t strBufBeforeLen = std::strlen(strBufBefore); | |||
| const size_t strAfterLen = strAfter.length(); | |||
| const size_t newBufSize = strBufBeforeLen + strAfterLen; | |||
| char* const newBuf = static_cast<char*>(malloc(newBufSize + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -99,14 +99,14 @@ | |||
| #define MACRO_NAME(a, b, c) MACRO_NAME2(a, b, c) | |||
| #define WEB_VIEW_DELEGATE_CLASS_NAME \ | |||
| MACRO_NAME(WebViewDelegate_, _, DISTRHO_NAMESPACE) | |||
| MACRO_NAME(WebViewDelegate_, _, WEB_VIEW_NAMESPACE) | |||
| @interface WEB_VIEW_DELEGATE_CLASS_NAME : NSObject<WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate> | |||
| @end | |||
| @implementation WEB_VIEW_DELEGATE_CLASS_NAME { | |||
| @public | |||
| WebViewMessageCallback callback; | |||
| WEB_VIEW_NAMESPACE::WebViewMessageCallback callback; | |||
| void* callbackPtr; | |||
| bool loaded; | |||
| } | |||
| @@ -242,6 +242,11 @@ START_NAMESPACE_DISTRHO | |||
| #if WEB_VIEW_USING_X11_IPC | |||
| #ifdef WEB_VIEW_DGL_NAMESPACE | |||
| using DISTRHO_NAMESPACE::ChildProcess; | |||
| using DISTRHO_NAMESPACE::RingBufferControl; | |||
| #endif | |||
| #ifdef __linux__ | |||
| typedef int32_t ipc_sem_t; | |||
| #else | |||
| @@ -773,8 +778,10 @@ void webViewIdle(const WebViewHandle handle) | |||
| d_stderr("server ringbuffer data race, abort!"); | |||
| handle->rbctrl2.flush(); | |||
| return; | |||
| break; | |||
| } | |||
| std::free(buffer); | |||
| #else | |||
| // unused | |||
| (void)handle; | |||
| @@ -941,7 +948,7 @@ struct QSize { | |||
| S NAME = reinterpret_cast<S>(dlsym(nullptr, #SN)); \ | |||
| DISTRHO_SAFE_ASSERT_RETURN(NAME != nullptr, false); | |||
| static void web_wake_idle(void* const ptr) | |||
| static int web_wake_idle(void* const ptr) | |||
| { | |||
| WebViewRingBuffer* const shmptr = static_cast<WebViewRingBuffer*>(ptr); | |||
| @@ -989,6 +996,7 @@ static void web_wake_idle(void* const ptr) | |||
| } | |||
| free(buffer); | |||
| return 0; | |||
| } | |||
| // ----------------------------------------------------------------------------------------------------------- | |||
| @@ -1039,7 +1047,9 @@ static bool gtk3(Display* const display, | |||
| { | |||
| void* lib; | |||
| if ((lib = dlopen("libwebkit2gtk-4.0.so.37", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
| (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) | |||
| (lib = dlopen("libwebkit2gtk-4.1.so.0", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
| (lib = dlopen("libwebkit2gtk-4.0.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr && | |||
| (lib = dlopen("libwebkit2gtk-4.1.so", RTLD_NOW|RTLD_GLOBAL)) == nullptr) | |||
| { | |||
| d_stdout("WebView gtk3 platform not available: %s", dlerror()); | |||
| return false; | |||
| @@ -1135,10 +1145,8 @@ static bool gtk3(Display* const display, | |||
| GtkWidget* const window = gtk_plug_new(winId); | |||
| DISTRHO_SAFE_ASSERT_RETURN(window != nullptr, false); | |||
| gtk_window_set_default_size(GTK_WINDOW(window), | |||
| (width - x) * scaleFactor, | |||
| (height - y) * scaleFactor); | |||
| gtk_window_move(GTK_WINDOW(window), x * scaleFactor, y * scaleFactor); | |||
| gtk_window_set_default_size(GTK_WINDOW(window), width, height); | |||
| gtk_window_move(GTK_WINDOW(window), x, y); | |||
| WebKitSettings* const settings = webkit_settings_new(); | |||
| DISTRHO_SAFE_ASSERT_RETURN(settings != nullptr, false); | |||
| @@ -1774,7 +1782,7 @@ static bool qtwebengine(const int qtVersion, | |||
| QWebEnginePage_setWebChannel(&page, &channel, 0); | |||
| QWebEngineView_move(&webview, QPoint(x, y)); | |||
| QWebEngineView_resize(&webview, QSize(static_cast<int>(width), static_cast<int>(height))); | |||
| QWebEngineView_resize(&webview, QSize(static_cast<int>(width / scaleFactor), static_cast<int>(height / scaleFactor))); | |||
| QWebEngineView_winId(&webview); | |||
| QWindow_setParent(QWebEngineView_windowHandle(&webview), QWindow_fromWinId(winId)); | |||
| @@ -2061,3 +2069,4 @@ END_NAMESPACE_DISTRHO | |||
| #undef WEB_VIEW_DISTRHO_NAMESPACE | |||
| #undef WEB_VIEW_DGL_NAMESPACE | |||
| #undef WEB_VIEW_NAMESPACE | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -18,7 +18,7 @@ | |||
| # error bad include | |||
| #endif | |||
| #if !defined(DGL_UI_USE_WEB_VIEW) && defined(DISTRHO_UI_WEB_VIEW) && DISTRHO_UI_WEB_VIEW == 0 | |||
| #if !defined(DGL_USE_WEB_VIEW) && defined(DISTRHO_UI_WEB_VIEW) && DISTRHO_UI_WEB_VIEW == 0 | |||
| # error To use WebViews in DPF plugins please set DISTRHO_UI_WEB_VIEW to 1 | |||
| #endif | |||
| @@ -125,3 +125,12 @@ void webViewReload(WebViewHandle webview); | |||
| void webViewResize(WebViewHandle webview, uint width, uint height, double scaleFactor); | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| /** | |||
| Helper class for usage in std::shared_ptr and std::unique_ptr. | |||
| */ | |||
| struct WebViewDestroy { | |||
| void operator()(WebViewHandle handle) { webViewDestroy(handle); } | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -26,24 +26,41 @@ START_NAMESPACE_DISTRHO | |||
| class WebView; | |||
| WebView* webview_choc_create(const WebViewOptions& opts); | |||
| END_NAMESPACE_DISTRHO | |||
| #ifdef WEB_VIEW_DGL_NAMESPACE | |||
| START_NAMESPACE_DGL | |||
| using DISTRHO_NAMESPACE::WebView; | |||
| #else | |||
| START_NAMESPACE_DISTRHO | |||
| #endif | |||
| WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts); | |||
| void webview_choc_destroy(WebView*); | |||
| void* webview_choc_handle(WebView*); | |||
| void webview_choc_eval(WebView*, const char* js); | |||
| void webview_choc_navigate(WebView*, const char* url); | |||
| #ifdef WEB_VIEW_DGL_NAMESPACE | |||
| END_NAMESPACE_DGL | |||
| #else | |||
| END_NAMESPACE_DISTRHO | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #ifdef DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||
| # define WC_ERR_INVALID_CHARS 0 | |||
| # define WC_ERR_INVALID_CHARS 0x80 | |||
| # include "choc/choc_WebView.h" | |||
| #ifdef WEB_VIEW_DGL_NAMESPACE | |||
| START_NAMESPACE_DGL | |||
| #else | |||
| START_NAMESPACE_DISTRHO | |||
| #endif | |||
| WebView* webview_choc_create(const WebViewOptions& opts) | |||
| WebView* webview_choc_create(const WEB_VIEW_NAMESPACE::WebViewOptions& opts) | |||
| { | |||
| WebView::Options wopts; | |||
| wopts.acceptsFirstMouseClick = true; | |||
| @@ -52,7 +69,7 @@ WebView* webview_choc_create(const WebViewOptions& opts) | |||
| std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts); | |||
| DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr); | |||
| if (const WebViewMessageCallback callback = opts.callback) | |||
| if (const WEB_VIEW_NAMESPACE::WebViewMessageCallback callback = opts.callback) | |||
| { | |||
| webview->addInitScript("function postMessage(m){window.chrome.webview.postMessage(m);}"); | |||
| @@ -94,7 +111,11 @@ void webview_choc_navigate(WebView* const webview, const char* const url) | |||
| webview->navigate(url); | |||
| } | |||
| #ifdef WEB_VIEW_DGL_NAMESPACE | |||
| END_NAMESPACE_DGL | |||
| #else | |||
| END_NAMESPACE_DISTRHO | |||
| #endif | |||
| #endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -202,7 +202,8 @@ static constexpr const uint32_t kType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_AU_TYP | |||
| static constexpr const uint32_t kSubType = d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)); | |||
| static constexpr const uint32_t kManufacturer = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)); | |||
| static constexpr const uint32_t kWantedAudioFormat = kAudioFormatFlagsNativeFloatPacked | |||
| static constexpr const uint32_t kWantedAudioFormat = 0 | |||
| | kAudioFormatFlagsNativeFloatPacked | |||
| | kAudioFormatFlagIsNonInterleaved; | |||
| @@ -263,7 +264,7 @@ bool isNumChannelsComboValid(const uint16_t numInputs, const uint16_t numOutputs | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| struct PropertyListener { | |||
| AudioUnitPropertyID prop; | |||
| AudioUnitPropertyID prop; | |||
| AudioUnitPropertyListenerProc proc; | |||
| void* userData; | |||
| }; | |||
| @@ -276,12 +277,28 @@ struct RenderListener { | |||
| typedef std::vector<PropertyListener> PropertyListeners; | |||
| typedef std::vector<RenderListener> RenderListeners; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| typedef struct { | |||
| UInt32 numPackets; | |||
| MIDIPacket packets[kMaxMidiEvents]; | |||
| } d_MIDIPacketList; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| // useful definitions | |||
| static constexpr const uint32_t kMIDIPacketNonDataSize = sizeof(MIDIPacket) | |||
| #if __cplusplus >= 201103L | |||
| - sizeof(MIDIPacket::data); | |||
| #else | |||
| - sizeof(static_cast<MIDIPacket*>(0)->data); | |||
| #endif | |||
| static constexpr const uint32_t kMIDIPacketListNonDataSize = sizeof(MIDIPacketList) | |||
| #if __cplusplus >= 201103L | |||
| - sizeof(MIDIPacketList::packet); | |||
| #else | |||
| - sizeof(static_cast<MIDIPacketList*>(0)->packet); | |||
| #endif | |||
| // size of data used for midi events | |||
| static constexpr const uint32_t kMIDIPacketListMaxDataSize = kMIDIPacketNonDataSize * kMaxMidiEvents | |||
| + sizeof(Byte) * MidiEvent::kDataSize * kMaxMidiEvents; | |||
| // size of midi list + data | |||
| static constexpr const uint32_t kMIDIPacketListSize = kMIDIPacketListNonDataSize + kMIDIPacketListMaxDataSize; | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -331,10 +348,14 @@ public: | |||
| fUsingRenderListeners(false), | |||
| fParameterCount(fPlugin.getParameterCount()), | |||
| fLastParameterValues(nullptr), | |||
| fBypassParameterIndex(UINT32_MAX) | |||
| fBypassParameterIndex(UINT32_MAX), | |||
| fResetParameterIndex(UINT32_MAX) | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| , fMidiEventCount(0) | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| , fMidiOutputDataOffset(0) | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| , fCurrentProgram(-1) | |||
| , fLastFactoryProgram(0) | |||
| @@ -345,7 +366,7 @@ public: | |||
| , fStateCount(fPlugin.getStateCount()) | |||
| #endif | |||
| { | |||
| if (fParameterCount != 0) | |||
| if (fParameterCount != 0) | |||
| { | |||
| fLastParameterValues = new float[fParameterCount]; | |||
| std::memset(fLastParameterValues, 0, sizeof(float) * fParameterCount); | |||
| @@ -354,8 +375,17 @@ public: | |||
| { | |||
| fLastParameterValues[i] = fPlugin.getParameterValue(i); | |||
| if (fPlugin.getParameterDesignation(i) == kParameterDesignationBypass) | |||
| switch (fPlugin.getParameterDesignation(i)) | |||
| { | |||
| case kParameterDesignationNull: | |||
| break; | |||
| case kParameterDesignationBypass: | |||
| fBypassParameterIndex = i; | |||
| break; | |||
| case kParameterDesignationReset: | |||
| fResetParameterIndex = i; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| @@ -370,8 +400,10 @@ public: | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| if ((fMidiOutputPackets = static_cast<MIDIPacketList*>(std::malloc(kMIDIPacketListSize))) != nullptr) | |||
| std::memset(fMidiOutputPackets, 0, kMIDIPacketListSize); | |||
| std::memset(&fMidiOutput, 0, sizeof(fMidiOutput)); | |||
| std::memset(&fMidiOutputPackets, 0, sizeof(fMidiOutputPackets)); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| @@ -428,6 +460,10 @@ public: | |||
| reallocAudioBufferList(false); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| std::free(fMidiOutputPackets); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| for (uint32_t i=0; i<fProgramCount; ++i) | |||
| CFRelease(fFactoryPresetsData[i].presetName); | |||
| @@ -451,7 +487,8 @@ public: | |||
| fMidiEventCount = 0; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| fMidiOutputPackets.numPackets = 0; | |||
| fMidiOutputDataOffset = 0; | |||
| fMidiOutputPackets->numPackets = 0; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| fTimePosition.clear(); | |||
| @@ -635,7 +672,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| outDataSize = sizeof(HostCallbackInfo); | |||
| outWritable = false; | |||
| outWritable = true; | |||
| return noErr; | |||
| #else | |||
| return kAudioUnitErr_InvalidProperty; | |||
| @@ -659,6 +696,17 @@ public: | |||
| outWritable = true; | |||
| return noErr; | |||
| case kAudioUnitProperty_SupportsMPE: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
| outDataSize = sizeof(UInt32); | |||
| outWritable = false; | |||
| return noErr; | |||
| #else | |||
| return kAudioUnitErr_InvalidProperty; | |||
| #endif | |||
| case kAudioUnitProperty_CocoaUI: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| @@ -708,7 +756,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| outDataSize = sizeof(uint16_t); | |||
| outWritable = false; | |||
| outWritable = true; | |||
| return noErr; | |||
| case 'DPFe': | |||
| @@ -739,7 +787,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| outDataSize = sizeof(uint32_t); | |||
| outWritable = false; | |||
| outWritable = true; | |||
| return noErr; | |||
| #endif | |||
| @@ -748,7 +796,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| outDataSize = sizeof(CFArrayRef); | |||
| outWritable = false; | |||
| outWritable = true; | |||
| return noErr; | |||
| case 'DPFs': | |||
| @@ -764,7 +812,7 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| outDataSize = sizeof(void*); | |||
| outWritable = false; | |||
| outWritable = true; | |||
| return noErr; | |||
| #endif | |||
| @@ -885,13 +933,13 @@ public: | |||
| case kAudioUnitProperty_FastDispatch: | |||
| switch (inElement) | |||
| { | |||
| case kAudioUnitGetParameterSelect: | |||
| case kAudioUnitGetParameterSelect: | |||
| *static_cast<AudioUnitGetParameterProc*>(outData) = FastDispatchGetParameter; | |||
| return noErr; | |||
| case kAudioUnitSetParameterSelect: | |||
| case kAudioUnitSetParameterSelect: | |||
| *static_cast<AudioUnitSetParameterProc*>(outData) = FastDispatchSetParameter; | |||
| return noErr; | |||
| case kAudioUnitRenderSelect: | |||
| case kAudioUnitRenderSelect: | |||
| *static_cast<AudioUnitRenderProc*>(outData) = FastDispatchRender; | |||
| return noErr; | |||
| } | |||
| @@ -1028,6 +1076,12 @@ public: | |||
| } | |||
| return noErr; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
| case kAudioUnitProperty_SupportsMPE: | |||
| *static_cast<UInt32*>(outData) = 1; | |||
| return noErr; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| case kAudioUnitProperty_CocoaUI: | |||
| { | |||
| @@ -1099,6 +1153,8 @@ public: | |||
| const CFStringRef keyRef = CFStringCreateWithCString(nullptr, | |||
| fPlugin.getStateKey(i), | |||
| kCFStringEncodingASCII); | |||
| DISTRHO_SAFE_ASSERT_CONTINUE(keyRef != nullptr); | |||
| CFArrayAppendValue(keysRef, keyRef); | |||
| CFRelease(keyRef); | |||
| } | |||
| @@ -1414,7 +1470,7 @@ public: | |||
| const float value = bypass ? 1.f : 0.f; | |||
| fLastParameterValues[fBypassParameterIndex] = value; | |||
| fPlugin.setParameterValue(fBypassParameterIndex, value); | |||
| notifyPropertyListeners(inProp, inScope, inElement); | |||
| notifyPropertyListeners(inProp, inScope, inElement); | |||
| } | |||
| } | |||
| return noErr; | |||
| @@ -1436,12 +1492,12 @@ public: | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| { | |||
| const UInt32 usableDataSize = std::min(inDataSize, static_cast<UInt32>(sizeof(HostCallbackInfo))); | |||
| const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0; | |||
| const bool changed = std::memcmp(&fHostCallbackInfo, inData, usableDataSize) != 0; | |||
| std::memcpy(&fHostCallbackInfo, inData, usableDataSize); | |||
| std::memcpy(&fHostCallbackInfo, inData, usableDataSize); | |||
| if (sizeof(HostCallbackInfo) > usableDataSize) | |||
| std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||
| std::memset(&fHostCallbackInfo + usableDataSize, 0, sizeof(HostCallbackInfo) - usableDataSize); | |||
| if (changed) | |||
| notifyPropertyListeners(inProp, inScope, inElement); | |||
| @@ -1568,7 +1624,7 @@ public: | |||
| AUEventListenerNotify(NULL, NULL, &event); | |||
| if (fBypassParameterIndex == inElement) | |||
| notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||
| notifyPropertyListeners(kAudioUnitProperty_BypassEffect, kAudioUnitScope_Global, 0); | |||
| } | |||
| return noErr; | |||
| @@ -1593,28 +1649,44 @@ public: | |||
| case 'DPFs': | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inScope == kAudioUnitScope_Global, inScope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFStringRef), inDataSize, kAudioUnitErr_InvalidPropertyValue); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inDataSize == sizeof(CFDictionaryRef), inDataSize, kAudioUnitErr_InvalidPropertyValue); | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement < fStateCount, inElement, kAudioUnitErr_InvalidElement); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(inElement == 0, inElement, kAudioUnitErr_InvalidElement); | |||
| { | |||
| const CFStringRef valueRef = *static_cast<const CFStringRef*>(inData); | |||
| const CFDictionaryRef dictRef = *static_cast<const CFDictionaryRef*>(inData); | |||
| DISTRHO_SAFE_ASSERT_RETURN(CFGetTypeID(dictRef) == CFDictionaryGetTypeID(), | |||
| kAudioUnitErr_InvalidPropertyValue); | |||
| DISTRHO_SAFE_ASSERT_RETURN(CFDictionaryGetCount(dictRef) == 1, kAudioUnitErr_InvalidPropertyValue); | |||
| CFStringRef keyRef = nullptr; | |||
| CFStringRef valueRef = nullptr; | |||
| CFDictionaryGetKeysAndValues(dictRef, | |||
| reinterpret_cast<const void**>(&keyRef), | |||
| reinterpret_cast<const void**>(&valueRef)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(keyRef != nullptr && CFGetTypeID(keyRef) == CFStringGetTypeID(), | |||
| kAudioUnitErr_InvalidPropertyValue); | |||
| DISTRHO_SAFE_ASSERT_RETURN(valueRef != nullptr && CFGetTypeID(valueRef) == CFStringGetTypeID(), | |||
| kAudioUnitErr_InvalidPropertyValue); | |||
| const CFIndex valueLen = CFStringGetLength(valueRef); | |||
| char* const value = static_cast<char*>(std::malloc(valueLen + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, kAudio_ParamError); | |||
| DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8), | |||
| const CFIndex keyRefLen = CFStringGetLength(keyRef); | |||
| char* key = static_cast<char*>(std::malloc(keyRefLen + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(keyRef, key, keyRefLen + 1, kCFStringEncodingASCII), | |||
| kAudioUnitErr_InvalidPropertyValue); | |||
| const String& key(fPlugin.getStateKey(inElement)); | |||
| const CFIndex valueRefLen = CFStringGetLength(valueRef); | |||
| char* value = static_cast<char*>(std::malloc(valueRefLen + 1)); | |||
| DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueRefLen + 1, kCFStringEncodingUTF8), | |||
| kAudioUnitErr_InvalidPropertyValue); | |||
| const String dkey(key); | |||
| // save this key as needed | |||
| if (fPlugin.wantStateKey(key)) | |||
| fStateMap[key] = value; | |||
| if (fPlugin.wantStateKey(dkey)) | |||
| fStateMap[dkey] = value; | |||
| fPlugin.setState(key, value); | |||
| fPlugin.setState(dkey, value); | |||
| std::free(key); | |||
| std::free(value); | |||
| } | |||
| return noErr; | |||
| @@ -1777,7 +1849,12 @@ public: | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global || scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope, kAudioUnitErr_InvalidScope); | |||
| DISTRHO_SAFE_ASSERT_UINT_RETURN(elem == 0, elem, kAudioUnitErr_InvalidElement); | |||
| if (fPlugin.isActive()) | |||
| if (fResetParameterIndex != UINT32_MAX) | |||
| { | |||
| fPlugin.setParameterValue(fResetParameterIndex, 1.f); | |||
| fPlugin.setParameterValue(fResetParameterIndex, 0.f); | |||
| } | |||
| else if (fPlugin.isActive()) | |||
| { | |||
| fPlugin.deactivate(); | |||
| fPlugin.activate(); | |||
| @@ -1787,7 +1864,8 @@ public: | |||
| fMidiEventCount = 0; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| fMidiOutputPackets.numPackets = 0; | |||
| fMidiOutputDataOffset = 0; | |||
| fMidiOutputPackets->numPackets = 0; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| fTimePosition.clear(); | |||
| @@ -2015,7 +2093,7 @@ public: | |||
| midiEvent.data[1] = inData1; | |||
| midiEvent.data[2] = inData2; | |||
| switch (inStatus) | |||
| switch (inStatus & 0xF0) | |||
| { | |||
| case 0x80: | |||
| case 0x90: | |||
| @@ -2057,6 +2135,8 @@ public: | |||
| break; | |||
| default: | |||
| // invalid | |||
| d_debug("auMIDIEvent received invalid event %u %u %u %u @ %u", | |||
| inStatus, inData1, inData2, inOffsetSampleFrame, fMidiEventCount); | |||
| return kAudioUnitErr_InvalidPropertyValue; | |||
| } | |||
| @@ -2133,6 +2213,7 @@ private: | |||
| const uint32_t fParameterCount; | |||
| float* fLastParameterValues; | |||
| uint32_t fBypassParameterIndex; | |||
| uint32_t fResetParameterIndex; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| uint32_t fMidiEventCount; | |||
| @@ -2141,8 +2222,9 @@ private: | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| uint32_t fMidiOutputDataOffset; | |||
| MIDIPacketList* fMidiOutputPackets; | |||
| AUMIDIOutputCallbackStruct fMidiOutput; | |||
| d_MIDIPacketList fMidiOutputPackets; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| @@ -2172,7 +2254,7 @@ private: | |||
| const PropertyListener& pl(*it); | |||
| if (pl.prop == prop) | |||
| pl.proc(pl.userData, fComponent, prop, scope, elem); | |||
| pl.proc(pl.userData, fComponent, prop, scope, elem); | |||
| } | |||
| } | |||
| @@ -2217,7 +2299,8 @@ private: | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| fMidiOutputPackets.numPackets = 0; | |||
| fMidiOutputDataOffset = 0; | |||
| fMidiOutputPackets->numPackets = 0; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| @@ -2294,12 +2377,11 @@ private: | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| if (fMidiOutputPackets.numPackets != 0 && fMidiOutput.midiOutputCallback != nullptr) | |||
| if (fMidiOutputPackets != nullptr && | |||
| fMidiOutputPackets->numPackets != 0 && | |||
| fMidiOutput.midiOutputCallback != nullptr) | |||
| { | |||
| fMidiOutput.midiOutputCallback(fMidiOutput.userData, | |||
| inTimeStamp, | |||
| 0, | |||
| reinterpret_cast<const ::MIDIPacketList*>(&fMidiOutputPackets)); | |||
| fMidiOutput.midiOutputCallback(fMidiOutput.userData, inTimeStamp, 0, fMidiOutputPackets); | |||
| } | |||
| #else | |||
| // unused | |||
| @@ -2497,12 +2579,12 @@ private: | |||
| CFStringRef keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII); | |||
| CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8); | |||
| if (CFDictionaryRef dictRef = CFDictionaryCreate(nullptr, | |||
| reinterpret_cast<const void**>(&keyRef), | |||
| reinterpret_cast<const void**>(&valueRef), | |||
| 1, | |||
| &kCFTypeDictionaryKeyCallBacks, | |||
| &kCFTypeDictionaryValueCallBacks)) | |||
| if (const CFDictionaryRef dictRef = CFDictionaryCreate(nullptr, | |||
| reinterpret_cast<const void**>(&keyRef), | |||
| reinterpret_cast<const void**>(&valueRef), | |||
| 1, | |||
| &kCFTypeDictionaryKeyCallBacks, | |||
| &kCFTypeDictionaryValueCallBacks)) | |||
| { | |||
| CFArrayAppendValue(statesRef, dictRef); | |||
| CFRelease(dictRef); | |||
| @@ -2716,17 +2798,21 @@ private: | |||
| bool writeMidi(const MidiEvent& midiEvent) | |||
| { | |||
| DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("MIDI output unsupported", fMidiOutput.midiOutputCallback != nullptr, false); | |||
| DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN("Out of memory", fMidiOutputPackets != nullptr, false); | |||
| if (midiEvent.size > sizeof(MIDIPacket::data)) | |||
| return true; | |||
| if (fMidiOutputPackets.numPackets == kMaxMidiEvents) | |||
| if (fMidiOutputDataOffset + kMIDIPacketNonDataSize + midiEvent.size >= kMIDIPacketListMaxDataSize) | |||
| return false; | |||
| const uint8_t* const midiData = midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data; | |||
| MIDIPacket& packet(fMidiOutputPackets.packets[fMidiOutputPackets.numPackets++]); | |||
| packet.timeStamp = midiEvent.frame; | |||
| packet.length = midiEvent.size; | |||
| std::memcpy(packet.data, midiData, midiEvent.size); | |||
| MIDIPacket* const packet = reinterpret_cast<MIDIPacket*>( | |||
| reinterpret_cast<uint8_t*>(fMidiOutputPackets->packet) + fMidiOutputDataOffset); | |||
| packet->timeStamp = midiEvent.frame; | |||
| packet->length = midiEvent.size; | |||
| std::memcpy(packet->data, midiData, midiEvent.size); | |||
| ++fMidiOutputPackets->numPackets; | |||
| fMidiOutputDataOffset += kMIDIPacketNonDataSize + midiEvent.size; | |||
| return true; | |||
| } | |||
| @@ -2793,7 +2879,7 @@ private: | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| struct AudioComponentPlugInInstance { | |||
| AudioComponentPlugInInterface acpi; | |||
| AudioComponentPlugInInterface acpi; | |||
| PluginAU* plugin; | |||
| AudioComponentPlugInInstance() noexcept | |||
| @@ -2802,9 +2888,9 @@ struct AudioComponentPlugInInstance { | |||
| { | |||
| std::memset(&acpi, 0, sizeof(acpi)); | |||
| acpi.Open = Open; | |||
| acpi.Close = Close; | |||
| acpi.Lookup = Lookup; | |||
| acpi.reserved = nullptr; | |||
| acpi.Close = Close; | |||
| acpi.Lookup = Lookup; | |||
| acpi.reserved = nullptr; | |||
| } | |||
| ~AudioComponentPlugInInstance() | |||
| @@ -2812,14 +2898,18 @@ struct AudioComponentPlugInInstance { | |||
| delete plugin; | |||
| } | |||
| static OSStatus Open(void* const self, const AudioUnit component) | |||
| static OSStatus Open(void* const self, const AudioUnit component) | |||
| { | |||
| d_debug("AudioComponentPlugInInstance::Open(%p)", self); | |||
| static_cast<AudioComponentPlugInInstance*>(self)->plugin = new PluginAU(component); | |||
| return noErr; | |||
| } | |||
| static OSStatus Close(void* const self) | |||
| static OSStatus Close(void* const self) | |||
| { | |||
| d_debug("AudioComponentPlugInInstance::Close(%p)", self); | |||
| delete static_cast<AudioComponentPlugInInstance*>(self); | |||
| return noErr; | |||
| } | |||
| @@ -2908,15 +2998,15 @@ struct AudioComponentPlugInInstance { | |||
| d_debug("AudioComponentPlugInInstance::GetPropertyInfo(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
| self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
| UInt32 dataSize = 0; | |||
| Boolean writable = false; | |||
| UInt32 dataSize = 0; | |||
| Boolean writable = false; | |||
| const OSStatus res = self->plugin->auGetPropertyInfo(inProp, inScope, inElement, dataSize, writable); | |||
| if (outDataSize != nullptr) | |||
| *outDataSize = dataSize; | |||
| if (outDataSize != nullptr) | |||
| *outDataSize = dataSize; | |||
| if (outWritable != nullptr) | |||
| *outWritable = writable; | |||
| if (outWritable != nullptr) | |||
| *outWritable = writable; | |||
| return res; | |||
| } | |||
| @@ -2928,8 +3018,16 @@ struct AudioComponentPlugInInstance { | |||
| void* const outData, | |||
| UInt32* const ioDataSize) | |||
| { | |||
| d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
| self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
| #ifdef DEBUG | |||
| switch (inProp) { | |||
| case kAudioUnitProperty_PresentPreset: | |||
| break; | |||
| default: | |||
| d_debug("AudioComponentPlugInInstance::GetProperty(%p, %d:%x:%s, %d:%s, %d, ...)", | |||
| self, inProp, inProp, AudioUnitPropertyID2Str(inProp), inScope, AudioUnitScope2Str(inScope), inElement); | |||
| break; | |||
| } | |||
| #endif | |||
| DISTRHO_SAFE_ASSERT_RETURN(ioDataSize != nullptr, kAudio_ParamError); | |||
| Boolean writable; | |||
| @@ -2952,24 +3050,24 @@ struct AudioComponentPlugInInstance { | |||
| if (res != noErr) | |||
| return res; | |||
| void* outBuffer; | |||
| void* outBuffer; | |||
| uint8_t* tmpBuffer; | |||
| if (inDataSize < outDataSize) | |||
| { | |||
| tmpBuffer = new uint8_t[outDataSize]; | |||
| outBuffer = tmpBuffer; | |||
| } | |||
| { | |||
| tmpBuffer = new uint8_t[outDataSize]; | |||
| outBuffer = tmpBuffer; | |||
| } | |||
| else | |||
| { | |||
| tmpBuffer = nullptr; | |||
| outBuffer = outData; | |||
| } | |||
| tmpBuffer = nullptr; | |||
| outBuffer = outData; | |||
| } | |||
| res = self->plugin->auGetProperty(inProp, inScope, inElement, outBuffer); | |||
| if (res != noErr) | |||
| if (res != noErr) | |||
| { | |||
| *ioDataSize = 0; | |||
| *ioDataSize = 0; | |||
| return res; | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -286,7 +286,7 @@ public: | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), scaleFactor); | |||
| fPlugin.getInstancePointer(), scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| *width = tmpUI.getWidth(); | |||
| *height = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||
| @@ -306,13 +306,15 @@ public: | |||
| #if DISTRHO_UI_USER_RESIZABLE | |||
| if (UIExporter* const ui = fUI.get()) | |||
| return ui->isResizable(); | |||
| #endif | |||
| return true; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| bool getResizeHints(clap_gui_resize_hints_t* const hints) const | |||
| { | |||
| if (canResize()) | |||
| if (fUI != nullptr && fUI->isResizable()) | |||
| { | |||
| uint minimumWidth, minimumHeight; | |||
| bool keepAspectRatio; | |||
| @@ -344,7 +346,7 @@ public: | |||
| bool adjustSize(uint32_t* const width, uint32_t* const height) const | |||
| { | |||
| if (canResize()) | |||
| if (fUI != nullptr && fUI->isResizable()) | |||
| { | |||
| uint minimumWidth, minimumHeight; | |||
| bool keepAspectRatio; | |||
| @@ -582,7 +584,8 @@ private: | |||
| nullptr, // TODO fileRequestCallback, | |||
| d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), | |||
| fScaleFactor); | |||
| fScaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic); | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| fUI->programLoaded(fCurrentProgram); | |||
| @@ -751,6 +754,7 @@ public: | |||
| updateStateValueCallback), | |||
| fHost(host), | |||
| fOutputEvents(nullptr), | |||
| fResetParameterIndex(UINT32_MAX), | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS != 0 | |||
| fUsingCV(false), | |||
| #endif | |||
| @@ -763,7 +767,19 @@ public: | |||
| #endif | |||
| fHostExtensions(host) | |||
| { | |||
| fCachedParameters.setup(fPlugin.getParameterCount()); | |||
| if (const uint32_t paramCount = fPlugin.getParameterCount()) | |||
| { | |||
| fCachedParameters.setup(paramCount); | |||
| for (uint32_t i=0; i<paramCount; ++i) | |||
| { | |||
| if (fPlugin.getParameterDesignation(i) == kParameterDesignationReset) | |||
| { | |||
| fResetParameterIndex = i; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| fNotesRingBuffer.setRingBuffer(&fNotesBuffer, true); | |||
| @@ -821,6 +837,22 @@ public: | |||
| #endif | |||
| } | |||
| void reset() | |||
| { | |||
| if (fResetParameterIndex != UINT32_MAX) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| fMidiEventCount = 0; | |||
| #endif | |||
| fPlugin.setParameterValue(fResetParameterIndex, 1.f); | |||
| fPlugin.setParameterValue(fResetParameterIndex, 0.f); | |||
| } | |||
| else | |||
| { | |||
| fHost->request_restart(fHost); | |||
| } | |||
| } | |||
| bool process(const clap_process_t* const process) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| @@ -1114,14 +1146,19 @@ public: | |||
| { | |||
| const ParameterRanges& ranges(fPlugin.getParameterRanges(index)); | |||
| if (fPlugin.getParameterDesignation(index) == kParameterDesignationBypass) | |||
| switch (fPlugin.getParameterDesignation(index)) | |||
| { | |||
| case kParameterDesignationBypass: | |||
| info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_BYPASS|CLAP_PARAM_IS_AUTOMATABLE; | |||
| std::strcpy(info->name, "Bypass"); | |||
| std::strcpy(info->module, "dpf_bypass"); | |||
| } | |||
| else | |||
| { | |||
| break; | |||
| case kParameterDesignationReset: | |||
| info->flags = CLAP_PARAM_IS_STEPPED|CLAP_PARAM_IS_READONLY; | |||
| std::strcpy(info->name, "Reset"); | |||
| std::strcpy(info->module, "dpf_reset"); | |||
| break; | |||
| default: | |||
| const uint32_t hints = fPlugin.getParameterHints(index); | |||
| const uint32_t groupId = fPlugin.getParameterGroupId(index); | |||
| @@ -1151,6 +1188,7 @@ public: | |||
| } | |||
| d_strncpy(info->module + wrtn, fPlugin.getParameterSymbol(index), CLAP_PATH_SIZE - wrtn); | |||
| break; | |||
| } | |||
| info->id = index; | |||
| @@ -1786,6 +1824,7 @@ private: | |||
| const clap_host_t* const fHost; | |||
| const clap_output_events_t* fOutputEvents; | |||
| uint32_t fResetParameterIndex; | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS != 0 | |||
| const float* fAudioInputs[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
| #endif | |||
| @@ -2284,23 +2323,33 @@ static bool CLAP_ABI clap_plugin_note_ports_get(const clap_plugin_t*, uint32_t, | |||
| { | |||
| if (is_input) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| info->id = 0; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
| info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; | |||
| info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; | |||
| #else | |||
| info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; | |||
| info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; | |||
| #endif | |||
| std::strcpy(info->name, "Event/MIDI Input"); | |||
| return true; | |||
| #endif | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| info->id = 0; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
| info->supported_dialects = CLAP_NOTE_DIALECT_MIDI | CLAP_NOTE_DIALECT_MIDI_MPE; | |||
| info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI_MPE; | |||
| #else | |||
| info->supported_dialects = CLAP_NOTE_DIALECT_MIDI; | |||
| info->preferred_dialect = CLAP_NOTE_DIALECT_MIDI; | |||
| #endif | |||
| std::strcpy(info->name, "Event/MIDI Output"); | |||
| return true; | |||
| #endif | |||
| #endif | |||
| } | |||
| return false; | |||
| @@ -2440,9 +2489,10 @@ static void CLAP_ABI clap_plugin_stop_processing(const clap_plugin_t*) | |||
| // nothing to do | |||
| } | |||
| static void CLAP_ABI clap_plugin_reset(const clap_plugin_t*) | |||
| static void CLAP_ABI clap_plugin_reset(const clap_plugin_t* const plugin) | |||
| { | |||
| // nothing to do | |||
| PluginCLAP* const instance = static_cast<PluginCLAP*>(plugin->plugin_data); | |||
| instance->reset(); | |||
| } | |||
| static clap_process_status CLAP_ABI clap_plugin_process(const clap_plugin_t* const plugin, const clap_process_t* const process) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -65,6 +65,10 @@ | |||
| # define DISTRHO_PLUGIN_WANT_LATENCY 0 | |||
| #endif | |||
| #ifndef DISTRHO_PLUGIN_WANT_MIDI_AS_MPE | |||
| # define DISTRHO_PLUGIN_WANT_MIDI_AS_MPE 0 | |||
| #endif | |||
| #ifndef DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| # define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0 | |||
| #endif | |||
| @@ -178,6 +182,13 @@ | |||
| # error Synths need audio output to work! | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Test if MIDI as MPE enabled where it doesn't make sense | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_AS_MPE && ! (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) | |||
| # error MIDI as MPE needs MIDI input or output to work! | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Enable MIDI input if synth, test if midi-input disabled when synth | |||
| @@ -275,15 +286,8 @@ static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)) == 5, "The macro DISTR | |||
| # error DISTRHO_UI_IS_STANDALONE must not be defined | |||
| #endif | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| # error DPF_USING_LD_LINUX_WEBVIEW must not be defined | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Set DPF_USING_LD_LINUX_WEBVIEW for internal use | |||
| #if DISTRHO_UI_WEB_VIEW && defined(DISTRHO_OS_LINUX) | |||
| # define DPF_USING_LD_LINUX_WEBVIEW | |||
| #ifdef DISTRHO_UI_LINUX_WEBVIEW_START | |||
| # error DISTRHO_UI_LINUX_WEBVIEW_START must not be defined | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -338,6 +338,64 @@ public: | |||
| DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,); | |||
| DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| { | |||
| uint32_t j=0; | |||
| # if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j) | |||
| fPlugin->initAudioPort(true, i, fData->audioPorts[j]); | |||
| # endif | |||
| # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j) | |||
| fPlugin->initAudioPort(false, i, fData->audioPorts[j]); | |||
| # endif | |||
| } | |||
| #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
| fPlugin->initParameter(i, fData->parameters[i]); | |||
| { | |||
| std::set<uint32_t> portGroupIndices; | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
| portGroupIndices.insert(fData->audioPorts[i].groupId); | |||
| #endif | |||
| for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
| portGroupIndices.insert(fData->parameters[i].groupId); | |||
| portGroupIndices.erase(kPortGroupNone); | |||
| if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size())) | |||
| { | |||
| fData->portGroups = new PortGroupWithId[portGroupSize]; | |||
| fData->portGroupCount = portGroupSize; | |||
| uint32_t index = 0; | |||
| for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index) | |||
| { | |||
| PortGroupWithId& portGroup(fData->portGroups[index]); | |||
| portGroup.groupId = *it; | |||
| if (portGroup.groupId < portGroupSize) | |||
| fPlugin->initPortGroup(portGroup.groupId, portGroup); | |||
| else | |||
| fillInPredefinedPortGroupData(portGroup.groupId, portGroup); | |||
| } | |||
| } | |||
| } | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| for (uint32_t i=0; i < fData->programCount; ++i) | |||
| fPlugin->initProgramName(i, fData->programNames[i]); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| for (uint32_t i=0; i < fData->stateCount; ++i) | |||
| fPlugin->initState(i, fData->states[i]); | |||
| #endif | |||
| #if defined(DPF_RUNTIME_TESTING) && defined(__GNUC__) && !defined(__clang__) | |||
| /* Run-time testing build. | |||
| * Verify that virtual functions are overriden if parameters, programs or states are in use. | |||
| @@ -380,17 +438,30 @@ public: | |||
| # if DISTRHO_PLUGIN_WANT_STATE | |||
| if (fData->stateCount != 0) | |||
| { | |||
| if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) == | |||
| (void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState)) | |||
| bool hasNonUiState = false; | |||
| for (uint32_t i=0; i < fData->stateCount; ++i) | |||
| { | |||
| d_stderr2("DPF warning: Plugins with state must implement `initState`"); | |||
| abort(); | |||
| if ((fData->states[i].hints & kStateIsOnlyForUI) == 0) | |||
| { | |||
| hasNonUiState = true; | |||
| break; | |||
| } | |||
| } | |||
| if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) | |||
| if (hasNonUiState) | |||
| { | |||
| d_stderr2("DPF warning: Plugins with state must implement `setState`"); | |||
| abort(); | |||
| if ((void*)(fPlugin->*(static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState))) == | |||
| (void*)static_cast<void(Plugin::*)(uint32_t,State&)>(&Plugin::initState)) | |||
| { | |||
| d_stderr2("DPF warning: Plugins with state must implement `initState`"); | |||
| abort(); | |||
| } | |||
| if ((void*)(fPlugin->*(&Plugin::setState)) == (void*)&Plugin::setState) | |||
| { | |||
| d_stderr2("DPF warning: Plugins with state must implement `setState`"); | |||
| abort(); | |||
| } | |||
| } | |||
| } | |||
| # endif | |||
| @@ -412,64 +483,6 @@ public: | |||
| # endif | |||
| #endif | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| { | |||
| uint32_t j=0; | |||
| # if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++j) | |||
| fPlugin->initAudioPort(true, i, fData->audioPorts[j]); | |||
| # endif | |||
| # if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++j) | |||
| fPlugin->initAudioPort(false, i, fData->audioPorts[j]); | |||
| # endif | |||
| } | |||
| #endif // DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
| fPlugin->initParameter(i, fData->parameters[i]); | |||
| { | |||
| std::set<uint32_t> portGroupIndices; | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
| portGroupIndices.insert(fData->audioPorts[i].groupId); | |||
| #endif | |||
| for (uint32_t i=0, count=fData->parameterCount; i < count; ++i) | |||
| portGroupIndices.insert(fData->parameters[i].groupId); | |||
| portGroupIndices.erase(kPortGroupNone); | |||
| if (const uint32_t portGroupSize = static_cast<uint32_t>(portGroupIndices.size())) | |||
| { | |||
| fData->portGroups = new PortGroupWithId[portGroupSize]; | |||
| fData->portGroupCount = portGroupSize; | |||
| uint32_t index = 0; | |||
| for (std::set<uint32_t>::iterator it = portGroupIndices.begin(); it != portGroupIndices.end(); ++it, ++index) | |||
| { | |||
| PortGroupWithId& portGroup(fData->portGroups[index]); | |||
| portGroup.groupId = *it; | |||
| if (portGroup.groupId < portGroupSize) | |||
| fPlugin->initPortGroup(portGroup.groupId, portGroup); | |||
| else | |||
| fillInPredefinedPortGroupData(portGroup.groupId, portGroup); | |||
| } | |||
| } | |||
| } | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| for (uint32_t i=0, count=fData->programCount; i < count; ++i) | |||
| fPlugin->initProgramName(i, fData->programNames[i]); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| for (uint32_t i=0, count=fData->stateCount; i < count; ++i) | |||
| fPlugin->initState(i, fData->states[i]); | |||
| #endif | |||
| fData->callbacksPtr = callbacksPtr; | |||
| fData->writeMidiCallbackFunc = writeMidiCall; | |||
| fData->requestParameterValueChangeCallbackFunc = requestParameterValueChangeCall; | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * This program is free software; you can redistribute it and/or | |||
| * modify it under the terms of the GNU Lesser General Public | |||
| @@ -88,10 +88,6 @@ static const writeMidiFunc writeMidiCallback = nullptr; | |||
| static const requestParameterValueChangeFunc requestParameterValueChangeCallback = nullptr; | |||
| #endif | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| static volatile bool gCloseSignalReceived = false; | |||
| @@ -556,7 +552,7 @@ protected: | |||
| midiData[1] = note; | |||
| midiData[2] = velocity; | |||
| fNotesRingBuffer.writeCustomData(midiData, 3); | |||
| fNotesRingBuffer.commitWrite(); | |||
| fNotesRingBuffer.commitWrite("PluginJack::sendNote"); | |||
| } | |||
| # endif | |||
| @@ -1003,9 +999,9 @@ int main(int argc, char* argv[]) | |||
| } | |||
| #endif | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| #if defined(DISTRHO_UI_LINUX_WEBVIEW_START) | |||
| if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) | |||
| return dpf_webview_start(argc, argv); | |||
| return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | |||
| #endif | |||
| if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | |||
| @@ -66,6 +66,10 @@ | |||
| # define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048 | |||
| #endif | |||
| #ifndef DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| # define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| #endif | |||
| #ifndef DISTRHO_PLUGIN_USES_MODGUI | |||
| # define DISTRHO_PLUGIN_USES_MODGUI 0 | |||
| #endif | |||
| @@ -260,14 +264,14 @@ void lv2_generate_ttl(const char* const basename) | |||
| const String pluginDLL(basename); | |||
| const String pluginTTL(pluginDLL + ".ttl"); | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| #if DISTRHO_PLUGIN_HAS_UI | |||
| String pluginUI(pluginDLL); | |||
| # if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| #if ! DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| pluginUI.truncate(pluginDLL.rfind("_dsp")); | |||
| pluginUI += "_ui"; | |||
| const String uiTTL(pluginUI + ".ttl"); | |||
| # endif | |||
| #endif | |||
| #endif | |||
| #endif | |||
| // --------------------------------------------- | |||
| @@ -278,7 +282,7 @@ void lv2_generate_ttl(const char* const basename) | |||
| String manifestString; | |||
| manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
| manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||
| #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| #if DISTRHO_PLUGIN_HAS_UI && DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| manifestString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| @@ -304,14 +308,14 @@ void lv2_generate_ttl(const char* const basename) | |||
| manifestString += "<" DISTRHO_UI_URI ">\n"; | |||
| manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n"; | |||
| manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n"; | |||
| # if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # if DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| addAttribute(manifestString, "lv2:extensionData", lv2ManifestUiExtensionData, 4); | |||
| addAttribute(manifestString, "lv2:optionalFeature", lv2ManifestUiOptionalFeatures, 4); | |||
| addAttribute(manifestString, "lv2:requiredFeature", lv2ManifestUiRequiredFeatures, 4); | |||
| addAttribute(manifestString, "opts:supportedOption", lv2ManifestUiSupportedOptions, 4, true); | |||
| # else // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # else // DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n"; | |||
| # endif // DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| # endif // DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| manifestString += "\n"; | |||
| #endif | |||
| @@ -363,6 +367,7 @@ void lv2_generate_ttl(const char* const basename) | |||
| #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
| pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"; | |||
| #endif | |||
| pluginString += "@prefix dg: <http://www.darkglass.com/lv2/ns#> .\n"; | |||
| pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | |||
| pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | |||
| pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | |||
| @@ -758,6 +763,16 @@ void lv2_generate_ttl(const char* const basename) | |||
| pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n"; | |||
| pluginString += " lv2:designation lv2:enabled ;\n"; | |||
| break; | |||
| case kParameterDesignationReset: | |||
| designated = true; | |||
| pluginString += " lv2:name \"Reset\" ;\n"; | |||
| pluginString += " lv2:symbol \"" + String(ParameterDesignationSymbols::reset) + "\" ;\n"; | |||
| pluginString += " lv2:default 0 ;\n"; | |||
| pluginString += " lv2:minimum 0 ;\n"; | |||
| pluginString += " lv2:maximum 1 ;\n"; | |||
| pluginString += " lv2:portProperty lv2:toggled , lv2:integer , <" LV2_PORT_PROPS__trigger "> ;\n"; | |||
| pluginString += " lv2:designation <" LV2_KXSTUDIO_PROPERTIES__Reset "> ;\n"; | |||
| break; | |||
| } | |||
| } | |||
| @@ -983,6 +998,22 @@ void lv2_generate_ttl(const char* const basename) | |||
| } | |||
| } | |||
| // Darkglass Anagram | |||
| #ifdef DISTRHO_PLUGIN_ABBREVIATION | |||
| pluginString += " dg:abbreviation \"" DISTRHO_PLUGIN_ABBREVIATION "\" ;\n"; | |||
| #endif | |||
| #ifdef DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_OFF | |||
| pluginString += " dg:blockImageOff <" DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_OFF "> ;\n"; | |||
| #endif | |||
| #ifdef DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_ON | |||
| pluginString += " dg:blockImageOn <" DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_ON "> ;\n"; | |||
| #endif | |||
| #if defined(DISTRHO_PLUGIN_ABBREVIATION) || \ | |||
| defined(DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_OFF) || \ | |||
| defined(DISTRHO_PLUGIN_ANAGRAM_BLOCK_IMAGE_ON) | |||
| pluginString += "\n"; | |||
| #endif | |||
| #ifdef DISTRHO_PLUGIN_BRAND | |||
| // MOD | |||
| pluginString += " mod:brand \"" DISTRHO_PLUGIN_BRAND "\" ;\n"; | |||
| @@ -1554,7 +1585,7 @@ void lv2_generate_ttl(const char* const basename) | |||
| // --------------------------------------------- | |||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT | |||
| { | |||
| std::cout << "Writing " << uiTTL << "..."; std::cout.flush(); | |||
| std::fstream uiFile(uiTTL, std::ios::out); | |||
| @@ -0,0 +1,158 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| * permission notice appear in all copies. | |||
| * | |||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| */ | |||
| #include "DistrhoPluginInternal.hpp" | |||
| #ifndef DISTRHO_NO_WARNINGS | |||
| # if DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST | |||
| # error Cannot use parameter value change request with MAPI | |||
| # endif | |||
| # if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| # error Cannot use MIDI with MAPI | |||
| # endif | |||
| # if DISTRHO_PLUGIN_WANT_FULL_STATE | |||
| # error Cannot use full state with MAPI | |||
| # endif | |||
| # if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
| # error Cannot use time position with MAPI | |||
| # endif | |||
| #endif | |||
| #include "mapi/mapi.h" | |||
| START_NAMESPACE_DISTRHO | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| class PluginMAPI | |||
| { | |||
| public: | |||
| PluginMAPI() | |||
| : fPlugin(nullptr, nullptr, nullptr, nullptr) | |||
| { | |||
| fPlugin.activate(); | |||
| } | |||
| ~PluginMAPI() noexcept | |||
| { | |||
| fPlugin.deactivate(); | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| void process(const float* const* ins, float** outs, unsigned int frames) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| fPlugin.run(const_cast<const float**>(ins), outs, frames, nullptr, 0); | |||
| #else | |||
| fPlugin.run(const_cast<const float**>(ins), outs, frames); | |||
| #endif | |||
| updateParameterOutputsAndTriggers(); | |||
| } | |||
| void setParameter(unsigned int index, float value) | |||
| { | |||
| fPlugin.setParameterValue(index, fPlugin.getParameterRanges(index).getFixedValue(value)); | |||
| } | |||
| void setState(const char* key, const char* value) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| fPlugin.setState(key, value); | |||
| #else | |||
| // unused | |||
| (void)key; | |||
| (void)value; | |||
| #endif | |||
| } | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| private: | |||
| PluginExporter fPlugin; | |||
| void updateParameterOutputsAndTriggers() | |||
| { | |||
| float value; | |||
| for (uint32_t i = 0, count = fPlugin.getParameterCount(); i < count; ++i) | |||
| { | |||
| if ((fPlugin.getParameterHints(i) & kParameterIsTrigger) == kParameterIsTrigger) | |||
| { | |||
| // NOTE: no trigger support in MAPI, simulate it here | |||
| value = fPlugin.getParameterRanges(i).def; | |||
| if (d_isEqual(value, fPlugin.getParameterValue(i))) | |||
| continue; | |||
| fPlugin.setParameterValue(i, value); | |||
| } | |||
| } | |||
| } | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| MAPI_EXPORT | |||
| mapi_handle_t mapi_create(unsigned int sample_rate) | |||
| { | |||
| if (d_nextBufferSize == 0) | |||
| { | |||
| #if defined(_DARKGLASS_DEVICE_PABLITO) | |||
| d_nextBufferSize = 16; | |||
| #elif defined(__MOD_DEVICES__) | |||
| d_nextBufferSize = 128; | |||
| #else | |||
| d_nextBufferSize = 2048; | |||
| #endif | |||
| } | |||
| d_nextSampleRate = sample_rate; | |||
| return new PluginMAPI(); | |||
| } | |||
| MAPI_EXPORT | |||
| void mapi_process(mapi_handle_t handle, | |||
| const float* const* ins, | |||
| float** outs, | |||
| unsigned int frames) | |||
| { | |||
| static_cast<PluginMAPI*>(handle)->process(ins, outs, frames); | |||
| } | |||
| MAPI_EXPORT | |||
| void mapi_set_parameter(mapi_handle_t handle, unsigned int index, float value) | |||
| { | |||
| static_cast<PluginMAPI*>(handle)->setParameter(index, value); | |||
| } | |||
| MAPI_EXPORT | |||
| void mapi_set_state(mapi_handle_t handle, const char* key, const char* value) | |||
| { | |||
| static_cast<PluginMAPI*>(handle)->setState(key, value); | |||
| } | |||
| MAPI_EXPORT | |||
| void mapi_destroy(mapi_handle_t handle) | |||
| { | |||
| delete static_cast<PluginMAPI*>(handle); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -175,7 +175,8 @@ public: | |||
| nullptr, // TODO file request | |||
| d_nextBundlePath, | |||
| plugin->getInstancePointer(), | |||
| scaleFactor), | |||
| scaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic), | |||
| fKeyboardModifiers(0) | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| , fNotesRingBuffer() | |||
| @@ -398,8 +399,8 @@ public: | |||
| { | |||
| parameterValues = new float[parameterCount]; | |||
| for (uint32_t i=0; i < parameterCount; ++i) | |||
| parameterValues[i] = NAN; | |||
| for (uint32_t i = 0; i < parameterCount; ++i) | |||
| parameterValues[i] = fPlugin.getParameterDefault(i); | |||
| } | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| @@ -600,7 +601,7 @@ public: | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(), | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| fPlugin.getInstancePointer(), scaleFactor); | |||
| fPlugin.getInstancePointer(), scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| fVstRect.right = tmpUI.getWidth(); | |||
| fVstRect.bottom = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||
| @@ -1709,7 +1710,7 @@ const vst_effect* VSTPluginMain(const vst_host_callback audioMaster) | |||
| return effect; | |||
| } | |||
| #if !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) || DISTRHO_UI_WEB_VIEW) | |||
| #if !(defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) || (defined(DISTRHO_OS_LINUX) && defined(DGL_USE_WEB_VIEW))) | |||
| DISTRHO_PLUGIN_EXPORT | |||
| const vst_effect* VSTPluginMainCompat(vst_host_callback) asm ("main"); | |||
| @@ -1747,6 +1747,12 @@ public: | |||
| case kParameterDesignationBypass: | |||
| flags |= V3_PARAM_IS_BYPASS; | |||
| break; | |||
| case kParameterDesignationReset: | |||
| info->flags = V3_PARAM_READ_ONLY | V3_PARAM_IS_HIDDEN; | |||
| info->step_count = 1; | |||
| strncpy_utf16(info->title, "Reset", 128); | |||
| strncpy_utf16(info->short_title, "Reset", 128); | |||
| return V3_OK; | |||
| } | |||
| if (hints & kParameterIsOutput) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -125,6 +125,7 @@ public: | |||
| CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes); | |||
| // setup property listeners | |||
| AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this); | |||
| AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this); | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| @@ -322,15 +323,22 @@ private: | |||
| #if DISTRHO_PLUGIN_WANT_STATE | |||
| void setState(const char* const key, const char* const value) | |||
| { | |||
| const std::vector<String>::iterator it = std::find(fStateKeys.begin(), fStateKeys.end(), key); | |||
| DISTRHO_SAFE_ASSERT_RETURN(it != fStateKeys.end(),); | |||
| if (const CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8)) | |||
| CFStringRef keyRef = CFStringCreateWithCString(nullptr, key, kCFStringEncodingASCII); | |||
| CFStringRef valueRef = CFStringCreateWithCString(nullptr, value, kCFStringEncodingUTF8); | |||
| if (const CFDictionaryRef dictRef = CFDictionaryCreate(nullptr, | |||
| reinterpret_cast<const void**>(&keyRef), | |||
| reinterpret_cast<const void**>(&valueRef), | |||
| 1, | |||
| &kCFTypeDictionaryKeyCallBacks, | |||
| &kCFTypeDictionaryValueCallBacks)) | |||
| { | |||
| const uint32_t index = it - fStateKeys.begin(); | |||
| AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, index, &valueRef, sizeof(CFStringRef)); | |||
| CFRelease(valueRef); | |||
| AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, 0, &dictRef, sizeof(dictRef)); | |||
| CFRelease(dictRef); | |||
| } | |||
| CFRelease(keyRef); | |||
| CFRelease(valueRef); | |||
| } | |||
| static void setStateCallback(void* const ptr, const char* const key, const char* const value) | |||
| @@ -387,6 +395,9 @@ END_NAMESPACE_DISTRHO | |||
| #define COCOA_VIEW_CLASS_NAME \ | |||
| MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID) | |||
| using DISTRHO_NAMESPACE::DPF_UI_AU; | |||
| using DISTRHO_NAMESPACE::d_nextSampleRate; | |||
| @interface COCOA_VIEW_CLASS_NAME : NSView | |||
| { | |||
| @public | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -38,10 +38,6 @@ static constexpr const setSizeFunc setSizeCallback = nullptr; | |||
| // unsupported in DSSI | |||
| static constexpr const fileRequestFunc fileRequestCallback = nullptr; | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -391,9 +387,9 @@ int main(int argc, char* argv[]) | |||
| { | |||
| USE_NAMESPACE_DISTRHO | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| #if defined(DISTRHO_UI_LINUX_WEBVIEW_START) | |||
| if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0) | |||
| return dpf_webview_start(argc - 1, argv + 1); | |||
| return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv); | |||
| #endif | |||
| // dummy test mode | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -21,18 +21,18 @@ | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI exporter class | |||
| class UIExporter | |||
| { | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| // UI Widget and its private data | |||
| UI* ui; | |||
| UI::PrivateData* uiData; | |||
| // ------------------------------------------------------------------- | |||
| // ---------------------------------------------------------------------------------------------------------------- | |||
| public: | |||
| UIExporter(void* const callbacksPtr, | |||
| @@ -47,11 +47,12 @@ public: | |||
| const char* const bundlePath = nullptr, | |||
| void* const dspPtr = nullptr, | |||
| const double scaleFactor = 0.0, | |||
| const DGL_NAMESPACE::Application::Type appType = DGL_NAMESPACE::Application::kTypeAuto, | |||
| const uint32_t bgColor = 0, | |||
| const uint32_t fgColor = 0xffffffff, | |||
| const char* const appClassName = nullptr) | |||
| : ui(nullptr), | |||
| uiData(new UI::PrivateData(appClassName)) | |||
| uiData(new UI::PrivateData(appClassName, appType)) | |||
| { | |||
| uiData->sampleRate = sampleRate; | |||
| uiData->bundlePath = bundlePath != nullptr ? strdup(bundlePath) : nullptr; | |||
| @@ -267,12 +268,12 @@ public: | |||
| uiData->app.repaintIfNeeeded(); | |||
| } | |||
| void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs) | |||
| void addIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb, const uint timerFrequencyInMs) | |||
| { | |||
| uiData->window->addIdleCallback(cb, timerFrequencyInMs); | |||
| } | |||
| void removeIdleCallbackForNativeIdle(IdleCallback* const cb) | |||
| void removeIdleCallbackForNativeIdle(DGL_NAMESPACE::IdleCallback* const cb) | |||
| { | |||
| uiData->window->removeIdleCallback(cb); | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -52,7 +52,7 @@ static constexpr const sendNoteFunc sendNoteCallback = nullptr; | |||
| // unwanted in LV2, resize extension is deprecated and hosts can do it without extensions | |||
| static constexpr const setSizeFunc setSizeCallback = nullptr; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| template <class LV2F> | |||
| static const LV2F* getLv2Feature(const LV2_Feature* const* features, const char* const uri) | |||
| @@ -80,6 +80,7 @@ public: | |||
| void* const dspPtr, | |||
| const float sampleRate, | |||
| const float scaleFactor, | |||
| const DGL_NAMESPACE::Application::Type appType, | |||
| const uint32_t bgColor, | |||
| const uint32_t fgColor, | |||
| const char* const appClassName) | |||
| @@ -101,7 +102,7 @@ public: | |||
| sendNoteCallback, | |||
| setSizeCallback, | |||
| fileRequestCallback, | |||
| bundlePath, dspPtr, scaleFactor, bgColor, fgColor, appClassName) | |||
| bundlePath, dspPtr, scaleFactor, appType, bgColor, fgColor, appClassName) | |||
| { | |||
| if (widget != nullptr) | |||
| *widget = (LV2UI_Widget)fUI.getNativeWindowHandle(); | |||
| @@ -483,7 +484,7 @@ private: | |||
| } | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| const char* const uri, | |||
| @@ -499,6 +500,9 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| return nullptr; | |||
| } | |||
| // TODO allow classic vs modern ui type | |||
| static constexpr const DGL_NAMESPACE::Application::Type appType = DGL_NAMESPACE::Application::kTypeClassic; | |||
| const LV2_Options_Option* options = nullptr; | |||
| const LV2_URID_Map* uridMap = nullptr; | |||
| void* parentId = nullptr; | |||
| @@ -633,7 +637,7 @@ static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, | |||
| return new UiLv2(bundlePath, winId, options, uridMap, features, | |||
| controller, writeFunction, widget, instance, | |||
| sampleRate, scaleFactor, bgColor, fgColor, appClassName); | |||
| sampleRate, scaleFactor, appType, bgColor, fgColor, appClassName); | |||
| } | |||
| #define uiPtr ((UiLv2*)ui) | |||
| @@ -648,7 +652,7 @@ static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t buffe | |||
| uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static int lv2ui_idle(LV2UI_Handle ui) | |||
| { | |||
| @@ -665,7 +669,7 @@ static int lv2ui_hide(LV2UI_Handle ui) | |||
| return uiPtr->lv2ui_hide(); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static uint32_t lv2_get_options(LV2UI_Handle ui, LV2_Options_Option* options) | |||
| { | |||
| @@ -677,7 +681,7 @@ static uint32_t lv2_set_options(LV2UI_Handle ui, const LV2_Options_Option* optio | |||
| return uiPtr->lv2_set_options(options); | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
| static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program) | |||
| @@ -686,7 +690,7 @@ static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t progra | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static const void* lv2ui_extension_data(const char* uri) | |||
| { | |||
| @@ -713,7 +717,7 @@ static const void* lv2ui_extension_data(const char* uri) | |||
| #undef instancePtr | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static const LV2UI_Descriptor sLv2UiDescriptor = { | |||
| DISTRHO_UI_URI, | |||
| @@ -723,7 +727,7 @@ static const LV2UI_Descriptor sLv2UiDescriptor = { | |||
| lv2ui_extension_data | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -929,4 +933,4 @@ void modgui_cleanup(const LV2UI_Handle handle) | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -61,14 +61,20 @@ | |||
| START_NAMESPACE_DISTRHO | |||
| // ----------------------------------------------------------------------- | |||
| /* define webview start */ | |||
| #if defined(HAVE_X11) && defined(DISTRHO_OS_LINUX) && DISTRHO_UI_WEB_VIEW | |||
| # define DISTRHO_UI_LINUX_WEBVIEW_START | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Plugin Application, will set class name based on plugin details | |||
| class PluginApplication : public DGL_NAMESPACE::Application | |||
| { | |||
| public: | |||
| explicit PluginApplication(const char* className) | |||
| : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE) | |||
| explicit PluginApplication(const char* className, const Application::Type type) | |||
| : DGL_NAMESPACE::Application(DISTRHO_UI_IS_STANDALONE, type) | |||
| { | |||
| #if defined(__MOD_DEVICES__) || !defined(__EMSCRIPTEN__) | |||
| if (className == nullptr) | |||
| @@ -102,7 +108,7 @@ public: | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // Plugin Window, will pass some Window events to UI | |||
| class PluginWindow : public DGL_NAMESPACE::Window | |||
| @@ -132,7 +138,10 @@ public: | |||
| // this is called just before creating UI, ensuring proper context to it | |||
| if (pData->initPost()) | |||
| { | |||
| puglBackendEnter(pData->view); | |||
| pData->createContextIfNeeded(); | |||
| } | |||
| } | |||
| ~PluginWindow() override | |||
| @@ -234,7 +243,7 @@ protected: | |||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI callbacks | |||
| typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |||
| @@ -244,7 +253,7 @@ typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8 | |||
| typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |||
| typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI private data | |||
| struct UI::PrivateData { | |||
| @@ -283,8 +292,8 @@ struct UI::PrivateData { | |||
| setSizeFunc setSizeCallbackFunc; | |||
| fileRequestFunc fileRequestCallbackFunc; | |||
| PrivateData(const char* const appClassName) noexcept | |||
| : app(appClassName), | |||
| PrivateData(const char* const appClassName, const DGL_NAMESPACE::Application::Type appType) noexcept | |||
| : app(appClassName, appType), | |||
| window(nullptr), | |||
| #if DISTRHO_UI_USE_WEB_VIEW | |||
| webview(nullptr), | |||
| @@ -383,7 +392,7 @@ struct UI::PrivateData { | |||
| #endif | |||
| }; | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // UI private data fileRequestCallback, which requires PluginWindow definitions | |||
| inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||
| @@ -410,7 +419,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||
| return false; | |||
| } | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| // PluginWindow onFileSelected that require UI::PrivateData definitions | |||
| #if DISTRHO_UI_FILE_BROWSER | |||
| @@ -448,7 +457,7 @@ inline void PluginWindow::onFileSelected(const char* const filename) | |||
| } | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -129,7 +129,7 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept | |||
| * Helper class for getting a native idle timer. | |||
| */ | |||
| #if !DPF_VST3_USING_HOST_RUN_LOOP | |||
| class NativeIdleCallback : public IdleCallback | |||
| class NativeIdleCallback : public DGL_NAMESPACE::IdleCallback | |||
| { | |||
| public: | |||
| NativeIdleCallback(UIExporter& ui) | |||
| @@ -205,7 +205,8 @@ public: | |||
| nullptr, // TODO file request | |||
| d_nextBundlePath, | |||
| instancePointer, | |||
| scaleFactor) | |||
| scaleFactor, | |||
| DGL_NAMESPACE::Application::kTypeClassic) | |||
| { | |||
| } | |||
| @@ -1374,7 +1375,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp { | |||
| #else | |||
| UIExporter tmpUI(nullptr, 0, view->sampleRate, | |||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath, | |||
| view->instancePointer, scaleFactor); | |||
| view->instancePointer, scaleFactor, DGL_NAMESPACE::Application::kTypeClassic); | |||
| rect->right = tmpUI.getWidth(); | |||
| rect->bottom = tmpUI.getHeight(); | |||
| scaleFactor = tmpUI.getScaleFactor(); | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -23,13 +23,19 @@ | |||
| #include "../DistrhoStandaloneUtils.hpp" | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| # include <direct.h> | |||
| # include <shlobj.h> | |||
| # include <windows.h> | |||
| #else | |||
| # ifndef STATIC_BUILD | |||
| # include <dlfcn.h> | |||
| # endif | |||
| # include <fcntl.h> | |||
| # include <limits.h> | |||
| # include <pwd.h> | |||
| # include <stdlib.h> | |||
| # include <sys/stat.h> | |||
| # include <unistd.h> | |||
| #endif | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| @@ -109,6 +115,240 @@ const char* getPluginFormatName() noexcept | |||
| #endif | |||
| } | |||
| #ifndef DISTRHO_OS_WINDOWS | |||
| static inline | |||
| void _createDirIfNeeded(const char* const dir) | |||
| { | |||
| try { | |||
| if (access(dir, F_OK) != 0) | |||
| mkdir(dir, 0755); | |||
| } DISTRHO_SAFE_EXCEPTION("createDirIfNeeded"); | |||
| } | |||
| #endif | |||
| static const char* _getDocumentsDir(); | |||
| static const char* _getDocumentsDirForPlugin(); | |||
| static const char* _getHomeDir(); | |||
| static const char* _getConfigDir() | |||
| { | |||
| #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) | |||
| return _getDocumentsDir(); | |||
| #else | |||
| static String dir; | |||
| if (dir.isEmpty()) | |||
| { | |||
| if (const char* const xdgEnv = getenv("XDG_CONFIG_HOME")) | |||
| { | |||
| dir = xdgEnv; | |||
| if (dir.isNotEmpty() && ! dir.endsWith('/')) | |||
| dir += "/"; | |||
| } | |||
| if (dir.isEmpty()) | |||
| { | |||
| dir = _getHomeDir(); | |||
| dir += ".config/"; | |||
| } | |||
| _createDirIfNeeded(dir); | |||
| } | |||
| return dir; | |||
| #endif | |||
| } | |||
| static const char* _getConfigDirForPlugin() | |||
| { | |||
| #if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS) | |||
| return _getDocumentsDirForPlugin(); | |||
| #else | |||
| static String dir; | |||
| if (dir.isEmpty()) | |||
| { | |||
| dir = _getConfigDir(); | |||
| dir += DISTRHO_PLUGIN_NAME DISTRHO_OS_SEP_STR; | |||
| _createDirIfNeeded(dir); | |||
| } | |||
| return dir; | |||
| #endif | |||
| } | |||
| static const char* _getDocumentsDir() | |||
| { | |||
| static String dir; | |||
| if (dir.isEmpty()) | |||
| { | |||
| #if defined(DISTRHO_OS_MAC) | |||
| dir = _getHomeDir(); | |||
| dir += "Documents/"; | |||
| #elif defined(DISTRHO_OS_WASM) | |||
| dir = _getHomeDir(); | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| WCHAR wpath[MAX_PATH]; | |||
| if (SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, wpath) == S_OK) | |||
| { | |||
| CHAR apath[MAX_PATH]; | |||
| if (WideCharToMultiByte(CP_UTF8, 0, wpath, -1, apath, MAX_PATH, nullptr, nullptr) != 0) | |||
| dir = apath; | |||
| } | |||
| #else | |||
| String xdgDirsConfigPath(_getConfigDir()); | |||
| xdgDirsConfigPath += "user-dirs.dirs"; | |||
| if (FILE* const f = std::fopen(xdgDirsConfigPath, "r")) | |||
| { | |||
| std::fseek(f, 0, SEEK_END); | |||
| const long size = std::ftell(f); | |||
| std::fseek(f, 0, SEEK_SET); | |||
| // something is wrong if config dirs file is longer than 1MiB! | |||
| if (size > 0 && size < 1024 * 1024) | |||
| { | |||
| if (char* filedata = static_cast<char*>(std::malloc(size))) | |||
| { | |||
| for (long r = 0, total = 0; total < size;) | |||
| { | |||
| r = std::fread(filedata + total, 1, size - total, f); | |||
| if (r == 0) | |||
| { | |||
| std::free(filedata); | |||
| filedata = nullptr; | |||
| break; | |||
| } | |||
| total += r; | |||
| } | |||
| if (filedata != nullptr) | |||
| { | |||
| if (char* const xdgDocsDir = std::strstr(filedata, "XDG_DOCUMENTS_DIR=\"")) | |||
| { | |||
| if (char* const xdgDocsDirNL = std::strstr(xdgDocsDir, "\"\n")) | |||
| { | |||
| *xdgDocsDirNL = '\0'; | |||
| String sdir(xdgDocsDir + 19); | |||
| if (sdir.startsWith("$HOME")) | |||
| { | |||
| dir = _getHomeDir(); | |||
| dir += sdir.buffer() + 6; | |||
| } | |||
| else | |||
| { | |||
| dir = sdir; | |||
| } | |||
| } | |||
| } | |||
| std::free(filedata); | |||
| } | |||
| } | |||
| } | |||
| std::fclose(f); | |||
| } | |||
| // ${XDG_CONFIG_HOME}/user-dirs.dirs does not exist or has bad data | |||
| if (dir.isEmpty()) | |||
| { | |||
| dir = _getHomeDir(); | |||
| dir += "Documents/"; | |||
| } | |||
| _createDirIfNeeded(dir); | |||
| #endif | |||
| if (dir.isNotEmpty() && ! dir.endsWith(DISTRHO_OS_SEP)) | |||
| dir += DISTRHO_OS_SEP_STR; | |||
| } | |||
| return dir; | |||
| } | |||
| static const char* _getDocumentsDirForPlugin() | |||
| { | |||
| static String dir; | |||
| if (dir.isEmpty()) | |||
| { | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| WCHAR wpath[MAX_PATH]; | |||
| if (SHGetFolderPathW(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, wpath) == S_OK) | |||
| { | |||
| wcscat(wpath, L"\\" DISTRHO_PLUGIN_NAME "\\"); | |||
| _wmkdir(wpath); | |||
| CHAR apath[MAX_PATH]; | |||
| if (WideCharToMultiByte(CP_UTF8, 0, wpath, -1, apath, MAX_PATH, nullptr, nullptr) != 0) | |||
| dir = apath; | |||
| } | |||
| #else | |||
| dir = _getDocumentsDir(); | |||
| dir += DISTRHO_PLUGIN_NAME DISTRHO_OS_SEP_STR; | |||
| _createDirIfNeeded(dir); | |||
| #endif | |||
| } | |||
| return dir; | |||
| } | |||
| static const char* _getHomeDir() | |||
| { | |||
| static String dir; | |||
| if (dir.isEmpty()) | |||
| { | |||
| #ifdef DISTRHO_OS_WINDOWS | |||
| WCHAR wpath[MAX_PATH]; | |||
| if (SHGetFolderPathW(nullptr, CSIDL_PROFILE, nullptr, SHGFP_TYPE_CURRENT, wpath) == S_OK) | |||
| { | |||
| CHAR apath[MAX_PATH]; | |||
| if (WideCharToMultiByte(CP_UTF8, 0, wpath, -1, apath, MAX_PATH, nullptr, nullptr) != 0) | |||
| dir = apath; | |||
| } | |||
| #else | |||
| if (const char* const homeEnv = getenv("HOME")) | |||
| dir = homeEnv; | |||
| if (dir.isEmpty()) | |||
| if (struct passwd* const pwd = getpwuid(getuid())) | |||
| dir = pwd->pw_dir; | |||
| _createDirIfNeeded(dir); | |||
| #endif | |||
| if (dir.isNotEmpty() && ! dir.endsWith(DISTRHO_OS_SEP)) | |||
| dir += DISTRHO_OS_SEP_STR; | |||
| } | |||
| return dir; | |||
| } | |||
| const char* getSpecialDir(const SpecialDir dir) | |||
| { | |||
| switch (dir) | |||
| { | |||
| case kSpecialDirHome: | |||
| return _getHomeDir(); | |||
| case kSpecialDirConfig: | |||
| return _getConfigDir(); | |||
| case kSpecialDirConfigForPlugin: | |||
| return _getConfigDirForPlugin(); | |||
| case kSpecialDirDocuments: | |||
| return _getDocumentsDir(); | |||
| case kSpecialDirDocumentsForPlugin: | |||
| return _getDocumentsDirForPlugin(); | |||
| } | |||
| return nullptr; | |||
| } | |||
| const char* getResourcePath(const char* const bundlePath) noexcept | |||
| { | |||
| DISTRHO_SAFE_ASSERT_RETURN(bundlePath != nullptr, nullptr); | |||
| @@ -166,11 +406,6 @@ bool requestBufferSizeChange(uint) { return false; } | |||
| bool requestMIDI() { return false; } | |||
| #endif | |||
| /* define webview start */ | |||
| #ifdef DPF_USING_LD_LINUX_WEBVIEW | |||
| int dpf_webview_start(int argc, char* argv[]); | |||
| #endif | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| END_NAMESPACE_DISTRHO | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * JackBridge for DPF | |||
| * Copyright (C) 2013-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2013-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -68,6 +68,9 @@ typedef void* lib_t; | |||
| # pragma clang diagnostic push | |||
| # pragma clang diagnostic ignored "-Wdeprecated-declarations" | |||
| # pragma clang diagnostic ignored "-Wunused-but-set-variable" | |||
| # if __clang_major__ >= 17 | |||
| # pragma clang diagnostic ignored "-Wvla-cxx-extension" | |||
| # endif | |||
| # endif | |||
| # include "RtAudioBridge.hpp" | |||
| # ifdef RTAUDIO_API_TYPE | |||
| @@ -467,29 +470,37 @@ struct JackBridge { | |||
| #endif | |||
| { | |||
| #ifdef HAVE_JACK | |||
| #if defined(DISTRHO_OS_MAC) | |||
| const char* const filename = "libjack.dylib"; | |||
| #elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) | |||
| const char* const filename = "libjack64.dll"; | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| const char* const filename = "libjack.dll"; | |||
| #else | |||
| const char* const filename = "libjack.so.0"; | |||
| #endif | |||
| static constexpr const char* const filenames[] = { | |||
| #if defined(DISTRHO_OS_MAC) | |||
| "libjack.0.dylib", | |||
| "/usr/local/lib/libjack.0.dylib", | |||
| #elif defined(DISTRHO_OS_WINDOWS) && defined(_WIN64) | |||
| "libjack64.dll", | |||
| #elif defined(DISTRHO_OS_WINDOWS) | |||
| "libjack.dll", | |||
| #else | |||
| "libjack.so.0", | |||
| #endif | |||
| }; | |||
| USE_NAMESPACE_DISTRHO | |||
| lib = lib_open(filename); | |||
| for (uint i = 0; i < ARRAY_SIZE(filenames); ++i) | |||
| { | |||
| lib = lib_open(filenames[i]); | |||
| if (lib != nullptr) | |||
| { | |||
| d_stdout("%s loaded successfully!", filenames[i]); | |||
| break; | |||
| } | |||
| } | |||
| if (lib == nullptr) | |||
| { | |||
| d_stderr("Failed to load JACK DLL, reason:\n%s", lib_error(filename)); | |||
| d_stderr("Failed to load JACK DLL, reason:\n%s", lib_error(filenames[0])); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| d_stdout("%s loaded successfully!", filename); | |||
| } | |||
| #define JOIN(a, b) a ## b | |||
| #define LIB_SYMBOL(NAME) JOIN(NAME, _ptr) = lib_symbol<jacksym_##NAME>(lib, "jack_" #NAME); | |||
| @@ -951,7 +962,7 @@ jack_client_t* jackbridge_client_open(const char* client_name, uint32_t options, | |||
| return kValidClient; | |||
| delete nativeBridge; | |||
| #endif | |||
| #if defined(HAVE_RTAUDIO) && defined(RTAUDIO_API_TYPE) | |||
| nativeBridge = new RtAudioBridge; | |||
| if (nativeBridge->open(client_name)) | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * Native Bridge for DPF | |||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -19,6 +19,7 @@ | |||
| #include "JackBridge.hpp" | |||
| #include "../../extra/Mutex.hpp" | |||
| #include "../../extra/RingBuffer.hpp" | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS > 2 | |||
| @@ -34,6 +35,8 @@ | |||
| #endif | |||
| using DISTRHO_NAMESPACE::HeapRingBuffer; | |||
| using DISTRHO_NAMESPACE::RecursiveMutex; | |||
| using DISTRHO_NAMESPACE::RecursiveMutexLocker; | |||
| struct NativeBridge { | |||
| // Current status information | |||
| @@ -64,23 +67,25 @@ struct NativeBridge { | |||
| kPortMaskInputMIDI = kPortMaskInput|kPortMaskMIDI, | |||
| kPortMaskOutputMIDI = kPortMaskOutput|kPortMaskMIDI, | |||
| }; | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| float* audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
| float* audioBufferStorage; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| bool midiAvailable; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| bool midiUsed; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| static constexpr const uint32_t kMaxMIDIInputMessageSize = 3; | |||
| static constexpr const uint32_t kRingBufferMessageSize = 1u /*+ sizeof(double)*/ + kMaxMIDIInputMessageSize; | |||
| uint8_t midiDataStorage[kMaxMIDIInputMessageSize]; | |||
| HeapRingBuffer midiInBufferCurrent; | |||
| HeapRingBuffer midiInBufferPending; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| #endif | |||
| RecursiveMutex midiInLock; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| HeapRingBuffer midiOutBuffer; | |||
| #endif | |||
| #endif | |||
| NativeBridge() | |||
| : bufferSize(0), | |||
| @@ -101,6 +106,7 @@ struct NativeBridge { | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| , midiAvailable(false) | |||
| , midiUsed(false) | |||
| #endif | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| @@ -132,8 +138,16 @@ struct NativeBridge { | |||
| #endif | |||
| } | |||
| virtual bool isMIDIEnabled() const | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| return midiUsed; | |||
| #else | |||
| return false; | |||
| #endif | |||
| } | |||
| virtual bool supportsBufferSizeChanges() const { return false; } | |||
| virtual bool isMIDIEnabled() const { return false; } | |||
| virtual bool requestAudioInput() { return false; } | |||
| virtual bool requestBufferSizeChange(uint32_t) { return false; } | |||
| virtual bool requestMIDI() { return false; } | |||
| @@ -158,7 +172,10 @@ struct NativeBridge { | |||
| if (midiAvailable) | |||
| { | |||
| // NOTE: this function is only called once per run | |||
| midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending); | |||
| { | |||
| const RecursiveMutexLocker cml(midiInLock); | |||
| midiInBufferCurrent.copyFromAndClearOther(midiInBufferPending); | |||
| } | |||
| return midiInBufferCurrent.getReadableDataSize() / kRingBufferMessageSize; | |||
| } | |||
| #endif | |||
| @@ -212,10 +229,10 @@ struct NativeBridge { | |||
| case 2: fail |= !midiOutBuffer.writeByte(0); | |||
| } | |||
| fail |= !midiOutBuffer.writeUInt(time); | |||
| midiOutBuffer.commitWrite(); | |||
| midiOutBuffer.commitWrite("NativeBridge::writeEvent (with data)"); | |||
| return !fail; | |||
| } | |||
| midiOutBuffer.commitWrite(); | |||
| midiOutBuffer.commitWrite("NativeBridge::writeEvent (without data)"); | |||
| } | |||
| #endif | |||
| @@ -231,7 +248,7 @@ struct NativeBridge { | |||
| if (audio) | |||
| { | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||
| audioBufferStorage = new float[bufferSize*(DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS)]; | |||
| for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||
| @@ -245,6 +262,9 @@ struct NativeBridge { | |||
| if (midi) | |||
| { | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| midiUsed = true; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| midiInBufferCurrent.createBuffer(kMaxMIDIInputMessageSize * 512); | |||
| midiInBufferPending.createBuffer(kMaxMIDIInputMessageSize * 512); | |||
| @@ -261,12 +281,18 @@ struct NativeBridge { | |||
| delete[] audioBufferStorage; | |||
| audioBufferStorage = nullptr; | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| midiInBufferCurrent.deleteBuffer(); | |||
| midiInBufferPending.deleteBuffer(); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| midiOutBuffer.deleteBuffer(); | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| if (midiUsed) | |||
| { | |||
| midiUsed = false; | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||
| midiInBufferCurrent.deleteBuffer(); | |||
| midiInBufferPending.deleteBuffer(); | |||
| #endif | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| midiOutBuffer.deleteBuffer(); | |||
| #endif | |||
| } | |||
| #endif | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * RtAudio Bridge for DPF | |||
| * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2021-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -19,7 +19,7 @@ | |||
| #include "NativeBridge.hpp" | |||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0 | |||
| #if (DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS) == 0 | |||
| # error RtAudio without audio does not make sense | |||
| #endif | |||
| @@ -33,7 +33,7 @@ | |||
| # define RTAUDIO_API_TYPE WINDOWS_WASAPI | |||
| # define RTMIDI_API_TYPE WINDOWS_MM | |||
| #else | |||
| # if defined(HAVE_PULSEAUDIO) | |||
| # if defined(HAVE_PULSEAUDIO) && !defined(DPF_JACK_STANDALONE_SKIP_PULSEAUDIO_FALLBACK) | |||
| # define __LINUX_PULSE__ | |||
| # define RTAUDIO_API_TYPE LINUX_PULSE | |||
| # elif defined(HAVE_ALSA) | |||
| @@ -392,6 +392,28 @@ struct RtAudioBridge : NativeBridge { | |||
| const ScopedDenormalDisable sdd; | |||
| self->jackProcessCallback(numFrames, self->jackProcessArg); | |||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | |||
| if (self->midiOutBuffer.isDataAvailableForReading()) | |||
| { | |||
| static_assert(kMaxMIDIInputMessageSize + 1u == 4, "change code if bumping this value"); | |||
| uint8_t data[4] = {}; | |||
| while (self->midiOutBuffer.isDataAvailableForReading() && | |||
| self->midiOutBuffer.readCustomData(data, ARRAY_SIZE(data))) | |||
| { | |||
| // offset not used in RtMidiOut | |||
| self->midiOutBuffer.readUInt(); | |||
| for (std::vector<RtMidiOut>::iterator it = self->midiOuts.begin(), end = self->midiOuts.end(); it != end; ++it) | |||
| { | |||
| static_cast<RtMidiOut&>(*it).sendMessage(data + 1, data[0]); | |||
| } | |||
| } | |||
| self->midiOutBuffer.flush(); | |||
| } | |||
| #endif | |||
| return 0; | |||
| } | |||
| @@ -403,13 +425,15 @@ struct RtAudioBridge : NativeBridge { | |||
| RtAudioBridge* const self = static_cast<RtAudioBridge*>(userData); | |||
| const RecursiveMutexLocker rml(self->midiInLock); | |||
| self->midiInBufferPending.writeByte(static_cast<uint8_t>(len)); | |||
| // TODO timestamp | |||
| // self->midiInBufferPending.writeDouble(timestamp); | |||
| self->midiInBufferPending.writeCustomData(message->data(), len); | |||
| for (uint8_t i=len; i<kMaxMIDIInputMessageSize; ++i) | |||
| for (uint8_t i = len; i < kMaxMIDIInputMessageSize; ++i) | |||
| self->midiInBufferPending.writeByte(0); | |||
| self->midiInBufferPending.commitWrite(); | |||
| self->midiInBufferPending.commitWrite("RtMidiCallback"); | |||
| } | |||
| #endif | |||
| }; | |||
| @@ -224,55 +224,58 @@ struct WebBridge : NativeBridge { | |||
| var constraints = {}; | |||
| // we need to use this weird awkward way for objects, otherwise build fails | |||
| constraints['audio'] = true; | |||
| constraints['video'] = false; | |||
| constraints['autoGainControl'] = {}; | |||
| constraints['autoGainControl']['ideal'] = false; | |||
| constraints['echoCancellation'] = {}; | |||
| constraints['echoCancellation']['ideal'] = false; | |||
| constraints['noiseSuppression'] = {}; | |||
| constraints['noiseSuppression']['ideal'] = false; | |||
| constraints['channelCount'] = {}; | |||
| constraints['channelCount']['min'] = 0; | |||
| constraints['channelCount']['ideal'] = numInputs; | |||
| constraints['latency'] = {}; | |||
| constraints['latency']['min'] = 0; | |||
| constraints['latency']['ideal'] = 0; | |||
| constraints['sampleSize'] = {}; | |||
| constraints['sampleSize']['min'] = 8; | |||
| constraints['sampleSize']['max'] = 32; | |||
| constraints['sampleSize']['ideal'] = 16; | |||
| // old property for chrome | |||
| constraints['googAutoGainControl'] = false; | |||
| constraints['audio'] = {}; | |||
| constraints['audio']['autoGainControl'] = {}; | |||
| constraints['audio']['autoGainControl']['ideal'] = false; | |||
| constraints['audio']['echoCancellation'] = {}; | |||
| constraints['audio']['echoCancellation']['ideal'] = false; | |||
| constraints['audio']['noiseSuppression'] = {}; | |||
| constraints['audio']['noiseSuppression']['ideal'] = false; | |||
| constraints['audio']['channelCount'] = {}; | |||
| constraints['audio']['channelCount']['min'] = 0; | |||
| constraints['audio']['channelCount']['ideal'] = numInputs; | |||
| constraints['audio']['latency'] = {}; | |||
| constraints['audio']['latency']['min'] = 0; | |||
| constraints['audio']['latency']['ideal'] = 0; | |||
| constraints['audio']['sampleSize'] = {}; | |||
| constraints['audio']['sampleSize']['min'] = 8; | |||
| constraints['audio']['sampleSize']['max'] = 32; | |||
| constraints['audio']['sampleSize']['ideal'] = 16; | |||
| // old properties for chrome | |||
| constraints['audio']['googAudioMirroring'] = {}; | |||
| constraints['audio']['googAudioMirroring']['ideal'] = false; | |||
| constraints['audio']['googAutoGainControl'] = {}; | |||
| constraints['audio']['googAutoGainControl']['ideal'] = false; | |||
| constraints['audio']['googAutoGainControl2'] = {}; | |||
| constraints['audio']['googAutoGainControl2']['ideal'] = false; | |||
| constraints['audio']['googDAEchoCancellation'] = {}; | |||
| constraints['audio']['googDAEchoCancellation']['ideal'] = false; | |||
| constraints['audio']['googEchoCancellation'] = {}; | |||
| constraints['audio']['googEchoCancellation']['ideal'] = false; | |||
| constraints['audio']['googEchoCancellation2'] = {}; | |||
| constraints['audio']['googEchoCancellation2']['ideal'] = false; | |||
| constraints['audio']['googHighpassFilter'] = {}; | |||
| constraints['audio']['googHighpassFilter']['ideal'] = false; | |||
| constraints['audio']['googNoiseSuppression'] = {}; | |||
| constraints['audio']['googNoiseSuppression']['ideal'] = false; | |||
| constraints['audio']['googNoiseSuppression2'] = {}; | |||
| constraints['audio']['googNoiseSuppression2']['ideal'] = false; | |||
| constraints['audio']['googTypingNoiseDetection'] = {}; | |||
| constraints['audio']['googTypingNoiseDetection']['ideal'] = false; | |||
| constraints['audio']['intelligibilityEnhancer'] = {}; | |||
| constraints['audio']['intelligibilityEnhancer']['ideal'] = false; | |||
| constraints['audio']['levelControl'] = {}; | |||
| constraints['audio']['levelControl']['ideal'] = false; | |||
| constraints['audio']['levelControlInitialPeakLevelDBFS'] = {}; | |||
| constraints['audio']['levelControlInitialPeakLevelDBFS']['ideal'] = false; | |||
| var success = function(stream) { | |||
| var tracks = stream.getAudioTracks(); | |||
| // try to force as much as we can | |||
| for (var i in tracks) { | |||
| var track = tracks[i]; | |||
| track.applyConstraints({'autoGainControl': { 'exact': false } }) | |||
| .then(function(){console.log("Mic/Input auto-gain control has been disabled")}) | |||
| .catch(function(){console.log("Cannot disable Mic/Input auto-gain")}); | |||
| track.applyConstraints({'echoCancellation': { 'exact': false } }) | |||
| .then(function(){console.log("Mic/Input echo-cancellation has been disabled")}) | |||
| .catch(function(){console.log("Cannot disable Mic/Input echo-cancellation")}); | |||
| track.applyConstraints({'noiseSuppression': { 'exact': false } }) | |||
| .then(function(){console.log("Mic/Input noise-suppression has been disabled")}) | |||
| .catch(function(){console.log("Cannot disable Mic/Input noise-suppression")}); | |||
| track.applyConstraints({'googAutoGainControl': { 'exact': false } }) | |||
| .then(function(){}) | |||
| .catch(function(){}); | |||
| } | |||
| WAB.captureStreamNode = WAB.audioContext['createMediaStreamSource'](stream); | |||
| WAB.captureStreamNode.connect(WAB.processor); | |||
| }; | |||
| var fail = function() { | |||
| var fail = function(err) { | |||
| console.error(err); | |||
| }; | |||
| if (navigator.mediaDevices !== undefined && navigator.mediaDevices.getUserMedia !== undefined) { | |||
| @@ -494,7 +497,7 @@ struct WebBridge : NativeBridge { | |||
| }, offset, bytes[0], bytes[1], bytes[2], bytes[3], timestamp); | |||
| } | |||
| self->midiOutBuffer.clearData(); | |||
| self->midiOutBuffer.flush(); | |||
| } | |||
| #endif | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| LV2 KXStudio Properties Extension | |||
| Copyright 2014-2021 Filipe Coelho <falktx@falktx.com> | |||
| Copyright 2014-2024 Filipe Coelho <falktx@falktx.com> | |||
| Permission to use, copy, modify, and/or distribute this software for any | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -27,6 +27,7 @@ | |||
| #define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" | |||
| #define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" | |||
| #define LV2_KXSTUDIO_PROPERTIES__Reset LV2_KXSTUDIO_PROPERTIES_PREFIX "Reset" | |||
| #define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" | |||
| #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | |||
| @@ -0,0 +1,73 @@ | |||
| // Copyright 2025 Filipe Coelho <falktx@falktx.com> | |||
| // SPDX-License-Identifier: ISC | |||
| #pragma once | |||
| #ifdef __cplusplus | |||
| extern "C" { | |||
| # define MAPI_API extern "C" | |||
| #else | |||
| # define MAPI_API | |||
| #endif | |||
| /* Define MAPI_EXPORT for exporting function symbols */ | |||
| #ifdef _WIN32 | |||
| # define MAPI_EXPORT MAPI_API __declspec (dllexport) | |||
| #else | |||
| # define MAPI_EXPORT MAPI_API __attribute__ ((visibility("default"))) | |||
| #endif | |||
| /** Handle used through-out this API. */ | |||
| typedef void* mapi_handle_t; | |||
| /** | |||
| Create an effect. | |||
| @param sample_rate Sample rate in Hz to use for the effect. | |||
| @return A handle for the new effect, or NULL if creation failed. | |||
| */ | |||
| MAPI_EXPORT | |||
| mapi_handle_t mapi_create(unsigned int sample_rate); | |||
| /** | |||
| Process an effect. | |||
| @param handle A previously created effect. | |||
| @param ins An array of audio buffers used for audio input. | |||
| @param outs An array of audio buffers used for audio output. | |||
| @param frames How many frames to process. | |||
| @note Input and output buffers might share the same location in memory, | |||
| typically referred to as "in-place processing". | |||
| */ | |||
| MAPI_EXPORT | |||
| void mapi_process(mapi_handle_t handle, | |||
| const float* const* ins, | |||
| float** outs, | |||
| unsigned int frames); | |||
| /** | |||
| Set an effect parameter. | |||
| @param handle A previously created effect. | |||
| @param index A known index for this effect. | |||
| @param value A full-ranged value. | |||
| */ | |||
| MAPI_EXPORT | |||
| void mapi_set_parameter(mapi_handle_t handle, unsigned int index, float value); | |||
| /** | |||
| Set an effect state, using strings for both key and value. | |||
| @param handle A previously created effect. | |||
| @param key A known key for this effect, must not be NULL or empty. | |||
| @param value A non-NULL value, allowed to be empty. | |||
| */ | |||
| MAPI_EXPORT | |||
| void mapi_set_state(mapi_handle_t handle, const char* key, const char* value); | |||
| /** | |||
| Destroy a previously created effect. | |||
| @param handle A previously created effect. | |||
| */ | |||
| MAPI_EXPORT | |||
| void mapi_destroy(mapi_handle_t handle); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -1,6 +1,6 @@ | |||
| /* | |||
| * DISTRHO Plugin Framework (DPF) | |||
| * Copyright (C) 2012-2024 Filipe Coelho <falktx@falktx.com> | |||
| * Copyright (C) 2012-2025 Filipe Coelho <falktx@falktx.com> | |||
| * | |||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||
| @@ -33,10 +33,6 @@ | |||
| #define DISTRHO_UI_DEFAULT_WIDTH 768 | |||
| #define DISTRHO_UI_DEFAULT_HEIGHT 512 | |||
| // #ifdef _WIN32 | |||
| // #define WEB_VIEW_USING_CHOC 1 | |||
| // #endif | |||
| enum Parameters { | |||
| kParameterWidth = 0, | |||
| kParameterHeight, | |||
| @@ -0,0 +1,203 @@ | |||
| <!doctype html> | |||
| <html lang="en-us"> | |||
| <head> | |||
| <meta charset="utf-8"> | |||
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |||
| <meta name="description" content="@NAME@" /> | |||
| <meta name="theme-color" content="#111111"> | |||
| <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0" user-scalable="no"> | |||
| <title>@NAME@</title> | |||
| <style> | |||
| html { | |||
| background-color: #111111; | |||
| color: #eee; | |||
| overflow: hidden; | |||
| } | |||
| body, canvas { | |||
| padding: 0; | |||
| margin: 0; | |||
| } | |||
| #canvas_file_open { | |||
| display: none; | |||
| } | |||
| #canvas_wrapper { | |||
| --device-pixel-ratio: 1; | |||
| display: none; | |||
| image-rendering: pixelated; | |||
| image-rendering: crisp-edges; | |||
| position: fixed; | |||
| transform-origin: 0 0 0; | |||
| transform: scale(calc(1 / var(--device-pixel-ratio))); | |||
| width: 100vw; | |||
| height: 100vh; | |||
| /* center */ | |||
| margin: auto auto; | |||
| top: 0; | |||
| bottom: 0; | |||
| left: 0; | |||
| right: 0; | |||
| } | |||
| #error { | |||
| background: rgba(0,0,0,0.75); | |||
| display: none; | |||
| position: fixed; | |||
| padding: 0.5em; | |||
| left: 0; | |||
| right: 0; | |||
| width: 100%; | |||
| z-index: 2; | |||
| } | |||
| .emscripten { | |||
| display: block; | |||
| margin-left: auto; | |||
| margin-right: auto; | |||
| padding-right: 0; | |||
| text-align: center; | |||
| } | |||
| .spinner { | |||
| height: 50px; | |||
| width: 50px; | |||
| margin: 0px auto; | |||
| margin-top: 100px; | |||
| -webkit-animation: rotation .8s linear infinite; | |||
| -moz-animation: rotation .8s linear infinite; | |||
| -o-animation: rotation .8s linear infinite; | |||
| animation: rotation 0.8s linear infinite; | |||
| border-left: 10px solid rgb(0,150,240); | |||
| border-right: 10px solid rgb(0,150,240); | |||
| border-bottom: 10px solid rgb(0,150,240); | |||
| border-top: 10px solid rgb(100,0,200); | |||
| border-radius: 100%; | |||
| background-color: rgb(200,100,250); | |||
| } | |||
| @-webkit-keyframes rotation { | |||
| from {-webkit-transform: rotate(0deg);} | |||
| to {-webkit-transform: rotate(360deg);} | |||
| } | |||
| @-moz-keyframes rotation { | |||
| from {-moz-transform: rotate(0deg);} | |||
| to {-moz-transform: rotate(360deg);} | |||
| } | |||
| @-o-keyframes rotation { | |||
| from {-o-transform: rotate(0deg);} | |||
| to {-o-transform: rotate(360deg);} | |||
| } | |||
| @keyframes rotation { | |||
| from {transform: rotate(0deg);} | |||
| to {transform: rotate(360deg);} | |||
| } | |||
| </style> | |||
| </head> | |||
| <body> | |||
| <figure style="overflow:visible;" id="spinner"> | |||
| <div class="spinner"></div> | |||
| <center style="margin-top:0.5em"><strong>@NAME@</strong></center> | |||
| </figure> | |||
| <div class="emscripten" id="error"></div> | |||
| <div class="emscripten" id="status">Downloading...</div> | |||
| <div class="emscripten"> | |||
| <progress value="0" max="100" id="progress" hidden=1></progress> | |||
| </div> | |||
| <div id="canvas_wrapper"> | |||
| <input type="file" id="canvas_file_open" ></input> | |||
| <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas> | |||
| </div> | |||
| <script type='text/javascript'> | |||
| 'use strict'; | |||
| var wasmErrors = []; | |||
| var errorElement = document.getElementById('error'); | |||
| var statusElement = document.getElementById('status'); | |||
| var progressElement = document.getElementById('progress'); | |||
| var spinnerElement = document.getElementById('spinner'); | |||
| if (typeof(WebAssembly) === "undefined") { | |||
| wasmErrors.push('WebAssembly unsupported'); | |||
| } else { | |||
| if (!WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0,2,8,1,1,97,1,98,3,127,1,6,6,1,127,1,65,0,11,7,5,1,1,97,3,1]))) { | |||
| wasmErrors.push('Importable/Exportable mutable globals unsupported'); | |||
| } | |||
| } | |||
| if (wasmErrors.length !== 0) { | |||
| errorElement.innerHTML = 'Cannot start @NAME@:<br>' + wasmErrors.join('<br>') + '<br><br>Perhaps try a different browser?'; | |||
| errorElement.style.display = 'block'; | |||
| statusElement.style.display = 'none'; | |||
| progressElement.style.display = 'none'; | |||
| spinnerElement.style.display = 'none'; | |||
| } else { | |||
| var canvasWrapper = document.getElementById('canvas_wrapper'); | |||
| var Module = { | |||
| preRun: [], | |||
| postRun: function() { | |||
| statusElement.style.display = 'none'; | |||
| progressElement.style.display = 'none'; | |||
| spinnerElement.style.display = 'none'; | |||
| canvasWrapper.style.display = 'block'; | |||
| window.dispatchEvent(new Event('resize')); | |||
| }, | |||
| canvas: (function() { | |||
| var canvas = document.getElementById('canvas'); | |||
| // As a default initial behavior, pop up an alert when webgl context is lost. To make your | |||
| // application robust, you may want to override this behavior before shipping! | |||
| // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 | |||
| canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); | |||
| return canvas; | |||
| })(), | |||
| setStatus: function(text) { | |||
| if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; | |||
| if (text === Module.setStatus.last.text) return; | |||
| var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); | |||
| var now = Date.now(); | |||
| if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon | |||
| Module.setStatus.last.time = now; | |||
| Module.setStatus.last.text = text; | |||
| if (m) { | |||
| text = m[1]; | |||
| progressElement.value = parseInt(m[2])*100; | |||
| progressElement.max = parseInt(m[4])*100; | |||
| progressElement.hidden = false; | |||
| spinnerElement.hidden = false; | |||
| } else { | |||
| progressElement.value = null; | |||
| progressElement.max = null; | |||
| progressElement.hidden = true; | |||
| if (!text) spinnerElement.hidden = true; | |||
| } | |||
| statusElement.innerHTML = text; | |||
| }, | |||
| totalDependencies: 0, | |||
| monitorRunDependencies: function(left) { | |||
| this.totalDependencies = Math.max(this.totalDependencies, left); | |||
| Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); | |||
| } | |||
| }; | |||
| Module.setStatus('Downloading...'); | |||
| window.onerror = function(err) { | |||
| errorElement.innerHTML = 'Exception thrown:<br>' + err | |||
| errorElement.style.display = 'block'; | |||
| spinnerElement.style.display = 'none'; | |||
| Module.setStatus = function(text) { | |||
| if (text) console.error('[post-exception status] ' + text); | |||
| }; | |||
| }; | |||
| var jsModuleScript = document.createElement('script'); | |||
| jsModuleScript.setAttribute('async', true); | |||
| jsModuleScript.setAttribute('src', "@NAME@.js"); | |||
| jsModuleScript.setAttribute('type','text/javascript'); | |||
| document.head.appendChild(jsModuleScript); | |||
| } | |||
| </script> | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,77 @@ | |||
| #!/bin/bash | |||
| # the realpath function is not available on some systems | |||
| if ! which realpath &>/dev/null; then | |||
| function realpath() { | |||
| [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}" | |||
| } | |||
| fi | |||
| set -e | |||
| DPF_UTILS_DIR="$(dirname $(realpath ${0}))" | |||
| if [ -d bin ]; then | |||
| cd bin | |||
| elif [ -d build/bin ]; then | |||
| cd build/bin | |||
| else | |||
| echo "Please run this script from the root folder" | |||
| exit | |||
| fi | |||
| if [ "$(uname -s)" = "Darwin" ]; then | |||
| CLAP_PATH=~/Library/Audio/Plug-Ins/CLAP | |||
| LV2_PATH=~/Library/Audio/Plug-Ins/LV2 | |||
| VST2_PATH=~/Library/Audio/Plug-Ins/VST | |||
| VST3_PATH=~/Library/Audio/Plug-Ins/VST3 | |||
| else | |||
| CLAP_PATH=~/.clap | |||
| LV2_PATH=~/.lv2 | |||
| VST2_PATH=~/.vst | |||
| VST3_PATH=~/.vst3 | |||
| fi | |||
| export IFS=$'\n' | |||
| # NOTE macOS ignores AU plugins installed in ~/Library/Audio/Plug-Ins/Components/ | |||
| # we **MUST** install AU plugins system-wide, so we need sudo/root here | |||
| # they cannot be symlinks either, so we do a full copy | |||
| for p in $(find . -maxdepth 1 -name '*.component' -print | grep '.component'); do | |||
| basename=$(basename ${p}) | |||
| if [ ! -L /Library/Audio/Plug-Ins/Components/"${basename}" ]; then | |||
| sudo cp -r $(pwd)/"${basename}" /Library/Audio/Plug-Ins/Components/ | |||
| fi | |||
| done | |||
| for p in $(find . -maxdepth 1 -name '*.clap' -print); do | |||
| basename=$(basename ${p}) | |||
| mkdir -p ${CLAP_PATH} | |||
| if [ ! -L ${CLAP_PATH}/"${basename}" ]; then | |||
| ln -s $(pwd)/"${basename}" ${CLAP_PATH}/"${basename}" | |||
| fi | |||
| done | |||
| for p in $(find . -maxdepth 1 -name '*.lv2' -print); do | |||
| basename=$(basename ${p}) | |||
| mkdir -p ${LV2_PATH} | |||
| if [ ! -L ${LV2_PATH}/"${basename}" ]; then | |||
| ln -s $(pwd)/"${basename}" ${LV2_PATH}/"${basename}" | |||
| fi | |||
| done | |||
| for p in $(find . -maxdepth 1 -name '*.vst' -print); do | |||
| basename=$(basename ${p}) | |||
| mkdir -p ${VST2_PATH} | |||
| if [ ! -L ${VST2_PATH}/"${basename}" ]; then | |||
| ln -s $(pwd)/"${basename}" ${VST2_PATH}/"${basename}" | |||
| fi | |||
| done | |||
| for p in $(find . -maxdepth 1 -name '*.vst3' -print); do | |||
| basename=$(basename ${p}) | |||
| mkdir -p ${VST3_PATH} | |||
| if [ ! -L ${VST3_PATH}/"${basename}" ]; then | |||
| ln -s $(pwd)/"${basename}" ${VST3_PATH}/"${basename}" | |||
| fi | |||
| done | |||
| @@ -0,0 +1,6 @@ | |||
| EXPORTS | |||
| mapi_create | |||
| mapi_process | |||
| mapi_set_parameter | |||
| mapi_set_state | |||
| mapi_destroy | |||
| @@ -0,0 +1,5 @@ | |||
| _mapi_create | |||
| _mapi_process | |||
| _mapi_set_parameter | |||
| _mapi_set_state | |||
| _mapi_destroy | |||
| @@ -0,0 +1,4 @@ | |||
| { | |||
| global: mapi_create; mapi_process; mapi_set_parameter; mapi_set_state; mapi_destroy; | |||
| local: *; | |||
| }; | |||
| @@ -1,2 +0,0 @@ | |||
| EXPORTS | |||
| createSharedPlugin | |||
| @@ -1 +0,0 @@ | |||
| _createSharedPlugin | |||
| @@ -1,4 +0,0 @@ | |||
| { | |||
| global: createSharedPlugin; | |||
| local: *; | |||
| }; | |||
| @@ -93,3 +93,27 @@ | |||
| fun:fftwf_plan_dft_r2c_1d | |||
| ... | |||
| } | |||
| { | |||
| leak in fftw plan | |||
| Memcheck:Leak | |||
| fun:malloc | |||
| fun:fftwf_malloc_plain | |||
| ... | |||
| fun:fftwf_mkapiplan | |||
| fun:fftwf_plan_many_r2r | |||
| fun:fftwf_plan_r2r | |||
| fun:fftwf_plan_r2r_1d | |||
| ... | |||
| } | |||
| { | |||
| leak in fftw plan | |||
| Memcheck:Leak | |||
| fun:memalign | |||
| fun:fftwf_malloc_plain | |||
| ... | |||
| fun:fftwf_mkapiplan | |||
| fun:fftwf_plan_many_r2r | |||
| fun:fftwf_plan_r2r | |||
| fun:fftwf_plan_r2r_1d | |||
| ... | |||
| } | |||