Browse Source

Update to latest DPF

Signed-off-by: falktx@falktx.com <falkTX>
main
falktx@falktx.com 9 months ago
parent
commit
f42469deb2
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
100 changed files with 17843 additions and 1321 deletions
  1. +2
    -2
      Makefile
  2. +5
    -5
      dpf/CMakeLists.txt
  3. +23
    -23
      dpf/FEATURES.md
  4. +11
    -10
      dpf/LICENSE
  5. +10
    -9
      dpf/LICENSING.md
  6. +149
    -15
      dpf/Makefile.base.mk
  7. +140
    -30
      dpf/Makefile.plugins.mk
  8. +352
    -47
      dpf/cmake/DPF-plugin.cmake
  9. +36
    -1
      dpf/dgl/Application.hpp
  10. +49
    -16
      dpf/dgl/Base.hpp
  11. +4
    -2
      dpf/dgl/EventHandlers.hpp
  12. +1
    -0
      dpf/dgl/ImageBaseWidgets.hpp
  13. +4
    -8
      dpf/dgl/Makefile
  14. +1
    -0
      dpf/dgl/StandaloneWindow.hpp
  15. +2
    -2
      dpf/dgl/Widget.hpp
  16. +7
    -6
      dpf/dgl/Window.hpp
  17. +70
    -2
      dpf/dgl/src/Application.cpp
  18. +33
    -9
      dpf/dgl/src/ApplicationPrivateData.cpp
  19. +6
    -0
      dpf/dgl/src/ApplicationPrivateData.hpp
  20. +7
    -7
      dpf/dgl/src/Cairo.cpp
  21. +10
    -5
      dpf/dgl/src/EventHandlers.cpp
  22. +7
    -0
      dpf/dgl/src/ImageBaseWidgets.cpp
  23. +13
    -13
      dpf/dgl/src/Layout.cpp
  24. +11
    -11
      dpf/dgl/src/OpenGL.cpp
  25. +193
    -0
      dpf/dgl/src/Stub.cpp
  26. +2
    -2
      dpf/dgl/src/SubWidget.cpp
  27. +43
    -23
      dpf/dgl/src/Window.cpp
  28. +23
    -17
      dpf/dgl/src/WindowPrivateData.cpp
  29. +11
    -7
      dpf/dgl/src/WindowPrivateData.hpp
  30. +2
    -0
      dpf/dgl/src/pugl-upstream/.clang-tidy
  31. +19
    -14
      dpf/dgl/src/pugl-upstream/include/pugl/pugl.h
  32. +13
    -5
      dpf/dgl/src/pugl-upstream/src/common.c
  33. +6
    -0
      dpf/dgl/src/pugl-upstream/src/internal.c
  34. +39
    -24
      dpf/dgl/src/pugl-upstream/src/mac.m
  35. +1
    -3
      dpf/dgl/src/pugl-upstream/src/mac_cairo.m
  36. +44
    -23
      dpf/dgl/src/pugl-upstream/src/win.c
  37. +1
    -1
      dpf/dgl/src/pugl-upstream/src/win_gl.c
  38. +1
    -1
      dpf/dgl/src/pugl-upstream/src/win_vulkan.c
  39. +52
    -31
      dpf/dgl/src/pugl-upstream/src/x11.c
  40. +35
    -18
      dpf/dgl/src/pugl.cpp
  41. +56
    -43
      dpf/distrho/DistrhoDetails.hpp
  42. +54
    -21
      dpf/distrho/DistrhoInfo.hpp
  43. +56
    -4
      dpf/distrho/DistrhoPlugin.hpp
  44. +392
    -0
      dpf/distrho/DistrhoPluginInfo.h.template
  45. +6
    -2
      dpf/distrho/DistrhoPluginMain.cpp
  46. +6
    -4
      dpf/distrho/DistrhoPluginUtils.hpp
  47. +8
    -55
      dpf/distrho/DistrhoUI.hpp
  48. +20
    -2
      dpf/distrho/DistrhoUIMain.cpp
  49. +19
    -8
      dpf/distrho/DistrhoUI_macOS.mm
  50. +27
    -0
      dpf/distrho/DistrhoUI_win32.cpp
  51. +108
    -22
      dpf/distrho/DistrhoUtils.hpp
  52. +276
    -0
      dpf/distrho/extra/ChildProcess.hpp
  53. +42
    -3
      dpf/distrho/extra/FileBrowserDialogImpl.cpp
  54. +8
    -4
      dpf/distrho/extra/FileBrowserDialogImpl.hpp
  55. +89
    -2
      dpf/distrho/extra/RingBuffer.hpp
  56. +7
    -3
      dpf/distrho/extra/Sleep.hpp
  57. +4
    -18
      dpf/distrho/extra/String.hpp
  58. +127
    -0
      dpf/distrho/extra/Time.hpp
  59. +28
    -0
      dpf/distrho/extra/WebView.hpp
  60. +1493
    -0
      dpf/distrho/extra/WebViewImpl.cpp
  61. +126
    -0
      dpf/distrho/extra/WebViewImpl.hpp
  62. +101
    -0
      dpf/distrho/extra/WebViewWin32.hpp
  63. +15
    -0
      dpf/distrho/extra/choc/LICENSE.md
  64. +22
    -0
      dpf/distrho/extra/choc/README.md
  65. +2803
    -0
      dpf/distrho/extra/choc/choc.patch
  66. +154
    -0
      dpf/distrho/extra/choc/choc_DesktopWindow.h
  67. +141
    -0
      dpf/distrho/extra/choc/choc_DynamicLibrary.h
  68. +511
    -0
      dpf/distrho/extra/choc/choc_MemoryDLL.h
  69. +67
    -0
      dpf/distrho/extra/choc/choc_Platform.h
  70. +74
    -0
      dpf/distrho/extra/choc/choc_StringUtilities.h
  71. +4769
    -0
      dpf/distrho/extra/choc/choc_WebView.h
  72. +3
    -0
      dpf/distrho/src/DistrhoDefines.h
  73. +2
    -1
      dpf/distrho/src/DistrhoPlugin.cpp
  74. +3205
    -0
      dpf/distrho/src/DistrhoPluginAU.cpp
  75. +19
    -27
      dpf/distrho/src/DistrhoPluginCLAP.cpp
  76. +126
    -45
      dpf/distrho/src/DistrhoPluginChecks.h
  77. +281
    -0
      dpf/distrho/src/DistrhoPluginExport.cpp
  78. +47
    -10
      dpf/distrho/src/DistrhoPluginInternal.hpp
  79. +42
    -15
      dpf/distrho/src/DistrhoPluginJACK.cpp
  80. +13
    -25
      dpf/distrho/src/DistrhoPluginLV2.cpp
  81. +10
    -8
      dpf/distrho/src/DistrhoPluginLV2export.cpp
  82. +4
    -14
      dpf/distrho/src/DistrhoPluginVST.hpp
  83. +29
    -37
      dpf/distrho/src/DistrhoPluginVST2.cpp
  84. +33
    -34
      dpf/distrho/src/DistrhoPluginVST3.cpp
  85. +243
    -107
      dpf/distrho/src/DistrhoUI.cpp
  86. +502
    -0
      dpf/distrho/src/DistrhoUIAU.mm
  87. +22
    -4
      dpf/distrho/src/DistrhoUIDSSI.cpp
  88. +24
    -55
      dpf/distrho/src/DistrhoUIInternal.hpp
  89. +4
    -1
      dpf/distrho/src/DistrhoUILV2.cpp
  90. +60
    -119
      dpf/distrho/src/DistrhoUIPrivateData.hpp
  91. +9
    -173
      dpf/distrho/src/DistrhoUIVST3.cpp
  92. +13
    -5
      dpf/distrho/src/DistrhoUtils.cpp
  93. +2
    -2
      dpf/distrho/src/jackbridge/JackBridge.cpp
  94. +4
    -4
      dpf/distrho/src/jackbridge/NativeBridge.hpp
  95. +7
    -0
      dpf/utils/au-services-restart.sh
  96. +10
    -4
      dpf/utils/generate-ttl.sh
  97. +64
    -27
      dpf/utils/package-osx-bundles.sh
  98. +17
    -16
      dpf/utils/plugin.pkg/package.xml.in
  99. +1
    -0
      dpf/utils/symbols/au.exp
  100. +0
    -5
      plugins/3BandEQ/DistrhoPlugin3BandEQ.hpp

+ 2
- 2
Makefile View File

@@ -28,9 +28,9 @@ endif

dgl:
ifeq ($(HAVE_CAIRO_OR_OPENGL),true)
$(MAKE) FILE_BROWSER_DISABLED=true -C dpf/dgl
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl
ifeq ($(HAVE_OPENGL),true)
$(MAKE) FILE_BROWSER_DISABLED=true -C dpf/dgl opengl3
$(MAKE) USE_FILE_BROWSER=false -C dpf/dgl opengl3
endif
endif



+ 5
- 5
dpf/CMakeLists.txt View File

@@ -1,5 +1,6 @@
# DISTRHO Plugin Framework (DPF)
# Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
# Copyright (C) 2022-2024 Filipe Coelho <falktx@falktx.com>
#
# SPDX-License-Identifier: ISC

@@ -33,10 +34,11 @@ if(DPF_LIBRARIES)
if(PKG_CONFIG_FOUND)
pkg_check_modules(CAIRO "cairo")
if(CAIRO_FOUND AND (NOT HAIKU))
dpf__add_dgl_cairo(FALSE)
dpf__add_dgl_cairo(TRUE, TRUE)
endif()
endif()
dpf__add_dgl_opengl(FALSE)
dpf__add_dgl_external(TRUE)
dpf__add_dgl_opengl(TRUE, TRUE)
endif()

if(DPF_EXAMPLES)
@@ -47,9 +49,6 @@ if(DPF_EXAMPLES)
add_subdirectory("examples/CairoUI")
endif()
endif()
if((NOT WIN32) AND (NOT APPLE))
add_subdirectory("examples/ExternalUI")
endif()
add_subdirectory("examples/EmbedExternalUI")
add_subdirectory("examples/FileHandling")
add_subdirectory("examples/Info")
@@ -58,4 +57,5 @@ if(DPF_EXAMPLES)
add_subdirectory("examples/MidiThrough")
add_subdirectory("examples/Parameters")
add_subdirectory("examples/States")
add_subdirectory("examples/WebMeters")
endif()

+ 23
- 23
dpf/FEATURES.md View File

@@ -4,29 +4,29 @@ This file describes the available features for each plugin format.
The limitations could be due to the plugin format itself or within DPF.
If the limitation is within DPF, a link is provided to a description below on the reason for it.

| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | CLAP | Feature |
|---------------------|---------------------------------------|--------------------|---------------------|-------------------------------|----------------------------|----------------------------|-------------------------------|---------------------|
| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | Yes | Yes | Audio port groups |
| Audio port as CV | Yes | No | No | Yes | No | [Yes*](#vst3-cv) | [No*](#work-in-progress) | Audio port as CV |
| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Audio sidechan |
| Bypass control | No | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Bypass control |
| MIDI input | Yes | No | Yes | Yes | Yes | Yes | Yes | MIDI input |
| MIDI output | Yes | No | No | Yes | Yes | Yes | Yes | MIDI output |
| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Yes | Parameter changes |
| Parameter groups | No | No | No | Yes | Yes | [No*](#work-in-progress) | Yes | Parameter groups |
| Parameter outputs | No | No | No | Yes | No | Yes | Yes | Parameter outputs |
| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers |
| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-rdf) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | No | Programs |
| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | Yes | States |
| Full/internal state | Yes | No | No | Yes | Yes | Yes | Yes | Full/internal state |
| Time position | Yes | No | No | Yes | Yes | Yes | Yes | Time position |
| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | Yes | UI |
| UI bg/fg colors | No | No | No | Yes | No | No? | No | UI bg/fg colors |
| UI direct access | Yes | No | No | Yes | Yes | Yes | Yes | UI direct access |
| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-deprecated) | [No*](#work-in-progress) | [No*](#work-in-progress) | UI host-filebrowser |
| UI host-resize | Yes | No | Yes | Yes | No | Yes | Yes | UI host-resize |
| UI remote control | No | No | Yes | Yes | No | Yes | No | UI remote control |
| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | Yes | UI send midi note |
| Feature | JACK/Standalone | LADSPA | DSSI | LV2 | VST2 | VST3 | CLAP | AU | Feature |
|---------------------|---------------------------------------|--------------------|---------------------|-------------------------------|----------------------------|----------------------------|----------------------------|----------------------------|---------------------|
| Audio port groups | [Yes*](#jack-audio-port-groups) | No | No | Yes | No | Yes | Yes | [No*](#work-in-progress) | Audio port groups |
| Audio port as CV | Yes | No | No | Yes | No | [Yes*](#vst3-cv) | [No*](#work-in-progress) | No | Audio port as CV |
| Audio sidechan | Yes | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | [No*](#work-in-progress) | Audio sidechan |
| Bypass control | No | No | No | Yes | [No*](#vst2-deprecated) | Yes | Yes | Yes | Bypass control |
| MIDI input | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes | MIDI input |
| MIDI output | Yes | No | No | Yes | Yes | Yes | Yes | Yes | MIDI output |
| Parameter changes | Yes | No | No | [No*](#lv2-parameter-changes) | Yes | Yes | Yes | Yes | Parameter changes |
| Parameter groups | No | No | No | Yes | Yes | [No*](#work-in-progress) | Yes | [No*](#work-in-progress) | Parameter groups |
| Parameter outputs | No | No | No | Yes | No | Yes | Yes | Yes | Parameter outputs |
| Parameter triggers | Yes | No | No | Yes | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | [No*](#parameter-triggers) | Parameter triggers |
| Programs | [Yes*](#jack-parameters-and-programs) | [No*](#ladspa-rdf) | [Yes*](#dssi-state) | Yes | [No*](#vst2-programs) | Yes | No | Yes | Programs |
| States | Yes | No | [Yes*](#dssi-state) | Yes | Yes | Yes | Yes | Yes | States |
| Full/internal state | Yes | No | No | Yes | Yes | Yes | Yes | Yes | Full/internal state |
| Time position | Yes | No | No | Yes | Yes | Yes | Yes | Yes | Time position |
| UI | [Yes*](#jack-custom-ui-only) | No | External only | Yes | Embed only | Embed only | Yes | Embed only | UI |
| UI bg/fg colors | No | No | No | Yes | No | No? | No | No | UI bg/fg colors |
| UI direct access | Yes | No | No | Yes | Yes | Yes | Yes | Yes | UI direct access |
| UI host-filebrowser | No | No | No | Yes | [No*](#vst2-deprecated) | [No*](#work-in-progress) | [No*](#work-in-progress) | No | UI host-filebrowser |
| UI host-resize | Yes | No | Yes | Yes | No | Yes | Yes | No | UI host-resize |
| UI remote control | No | No | Yes | Yes | No | Yes | No | Yes | UI remote control |
| UI send midi note | Yes | No | Yes | Yes | Yes | Yes | Yes | Yes | UI send midi note |

For things that could be unclear:



+ 11
- 10
dpf/LICENSE View File

@@ -1,12 +1,13 @@
Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
Copyright (C) 2012-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 copyright notice and this
permission notice appear in all copies.
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.
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.

+ 10
- 9
dpf/LICENSING.md View File

@@ -7,15 +7,16 @@ This file describes the licensing that applies to each individual plugin format
Regardless of target format, DPF itself needs to be mentioned in attribution.
See the [LICENSE](LICENSE) file for copyright details.

| Target | License(s) | License restrictions | Additional attribution |
|-----------------|----------------------|-----------------------|------------------------|
| JACK/Standalone | MIT (RtAudio) | Copyright attribution | **RtAudio**: 2001-2019 Gary P. Scavone |
| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld |
| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;<br/> **ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai |
| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;<br/> 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld |
| VST2 | BSD-3 | Copyright attribution | 2020-2022 Michael Fabian 'Xaymar' Dirks |
| VST3 | ISC | Copyright attribution | (none, only DPF files used) |
| CLAP | MIT | Copyright attribution | 2014-2022 Alexandre Bique |
| Target | License(s) | License restrictions | Additional attribution |
|-----------------|-----------------------|-----------------------|-----------------------------------------|
| JACK/Standalone | MIT (RtAudio, RtMidi) | Copyright attribution | **RtAudio**: 2001-2021 Gary P. Scavone |
| LADSPA | LGPLv2.1+ | ??? (*) | 2000-2002 Richard W. E. Furse, Paul Barton-Davis, Stefan Westerfeld |
| DSSI | LGPLv2.1+ | ??? (*) | **DSSI**: 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton;<br/> **ALSA**: 1998-2001 Jaroslav Kysela, Abramo Bagnara, Takashi Iwai |
| LV2 | ISC | Copyright attribution | 2006-2020 Steve Harris, David Robillard;<br/> 2000-2002 Richard W.E. Furse, Paul Barton-Davis, Stefan Westerfeld |
| VST2 | BSD-3 | Copyright attribution | 2020-2022 Michael Fabian 'Xaymar' Dirks |
| VST3 | ISC | Copyright attribution | (none, only DPF files used) |
| CLAP | MIT | Copyright attribution | 2014-2022 Alexandre Bique |
| AU | ISC | Copyright attribution | (none, only DPF files used) |

### LADSPA and DSSI special note



+ 149
- 15
dpf/Makefile.base.mk View File

@@ -4,15 +4,22 @@
# Created by falkTX
#

AR ?= ar
CC ?= gcc
CXX ?= g++

# Before including this file, a few variables can be set in order to tweak build behaviour:

# DEBUG=true
# Building in debug mode
# Implies SKIP_STRIPPING=true as well

# NOOPT=true
# Do not automatically set optimization flags

# SKIP_STRIPPING=true
# Do not strip output binaries

# NVG_DISABLE_SKIPPING_WHITESPACE=true
# Tweak `nvgTextBreakLines` to allow space characters
# FIXME proper details

# NVG_FONT_TEXTURE_FLAGS=0
# FILE_BROWSER_DISABLED=true
# WINDOWS_ICON_ID=0
@@ -21,9 +28,25 @@ CXX ?= g++
# USE_OPENGL3=true
# USE_NANOVG_FBO=true
# USE_NANOVG_FREETYPE=true
# USE_FILE_BROWSER=true
# USE_WEB_VIEW=true

# STATIC_BUILD=true
# Tweak build to be able to generate fully static builds (e.g. skip use of libdl)
# Experimental, use only if you know what you are doing

# FORCE_NATIVE_AUDIO_FALLBACK=true
# Do not use JACK for the standalone, only native audio

# SKIP_NATIVE_AUDIO_FALLBACK=true
# Do not use native audio for the standalone, only use JACK

# ---------------------------------------------------------------------------------------------------------------------
# Read target compiler from environment

AR ?= ar
CC ?= gcc
CXX ?= g++

# ---------------------------------------------------------------------------------------------------------------------
# Protect against multiple inclusion
@@ -212,6 +235,27 @@ ifeq ($(MACOS),true)
UNIX = true
endif

# ---------------------------------------------------------------------------------------------------------------------
# Compatibility checks

ifeq ($(FILE_BROWSER_DISABLED),true)
$(error FILE_BROWSER_DISABLED has been replaced by USE_FILE_BROWSER (opt-in vs opt-out))
endif

ifeq ($(USE_FILEBROWSER),true)
$(error typo detected use USE_FILE_BROWSER instead of USE_FILEBROWSER)
endif

ifeq ($(USE_WEBVIEW),true)
$(error typo detected use USE_WEB_VIEW instead of USE_WEBVIEW)
endif

# ---------------------------------------------------------------------------------------------------------------------
# Set optional flags

USE_FILE_BROWSER ?= true
USE_WEB_VIEW ?= false

# ---------------------------------------------------------------------------------------------------------------------
# Set build and link flags

@@ -250,7 +294,9 @@ BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse
endif

ifeq ($(MACOS),true)
ifneq ($(MACOS_NO_DEAD_STRIP),true)
LINK_OPTS += -Wl,-dead_strip,-dead_strip_dylibs
endif
else ifeq ($(WASM),true)
LINK_OPTS += -O3
LINK_OPTS += -Wl,--gc-sections
@@ -416,6 +462,9 @@ else ifeq ($(MACOS),true)

DGL_SYSTEM_LIBS += -framework Cocoa
DGL_SYSTEM_LIBS += -framework CoreVideo
ifeq ($(USE_WEB_VIEW),true)
DGL_SYSTEM_LIBS += -framework WebKit
endif

else ifeq ($(WASM),true)

@@ -430,13 +479,19 @@ DGL_SYSTEM_LIBS += -lcomdlg32
DGL_SYSTEM_LIBS += -ldwmapi
DGL_SYSTEM_LIBS += -lgdi32
# DGL_SYSTEM_LIBS += -lole32
ifeq ($(USE_WEB_VIEW),true)
DGL_SYSTEM_LIBS += -lole32
DGL_SYSTEM_LIBS += -luuid
endif

else

ifneq ($(FILE_BROWSER_DISABLED),true)
ifeq ($(HAVE_DBUS),true)
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
@@ -453,6 +508,10 @@ ifeq ($(HAVE_XRANDR),true)
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xrandr) -DHAVE_XRANDR
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xrandr)
endif
ifeq ($(USE_WEB_VIEW),true)
DGL_FLAGS += -pthread
DGL_SYSTEM_LIBS += -pthread -lrt
endif
endif # HAVE_X11

endif
@@ -563,11 +622,11 @@ SHARED_MEMORY_LIBS = -lrt
endif

# ---------------------------------------------------------------------------------------------------------------------
# Backwards-compatible HAVE_DGL
# Generic HAVE_DGL

ifeq ($(HAIKU_OR_MACOS_OR_WASM_OR_WINDOWS),true)
HAVE_DGL = true
else ifeq ($(HAVE_OPENGL),true)
else
HAVE_DGL = $(HAVE_X11)
endif

@@ -593,10 +652,6 @@ ifneq ($(NVG_FONT_TEXTURE_FLAGS),)
BUILD_CXX_FLAGS += -DNVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS)
endif

ifeq ($(FILE_BROWSER_DISABLED),true)
BUILD_CXX_FLAGS += -DDGL_FILE_BROWSER_DISABLED
endif

ifneq ($(WINDOWS_ICON_ID),)
BUILD_CXX_FLAGS += -DDGL_WINDOWS_ICON_ID=$(WINDOWS_ICON_ID)
endif
@@ -633,6 +688,14 @@ ifeq ($(USE_RGBA),true)
BUILD_CXX_FLAGS += -DDGL_USE_RGBA
endif

ifeq ($(USE_FILE_BROWSER),true)
BUILD_CXX_FLAGS += -DDGL_USE_FILE_BROWSER
endif

ifeq ($(USE_WEB_VIEW),true)
BUILD_CXX_FLAGS += -DDGL_USE_WEB_VIEW
endif

# ---------------------------------------------------------------------------------------------------------------------
# Set app extension

@@ -688,7 +751,9 @@ endif
# Set VST3 binary directory, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html

ifeq ($(LINUX),true)
VST3_BINARY_DIR = Contents/$(TARGET_PROCESSOR)-linux
# This must match `uname -m`, which differs from `gcc -dumpmachine` on PowerPC.
VST3_ARCHITECTURE := $(patsubst powerpc%,ppc%,$(TARGET_PROCESSOR))
VST3_BINARY_DIR = Contents/$(VST3_ARCHITECTURE)-linux
else ifeq ($(MACOS),true)
VST3_BINARY_DIR = Contents/MacOS
else ifeq ($(WASM),true)
@@ -796,30 +861,99 @@ MOD_ENVIRONMENT = \
modduo:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-static,arm-mod-linux-gnueabihf.static,arm)

modduo-new:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduo-new,arm-modaudio-linux-gnueabihf,arm)

modduox:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-static,aarch64-mod-linux-gnueabi.static,aarch64)

modduox-new:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/modduox-new,aarch64-modaudio-linux-gnueabi,aarch64)

moddwarf:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf,aarch64-mod-linux-gnu,aarch64)

moddwarf-new:
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_WORKDIR)/moddwarf-new,aarch64-modaudio-linux-gnu,aarch64)

modpush:
tar -C bin -cz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo
tar -C bin -chz $(subst bin/,,$(wildcard bin/*.lv2)) | base64 | curl -F 'package=@-' http://192.168.51.1/sdk/install && echo

ifneq (,$(findstring modduo-,$(MAKECMDGOALS)))
ifneq (,$(findstring modduo-new-,$(MAKECMDGOALS)))
$(MAKECMDGOALS):
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_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))
endif

ifneq (,$(findstring modduox-,$(MAKECMDGOALS)))
ifneq (,$(findstring modduox-new-,$(MAKECMDGOALS)))
$(MAKECMDGOALS):
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_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))
endif

ifneq (,$(findstring moddwarf-,$(MAKECMDGOALS)))
ifneq (,$(findstring moddwarf-new-,$(MAKECMDGOALS)))
$(MAKECMDGOALS):
$(MAKE) $(call MOD_ENVIRONMENT,$(MOD_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))
endif

# ---------------------------------------------------------------------------------------------------------------------
# Convenience rules for common builds

macos-intel-10.8:
$(MAKE) \
CFLAGS="$(CFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.8" \
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.8 -stdlib=libc++" \
LDFLAGS="$(LDFLAGS) -stdlib=libc++" \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

macos-universal-10.8:
$(MAKE) \
CFLAGS="$(CFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.15" \
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_8 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_8 -mmacosx-version-min=10.15 -stdlib=libc++" \
LDFLAGS="$(LDFLAGS) -stdlib=libc++" \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

macos-intel-10.15:
$(MAKE) \
CFLAGS="$(CFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

macos-universal-10.15:
$(MAKE) \
CFLAGS="$(CFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \
CXXFLAGS="$(CXXFLAGS) -arch x86_64 -arch arm64 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_15 -DMAC_OS_X_VERSION_MIN_REQUIRED=MAC_OS_X_VERSION_10_15 -mmacosx-version-min=10.15" \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

mingw32:
$(MAKE) \
AR=i686-w64-mingw32-ar \
CC=i686-w64-mingw32-gcc \
CXX=i686-w64-mingw32-g++ \
EXE_WRAPPER=wine \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

mingw64:
$(MAKE) \
AR=x86_64-w64-mingw32-ar \
CC=x86_64-w64-mingw32-gcc \
CXX=x86_64-w64-mingw32-g++ \
EXE_WRAPPER=wine \
PKG_CONFIG=/usr/bin/false \
PKG_CONFIG_PATH=/NOT

# ---------------------------------------------------------------------------------------------------------------------
# Protect against multiple inclusion



+ 140
- 30
dpf/Makefile.plugins.mk View File

@@ -1,27 +1,75 @@
#!/usr/bin/make -f
# Makefile for DPF Example Plugins #
# -------------------------------- #
# Makefile for DPF #
# ---------------- #
# Created by falkTX
#

# NOTE: NAME, FILES_DSP and FILES_UI must have been defined before including this file!

# 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)

# 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

# NOTE the "lv2" target refers to a monolithic build (dsp and ui combined),
# while "lv2_sep" target has dsp and ui in separate binaries.
# use of this target must match the definition of `DISTRHO_PLUGIN_WANT_DIRECT_ACCESS`

# ---------------------------------------------------------------------------------------------------------------------
# Try to figure out where DPF is located

ifeq ($(DPF_PATH),)
ifneq (,$(wildcard dpf/Makefile.base.mk))
BASE_PATH=.
DPF_PATH=dpf
else ifneq (,$(wildcard ../dpf/Makefile.base.mk))
BASE_PATH=..
DPF_PATH=../dpf
else ifneq (,$(wildcard ../../dpf/Makefile.base.mk))
BASE_PATH=../..
DPF_PATH=../../dpf

# find path to this makefile
DPF_PLUGINS_MAKEFILE = $(lastword $(filter %Makefile.plugins.mk,$(MAKEFILE_LIST)))

# error out if wrongly named or referencing it without any path
ifeq (,$(findstring /Makefile.plugins.mk,$(DPF_PLUGINS_MAKEFILE)))
$(error wrong inclusion of Makefile.plugins.mk, must be either absolute or relative path)
endif

# find path to DPF
DPF_PATH = $(patsubst %/Makefile.plugins.mk,%,$(DPF_PLUGINS_MAKEFILE))

# best guess for where to place binary files
ifeq ($(DPF_PATH),..)
BASE_PATH = $(DPF_PATH)
else ifeq ($(DPF_PATH),../..)
BASE_PATH = $(DPF_PATH)
else ifeq ($(DPF_PATH),../../..)
BASE_PATH = $(DPF_PATH)
else
BASE_PATH=../..
DPF_PATH=../..
BASE_PATH = $(patsubst %/,%,$(dir $(DPF_PATH)))
endif

endif

# ---------------------------------------------------------------------------------------------------------------------
# Check for proper UI_TYPE parameter

ifeq ($(UI_TYPE),)
else ifeq ($(UI_TYPE),cairo)
else ifeq ($(UI_TYPE),external)
else ifeq ($(UI_TYPE),generic)
else ifeq ($(UI_TYPE),opengl)
else ifeq ($(UI_TYPE),opengl3)
USE_OPENGL3 = true
else ifeq ($(UI_TYPE),vulkan)
else ifeq ($(UI_TYPE),webview)
USE_CLAP_BUNDLE = true
USE_VST2_BUNDLE = true
USE_WEB_VIEW = true
else
$(error unknown UI_TYPE $(UI_TYPE))
endif

# ---------------------------------------------------------------------------------------------------------------------
# Include DPF base setup

include $(DPF_PATH)/Makefile.base.mk

# ---------------------------------------------------------------------------------------------------------------------
@@ -140,6 +188,8 @@ OBJS_UI = $(FILES_UI:%=$(BUILD_DIR)/%.o)

ifeq ($(MACOS),true)
OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o
else ifeq ($(WINDOWS)$(USE_WEB_VIEW),truetrue)
OBJS_UI += $(BUILD_DIR)/DistrhoUI_win32.cpp.o
endif

# ---------------------------------------------------------------------------------------------------------------------
@@ -159,6 +209,9 @@ ifeq ($(HAVE_OPENGL),true)
UI_TYPE = opengl
else ifeq ($(HAVE_CAIRO),true)
UI_TYPE = cairo
else
HAVE_DGL = false
UI_TYPE = none
endif
endif

@@ -211,12 +264,22 @@ endif
endif

ifeq ($(UI_TYPE),external)
DGL_FLAGS += -DDGL_EXTERNAL
DGL_FLAGS += -DDGL_EXTERNAL -DHAVE_DGL
ifeq ($(HAVE_STUB),true)
DGL_FLAGS += $(STUB_FLAGS)
DGL_LIBS += $(STUB_LIBS)
DGL_LIB = $(DGL_BUILD_DIR)/libdgl-stub.a
HAVE_DGL = true
else
HAVE_DGL = false
endif
endif

ifeq ($(UI_TYPE),stub)
ifeq ($(UI_TYPE),webview)
DGL_FLAGS += -DDGL_EXTERNAL -DHAVE_DGL
ifeq ($(HAVE_STUB),true)
DGL_FLAGS += $(STUB_FLAGS)
DGL_LIBS += $(STUB_LIBS)
DGL_LIB = $(DGL_BUILD_DIR)/libdgl-stub.a
HAVE_DGL = true
else
@@ -224,6 +287,10 @@ HAVE_DGL = false
endif
endif

ifeq ($(HAVE_DGL)$(LINUX)$(USE_WEB_VIEW),truetruetrue)
DGL_LIB_SHARED = $(shell $(CC) -print-file-name=Scrt1.o)
endif

DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm

# TODO split dsp and ui object build flags
@@ -296,6 +363,8 @@ static = $(TARGET_DIR)/$(NAME).a

ifeq ($(MACOS),true)
BUNDLE_RESOURCES = Info.plist PkgInfo Resources/empty.lproj
au = $(TARGET_DIR)/$(NAME).component/Contents/MacOS/$(NAME)
aufiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).component/Contents/%)
vst2files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst/Contents/%)
vst3files += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).vst3/Contents/%)
clapfiles += $(BUNDLE_RESOURCES:%=$(TARGET_DIR)/$(NAME).clap/Contents/%)
@@ -316,6 +385,7 @@ endif
# Set plugin symbols to export

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_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp
SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp
@@ -410,10 +480,11 @@ ifeq ($(DPF_BUILD_DIR),)
endif
rm -rf $(TARGET_DIR)/$(NAME)
rm -rf $(TARGET_DIR)/$(NAME)-*
rm -rf $(TARGET_DIR)/$(NAME).clap
rm -rf $(TARGET_DIR)/$(NAME).component
rm -rf $(TARGET_DIR)/$(NAME).lv2
rm -rf $(TARGET_DIR)/$(NAME).vst
rm -rf $(TARGET_DIR)/$(NAME).vst3
rm -rf $(TARGET_DIR)/$(NAME).clap

# ---------------------------------------------------------------------------------------------------------------------
# DGL
@@ -458,15 +529,18 @@ $(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm $(EX
@echo "Compiling DistrhoUI_macOS.mm ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@

$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_DSP_DEPENDENCIES)
$(BUILD_DIR)/DistrhoUI_win32.cpp.o: $(DPF_PATH)/distrho/DistrhoUI_win32.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoPluginMain.cpp (JACK)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@
@echo "Compiling DistrhoUI_win32.cpp ($*)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -std=gnu++17 -c -o $@

$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) $(EXTRA_UI_DEPENDENCIES)
-@mkdir -p $(BUILD_DIR)
@echo "Compiling DistrhoUIMain.cpp (DSSI)"
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI $(LIBLO_FLAGS) -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)/DistrhoUIMain_AU.cpp.o: BUILD_CXX_FLAGS += -ObjC++

$(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: BUILD_CXX_FLAGS += $(LIBLO_FLAGS)

# ---------------------------------------------------------------------------------------------------------------------
# JACK
@@ -517,9 +591,9 @@ 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)
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
else
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
$(lv2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@echo "Creating LV2 plugin for $(NAME)"
@@ -530,7 +604,7 @@ $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o
@echo "Creating LV2 plugin library for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@

$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB)
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
-@mkdir -p $(shell dirname $@)
@echo "Creating LV2 plugin UI for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@
@@ -635,7 +709,7 @@ modgui:
vst2 vst: $(vst2) $(vst2files)

ifeq ($(HAVE_DGL),true)
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB)
$(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
else
$(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o
endif
@@ -649,7 +723,7 @@ endif
vst3: $(vst3) $(vst3files)

ifeq ($(HAVE_DGL),true)
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB)
$(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
else
$(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o
endif
@@ -671,7 +745,7 @@ endif
clap: $(clap) $(clapfiles)

ifeq ($(HAVE_DGL),true)
$(clap): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.o $(DGL_LIB)
$(clap): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o $(BUILD_DIR)/DistrhoUIMain_CLAP.cpp.o $(DGL_LIB) $(DGL_LIB_SHARED)
else
$(clap): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_CLAP.cpp.o
endif
@@ -679,13 +753,39 @@ endif
@echo "Creating CLAP plugin for $(NAME)"
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(EXTRA_DSP_LIBS) $(EXTRA_UI_LIBS) $(DGL_LIBS) $(CLAP_LIBS) $(SHARED) $(SYMBOLS_CLAP) -o $@

# ---------------------------------------------------------------------------------------------------------------------
# AU

au: $(au) $(aufiles)

ifeq ($(HAVE_DGL),true)
$(au): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o $(BUILD_DIR)/DistrhoUIMain_AU.cpp.o $(DGL_LIB)
else
$(au): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_AU.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@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 $@

# ---------------------------------------------------------------------------------------------------------------------
# Export

ifeq ($(HAVE_DGL),true)
$(BUILD_DIR)/export$(APP_EXT): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_EXPORT.cpp.o $(BUILD_DIR)/DistrhoUIMain_EXPORT.cpp.o $(DGL_LIB)
else
$(BUILD_DIR)/export$(APP_EXT): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_EXPORT.cpp.o
endif
-@mkdir -p $(shell dirname $@)
@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)
$(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
@@ -727,6 +827,13 @@ $(TARGET_DIR)/%/Resources/empty.lproj: $(DPF_PATH)/utils/plugin.bundle/Contents/
-@mkdir -p $(shell dirname $@)
$(SILENT)cp $< $@

# ---------------------------------------------------------------------------------------------------------------------
# format-specific files

$(TARGET_DIR)/$(NAME).component/Contents/Info.plist: $(BUILD_DIR)/export$(APP_EXT)
-@mkdir -p $(shell dirname $@)
cd $(TARGET_DIR)/$(NAME).component/Contents && $(abspath $<) "$(NAME)"

# ---------------------------------------------------------------------------------------------------------------------

-include $(OBJS_DSP:%.o=%.d)
@@ -741,6 +848,8 @@ endif
-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

@@ -750,6 +859,7 @@ endif
-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



+ 352
- 47
dpf/cmake/DPF-plugin.cmake View File

@@ -1,6 +1,6 @@
# DISTRHO Plugin Framework (DPF)
# Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
# Copyright (C) 2022 Filipe Coelho <falktx@falktx.com>
# Copyright (C) 2022-2024 Filipe Coelho <falktx@falktx.com>
#
# SPDX-License-Identifier: ISC

@@ -75,7 +75,13 @@ include(CMakeParseArguments)
# `jack`, `ladspa`, `dssi`, `lv2`, `vst2`, `vst3`, `clap`
#
# `UI_TYPE` <type>
# the user interface type: `opengl` (default), `cairo`, `external`
# the user interface type, can be one of the following:
# - cairo
# - external
# - opengl (default)
# - opengl3
# - vulkan
# - webview
#
# `FILES_COMMON` <file1>...<fileN>
# list of sources which are part of both DSP and UI
@@ -96,8 +102,14 @@ include(CMakeParseArguments)
# `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_plugin NAME)
set(options MONOLITHIC NO_SHARED_RESOURCES)
set(options MONOLITHIC NO_SHARED_RESOURCES 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})
@@ -107,23 +119,35 @@ function(dpf_add_plugin NAME)
endif()

set(_dgl_library)
set(_dgl_external OFF)
if(_dpf_plugin_FILES_UI)
if(_dpf_plugin_UI_TYPE STREQUAL "cairo")
dpf__add_dgl_cairo("${_dpf_plugin_NO_SHARED_RESOURCES}")
dpf__add_dgl_cairo($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
set(_dgl_library dgl-cairo)
elseif(_dpf_plugin_UI_TYPE STREQUAL "external")
dpf__add_dgl_external($<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
set(_dgl_library dgl-external)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl")
dpf__add_dgl_opengl("${_dpf_plugin_NO_SHARED_RESOURCES}")
dpf__add_dgl_opengl($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
set(_dgl_library dgl-opengl)
elseif(_dpf_plugin_UI_TYPE STREQUAL "external")
set(_dgl_external ON)
elseif(_dpf_plugin_UI_TYPE STREQUAL "opengl3")
dpf__add_dgl_opengl3($<NOT:$<BOOL:${_dpf_plugin_NO_SHARED_RESOURCES}>> $<BOOL:${_dpf_plugin_USE_FILE_BROWSER}>)
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}>)
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}>)
set(_dgl_library dgl-external)
else()
message(FATAL_ERROR "Unrecognized UI type for plugin: ${_dpf_plugin_UI_TYPE}")
endif()
else()
set(_dpf_plugin_UI_TYPE "")
endif()

set(_dgl_has_ui OFF)
if(_dgl_library OR _dgl_external)
if(_dgl_library)
set(_dgl_has_ui ON)
endif()

@@ -137,6 +161,14 @@ function(dpf_add_plugin NAME)
target_include_directories("${NAME}" PUBLIC
"${DPF_ROOT_DIR}/distrho")

if(_dpf_plugin_USE_FILE_BROWSER)
target_compile_definitions("${NAME}" PUBLIC "DGL_USE_FILE_BROWSER")
endif()

if(_dpf_plugin_USE_WEB_VIEW)
target_compile_definitions("${NAME}" PUBLIC "DGL_USE_WEB_VIEW")
endif()

if(_dpf_plugin_MODGUI_CLASS_NAME)
target_compile_definitions("${NAME}" PUBLIC "DISTRHO_PLUGIN_MODGUI_CLASS_NAME=\"${_dpf_plugin_MODGUI_CLASS_NAME}\"")
endif()
@@ -145,7 +177,7 @@ function(dpf_add_plugin NAME)
target_link_libraries("${NAME}" PRIVATE "dl")
endif()

if(_dgl_library AND NOT _dgl_external)
if(_dgl_library)
# make sure that all code will see DGL_* definitions
target_link_libraries("${NAME}" PUBLIC
"${_dgl_library}-definitions"
@@ -156,22 +188,20 @@ function(dpf_add_plugin NAME)
dpf__add_static_library("${NAME}-dsp" ${_dpf_plugin_FILES_DSP})
target_link_libraries("${NAME}-dsp" PUBLIC "${NAME}")

if(_dgl_library AND NOT _dgl_external)
if(_dgl_library)
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI})
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library})
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
target_link_libraries("${NAME}-ui" PRIVATE "dl")
if(LINUX AND _dpf_plugin_USE_WEB_VIEW)
execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=Scrt1.o
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE _dpf_plugin_shared_crt)
target_link_libraries("${NAME}-ui" PRIVATE "rt")
endif()
endif()
# add the files containing Objective-C classes
dpf__add_plugin_specific_ui_sources("${NAME}-ui")
elseif(_dgl_external)
dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI})
target_link_libraries("${NAME}-ui" PUBLIC "${NAME}")
if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU))
target_link_libraries("${NAME}-ui" PRIVATE "dl")
endif()
# add the files containing Objective-C classes
dpf__add_plugin_specific_ui_sources("${NAME}-ui")
# add the files containing C++17 or Objective-C classes
dpf__add_plugin_specific_ui_sources("${NAME}-ui" "${_dpf_plugin_USE_WEB_VIEW}")
else()
add_library("${NAME}-ui" INTERFACE)
endif()
@@ -185,13 +215,17 @@ function(dpf_add_plugin NAME)
elseif(_target STREQUAL "dssi")
dpf__build_dssi("${NAME}" "${_dgl_has_ui}")
elseif(_target STREQUAL "lv2")
dpf__build_lv2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_MONOLITHIC}")
dpf__build_lv2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_MONOLITHIC}" "${_dpf_plugin_shared_crt}")
elseif(_target STREQUAL "vst2")
dpf__build_vst2("${NAME}" "${_dgl_has_ui}")
dpf__build_vst2("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}")
elseif(_target STREQUAL "vst3")
dpf__build_vst3("${NAME}" "${_dgl_has_ui}")
dpf__build_vst3("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}")
elseif(_target STREQUAL "clap")
dpf__build_clap("${NAME}" "${_dgl_has_ui}")
dpf__build_clap("${NAME}" "${_dgl_has_ui}" "${_dpf_plugin_shared_crt}")
elseif(_target STREQUAL "au")
if (APPLE)
dpf__build_au("${NAME}" "${_dgl_has_ui}")
endif()
elseif(_target STREQUAL "static")
dpf__build_static("${NAME}" "${_dgl_has_ui}")
else()
@@ -341,7 +375,7 @@ endfunction()
#
# Add build rules for an LV2 plugin.
#
function(dpf__build_lv2 NAME HAS_UI MONOLITHIC)
function(dpf__build_lv2 NAME HAS_UI MONOLITHIC EXTRA_UI_LINK_OPTS)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-lv2" ${_no_srcs})
@@ -362,12 +396,14 @@ function(dpf__build_lv2 NAME HAS_UI MONOLITHIC)
if(MONOLITHIC)
dpf__add_ui_main("${NAME}-lv2" "lv2" "${HAS_UI}")
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-ui")
target_link_options("${NAME}-lv2" PRIVATE "${EXTRA_UI_LINK_OPTS}")
set_target_properties("${NAME}-lv2" PROPERTIES
OUTPUT_NAME "${NAME}")
else()
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs})
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui")
target_link_options("${NAME}-lv2-ui" PRIVATE "${EXTRA_UI_LINK_OPTS}")
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui")
set_target_properties("${NAME}-lv2-ui" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>"
@@ -396,7 +432,7 @@ endfunction()
#
# Add build rules for a VST2 plugin.
#
function(dpf__build_vst2 NAME HAS_UI)
function(dpf__build_vst2 NAME HAS_UI EXTRA_UI_LINK_OPTS)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-vst2" ${_no_srcs})
@@ -404,6 +440,7 @@ function(dpf__build_vst2 NAME HAS_UI)
dpf__add_ui_main("${NAME}-vst2" "vst2" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-vst2" "vst2")
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui")
target_link_options("${NAME}-vst2" PRIVATE "${EXTRA_UI_LINK_OPTS}")
set_target_properties("${NAME}-vst2" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst2/$<0:>"
@@ -456,7 +493,7 @@ function(dpf__determine_vst3_package_architecture OUTPUT_VARIABLE)
else()
set(vst3_package_arch "i386")
endif()
elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*)$")
elseif(vst3_system_arch MATCHES "^(armv[3-8][a-z]*|ppc(64)?(le)?)$")
set(vst3_package_arch "${vst3_system_arch}")
elseif(vst3_system_arch MATCHES "^(aarch64)$")
set(vst3_package_arch "aarch64")
@@ -474,7 +511,7 @@ endfunction()
#
# Add build rules for a VST3 plugin.
#
function(dpf__build_vst3 NAME HAS_UI)
function(dpf__build_vst3 NAME HAS_UI EXTRA_UI_LINK_OPTS)
dpf__determine_vst3_package_architecture(vst3_arch)

dpf__create_dummy_source_list(_no_srcs)
@@ -484,6 +521,7 @@ function(dpf__build_vst3 NAME HAS_UI)
dpf__add_ui_main("${NAME}-vst3" "vst3" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-vst3" "vst3")
target_link_libraries("${NAME}-vst3" PRIVATE "${NAME}-dsp" "${NAME}-ui")
target_link_options("${NAME}-vst3" PRIVATE "${EXTRA_UI_LINK_OPTS}")
set_target_properties("${NAME}-vst3" PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/vst3/$<0:>"
OUTPUT_NAME "${NAME}"
@@ -516,7 +554,7 @@ endfunction()
#
# Add build rules for a CLAP plugin.
#
function(dpf__build_clap NAME HAS_UI)
function(dpf__build_clap NAME HAS_UI EXTRA_UI_LINK_OPTS)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-clap" ${_no_srcs})
@@ -524,6 +562,7 @@ function(dpf__build_clap NAME HAS_UI)
dpf__add_ui_main("${NAME}-clap" "clap" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-clap" "clap")
target_link_libraries("${NAME}-clap" PRIVATE "${NAME}-dsp" "${NAME}-ui")
target_link_options("${NAME}-clap" PRIVATE "${EXTRA_UI_LINK_OPTS}")
set_target_properties("${NAME}-clap" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>"
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/clap/$<0:>"
@@ -544,6 +583,53 @@ function(dpf__build_clap NAME HAS_UI)
endif()
endfunction()

# dpf__build_au
# ------------------------------------------------------------------------------
#
# Add build rules for an AUv2 plugin.
#
function(dpf__build_au NAME HAS_UI)
dpf__create_dummy_source_list(_no_srcs)

dpf__add_module("${NAME}-au" ${_no_srcs})
dpf__add_plugin_main("${NAME}-au" "au")
dpf__add_ui_main("${NAME}-au" "au" "${HAS_UI}")
dpf__set_module_export_list("${NAME}-au" "au")
find_library(APPLE_AUDIOTOOLBOX_FRAMEWORK "AudioToolbox")
find_library(APPLE_AUDIOUNIT_FRAMEWORK "AudioUnit")
find_library(APPLE_COREFOUNDATION_FRAMEWORK "CoreFoundation")
target_compile_options("${NAME}-au" PRIVATE "-ObjC++")
target_link_libraries("${NAME}-au" PRIVATE
"${NAME}-dsp"
"${NAME}-ui"
"${APPLE_AUDIOTOOLBOX_FRAMEWORK}"
"${APPLE_AUDIOUNIT_FRAMEWORK}"
"${APPLE_COREFOUNDATION_FRAMEWORK}")
set_target_properties("${NAME}-au" PROPERTIES
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents/MacOS/$<0:>"
ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/obj/au/$<0:>"
OUTPUT_NAME "${NAME}"
PREFIX ""
SUFFIX "")

dpf__add_executable("${NAME}-export" ${_no_srcs})
dpf__add_plugin_main("${NAME}-export" "export")
dpf__add_ui_main("${NAME}-export" "export" "${HAS_UI}")
target_link_libraries("${NAME}-export" PRIVATE "${NAME}-dsp" "${NAME}-ui")

separate_arguments(CMAKE_CROSSCOMPILING_EMULATOR)

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")

add_dependencies("${NAME}-au" "${NAME}-export")

file(COPY "${DPF_ROOT_DIR}/utils/plugin.bundle/Contents/PkgInfo"
DESTINATION "${PROJECT_BINARY_DIR}/bin/${NAME}.component/Contents")
endfunction()

# dpf__build_static
# ------------------------------------------------------------------------------
#
@@ -577,7 +663,7 @@ endfunction()
#
# Add the Cairo variant of DGL, if not already available.
#
function(dpf__add_dgl_cairo NO_SHARED_RESOURCES)
function(dpf__add_dgl_cairo SHARED_RESOURCES USE_FILE_BROWSER)
if(TARGET dgl-cairo)
return()
endif()
@@ -605,23 +691,27 @@ function(dpf__add_dgl_cairo NO_SHARED_RESOURCES)
"${DPF_ROOT_DIR}/dgl/src/Window.cpp"
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp"
"${DPF_ROOT_DIR}/dgl/src/Cairo.cpp")
if(NO_SHARED_RESOURCES)
target_compile_definitions(dgl-cairo PUBLIC "DGL_NO_SHARED_RESOURCES")
else()
if(SHARED_RESOURCES)
target_sources(dgl-cairo PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp")
else()
target_compile_definitions(dgl-cairo PUBLIC "DGL_NO_SHARED_RESOURCES")
endif()
if(NOT APPLE)
if(APPLE)
target_sources(dgl-cairo PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
else()
target_sources(dgl-cairo PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
endif()
target_include_directories(dgl-cairo PUBLIC
"${DPF_ROOT_DIR}/dgl")
target_include_directories(dgl-cairo PUBLIC
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include")

if(USE_FILE_BROWSER)
target_compile_definitions(dgl-cairo PUBLIC "DGL_USE_FILE_BROWSER")
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-cairo PRIVATE dgl-system-libs)

@@ -637,12 +727,68 @@ function(dpf__add_dgl_cairo NO_SHARED_RESOURCES)
target_link_libraries(dgl-cairo PRIVATE dgl-cairo-definitions)
endfunction()

# dpf__add_dgl_external
# ------------------------------------------------------------------------------
#
# Add the external variant of DGL, if not already available.
#
function(dpf__add_dgl_external USE_FILE_BROWSER)
if(TARGET dgl-external)
return()
endif()

dpf__add_static_library(dgl-external 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/Stub.cpp")

if(APPLE)
target_sources(dgl-external PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
else()
target_sources(dgl-external PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
endif()
target_include_directories(dgl-external PUBLIC
"${DPF_ROOT_DIR}/dgl")
target_include_directories(dgl-external PUBLIC
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include")

if(USE_FILE_BROWSER)
target_compile_definitions(dgl-external PUBLIC "DGL_USE_FILE_BROWSER")
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)

add_library(dgl-external-definitions INTERFACE)
target_compile_definitions(dgl-external-definitions INTERFACE "DGL_EXTERNAL" "HAVE_DGL")

target_include_directories(dgl-external PUBLIC "${OPENGL_INCLUDE_DIR}")
target_link_libraries(dgl-external PRIVATE dgl-external-definitions "${OPENGL_gl_LIBRARY}")
endfunction()

# dpf__add_dgl_opengl
# ------------------------------------------------------------------------------
#
# Add the OpenGL variant of DGL, if not already available.
#
function(dpf__add_dgl_opengl NO_SHARED_RESOURCES)
function(dpf__add_dgl_opengl SHARED_RESOURCES USE_FILE_BROWSER)
if(TARGET dgl-opengl)
return()
endif()
@@ -672,17 +818,17 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES)
"${DPF_ROOT_DIR}/dgl/src/WindowPrivateData.cpp"
"${DPF_ROOT_DIR}/dgl/src/OpenGL.cpp"
"${DPF_ROOT_DIR}/dgl/src/NanoVG.cpp")
if(NO_SHARED_RESOURCES)
target_compile_definitions(dgl-opengl PUBLIC "DGL_NO_SHARED_RESOURCES")
else()
if(SHARED_RESOURCES)
target_sources(dgl-opengl PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp")
else()
target_compile_definitions(dgl-opengl PUBLIC "DGL_NO_SHARED_RESOURCES")
endif()
if(NOT APPLE)
if(APPLE)
target_sources(dgl-opengl PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
else()
target_sources(dgl-opengl PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
endif()
target_include_directories(dgl-opengl PUBLIC
"${DPF_ROOT_DIR}/dgl")
@@ -693,6 +839,10 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES)
target_compile_definitions(dgl-opengl PUBLIC "GL_SILENCE_DEPRECATION")
endif()

if(USE_FILE_BROWSER)
target_compile_definitions(dgl-opengl PUBLIC "DGL_USE_FILE_BROWSER")
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-opengl PRIVATE dgl-system-libs)

@@ -703,15 +853,165 @@ function(dpf__add_dgl_opengl NO_SHARED_RESOURCES)
target_link_libraries(dgl-opengl PRIVATE dgl-opengl-definitions "${OPENGL_gl_LIBRARY}")
endfunction()

# dpf__add_dgl_opengl3
# ------------------------------------------------------------------------------
#
# Add the OpenGL3 variant of DGL, if not already available.
#
function(dpf__add_dgl_opengl3 SHARED_RESOURCES USE_FILE_BROWSER)
if(TARGET dgl-opengl3)
return()
endif()

if(NOT OpenGL_GL_PREFERENCE)
set(OpenGL_GL_PREFERENCE "LEGACY")
endif()

find_package(OpenGL REQUIRED)

dpf__add_static_library(dgl-opengl3 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/NanoVG.cpp")
if(SHARED_RESOURCES)
target_sources(dgl-opengl3 PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp")
else()
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_NO_SHARED_RESOURCES")
endif()
if(APPLE)
target_sources(dgl-opengl3 PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
else()
target_sources(dgl-opengl3 PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
endif()
target_include_directories(dgl-opengl3 PUBLIC
"${DPF_ROOT_DIR}/dgl")
target_include_directories(dgl-opengl3 PUBLIC
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include")

if(APPLE)
target_compile_definitions(dgl-opengl3 PUBLIC "GL_SILENCE_DEPRECATION")
endif()

if(USE_FILE_BROWSER)
target_compile_definitions(dgl-opengl3 PUBLIC "DGL_USE_FILE_BROWSER")
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_include_directories(dgl-opengl3 PUBLIC "${OPENGL_INCLUDE_DIR}")
target_link_libraries(dgl-opengl3 PRIVATE dgl-opengl3-definitions "${OPENGL_gl_LIBRARY}")
endfunction()

# dpf__add_dgl_vulkan
# ------------------------------------------------------------------------------
#
# Add the Vulkan variant of DGL, if not already available.
#
function(dpf__add_dgl_vulkan SHARED_RESOURCES USE_FILE_BROWSER)
if(TARGET dgl-vulkan)
return()
endif()

find_package(Vulkan REQUIRED)

dpf__add_static_library(dgl-vulkan 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/Vulkan.cpp")
if(NO_SHARED_RESOURCES)
target_sources(dgl-vulkan PRIVATE "${DPF_ROOT_DIR}/dgl/src/Resources.cpp")
else()
target_compile_definitions(dgl-vulkan PUBLIC "DGL_NO_SHARED_RESOURCES")
endif()
if(APPLE)
target_sources(dgl-vulkan PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.mm")
else()
target_sources(dgl-vulkan PRIVATE
"${DPF_ROOT_DIR}/dgl/src/pugl.cpp")
endif()
target_include_directories(dgl-vulkan PUBLIC
"${DPF_ROOT_DIR}/dgl")
target_include_directories(dgl-vulkan PUBLIC
"${DPF_ROOT_DIR}/dgl/src/pugl-upstream/include")

if(APPLE)
target_compile_definitions(dgl-vulkan PUBLIC "GL_SILENCE_DEPRECATION")
endif()

if(USE_FILE_BROWSER)
target_compile_definitions(dgl-vulkan PUBLIC "DGL_USE_FILE_BROWSER")
endif()

dpf__add_dgl_system_libs()
target_link_libraries(dgl-vulkan PRIVATE dgl-system-libs)

add_library(dgl-vulkan-definitions INTERFACE)
target_compile_definitions(dgl-vulkan-definitions INTERFACE "DGL_VULKAN" "HAVE_VULKAN" "HAVE_DGL")

target_include_directories(dgl-vulkan PUBLIC "${OPENGL_INCLUDE_DIR}")
target_link_libraries(dgl-vulkan PRIVATE dgl-vulkan-definitions "${OPENGL_gl_LIBRARY}")
endfunction()

# dpf__add_plugin_specific_ui_sources
# ------------------------------------------------------------------------------
#
# Compile system specific files, for now it is just Objective-C code
# Compile system specific files
#
function(dpf__add_plugin_specific_ui_sources NAME)
function(dpf__add_plugin_specific_ui_sources NAME USE_WEB_VIEW)
if(APPLE)
target_sources("${NAME}" PRIVATE
"${DPF_ROOT_DIR}/distrho/DistrhoUI_macOS.mm")
if(USE_WEB_VIEW)
find_library(APPLE_WEBKIT_FRAMEWORK "WebKit")
target_link_libraries("${NAME}" PRIVATE "${APPLE_WEBKIT_FRAMEWORK}")
endif()
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()
target_link_libraries("${NAME}" PRIVATE "ole32" "uuid")
endif()
endfunction()

@@ -804,7 +1104,9 @@ endfunction()
function(dpf__add_module NAME)
add_library("${NAME}" MODULE ${ARGN})
dpf__set_target_defaults("${NAME}")
if(MINGW)
if(APPLE)
set_target_properties("${NAME}" PROPERTIES SUFFIX ".dylib")
elseif(MINGW)
target_link_libraries("${NAME}" PRIVATE "-static")
endif()
endfunction()
@@ -861,6 +1163,9 @@ 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))
target_link_options("${NAME}" PUBLIC "-Wl,--no-undefined")
endif()
endfunction()

# dpf__add_plugin_main


+ 36
- 1
dpf/dgl/Application.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -27,6 +27,41 @@ END_NAMESPACE_DISTRHO

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------
// build config sentinels

/**
This set of static variables act as a build sentinel that detects a configuration error.

Usually this means the way DGL was built and how it is being used and linked into your program is different,
we want to avoid such combinations as memory layout would then also be different
leading to all sort of subtle but very nasty memory corruption issues.

Make sure the flags used to build DGL match the ones used by your program and the link errors should go away.
*/
#define BUILD_CONFIG_SENTINEL(NAME) \
static struct DISTRHO_JOIN_MACRO(_, NAME) { bool ok; DISTRHO_JOIN_MACRO(_, NAME)() noexcept; } NAME;

#ifdef DPF_DEBUG
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_off)
#endif

#ifdef DGL_USE_FILE_BROWSER
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off)
#endif

#ifdef DGL_NO_SHARED_RESOURCES
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off)
#endif

#undef BUILD_CONFIG_SENTINEL

// --------------------------------------------------------------------------------------------------------------------

/**


+ 49
- 16
dpf/dgl/Base.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -20,6 +20,35 @@
#include "../distrho/extra/LeakDetector.hpp"
#include "../distrho/extra/ScopedPointer.hpp"

// --------------------------------------------------------------------------------------------------------------------
// Compatibility checks

#if defined(DGL_CAIRO) && defined(DGL_EXTERNAL)
# error invalid build config: trying to build for both cairo and external at the same time
#elif defined(DGL_CAIRO) && defined(DGL_OPENGL)
# error invalid build config: trying to build for both cairo and opengl at the same time
#elif defined(DGL_CAIRO) && defined(DGL_VULKAN)
# error invalid build config: trying to build for both cairo and vulkan at the same time
#elif defined(DGL_EXTERNAL) && defined(DGL_OPENGL)
# error invalid build config: trying to build for both external and opengl at the same time
#elif defined(DGL_EXTERNAL) && defined(DGL_VULKAN)
# error invalid build config: trying to build for both external and vulkan at the same time
#elif defined(DGL_OPENGL) && defined(DGL_VULKAN)
# error invalid build config: trying to build for both opengl and vulkan at the same time
#endif

#ifdef DGL_USE_FILEBROWSER
# 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
#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

// --------------------------------------------------------------------------------------------------------------------
// Define namespace

@@ -40,10 +69,13 @@ START_NAMESPACE_DGL
Keyboard modifier flags.
*/
enum Modifier {
kModifierShift = 1u << 0u, ///< Shift key
kModifierControl = 1u << 1u, ///< Control key
kModifierAlt = 1u << 2u, ///< Alt/Option key
kModifierSuper = 1u << 3u ///< Mod4/Command/Windows key
kModifierShift = 1U << 0U, ///< Shift key
kModifierControl = 1U << 1U, ///< Control key
kModifierAlt = 1U << 2U, ///< Alt/Option key
kModifierSuper = 1U << 3U, ///< Mod4/Command/Windows key
kModifierNumLock = 1U << 4U, ///< Num lock enabled
kModifierScrollLock = 1U << 5U, ///< Scroll lock enabled
kModifierCapsLock = 1U << 6U, ///< Caps lock enabled
};

/**
@@ -63,13 +95,14 @@ enum Modifier {
enum Key {
// Convenience symbols for ASCII control characters
kKeyBackspace = 0x00000008U, ///< Backspace
kKeyTab = 0x00000009U, ///< Tab
kKeyEnter = 0x0000000DU, ///< Enter
kKeyEscape = 0x0000001BU, ///< Escape
kKeyDelete = 0x0000007FU, ///< Delete
kKeySpace = 0x00000020U, ///< Space

// Unicode Private Use Area
kKeyF1 = 0x0000E000U, ///< F1
kKeyF1 = 0xE000U, ///< F1
kKeyF2, ///< F2
kKeyF3, ///< F3
kKeyF4, ///< F4
@@ -81,7 +114,7 @@ enum Key {
kKeyF10, ///< F10
kKeyF11, ///< F11
kKeyF12, ///< F12
kKeyPageUp = 0xE031, ///< Page Up
kKeyPageUp = 0xE031U, ///< Page Up
kKeyPageDown, ///< Page Down
kKeyEnd, ///< End
kKeyHome, ///< Home
@@ -96,7 +129,7 @@ enum Key {
kKeyNumLock, ///< Num Lock
kKeyScrollLock, ///< Scroll Lock
kKeyCapsLock, ///< Caps Lock
kKeyShiftL = 0xE051U, ///< Left Shift,
kKeyShiftL = 0xE051U, ///< Left Shift
kKeyShiftR, ///< Right Shift
kKeyControlL, ///< Left Control
kKeyControlR, ///< Right Control
@@ -150,7 +183,7 @@ enum Key {
*/
enum EventFlag {
kFlagSendEvent = 1, ///< Event is synthetic
kFlagIsHint = 2 ///< Event is a hint (not direct user input)
kFlagIsHint = 2, ///< Event is a hint (not direct user input)
};

/**
@@ -159,7 +192,7 @@ enum EventFlag {
enum CrossingMode {
kCrossingNormal, ///< Crossing due to pointer motion
kCrossingGrab, ///< Crossing due to a grab
kCrossingUngrab ///< Crossing due to a grab release
kCrossingUngrab, ///< Crossing due to a grab release
};

/**
@@ -204,7 +237,7 @@ enum MouseCursor {

// Backwards compatibility with old DPF
kMouseCursorDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpLeftDownRight") = kMouseCursorUpLeftDownRight,
kMouseCursorAntiDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpRightDownLeft") = kMouseCursorUpRightDownLeft
kMouseCursorAntiDiagonal DISTRHO_DEPRECATED_BY("kMouseCursorUpRightDownLeft") = kMouseCursorUpRightDownLeft,
};

/**
@@ -215,11 +248,11 @@ enum MouseCursor {
while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads.
*/
enum ScrollDirection {
kScrollUp, ///< Scroll up
kScrollDown, ///< Scroll down
kScrollLeft, ///< Scroll left
kScrollRight, ///< Scroll right
kScrollSmooth ///< Smooth scroll in any direction
kScrollUp, ///< Scroll up
kScrollDown, ///< Scroll down
kScrollLeft, ///< Scroll left
kScrollRight, ///< Scroll right
kScrollSmooth, ///< Smooth scroll in any direction
};

/**


+ 4
- 2
dpf/dgl/EventHandlers.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -133,6 +133,8 @@ public:
// returns 0-1 ranged value, already with log scale as needed
float getNormalizedValue() const noexcept;

float getDefault() const noexcept;

// NOTE: value is assumed to be scaled if using log
void setDefault(float def) noexcept;

@@ -186,7 +188,7 @@ private:
struct PrivateData;
PrivateData* const pData;

DISTRHO_LEAK_DETECTOR(SliderEventHandler)
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SliderEventHandler)
};

// --------------------------------------------------------------------------------------------------------------------


+ 1
- 0
dpf/dgl/ImageBaseWidgets.hpp View File

@@ -138,6 +138,7 @@ public:
virtual void imageKnobDragStarted(ImageBaseKnob* imageKnob) = 0;
virtual void imageKnobDragFinished(ImageBaseKnob* imageKnob) = 0;
virtual void imageKnobValueChanged(ImageBaseKnob* imageKnob, float value) = 0;
virtual void imageKnobDoubleClicked(ImageBaseKnob*) {};
};

explicit ImageBaseKnob(Widget* parentWidget, const ImageType& image, Orientation orientation = Vertical) noexcept;


+ 4
- 8
dpf/dgl/Makefile View File

@@ -14,6 +14,7 @@ BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include
LINK_FLAGS += $(DGL_LIBS)

ifeq ($(MACOS),true)
BUILD_CXX_FLAGS += -DDISTRHO_MACOS_NAMESPACE_TIME=$(shell date +%s)
BUILD_CXX_FLAGS += -Wno-deprecated-declarations
else
PUGL_EXTRA_FLAGS = -Wno-extra -Wmissing-field-initializers
@@ -90,7 +91,8 @@ endif

# ---------------------------------------------------------------------------------------------------------------------

OBJS_stub = $(OBJS_common)
OBJS_stub = $(OBJS_common) \
$(BUILD_DIR)/dgl/Stub.cpp.o

ifeq ($(MACOS),true)
OBJS_stub += $(BUILD_DIR)/dgl/pugl.mm.o
@@ -117,8 +119,6 @@ endif

ifeq ($(HAVE_OPENGL),true)
TARGETS += $(BUILD_DIR)/libdgl-opengl.a
# Compat name, to be removed soon
TARGETS += $(BUILD_DIR)/libdgl.a
endif

ifeq ($(HAVE_STUB),true)
@@ -138,6 +138,7 @@ opengl: $(BUILD_DIR)/libdgl-opengl.a
opengl3: $(BUILD_DIR)/libdgl-opengl3.a
stub: $(BUILD_DIR)/libdgl-stub.a
vulkan: $(BUILD_DIR)/libdgl-vulkan.a
web: $(BUILD_DIR)/libdgl-web.a

# ---------------------------------------------------------------------------------------------------------------------

@@ -171,11 +172,6 @@ $(BUILD_DIR)/libdgl-vulkan.a: $(OBJS_vulkan)
$(SILENT)rm -f $@
$(SILENT)$(AR) crs $@ $^

# Compat name, to be removed soon
$(BUILD_DIR)/libdgl.a: $(BUILD_DIR)/libdgl-opengl.a
@echo "Symlinking libdgl.a"
$(SILENT)ln -sf $< $@

# ---------------------------------------------------------------------------------------------------------------------

$(BUILD_DIR)/dgl/%.c.o: src/%.c


+ 1
- 0
dpf/dgl/StandaloneWindow.hpp View File

@@ -73,6 +73,7 @@ public:
uint getHeight() const noexcept { return Window::getHeight(); }
const Size<uint> getSize() const noexcept { return Window::getSize(); }
void repaint() noexcept { Window::repaint(); }
void repaint(const Rectangle<uint>& rect) noexcept { Window::repaint(rect); }
void setWidth(uint width) { Window::setWidth(width); }
void setHeight(uint height) { Window::setHeight(height); }
void setSize(uint width, uint height) { Window::setSize(width, height); }


+ 2
- 2
dpf/dgl/Widget.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -407,7 +407,7 @@ protected:
/**
A function called to draw the widget contents.
*/
virtual void onDisplay() = 0;
virtual void onDisplay() {};

/**
A function called when a key is pressed or released.


+ 7
- 6
dpf/dgl/Window.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -19,7 +19,7 @@

#include "Geometry.hpp"

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
# include "FileBrowserDialog.hpp"
#endif

@@ -394,7 +394,7 @@ public:
*/
void focus();

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
/**
Open a file browser dialog with this window as transient parent.
A few options can be specified to setup the dialog.
@@ -405,7 +405,7 @@ public:
This function does not block the event loop.
*/
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif
#endif

/**
Request repaint of this window, for the entire area.
@@ -517,7 +517,7 @@ protected:
*/
virtual void onScaleFactorChanged(double scaleFactor);

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
/**
A function called when a path is selected by the user, as triggered by openFileBrowser().
This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
@@ -528,7 +528,7 @@ protected:
/** DEPRECATED Use onFileSelected(). */
DISTRHO_DEPRECATED_BY("onFileSelected(const char*)")
inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); }
#endif
#endif

private:
PrivateData* const pData;
@@ -545,6 +545,7 @@ private:
uint height,
double scaleFactor,
bool resizable,
bool usesScheduledRepaints,
bool usesSizeRequest,
bool doPostInit);



+ 70
- 2
dpf/dgl/src/Application.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -24,6 +24,55 @@

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------
// build config sentinels

#define BUILD_CONFIG_SENTINEL(NAME) \
DISTRHO_JOIN_MACRO(_, NAME)::DISTRHO_JOIN_MACRO(_, NAME)() noexcept : ok(false) {}

#ifdef DPF_DEBUG
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dpf_debug_off)
#endif

#ifdef DGL_USE_FILE_BROWSER
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_use_file_browser_off)
#endif

#ifdef DGL_NO_SHARED_RESOURCES
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_on)
#else
BUILD_CONFIG_SENTINEL(fail_to_link_is_mismatch_dgl_no_shared_resources_off)
#endif

#undef BUILD_CONFIG_SENTINEL

static inline
bool dpf_check_build_status() noexcept
{
return (
#ifdef DPF_DEBUG
fail_to_link_is_mismatch_dpf_debug_on.ok &&
#else
fail_to_link_is_mismatch_dpf_debug_off.ok &&
#endif
#ifdef DGL_USE_FILE_BROWSER
fail_to_link_is_mismatch_dgl_use_file_browser_on.ok &&
#else
fail_to_link_is_mismatch_dgl_use_file_browser_off.ok &&
#endif
#ifdef DGL_NO_SHARED_RESOURCES
fail_to_link_is_mismatch_dgl_no_shared_resources_on.ok &&
#else
fail_to_link_is_mismatch_dgl_no_shared_resources_off.ok &&
#endif
true
);
}

// --------------------------------------------------------------------------------------------------------------------

#ifdef __EMSCRIPTEN__
@@ -34,7 +83,26 @@ static void app_idle(void* const app)
#endif

Application::Application(const bool isStandalone)
: pData(new PrivateData(isStandalone)) {}
: pData(new PrivateData(isStandalone))
{
// 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_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()
{


+ 33
- 9
dpf/dgl/src/ApplicationPrivateData.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -23,24 +23,25 @@

START_NAMESPACE_DGL

typedef std::list<DGL_NAMESPACE::Window*>::iterator WindowListIterator;
typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator;

static d_ThreadHandle getCurrentThreadHandle() noexcept
{
#ifdef DISTRHO_OS_WINDOWS
#ifdef DISTRHO_OS_WINDOWS
return GetCurrentThread();
#else
#else
return pthread_self();
#endif
#endif
}

static bool isThisTheMainThread(const d_ThreadHandle mainThreadHandle) noexcept
{
#ifdef DISTRHO_OS_WINDOWS
#ifdef DISTRHO_OS_WINDOWS
return GetCurrentThread() == mainThreadHandle; // IsGUIThread ?
#else
#else
return pthread_equal(getCurrentThreadHandle(), mainThreadHandle) != 0;
#endif
#endif
}

// --------------------------------------------------------------------------------------------------------------------
@@ -59,6 +60,7 @@ Application::PrivateData::PrivateData(const bool standalone)
isQuitting(false),
isQuittingInNextCycle(false),
isStarting(true),
needsRepaint(false),
visibleWindows(0),
mainThreadHandle(getCurrentThreadHandle()),
windows(),
@@ -66,12 +68,16 @@ 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()
@@ -82,8 +88,12 @@ Application::PrivateData::~PrivateData()
windows.clear();
idleCallbacks.clear();

#ifdef DGL_USING_SDL
SDL_Quit();
#else
if (world != nullptr)
puglFreeWorld(world);
#endif
}

// --------------------------------------------------------------------------------------------------------------------
@@ -136,6 +146,20 @@ void Application::PrivateData::triggerIdleCallbacks()
}
}

void Application::PrivateData::repaintIfNeeeded()
{
if (needsRepaint)
{
needsRepaint = false;

for (WindowListIterator it = windows.begin(), ite = windows.end(); it != ite; ++it)
{
DGL_NAMESPACE::Window* const window(*it);
window->repaint();
}
}
}

void Application::PrivateData::quit()
{
if (! isThisTheMainThread(mainThreadHandle))
@@ -149,13 +173,13 @@ void Application::PrivateData::quit()

isQuitting = true;

#ifndef DPF_TEST_APPLICATION_CPP
#ifndef DPF_TEST_APPLICATION_CPP
for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit)
{
DGL_NAMESPACE::Window* const window(*rit);
window->close();
}
#endif
#endif
}

double Application::PrivateData::getTime() const


+ 6
- 0
dpf/dgl/src/ApplicationPrivateData.hpp View File

@@ -63,6 +63,9 @@ struct Application::PrivateData {
/** 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;

/** Counter of visible windows, only used in standalone mode.
If 0->1, application is starting. If 1->0, application is quitting/stopping. */
uint visibleWindows;
@@ -96,6 +99,9 @@ struct Application::PrivateData {
/** Run each idle callback without updating pugl world. */
void triggerIdleCallbacks();

/** Trigger a repaint of all windows if @a needsRepaint is true. */
void repaintIfNeeeded();

/** Set flag indicating application is quitting, and close all windows in reverse order of registration.
For standalone mode only. */
void quit();


+ 7
- 7
dpf/dgl/src/Cairo.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2024 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
@@ -438,9 +438,9 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, co
for (int w = 0; w < width; ++w)
{
const uchar a = urdata[h*width*4+w*4+3];
newdata[h*width*4+w*4+0] = (urdata[h*width*4+w*4+0] * a) >> 8;
newdata[h*width*4+w*4+1] = (urdata[h*width*4+w*4+1] * a) >> 8;
newdata[h*width*4+w*4+2] = (urdata[h*width*4+w*4+2] * a) >> 8;
newdata[h*width*4+w*4+0] = static_cast<uchar>((urdata[h*width*4+w*4+0] * a) >> 8);
newdata[h*width*4+w*4+1] = static_cast<uchar>((urdata[h*width*4+w*4+1] * a) >> 8);
newdata[h*width*4+w*4+2] = static_cast<uchar>((urdata[h*width*4+w*4+2] * a) >> 8);
newdata[h*width*4+w*4+3] = a;
}
}
@@ -465,9 +465,9 @@ void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, co
for (int w = 0; w < width; ++w)
{
const uchar a = urdata[h*width*4+w*4+3];
newdata[h*width*4+w*4+0] = (urdata[h*width*4+w*4+2] * a) >> 8;
newdata[h*width*4+w*4+1] = (urdata[h*width*4+w*4+1] * a) >> 8;
newdata[h*width*4+w*4+2] = (urdata[h*width*4+w*4+0] * a) >> 8;
newdata[h*width*4+w*4+0] = static_cast<uchar>((urdata[h*width*4+w*4+2] * a) >> 8);
newdata[h*width*4+w*4+1] = static_cast<uchar>((urdata[h*width*4+w*4+1] * a) >> 8);
newdata[h*width*4+w*4+2] = static_cast<uchar>((urdata[h*width*4+w*4+0] * a) >> 8);
newdata[h*width*4+w*4+3] = a;
}
}


+ 10
- 5
dpf/dgl/src/EventHandlers.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -419,7 +419,7 @@ struct KnobEventHandler::PrivateData {
if ((state & kKnobStateDragging) == 0x0)
return false;

float movDiff;
double movDiff;

switch (orientation)
{
@@ -431,8 +431,8 @@ struct KnobEventHandler::PrivateData {
break;
case Both:
{
const float movDiffX = ev.pos.getX() / scaleFactor - lastX;
const float movDiffY = lastY - ev.pos.getY() / scaleFactor;
const double movDiffX = ev.pos.getX() / scaleFactor - lastX;
const double movDiffY = lastY - ev.pos.getY() / scaleFactor;
movDiff = std::abs(movDiffX) > std::abs(movDiffY) ? movDiffX : movDiffY;
}
break;
@@ -444,7 +444,7 @@ struct KnobEventHandler::PrivateData {
return true;

const float divisor = (ev.mod & kModifierControl) ? accel * 10.f : accel;
valueTmp += (maximum - minimum) / divisor * movDiff;
valueTmp += (maximum - minimum) / divisor * static_cast<float>(movDiff);

if (usingLog)
valueTmp = logscale(valueTmp);
@@ -618,6 +618,11 @@ float KnobEventHandler::getNormalizedValue() const noexcept
return pData->getNormalizedValue();
}

float KnobEventHandler::getDefault() const noexcept
{
return pData->valueDef;
}

void KnobEventHandler::setDefault(const float def) noexcept
{
pData->valueDef = def;


+ 7
- 0
dpf/dgl/src/ImageBaseWidgets.cpp View File

@@ -316,6 +316,13 @@ struct ImageBaseKnob<ImageType>::PrivateData : public KnobEventHandler::Callback
callback->imageKnobValueChanged(imageKnob, value);
}

void knobDoubleClicked(SubWidget* const widget) override
{
if (callback != nullptr)
if (ImageBaseKnob* const imageKnob = dynamic_cast<ImageBaseKnob*>(widget))
callback->imageKnobDoubleClicked(imageKnob);
}

// implemented independently per graphics backend
void init();
void cleanup();


+ 13
- 13
dpf/dgl/src/Layout.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -35,8 +35,8 @@ uint Layout<true>::setAbsolutePos(int x, const int y, const uint padding)
SubWidgetWithSizeHint& s(*it);
maxHeight = std::max(maxHeight, s.widget->getHeight());
s.widget->setAbsolutePos(x, y);
x += s.widget->getWidth();
x += padding;
x += static_cast<int>(s.widget->getWidth());
x += static_cast<int>(padding);
}

return maxHeight;
@@ -52,8 +52,8 @@ uint Layout<false>::setAbsolutePos(const int x, int y, const uint padding)
SubWidgetWithSizeHint& s(*it);
maxWidth = std::max(maxWidth, s.widget->getWidth());
s.widget->setAbsolutePos(x, y);
y += s.widget->getHeight();
y += padding;
y += static_cast<int>(s.widget->getHeight());
y += static_cast<int>(padding);
}

return maxWidth;
@@ -78,7 +78,7 @@ void Layout<true>::setSize(const uint width, const uint padding)
}

if (const size_t numWidgets = widgets.size())
nonFixedWidth -= padding * (numWidgets - 1);
nonFixedWidth -= padding * static_cast<uint>(numWidgets - 1);

const uint widthPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedWidth / numDynamiclySizedWidgets : 0;

@@ -111,7 +111,7 @@ void Layout<false>::setSize(const uint height, const uint padding)
}

if (const size_t numWidgets = widgets.size())
nonFixedHeight -= padding * (numWidgets - 1);
nonFixedHeight -= padding * static_cast<uint>(numWidgets - 1);

const uint heightPerWidget = numDynamiclySizedWidgets != 0 ? nonFixedHeight / numDynamiclySizedWidgets : 0;

@@ -138,8 +138,8 @@ void HorizontallyStackedVerticalLayout::setAbsolutePos(int x, const int y, const
for (VerticalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
VerticalLayout* l(*it);
x += l->setAbsolutePos(x, y, padding);
x += padding;
x += static_cast<int>(l->setAbsolutePos(x, y, padding));
x += static_cast<int>(padding);
}
}

@@ -157,9 +157,9 @@ Size<uint> VerticallyStackedHorizontalLayout::adjustSize(const uint padding)
uint width = 0;
uint height = 0;

for (SubWidgetWithSizeHintIterator it=l->widgets.begin(), end=l->widgets.end(); it != end; ++it)
for (SubWidgetWithSizeHintIterator it2=l->widgets.begin(), end2=l->widgets.end(); it2 != end2; ++it2)
{
SubWidgetWithSizeHint& s(*it);
SubWidgetWithSizeHint& s(*it2);

if (width != 0)
width += padding;
@@ -191,8 +191,8 @@ void VerticallyStackedHorizontalLayout::setAbsolutePos(const int x, int y, const
for (HorizontalLayoutIterator it=items.begin(), end=items.end(); it != end; ++it)
{
HorizontalLayout* l(*it);
y += l->setAbsolutePos(x, y, padding);
y += padding;
y += static_cast<int>(l->setAbsolutePos(x, y, padding));
y += static_cast<int>(padding);
}
}



+ 11
- 11
dpf/dgl/src/OpenGL.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -691,12 +691,12 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const
const int w = static_cast<int>(self->getWidth());
const int h = static_cast<int>(self->getHeight());

if (viewportScaleFactor != 0.0 && viewportScaleFactor != 1.0)
if (d_isNotZero(viewportScaleFactor) && d_isNotEqual(viewportScaleFactor, 1.0))
{
glViewport(x,
-static_cast<int>(height * viewportScaleFactor - height + absolutePos.getY() + 0.5),
static_cast<int>(width * viewportScaleFactor + 0.5),
static_cast<int>(height * viewportScaleFactor + 0.5));
-d_roundToIntPositive(height * viewportScaleFactor - height + absolutePos.getY()),
d_roundToIntPositive(width * viewportScaleFactor),
d_roundToIntPositive(height * viewportScaleFactor));
}
else
{
@@ -712,16 +712,16 @@ void SubWidget::PrivateData::display(const uint width, const uint height, const
else
{
// set viewport pos
glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
-static_cast<int>(absolutePos.getY() * autoScaleFactor + 0.5),
glViewport(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor),
-d_roundToIntPositive(absolutePos.getY() * autoScaleFactor),
static_cast<int>(width),
static_cast<int>(height));

// then cut the outer bounds
glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5),
static_cast<int>(height - (self->getHeight() + absolutePos.getY()) * autoScaleFactor + 0.5),
static_cast<int>(self->getWidth() * autoScaleFactor + 0.5),
static_cast<int>(self->getHeight() * autoScaleFactor + 0.5));
glScissor(d_roundToIntPositive(absolutePos.getX() * autoScaleFactor),
d_roundToIntPositive(height - (static_cast<int>(self->getHeight()) + absolutePos.getY()) * autoScaleFactor),
d_roundToIntPositive(self->getWidth() * autoScaleFactor),
d_roundToIntPositive(self->getHeight() * autoScaleFactor));

glEnable(GL_SCISSOR_TEST);
needsDisableScissor = true;


+ 193
- 0
dpf/dgl/src/Stub.cpp View File

@@ -0,0 +1,193 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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 "Color.hpp"
#include "SubWidgetPrivateData.hpp"
#include "TopLevelWidgetPrivateData.hpp"
#include "WidgetPrivateData.hpp"
#include "WindowPrivateData.hpp"

START_NAMESPACE_DGL

// --------------------------------------------------------------------------------------------------------------------

static void notImplemented(const char* const name)
{
d_stderr2("stub function not implemented: %s", name);
}

// --------------------------------------------------------------------------------------------------------------------
// Color

void Color::setFor(const GraphicsContext&, bool)
{
notImplemented("Color::setFor");
}

// --------------------------------------------------------------------------------------------------------------------
// Line

template<typename T>
void Line<T>::draw(const GraphicsContext& context, T)
{
notImplemented("Line::draw");
}

template<typename T>
void Line<T>::draw()
{
notImplemented("Line::draw");
}

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>
void Circle<T>::draw(const GraphicsContext&)
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Circle::drawOutline");
}

template<typename T>
void Circle<T>::draw()
{
notImplemented("Circle::draw");
}

template<typename T>
void Circle<T>::drawOutline()
{
notImplemented("Circle::drawOutline");
}

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>
void Triangle<T>::draw(const GraphicsContext&)
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Triangle::drawOutline");
}

template<typename T>
void Triangle<T>::draw()
{
notImplemented("Triangle::draw");
}

template<typename T>
void Triangle<T>::drawOutline()
{
notImplemented("Triangle::drawOutline");
}

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>
void Rectangle<T>::draw(const GraphicsContext&)
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline(const GraphicsContext&, T)
{
notImplemented("Rectangle::drawOutline");
}

template<typename T>
void Rectangle<T>::draw()
{
notImplemented("Rectangle::draw");
}

template<typename T>
void Rectangle<T>::drawOutline()
{
notImplemented("Rectangle::drawOutline");
}

template class Rectangle<double>;
template class Rectangle<float>;
template class Rectangle<int>;
template class Rectangle<uint>;
template class Rectangle<short>;
template class Rectangle<ushort>;

// --------------------------------------------------------------------------------------------------------------------

void SubWidget::PrivateData::display(uint, uint, double)
{
}

// --------------------------------------------------------------------------------------------------------------------

void TopLevelWidget::PrivateData::display()
{
}

// --------------------------------------------------------------------------------------------------------------------

void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint)
{
notImplemented("Window::PrivateData::renderToPicture");
}

// --------------------------------------------------------------------------------------------------------------------

const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept
{
GraphicsContext& context((GraphicsContext&)graphicsContext);
return context;
}

// --------------------------------------------------------------------------------------------------------------------

END_NAMESPACE_DGL

+ 2
- 2
dpf/dgl/src/SubWidget.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -71,7 +71,7 @@ Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept
const int y = getAbsoluteY();

if (x >= 0 && y >= 0)
return Rectangle<uint>(x, y, getSize());
return Rectangle<uint>(static_cast<uint>(x), static_cast<uint>(y), getSize());

const int xOffset = std::min(0, x);
const int yOffset = std::min(0, y);


+ 43
- 23
dpf/dgl/src/Window.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -106,7 +106,7 @@ Window::Window(Application& app,
const uint height,
const double scaleFactor,
const bool resizable)
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false))
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false, false))
{
pData->initPost();
}
@@ -117,9 +117,11 @@ Window::Window(Application& app,
const uint height,
const double scaleFactor,
const bool resizable,
const bool isVST3,
const bool usesScheduledRepaints,
const bool usesSizeRequest,
const bool doPostInit)
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3))
: pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable,
usesScheduledRepaints, usesSizeRequest))
{
if (doPostInit)
pData->initPost();
@@ -225,7 +227,7 @@ 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);
DISTRHO_SAFE_ASSERT_RETURN(width > 0.0, 0);
return static_cast<uint>(width + 0.5);
}

@@ -234,7 +236,7 @@ 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);
DISTRHO_SAFE_ASSERT_RETURN(height > 0.0, 0);
return static_cast<uint>(height + 0.5);
}

@@ -243,8 +245,8 @@ 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>());
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));
}
@@ -269,10 +271,10 @@ void Window::setSize(uint width, uint height)
uint minWidth = pData->minWidth;
uint minHeight = pData->minHeight;

if (pData->autoScaling && scaleFactor != 1.0)
if (pData->autoScaling && d_isNotEqual(scaleFactor, 1.0))
{
minWidth *= scaleFactor;
minHeight *= scaleFactor;
minWidth = d_roundToUnsignedInt(minWidth * scaleFactor);
minHeight = d_roundToUnsignedInt(minHeight * scaleFactor);
}

// handle geometry constraints here
@@ -293,10 +295,10 @@ void Window::setSize(uint width, uint height)
{
// fix width
if (reqRatio > ratio)
width = static_cast<uint>(height * ratio + 0.5);
width = d_roundToUnsignedInt(height * ratio);
// fix height
else
height = static_cast<uint>(static_cast<double>(width) / ratio + 0.5);
height = d_roundToUnsignedInt(static_cast<double>(width) / ratio);
}
}
}
@@ -313,6 +315,16 @@ void Window::setSize(uint width, uint height)
else if (pData->view != nullptr)
{
puglSetSizeAndDefault(pData->view, width, height);

// there are no resize events for closed windows, so short-circuit the top-level widgets here
if (pData->isClosed)
{
for (std::list<TopLevelWidget*>::iterator it = pData->topLevelWidgets.begin(),
end = pData->topLevelWidgets.end(); it != end; ++it)
{
((Widget*)*it)->setSize(width, height);
}
}
}
}

@@ -402,7 +414,7 @@ void Window::focus()
pData->focus();
}

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
bool Window::openFileBrowser(const FileBrowserOptions& options)
{
return pData->openFileBrowser(options);
@@ -411,8 +423,13 @@ bool Window::openFileBrowser(const FileBrowserOptions& options)

void Window::repaint() noexcept
{
if (pData->view != nullptr)
puglPostRedisplay(pData->view);
if (pData->view == nullptr)
return;

if (pData->usesScheduledRepaints)
pData->appData->needsRepaint = true;

puglPostRedisplay(pData->view);
}

void Window::repaint(const Rectangle<uint>& rect) noexcept
@@ -420,6 +437,9 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
if (pData->view == nullptr)
return;

if (pData->usesScheduledRepaints)
pData->appData->needsRepaint = true;

PuglRect prect = {
static_cast<PuglCoord>(rect.getX()),
static_cast<PuglCoord>(rect.getY()),
@@ -430,10 +450,10 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept
{
const double autoScaleFactor = pData->autoScaleFactor;

prect.x *= autoScaleFactor;
prect.y *= autoScaleFactor;
prect.width *= autoScaleFactor;
prect.height *= 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);
}
puglPostRedisplayRect(pData->view, prect);
}
@@ -479,8 +499,8 @@ void Window::setGeometryConstraints(uint minimumWidth,

if (automaticallyScale && scaleFactor != 1.0)
{
minimumWidth *= scaleFactor;
minimumHeight *= scaleFactor;
minimumWidth = d_roundToUnsignedInt(minimumWidth * scaleFactor);
minimumHeight = d_roundToUnsignedInt(minimumHeight * scaleFactor);
}

puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio);
@@ -554,7 +574,7 @@ void Window::onScaleFactorChanged(double)
{
}

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
void Window::onFileSelected(const char*)
{
}


+ 23
- 17
dpf/dgl/src/WindowPrivateData.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -115,6 +115,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
isClosed(true),
isVisible(false),
isEmbed(false),
usesScheduledRepaints(false),
usesSizeRequest(false),
scaleFactor(DGL_NAMESPACE::getScaleFactor(view)),
autoScaling(false),
@@ -127,7 +128,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s)
waitingForClipboardEvents(false),
clipboardTypeId(0),
filenameToRenderInto(nullptr),
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
modal()
@@ -144,6 +145,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c
isClosed(true),
isVisible(false),
isEmbed(false),
usesScheduledRepaints(false),
usesSizeRequest(false),
scaleFactor(ppData->scaleFactor),
autoScaling(false),
@@ -156,7 +158,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c
waitingForClipboardEvents(false),
clipboardTypeId(0),
filenameToRenderInto(nullptr),
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
modal(ppData)
@@ -175,6 +177,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
isClosed(parentWindowHandle == 0),
isVisible(parentWindowHandle != 0),
isEmbed(parentWindowHandle != 0),
usesScheduledRepaints(false),
usesSizeRequest(false),
scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)),
autoScaling(false),
@@ -187,7 +190,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
waitingForClipboardEvents(false),
clipboardTypeId(0),
filenameToRenderInto(nullptr),
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
modal()
@@ -198,7 +201,9 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
Window::PrivateData::PrivateData(Application& a, Window* const s,
const uintptr_t parentWindowHandle,
const uint width, const uint height,
const double scale, const bool resizable, const bool usesSizeRequest_)
const double scale, const bool resizable,
const bool _usesScheduledRepaints,
const bool _usesSizeRequest)
: app(a),
appData(a.pData),
self(s),
@@ -207,7 +212,8 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
isClosed(parentWindowHandle == 0),
isVisible(parentWindowHandle != 0 && view != nullptr),
isEmbed(parentWindowHandle != 0),
usesSizeRequest(usesSizeRequest_),
usesScheduledRepaints(_usesScheduledRepaints),
usesSizeRequest(_usesSizeRequest),
scaleFactor(scale != 0.0 ? scale : DGL_NAMESPACE::getScaleFactor(view)),
autoScaling(false),
autoScaleFactor(1.0),
@@ -219,7 +225,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s,
waitingForClipboardEvents(false),
clipboardTypeId(0),
filenameToRenderInto(nullptr),
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
fileBrowserHandle(nullptr),
#endif
modal()
@@ -238,7 +244,7 @@ Window::PrivateData::~PrivateData()

if (isEmbed)
{
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
if (fileBrowserHandle != nullptr)
fileBrowserClose(fileBrowserHandle);
#endif
@@ -270,18 +276,18 @@ void Window::PrivateData::initPre(const uint width, const uint height, const boo

puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
puglSetViewHint(view, PUGL_IGNORE_KEY_REPEAT, PUGL_FALSE);
#if DGL_USE_RGBA
#if defined(DGL_USE_RGBA) && DGL_USE_RGBA
puglSetViewHint(view, PUGL_DEPTH_BITS, 24);
#else
#else
puglSetViewHint(view, PUGL_DEPTH_BITS, 16);
#endif
#endif
puglSetViewHint(view, PUGL_STENCIL_BITS, 8);

// PUGL_SAMPLES ??
puglSetEventFunc(view, puglEventCallback);

// setting default size triggers system-level calls, do it last
puglSetSizeHint(view, PUGL_DEFAULT_SIZE, width, height);
puglSetSizeHint(view, PUGL_DEFAULT_SIZE, static_cast<PuglSpan>(width), static_cast<PuglSpan>(height));
}

bool Window::PrivateData::initPost()
@@ -388,7 +394,7 @@ void Window::PrivateData::hide()
if (modal.enabled)
stopModal();

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
if (fileBrowserHandle != nullptr)
{
fileBrowserClose(fileBrowserHandle);
@@ -429,7 +435,7 @@ void Window::PrivateData::setResizable(const bool resizable)

void Window::PrivateData::idleCallback()
{
#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle))
{
self->onFileSelected(fileBrowserGetPath(fileBrowserHandle));
@@ -471,7 +477,7 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback)
return puglStopTimer(view, (uintptr_t)callback) == PUGL_SUCCESS;
}

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
// -----------------------------------------------------------------------
// file handling

@@ -492,7 +498,7 @@ bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options)

return fileBrowserHandle != nullptr;
}
#endif // ! DGL_FILE_BROWSER_DISABLED
#endif // DGL_USE_FILE_BROWSER

// -----------------------------------------------------------------------
// modal handling
@@ -598,7 +604,7 @@ void Window::PrivateData::onPuglConfigure(const double width, const double heigh
#ifndef DPF_TEST_WINDOW_CPP
FOR_EACH_TOP_LEVEL_WIDGET(it)
{
TopLevelWidget* const widget(*it);
TopLevelWidget* const widget = *it;

/* Some special care here, we call Widget::setSize instead of the TopLevelWidget one.
* This is because we want TopLevelWidget::setSize to handle both window and widget size,


+ 11
- 7
dpf/dgl/src/WindowPrivateData.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -60,7 +60,10 @@ struct Window::PrivateData : IdleCallback {
/** Whether this Window is embed into another (usually not DGL-controlled) Window. */
const bool isEmbed;

/** Whether to ignore resize requests and feed them into the host instead. used for VST3 */
/** Whether to schedule repaints on the next idle call, used for AU */
const bool usesScheduledRepaints;

/** Whether to ignore resize requests and feed them into the host instead, used for CLAP and VST3 */
const bool usesSizeRequest;

/** Scale factor to report to widgets on request, purely informational. */
@@ -87,10 +90,10 @@ struct Window::PrivateData : IdleCallback {
/** Render to a picture file when non-null, automatically free+unset after saving. */
char* filenameToRenderInto;

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
/** Handle for file browser dialog operations. */
DGL_NAMESPACE::FileBrowserHandle fileBrowserHandle;
#endif
#endif

/** Modal window setup. */
struct Modal {
@@ -131,7 +134,8 @@ struct Window::PrivateData : IdleCallback {

/** Constructor for an embed Window, with a few extra hints from the host side. */
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle,
uint width, uint height, double scaling, bool resizable, bool isVST3);
uint width, uint height, double scaling, bool resizable,
bool usesScheduledRepaints, bool usesSizeRequest);

/** Destructor. */
~PrivateData() override;
@@ -164,10 +168,10 @@ struct Window::PrivateData : IdleCallback {
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs);
bool removeIdleCallback(IdleCallback* callback);

#ifndef DGL_FILE_BROWSER_DISABLED
#ifdef DGL_USE_FILE_BROWSER
// file handling
bool openFileBrowser(const DGL_NAMESPACE::FileBrowserOptions& options);
#endif
#endif

static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height);



+ 2
- 0
dpf/dgl/src/pugl-upstream/.clang-tidy View File

@@ -6,9 +6,11 @@ Checks: >
-*-magic-numbers,
-altera*,
-bugprone-assignment-in-if-condition,
-bugprone-switch-missing-default-case,
-clang-diagnostic-unused-function,
-clang-diagnostic-unused-macros,
-llvmlibc-*,
-misc-include-cleaner,
-readability-identifier-length,
CheckOptions:
- key: hicpp-uppercase-literal-suffix.NewSuffixes


+ 19
- 14
dpf/dgl/src/pugl-upstream/include/pugl/pugl.h View File

@@ -145,7 +145,7 @@ typedef uint32_t PuglEventFlags;
typedef enum {
PUGL_CROSSING_NORMAL, ///< Crossing due to pointer motion
PUGL_CROSSING_GRAB, ///< Crossing due to a grab
PUGL_CROSSING_UNGRAB ///< Crossing due to a grab release
PUGL_CROSSING_UNGRAB, ///< Crossing due to a grab release
} PuglCrossingMode;

/// Common header for all event structs
@@ -342,6 +342,7 @@ typedef struct {
*/
typedef enum {
PUGL_KEY_BACKSPACE = 0x00000008U, ///< Backspace
PUGL_KEY_TAB = 0x00000009U, ///< Tab
PUGL_KEY_ENTER = 0x0000000DU, ///< Enter
PUGL_KEY_ESCAPE = 0x0000001BU, ///< Escape
PUGL_KEY_DELETE = 0x0000007FU, ///< Delete
@@ -414,10 +415,13 @@ typedef enum {

/// Keyboard modifier flags
typedef enum {
PUGL_MOD_SHIFT = 1U << 0U, ///< Shift key
PUGL_MOD_CTRL = 1U << 1U, ///< Control key
PUGL_MOD_ALT = 1U << 2U, ///< Alt/Option key
PUGL_MOD_SUPER = 1U << 3U ///< Mod4/Command/Windows key
PUGL_MOD_SHIFT = 1U << 0U, ///< Shift pressed
PUGL_MOD_CTRL = 1U << 1U, ///< Control pressed
PUGL_MOD_ALT = 1U << 2U, ///< Alt/Option pressed
PUGL_MOD_SUPER = 1U << 3U, ///< Super/Command/Windows pressed
PUGL_MOD_NUM_LOCK = 1U << 4U, ///< Num lock enabled
PUGL_MOD_SCROLL_LOCK = 1U << 5U, ///< Scroll lock enabled
PUGL_MOD_CAPS_LOCK = 1U << 6U, ///< Caps lock enabled
} PuglMod;

/// Bitwise OR of #PuglMod values
@@ -505,11 +509,11 @@ typedef struct {
arbitrary scroll direction freedom, like some touchpads.
*/
typedef enum {
PUGL_SCROLL_UP, ///< Scroll up
PUGL_SCROLL_DOWN, ///< Scroll down
PUGL_SCROLL_LEFT, ///< Scroll left
PUGL_SCROLL_RIGHT, ///< Scroll right
PUGL_SCROLL_SMOOTH ///< Smooth scroll in any direction
PUGL_SCROLL_UP, ///< Scroll up
PUGL_SCROLL_DOWN, ///< Scroll down
PUGL_SCROLL_LEFT, ///< Scroll left
PUGL_SCROLL_RIGHT, ///< Scroll right
PUGL_SCROLL_SMOOTH, ///< Smooth scroll in any direction
} PuglScrollDirection;

/**
@@ -763,7 +767,7 @@ typedef void* PuglWorldHandle;
/// The type of a World
typedef enum {
PUGL_PROGRAM, ///< Top-level application
PUGL_MODULE ///< Plugin or module within a larger application
PUGL_MODULE, ///< Plugin or module within a larger application
} PuglWorldType;

/// World flags
@@ -773,7 +777,7 @@ typedef enum {

X11: Calls XInitThreads() which is required for some drivers.
*/
PUGL_WORLD_THREADS = 1U << 0U
PUGL_WORLD_THREADS = 1U << 0U,
} PuglWorldFlag;

/// Bitwise OR of #PuglWorldFlag values
@@ -1023,7 +1027,7 @@ typedef enum {
If set, the view's size should be constrained to an aspect ratio no higher
than this. Mutually exclusive with #PUGL_FIXED_ASPECT.
*/
PUGL_MAX_ASPECT
PUGL_MAX_ASPECT,
} PuglSizeHint;

/// The number of #PuglSizeHint values
@@ -1569,7 +1573,8 @@ puglGetClipboard(PuglView* view, uint32_t typeIndex, size_t* len);
for example if compiled on X11 without Xcursor support.

@return #PUGL_BAD_PARAMETER if the given cursor is invalid,
#PUGL_FAILURE if the cursor is known but loading it system fails.
#PUGL_UNSUPPORTED if setting the cursor is not supported on this system, or
another error if the cursor is known but loading it fails.
*/
PUGL_API
PuglStatus


+ 13
- 5
dpf/dgl/src/pugl-upstream/src/common.c View File

@@ -146,12 +146,20 @@ puglNewView(PuglWorld* const world)

puglSetDefaultHints(view->hints);

// Add to world view list
++world->numViews;
world->views =
(PuglView**)realloc(world->views, world->numViews * sizeof(PuglView*));
// Enlarge world view list
const size_t newNumViews = world->numViews + 1U;
PuglView** const views =
(PuglView**)realloc(world->views, newNumViews * sizeof(PuglView*));

if (!views) {
free(view);
return NULL;
}

world->views[world->numViews - 1] = view;
// Add to world view list
world->views = views;
world->views[world->numViews] = view;
world->numViews = newNumViews;

return view;
}


+ 6
- 0
dpf/dgl/src/pugl-upstream/src/internal.c View File

@@ -132,6 +132,12 @@ puglFilterMods(const PuglMods state, const PuglKey key)
case PUGL_KEY_SUPER_L:
case PUGL_KEY_SUPER_R:
return state & ~(PuglMods)PUGL_MOD_SUPER;
case PUGL_KEY_NUM_LOCK:
return state & ~(PuglMods)PUGL_MOD_NUM_LOCK;
case PUGL_KEY_SCROLL_LOCK:
return state & ~(PuglMods)PUGL_MOD_SCROLL_LOCK;
case PUGL_KEY_CAPS_LOCK:
return state & ~(PuglMods)PUGL_MOD_CAPS_LOCK;
default:
break;
}


+ 39
- 24
dpf/dgl/src/pugl-upstream/src/mac.m View File

@@ -15,6 +15,7 @@

#include <mach/mach_time.h>

#include <stdint.h>
#include <stdlib.h>

#ifndef __MAC_10_10
@@ -325,11 +326,14 @@ dispatchCurrentChildViewConfiguration(PuglView* const view)
return;
}

const double viewY = (double)puglview->lastConfigure.height -
((rect.origin.y + rect.size.height) * scaleFactor);

const PuglExposeEvent ev = {
PUGL_EXPOSE,
0,
(PuglCoord)(rect.origin.x * scaleFactor),
(PuglCoord)(rect.origin.y * scaleFactor),
(PuglCoord)viewY,
(PuglSpan)(rect.size.width * scaleFactor),
(PuglSpan)(rect.size.height * scaleFactor),
};
@@ -371,7 +375,8 @@ getModifiers(const NSEvent* const ev)
return (((modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0) |
((modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0) |
((modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0) |
((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0));
((modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0) |
((modifierFlags & (1U << 16U)) ? PUGL_MOD_CAPS_LOCK : 0));
}

static PuglKey
@@ -625,10 +630,16 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)

- (void)scrollWheel:(NSEvent*)event
{
const NSPoint wloc = [self eventLocation:event];
const NSPoint rloc = [NSEvent mouseLocation];
const double dx = -[event scrollingDeltaX];
const double dy = [event scrollingDeltaY];
const NSPoint wloc = [self eventLocation:event];
const NSPoint rloc = [NSEvent mouseLocation];

double dx = -[event scrollingDeltaX];
double dy = [event scrollingDeltaY];
if (![event hasPreciseScrollingDeltas]) {
dx *= 10.0;
dy *= 10.0;
}

const PuglScrollDirection dir =
((dx == 0.0 && dy > 0.0)
? PUGL_SCROLL_UP
@@ -648,7 +659,7 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
rloc.x,
[[NSScreen mainScreen] frame].size.height - rloc.y,
getModifiers(event),
[event hasPreciseScrollingDeltas] ? PUGL_SCROLL_SMOOTH : dir,
dir,
dx,
dy,
};
@@ -836,32 +847,36 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type)
}
}

static bool
flagDiffers(const uint32_t lhs, const uint32_t rhs, const uint32_t mask)
{
return (lhs & mask) != (rhs & mask);
}

- (void)flagsChanged:(NSEvent*)event
{
const uint32_t mods = getModifiers(event);
PuglEventType type = PUGL_NOTHING;
PuglKey special = (PuglKey)0;

if ((mods & PUGL_MOD_SHIFT) != (puglview->impl->mods & PUGL_MOD_SHIFT)) {
type = mods & PUGL_MOD_SHIFT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
special = PUGL_KEY_SHIFT_L;
} else if ((mods & PUGL_MOD_CTRL) != (puglview->impl->mods & PUGL_MOD_CTRL)) {
type = mods & PUGL_MOD_CTRL ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
special = PUGL_KEY_CTRL_L;
} else if ((mods & PUGL_MOD_ALT) != (puglview->impl->mods & PUGL_MOD_ALT)) {
type = mods & PUGL_MOD_ALT ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
special = PUGL_KEY_ALT_L;
} else if ((mods & PUGL_MOD_SUPER) !=
(puglview->impl->mods & PUGL_MOD_SUPER)) {
type = mods & PUGL_MOD_SUPER ? PUGL_KEY_PRESS : PUGL_KEY_RELEASE;
special = PUGL_KEY_SUPER_L;
const uint16_t keyCode = [event keyCode];
if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_SHIFT)) {
special = (keyCode == 0x3C) ? PUGL_KEY_SHIFT_R : PUGL_KEY_SHIFT_L;
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_CTRL)) {
special = (keyCode == 0x3E) ? PUGL_KEY_CTRL_R : PUGL_KEY_CTRL_L;
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_ALT)) {
special = (keyCode == 0x3D) ? PUGL_KEY_ALT_R : PUGL_KEY_ALT_L;
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_SUPER)) {
special = PUGL_KEY_SUPER_L; // Left and right command are identical
} else if (flagDiffers(mods, puglview->impl->mods, PUGL_MOD_CAPS_LOCK)) {
special = PUGL_KEY_CAPS_LOCK;
}

if (special != 0) {
const NSPoint wloc = [self eventLocation:event];
const NSPoint rloc = [NSEvent mouseLocation];
const NSPoint wloc = [self eventLocation:event];
const NSPoint rloc = [NSEvent mouseLocation];
const bool release = [event type] == NSEventTypeKeyUp;

const PuglKeyEvent ev = {type,
const PuglKeyEvent ev = {release ? PUGL_KEY_RELEASE : PUGL_KEY_PRESS,
0,
[event timestamp],
wloc.x,


+ 1
- 3
dpf/dgl/src/pugl-upstream/src/mac_cairo.m View File

@@ -93,10 +93,8 @@ puglMacCairoEnter(PuglView* view, const PuglExposeEvent* expose)
const CGSize sizePx = {(CGFloat)view->lastConfigure.width,
(CGFloat)view->lastConfigure.height};

const CGSize sizePt = CGContextConvertSizeToUserSpace(context, sizePx);

// Convert coordinates to standard Cairo space
CGContextTranslateCTM(context, 0.0, sizePt.height);
CGContextTranslateCTM(context, 0.0, sizePx.height * scale);
CGContextScaleCTM(context, scale, -scale);

drawView->surface = cairo_quartz_surface_create_for_cg_context(


+ 44
- 23
dpf/dgl/src/pugl-upstream/src/win.c View File

@@ -94,6 +94,12 @@ puglWinStatus(const BOOL success)
static bool
puglRegisterWindowClass(const char* name)
{
#ifdef UNICODE
wchar_t* const wname = puglUtf8ToWideChar(name);
#else
const char* const wname = name;
#endif

HMODULE module = NULL;
if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
@@ -103,7 +109,7 @@ puglRegisterWindowClass(const char* name)
}

WNDCLASSEX wc = PUGL_INIT_STRUCT;
if (GetClassInfoEx(module, name, &wc)) {
if (GetClassInfoEx(module, wname, &wc)) {
return true; // Already registered
}

@@ -114,9 +120,13 @@ puglRegisterWindowClass(const char* name)
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszClassName = name;
wc.lpszClassName = wname;

return !!RegisterClassEx(&wc);
const bool success = !!RegisterClassEx(&wc);
#ifdef UNICODE
free(wname);
#endif
return success;
}

static unsigned
@@ -174,7 +184,7 @@ static double
puglWinGetViewScaleFactor(const PuglView* const view)
{
const HMODULE shcore =
LoadLibraryEx("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
LoadLibraryExA("Shcore.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!shcore) {
return 1.0;
}
@@ -209,7 +219,7 @@ puglInitWorldInternals(PuglWorldType type, PuglWorldFlags PUGL_UNUSED(flags))

if (type == PUGL_PROGRAM) {
HMODULE user32 =
LoadLibraryEx("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
LoadLibraryExA("user32.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (user32) {
PFN_SetProcessDPIAware SetProcessDPIAware =
(PFN_SetProcessDPIAware)GetProcAddress(user32, "SetProcessDPIAware");
@@ -398,7 +408,14 @@ puglFreeViewInternals(PuglView* view)
void
puglFreeWorldInternals(PuglWorld* world)
{
#ifdef UNICODE
wchar_t* const wname = puglUtf8ToWideChar(world->strings[PUGL_CLASS_NAME]);
UnregisterClass(wname, NULL);
free(wname);
#else
UnregisterClass(world->strings[PUGL_CLASS_NAME], NULL);
#endif

free(world->impl);
}

@@ -472,11 +489,15 @@ static uint32_t
getModifiers(void)
{
// clang-format off
return (((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) |
((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) |
((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) |
((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U));
return (
((GetKeyState(VK_SHIFT) < 0) ? (uint32_t)PUGL_MOD_SHIFT : 0U) |
((GetKeyState(VK_CONTROL) < 0) ? (uint32_t)PUGL_MOD_CTRL : 0U) |
((GetKeyState(VK_MENU) < 0) ? (uint32_t)PUGL_MOD_ALT : 0U) |
((GetKeyState(VK_LWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((GetKeyState(VK_RWIN) < 0) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((GetKeyState(VK_NUMLOCK) & 1U) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) |
((GetKeyState(VK_SCROLL) & 1U) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) |
((GetKeyState(VK_CAPITAL) & 1U) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U));
// clang-format on
}

@@ -1477,7 +1498,7 @@ puglPaste(PuglView* const view)
return PUGL_SUCCESS;
}

static const char* const cursor_ids[] = {
static const TCHAR* const cursor_ids[] = {
IDC_ARROW, // ARROW
IDC_IBEAM, // CARET
IDC_CROSS, // CROSSHAIR
@@ -1602,18 +1623,18 @@ puglWinCreateWindow(PuglView* const view,
AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags);

// Create window and get drawing context
if (!(*hwnd = CreateWindowEx(winExFlags,
className,
title,
winFlags,
wr.left,
wr.right,
wr.right - wr.left,
wr.bottom - wr.top,
(HWND)parent,
NULL,
NULL,
NULL))) {
if (!(*hwnd = CreateWindowExA(winExFlags,
className,
title,
winFlags,
wr.left,
wr.right,
wr.right - wr.left,
wr.bottom - wr.top,
(HWND)parent,
NULL,
NULL,
NULL))) {
return PUGL_REALIZE_FAILED;
}



+ 1
- 1
dpf/dgl/src/pugl-upstream/src/win_gl.c View File

@@ -288,7 +288,7 @@ puglGetProcAddress(const char* name)

return func
? func
: (PuglGlFunc)GetProcAddress(GetModuleHandle("opengl32.dll"), name);
: (PuglGlFunc)GetProcAddress(GetModuleHandleA("opengl32.dll"), name);
}

PuglStatus


+ 1
- 1
dpf/dgl/src/pugl-upstream/src/win_vulkan.c View File

@@ -32,7 +32,7 @@ puglNewVulkanLoader(PuglWorld* PUGL_UNUSED(world),

const char* const filename = libraryName ? libraryName : "vulkan-1.dll";
if (!(loader->libvulkan =
LoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS))) {
LoadLibraryExA(filename, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS))) {
free(loader);
return NULL;
}


+ 52
- 31
dpf/dgl/src/pugl-upstream/src/x11.c View File

@@ -416,8 +416,9 @@ updateSizeHints(const PuglView* const view)
sizeHints.max_width = (int)frame.width;
sizeHints.max_height = (int)frame.height;
} else {
// Avoid setting PBaseSize for top level views to avoid window manager bugs
const PuglViewSize defaultSize = view->sizeHints[PUGL_DEFAULT_SIZE];
if (puglIsValidSize(defaultSize)) {
if (puglIsValidSize(defaultSize) && view->parent) {
sizeHints.flags |= PBaseSize;
sizeHints.base_width = defaultSize.width;
sizeHints.base_height = defaultSize.height;
@@ -881,7 +882,8 @@ translateKey(PuglView* const view, XEvent* const xevent, PuglEvent* const event)
event->key.keycode = xevent->xkey.keycode;

// Mask off the control and shift bits to get the lowercase "main" symbol
xevent->xkey.state = xevent->xkey.state & ~(unsigned)(ControlMask|ShiftMask);
xevent->xkey.state =
xevent->xkey.state & ~(unsigned)(ControlMask | ShiftMask);

// Lookup unshifted key
char ustr[8] = PUGL_INIT_STRUCT;
@@ -919,7 +921,10 @@ translateModifiers(const unsigned xstate)
return (((xstate & ShiftMask) ? (uint32_t)PUGL_MOD_SHIFT : 0U) |
((xstate & ControlMask) ? (uint32_t)PUGL_MOD_CTRL : 0U) |
((xstate & Mod1Mask) ? (uint32_t)PUGL_MOD_ALT : 0U) |
((xstate & Mod4Mask) ? (uint32_t)PUGL_MOD_SUPER : 0U));
((xstate & Mod4Mask) ? (uint32_t)PUGL_MOD_SUPER : 0U) |
((xstate & Mod2Mask) ? (uint32_t)PUGL_MOD_NUM_LOCK : 0U) |
((xstate & Mod3Mask) ? (uint32_t)PUGL_MOD_SCROLL_LOCK : 0U) |
((xstate & LockMask) ? (uint32_t)PUGL_MOD_CAPS_LOCK : 0U));
}

static PuglStatus
@@ -957,28 +962,37 @@ getX11SelectionClipboard(PuglView* const view, const Atom selection)
: NULL;
}

static void
static PuglStatus
setClipboardFormats(PuglView* const view,
PuglX11Clipboard* const board,
const unsigned long numFormats,
const Atom* const formats)
{
Atom* const newFormats =
(Atom*)realloc(board->formats, numFormats * sizeof(Atom));
if (!newFormats) {
return;
}

// Clear current board formats
for (unsigned long i = 0; i < board->numFormats; ++i) {
free(board->formatStrings[i]);
board->formatStrings[i] = NULL;
}

board->formats = newFormats;
board->numFormats = 0;

board->formatStrings =
// Enlarge formats array
Atom* const newFormats =
(Atom*)realloc(board->formats, numFormats * sizeof(Atom));
if (!newFormats) {
return PUGL_NO_MEMORY;
}

board->formats = newFormats;

// Enlarge format strings array
char** const newFormatStrings =
(char**)realloc(board->formatStrings, numFormats * sizeof(char*));
if (!newFormatStrings) {
return PUGL_NO_MEMORY;
}

board->formatStrings = newFormatStrings;

for (unsigned long i = 0; i < numFormats; ++i) {
if (formats[i]) {
@@ -1005,6 +1019,8 @@ setClipboardFormats(PuglView* const view,
XFree(name);
}
}

return PUGL_SUCCESS;
}

static PuglEvent
@@ -1390,10 +1406,13 @@ puglStartTimer(PuglView* const view, const uintptr_t id, const double timeout)
}

// Add new timer
const size_t size = ++w->numTimers * sizeof(timer);
w->timers = (PuglTimer*)realloc(w->timers, size);
w->timers[w->numTimers - 1] = timer;
return PUGL_SUCCESS;
const size_t size = ++w->numTimers * sizeof(timer);
PuglTimer* const newTimers = (PuglTimer*)realloc(w->timers, size);
if (newTimers) {
w->timers = newTimers;
w->timers[w->numTimers - 1] = timer;
return PUGL_SUCCESS;
}
}
}
#else
@@ -1583,7 +1602,7 @@ retrieveSelection(const PuglWorld* const world,
return PUGL_SUCCESS;
}

static void
static PuglStatus
handleSelectionNotify(const PuglWorld* const world,
PuglView* const view,
const XSelectionEvent* const event)
@@ -1600,9 +1619,8 @@ handleSelectionNotify(const PuglWorld* const world,
unsigned long numFormats = 0;
Atom* formats = NULL;
if (!getAtomProperty(
view, event->requestor, event->property, &numFormats, &formats)) {
setClipboardFormats(view, board, numFormats, formats);

view, event->requestor, event->property, &numFormats, &formats) &&
!setClipboardFormats(view, board, numFormats, formats)) {
const PuglDataOfferEvent offer = {
PUGL_DATA_OFFER, 0, (double)event->time / 1e3};

@@ -1628,7 +1646,7 @@ handleSelectionNotify(const PuglWorld* const world,
}
}

puglDispatchEvent(view, &puglEvent);
return puglDispatchEvent(view, &puglEvent);
}

static PuglStatus
@@ -1754,8 +1772,7 @@ handleTimerEvent(PuglWorld* const world, const XEvent xevent)
static PuglStatus
dispatchX11Events(PuglWorld* const world)
{
PuglStatus st0 = PUGL_SUCCESS;
PuglStatus st1 = PUGL_SUCCESS;
PuglStatus st = PUGL_SUCCESS;

// Flush output to the server once at the start
Display* display = world->impl->display;
@@ -1791,9 +1808,13 @@ dispatchX11Events(PuglWorld* const world)
clearX11Clipboard(board);
}
} else if (xevent.type == SelectionNotify) {
handleSelectionNotify(world, view, &xevent.xselection);
st = handleSelectionNotify(world, view, &xevent.xselection);
} else if (xevent.type == SelectionRequest) {
handleSelectionRequest(world, view, &xevent.xselectionrequest);
st = handleSelectionRequest(world, view, &xevent.xselectionrequest);
}

if (st) {
break;
}

// Translate X11 event to Pugl event
@@ -1822,12 +1843,12 @@ dispatchX11Events(PuglWorld* const world)
break;
default:
// Dispatch event to application immediately
st0 = puglDispatchEvent(view, &event);
st = puglDispatchEvent(view, &event);
break;
}
}

return st0 ? st0 : st1;
return st;
}

#ifndef PUGL_DISABLE_DEPRECATED
@@ -2042,7 +2063,7 @@ puglSetTransientParent(PuglView* const view, const PuglNativeView parent)

view->transientParent = parent;

if (view->impl->win) {
if (view->impl->win && view->transientParent) {
XSetTransientForHint(
display, view->impl->win, (Window)view->transientParent);
}
@@ -2138,12 +2159,12 @@ puglSetClipboard(PuglView* const view,
PuglInternals* const impl = view->impl;
Display* const display = view->world->impl->display;
PuglX11Clipboard* const board = &view->impl->clipboard;
const PuglStatus st = puglSetBlob(&board->data, data, len);
PuglStatus st = puglSetBlob(&board->data, data, len);

if (!st) {
const Atom format = {XInternAtom(display, type, 0)};

setClipboardFormats(view, board, 1, &format);
st = setClipboardFormats(view, board, 1, &format);
XSetSelectionOwner(display, board->selection, impl->win, CurrentTime);

board->source = impl->win;
@@ -2174,7 +2195,7 @@ puglSetCursor(PuglView* const view, const PuglCursor cursor)
#else
(void)view;
(void)cursor;
return PUGL_FAILURE;
return PUGL_UNSUPPORTED;
#endif
}



+ 35
- 18
dpf/dgl/src/pugl.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -138,15 +138,18 @@ START_NAMESPACE_DGL
# endif
#elif defined(DISTRHO_OS_MAC)
# ifndef DISTRHO_MACOS_NAMESPACE_MACRO
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE)
# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglCairoView)
# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglOpenGLView)
# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView)
# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglVulkanView)
# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow)
# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindowDelegate)
# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView)
# ifndef DISTRHO_MACOS_NAMESPACE_TIME
# define DISTRHO_MACOS_NAMESPACE_TIME __apple_build_version__
# endif
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, TIME, INTERFACE) NS ## SEP ## TIME ## SEP ## INTERFACE
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, TIME, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, TIME, INTERFACE)
# define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglCairoView)
# define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglOpenGLView)
# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglStubView)
# define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglVulkanView)
# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindow)
# define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWindowDelegate)
# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, DISTRHO_MACOS_NAMESPACE_TIME, PuglWrapperView)
# endif
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
@@ -181,7 +184,14 @@ START_NAMESPACE_DGL
# include "pugl-upstream/src/win_vulkan.c"
# endif
#elif defined(HAVE_X11)
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
# endif
# include "pugl-upstream/src/x11.c"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic pop
# endif
# include "pugl-upstream/src/x11_stub.c"
# ifdef DGL_CAIRO
# include "pugl-upstream/src/x11_cairo.c"
@@ -277,13 +287,13 @@ void puglRaiseWindow(PuglView* const view)

PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect)
{
view->sizeHints[PUGL_MIN_SIZE].width = width;
view->sizeHints[PUGL_MIN_SIZE].height = height;
view->sizeHints[PUGL_MIN_SIZE].width = static_cast<PuglSpan>(width);
view->sizeHints[PUGL_MIN_SIZE].height = static_cast<PuglSpan>(height);

if (aspect)
{
view->sizeHints[PUGL_FIXED_ASPECT].width = width;
view->sizeHints[PUGL_FIXED_ASPECT].height = height;
view->sizeHints[PUGL_FIXED_ASPECT].width = static_cast<PuglSpan>(width);
view->sizeHints[PUGL_FIXED_ASPECT].height = static_cast<PuglSpan>(height);
}

#if defined(DISTRHO_OS_HAIKU)
@@ -353,7 +363,7 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)

#ifdef DGL_USING_X11
// workaround issues in fluxbox, see https://github.com/lv2/pugl/issues/118
if (view->impl->win)
if (view->impl->win && !view->parent && !view->transientParent)
{
view->sizeHints[PUGL_DEFAULT_SIZE].width = view->sizeHints[PUGL_DEFAULT_SIZE].height = 0;
}
@@ -397,9 +407,16 @@ PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)
if (const PuglStatus status = puglSetSize(view, width, height))
return status;

// handle new PUGL_DEFAULT_SIZE hint
if (const PuglStatus status = updateSizeHints(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;

// flush size changes
XFlush(view->world->impl->display);


+ 56
- 43
dpf/distrho/DistrhoDetails.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -511,15 +511,6 @@ struct ParameterEnumerationValue {
ParameterEnumerationValue(float v, const char* l) noexcept
: value(v),
label(l) {}

#if __cplusplus >= 201703L
/**
Constructor using custom values, constexpr compatible variant.
*/
constexpr ParameterEnumerationValue(float v, const std::string_view& l) noexcept
: value(v),
label(l) {}
#endif
};

/**
@@ -566,7 +557,7 @@ struct ParameterEnumerationValues {
When using this constructor the pointer to @values MUST have been statically declared.@n
It will not be automatically deleted later.
*/
constexpr ParameterEnumerationValues(uint32_t c, bool r, ParameterEnumerationValue* v) noexcept
constexpr ParameterEnumerationValues(uint8_t c, bool r, ParameterEnumerationValue* v) noexcept
: count(c),
restrictedMode(r),
values(v),
@@ -578,6 +569,8 @@ struct ParameterEnumerationValues {
if (deleteLater)
delete[] values;
}

DISTRHO_DECLARE_NON_COPYABLE(ParameterEnumerationValues)
};

/**
@@ -669,6 +662,7 @@ struct Parameter {
shortName(),
symbol(),
unit(),
description(),
ranges(),
enumValues(),
designation(kParameterDesignationNull),
@@ -684,6 +678,7 @@ struct Parameter {
shortName(),
symbol(s),
unit(u),
description(),
ranges(def, min, max),
enumValues(),
designation(kParameterDesignationNull),
@@ -702,6 +697,7 @@ struct Parameter {
shortName(),
symbol(s),
unit(u),
description(),
ranges(def, min, max),
enumValues(evcount, true, ev),
designation(kParameterDesignationNull),
@@ -709,29 +705,6 @@ struct Parameter {
groupId(kPortGroupNone) {}
#endif

#if __cplusplus >= 201703L
/**
Constructor for constexpr compatible data.
*/
constexpr Parameter(uint32_t h,
const std::string_view& n,
const std::string_view& sn,
const std::string_view& sym,
const std::string_view& u,
const std::string_view& desc) noexcept
: hints(h),
name(n),
shortName(sn),
symbol(sym),
unit(u),
description(desc),
ranges(),
enumValues(),
designation(kParameterDesignationNull),
midiCC(0),
groupId(kPortGroupNone) {}
#endif

/**
Initialize a parameter for a specific designation.
*/
@@ -757,17 +730,57 @@ struct Parameter {
break;
}
}
};

#if __cplusplus >= 202001L /* TODO */
/**
Bypass parameter definition in constexpr form.
*/
static constexpr const Parameter kParameterBypass = {
kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger,
"Bypass", "Bypass", ParameterDesignationSymbols::bypass, "", "", {}, {}, 0, kPortGroupNone,
Parameter& operator=(Parameter& other) noexcept
{
hints = other.hints;
name = other.name;
shortName = other.shortName;
symbol = other.symbol;
unit = other.unit;
description = other.description;
ranges = other.ranges;
designation = other.designation;
midiCC = other.midiCC;
groupId = other.groupId;

// enumValues needs special handling
enumValues.count = other.enumValues.count;
enumValues.restrictedMode = other.enumValues.restrictedMode;
enumValues.values = other.enumValues.values;
enumValues.deleteLater = other.enumValues.deleteLater;

// make sure to not delete data twice
other.enumValues.deleteLater = false;

return *this;
}

Parameter& operator=(const Parameter& other) noexcept
{
hints = other.hints;
name = other.name;
shortName = other.shortName;
symbol = other.symbol;
unit = other.unit;
description = other.description;
ranges = other.ranges;
designation = other.designation;
midiCC = other.midiCC;
groupId = other.groupId;

// make sure to not delete data twice
DISTRHO_SAFE_ASSERT_RETURN(other.enumValues.values == nullptr || !other.enumValues.deleteLater, *this);

// enumValues needs special handling
enumValues.count = other.enumValues.count;
enumValues.restrictedMode = other.enumValues.restrictedMode;
enumValues.values = other.enumValues.values;
enumValues.deleteLater = other.enumValues.deleteLater;

return *this;
}
};
#endif

/**
Port Group.@n


+ 54
- 21
dpf/distrho/DistrhoInfo.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -603,6 +603,12 @@ START_NAMESPACE_DISTRHO
*/
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1

/**
Whether the %UI uses Cairo for drawing instead of the default OpenGL mode.@n
When enabled your %UI instance will subclass @ref CairoTopLevelWidget instead of @ref TopLevelWidget.
*/
#define DISTRHO_UI_USE_CAIRO 1

/**
Whether the %UI uses a custom toolkit implementation based on OpenGL.@n
When enabled, the macros @ref DISTRHO_UI_CUSTOM_INCLUDE_PATH and @ref DISTRHO_UI_CUSTOM_WIDGET_TYPE are required.
@@ -616,6 +622,12 @@ START_NAMESPACE_DISTRHO
*/
#define DISTRHO_UI_CUSTOM_INCLUDE_PATH

/**
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL mode.@n
When enabled your %UI instance will subclass @ref NanoTopLevelWidget instead of @ref TopLevelWidget.
*/
#define DISTRHO_UI_USE_NANOVG 1

/**
The top-level-widget typedef to use for the custom toolkit.
This widget class MUST be a subclass of DGL TopLevelWindow class.
@@ -648,25 +660,54 @@ START_NAMESPACE_DISTRHO
#define DISTRHO_UI_DEFAULT_HEIGHT 300

/**
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n
When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget.
*/
#define DISTRHO_UI_USE_NANOVG 1

/**
Whether the %UI is resizable to any size by the user.@n
By default this is false, and resizing is only allowed under the plugin UI control,@n
Whether the %UI is resizable to any size by the user and OS.@n
By default this is false, with resizing only allowed when coded from the the plugin UI side.@n
Enabling this options makes it possible for the user to resize the plugin UI at anytime.
@see UI::setGeometryConstraints(uint, uint, bool, bool)
*/
#define DISTRHO_UI_USER_RESIZABLE 1

/**
Whether to %UI is going to use file browser dialogs.@n
By default this is false, with the file browser APIs not available for use.
*/
#define DISTRHO_UI_FILE_BROWSER 1

/**
Whether to %UI is going to use web browser views.@n
By default this is false, with the web browser APIs not available for use.
*/
#define DISTRHO_UI_WEB_VIEW 1

/**
The %UI URI when exporting in LV2 format.@n
By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix.
*/
#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"

/**
The AudioUnit type for a plugin.@n
This is a 4-character symbol, automatically set by DPF based on other plugin macros.
See https://developer.apple.com/documentation/audiotoolbox/1584142-audio_unit_types for more information.
*/
#define DISTRHO_PLUGIN_AU_TYPE aufx

/**
A 4-character symbol that identifies a brand or manufacturer, with at least one non-lower case character.@n
Plugins from the same brand should use the same symbol.
@note This macro is required when building AU plugins, and used for VST3 if present
@note Setting this macro will change the uid of a VST3 plugin.
If you already released a DPF-based VST3 plugin make sure to also enable DPF_VST3_DONT_USE_BRAND_ID
*/
#define DISTRHO_PLUGIN_BRAND_ID Dstr

/**
A 4-character symbol which identifies a plugin.@n
It must be unique within at least a set of plugins from the brand.
@note This macro is required when building AU plugins
*/
#define DISTRHO_PLUGIN_UNIQUE_ID test

/**
Custom LV2 category for the plugin.@n
This is a single string, and can be one of the following values:
@@ -842,7 +883,7 @@ START_NAMESPACE_DISTRHO
/**
Whether to enable runtime plugin tests.@n
This will check, during initialization of the plugin, if parameters, programs and states are setup properly.@n
Useful to enable as part of CI, can safely be skipped.@n
Useful to enable as part of CI, can be safely skipped.@n
Under DPF makefiles this can be enabled by using `make DPF_RUNTIME_TESTING=true`.

@note Some checks are only available with the GCC compiler,
@@ -857,10 +898,10 @@ START_NAMESPACE_DISTRHO
#define DPF_VST_SHOW_PARAMETER_OUTPUTS

/**
Disable all file browser related code.@n
Must be set as compiler macro when building DGL. (e.g. `CXXFLAGS="-DDGL_FILE_BROWSER_DISABLED"`)
Forcibly ignore DISTRHO_PLUGIN_BRAND_ID for VST3 plugins.@n
This is required for DPF-based VST3 plugins that got released without setting DISTRHO_PLUGIN_BRAND_ID first.
*/
#define DGL_FILE_BROWSER_DISABLED
#define DPF_VST3_DONT_USE_BRAND_ID

/**
Disable resource files, like internally used fonts.@n
@@ -868,14 +909,6 @@ START_NAMESPACE_DISTRHO
*/
#define DGL_NO_SHARED_RESOURCES

/**
Whether to use OpenGL3 instead of the default OpenGL2 compatility profile.
Under DPF makefiles this can be enabled by using `make USE_OPENGL3=true` on the dgl build step.

@note This is experimental and incomplete, contributions are welcome and appreciated.
*/
#define DGL_USE_OPENGL3

/** @} */

/* ------------------------------------------------------------------------------------------------------------


+ 56
- 4
dpf/distrho/DistrhoPlugin.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -189,30 +189,65 @@ protected:
Get the plugin label.@n
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters.
*/
#ifdef DISTRHO_PLUGIN_LABEL
virtual const char* getLabel() const
{
return DISTRHO_PLUGIN_LABEL;
}
#else
virtual const char* getLabel() const = 0;
#endif

/**
Get an extensive comment/description about the plugin.@n
Optional, returns nothing by default.
*/
virtual const char* getDescription() const { return ""; }
virtual const char* getDescription() const
{
#ifdef DISTRHO_PLUGIN_DESCRIPTION
return DISTRHO_PLUGIN_DESCRIPTION;
#else
return "";
#endif
}

/**
Get the plugin author/maker.
*/
#ifdef DISTRHO_PLUGIN_MAKER
virtual const char* getMaker() const
{
return DISTRHO_PLUGIN_MAKER;
}
#else
virtual const char* getMaker() const = 0;
#endif

/**
Get the plugin homepage.@n
Optional, returns nothing by default.
*/
virtual const char* getHomePage() const { return ""; }
virtual const char* getHomePage() const
{
#ifdef DISTRHO_PLUGIN_HOMEPAGE
return DISTRHO_PLUGIN_HOMEPAGE;
#else
return "";
#endif
}

/**
Get the plugin license (a single line of text or a URL).@n
For commercial plugins this should return some short copyright information.
*/
#ifdef DISTRHO_PLUGIN_LICENSE
virtual const char* getLicense() const
{
return DISTRHO_PLUGIN_LICENSE;
}
#else
virtual const char* getLicense() const = 0;
#endif

/**
Get the plugin version, in hexadecimal.
@@ -222,10 +257,19 @@ protected:

/**
Get the plugin unique Id.@n
This value is used by LADSPA, DSSI, VST2 and VST3 plugin formats.
This value is used by LADSPA, DSSI, VST2, VST3 and AUv2 plugin formats.@n
@note It is preferred that you set DISTRHO_PLUGIN_UNIQUE_ID macro instead of overriding this call,
as that is required for AUv2 plugins anyhow.
@see d_cconst()
*/
#ifdef DISTRHO_PLUGIN_UNIQUE_ID
virtual int64_t getUniqueId() const
{
return d_cconst(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID));
}
#else
virtual int64_t getUniqueId() const = 0;
#endif

/* --------------------------------------------------------------------------------------------------------
* Init */
@@ -364,6 +408,14 @@ protected:
*/
virtual void sampleRateChanged(double newSampleRate);

/**
Optional callback to inform the plugin about audio port IO changes.@n
This function will only be called when the plugin is deactivated.@n
Only used in AU (AudioUnit) format when DISTRHO_PLUGIN_EXTRA_IO is defined.
@see DISTRHO_PLUGIN_EXTRA_IO
*/
virtual void ioChanged(uint16_t numInputs, uint16_t numOutputs);

// -------------------------------------------------------------------------------------------------------

private:


+ 392
- 0
dpf/distrho/DistrhoPluginInfo.h.template View File

@@ -0,0 +1,392 @@
#pragma once

/**
This file contains C Macros that describe this plugin.
With these macros we can tell the host what features the plugin requires.
New functions will be available to call and/or override depending on which macros are enabled.

All values are either integer or strings.
For boolean-like values 1 means 'on' and 0 means 'off'.
*/

/**
The plugin name.
This is used to identify your plugin before a Plugin instance can be created.
@note This macro is required.
*/
#define DISTRHO_PLUGIN_NAME "Plugin Name"

/**
Number of audio inputs the plugin has.
@note This macro is required.
*/
#define DISTRHO_PLUGIN_NUM_INPUTS 2

/**
Number of audio outputs the plugin has.
@note This macro is required.
*/
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2

/**
The plugin URI when exporting in LV2 format.
TODO describe what a URI is
@note This macro is required.
*/
#define DISTRHO_PLUGIN_URI "urn:distrho:name"

/**
Whether the plugin has a custom UI.
*/
// #define DISTRHO_PLUGIN_HAS_UI 0

/**
Whether the plugin processing is realtime-safe.
TODO - list rtsafe requirements
*/
// #define DISTRHO_PLUGIN_IS_RT_SAFE 0

/**
Whether the plugin is a synth.
@ref DISTRHO_PLUGIN_WANT_MIDI_INPUT is automatically enabled when this is too.
@see DISTRHO_PLUGIN_WANT_MIDI_INPUT
*/
// #define DISTRHO_PLUGIN_IS_SYNTH 0

/**
Request the minimum buffer size for the input and output event ports.
Currently only used in LV2, with a default value of 2048 if unset.
*/
// #define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048

/**
Whether the plugin has an LV2 modgui.

This will simply add a "rdfs:seeAlso <modgui.ttl>" on the LV2 manifest.
It is up to you to create this file.
*/
// #define DISTRHO_PLUGIN_USES_MODGUI 0

/**
Enable direct access between the UI and plugin code.
@see UI::getPluginInstancePointer()
@note DO NOT USE THIS UNLESS STRICTLY NECESSARY!!
Try to avoid it at all costs!
*/
// #define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0

/**
Whether the plugin introduces latency during audio or midi processing.
@see Plugin::setLatency(uint32_t)
*/
// #define DISTRHO_PLUGIN_WANT_LATENCY 0

/**
Whether the plugin wants MIDI input.
This is automatically enabled if @ref DISTRHO_PLUGIN_IS_SYNTH is true.
*/
// #define DISTRHO_PLUGIN_WANT_MIDI_INPUT 0

/**
Whether the plugin wants MIDI output.
@see Plugin::writeMidiEvent(const MidiEvent&)
*/
// #define DISTRHO_PLUGIN_WANT_MIDI_OUTPUT 0

/**
Whether the plugin wants to change its own parameter inputs.
Not all hosts or plugin formats support this,
so Plugin::canRequestParameterValueChanges() can be used to query support at runtime.
@see Plugin::requestParameterValueChange(uint32_t, float)
*/
// #define DISTRHO_PLUGIN_WANT_PARAMETER_VALUE_CHANGE_REQUEST 0

/**
Whether the plugin provides its own internal programs.
@see Plugin::initProgramName(uint32_t, String&)
@see Plugin::loadProgram(uint32_t)
*/
// #define DISTRHO_PLUGIN_WANT_PROGRAMS 0

/**
Whether the plugin uses internal non-parameter data.
@see Plugin::initState(uint32_t, String&, String&)
@see Plugin::setState(const char*, const char*)
*/
// #define DISTRHO_PLUGIN_WANT_STATE 0

/**
Whether the plugin implements the full state API.
When this macro is enabled, the plugin must implement a new getState(const char* key) function, which the host calls when saving its session/project.
This is useful for plugins that have custom internal values not exposed to the host as key-value state pairs or parameters.
Most simple effects and synths will not need this.
@note this macro is automatically enabled if a plugin has programs and state, as the key-value state pairs need to be updated when the current program changes.
@see Plugin::getState(const char*)
*/
// #define DISTRHO_PLUGIN_WANT_FULL_STATE 0

/**
Whether the plugin wants time position information from the host.
@see Plugin::getTimePosition()
*/
// #define DISTRHO_PLUGIN_WANT_TIMEPOS 0

/**
Whether the UI uses Cairo for drawing instead of the default OpenGL mode.
When enabled your UI instance will subclass CairoTopLevelWidget instead of TopLevelWidget.
*/
// #define DISTRHO_UI_USE_CAIRO 0

/**
Whether the UI uses a custom toolkit implementation based on OpenGL.
When enabled, the macros DISTRHO_UI_CUSTOM_INCLUDE_PATH and DISTRHO_UI_CUSTOM_WIDGET_TYPE are required.
*/
// #define DISTRHO_UI_USE_CUSTOM 0

/**
The include path to the header file used by the custom toolkit implementation.
This path must be relative to dpf/distrho/DistrhoUI.hpp
*/
// #define DISTRHO_UI_CUSTOM_INCLUDE_PATH

/**
The top-level-widget typedef to use for the custom toolkit.
This widget class MUST be a subclass of DGL TopLevelWindow class.
It is recommended that you keep this widget class inside the DGL namespace,
and define widget type as e.g. DGL_NAMESPACE::MyCustomTopLevelWidget.
*/
// #define DISTRHO_UI_CUSTOM_WIDGET_TYPE

/**
Whether the %UI uses NanoVG for drawing instead of the default raw OpenGL mode.@n
When enabled your %UI instance will subclass NanoTopLevelWidget instead of TopLevelWidget.
*/
// #define DISTRHO_UI_USE_NANOVG 0

/**
Default UI width to use when creating initial and temporary windows.
Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts.
(which would normally be done for knowing the UI size before host creates a window for it)

Value must match 1x scale factor.

When this macro is defined, the companion DISTRHO_UI_DEFAULT_HEIGHT macro must be defined as well.
*/
// #define DISTRHO_UI_DEFAULT_WIDTH 300

/**
Default UI height to use when creating initial and temporary windows.
Setting this macro allows to skip a temporary UI from being created in certain VST2 and VST3 hosts.
(which would normally be done for knowing the UI size before host creates a window for it)

Value must match 1x scale factor.

When this macro is defined, the companion DISTRHO_UI_DEFAULT_WIDTH macro must be defined as well.
*/
// #define DISTRHO_UI_DEFAULT_HEIGHT 300

/**
Whether the UI is resizable to any size by the user and OS.
By default this is false, with resizing only allowed when coded from the the plugin UI side.
Enabling this options makes it possible for the user to resize the plugin UI at anytime.
@see UI::setGeometryConstraints(uint, uint, bool, bool)
*/
// #define DISTRHO_UI_USER_RESIZABLE 0

/**
Whether to UI is going to use file browser dialogs.
By default this is false, with the file browser APIs not available for use.
*/
// #define DISTRHO_UI_FILE_BROWSER 0

/**
Whether to UI is going to use web browser views.
By default this is false, with the web browser APIs not available for use.
*/
// #define DISTRHO_UI_WEB_VIEW 0

/**
The UI URI when exporting in LV2 format.
By default this is set to @ref DISTRHO_PLUGIN_URI with "#UI" as suffix.
*/
// #define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"

/**
The AudioUnit type for a plugin.
This is a 4-character symbol, automatically set by DPF based on other plugin macros.
See https://developer.apple.com/documentation/audiotoolbox/1584142-audio_unit_types for more information.
*/
// #define DISTRHO_PLUGIN_AU_TYPE aufx

/**
A 4-character symbol that identifies a brand or manufacturer, with at least one non-lower case character.
Plugins from the same brand should use the same symbol.
@note This macro is required when building AU plugins, and used for VST3 if present
@note Setting this macro will change the uid of a VST3 plugin.
If you already released a DPF-based VST3 plugin make sure to also enable DPF_VST3_DONT_USE_BRAND_ID
*/
#define DISTRHO_PLUGIN_BRAND_ID Dstr

/**
A 4-character symbol which identifies a plugin.
It must be unique within at least a set of plugins from the brand.
@note This macro is required when building AU plugins
*/
// #define DISTRHO_PLUGIN_UNIQUE_ID test

/**
Custom LV2 category for the plugin.
This is a single string, and can be one of the following values:

- lv2:AllpassPlugin
- lv2:AmplifierPlugin
- lv2:AnalyserPlugin
- lv2:BandpassPlugin
- lv2:ChorusPlugin
- lv2:CombPlugin
- lv2:CompressorPlugin
- lv2:ConstantPlugin
- lv2:ConverterPlugin
- lv2:DelayPlugin
- lv2:DistortionPlugin
- lv2:DynamicsPlugin
- lv2:EQPlugin
- lv2:EnvelopePlugin
- lv2:ExpanderPlugin
- lv2:FilterPlugin
- lv2:FlangerPlugin
- lv2:FunctionPlugin
- lv2:GatePlugin
- lv2:GeneratorPlugin
- lv2:HighpassPlugin
- lv2:InstrumentPlugin
- lv2:LimiterPlugin
- lv2:LowpassPlugin
- lv2:MIDIPlugin
- lv2:MixerPlugin
- lv2:ModulatorPlugin
- lv2:MultiEQPlugin
- lv2:OscillatorPlugin
- lv2:ParaEQPlugin
- lv2:PhaserPlugin
- lv2:PitchPlugin
- lv2:ReverbPlugin
- lv2:SimulatorPlugin
- lv2:SpatialPlugin
- lv2:SpectralPlugin
- lv2:UtilityPlugin
- lv2:WaveshaperPlugin

See http://lv2plug.in/ns/lv2core for more information.
*/
// #define DISTRHO_PLUGIN_LV2_CATEGORY "lv2:Plugin"

/**
Custom VST3 categories for the plugin.
This is a single concatenated string of categories, separated by a @c |.

Each effect category can be one of the following values:

- Fx
- Fx|Ambisonics
- Fx|Analyzer
- Fx|Delay
- Fx|Distortion
- Fx|Dynamics
- Fx|EQ
- Fx|Filter
- Fx|Instrument
- Fx|Instrument|External
- Fx|Spatial
- Fx|Generator
- Fx|Mastering
- Fx|Modulation
- Fx|Network
- Fx|Pitch Shift
- Fx|Restoration
- Fx|Reverb
- Fx|Surround
- Fx|Tools

Each instrument category can be one of the following values:

- Instrument
- Instrument|Drum
- Instrument|External
- Instrument|Piano
- Instrument|Sampler
- Instrument|Synth
- Instrument|Synth|Sampler

And extra categories possible for any plugin type:

- Mono
- Stereo
*/
// #define DISTRHO_PLUGIN_VST3_CATEGORIES "Fx|Stereo"

/**
Custom CLAP features for the plugin.
This is a list of features defined as a string array body, without the terminating @c , or nullptr.

A top-level category can be set as feature and be one of the following values:

- instrument
- audio-effect
- note-effect
- analyzer

The following sub-categories can also be set:

- synthesizer
- sampler
- drum
- drum-machine

- filter
- phaser
- equalizer
- de-esser
- phase-vocoder
- granular
- frequency-shifter
- pitch-shifter

- distortion
- transient-shaper
- compressor
- limiter

- flanger
- chorus
- delay
- reverb

- tremolo
- glitch

- utility
- pitch-correction
- restoration

- multi-effects

- mixing
- mastering

And finally the following audio capabilities can be set:

- mono
- stereo
- surround
- ambisonic
*/
// #define DISTRHO_PLUGIN_CLAP_FEATURES "audio-effect", "stereo"

/**
The plugin id when exporting in CLAP format, in reverse URI form.
@note This macro is required when building CLAP plugins
*/
// #define DISTRHO_PLUGIN_CLAP_ID "studio.kx.distrho.effect"

/** @} */

+ 6
- 2
dpf/distrho/DistrhoPluginMain.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -16,7 +16,9 @@

#include "src/DistrhoPlugin.cpp"

#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
#if defined(DISTRHO_PLUGIN_TARGET_AU)
# include "src/DistrhoPluginAU.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA)
# include "src/DistrhoPluginCarla.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP)
# include "src/DistrhoPluginCLAP.cpp"
@@ -31,6 +33,8 @@
# 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(); }


+ 6
- 4
dpf/distrho/DistrhoPluginUtils.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -53,13 +53,15 @@ const char* getPluginFormatName() noexcept;
Returns a path inside the bundle where the plugin is meant to store its resources in.@n
This path varies between systems and plugin formats, like so:

- AU: <bundle>/Contents/Resources
- CLAP+VST2 macOS: <bundle>/Contents/Resources
- CLAP+VST2 non-macOS: <bundle>/resources (see note)
- LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DPF just uses this one)
- VST2 macOS: <bundle>/Contents/Resources
- VST2 non-macOS: <bundle>/resources (see note)
- VST3: <bundle>/Contents/Resources

The other non-mentioned formats do not support bundles.@n

@note For VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory
@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)
*/
const char* getResourcePath(const char* bundlePath) noexcept;


+ 8
- 55
dpf/distrho/DistrhoUI.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -31,11 +31,7 @@
# include "Vulkan.hpp"
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include "../dgl/Base.hpp"
# include "extra/ExternalWindow.hpp"
typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget;
#elif DISTRHO_UI_USE_CUSTOM
#if DISTRHO_UI_USE_CUSTOM
# include DISTRHO_UI_CUSTOM_INCLUDE_PATH
typedef DISTRHO_UI_CUSTOM_WIDGET_TYPE UIWidget;
#elif DISTRHO_UI_USE_CAIRO
@@ -52,9 +48,8 @@ typedef DGL_NAMESPACE::TopLevelWidget UIWidget;
#if DISTRHO_UI_FILE_BROWSER
# include "extra/FileBrowserDialog.hpp"
#endif
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include <vector>
#endif

#include <vector>

START_NAMESPACE_DISTRHO

@@ -197,8 +192,7 @@ public:

This function does not block the event loop.

@note This is exactly the same API as provided by the Window class,
but redeclared here so that non-embed/DGL based UIs can still use file browser related functions.
@note This is exactly the same API as provided by the Window class, but redeclared here for convenience.
*/
bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
#endif
@@ -214,34 +208,6 @@ public:
void* getPluginInstancePointer() const noexcept;
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/* --------------------------------------------------------------------------------------------------------
* External UI helpers */

/**
Get the bundle path that will be used for the next UI.
@note: This function is only valid during createUI(),
it will return null when called from anywhere else.
*/
static const char* getNextBundlePath() noexcept;

/**
Get the scale factor that will be used for the next UI.
@note: This function is only valid during createUI(),
it will return 1.0 when called from anywhere else.
*/
static double getNextScaleFactor() noexcept;

# if DISTRHO_PLUGIN_HAS_EMBED_UI
/**
Get the Window Id that will be used for the next created window.
@note: This function is only valid during createUI(),
it will return 0 when called from anywhere else.
*/
static uintptr_t getNextWindowId() noexcept;
# endif
#endif

protected:
/* --------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks */
@@ -250,14 +216,14 @@ protected:
A parameter has changed on the plugin side.@n
This is called by the host to inform the UI about parameter changes.
*/
virtual void parameterChanged(uint32_t index, float value) = 0;
virtual void parameterChanged(uint32_t index, float value);

#if DISTRHO_PLUGIN_WANT_PROGRAMS
/**
A program has been loaded on the plugin side.@n
This is called by the host to inform the UI about program changes.
*/
virtual void programLoaded(uint32_t index) = 0;
virtual void programLoaded(uint32_t index);
#endif

#if DISTRHO_PLUGIN_WANT_STATE
@@ -265,7 +231,7 @@ protected:
A state has changed on the plugin side.@n
This is called by the host to inform the UI about state changes.
*/
virtual void stateChanged(const char* key, const char* value) = 0;
virtual void stateChanged(const char* key, const char* value);
#endif

/* --------------------------------------------------------------------------------------------------------
@@ -297,7 +263,6 @@ protected:
*/
virtual void uiScaleFactorChanged(double scaleFactor);

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/**
Get the types available for the data in a clipboard.
Must only be called within the context of uiClipboardDataOffer.
@@ -334,7 +299,6 @@ protected:
The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code.
*/
virtual void uiReshape(uint width, uint height);
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI

#if DISTRHO_UI_FILE_BROWSER
/**
@@ -352,21 +316,12 @@ protected:
/* --------------------------------------------------------------------------------------------------------
* UI Resize Handling, internal */

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/**
External Window resize function, called when the window is resized.
This is overriden here so the host knows when the UI is resized by you.
@see ExternalWindow::sizeChanged(uint,uint)
*/
void sizeChanged(uint width, uint height) override;
#else
/**
Widget resize function, called when the widget is resized.
This is overriden here so the host knows when the UI is resized by you.
@see Widget::onResize(const ResizeEvent&)
*/
void onResize(const ResizeEvent& ev) override;
#endif

// -------------------------------------------------------------------------------------------------------

@@ -375,10 +330,8 @@ private:
PrivateData* const uiData;
friend class PluginWindow;
friend class UIExporter;
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/** @internal */
void requestSizeChange(uint width, uint height) override;
#endif

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI)
};


+ 20
- 2
dpf/distrho/DistrhoUIMain.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -23,7 +23,10 @@

#if DISTRHO_PLUGIN_HAS_UI

#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
#if defined(DISTRHO_PLUGIN_TARGET_AU)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
# import "src/DistrhoUIAU.mm"
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
#elif defined(DISTRHO_PLUGIN_TARGET_CLAP)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
@@ -40,6 +43,8 @@
#elif defined(DISTRHO_PLUGIN_TARGET_VST3)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
# include "src/DistrhoUIVST3.cpp"
#elif defined(DISTRHO_PLUGIN_TARGET_EXPORT)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
#elif defined(DISTRHO_PLUGIN_TARGET_SHARED) || defined(DISTRHO_PLUGIN_TARGET_STATIC)
# define DISTRHO_PLUGIN_AND_UI_IN_SINGLE_OBJECT 1
#else
@@ -53,6 +58,19 @@
# define DISTRHO_IS_STANDALONE 0
# endif
# include "src/DistrhoUtils.cpp"
#else
# ifdef DISTRHO_PLUGIN_TARGET_JACK
# define DISTRHO_IS_STANDALONE 1
# else
# define DISTRHO_IS_STANDALONE 0
# endif
#endif

#if defined(DPF_USING_LD_LINUX_WEBVIEW) && !DISTRHO_IS_STANDALONE
int main(int argc, char* argv[])
{
return DISTRHO_NAMESPACE::dpf_webview_start(argc, argv);
}
#endif

#endif

+ 19
- 8
dpf/distrho/DistrhoUI_macOS.mm View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -20,9 +20,11 @@
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"

#if DISTRHO_UI_FILE_BROWSER || DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# import <Cocoa/Cocoa.h>
#endif
#define Point CocoaPoint
#define Size CocoaSize
#import <Cocoa/Cocoa.h>
#undef Point
#undef Size

#if DISTRHO_UI_FILE_BROWSER
# define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED
@@ -34,9 +36,19 @@ END_NAMESPACE_DISTRHO
# include "extra/FileBrowserDialogImpl.cpp"
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include <algorithm>
# include <cmath>
#if DISTRHO_UI_WEB_VIEW
# define DISTRHO_WEB_VIEW_HPP_INCLUDED
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE
# define WEB_VIEW_DISTRHO_NAMESPACE
START_NAMESPACE_DISTRHO
# include "extra/WebViewImpl.hpp"
END_NAMESPACE_DISTRHO
# include "extra/WebViewImpl.cpp"
#endif

#include <algorithm>
#include <cmath>

START_NAMESPACE_DISTRHO
double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
{
@@ -51,4 +63,3 @@ double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
return [NSScreen mainScreen].backingScaleFactor;
}
END_NAMESPACE_DISTRHO
#endif

+ 27
- 0
dpf/distrho/DistrhoUI_win32.cpp View File

@@ -0,0 +1,27 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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

#include "DistrhoDetails.hpp"
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"

#if DISTRHO_UI_WEB_VIEW
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION
# include "extra/WebView.hpp"
# include "extra/WebViewWin32.hpp"
#endif

+ 108
- 22
dpf/distrho/DistrhoUtils.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -38,7 +38,7 @@
typedef SSIZE_T ssize_t;
#endif

#if ! defined(CARLA_MATH_UTILS_HPP_INCLUDED) && ! defined(DISTRHO_PROPER_CPP11_SUPPORT)
#if ! defined(CARLA_MATH_UTILS_HPP_INCLUDED) && ! defined(DISTRHO_PROPER_CPP11_SUPPORT) && ! defined(DISTRHO_OS_MAC)
namespace std {
inline float fmin(float __x, float __y)
{ return __builtin_fminf(__x, __y); }
@@ -55,9 +55,6 @@ inline float round(float __x)
# define M_PI 3.14159265358979323846
#endif

#define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO
#define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO)

/* --------------------------------------------------------------------------------------------------------------------
* misc functions */

@@ -77,6 +74,15 @@ int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_
return (a << 24) | (b << 16) | (c << 8) | (d << 0);
}

/**
Return a 32-bit number from 4 ASCII characters.
*/
static inline constexpr
uint32_t d_cconst(const char str[4])
{
return (str[0] << 24) | (str[1] << 16) | (str[2] << 8) | str[3];
}

/**
Return an hexadecimal representation of a MAJ.MIN.MICRO version number.
*/
@@ -103,6 +109,27 @@ void d_pass() noexcept {}
@{
*/

/*
* Internal noexcept-safe fopen function.
*/
static inline
FILE* __d_fopen(const char* const filename, FILE* const fallback) noexcept
{
if (std::getenv("DPF_CAPTURE_CONSOLE_OUTPUT") == nullptr)
return fallback;

FILE* ret = nullptr;

try {
ret = std::fopen(filename, "a+");
} catch (...) {}

if (ret == nullptr)
ret = fallback;

return ret;
}

/**
Print a string to stdout with newline (gray color).
Does nothing if DEBUG is not defined.
@@ -113,12 +140,30 @@ void d_pass() noexcept {}
static inline
void d_debug(const char* const fmt, ...) noexcept
{
static FILE* const output = __d_fopen("/tmp/dpf.debug.log", stdout);

try {
va_list args;
va_start(args, fmt);
std::fprintf(stdout, "\x1b[30;1m");
std::vfprintf(stdout, fmt, args);
std::fprintf(stdout, "\x1b[0m\n");

if (output == stdout)
{
#ifdef DISTRHO_OS_MAC
std::fprintf(output, "\x1b[37;1m[dpf] ");
#else
std::fprintf(output, "\x1b[30;1m[dpf] ");
#endif
std::vfprintf(output, fmt, args);
std::fprintf(output, "\x1b[0m\n");
}
else
{
std::fprintf(output, "[dpf] ");
std::vfprintf(output, fmt, args);
std::fprintf(output, "\n");
}

std::fflush(output);
va_end(args);
} catch (...) {}
}
@@ -130,11 +175,18 @@ void d_debug(const char* const fmt, ...) noexcept
static inline
void d_stdout(const char* const fmt, ...) noexcept
{
static FILE* const output = __d_fopen("/tmp/dpf.stdout.log", stdout);

try {
va_list args;
va_start(args, fmt);
std::vfprintf(stdout, fmt, args);
std::fprintf(stdout, "\n");
std::fprintf(output, "[dpf] ");
std::vfprintf(output, fmt, args);
std::fprintf(output, "\n");
#ifndef DEBUG
if (output != stdout)
#endif
std::fflush(output);
va_end(args);
} catch (...) {}
}
@@ -145,11 +197,18 @@ void d_stdout(const char* const fmt, ...) noexcept
static inline
void d_stderr(const char* const fmt, ...) noexcept
{
static FILE* const output = __d_fopen("/tmp/dpf.stderr.log", stderr);

try {
va_list args;
va_start(args, fmt);
std::vfprintf(stderr, fmt, args);
std::fprintf(stderr, "\n");
std::fprintf(output, "[dpf] ");
std::vfprintf(output, fmt, args);
std::fprintf(output, "\n");
#ifndef DEBUG
if (output != stderr)
#endif
std::fflush(output);
va_end(args);
} catch (...) {}
}
@@ -160,12 +219,26 @@ void d_stderr(const char* const fmt, ...) noexcept
static inline
void d_stderr2(const char* const fmt, ...) noexcept
{
static FILE* const output = __d_fopen("/tmp/dpf.stderr2.log", stderr);

try {
va_list args;
va_start(args, fmt);
std::fprintf(stderr, "\x1b[31m");
std::vfprintf(stderr, fmt, args);
std::fprintf(stderr, "\x1b[0m\n");

if (output == stdout)
{
std::fprintf(output, "\x1b[31m[dpf] ");
std::vfprintf(output, fmt, args);
std::fprintf(output, "\x1b[0m\n");
}
else
{
std::fprintf(output, "[dpf] ");
std::vfprintf(output, fmt, args);
std::fprintf(output, "\n");
}

std::fflush(output);
va_end(args);
} catch (...) {}
}
@@ -310,7 +383,7 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept
}

/**
Round a floating point number to integer.
Round a floating point number to an integer.
Fast operation for values known to be 0 or positive.
*/
template<typename T>
@@ -321,7 +394,18 @@ int32_t d_roundToIntPositive(const T& value)
}

/**
Round a floating point number to integer.
Round a floating point number to an unsigned integer.
Fast operation for values known to be 0 or positive.
*/
template<typename T>
static inline constexpr
uint32_t d_roundToUnsignedInt(const T& value)
{
return static_cast<uint32_t>(value + static_cast<T>(0.5));
}

/**
Round a floating point number to an integer.
Fast operation for values known to be 0 or negative.
*/
template<typename T>
@@ -345,13 +429,15 @@ int32_t d_roundToInt(const T& value)
/** @} */

/* --------------------------------------------------------------------------------------------------------------------
* math functions */
* other stuff */

#ifndef DONT_SET_USING_DISTRHO_NAMESPACE
// If your code uses a lot of DISTRHO classes, then this will obviously save you
// a lot of typing, but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE.
namespace DISTRHO_NAMESPACE {}
using namespace DISTRHO_NAMESPACE;
/**
If your code uses a lot of DISTRHO classes, then this will obviously save you a lot of typing,
but can be disabled by setting DONT_SET_USING_DISTRHO_NAMESPACE.
*/
namespace DISTRHO_NAMESPACE {}
using namespace DISTRHO_NAMESPACE;
#endif

#endif // DISTRHO_UTILS_HPP_INCLUDED

+ 276
- 0
dpf/distrho/extra/ChildProcess.hpp View File

@@ -0,0 +1,276 @@
// SPDX-FileCopyrightText: 2023-2024 MOD Audio UG
// SPDX-License-Identifier: AGPL-3.0-or-later

#pragma once

#include "Sleep.hpp"
#include "Time.hpp"

#ifdef DISTRHO_OS_WINDOWS
# include <string>
# include <winsock2.h>
# include <windows.h>
#else
# include <cerrno>
# include <ctime>
# include <signal.h>
# include <sys/wait.h>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------

class ChildProcess
{
#ifdef _WIN32
PROCESS_INFORMATION pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
#else
pid_t pid = -1;
#endif

public:
ChildProcess()
{
}

~ChildProcess()
{
stop();
}

#ifdef _WIN32
bool start(const char* const args[], const WCHAR* const envp)
#else
bool start(const char* const args[], char* const* const envp = nullptr)
#endif
{
#ifdef _WIN32
std::string cmd;

for (uint i = 0; args[i] != nullptr; ++i)
{
if (i != 0)
cmd += " ";

if (args[i][0] != '"' && std::strchr(args[i], ' ') != nullptr)
{
cmd += "\"";
cmd += args[i];
cmd += "\"";
}
else
{
cmd += args[i];
}
}

wchar_t wcmd[PATH_MAX];
if (MultiByteToWideChar(CP_UTF8, 0, cmd.data(), -1, wcmd, PATH_MAX) <= 0)
return false;

STARTUPINFOW si = {};
si.cb = sizeof(si);

d_stdout("will start process with args '%s'", cmd.data());

return CreateProcessW(nullptr, // lpApplicationName
wcmd, // lpCommandLine
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
TRUE, // bInheritHandles
CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
const_cast<LPWSTR>(envp), // lpEnvironment
nullptr, // lpCurrentDirectory
&si, // lpStartupInfo
&pinfo) != FALSE;
#else
const pid_t ret = pid = vfork();

switch (ret)
{
// child process
case 0:
if (envp != nullptr)
execve(args[0], const_cast<char* const*>(args), envp);
else
execvp(args[0], const_cast<char* const*>(args));

d_stderr2("exec failed: %d:%s", errno, std::strerror(errno));
_exit(1);
break;

// error
case -1:
d_stderr2("vfork() failed: %d:%s", errno, std::strerror(errno));
break;
}

return ret > 0;
#endif
}

void stop(const uint32_t timeoutInMilliseconds = 2000)
{
const uint32_t timeout = d_gettime_ms() + timeoutInMilliseconds;
bool sendTerminate = true;

#ifdef _WIN32
if (pinfo.hProcess == INVALID_HANDLE_VALUE)
return;

const PROCESS_INFORMATION opinfo = pinfo;
pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };

for (DWORD exitCode;;)
{
if (GetExitCodeProcess(opinfo.hProcess, &exitCode) == FALSE ||
exitCode != STILL_ACTIVE ||
WaitForSingleObject(opinfo.hProcess, 0) != WAIT_TIMEOUT)
{
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
return;
}

if (sendTerminate)
{
sendTerminate = false;
TerminateProcess(opinfo.hProcess, ERROR_BROKEN_PIPE);
}

if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}
d_stderr("ChildProcess::stop() - timed out");
TerminateProcess(opinfo.hProcess, 9);
d_msleep(5);
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
break;
}
#else
if (pid <= 0)
return;

const pid_t opid = pid;
pid = -1;

for (pid_t ret;;)
{
try {
ret = ::waitpid(opid, nullptr, WNOHANG);
} DISTRHO_SAFE_EXCEPTION_BREAK("waitpid");

switch (ret)
{
case -1:
if (errno == ECHILD)
{
// success, child doesn't exist
return;
}
else
{
d_stderr("ChildProcess::stop() - waitpid failed: %d:%s", errno, std::strerror(errno));
return;
}
break;

case 0:
if (sendTerminate)
{
sendTerminate = false;
kill(opid, SIGTERM);
}
if (d_gettime_ms() < timeout)
{
d_msleep(5);
continue;
}

d_stderr("ChildProcess::stop() - timed out");
kill(opid, SIGKILL);
waitpid(opid, nullptr, WNOHANG);
break;

default:
if (ret == opid)
{
// success
return;
}
else
{
d_stderr("ChildProcess::stop() - got wrong pid %i (requested was %i)", int(ret), int(opid));
return;
}
}

break;
}
#endif
}

bool isRunning()
{
#ifdef _WIN32
if (pinfo.hProcess == INVALID_HANDLE_VALUE)
return false;

DWORD exitCode;
if (GetExitCodeProcess(pinfo.hProcess, &exitCode) == FALSE ||
exitCode != STILL_ACTIVE ||
WaitForSingleObject(pinfo.hProcess, 0) != WAIT_TIMEOUT)
{
const PROCESS_INFORMATION opinfo = pinfo;
pinfo = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0 };
CloseHandle(opinfo.hThread);
CloseHandle(opinfo.hProcess);
return false;
}

return true;
#else
if (pid <= 0)
return false;

const pid_t ret = ::waitpid(pid, nullptr, WNOHANG);

if (ret == pid || (ret == -1 && errno == ECHILD))
{
pid = 0;
return false;
}

return true;
#endif
}

#ifndef _WIN32
void signal(const int sig)
{
if (pid > 0)
kill(pid, sig);
}
#endif

void terminate()
{
#ifdef _WIN32
if (pinfo.hProcess != INVALID_HANDLE_VALUE)
TerminateProcess(pinfo.hProcess, 15);
#else
if (pid > 0)
kill(pid, SIGTERM);
#endif
}

DISTRHO_DECLARE_NON_COPYABLE(ChildProcess)
};

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

+ 42
- 3
dpf/distrho/extra/FileBrowserDialogImpl.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -27,10 +27,12 @@
#ifdef DISTRHO_OS_MAC
# import <Cocoa/Cocoa.h>
#endif

#ifdef DISTRHO_OS_WASM
# include <emscripten/emscripten.h>
# include <sys/stat.h>
#endif

#ifdef DISTRHO_OS_WINDOWS
# include <direct.h>
# include <process.h>
@@ -41,13 +43,30 @@
#else
# include <unistd.h>
#endif

#ifdef HAVE_DBUS
# include <dbus/dbus.h>
#endif

#ifdef HAVE_X11
# define DBLCLKTME 400
# include "sofd/libsofd.h"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-qual"
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wfloat-conversion"
# pragma GCC diagnostic ignored "-Wshadow"
# pragma GCC diagnostic ignored "-Wsign-conversion"
# pragma GCC diagnostic ignored "-Wstrict-overflow"
# endif
# include "sofd/libsofd.c"
# if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic pop
# endif
# undef HAVE_MNTENT
# undef MAX
# undef MIN
#endif

#ifdef FILE_BROWSER_DIALOG_DGL_NAMESPACE
@@ -329,6 +348,16 @@ struct FileBrowserData {
#else // DISTRHO_OS_WINDOWS
FileBrowserData(const bool save)
: selectedFile(nullptr)
#ifdef DISTRHO_OS_MAC
, nsBasePanel(nullptr)
, nsOpenPanel(nullptr)
#endif
#ifdef HAVE_DBUS
, dbuscon(nullptr)
#endif
#ifdef HAVE_X11
, x11display(nullptr)
#endif
{
#ifdef DISTRHO_OS_MAC
if (save)
@@ -393,6 +422,8 @@ struct FileBrowserData {
std::free(const_cast<char*>(selectedFile));
selectedFile = nullptr;
}

DISTRHO_DECLARE_NON_COPYABLE(FileBrowserData)
};

// --------------------------------------------------------------------------------------------------------------------
@@ -463,7 +494,11 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed,
[nsOpenPanel setCanChooseFiles:YES];
}

[nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]];
NSString* const startDirString = [[NSString alloc]
initWithBytes:startDir
length:strlen(startDir)
encoding:NSUTF8StringEncoding];
[nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:startDirString]];

// TODO file filter using allowedContentTypes: [UTType]

@@ -496,6 +531,9 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed,
}
}];
});

[startDirString release];
[titleString release];
# endif
#endif

@@ -590,7 +628,8 @@ FileBrowserHandle fileBrowserCreate(const bool isEmbed,
dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant);
dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray);
dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE,
&current_folder_val, startDir.length()+1);
&current_folder_val,
static_cast<int>(startDir.length() + 1));
dbus_message_iter_close_container(&variant, &variantArray);
dbus_message_iter_close_container(&dict, &variant);
dbus_message_iter_close_container(&array, &dict);


+ 8
- 4
dpf/distrho/extra/FileBrowserDialogImpl.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -18,6 +18,10 @@
# error bad include
#endif

#if !defined(DGL_USE_FILE_BROWSER) && defined(DISTRHO_UI_FILE_BROWSER) && DISTRHO_UI_FILE_BROWSER == 0
# error To use File Browser in DPF plugins please set DISTRHO_UI_FILE_BROWSER to 1
#endif

// --------------------------------------------------------------------------------------------------------------------
// File Browser Dialog stuff

@@ -109,17 +113,17 @@ FileBrowserHandle fileBrowserCreate(bool isEmbed,
in which case this idle function must not be called anymore for this handle.
You can then call fileBrowserGetPath to know the selected file (or null if cancelled).
*/
bool fileBrowserIdle(const FileBrowserHandle handle);
bool fileBrowserIdle(FileBrowserHandle handle);

/**
Close and free the file browser dialog, handle must not be used afterwards.
*/
void fileBrowserClose(const FileBrowserHandle handle);
void fileBrowserClose(FileBrowserHandle handle);

/**
Get the path chosen by the user or null.@n
Should only be called after fileBrowserIdle returns true.
*/
const char* fileBrowserGetPath(const FileBrowserHandle handle);
const char* fileBrowserGetPath(FileBrowserHandle handle);

// --------------------------------------------------------------------------------------------------------------------

+ 89
- 2
dpf/distrho/extra/RingBuffer.hpp View File

@@ -404,6 +404,36 @@ public:
return false;
}

// -------------------------------------------------------------------
// peek operations (returns a value without advancing read position)

/*
* Peek for an unsigned 32-bit integer.
* Returns 0 if reading fails.
*/
uint32_t peekUInt() const noexcept
{
uint32_t ui = 0;
return tryPeek(&ui, sizeof(int32_t)) ? ui : 0;
}

/*!
* Peek for a custom data type specified by the template typename used,
* with size being automatically deduced by the compiler (through the use of sizeof).
*
* Returns true if peeking succeeds.
* In case of failure, @a type value is automatically cleared by its deduced size.
*/
template <typename T>
bool peekCustomType(T& type) const noexcept
{
if (tryPeek(&type, sizeof(T)))
return true;

std::memset(&type, 0, sizeof(T));
return false;
}

// -------------------------------------------------------------------
// write operations

@@ -601,7 +631,7 @@ protected:
}
else
{
const uint32_t firstpart(buffer->size - tail);
const uint32_t firstpart = buffer->size - tail;
std::memcpy(bytebuf, buffer->buf + tail, firstpart);
std::memcpy(bytebuf + firstpart, buffer->buf, readto);
}
@@ -619,6 +649,63 @@ protected:
return true;
}

/** @internal try reading from the buffer, can fail. */
bool tryPeek(void* const buf, const uint32_t size) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(buffer != nullptr, false);
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif
DISTRHO_SAFE_ASSERT_RETURN(buffer->buf != nullptr, false);
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
DISTRHO_SAFE_ASSERT_RETURN(buf != nullptr, false);
DISTRHO_SAFE_ASSERT_RETURN(size > 0, false);
DISTRHO_SAFE_ASSERT_RETURN(size < buffer->size, false);

// empty
if (buffer->head == buffer->tail)
return false;

uint8_t* const bytebuf = static_cast<uint8_t*>(buf);

const uint32_t head = buffer->head;
const uint32_t tail = buffer->tail;
const uint32_t wrap = head > tail ? 0 : buffer->size;

if (size > wrap + head - tail)
return false;

uint32_t readto = tail + size;

if (readto > buffer->size)
{
readto -= buffer->size;

if (size == 1)
{
std::memcpy(bytebuf, buffer->buf + tail, 1);
}
else
{
const uint32_t firstpart = buffer->size - tail;
std::memcpy(bytebuf, buffer->buf + tail, firstpart);
std::memcpy(bytebuf + firstpart, buffer->buf, readto);
}
}
else
{
std::memcpy(bytebuf, buffer->buf + tail, size);

if (readto == buffer->size)
readto = 0;
}

return true;
}

/** @internal try writing to the buffer, can fail. */
bool tryWrite(const void* const buf, const uint32_t size) noexcept
{
@@ -656,7 +743,7 @@ protected:
}
else
{
const uint32_t firstpart(buffer->size - wrtn);
const uint32_t firstpart = buffer->size - wrtn;
std::memcpy(buffer->buf + wrtn, bytebuf, firstpart);
std::memcpy(buffer->buf, bytebuf + firstpart, writeto);
}


+ 7
- 3
dpf/distrho/extra/Sleep.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -29,7 +29,9 @@
# include <unistd.h>
#endif

// -----------------------------------------------------------------------
START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------
// d_*sleep

/*
@@ -66,6 +68,8 @@ void d_msleep(const uint msecs) noexcept
} DISTRHO_SAFE_EXCEPTION("d_msleep");
}

// -----------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_SLEEP_HPP_INCLUDED

+ 4
- 18
dpf/distrho/extra/String.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -22,10 +22,6 @@

#include <algorithm>

#if __cplusplus >= 201703L
# include <string_view>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
@@ -91,16 +87,6 @@ public:
_dup(strBuf);
}

#if __cplusplus >= 201703L
/*
* constexpr compatible variant.
*/
explicit constexpr String(const std::string_view& strView) noexcept
: fBuffer(const_cast<char*>(strView.data())),
fBufferLen(strView.size()),
fBufferAlloc(false) {}
#endif

/*
* Integer.
*/
@@ -695,11 +681,11 @@ public:
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";

#ifndef _MSC_VER
#ifndef _MSC_VER
const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U);
#else
#else
constexpr std::size_t kTmpBufSize = 65536U;
#endif
#endif

const uchar* bytesToEncode((const uchar*)data);



+ 127
- 0
dpf/distrho/extra/Time.hpp View File

@@ -0,0 +1,127 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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_TIME_HPP_INCLUDED
#define DISTRHO_TIME_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#ifdef DISTRHO_OS_WINDOWS
# include <winsock2.h>
# include <windows.h>
# include <mmsystem.h>
#else
# include <ctime>
#endif

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------
// d_gettime_*

/*
* Get a monotonically-increasing time in milliseconds.
*/
static inline
uint32_t d_gettime_ms() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const time_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000;
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000000) - s;
#elif defined(DISTRHO_OS_WINDOWS)
return static_cast<uint32_t>(timeGetTime());
#else
static struct {
timespec ts;
int r;
uint32_t ms;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint32_t>(s.ts.tv_sec * 1000 +
s.ts.tv_nsec / 1000000) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000) - s.ms;
#endif
}

/*
* Get a monotonically-increasing time in microseconds.
*/
static inline
uint64_t d_gettime_us() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000;
return (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / 1000) - s;
#elif defined(DISTRHO_OS_WINDOWS)
static struct {
LARGE_INTEGER freq;
LARGE_INTEGER counter;
BOOL r1, r2;
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) };

LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (counter.QuadPart - s.counter.QuadPart) * 1000000 / s.freq.QuadPart;
#else
static struct {
timespec ts;
int r;
uint64_t us;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000 +
s.ts.tv_nsec / 1000) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) - s.us;
#endif
}

/*
* Get a monotonically-increasing time in nanoseconds.
*/
static inline
uint64_t d_gettime_ns() noexcept
{
#if defined(DISTRHO_OS_MAC)
static const uint64_t s = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
return clock_gettime_nsec_np(CLOCK_UPTIME_RAW) - s;
#elif defined(DISTRHO_OS_WINDOWS)
static struct {
LARGE_INTEGER freq;
LARGE_INTEGER counter;
BOOL r1, r2;
} s = { {}, {}, QueryPerformanceFrequency(&s.freq), QueryPerformanceCounter(&s.counter) };

LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (counter.QuadPart - s.counter.QuadPart) * 1000000000ULL / s.freq.QuadPart;
#else
static struct {
timespec ts;
int r;
uint64_t ns;
} s = { {}, clock_gettime(CLOCK_MONOTONIC, &s.ts), static_cast<uint64_t>(s.ts.tv_sec * 1000000000ULL +
s.ts.tv_nsec) };
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (ts.tv_sec * 1000000000ULL + ts.tv_nsec) - s.ns;
#endif
}

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_TIME_HPP_INCLUDED

+ 28
- 0
dpf/distrho/extra/WebView.hpp View File

@@ -0,0 +1,28 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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_WEB_VIEW_HPP_INCLUDED
#define DISTRHO_WEB_VIEW_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

START_NAMESPACE_DISTRHO

#include "WebViewImpl.hpp"

END_NAMESPACE_DISTRHO

#endif // DISTRHO_WEB_VIEW_HPP_INCLUDED

+ 1493
- 0
dpf/distrho/extra/WebViewImpl.cpp
File diff suppressed because it is too large
View File


+ 126
- 0
dpf/distrho/extra/WebViewImpl.hpp View File

@@ -0,0 +1,126 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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.
*/

#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED)
# error bad include
#endif

#if !defined(DGL_UI_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

// --------------------------------------------------------------------------------------------------------------------
// Web View stuff

struct WebViewData;
typedef WebViewData* WebViewHandle;
typedef void (*WebViewMessageCallback)(void* arg, char* msg);

// --------------------------------------------------------------------------------------------------------------------

/**
Web view options, for customizing web view details.
*/
struct WebViewOptions {
/**
Position offset, for cases of mixing regular widgets with web views.
*/
struct PositionOffset {
/** Horizontal offset, with scale factor pre-applied */
int x;

/** Vertical offset, with scale factor pre-applied */
int y;

/** Constructor for default values */
PositionOffset() : x(0), y(0) {}
} offset;

/**
Set some JavaScript to evalute on every new page load.
*/
const char* initialJS;

/**
Message callback triggered from JavaScript code inside the WebView.
*/
WebViewMessageCallback callback;
void* callbackPtr;

/** Constructor for default values */
WebViewOptions()
: offset(),
initialJS(nullptr),
callback(nullptr),
callbackPtr(nullptr) {}

/** Constructor providing a callback */
WebViewOptions(const WebViewMessageCallback cb, void* const ptr)
: offset(),
initialJS(nullptr),
callback(cb),
callbackPtr(ptr) {}
};

// --------------------------------------------------------------------------------------------------------------------

/**
Create a new web view.

The web view will be added on top of an existing platform-specific view/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 must have scale factor pre-applied.

@p windowId: The native window id to attach this view to (X11 Window, HWND or NSView*)
@p scaleFactor: Scale factor in use
@p options: Extra options, optional
*/
WebViewHandle webViewCreate(const char* url,
uintptr_t windowId,
uint initialWidth,
uint initialHeight,
double scaleFactor,
const WebViewOptions& options = WebViewOptions());

/**
Destroy the web view, handle must not be used afterwards.
*/
void webViewDestroy(WebViewHandle webview);

/**
Idle the web view, to be called on regular intervals.
Can cause callbacks to trigger.
*/
void webViewIdle(WebViewHandle webview);

/**
Evaluate/run JavaScript on the web view.
*/
void webViewEvaluateJS(WebViewHandle webview, const char* js);

/**
Reload the web view current page.
*/
void webViewReload(WebViewHandle webview);

/**
Resize the web view.
*/
void webViewResize(WebViewHandle webview, uint width, uint height, double scaleFactor);

// --------------------------------------------------------------------------------------------------------------------

+ 101
- 0
dpf/distrho/extra/WebViewWin32.hpp View File

@@ -0,0 +1,101 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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.
*/

#if !defined(DISTRHO_WEB_VIEW_HPP_INCLUDED) && !defined(DGL_WEB_VIEW_HPP_INCLUDED)
# define DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION
# include "WebView.hpp"
#endif

// --------------------------------------------------------------------------------------------------------------------
// Web View stuff

START_NAMESPACE_DISTRHO

class WebView;

WebView* webview_choc_create(const 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);

END_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------

#ifdef DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION

# define WC_ERR_INVALID_CHARS 0
# include "choc/choc_WebView.h"

START_NAMESPACE_DISTRHO

WebView* webview_choc_create(const WebViewOptions& opts)
{
WebView::Options wopts;
wopts.acceptsFirstMouseClick = true;
wopts.enableDebugMode = true;

std::unique_ptr<WebView> webview = std::make_unique<WebView>(wopts);
DISTRHO_SAFE_ASSERT_RETURN(webview->loadedOK(), nullptr);

if (const WebViewMessageCallback callback = opts.callback)
{
webview->addInitScript("function postMessage(m){window.chrome.webview.postMessage(m);}");

void* const callbackPtr = opts.callbackPtr;
webview->bind([callback, callbackPtr](const std::string& value) {
char* const data = strdup(value.data());
callback(callbackPtr, data);
std::free(data);
});
}
else
{
webview->addInitScript("function postMessage(m){}");
}

if (opts.initialJS != nullptr)
webview->addInitScript(opts.initialJS);

return webview.release();
}

void webview_choc_destroy(WebView* const webview)
{
delete webview;
}

void* webview_choc_handle(WebView* const webview)
{
return webview->getViewHandle();
}

void webview_choc_eval(WebView* const webview, const char* const js)
{
webview->evaluateJavascript(js);
}

void webview_choc_navigate(WebView* const webview, const char* const url)
{
webview->navigate(url);
}

END_NAMESPACE_DISTRHO

#endif // DISTRHO_WEB_VIEW_INCLUDE_IMPLEMENTATION

// --------------------------------------------------------------------------------------------------------------------

+ 15
- 0
dpf/distrho/extra/choc/LICENSE.md View File

@@ -0,0 +1,15 @@
## CHOC: licensing

I'd like anyone to feel able to use this library code without worrying about the legal implications, so it's released under the permissive ISC license:

----

**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.**

https://en.wikipedia.org/wiki/ISC_license

----

Note that if you use the `choc::ui::WebView` class on Windows, it embeds some Microsoft redistributable code which has its own (permissive) license that you should be aware of. See inside the file `choc_WebView.h` for more details.

+ 22
- 0
dpf/distrho/extra/choc/README.md View File

@@ -0,0 +1,22 @@
Taken from https://github.com/Tracktion/choc

```
commit 2512542b2d65f3e92df7f2f1f7eeb712fa41a0de (HEAD -> main, origin/main, origin/HEAD)
Author: Cesare Ferrari <cesare.ferrari@gmail.com>
Date: Sun Apr 28 12:53:17 2024 +0100

Disable additional gcc warnin
```

With the big [choc.patch](./choc.patch) patch applied to top for:

- remove everything not related to windows
- remove everything unused by DPF
- convert webview JS callbacks to pass raw strings instead of json
- remove even more stuff (json no longer needed)
- convert choc asserts into distrho ones
- put everything inside distrho namespace

And then backported:

- https://github.com/Tracktion/choc/commit/792e4bd9bedf38b9a28f12be0535c90649d5616b

+ 2803
- 0
dpf/distrho/extra/choc/choc.patch
File diff suppressed because it is too large
View File


+ 154
- 0
dpf/distrho/extra/choc/choc_DesktopWindow.h View File

@@ -0,0 +1,154 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 CHOC_DESKTOPWINDOW_HEADER_INCLUDED
#define CHOC_DESKTOPWINDOW_HEADER_INCLUDED

#include "choc_Platform.h"

//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#define NOMINMAX
#define Rectangle Rectangle_renamed_to_avoid_name_collisions
#include <windows.h>
#undef Rectangle

START_NAMESPACE_DISTRHO

struct HWNDHolder
{
HWNDHolder() = default;
HWNDHolder (HWND h) : hwnd (h) {}
HWNDHolder (const HWNDHolder&) = delete;
HWNDHolder& operator= (const HWNDHolder&) = delete;
HWNDHolder (HWNDHolder&& other) : hwnd (other.hwnd) { other.hwnd = {}; }
HWNDHolder& operator= (HWNDHolder&& other) { reset(); hwnd = other.hwnd; other.hwnd = {}; return *this; }
~HWNDHolder() { reset(); }

operator HWND() const { return hwnd; }
operator void*() const { return (void*) hwnd; }

void reset() { if (IsWindow (hwnd)) DestroyWindow (hwnd); hwnd = {}; }

HWND hwnd = {};
};

struct WindowClass
{
WindowClass (std::wstring name, WNDPROC wndProc)
{
name += std::to_wstring (static_cast<uint32_t> (GetTickCount()));

moduleHandle = GetModuleHandle (nullptr);
auto icon = (HICON) LoadImage (moduleHandle, IDI_APPLICATION, IMAGE_ICON,
GetSystemMetrics (SM_CXSMICON),
GetSystemMetrics (SM_CYSMICON),
LR_DEFAULTCOLOR);

WNDCLASSEXW wc;
ZeroMemory (&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_OWNDC;
wc.hInstance = moduleHandle;
wc.lpszClassName = name.c_str();
wc.hIcon = icon;
wc.hIconSm = icon;
wc.lpfnWndProc = wndProc;

classAtom = (LPCWSTR) (uintptr_t) RegisterClassExW (&wc);
DISTRHO_SAFE_ASSERT (classAtom != 0);
}

~WindowClass()
{
UnregisterClassW (classAtom, moduleHandle);
}

HWNDHolder createWindow (DWORD style, int w, int h, void* userData)
{
if (auto hwnd = CreateWindowW (classAtom, L"", style, CW_USEDEFAULT, CW_USEDEFAULT,
w, h, nullptr, nullptr, moduleHandle, nullptr))
{
SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) userData);
return hwnd;
}

return {};
}

auto getClassName() const { return classAtom; }

HINSTANCE moduleHandle = {};
LPCWSTR classAtom = {};
};

static std::string createUTF8FromUTF16 (const std::wstring& utf16)
{
if (! utf16.empty())
{
auto numWideChars = static_cast<int> (utf16.size());
auto resultSize = WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, nullptr, 0, nullptr, nullptr);

if (resultSize > 0)
{
std::string result;
result.resize (static_cast<size_t> (resultSize));

if (WideCharToMultiByte (CP_UTF8, WC_ERR_INVALID_CHARS, utf16.data(), numWideChars, result.data(), resultSize, nullptr, nullptr) > 0)
return result;
}
}

return {};
}

static std::wstring createUTF16StringFromUTF8 (std::string_view utf8)
{
if (! utf8.empty())
{
auto numUTF8Bytes = static_cast<int> (utf8.size());
auto resultSize = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, nullptr, 0);

if (resultSize > 0)
{
std::wstring result;
result.resize (static_cast<size_t> (resultSize));

if (MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), numUTF8Bytes, result.data(), resultSize) > 0)
return result;
}
}

return {};
}

END_NAMESPACE_DISTRHO

#endif // CHOC_DESKTOPWINDOW_HEADER_INCLUDED

+ 141
- 0
dpf/distrho/extra/choc/choc_DynamicLibrary.h View File

@@ -0,0 +1,141 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED
#define CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED

#include <string>

START_NAMESPACE_DISTRHO

//==============================================================================
/**
A minimal cross-platform loader for .dll/.so files.
*/
struct DynamicLibrary
{
DynamicLibrary() = default;

/// Attempts to load a library with the given name or path.
DynamicLibrary (std::string_view library);

DynamicLibrary (const DynamicLibrary&) = delete;
DynamicLibrary& operator= (const DynamicLibrary&) = delete;
DynamicLibrary (DynamicLibrary&&);
DynamicLibrary& operator= (DynamicLibrary&&);

/// On destruction, this object releases the library that was loaded
~DynamicLibrary();

/// Returns a pointer to the function with this name, or nullptr if not found.
void* findFunction (std::string_view functionName);

/// Returns true if the library was successfully loaded
operator bool() const noexcept { return handle != nullptr; }

/// Releases any handle that this object is holding
void close();

/// platform-specific handle. Will be nullptr if not loaded
void* handle = nullptr;
};



//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

inline DynamicLibrary::~DynamicLibrary()
{
close();
}

inline DynamicLibrary::DynamicLibrary (DynamicLibrary&& other) : handle (other.handle)
{
other.handle = nullptr;
}

inline DynamicLibrary& DynamicLibrary::operator= (DynamicLibrary&& other)
{
close();
handle = other.handle;
other.handle = nullptr;
return *this;
}

//==============================================================================
namespace win32_defs
{
#if ! (defined (_WINDOWS_) || defined (_APISETLIBLOADER_)) // only use these local definitions if windows.h isn't already included
using CHOC_HMODULE = void*;
#ifdef _MSC_VER
extern "C" CHOC_HMODULE __stdcall choc_LoadLibraryA (const char*);
extern "C" int __stdcall choc_FreeLibrary (CHOC_HMODULE);
extern "C" void* __stdcall choc_GetProcAddress (CHOC_HMODULE, const char*);
#pragma comment(linker,"/alternatename:choc_LoadLibraryA=LoadLibraryA")
#pragma comment(linker,"/alternatename:choc_FreeLibrary=FreeLibrary")
#pragma comment(linker,"/alternatename:choc_GetProcAddress=GetProcAddress")
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return choc_LoadLibraryA (l); }
static inline int FreeLibrary (CHOC_HMODULE m) { return choc_FreeLibrary (m); }
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return choc_GetProcAddress (m, f); }
#else
extern "C" __declspec(dllimport) CHOC_HMODULE __stdcall LoadLibraryA (const char*);
extern "C" __declspec(dllimport) int __stdcall FreeLibrary (CHOC_HMODULE);
extern "C" __declspec(dllimport) void* __stdcall GetProcAddress (CHOC_HMODULE, const char*);
#endif
#else
using CHOC_HMODULE = HMODULE;
static inline CHOC_HMODULE LoadLibraryA (const char* l) { return ::LoadLibraryA (l); }
static inline int FreeLibrary (CHOC_HMODULE m) { return ::FreeLibrary (m); }
static inline void* GetProcAddress (CHOC_HMODULE m, const char* f) { return (void*) ::GetProcAddress (m, f); }
#endif
}

inline DynamicLibrary::DynamicLibrary (std::string_view library)
{
handle = (void*) win32_defs::LoadLibraryA (std::string (library).c_str());
}

inline void DynamicLibrary::close()
{
if (handle != nullptr)
{
win32_defs::FreeLibrary ((win32_defs::CHOC_HMODULE) handle);
handle = nullptr;
}
}

inline void* DynamicLibrary::findFunction (std::string_view name)
{
if (handle != nullptr)
return (void*) win32_defs::GetProcAddress ((win32_defs::CHOC_HMODULE) handle, std::string (name).c_str());

return {};
}

END_NAMESPACE_DISTRHO

#endif // CHOC_DYNAMIC_LIBRARY_HEADER_INCLUDED

+ 511
- 0
dpf/distrho/extra/choc/choc_MemoryDLL.h View File

@@ -0,0 +1,511 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 CHOC_MEMORYDLL_HEADER_INCLUDED
#define CHOC_MEMORYDLL_HEADER_INCLUDED

#include <stddef.h>
#include <memory>
#include <string>

START_NAMESPACE_DISTRHO

/**
MemoryDLL is an egregious hack that allows you to load DLL files from a chunk
of memory in the same way you might load them from a file on disk.

This opens up the ability to do horrible things such as embedding a random DLL
in a chunk of C++ code, so that it gets baked directly into your executable..
That means that if your app requires a 3rd-party DLL but you don't want the hassle
of having to install the DLL file in the right place on your users' machines, you
could use this trick to embed it invisibly inside your executable...

Currently this is only implemented for Windows DLLs, but a linux/OSX loader for
.dylibs is also totally feasible if anyone fancies having a go :)

@see DynamicLibrary
*/
struct MemoryDLL
{
MemoryDLL() = default;
MemoryDLL (MemoryDLL&&) = default;
MemoryDLL& operator= (MemoryDLL&&) = default;
~MemoryDLL();

/// Attempts to load a chunk of memory that contains a DLL file image.
MemoryDLL (const void* data, size_t size);

/// Returns a pointer to the function with this name, or nullptr if not found.
void* findFunction (std::string_view functionName);

/// Returns true if the library was successfully loaded
operator bool() const { return pimpl != nullptr; }

private:
struct Pimpl;
std::unique_ptr<Pimpl> pimpl;
};

END_NAMESPACE_DISTRHO



//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

#include <vector>
#include <unordered_map>
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#define NOMINMAX
#define Rectangle Rectangle_renamed_to_avoid_name_collisions
#include <windows.h>
#undef Rectangle

START_NAMESPACE_DISTRHO

struct MemoryDLL::Pimpl
{
Pimpl() = default;

~Pimpl()
{
if (entryFunction != nullptr)
(*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_DETACH, nullptr);

for (auto& m : loadedModules)
FreeLibrary (m);

if (imageData != nullptr)
VirtualFree (imageData, 0, MEM_RELEASE);

for (auto m : virtualBlocks)
VirtualFree (m, 0, MEM_RELEASE);
}

bool initialise (const void* data, size_t size)
{
if (size < sizeof (IMAGE_DOS_HEADER))
return false;

auto dosHeader = static_cast<const IMAGE_DOS_HEADER*> (data);

if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE
|| size < static_cast<size_t> (dosHeader->e_lfanew) + sizeof (IMAGE_NT_HEADERS))
return false;

const auto& headers = *getOffsetAs<IMAGE_NT_HEADERS> (data, dosHeader->e_lfanew);

if (headers.Signature != IMAGE_NT_SIGNATURE
|| (headers.OptionalHeader.SectionAlignment & 1) != 0)
return false;

#ifdef _M_ARM64
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_ARM64) return false;
#elif defined (_WIN64)
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) return false;
#else
if (headers.FileHeader.Machine != IMAGE_FILE_MACHINE_I386) return false;
#endif

SYSTEM_INFO systemInfo;
GetNativeSystemInfo (std::addressof (systemInfo));

auto alignedImageSize = roundUp (headers.OptionalHeader.SizeOfImage, systemInfo.dwPageSize);

if (alignedImageSize != roundUp (getLastSectionEnd (headers), systemInfo.dwPageSize))
return false;

imageData = VirtualAlloc (reinterpret_cast<void*> (headers.OptionalHeader.ImageBase),
alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
{
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
return false;
}

while ((((uint64_t) imageData) >> 32) < (((uint64_t) imageData + alignedImageSize) >> 32))
{
virtualBlocks.push_back (imageData);
imageData = VirtualAlloc (nullptr, alignedImageSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

if (imageData == nullptr)
return false;
}

isDLL = (headers.FileHeader.Characteristics & IMAGE_FILE_DLL) != 0;
pageSize = systemInfo.dwPageSize;

if (size < headers.OptionalHeader.SizeOfHeaders)
return false;

auto newHeaders = VirtualAlloc (imageData, headers.OptionalHeader.SizeOfHeaders, MEM_COMMIT, PAGE_READWRITE);
memcpy (newHeaders, dosHeader, headers.OptionalHeader.SizeOfHeaders);
imageHeaders = getOffsetAs<IMAGE_NT_HEADERS> (newHeaders, dosHeader->e_lfanew);
imageHeaders->OptionalHeader.ImageBase = reinterpret_cast<uintptr_t> (imageData);

if (copySections (data, size, headers.OptionalHeader.SectionAlignment))
{
if (auto locationDelta = (ptrdiff_t) (imageHeaders->OptionalHeader.ImageBase - headers.OptionalHeader.ImageBase))
performRelocation (locationDelta);

if (loadImports() && prepareSections())
{
executeTLS();
loadNameTable();

if (imageHeaders->OptionalHeader.AddressOfEntryPoint != 0)
{
entryFunction = getOffsetAs<char> (imageData, imageHeaders->OptionalHeader.AddressOfEntryPoint);

if (isDLL)
return (*reinterpret_cast<DLLEntryFn> (entryFunction)) ((HINSTANCE) imageData, DLL_PROCESS_ATTACH, nullptr);

return true;
}
}
}

return false;
}

void* findFunction (std::string_view name)
{
if (auto found = exportedFunctionOffsets.find (std::string (name)); found != exportedFunctionOffsets.end())
return getOffsetAs<char> (imageData, found->second);

return {};
}

private:
PIMAGE_NT_HEADERS imageHeaders = {};
void* imageData = nullptr;
std::vector<HMODULE> loadedModules;
uint32_t pageSize = 0;
bool isDLL = false;
std::vector<void*> virtualBlocks;
std::unordered_map<std::string, size_t> exportedFunctionOffsets;
using DLLEntryFn = BOOL(WINAPI*)(HINSTANCE, DWORD, void*);
void* entryFunction = {};

template <typename Type, typename Diff>
static const Type* getOffsetAs (const void* address, Diff offset)
{
return reinterpret_cast<const Type*> (static_cast<const char*> (address) + offset);
}

template <typename Type, typename Diff>
static Type* getOffsetAs (void* address, Diff offset)
{
return reinterpret_cast<Type*> (static_cast<char*> (address) + offset);
}

template <typename Type>
Type* getDataDirectoryAddress (int type) const
{
auto& dd = imageHeaders->OptionalHeader.DataDirectory[type];

if (dd.Size > 0)
return getOffsetAs<Type> (imageData, dd.VirtualAddress);

return {};
}

static size_t getLastSectionEnd (const IMAGE_NT_HEADERS& headers)
{
auto section = IMAGE_FIRST_SECTION (&headers);
auto optionalSectionSize = headers.OptionalHeader.SectionAlignment;
size_t lastSectionEnd = 0;

for (uint32_t i = 0; i < headers.FileHeader.NumberOfSections; ++i, ++section)
{
auto end = section->VirtualAddress + (section->SizeOfRawData == 0 ? optionalSectionSize
: section->SizeOfRawData);
if (end > lastSectionEnd)
lastSectionEnd = end;
}

return lastSectionEnd;
}

void loadNameTable()
{
if (auto exports = getDataDirectoryAddress<IMAGE_EXPORT_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_EXPORT))
{
if (exports->NumberOfNames > 0 && exports->NumberOfFunctions > 0)
{
auto name = getOffsetAs<const DWORD> (imageData, exports->AddressOfNames);
auto ordinal = getOffsetAs<const WORD> (imageData, exports->AddressOfNameOrdinals);

exportedFunctionOffsets.reserve (exports->NumberOfNames);

for (size_t i = 0; i < exports->NumberOfNames; ++i, ++name, ++ordinal)
if (*ordinal <= exports->NumberOfFunctions)
exportedFunctionOffsets[std::string (getOffsetAs<const char> (imageData, *name))]
= getOffsetAs<DWORD> (imageData, exports->AddressOfFunctions)[*ordinal];
}
}
}

void executeTLS()
{
if (auto tls = getDataDirectoryAddress<IMAGE_TLS_DIRECTORY> (IMAGE_DIRECTORY_ENTRY_TLS))
if (auto callback = reinterpret_cast<PIMAGE_TLS_CALLBACK*> (tls->AddressOfCallBacks))
while (*callback != nullptr)
(*callback++) ((void*) imageData, DLL_PROCESS_ATTACH, nullptr);
}

bool prepareSections()
{
auto section = IMAGE_FIRST_SECTION (imageHeaders);
auto size = getSectionSize (*section);
auto address = getSectionAddress (*section);
auto addressPage = getPageBase (address);
auto characteristics = section->Characteristics;

for (WORD i = 1; i < imageHeaders->FileHeader.NumberOfSections; ++i)
{
++section;
auto nextSize = getSectionSize (*section);
auto nextAddress = getSectionAddress (*section);
auto nextAddressPage = getPageBase (nextAddress);

if (addressPage == nextAddressPage || address + size > nextAddressPage)
{
if ((section->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0 || (characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0)
characteristics = (characteristics | section->Characteristics) & ~static_cast<DWORD> (IMAGE_SCN_MEM_DISCARDABLE);
else
characteristics |= section->Characteristics;

size = static_cast<size_t> ((nextAddress + nextSize) - address);
continue;
}

if (! setProtectionFlags (size, characteristics, address, addressPage, false))
return false;

size = nextSize;
address = nextAddress;
addressPage = nextAddressPage;
characteristics = section->Characteristics;
}

return setProtectionFlags (size, characteristics, address, addressPage, true);
}

bool setProtectionFlags (size_t sectionSize, DWORD sectionCharacteristics, void* sectionAddress, void* addressPage, bool isLast)
{
if (sectionSize == 0)
return true;

if ((sectionCharacteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)
{
if (sectionAddress == addressPage
&& (isLast || imageHeaders->OptionalHeader.SectionAlignment == pageSize || (sectionSize % pageSize) == 0))
VirtualFree (sectionAddress, sectionSize, MEM_DECOMMIT);

return true;
}

auto getProtectionFlags = [] (DWORD type)
{
return ((type & IMAGE_SCN_MEM_NOT_CACHED) ? PAGE_NOCACHE : 0)
| ((type & IMAGE_SCN_MEM_EXECUTE)
? ((type & IMAGE_SCN_MEM_READ)
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ)
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_EXECUTE_WRITECOPY : PAGE_EXECUTE))
: ((type & IMAGE_SCN_MEM_READ)
? ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_READWRITE : PAGE_READONLY)
: ((type & IMAGE_SCN_MEM_WRITE) ? PAGE_WRITECOPY : PAGE_NOACCESS)));
};

DWORD oldProtectValue;
return VirtualProtect (sectionAddress, sectionSize,
static_cast<DWORD> (getProtectionFlags (sectionCharacteristics)),
std::addressof (oldProtectValue)) != 0;
}

bool loadImports()
{
auto imp = getDataDirectoryAddress<IMAGE_IMPORT_DESCRIPTOR> (IMAGE_DIRECTORY_ENTRY_IMPORT);

if (imp == nullptr)
return false;

while (! IsBadReadPtr (imp, sizeof (IMAGE_IMPORT_DESCRIPTOR)) && imp->Name != 0)
{
auto handle = LoadLibraryA (getOffsetAs<const char> (imageData, imp->Name));

if (handle == nullptr)
return false;

loadedModules.push_back (handle);
auto thunkRef = getOffsetAs<uintptr_t> (imageData, imp->OriginalFirstThunk ? imp->OriginalFirstThunk
: imp->FirstThunk);
auto funcRef = getOffsetAs<FARPROC> (imageData, imp->FirstThunk);

for (; *thunkRef != 0; ++thunkRef, ++funcRef)
{
auto name = IMAGE_SNAP_BY_ORDINAL(*thunkRef)
? (LPCSTR) IMAGE_ORDINAL(*thunkRef)
: (LPCSTR) std::addressof (getOffsetAs<IMAGE_IMPORT_BY_NAME> (imageData, *thunkRef)->Name);

*funcRef = GetProcAddress (handle, name);

if (*funcRef == 0)
return false;
}

++imp;
}

return true;
}

size_t getSectionSize (const IMAGE_SECTION_HEADER& section) const
{
if (auto size = section.SizeOfRawData)
return size;

if (section.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
return imageHeaders->OptionalHeader.SizeOfInitializedData;

if (section.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
return imageHeaders->OptionalHeader.SizeOfUninitializedData;

return 0;
}

static size_t roundUp (size_t value, size_t alignment) { return (value + alignment - 1) & ~(alignment - 1); }
char* getPageBase (void* address) const { return (char*) (reinterpret_cast<uintptr_t> (address) & ~static_cast<uintptr_t> (pageSize - 1)); }

char* getSectionAddress (const IMAGE_SECTION_HEADER& section) const
{
#ifdef _WIN64
return reinterpret_cast<char*> (static_cast<uintptr_t> (section.Misc.PhysicalAddress)
| (static_cast<uintptr_t> (imageHeaders->OptionalHeader.ImageBase & 0xffffffff00000000)));
#else
return reinterpret_cast<char*> (section.Misc.PhysicalAddress);
#endif
}

bool copySections (const void* data, size_t size, size_t sectionAlignment) const
{
auto section = IMAGE_FIRST_SECTION (imageHeaders);

for (int i = 0; i < imageHeaders->FileHeader.NumberOfSections; ++i, ++section)
{
if (section->SizeOfRawData == 0)
{
if (sectionAlignment == 0)
continue;

if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress),
sectionAlignment, MEM_COMMIT, PAGE_READWRITE))
{
dest = getOffsetAs<char> (imageData, section->VirtualAddress);
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest));
memset (dest, 0, sectionAlignment);
continue;
}

return false;
}

if (size < section->PointerToRawData + section->SizeOfRawData)
return false;

if (auto dest = VirtualAlloc (getOffsetAs<char> (imageData, section->VirtualAddress),
section->SizeOfRawData, MEM_COMMIT, PAGE_READWRITE))
{
dest = getOffsetAs<char> (imageData, section->VirtualAddress);
memcpy (dest, static_cast<const char*> (data) + section->PointerToRawData, section->SizeOfRawData);
section->Misc.PhysicalAddress = static_cast<uint32_t> (reinterpret_cast<uintptr_t> (dest));
continue;
}

return false;
}

return true;
}

void performRelocation (ptrdiff_t delta)
{
auto directory = imageHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

if (directory.Size != 0)
{
auto relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (imageData, directory.VirtualAddress);

while (relocation->VirtualAddress > 0)
{
auto dest = getOffsetAs<char> (imageData, relocation->VirtualAddress);
auto offset = getOffsetAs<uint16_t> (relocation, sizeof (IMAGE_BASE_RELOCATION));

for (uint32_t i = 0; i < (relocation->SizeOfBlock - sizeof (IMAGE_BASE_RELOCATION)) / 2; ++i, ++offset)
{
switch (*offset >> 12)
{
case IMAGE_REL_BASED_HIGHLOW: addDelta<uint32_t> (dest + (*offset & 0xfff), delta); break;
case IMAGE_REL_BASED_DIR64: addDelta<uint64_t> (dest + (*offset & 0xfff), delta); break;
case IMAGE_REL_BASED_ABSOLUTE:
default: break;
}
}

relocation = getOffsetAs<IMAGE_BASE_RELOCATION> (relocation, relocation->SizeOfBlock);
}
}
}

template <typename Type>
static void addDelta (char* addr, ptrdiff_t delta)
{
*reinterpret_cast<Type*> (addr) = static_cast<Type> (static_cast<ptrdiff_t> (*reinterpret_cast<Type*> (addr)) + delta);
}
};

inline MemoryDLL::~MemoryDLL() = default;

inline MemoryDLL::MemoryDLL (const void* data, size_t size) : pimpl (std::make_unique<Pimpl>())
{
if (! pimpl->initialise (data, size))
pimpl.reset();
}

inline void* MemoryDLL::findFunction (std::string_view name)
{
return pimpl != nullptr ? pimpl->findFunction (name) : nullptr;
}

END_NAMESPACE_DISTRHO

#endif // CHOC_MEMORYDLL_HEADER_INCLUDED

+ 67
- 0
dpf/distrho/extra/choc/choc_Platform.h View File

@@ -0,0 +1,67 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 CHOC_PLATFORM_DETECT_HEADER_INCLUDED
#define CHOC_PLATFORM_DETECT_HEADER_INCLUDED

/*
These conditionals declare the macros
- CHOC_WINDOWS
- CHOC_ANDROID
- CHOC_LINUX
- CHOC_OSX
- CHOC_IOS
...based on the current operating system.

It also declares a string literal macro CHOC_OPERATING_SYSTEM_NAME
which can be used if you need a text description of the OS.
*/
#if defined (_WIN32) || defined (_WIN64)
#define CHOC_WINDOWS 1
#define CHOC_OPERATING_SYSTEM_NAME "Windows"
#elif __ANDROID__
#define CHOC_ANDROID 1
#define CHOC_OPERATING_SYSTEM_NAME "Android"
#elif defined (LINUX) || defined (__linux__)
#define CHOC_LINUX 1
#define CHOC_OPERATING_SYSTEM_NAME "Linux"
#elif __APPLE__
#define CHOC_APPLE 1
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define CHOC_IOS 1
#define CHOC_OPERATING_SYSTEM_NAME "iOS"
#else
#define CHOC_OSX 1
#define CHOC_OPERATING_SYSTEM_NAME "OSX"
#endif
#elif defined (__FreeBSD__) || (__OpenBSD__)
#define CHOC_BSD 1
#define CHOC_OPERATING_SYSTEM_NAME "BSD"
#elif defined (_POSIX_VERSION)
#define CHOC_POSIX 1
#define CHOC_OPERATING_SYSTEM_NAME "Posix"
#elif defined (__EMSCRIPTEN__)
#define CHOC_EMSCRIPTEN 1
#define CHOC_OPERATING_SYSTEM_NAME "Emscripten"
#else
#error "Unknown platform!"
#endif


#endif // CHOC_PLATFORM_DETECT_HEADER_INCLUDED

+ 74
- 0
dpf/distrho/extra/choc/choc_StringUtilities.h View File

@@ -0,0 +1,74 @@
//
// ██████ ██  ██  ██████  ██████
// ██      ██  ██ ██    ██ ██       ** Classy Header-Only Classes **
// ██  ███████ ██  ██ ██
// ██  ██   ██ ██  ██ ██ https://github.com/Tracktion/choc
//  ██████ ██  ██  ██████   ██████
//
// CHOC is (C)2022 Tracktion Corporation, and is offered under the terms of the ISC license:
//
// 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 CHOC_STRING_UTILS_HEADER_INCLUDED
#define CHOC_STRING_UTILS_HEADER_INCLUDED

#include <cctype>
#include <string>
#include <vector>
#include <cmath>
#include <chrono>
#include <memory>
#include <algorithm>
#include <cwctype>

START_NAMESPACE_DISTRHO

//==============================================================================
/// Returns a hex string for the given value.
/// If the minimum number of digits is non-zero, it will be zero-padded to fill this length;
template <typename IntegerType>
std::string createHexString (IntegerType value);


//==============================================================================
// _ _ _ _
// __| | ___ | |_ __ _ (_)| | ___
// / _` | / _ \| __| / _` || || |/ __|
// | (_| || __/| |_ | (_| || || |\__ \ _ _ _
// \__,_| \___| \__| \__,_||_||_||___/(_)(_)(_)
//
// Code beyond this point is implementation detail...
//
//==============================================================================

template <typename IntegerType>
std::string createHexString (IntegerType v)
{
static_assert (std::is_integral<IntegerType>::value, "Need to pass integers into this method");
auto value = static_cast<typename std::make_unsigned<IntegerType>::type> (v);

char hex[40];
const auto end = hex + sizeof (hex) - 1;
auto d = end;
*d = 0;

for (;;)
{
*--d = "0123456789abcdef"[static_cast<uint32_t> (value) & 15u];
value = static_cast<decltype (value)> (value >> 4);

if (value == 0)
return std::string (d, end);
}
}

END_NAMESPACE_DISTRHO

#endif

+ 4769
- 0
dpf/distrho/extra/choc/choc_WebView.h
File diff suppressed because it is too large
View File


+ 3
- 0
dpf/distrho/src/DistrhoDefines.h View File

@@ -212,6 +212,8 @@ private: \

/* Useful macros */
#define ARRAY_SIZE(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
#define STRINGIFY2(s) #s
#define STRINGIFY(s) STRINGIFY2(s)

/* Useful typedefs */
typedef unsigned char uchar;
@@ -223,5 +225,6 @@ typedef unsigned long long int ulonglong;
/* Deprecated macros */
#define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName)
#define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) DISTRHO_DECLARE_NON_COPYABLE(StructName)
#define DISTRHO_MACRO_AS_STRING(MACRO) STRINGIFY2(MACRO)

#endif // DISTRHO_DEFINES_H_INCLUDED

+ 2
- 1
dpf/distrho/src/DistrhoPlugin.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -246,6 +246,7 @@ void Plugin::setState(const char*, const char*) {}

void Plugin::bufferSizeChanged(uint32_t) {}
void Plugin::sampleRateChanged(double) {}
void Plugin::ioChanged(uint16_t, uint16_t) {}

// -----------------------------------------------------------------------------------------------------------



+ 3205
- 0
dpf/distrho/src/DistrhoPluginAU.cpp
File diff suppressed because it is too large
View File


+ 19
- 27
dpf/distrho/src/DistrhoPluginCLAP.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -29,7 +29,7 @@
# error DISTRHO_PLUGIN_CLAP_ID undefined!
#endif

#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL)
# undef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif
@@ -57,7 +57,7 @@
#include "clap/ext/thread-check.h"
#include "clap/ext/timer-support.h"

#if (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)
# define DPF_CLAP_USING_HOST_TIMER 0
#else
# define DPF_CLAP_USING_HOST_TIMER 1
@@ -211,7 +211,9 @@ public:
#endif
const bool isFloating)
: fPlugin(plugin),
#if DISTRHO_PLUGIN_WANT_STATE
fPluginEventQueue(eventQueue),
#endif
fEventQueue(eventQueue->fEventQueue),
fCachedParameters(eventQueue->fCachedParameters),
#if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -280,10 +282,10 @@ public:

double scaleFactor = fScaleFactor;
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT)
*width = DISTRHO_UI_DEFAULT_WIDTH;
*height = DISTRHO_UI_DEFAULT_HEIGHT;
if (d_isZero(scaleFactor))
scaleFactor = 1.0;
*width = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor;
*height = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor;
#else
UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath,
@@ -371,10 +373,10 @@ public:
{
// fix width
if (reqRatio > ratio)
*width = static_cast<int32_t>(*height * ratio + 0.5);
*width = d_roundToIntPositive(*height * ratio);
// fix height
else
*height = static_cast<int32_t>(static_cast<double>(*width) / ratio + 0.5);
*height = d_roundToIntPositive(static_cast<double>(*width) / ratio);
}
}

@@ -534,7 +536,9 @@ public:
private:
// Plugin and UI
PluginExporter& fPlugin;
#if DISTRHO_PLUGIN_WANT_STATE
ClapEventQueue* const fPluginEventQueue;
#endif
ClapEventQueue::Queue& fEventQueue;
ClapEventQueue::CachedParameters& fCachedParameters;
#if DISTRHO_PLUGIN_WANT_PROGRAMS
@@ -600,8 +604,8 @@ private:
// Set state
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& value = cit->second;
const String& key(cit->first);
const String& value(cit->second);

// TODO skip DSP only states

@@ -1433,7 +1437,7 @@ public:
// Update current state
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& key(cit->first);
fStateMap[key] = fPlugin.getStateValue(key);
}
#endif
@@ -1457,8 +1461,8 @@ public:

for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& value = cit->second;
const String& key(cit->first);
const String& value(cit->second);

// join key and value
String tmpStr;
@@ -1764,23 +1768,11 @@ public:
{
fPlugin.setState(key, value);

// check if we want to save this key
if (! fPlugin.wantStateKey(key))
return;

// check if key already exists
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
if (fPlugin.wantStateKey(key))
{
const String& dkey(it->first);

if (dkey == key)
{
it->second = value;
return;
}
const String dkey(key);
fStateMap[dkey] = value;
}

d_stderr("Failed to find plugin state with key \"%s\"", key);
}
#endif



+ 126
- 45
dpf/distrho/src/DistrhoPluginChecks.h View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -23,7 +23,7 @@

#include "DistrhoPluginInfo.h"

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Check if all required macros are defined

#ifndef DISTRHO_PLUGIN_NAME
@@ -42,17 +42,13 @@
# error DISTRHO_PLUGIN_URI undefined!
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Define optional macros if not done yet

#ifndef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif

#ifndef DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# define DISTRHO_PLUGIN_HAS_EXTERNAL_UI 0
#endif

#ifndef DISTRHO_PLUGIN_IS_RT_SAFE
# define DISTRHO_PLUGIN_IS_RT_SAFE 0
#endif
@@ -95,47 +91,94 @@
#endif

#ifndef DISTRHO_UI_FILE_BROWSER
# if defined(DGL_FILE_BROWSER_DISABLED) || DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# define DISTRHO_UI_FILE_BROWSER 0
# else
# define DISTRHO_UI_FILE_BROWSER 1
# endif
# define DISTRHO_UI_FILE_BROWSER 0
#endif
#ifndef DISTRHO_UI_WEB_VIEW
# define DISTRHO_UI_WEB_VIEW 0
#endif

#ifndef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif

// --------------------------------------------------------------------------------------------------------------------
// set UI type

#ifndef DISTRHO_UI_USE_CAIRO
# define DISTRHO_UI_USE_CAIRO 0
#endif

#ifndef DISTRHO_UI_USE_CUSTOM
# define DISTRHO_UI_USE_CUSTOM 0
#endif

#ifndef DISTRHO_UI_USE_EXTERNAL
# define DISTRHO_UI_USE_EXTERNAL 0
#endif

#ifndef DISTRHO_UI_USE_NANOVG
# define DISTRHO_UI_USE_NANOVG 0
#endif

// -----------------------------------------------------------------------
// Define DISTRHO_PLUGIN_HAS_EMBED_UI if needed
#ifndef DISTRHO_UI_USE_WEB_VIEW
# define DISTRHO_UI_USE_WEB_VIEW 0
#endif

// --------------------------------------------------------------------------------------------------------------------
// Define DISTRHO_UI_WEB_VIEW if needed

#ifndef DISTRHO_PLUGIN_HAS_EMBED_UI
# if (defined(DGL_CAIRO) && defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && defined(HAVE_OPENGL))
# define DISTRHO_PLUGIN_HAS_EMBED_UI 1
# else
# define DISTRHO_PLUGIN_HAS_EMBED_UI 0
# endif
#if DISTRHO_UI_USE_WEB_VIEW && !DISTRHO_UI_WEB_VIEW
# undef DISTRHO_UI_WEB_VIEW
# define DISTRHO_UI_WEB_VIEW 1
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Define DISTRHO_UI_URI if needed

#ifndef DISTRHO_UI_URI
# define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#DPF_UI"
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Test for wrong compiler macros

#if defined(DISTRHO_PLUGIN_HAS_EMBED_UI)
# warning DISTRHO_PLUGIN_HAS_EMBED_UI has been removed, it is now always on
#endif

#if defined(DISTRHO_PLUGIN_HAS_EXTERNAL_UI)
# error DISTRHO_PLUGIN_HAS_EXTERNAL_UI has been replaced by DISTRHO_UI_USE_EXTERNAL
#endif

#ifdef DISTRHO_UI_FILEBROWSER
# error typo detected use DISTRHO_UI_FILE_BROWSER instead of DISTRHO_UI_FILEBROWSER
#endif

#ifdef DISTRHO_UI_WEBVIEW
# error typo detected use DISTRHO_UI_WEB_VIEW instead of DISTRHO_UI_WEBVIEW
#endif

#ifdef DISTRHO_UI_USE_WEBVIEW
# error typo detected use DISTRHO_UI_USE_WEB_VIEW instead of DISTRHO_UI_USE_WEBVIEW
#endif

#if DISTRHO_UI_FILE_BROWSER && !defined(DGL_USE_FILE_BROWSER)
# error invalid build config: file browser requested but `USE_FILE_BROWSER` build option is not set
#endif

#if DISTRHO_UI_WEB_VIEW && !defined(DGL_USE_WEB_VIEW)
# error invalid build config: web view requested but `USE_WEB_VIEW` build option is not set
#endif

// --------------------------------------------------------------------------------------------------------------------
// Test if synth has audio outputs

#if DISTRHO_PLUGIN_IS_SYNTH && DISTRHO_PLUGIN_NUM_OUTPUTS == 0
# error Synths need audio output to work!
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Enable MIDI input if synth, test if midi-input disabled when synth

#ifndef DISTRHO_PLUGIN_WANT_MIDI_INPUT
@@ -144,7 +187,7 @@
# error Synths need MIDI input to work!
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Enable state if plugin wants state files (deprecated)

#ifdef DISTRHO_PLUGIN_WANT_STATEFILES
@@ -156,7 +199,7 @@
# endif
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Enable full state if plugin exports presets

#if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && defined(DISTRHO_PLUGIN_WANT_FULL_STATE_WAS_NOT_SET)
@@ -165,29 +208,15 @@
# define DISTRHO_PLUGIN_WANT_FULL_STATE 1
#endif

// -----------------------------------------------------------------------
// Disable file browser if using external UI

#if DISTRHO_UI_FILE_BROWSER && DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# warning file browser APIs do not work for external UIs
# undef DISTRHO_UI_FILE_BROWSER 0
# define DISTRHO_UI_FILE_BROWSER 0
#endif

// -----------------------------------------------------------------------
// Disable UI if DGL or external UI is not available
// --------------------------------------------------------------------------------------------------------------------
// Disable UI if DGL is not available

#if (defined(DGL_CAIRO) && ! defined(HAVE_CAIRO)) || (defined(DGL_OPENGL) && ! defined(HAVE_OPENGL))
# undef DISTRHO_PLUGIN_HAS_EMBED_UI
# define DISTRHO_PLUGIN_HAS_EMBED_UI 0
#endif

#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_HAS_UI && !defined(HAVE_DGL)
# undef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Make sure both default width and height are provided

#if defined(DISTRHO_UI_DEFAULT_WIDTH) && !defined(DISTRHO_UI_DEFAULT_HEIGHT)
@@ -198,13 +227,65 @@
# error DISTRHO_UI_DEFAULT_HEIGHT is defined but DISTRHO_UI_DEFAULT_WIDTH is not
#endif

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// Define DISTRHO_PLUGIN_AU_TYPE if needed

#ifndef DISTRHO_PLUGIN_AU_TYPE
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) && DISTRHO_PLUGIN_NUM_INPUTS != 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
# define DISTRHO_PLUGIN_AU_TYPE aumf /* kAudioUnitType_MusicEffect */
# elif (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT) && DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS != 0
# define DISTRHO_PLUGIN_AU_TYPE aumu /* kAudioUnitType_MusicDevice */
# elif DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
# define DISTRHO_PLUGIN_AU_TYPE aumi /* kAudioUnitType_MIDIProcessor */
# elif DISTRHO_PLUGIN_NUM_INPUTS == 0 && DISTRHO_PLUGIN_NUM_OUTPUTS != 0
# define DISTRHO_PLUGIN_AU_TYPE augn /* kAudioUnitType_Generator */
# else
# define DISTRHO_PLUGIN_AU_TYPE aufx /* kAudioUnitType_Effect */
# endif
#endif

// --------------------------------------------------------------------------------------------------------------------
// Check that symbol macros are well defined

#ifdef DISTRHO_PROPER_CPP11_SUPPORT

#ifdef DISTRHO_PLUGIN_AU_TYPE
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_AU_TYPE)) == 5, "The macro DISTRHO_PLUGIN_AU_TYPE has incorrect length");
# if DISTRHO_PLUGIN_NUM_INPUTS == 0 || DISTRHO_PLUGIN_NUM_OUTPUTS == 0
static constexpr const char _aut[5] = STRINGIFY(DISTRHO_PLUGIN_AU_TYPE);
static_assert(_aut[0] != 'a' || _aut[0] != 'u' || _aut[0] != 'm' || _aut[0] != 'u',
"The 'aumu' type requires both audio input and output");
# endif
#endif

#ifdef DISTRHO_PLUGIN_BRAND_ID
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID)) == 5, "The macro DISTRHO_PLUGIN_BRAND_ID has incorrect length");
#endif

#ifdef DISTRHO_PLUGIN_UNIQUE_ID
static_assert(sizeof(STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID)) == 5, "The macro DISTRHO_PLUGIN_UNIQUE_ID has incorrect length");
#endif

#endif

// --------------------------------------------------------------------------------------------------------------------
// Prevent users from messing about with DPF internals

#ifdef DISTRHO_UI_IS_STANDALONE
# 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
#endif

// --------------------------------------------------------------------------------------------------------------------

#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED

+ 281
- 0
dpf/distrho/src/DistrhoPluginExport.cpp View File

@@ -0,0 +1,281 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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"
#include "../DistrhoPluginUtils.hpp"

#ifndef DISTRHO_PLUGIN_BRAND_ID
# error DISTRHO_PLUGIN_BRAND_ID undefined!
#endif

#ifndef DISTRHO_PLUGIN_UNIQUE_ID
# error DISTRHO_PLUGIN_UNIQUE_ID undefined!
#endif

#include <fstream>
#include <iostream>

USE_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------

void generate_au_plist(const PluginExporter& plugin,
const char* const basename,
const char* const license)
{
std::cout << "Writing Info.plist..."; std::cout.flush();
std::fstream outputFile("Info.plist", std::ios::out);

const uint32_t version = plugin.getVersion();

const uint32_t majorVersion = (version & 0xFF0000) >> 16;
const uint32_t minorVersion = (version & 0x00FF00) >> 8;
const uint32_t microVersion = (version & 0x0000FF) >> 0;

outputFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
outputFile << "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
outputFile << "<plist>\n";
outputFile << " <dict>\n";
outputFile << " <key>CFBundleExecutable</key>\n";
outputFile << " <string>" << basename << "</string>\n";
outputFile << " <key>CFBundleIconFile</key>\n";
outputFile << " <string></string>\n";
outputFile << " <key>CFBundleIdentifier</key>\n";
outputFile << " <string>" DISTRHO_PLUGIN_CLAP_ID "</string>\n";
outputFile << " <key>CFBundleName</key>\n";
outputFile << " <string>" << basename << "</string>\n";
outputFile << " <key>CFBundleDisplayName</key>\n";
outputFile << " <string>" << plugin.getName() << "</string>\n";
outputFile << " <key>CFBundlePackageType</key>\n";
outputFile << " <string>BNDL</string>\n";
outputFile << " <key>CFBundleSignature</key>\n";
outputFile << " <string>" << "????" << "</string>\n";
outputFile << " <key>CFBundleShortVersionString</key>\n";
outputFile << " <string>" << majorVersion << "." << minorVersion << "." << microVersion << "</string>\n";
outputFile << " <key>CFBundleVersion</key>\n";
outputFile << " <string>" << majorVersion << "." << minorVersion << "." << microVersion << "</string>\n";
if (license != nullptr && license[0] != '\0')
{
outputFile << " <key>NSHumanReadableCopyright</key>\n";
outputFile << " <string>" << license << "</string>\n";
}
outputFile << " <key>NSHighResolutionCapable</key>\n";
outputFile << " <true/>\n";
outputFile << " <key>AudioComponents</key>\n";
outputFile << " <array>\n";
outputFile << " <dict>\n";
outputFile << " <key>name</key>\n";
outputFile << " <string>" << plugin.getMaker() << ": " << plugin.getName() << "</string>\n";
outputFile << " <key>description</key>\n";
outputFile << " <string>" << plugin.getDescription() << "</string>\n";
outputFile << " <key>factoryFunction</key>\n";
outputFile << " <string>PluginAUFactory</string>\n";
outputFile << " <key>type</key>\n";
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_AU_TYPE) "</string>\n";
outputFile << " <key>subtype</key>\n";
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_UNIQUE_ID) "</string>\n";
outputFile << " <key>manufacturer</key>\n";
outputFile << " <string>" STRINGIFY(DISTRHO_PLUGIN_BRAND_ID) "</string>\n";
outputFile << " <key>version</key>\n";
outputFile << " <integer>" << version << "</integer>\n";
outputFile << " <key>resourceUsage</key>\n";
outputFile << " <dict>\n";
outputFile << " <key>network.client</key>\n";
outputFile << " <true/>\n";
outputFile << " <key>temporary-exception.files.all.read-write</key>\n";
outputFile << " <true/>\n";
outputFile << " </dict>\n";
outputFile << " </dict>\n";
outputFile << " </array>\n";
outputFile << " </dict>\n";
outputFile << "</plist>\n";

outputFile.close();
std::cout << " done!" << std::endl;
}

// --------------------------------------------------------------------------------------------------------------------

int main(int argc, char* argv[])
{
if (argc <= 1)
return 1;

// Dummy plugin to get data from
d_nextBufferSize = 512;
d_nextSampleRate = 44100.0;
d_nextPluginIsDummy = true;
PluginExporter plugin(nullptr, nullptr, nullptr, nullptr);
d_nextBufferSize = 0;
d_nextSampleRate = 0.0;
d_nextPluginIsDummy = false;

String license(plugin.getLicense());

if (license.isEmpty())
{}
// License as URL, use as-is
else if (license.contains("://"))
{}
// License contains quotes, use as-is
else if (license.contains('"'))
{}
// Regular license string, convert to URL as much as we can
else
{
const String uplicense(license.asUpper());

// for reference, see https://spdx.org/licenses/

// common licenses
/**/ if (uplicense == "AGPL-1.0-ONLY" ||
uplicense == "AGPL1" ||
uplicense == "AGPLV1")
{
license = "http://spdx.org/licenses/AGPL-1.0-only.html";
}
else if (uplicense == "AGPL-1.0-OR-LATER" ||
uplicense == "AGPL1+" ||
uplicense == "AGPLV1+")
{
license = "http://spdx.org/licenses/AGPL-1.0-or-later.html";
}
else if (uplicense == "AGPL-3.0-ONLY" ||
uplicense == "AGPL3" ||
uplicense == "AGPLV3")
{
license = "http://spdx.org/licenses/AGPL-3.0-only.html";
}
else if (uplicense == "AGPL-3.0-OR-LATER" ||
uplicense == "AGPL3+" ||
uplicense == "AGPLV3+")
{
license = "http://spdx.org/licenses/AGPL-3.0-or-later.html";
}
else if (uplicense == "APACHE-2.0" ||
uplicense == "APACHE2" ||
uplicense == "APACHE-2")
{
license = "http://spdx.org/licenses/Apache-2.0.html";
}
else if (uplicense == "BSD-2-CLAUSE" ||
uplicense == "BSD2" ||
uplicense == "BSD-2")
{
license = "http://spdx.org/licenses/BSD-2-Clause.html";
}
else if (uplicense == "BSD-3-CLAUSE" ||
uplicense == "BSD3" ||
uplicense == "BSD-3")
{
license = "http://spdx.org/licenses/BSD-3-Clause.html";
}
else if (uplicense == "GPL-2.0-ONLY" ||
uplicense == "GPL2" ||
uplicense == "GPLV2")
{
license = "http://spdx.org/licenses/GPL-2.0-only.html";
}
else if (uplicense == "GPL-2.0-OR-LATER" ||
uplicense == "GPL2+" ||
uplicense == "GPLV2+" ||
uplicense == "GPLV2.0+" ||
uplicense == "GPL V2+")
{
license = "http://spdx.org/licenses/GPL-2.0-or-later.html";
}
else if (uplicense == "GPL-3.0-ONLY" ||
uplicense == "GPL3" ||
uplicense == "GPLV3")
{
license = "http://spdx.org/licenses/GPL-3.0-only.html";
}
else if (uplicense == "GPL-3.0-OR-LATER" ||
uplicense == "GPL3+" ||
uplicense == "GPLV3+" ||
uplicense == "GPLV3.0+" ||
uplicense == "GPL V3+")
{
license = "http://spdx.org/licenses/GPL-3.0-or-later.html";
}
else if (uplicense == "ISC")
{
license = "http://spdx.org/licenses/ISC.html";
}
else if (uplicense == "LGPL-2.0-ONLY" ||
uplicense == "LGPL2" ||
uplicense == "LGPLV2")
{
license = "http://spdx.org/licenses/LGPL-2.0-only.html";
}
else if (uplicense == "LGPL-2.0-OR-LATER" ||
uplicense == "LGPL2+" ||
uplicense == "LGPLV2+")
{
license = "http://spdx.org/licenses/LGPL-2.0-or-later.html";
}
else if (uplicense == "LGPL-2.1-ONLY" ||
uplicense == "LGPL2.1" ||
uplicense == "LGPLV2.1")
{
license = "http://spdx.org/licenses/LGPL-2.1-only.html";
}
else if (uplicense == "LGPL-2.1-OR-LATER" ||
uplicense == "LGPL2.1+" ||
uplicense == "LGPLV2.1+")
{
license = "http://spdx.org/licenses/LGPL-2.1-or-later.html";
}
else if (uplicense == "LGPL-3.0-ONLY" ||
uplicense == "LGPL3" ||
uplicense == "LGPLV3")
{
license = "http://spdx.org/licenses/LGPL-2.0-only.html";
}
else if (uplicense == "LGPL-3.0-OR-LATER" ||
uplicense == "LGPL3+" ||
uplicense == "LGPLV3+")
{
license = "http://spdx.org/licenses/LGPL-3.0-or-later.html";
}
else if (uplicense == "MIT")
{
license = "http://spdx.org/licenses/MIT.html";
}

// generic fallbacks
else if (uplicense.startsWith("GPL"))
{
license = "http://opensource.org/licenses/gpl-license";
}
else if (uplicense.startsWith("LGPL"))
{
license = "http://opensource.org/licenses/lgpl-license";
}

// unknown or not handled yet, log a warning
else
{
d_stderr("Unknown license string '%s'", license.buffer());
}
}

generate_au_plist(plugin, argv[1], license);

return 0;
}

// --------------------------------------------------------------------------------------------------------------------

+ 47
- 10
dpf/distrho/src/DistrhoPluginInternal.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -309,6 +309,9 @@ struct Plugin::PrivateData {
#if DISTRHO_PLUGIN_WANT_STATE
bool updateStateValueCallback(const char* const key, const char* const value)
{
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, false);

d_stdout("updateStateValueCallback %p", updateStateValueCallbackFunc);
if (updateStateValueCallbackFunc != nullptr)
return updateStateValueCallbackFunc(callbacksPtr, key, value);
@@ -756,6 +759,24 @@ public:
fPlugin->setParameterValue(index, value);
}

/*
bool getParameterIndexForSymbol(const char* const symbol, uint32_t& index)
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);

for (uint32_t i=0; i < fData->parameterCount; ++i)
{
if (fData->parameters[i].symbol == symbol)
{
index = i;
return true;
}
}

return false;
}
*/

uint32_t getPortGroupCount() const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
@@ -868,7 +889,7 @@ public:
}
#endif

# if DISTRHO_PLUGIN_WANT_FULL_STATE
#if DISTRHO_PLUGIN_WANT_FULL_STATE
String getStateValue(const char* const key) const
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, sFallbackString);
@@ -876,7 +897,7 @@ public:

return fPlugin->getState(key);
}
# endif
#endif

void setState(const char* const key, const char* const value)
{
@@ -947,7 +968,7 @@ public:
}
}

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void run(const float** const inputs, float** const outputs, const uint32_t frames,
const MidiEvent* const midiEvents, const uint32_t midiEventCount)
{
@@ -964,7 +985,7 @@ public:
fPlugin->run(inputs, outputs, frames, midiEvents, midiEventCount);
fData->isProcessing = false;
}
#else
#else
void run(const float** const inputs, float** const outputs, const uint32_t frames)
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
@@ -980,7 +1001,21 @@ public:
fPlugin->run(inputs, outputs, frames);
fData->isProcessing = false;
}
#endif
#endif

// -------------------------------------------------------------------

#ifdef DISTRHO_PLUGIN_TARGET_AU
void setAudioPortIO(const uint16_t numInputs, const uint16_t numOutputs)
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);

if (fIsActive) fPlugin->deactivate();
fPlugin->ioChanged(numInputs, numOutputs);
if (fIsActive) fPlugin->activate();
}
#endif

// -------------------------------------------------------------------

@@ -996,14 +1031,14 @@ public:
return fData->sampleRate;
}

void setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
bool setBufferSize(const uint32_t bufferSize, const bool doCallback = false)
{
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, false);
DISTRHO_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
DISTRHO_SAFE_ASSERT(bufferSize >= 2);

if (fData->bufferSize == bufferSize)
return;
return false;

fData->bufferSize = bufferSize;

@@ -1013,6 +1048,8 @@ public:
fPlugin->bufferSizeChanged(bufferSize);
if (fIsActive) fPlugin->activate();
}

return true;
}

void setSampleRate(const double sampleRate, const bool doCallback = false)


+ 42
- 15
dpf/distrho/src/DistrhoPluginJACK.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2024 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
@@ -44,7 +44,9 @@
# undef Point
#endif

#ifndef DISTRHO_OS_WINDOWS
#ifdef DISTRHO_OS_WINDOWS
# include <objbase.h>
#else
# include <signal.h>
# include <unistd.h>
#endif
@@ -86,6 +88,10 @@ 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;
@@ -234,20 +240,26 @@ public:

std::fflush(stdout);

#if DISTRHO_PLUGIN_HAS_UI
#if DISTRHO_PLUGIN_HAS_UI
String title(fPlugin.getMaker());

if (title.isNotEmpty())
title += ": ";

if (const char* const name = jackbridge_get_client_name(fClient))
fUI.setWindowTitle(name);
title += name;
else
fUI.setWindowTitle(fPlugin.getName());
title += fPlugin.getName();

fUI.setWindowTitle(title);
fUI.exec(this);
#else
#else
while (! gCloseSignalReceived)
d_sleep(1);

// unused
(void)winId;
#endif
#endif
}

~PluginJack()
@@ -955,6 +967,11 @@ int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO;

#ifdef DISTRHO_OS_WINDOWS
OleInitialize(nullptr);
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
#endif

initSignalHandler();

#ifndef STATIC_BUILD
@@ -965,15 +982,11 @@ int main(int argc, char* argv[])
String tmpPath(getBinaryFilename());
tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP));
#if defined(DISTRHO_OS_MAC)
if (tmpPath.endsWith("/MacOS"))
if (tmpPath.endsWith("/Contents/MacOS"))
{
tmpPath.truncate(tmpPath.rfind('/'));
if (tmpPath.endsWith("/Contents"))
{
tmpPath.truncate(tmpPath.rfind('/'));
bundlePath = tmpPath;
d_nextBundlePath = bundlePath.buffer();
}
tmpPath.truncate(tmpPath.length() - 15);
bundlePath = tmpPath;
d_nextBundlePath = bundlePath.buffer();
}
#else
#ifdef DISTRHO_OS_WINDOWS
@@ -990,6 +1003,11 @@ int main(int argc, char* argv[])
}
#endif

#ifdef DPF_USING_LD_LINUX_WEBVIEW
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
return dpf_webview_start(argc, argv);
#endif

if (argc == 2 && std::strcmp(argv[1], "selftest") == 0)
{
#ifdef DPF_RUNTIME_TESTING
@@ -1027,6 +1045,10 @@ int main(int argc, char* argv[])
}

hasConsole = true;

// tell windows to output console output as utf-8
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
}
#endif

@@ -1155,6 +1177,11 @@ int main(int argc, char* argv[])
}
#endif

#ifdef DISTRHO_OS_WINDOWS
CoUninitialize();
OleUninitialize();
#endif

return 0;
}



+ 13
- 25
dpf/distrho/src/DistrhoPluginLV2.cpp View File

@@ -459,7 +459,7 @@ public:

if (fLastPositionData.barBeat >= 0.0f)
{
const double rest = std::fmod(fLastPositionData.barBeat, 1.0f);
const double rest = std::fmod(fLastPositionData.barBeat, 1.0);
fTimePosition.bbt.beat = std::round(fLastPositionData.barBeat - rest + 1.0);
fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
}
@@ -590,7 +590,7 @@ public:

const LV2_Atom* property = nullptr;
const LV2_Atom* value = nullptr;
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr);
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, 0);

if (property != nullptr && property->type == fURIDs.atomURID &&
value != nullptr && (value->type == fURIDs.atomPath || value->type == fURIDs.atomString))
@@ -1122,7 +1122,7 @@ public:

const LV2_Atom* property = nullptr;
const LV2_Atom* value = nullptr;
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, nullptr);
lv2_atom_object_get(object, fURIDs.patchProperty, &property, fURIDs.patchValue, &value, 0);
DISTRHO_SAFE_ASSERT_RETURN(property != nullptr, LV2_WORKER_ERR_UNKNOWN);
DISTRHO_SAFE_ASSERT_RETURN(property->type == fURIDs.atomURID, LV2_WORKER_ERR_UNKNOWN);
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr, LV2_WORKER_ERR_UNKNOWN);
@@ -1353,38 +1353,26 @@ private:

// save this key if necessary
if (fPlugin.wantStateKey(key))
updateInternalState(key, newValue, false);
{
const String dkey(key);
fStateMap[dkey] = newValue;
}
}

bool updateState(const char* const key, const char* const newValue)
{
fPlugin.setState(key, newValue);
return updateInternalState(key, newValue, true);
}

bool updateInternalState(const char* const key, const char* const newValue, const bool sendToUI)
{
// key must already exist
for (StringToStringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
{
const String& dkey(it->first);

if (dkey == key)
if (fPlugin.getStateKey(i) == key)
{
it->second = newValue;
const String dkey(key);
fStateMap[dkey] = newValue;

if (sendToUI)
{
for (uint32_t i=0, count=fPlugin.getStateCount(); i < count; ++i)
{
if (fPlugin.getStateKey(i) == key)
{
if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
fNeededUiSends[i] = true;
break;
}
}
}
if ((fPlugin.getStateHints(i) & kStateIsOnlyForDSP) == 0x0)
fNeededUiSends[i] = true;

return true;
}


+ 10
- 8
dpf/distrho/src/DistrhoPluginLV2export.cpp View File

@@ -74,12 +74,12 @@
# define DISTRHO_PLUGIN_USES_CUSTOM_MODGUI 0
#endif

#if DISTRHO_PLUGIN_HAS_EMBED_UI
# if DISTRHO_OS_HAIKU
#if DISTRHO_PLUGIN_HAS_UI
# if defined(DISTRHO_OS_HAIKU)
# define DISTRHO_LV2_UI_TYPE "BeUI"
# elif DISTRHO_OS_MAC
# elif defined(DISTRHO_OS_MAC)
# define DISTRHO_LV2_UI_TYPE "CocoaUI"
# elif DISTRHO_OS_WINDOWS
# elif defined(DISTRHO_OS_WINDOWS)
# define DISTRHO_LV2_UI_TYPE "WindowsUI"
# else
# define DISTRHO_LV2_UI_TYPE "X11UI"
@@ -155,7 +155,7 @@ static constexpr const char* const lv2ManifestUiExtensionData[] = {
};

static constexpr const char* const lv2ManifestUiOptionalFeatures[] = {
#if DISTRHO_PLUGIN_HAS_EMBED_UI
#if DISTRHO_PLUGIN_HAS_UI
#if !DISTRHO_UI_USER_RESIZABLE
"ui:noUserResize",
#endif
@@ -1003,8 +1003,10 @@ void lv2_generate_ttl(const char* const basename)
{
const String license(plugin.getLicense());

if (license.isEmpty())
{}
// Using URL as license
if (license.contains("://"))
else if (license.contains("://"))
{
pluginString += " doap:license <" + license + "> ;\n\n";
}
@@ -1253,7 +1255,7 @@ void lv2_generate_ttl(const char* const basename)
std::cout << " done!" << std::endl;
}

#if DISTRHO_PLUGIN_USES_MODGUI && DISTRHO_PLUGIN_HAS_EMBED_UI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI
#if DISTRHO_PLUGIN_USES_MODGUI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI
{
std::cout << "Writing modgui.ttl..."; std::cout.flush();
std::fstream modguiFile("modgui.ttl", std::ios::out);
@@ -1548,7 +1550,7 @@ void lv2_generate_ttl(const char* const basename)
stylesheetFile.close();
std::cout << " done!" << std::endl;
}
#endif // DISTRHO_PLUGIN_USES_MODGUI && DISTRHO_PLUGIN_HAS_EMBED_UI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI
#endif // DISTRHO_PLUGIN_USES_MODGUI && !DISTRHO_PLUGIN_USES_CUSTOM_MODGUI

// ---------------------------------------------



+ 4
- 14
dpf/distrho/src/DistrhoPluginVST.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -23,17 +23,7 @@
#include <algorithm>
#include <cmath>

#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI
# undef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif

#if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# undef DISTRHO_PLUGIN_HAS_UI
# define DISTRHO_PLUGIN_HAS_UI 0
#endif

#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_HAS_UI
# include "Base.hpp"
#endif

@@ -45,7 +35,7 @@

// --------------------------------------------------------------------------------------------------------------------

#ifdef DISTRHO_PROPER_CPP11_SUPPORT
#if defined(DISTRHO_PROPER_CPP11_SUPPORT) || defined(DISTRHO_OS_MAC)
# include <atomic>
#else
// quick and dirty std::atomic replacement for the things we need
@@ -224,7 +214,7 @@ void snprintf_u32_utf16(int16_t* const dst, const uint32_t value, const size_t s
return snprintf_utf16_t<uint32_t>(dst, value, "%u", size);
}

#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_HAS_UI
// --------------------------------------------------------------------------------------------------------------------
// translate a vstgui-based key character and code to matching values used by DPF



+ 29
- 37
dpf/distrho/src/DistrhoPluginVST2.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -178,10 +178,8 @@ public:
nullptr, // TODO file request
d_nextBundlePath,
plugin->getInstancePointer(),
scaleFactor)
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
, fKeyboardModifiers(0)
#endif
scaleFactor),
fKeyboardModifiers(0)
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
, fNotesRingBuffer()
#endif
@@ -242,7 +240,6 @@ public:
}
#endif

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
int handlePluginKeyEvent(const bool down, const int32_t index, const intptr_t value)
{
d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value);
@@ -281,7 +278,6 @@ public:
value >= 0 ? static_cast<uint>(value) : 0,
fKeyboardModifiers) ? 1 : 0;
}
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI

// ----------------------------------------------------------------------------------------------------------------

@@ -347,9 +343,7 @@ private:

// Plugin UI
UIExporter fUI;
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uint16_t fKeyboardModifiers;
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
RingBufferControl<SmallStackBuffer> fNotesRingBuffer;
#endif
@@ -429,7 +423,7 @@ public:
memset(parameterChecks, 0, sizeof(bool)*parameterCount);
}

#if DISTRHO_OS_MAC
#ifdef DISTRHO_OS_MAC
#ifdef __LP64__
fUsingNsView = true;
#else
@@ -602,10 +596,10 @@ public:
{
double scaleFactor = fLastScaleFactor;
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT)
fVstRect.right = DISTRHO_UI_DEFAULT_WIDTH;
fVstRect.bottom = DISTRHO_UI_DEFAULT_HEIGHT;
if (d_isZero(scaleFactor))
scaleFactor = 1.0;
fVstRect.right = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor;
fVstRect.bottom = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor;
#else
UIExporter tmpUI(nullptr, 0, fPlugin.getSampleRate(),
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath,
@@ -627,7 +621,7 @@ public:
delete fVstUI; // for hosts which don't pair create/destroy calls (Minihost Modular)
fVstUI = nullptr;

#if DISTRHO_OS_MAC
#ifdef DISTRHO_OS_MAC
if (! fUsingNsView)
{
d_stderr("Host doesn't support hasCockosViewAsConfig, cannot use UI");
@@ -678,7 +672,6 @@ public:
fVstUI->idle();
break;

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
case VST_EFFECT_OPCODE_3B: // key down
if (fVstUI != nullptr)
return fVstUI->handlePluginKeyEvent(true, index, value);
@@ -688,7 +681,6 @@ public:
if (fVstUI != nullptr)
return fVstUI->handlePluginKeyEvent(false, index, value);
break;
#endif
#endif // DISTRHO_PLUGIN_HAS_UI

#if DISTRHO_PLUGIN_WANT_STATE
@@ -917,7 +909,7 @@ public:
case VST_EFFECT_OPCODE_SUPPORTS:
if (const char* const canDo = (const char*)ptr)
{
#if DISTRHO_OS_MAC && DISTRHO_PLUGIN_HAS_UI
#if defined(DISTRHO_OS_MAC) && DISTRHO_PLUGIN_HAS_UI
if (std::strcmp(canDo, "hasCockosViewAsConfig") == 0)
{
fUsingNsView = true;
@@ -1084,7 +1076,7 @@ public:
if (fMidiEventCount != kMaxMidiEvents && fNotesRingBuffer.isDataAvailableForReading())
{
uint8_t midiData[3];
uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount-1].frame : 0;
const uint32_t frame = fMidiEventCount != 0 ? fMidiEvents[fMidiEventCount - 1].frame : 0;

while (fNotesRingBuffer.isDataAvailableForReading())
{
@@ -1140,7 +1132,7 @@ private:
UIVst* fVstUI;
vst_rect fVstRect;
float fLastScaleFactor;
#if DISTRHO_OS_MAC
#ifdef DISTRHO_OS_MAC
bool fUsingNsView;
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
@@ -1286,22 +1278,11 @@ private:
fPlugin.setState(key, value);

// check if we want to save this key
if (! fPlugin.wantStateKey(key))
return;

// check if key already exists
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
if (fPlugin.wantStateKey(key))
{
const String& dkey(it->first);

if (dkey == key)
{
it->second = value;
return;
}
const String dkey(key);
fStateMap[dkey] = value;
}

d_stderr("Failed to find plugin state with key \"%s\"", key);
}
#endif
};
@@ -1607,11 +1588,7 @@ static void VST_FUNCTION_INTERFACE vst_processReplacingCallback(vst_effect* cons
END_NAMESPACE_DISTRHO

DISTRHO_PLUGIN_EXPORT
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WASM) || defined(DISTRHO_OS_WINDOWS)
const vst_effect* VSTPluginMain(vst_host_callback audioMaster);
#else
const vst_effect* VSTPluginMain(vst_host_callback audioMaster) asm ("main");
#endif
const vst_effect* VSTPluginMain(vst_host_callback);

DISTRHO_PLUGIN_EXPORT
const vst_effect* VSTPluginMain(const vst_host_callback audioMaster)
@@ -1735,4 +1712,19 @@ 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)
DISTRHO_PLUGIN_EXPORT
const vst_effect* VSTPluginMainCompat(vst_host_callback) asm ("main");

DISTRHO_PLUGIN_EXPORT
const vst_effect* VSTPluginMainCompat(const vst_host_callback audioMaster)
{
// protect main symbol against running as executable
if (reinterpret_cast<uintptr_t>(audioMaster) < 0xff)
return nullptr;

return VSTPluginMain(audioMaster);
}
#endif

// --------------------------------------------------------------------------------------------------------------------

+ 33
- 34
dpf/distrho/src/DistrhoPluginVST3.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -92,11 +92,17 @@ static constexpr const uint32_t dpf_id_view = d_cconst('v', 'i', 'e', 'w');
// --------------------------------------------------------------------------------------------------------------------
// plugin specific uids (values are filled in during plugin init)

static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, 0 };
static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, 0 };
static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, 0 };
static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, 0 };
static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, 0 };
#if defined(DISTRHO_PLUGIN_BRAND_ID) && !defined(DPF_VST3_DONT_USE_BRAND_ID)
static constexpr const uint32_t dpf_id_brand = d_cconst(STRINGIFY(DISTRHO_PLUGIN_BRAND_ID));
#else
static constexpr const uint32_t dpf_id_brand = 0;
#endif

static dpf_tuid dpf_tuid_class = { dpf_id_entry, dpf_id_clas, 0, dpf_id_brand };
static dpf_tuid dpf_tuid_component = { dpf_id_entry, dpf_id_comp, 0, dpf_id_brand };
static dpf_tuid dpf_tuid_controller = { dpf_id_entry, dpf_id_ctrl, 0, dpf_id_brand };
static dpf_tuid dpf_tuid_processor = { dpf_id_entry, dpf_id_proc, 0, dpf_id_brand };
static dpf_tuid dpf_tuid_view = { dpf_id_entry, dpf_id_view, 0, dpf_id_brand };

// --------------------------------------------------------------------------------------------------------------------
// Utility functions
@@ -1180,7 +1186,7 @@ public:
// Update current state
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& key(cit->first);
fStateMap[key] = fPlugin.getStateValue(key);
}
#endif
@@ -1204,8 +1210,8 @@ public:

for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& value = cit->second;
const String& key(cit->first);
const String& value(cit->second);

// join key and value
String tmpStr;
@@ -1419,7 +1425,7 @@ public:

fTimePosition.bbt.valid = true;
fTimePosition.bbt.bar = static_cast<int32_t>(ppqPos) / ppqPerBar + 1;
fTimePosition.bbt.beat = d_roundToIntPositive<int32_t>(barBeats - rest) + 1;
fTimePosition.bbt.beat = static_cast<int32_t>(barBeats - rest) + 1;
fTimePosition.bbt.tick = rest * fTimePosition.bbt.ticksPerBeat;
fTimePosition.bbt.beatsPerBar = ctx->time_sig_numerator;
fTimePosition.bbt.beatType = ctx->time_sig_denom;
@@ -1968,24 +1974,24 @@ public:
{
#if DPF_VST3_USES_SEPARATE_CONTROLLER
case kVst3InternalParameterBufferSize:
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_BUFFER_SIZE));
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_BUFFER_SIZE));
case kVst3InternalParameterSampleRate:
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_SAMPLE_RATE));
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_SAMPLE_RATE));
#endif
#if DISTRHO_PLUGIN_WANT_LATENCY
case kVst3InternalParameterLatency:
return std::max(0.0, std::min(1.0, plain / DPF_VST3_MAX_LATENCY));
return std::max<double>(0.0, std::min<double>(1.0, plain / DPF_VST3_MAX_LATENCY));
#endif
#if DISTRHO_PLUGIN_WANT_PROGRAMS
case kVst3InternalParameterProgram:
return std::max(0.0, std::min(1.0, plain / fProgramCountMinusOne));
return std::max<double>(0.0, std::min<double>(1.0, plain / fProgramCountMinusOne));
#endif
}
#endif

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
if (rindex < kVst3InternalParameterCount)
return std::max(0.0, std::min(1.0, plain / 127));
return std::max<double>(0.0, std::min<double>(1.0, plain / 127));
#endif

const uint32_t index = static_cast<uint32_t>(rindex - kVst3InternalParameterCount);
@@ -2194,7 +2200,7 @@ public:
// Update current state from plugin side
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& key(cit->first);
fStateMap[key] = fPlugin.getStateValue(key);
}
#endif
@@ -2203,8 +2209,8 @@ public:
// Set state
for (StringMap::const_iterator cit=fStateMap.begin(), cite=fStateMap.end(); cit != cite; ++cit)
{
const String& key = cit->first;
const String& value = cit->second;
const String& key(cit->first);
const String& value(cit->second);

sendStateSetToUI(key, value);
}
@@ -2399,20 +2405,8 @@ public:
// save this key as needed
if (fPlugin.wantStateKey(key))
{
for (StringMap::iterator it=fStateMap.begin(), ite=fStateMap.end(); it != ite; ++it)
{
const String& dkey(it->first);

if (dkey == key)
{
it->second = value;
std::free(key16);
std::free(value16);
return V3_OK;
}
}

d_stderr("Failed to find plugin state with key \"%s\"", key);
const String dkey(key);
fStateMap[dkey] = value;
}

std::free(key16);
@@ -3103,7 +3097,7 @@ private:
event.midi_cc_out.cc_number = data[1];
event.midi_cc_out.value = data[2];
if (midiEvent.size == 4)
event.midi_cc_out.value2 = midiEvent.size == 4;
event.midi_cc_out.value2 = data[3];
break;
/* TODO how do we deal with program changes??
case 0xC0:
@@ -4577,8 +4571,13 @@ static const char* getPluginCategories()
categories = DISTRHO_PLUGIN_VST3_CATEGORIES;
#elif DISTRHO_PLUGIN_IS_SYNTH
categories = "Instrument";
#else
categories = "Fx";
#endif
firstInit = false;

// An empty category is considered invalid in Cubase
DISTRHO_SAFE_ASSERT(categories.isNotEmpty());
}

return categories.buffer();
@@ -4864,7 +4863,7 @@ struct dpf_factory : v3_plugin_factory_cpp {
DISTRHO_NAMESPACE::strncpy_utf16(info->name, sPlugin->getName(), ARRAY_SIZE(info->name));
DISTRHO_NAMESPACE::strncpy_utf16(info->vendor, sPlugin->getMaker(), ARRAY_SIZE(info->vendor));
DISTRHO_NAMESPACE::strncpy_utf16(info->version, getPluginVersion(), ARRAY_SIZE(info->version));
DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "Travesty 3.7.4", ARRAY_SIZE(info->sdk_version));
DISTRHO_NAMESPACE::strncpy_utf16(info->sdk_version, "VST 3.7.4", ARRAY_SIZE(info->sdk_version));

if (idx == 0)
{


+ 243
- 107
dpf/distrho/src/DistrhoUI.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2023 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -15,8 +15,8 @@
*/

#include "DistrhoDetails.hpp"
#include "DistrhoPluginUtils.hpp"
#include "src/DistrhoPluginChecks.h"
#include "src/DistrhoDefines.h"

#include <cstddef>

@@ -26,6 +26,15 @@
# include <stdint.h>
#endif

#if defined(DISTRHO_OS_WINDOWS)
# include <winsock2.h>
# include <windows.h>
#elif defined(HAVE_X11)
# define Window X11Window
# include <X11/Xresource.h>
# undef Window
#endif

#if DISTRHO_UI_FILE_BROWSER && !defined(DISTRHO_OS_MAC)
# define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION
# define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION)
@@ -50,35 +59,29 @@
START_NAMESPACE_DISTRHO
# include "../extra/FileBrowserDialogImpl.hpp"
END_NAMESPACE_DISTRHO
# define Window X11Window
# include "../extra/FileBrowserDialogImpl.cpp"
# undef Window
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# if defined(DISTRHO_OS_WINDOWS)
# include <winsock2.h>
# include <windows.h>
# elif defined(HAVE_X11)
# include <X11/Xresource.h>
# endif
#else
# include "src/TopLevelWidgetPrivateData.hpp"
# include "src/WindowPrivateData.hpp"
#if DISTRHO_UI_WEB_VIEW && !defined(DISTRHO_OS_MAC)
# define DISTRHO_WEB_VIEW_HPP_INCLUDED
# define WEB_VIEW_NAMESPACE DISTRHO_NAMESPACE
# define WEB_VIEW_DISTRHO_NAMESPACE
START_NAMESPACE_DISTRHO
# include "../extra/WebViewImpl.hpp"
END_NAMESPACE_DISTRHO
# define Window X11Window
# include "../extra/WebViewImpl.cpp"
# undef Window
#endif

#include "src/TopLevelWidgetPrivateData.hpp"
#include "src/WindowPrivateData.hpp"
#include "DistrhoUIPrivateData.hpp"

START_NAMESPACE_DISTRHO

/* ------------------------------------------------------------------------------------------------------------
* Static data, see DistrhoUIInternal.hpp */

const char* g_nextBundlePath = nullptr;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uintptr_t g_nextWindowId = 0;
double g_nextScaleFactor = 1.0;
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/* ------------------------------------------------------------------------------------------------------------
* get global scale factor */

@@ -91,23 +94,23 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
return std::max(1.0, std::atof(scale));

#if defined(DISTRHO_OS_WINDOWS)
#if defined(DISTRHO_OS_WINDOWS)
if (const HMODULE Shcore = LoadLibraryA("Shcore.dll"))
{
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*);
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*);

# if defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-function-type"
# endif
#if defined(__GNUC__) && (__GNUC__ >= 9)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
const PFN_GetProcessDpiAwareness GetProcessDpiAwareness
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness");
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor");
# if defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic pop
# endif
#if defined(__GNUC__) && (__GNUC__ >= 9)
#pragma GCC diagnostic pop
#endif

DWORD dpiAware = 0;
DWORD scaleFactor = 100;
@@ -123,7 +126,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
FreeLibrary(Shcore);
return static_cast<double>(scaleFactor) / 100.0;
}
#elif defined(HAVE_X11)
#elif defined(HAVE_X11)
::Display* const display = XOpenDisplay(nullptr);
DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0);

@@ -154,7 +157,7 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle)

XCloseDisplay(display);
return dpi / 96;
#endif
#endif

return 1.0;

@@ -163,80 +166,167 @@ static double getDesktopScaleFactor(const uintptr_t parentWindowHandle)
}
#endif // !DISTRHO_OS_MAC

#endif

/* ------------------------------------------------------------------------------------------------------------
* UI::PrivateData special handling */

UI::PrivateData* UI::PrivateData::s_nextPrivateData = nullptr;

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
ExternalWindow::PrivateData
#else
PluginWindow&
#endif
UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height, const bool adjustForScaleFactor)
PluginWindow& UI::PrivateData::createNextWindow(UI* const ui, uint width, uint height)
{
UI::PrivateData* const pData = s_nextPrivateData;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
const double scaleFactor = d_isNotZero(pData->scaleFactor) ? pData->scaleFactor : getDesktopScaleFactor(pData->winId);
UI::PrivateData* const uiData = s_nextPrivateData;
const double scaleFactor = d_isNotZero(uiData->scaleFactor) ? uiData->scaleFactor : getDesktopScaleFactor(uiData->winId);

if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0))
if (d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0))
{
width *= scaleFactor;
height *= scaleFactor;
}

pData->window = new PluginWindow(ui, pData->app);
ExternalWindow::PrivateData ewData;
ewData.parentWindowHandle = pData->winId;
ewData.width = width;
ewData.height = height;
ewData.scaleFactor = scaleFactor;
ewData.title = DISTRHO_PLUGIN_NAME;
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE;
return ewData;
#else
const double scaleFactor = pData->scaleFactor;
d_stdout("createNextWindow %u %u %f", width, height, scaleFactor);
uiData->window = new PluginWindow(ui, uiData->app, uiData->winId, width, height, scaleFactor);

if (adjustForScaleFactor && d_isNotZero(scaleFactor) && d_isNotEqual(scaleFactor, 1.0))
if (uiData->callbacksPtr != nullptr)
{
width *= scaleFactor;
height *= scaleFactor;
}
#if DISTRHO_UI_USE_WEB_VIEW
String path;
if (uiData->bundlePath != nullptr)
{
path = getResourcePath(uiData->bundlePath);
}
else
{
path = getBinaryFilename();
path.truncate(path.rfind(DISTRHO_OS_SEP));
path += "/resources";
}

pData->window = new PluginWindow(ui, pData->app, pData->winId, width, height, scaleFactor);
// TODO convert win32 paths to web
// TODO encode paths (e.g. %20 for space)

WebViewOptions opts;
opts.initialJS = ""
"editParameter = function(index, started){ postMessage('editparam '+index+' '+(started ? 1 : 0)) };"
"setParameterValue = function(index, value){ postMessage('setparam '+index+' '+value) };"
#if DISTRHO_PLUGIN_WANT_STATE
"setState = function(key, value){ postMessage('setstate '+key+' '+value) };"
"requestStateFile = function(key){ postMessage('reqstatefile '+key) };"
#endif
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
"sendNote = function(channel, note, velocity){ postMessage('sendnote '+channel+' '+note+' '+velocity) };"
#endif
;
opts.callback = webViewMessageCallback;
opts.callbackPtr = uiData;
uiData->webview = webViewCreate("file://" + path + "/index.html", uiData->winId, width, height, scaleFactor, opts);
#endif
}
// If there are no callbacks, this is most likely a temporary window, so ignore idle callbacks
if (pData->callbacksPtr == nullptr)
pData->window->setIgnoreIdleCallbacks();
else
{
uiData->window->setIgnoreIdleCallbacks();
}

return uiData->window.getObject();
}

return pData->window.getObject();
#if DISTRHO_UI_USE_WEB_VIEW
void UI::PrivateData::webViewMessageCallback(void* const arg, char* const msg)
{
UI::PrivateData* const uiData = static_cast<UI::PrivateData*>(arg);

if (std::strncmp(msg, "setparam ", 9) == 0)
{
const char* const strindex = msg + 9;
char* strvalue = nullptr;
const ulong index = std::strtoul(strindex, &strvalue, 10);
DISTRHO_SAFE_ASSERT_RETURN(strvalue != nullptr && strindex != strvalue,);

float value;
{
const ScopedSafeLocale ssl;
value = std::atof(strvalue);
}
uiData->setParamCallback(index + uiData->parameterOffset, value);
return;
}

if (std::strncmp(msg, "editparam ", 10) == 0)
{
const char* const strindex = msg + 10;
char* strvalue = nullptr;
const ulong index = std::strtoul(strindex, &strvalue, 10);
DISTRHO_SAFE_ASSERT_RETURN(strvalue != nullptr && strindex != strvalue,);

const bool started = strvalue[0] != '0';
uiData->editParamCallback(index + uiData->parameterOffset, started);
return;
}

#if DISTRHO_PLUGIN_WANT_STATE
if (std::strncmp(msg, "setstate ", 9) == 0)
{
char* const key = msg + 9;
char* const sep = std::strchr(key, ' ');
DISTRHO_SAFE_ASSERT_RETURN(sep != nullptr,);
*sep = 0;
char* const value = sep + 1;

uiData->setStateCallback(key, value);
return;
}

if (std::strncmp(msg, "reqstatefile ", 13) == 0)
{
const char* const key = msg + 13;
uiData->fileRequestCallback(key);
return;
}
#endif

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
if (std::strncmp(msg, "sendnote ", 9) == 0)
{
const char* const strchannel = msg + 9;
char* strnote = nullptr;
char* strvelocity = nullptr;
char* end = nullptr;

const ulong channel = std::strtoul(strchannel, &strnote, 10);
DISTRHO_SAFE_ASSERT_RETURN(strnote != nullptr && strchannel != strnote,);

const ulong note = std::strtoul(strnote, &strvelocity, 10);
DISTRHO_SAFE_ASSERT_RETURN(strvelocity != nullptr && strchannel != strvelocity,);

const ulong velocity = std::strtoul(strvelocity, &end, 10);
DISTRHO_SAFE_ASSERT_RETURN(end != nullptr && strvelocity != end,);

uiData->sendNoteCallback(channel, note, velocity);
return;
}
#endif

d_stderr("UI received unknown message '%s'", msg);
}
#endif

/* ------------------------------------------------------------------------------------------------------------
* UI */

UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetAsMinimumSize)
: UIWidget(UI::PrivateData::createNextWindow(this,
// width
#ifdef DISTRHO_UI_DEFAULT_WIDTH
width == 0 ? DISTRHO_UI_DEFAULT_WIDTH :
#endif
width,
// height
#ifdef DISTRHO_UI_DEFAULT_HEIGHT
height == 0 ? DISTRHO_UI_DEFAULT_HEIGHT :
#endif
height,
#ifdef DISTRHO_UI_DEFAULT_WIDTH
width == 0
#else
false
#endif
height
)),
uiData(UI::PrivateData::s_nextPrivateData)
{
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
if (width != 0 && height != 0)
{
Widget::setSize(width, height);
@@ -250,14 +340,14 @@ UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetA
Widget::setSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT);
}
#endif
#else
// unused
(void)automaticallyScaleAndSetAsMinimumSize;
#endif
}

UI::~UI()
{
#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
webViewDestroy(uiData->webview);
#endif
}

/* ------------------------------------------------------------------------------------------------------------
@@ -265,15 +355,11 @@ UI::~UI()

bool UI::isResizable() const noexcept
{
#if DISTRHO_UI_USER_RESIZABLE
# if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
return true;
# else
#if DISTRHO_UI_USER_RESIZABLE
return uiData->window->isResizable();
# endif
#else
#else
return false;
#endif
#endif
}

uint UI::getBackgroundColor() const noexcept
@@ -344,33 +430,94 @@ void* UI::getPluginInstancePointer() const noexcept
}
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/* ------------------------------------------------------------------------------------------------------------
* External UI helpers (static calls) */
* DSP/Plugin Callbacks */

const char* UI::getNextBundlePath() noexcept
void UI::parameterChanged(const uint32_t index, const float value)
{
return g_nextBundlePath;
#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
{
char msg[128];
{
const ScopedSafeLocale ssl;
std::snprintf(msg, sizeof(msg) - 1,
"typeof(parameterChanged) === 'function' && parameterChanged(%u,%f)", index, value);
}
webViewEvaluateJS(uiData->webview, msg);
}
#else
// unused
(void)index;
(void)value;
#endif
}

double UI::getNextScaleFactor() noexcept
#if DISTRHO_PLUGIN_WANT_PROGRAMS
void UI::programLoaded(const uint32_t index)
{
return g_nextScaleFactor;
#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
{
char msg[128];
std::snprintf(msg, sizeof(msg) - 1,
"typeof(programLoaded) === 'function' && programLoaded(%u)", index);
webViewEvaluateJS(uiData->webview, msg);
}
#else
// unused
(void)index;
#endif
}
#endif

# if DISTRHO_PLUGIN_HAS_EMBED_UI
uintptr_t UI::getNextWindowId() noexcept
#if DISTRHO_PLUGIN_WANT_STATE
void UI::stateChanged(const char* const key, const char* const value)
{
return g_nextWindowId;
#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
{
const size_t keylen = std::strlen(key);
const size_t valuelen = std::strlen(value);
const size_t msglen = keylen + valuelen + 60;
if (char* const msg = static_cast<char*>(std::malloc(msglen)))
{
// TODO escape \\'
std::snprintf(msg, msglen - 1,
"typeof(stateChanged) === 'function' && stateChanged('%s','%s')", key, value);
msg[msglen - 1] = '\0';
webViewEvaluateJS(uiData->webview, msg);
std::free(msg);
}
}
#else
// unused
(void)key;
(void)value;
#endif
}
# endif
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#endif

/* ------------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks (optional) */

void UI::sampleRateChanged(double)
void UI::sampleRateChanged(const double sampleRate)
{
#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
{
char msg[128];
{
const ScopedSafeLocale ssl;
std::snprintf(msg, sizeof(msg) - 1,
"typeof(sampleRateChanged) === 'function' && sampleRateChanged(%f)", sampleRate);
}
webViewEvaluateJS(uiData->webview, msg);
}
#else
// unused
(void)sampleRate;
#endif
}

/* ------------------------------------------------------------------------------------------------------------
@@ -380,7 +527,6 @@ void UI::uiScaleFactorChanged(double)
{
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
std::vector<DGL_NAMESPACE::ClipboardDataOffer> UI::getClipboardDataOfferTypes()
{
return uiData->window->getClipboardDataOfferTypes();
@@ -409,7 +555,6 @@ void UI::uiReshape(const uint width, const uint height)
// NOTE this must be the same as Window::onReshape
pData->fallbackOnResize(width, height);
}
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI

#if DISTRHO_UI_FILE_BROWSER
void UI::uiFileBrowserSelected(const char*)
@@ -420,19 +565,11 @@ void UI::uiFileBrowserSelected(const char*)
/* ------------------------------------------------------------------------------------------------------------
* UI Resize Handling, internal */

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
void UI::sizeChanged(const uint width, const uint height)
{
UIWidget::sizeChanged(width, height);

uiData->setSizeCallback(width, height);
}
#else
void UI::onResize(const ResizeEvent& ev)
{
UIWidget::onResize(ev);

#if !(defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP))
#if ! DISTRHO_UI_USES_SIZE_REQUEST
if (uiData->initializing)
return;

@@ -442,10 +579,10 @@ void UI::onResize(const ResizeEvent& ev)
#endif
}

// NOTE: only used for VST3 and CLAP
// NOTE: only used for CLAP and VST3
void UI::requestSizeChange(const uint width, const uint height)
{
#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
#if DISTRHO_UI_USES_SIZE_REQUEST
if (uiData->initializing)
uiData->window->setSizeFromHost(width, height);
else
@@ -456,7 +593,6 @@ void UI::requestSizeChange(const uint width, const uint height)
(void)height;
#endif
}
#endif

// -----------------------------------------------------------------------------------------------------------



+ 502
- 0
dpf/distrho/src/DistrhoUIAU.mm View File

@@ -0,0 +1,502 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-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 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 "DistrhoUIInternal.hpp"

#define Point AudioUnitPoint
#define Size AudioUnitSize

#include <AudioUnit/AudioUnit.h>
#include <AudioUnit/AUCocoaUIView.h>
#include <Cocoa/Cocoa.h>

#undef Point
#undef Size

#ifndef DISTRHO_PLUGIN_BRAND_ID
# error DISTRHO_PLUGIN_BRAND_ID undefined!
#endif

#ifndef DISTRHO_PLUGIN_UNIQUE_ID
# error DISTRHO_PLUGIN_UNIQUE_ID undefined!
#endif

START_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------

#if ! DISTRHO_PLUGIN_WANT_STATE
static constexpr const setStateFunc setStateCallback = nullptr;
#endif
#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
static constexpr const sendNoteFunc sendNoteCallback = nullptr;
#endif

// unsupported in AU
static constexpr const fileRequestFunc fileRequestCallback = nullptr;

// --------------------------------------------------------------------------------------------------------------------
// Static data, see DistrhoPlugin.cpp

extern double d_nextSampleRate;
extern const char* d_nextBundlePath;

// --------------------------------------------------------------------------------------------------------------------

class DPF_UI_AU
{
public:
DPF_UI_AU(const AudioUnit component,
NSView* const view,
const double sampleRate,
void* const instancePointer)
: fComponent(component),
fParentView(view),
fTimerRef(nullptr),
fUI(this,
reinterpret_cast<uintptr_t>(view),
sampleRate,
editParameterCallback,
setParameterCallback,
setStateCallback,
sendNoteCallback,
setSizeCallback,
fileRequestCallback,
d_nextBundlePath,
instancePointer)
{
#if DISTRHO_PLUGIN_WANT_STATE
// create state keys
{
CFArrayRef keysRef = nullptr;
UInt32 dataSize = sizeof(CFArrayRef);
if (AudioUnitGetProperty(fComponent, 'DPFl', kAudioUnitScope_Global, 0, &keysRef, &dataSize) == noErr
&& dataSize == sizeof(CFArrayRef))
{
const CFIndex numStates = CFArrayGetCount(keysRef);
char* key = nullptr;
CFIndex keyLen = -1;

fStateKeys.resize(numStates);

for (CFIndex i=0; i<numStates; ++i)
{
const CFStringRef keyRef = static_cast<CFStringRef>(CFArrayGetValueAtIndex(keysRef, i));
DISTRHO_SAFE_ASSERT_BREAK(CFGetTypeID(keyRef) == CFStringGetTypeID());

const CFIndex keyRefLen = CFStringGetLength(keyRef);
if (keyLen < keyRefLen)
{
keyLen = keyRefLen;
key = static_cast<char*>(std::realloc(key, keyLen + 1));
}
DISTRHO_SAFE_ASSERT_BREAK(CFStringGetCString(keyRef, key, keyLen + 1, kCFStringEncodingASCII));

fStateKeys[i] = key;
}

CFRelease(keysRef);
std::free(key);
}
}
#endif

// setup idle timer
constexpr const CFTimeInterval interval = 60 * 0.0001;

CFRunLoopTimerContext context = {};
context.info = this;
fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0,
_idleCallback, &context);
DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,);

CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes);

AudioUnitAddPropertyListener(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this);
AudioUnitAddPropertyListener(fComponent, 'DPFp', auPropertyChangedCallback, this);
#if DISTRHO_PLUGIN_WANT_PROGRAMS
AudioUnitAddPropertyListener(fComponent, 'DPFo', auPropertyChangedCallback, this);
#endif
#if DISTRHO_PLUGIN_WANT_STATE
AudioUnitAddPropertyListener(fComponent, 'DPFs', auPropertyChangedCallback, this);
#endif
}

~DPF_UI_AU()
{
AudioUnitRemovePropertyListenerWithUserData(fComponent, kAudioUnitProperty_SampleRate, auPropertyChangedCallback, this);
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFp', auPropertyChangedCallback, this);
#if DISTRHO_PLUGIN_WANT_PROGRAMS
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFo', auPropertyChangedCallback, this);
#endif
#if DISTRHO_PLUGIN_WANT_STATE
AudioUnitRemovePropertyListenerWithUserData(fComponent, 'DPFs', auPropertyChangedCallback, this);
#endif

if (fTimerRef != nullptr)
{
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes);
CFRelease(fTimerRef);
}
}

void postSetup()
{
const double scaleFactor = fUI.getScaleFactor();
const NSSize size = NSMakeSize(fUI.getWidth() / scaleFactor, fUI.getHeight() / scaleFactor);

[fParentView setFrameSize:size];
[fParentView setHidden:NO];
}

private:
const AudioUnit fComponent;
NSView* const fParentView;
CFRunLoopTimerRef fTimerRef;

UIExporter fUI;

#if DISTRHO_PLUGIN_WANT_STATE
std::vector<String> fStateKeys;
#endif

// ----------------------------------------------------------------------------------------------------------------
// Idle setup

void idleCallback()
{
fUI.idleFromNativeIdle();
}

static void _idleCallback(CFRunLoopTimerRef, void* const info)
{
static_cast<DPF_UI_AU*>(info)->idleCallback();
}

// ----------------------------------------------------------------------------------------------------------------
// AU callbacks

void auSampleRateChanged(const AudioUnitScope scope)
{
Float64 sampleRate = 0;
UInt32 dataSize = sizeof(Float64);
if (AudioUnitGetProperty(fComponent, kAudioUnitProperty_SampleRate, scope, 0, &sampleRate, &dataSize) == noErr
&& dataSize == sizeof(Float64))
{
fUI.setSampleRate(sampleRate, true);
}
}

void auParameterChanged(const AudioUnitElement elem)
{
float value = 0;
UInt32 dataSize = sizeof(float);
if (AudioUnitGetProperty(fComponent, 'DPFp', kAudioUnitScope_Global, elem, &value, &dataSize) == noErr
&& dataSize == sizeof(float))
{
fUI.parameterChanged(elem, value);
}
}

#if DISTRHO_PLUGIN_WANT_PROGRAMS
void auProgramChanged()
{
uint32_t program = 0;
UInt32 dataSize = sizeof(uint32_t);
if (AudioUnitGetProperty(fComponent, 'DPFo', kAudioUnitScope_Global, 0, &program, &dataSize) == noErr
&& dataSize == sizeof(uint32_t))
{
fUI.programLoaded(program);
}
}
#endif

#if DISTRHO_PLUGIN_WANT_STATE
void auStateChanged(const AudioUnitElement elem)
{
DISTRHO_SAFE_ASSERT_RETURN(elem < fStateKeys.size(),);

CFStringRef valueRef = nullptr;
UInt32 dataSize = sizeof(valueRef);
if (AudioUnitGetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, elem, &valueRef, &dataSize) == noErr
&& dataSize == sizeof(CFStringRef)
&& valueRef != nullptr
&& CFGetTypeID(valueRef) == CFStringGetTypeID())
{
const CFIndex valueLen = CFStringGetLength(valueRef);
char* const value = static_cast<char*>(std::malloc(valueLen + 1));
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(CFStringGetCString(valueRef, value, valueLen + 1, kCFStringEncodingUTF8),);

fUI.stateChanged(fStateKeys[elem], value);

CFRelease(valueRef);
std::free(value);
}
}
#endif

static void auPropertyChangedCallback(void* const userData,
const AudioUnit component,
const AudioUnitPropertyID prop,
const AudioUnitScope scope,
const AudioUnitElement elem)
{
DPF_UI_AU* const self = static_cast<DPF_UI_AU*>(userData);

DISTRHO_SAFE_ASSERT_RETURN(self != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(self->fComponent == component,);

switch (prop)
{
case kAudioUnitProperty_SampleRate:
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Input || scope == kAudioUnitScope_Output, scope,);
self->auSampleRateChanged(scope);
break;
case 'DPFp':
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,);
self->auParameterChanged(elem);
break;
#if DISTRHO_PLUGIN_WANT_PROGRAMS
case 'DPFo':
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,);
self->auProgramChanged();
break;
#endif
#if DISTRHO_PLUGIN_WANT_STATE
case 'DPFs':
DISTRHO_SAFE_ASSERT_UINT_RETURN(scope == kAudioUnitScope_Global, scope,);
self->auStateChanged(elem);
break;
#endif
}
}

// ----------------------------------------------------------------------------------------------------------------
// DPF callbacks

void editParameter(const uint32_t rindex, const bool started) const
{
const uint8_t flag = started ? 1 : 2;
AudioUnitSetProperty(fComponent, 'DPFe', kAudioUnitScope_Global, rindex, &flag, sizeof(uint8_t));

if (! started)
{
const uint8_t cancel = 0;
AudioUnitSetProperty(fComponent, 'DPFe', kAudioUnitScope_Global, rindex, &cancel, sizeof(uint8_t));
}
}

static void editParameterCallback(void* const ptr, const uint32_t rindex, const bool started)
{
static_cast<DPF_UI_AU*>(ptr)->editParameter(rindex, started);
}

// ----------------------------------------------------------------------------------------------------------------

void setParameter(const uint32_t rindex, const float value)
{
AudioUnitSetProperty(fComponent, 'DPFp', kAudioUnitScope_Global, rindex, &value, sizeof(float));
}

static void setParameterCallback(void* const ptr, const uint32_t rindex, const float value)
{
static_cast<DPF_UI_AU*>(ptr)->setParameter(rindex, value);
}

// ----------------------------------------------------------------------------------------------------------------

#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))
{
const uint32_t index = it - fStateKeys.begin();
AudioUnitSetProperty(fComponent, 'DPFs', kAudioUnitScope_Global, index, &valueRef, sizeof(CFStringRef));
CFRelease(valueRef);
}
}

static void setStateCallback(void* const ptr, const char* const key, const char* const value)
{
static_cast<DPF_UI_AU*>(ptr)->setState(key, value);
}
#endif

// ----------------------------------------------------------------------------------------------------------------

#if DISTRHO_PLUGIN_WANT_MIDI_INPUT
void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
{
const uint8_t data[3] = { static_cast<uint8_t>((velocity != 0 ? 0x90 : 0x80) | channel), note, velocity };
AudioUnitSetProperty(fComponent, 'DPFn', kAudioUnitScope_Global, 0, data, sizeof(data));

const uint8_t cancel[3] = { 0, 0, 0 };
AudioUnitSetProperty(fComponent, 'DPFn', kAudioUnitScope_Global, 0, cancel, sizeof(cancel));
}

static void sendNoteCallback(void* const ptr, const uint8_t channel, const uint8_t note, const uint8_t velocity)
{
static_cast<DPF_UI_AU*>(ptr)->sendNote(channel, note, velocity);
}
#endif

// ----------------------------------------------------------------------------------------------------------------

void setSize(const uint width, const uint height)
{
const double scaleFactor = fUI.getScaleFactor();
const NSSize size = NSMakeSize(width / scaleFactor, height / scaleFactor);

[fParentView setFrameSize:size];
}

static void setSizeCallback(void* const ptr, const uint width, const uint height)
{
static_cast<DPF_UI_AU*>(ptr)->setSize(width, height);
}
};

// --------------------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------

#define MACRO_NAME2(a, b, c, d, e, f) a ## b ## c ## d ## e ## f
#define MACRO_NAME(a, b, c, d, e, f) MACRO_NAME2(a, b, c, d, e, f)

// --------------------------------------------------------------------------------------------------------------------

#define COCOA_VIEW_CLASS_NAME \
MACRO_NAME(CocoaView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID)

@interface COCOA_VIEW_CLASS_NAME : NSView
{
@public
DPF_UI_AU* ui;
}
@end

@implementation COCOA_VIEW_CLASS_NAME

- (id) initWithPreferredSize:(NSSize)size
{
ui = nullptr;
self = [super initWithFrame: NSMakeRect(0, 0, size.width, size.height)];
[self setHidden:YES];
return self;
}

- (BOOL) acceptsFirstResponder
{
return YES;
}

- (void) dealloc
{
delete ui;
ui = nullptr;

[super dealloc];
}

- (BOOL) isFlipped
{
return YES;
}

@end

// --------------------------------------------------------------------------------------------------------------------

#define COCOA_UI_CLASS_NAME \
MACRO_NAME(CocoaAUView_, DISTRHO_PLUGIN_AU_TYPE, _, DISTRHO_PLUGIN_UNIQUE_ID, _, DISTRHO_PLUGIN_BRAND_ID)

@interface COCOA_UI_CLASS_NAME : NSObject<AUCocoaUIBase>
{
COCOA_VIEW_CLASS_NAME* view;
}
@end

@implementation COCOA_UI_CLASS_NAME

- (NSString*) description
{
return @DISTRHO_PLUGIN_NAME;
}

- (unsigned) interfaceVersion
{
return 0;
}

- (NSView*) uiViewForAudioUnit:(AudioUnit)component withSize:(NSSize)inPreferredSize
{
Float64 sampleRate = d_nextSampleRate;
void* instancePointer = nullptr;
AudioUnitScope scope;
UInt32 dataSize;

// fetch direct access pointer
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
dataSize = sizeof(void*);
AudioUnitGetProperty(component, 'DPFa', kAudioUnitScope_Global, 0, &instancePointer, &dataSize);
#endif

// fetch current sample rate
#if DISTRHO_PLUGIN_NUM_INPUTS != 0
dataSize = sizeof(Float64);
AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input, 0, &sampleRate, &dataSize);
#elif DISTRHO_PLUGIN_NUM_OUTPUTS != 0
dataSize = sizeof(Float64);
AudioUnitGetProperty(component, kAudioUnitProperty_SampleRate, kAudioUnitScope_Output, 0, &sampleRate, &dataSize);
#endif

#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT)
inPreferredSize = NSMakeSize(DISTRHO_UI_DEFAULT_WIDTH, DISTRHO_UI_DEFAULT_HEIGHT);
#endif

// create view
view = [[[COCOA_VIEW_CLASS_NAME alloc] initWithPreferredSize:inPreferredSize] autorelease];
view->ui = new DPF_UI_AU(component, view, sampleRate, instancePointer);
view->ui->postSetup();

// request data from DSP side
{
const uint16_t magic = 1337;
AudioUnitSetProperty(component, 'DPFi', kAudioUnitScope_Global, 0, &magic, sizeof(uint16_t));
const uint16_t cancel = 0;
AudioUnitSetProperty(component, 'DPFi', kAudioUnitScope_Global, 0, &cancel, sizeof(uint16_t));
}

return view;

// maybe unused
(void)scope;
}

@end

// --------------------------------------------------------------------------------------------------------------------

#undef MACRO_NAME
#undef MACRO_NAME2

// --------------------------------------------------------------------------------------------------------------------

+ 22
- 4
dpf/distrho/src/DistrhoUIDSSI.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -26,11 +26,24 @@

START_NAMESPACE_DISTRHO

// --------------------------------------------------------------------------------------------------------------------

#if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
static constexpr const sendNoteFunc sendNoteCallback = nullptr;
#endif

// -----------------------------------------------------------------------
// unused in DSSI, we only use external and standalone UIs
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

// --------------------------------------------------------------------------------------------------------------------


struct OscData {
lo_address addr;
@@ -98,7 +111,7 @@ class UIDssi : public DGL_NAMESPACE::IdleCallback
public:
UIDssi(const OscData& oscData, const char* const uiTitle, const double sampleRate)
: fUI(this, 0, sampleRate, nullptr,
setParameterCallback, setStateCallback, sendNoteCallback, nullptr, nullptr),
setParameterCallback, setStateCallback, sendNoteCallback, setSizeCallback, fileRequestCallback),
fHostClosed(false),
fOscData(oscData)
{
@@ -378,6 +391,11 @@ int main(int argc, char* argv[])
{
USE_NAMESPACE_DISTRHO

#ifdef DPF_USING_LD_LINUX_WEBVIEW
if (argc >= 2 && std::strcmp(argv[1], "dpf-ld-linux-webview") == 0)
return dpf_webview_start(argc - 1, argv + 1);
#endif

// dummy test mode
if (argc == 1)
{
@@ -395,7 +413,7 @@ int main(int argc, char* argv[])

if (argc != 5)
{
fprintf(stderr, "Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>\n", argv[0]);
d_stderr("Usage: %s <osc-url> <plugin-dll> <plugin-label> <instance-name>", argv[0]);
return 1;
}



+ 24
- 55
dpf/distrho/src/DistrhoUIInternal.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -21,15 +21,6 @@

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// Static data, see DistrhoUI.cpp

extern const char* g_nextBundlePath;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
extern uintptr_t g_nextWindowId;
extern double g_nextScaleFactor;
#endif

// -----------------------------------------------------------------------
// UI exporter class

@@ -79,41 +70,23 @@ public:
uiData->setSizeCallbackFunc = setSizeCall;
uiData->fileRequestCallbackFunc = fileRequestCall;

g_nextBundlePath = bundlePath;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
g_nextWindowId = winId;
g_nextScaleFactor = scaleFactor;
#endif
UI::PrivateData::s_nextPrivateData = uiData;

UI* const uiPtr = createUI();

g_nextBundlePath = nullptr;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
g_nextWindowId = 0;
g_nextScaleFactor = 0.0;
#else
// enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp
uiData->window->leaveContext();
#endif
UI::PrivateData::s_nextPrivateData = nullptr;

DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,);
ui = uiPtr;
uiData->initializing = false;

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
// unused
(void)bundlePath;
#endif
}

~UIExporter()
{
quit();
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uiData->window->enterContextForDeletion();
#endif
delete ui;
delete uiData;
}
@@ -137,13 +110,9 @@ public:

bool getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
{
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uiData->window->getGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio);
#else
const DGL_NAMESPACE::Size<uint> size(uiData->window->getGeometryConstraints(keepAspectRatio));
minimumWidth = size.getWidth();
minimumHeight = size.getHeight();
#endif
return true;
}

@@ -225,13 +194,20 @@ public:
uiData->window->focus();
uiData->app.addIdleCallback(cb);
uiData->app.exec();
uiData->app.removeIdleCallback(cb);
}

void exec_idle()
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, );

#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
webViewIdle(uiData->webview);
#endif

ui->uiIdle();
uiData->app.repaintIfNeeeded();
}

void showAndFocus()
@@ -246,7 +222,14 @@ public:
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false);

uiData->app.idle();

#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
webViewIdle(uiData->webview);
#endif

ui->uiIdle();
uiData->app.repaintIfNeeeded();
return ! uiData->app.isQuitting();
}

@@ -261,25 +244,29 @@ public:
uiData->app.quit();
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
void repaint()
{
uiData->window->repaint();
}
#endif

// -------------------------------------------------------------------

#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)
#if defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)
void idleFromNativeIdle()
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

uiData->app.triggerIdleCallbacks();

#if DISTRHO_UI_USE_WEB_VIEW
if (uiData->webview != nullptr)
webViewIdle(uiData->webview);
#endif

ui->uiIdle();
uiData->app.repaintIfNeeeded();
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
void addIdleCallbackForNativeIdle(IdleCallback* const cb, const uint timerFrequencyInMs)
{
uiData->window->addIdleCallback(cb, timerFrequencyInMs);
@@ -290,28 +277,18 @@ public:
uiData->window->removeIdleCallback(cb);
}
#endif
#endif

// -------------------------------------------------------------------

void setWindowOffset(const int x, const int y)
{
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
// TODO
(void)x; (void)y;
#else
uiData->window->setOffset(x, y);
#endif
}

#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
#if DISTRHO_UI_USES_SIZE_REQUEST
void setWindowSizeFromHost(const uint width, const uint height)
{
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
ui->setSize(width, height);
#else
uiData->window->setSizeFromHost(width, height);
#endif
}
#endif

@@ -322,11 +299,7 @@ public:

void setWindowTransientWinId(const uintptr_t transientParentWindowHandle)
{
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
ui->setTransientWindowId(transientParentWindowHandle);
#else
uiData->window->setTransientParent(transientParentWindowHandle);
#endif
}

bool setWindowVisible(const bool yesNo)
@@ -336,7 +309,6 @@ public:
return ! uiData->app.isQuitting();
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
bool handlePluginKeyboardVST(const bool press, const bool special, const uint keychar, const uint keycode, const uint16_t mods)
{
using namespace DGL_NAMESPACE;
@@ -369,7 +341,6 @@ public:

return ret;
}
#endif

// -------------------------------------------------------------------

@@ -380,14 +351,12 @@ public:
ui->uiScaleFactorChanged(scaleFactor);
}

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
void notifyFocusChanged(const bool focus)
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

ui->uiFocus(focus, DGL_NAMESPACE::kCrossingNormal);
}
#endif

void setSampleRate(const double sampleRate, const bool doCallback = false)
{


+ 4
- 1
dpf/distrho/src/DistrhoUILV2.cpp View File

@@ -49,6 +49,9 @@ static constexpr const setStateFunc setStateCallback = nullptr;
static constexpr const sendNoteFunc sendNoteCallback = nullptr;
#endif

// unwanted in LV2, resize extension is deprecated and hosts can do it without extensions
static constexpr const setSizeFunc setSizeCallback = nullptr;

// -----------------------------------------------------------------------

template <class LV2F>
@@ -96,7 +99,7 @@ public:
setParameterCallback,
setStateCallback,
sendNoteCallback,
nullptr, // resize is very messy, hosts can do it without extensions
setSizeCallback,
fileRequestCallback,
bundlePath, dspPtr, scaleFactor, bgColor, fgColor, appClassName)
{


+ 60
- 119
dpf/distrho/src/DistrhoUIPrivateData.hpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -23,33 +23,38 @@
# include "DistrhoPluginVST.hpp"
#endif

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include "../extra/Sleep.hpp"
// TODO import and use file browser here
#else
# include "../../dgl/src/ApplicationPrivateData.hpp"
# include "../../dgl/src/WindowPrivateData.hpp"
# include "../../dgl/src/pugl.hpp"
#endif
#include "../../dgl/src/ApplicationPrivateData.hpp"
#include "../../dgl/src/WindowPrivateData.hpp"
#include "../../dgl/src/pugl.hpp"

#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER
# include <map>
# include <string>
#endif

#if DISTRHO_UI_USE_WEB_VIEW
# include "extra/WebView.hpp"
#endif

#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
# define DISTRHO_UI_IS_STANDALONE 1
#else
# define DISTRHO_UI_IS_STANDALONE 0
#endif

#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
# define DISTRHO_UI_USES_SIZE_REQUEST true
#if defined(DISTRHO_PLUGIN_TARGET_AU)
# define DISTRHO_UI_USES_SCHEDULED_REPAINTS 1
#else
# define DISTRHO_UI_USES_SIZE_REQUEST false
# define DISTRHO_UI_USES_SCHEDULED_REPAINTS 0
#endif

#ifdef DISTRHO_PLUGIN_TARGET_VST2
#if defined(DISTRHO_PLUGIN_TARGET_CLAP) || defined(DISTRHO_PLUGIN_TARGET_VST3)
# define DISTRHO_UI_USES_SIZE_REQUEST 1
#else
# define DISTRHO_UI_USES_SIZE_REQUEST 0
#endif

#if defined(DISTRHO_PLUGIN_TARGET_AU) || defined(DISTRHO_PLUGIN_TARGET_VST2)
# undef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif
@@ -59,54 +64,6 @@ START_NAMESPACE_DISTRHO
// -----------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
struct PluginApplication
{
DGL_NAMESPACE::IdleCallback* idleCallback;
UI* ui;

explicit PluginApplication(const char*)
: idleCallback(nullptr),
ui(nullptr) {}

void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb)
{
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,);

idleCallback = cb;
}

bool isQuitting() const noexcept
{
return ui->isQuitting();
}

bool isStandalone() const noexcept
{
return DISTRHO_UI_IS_STANDALONE;
}

void exec()
{
while (ui->isRunning())
{
d_msleep(30);
idleCallback->idleCallback();
}

if (! ui->isQuitting())
ui->close();
}

// these are not needed
void idle() {}
void quit() {}
void triggerIdleCallbacks() {}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};
#else
class PluginApplication : public DGL_NAMESPACE::Application
{
public:
@@ -137,49 +94,17 @@ public:
pData->triggerIdleCallbacks();
}

void repaintIfNeeeded()
{
pData->repaintIfNeeeded();
}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};
#endif

// -----------------------------------------------------------------------
// Plugin Window, will pass some Window events to UI

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
class PluginWindow
{
UI* const ui;

public:
explicit PluginWindow(UI* const uiPtr, PluginApplication& app)
: ui(uiPtr)
{
app.ui = ui;
}

// fetch cached data
uint getWidth() const noexcept { return ui->pData.width; }
uint getHeight() const noexcept { return ui->pData.height; }
double getScaleFactor() const noexcept { return ui->pData.scaleFactor; }

// direct mappings
void close() { ui->close(); }
void focus() { ui->focus(); }
void show() { ui->show(); }
bool isResizable() const noexcept { return ui->isResizable(); }
bool isVisible() const noexcept { return ui->isVisible(); }
void setTitle(const char* const title) { ui->setTitle(title); }
void setVisible(const bool visible) { ui->setVisible(visible); }
uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); }
void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
{
minimumWidth = ui->pData.minWidth;
minimumHeight = ui->pData.minHeight;
keepAspectRatio = ui->pData.keepAspectRatio;
}

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
class PluginWindow : public DGL_NAMESPACE::Window
{
UI* const ui;
@@ -194,7 +119,10 @@ public:
const uint height,
const double scaleFactor)
: Window(app, parentWindowHandle, width, height, scaleFactor,
DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_USES_SIZE_REQUEST, false),
DISTRHO_UI_USER_RESIZABLE,
DISTRHO_UI_USES_SCHEDULED_REPAINTS,
DISTRHO_UI_USES_SIZE_REQUEST,
false),
ui(uiPtr),
initializing(true),
receivedReshapeDuringInit(false)
@@ -219,11 +147,15 @@ public:
if (pData->view == nullptr)
return;

if (receivedReshapeDuringInit)
ui->uiReshape(getWidth(), getHeight());

initializing = false;
puglBackendLeave(pData->view);

if (receivedReshapeDuringInit)
{
puglBackendEnter(pData->view);
ui->uiReshape(getWidth(), getHeight());
puglBackendLeave(pData->view);
}
}

// used for temporary windows (VST/CLAP get size without active/visible view)
@@ -239,7 +171,7 @@ public:
puglBackendEnter(pData->view);
}

#if defined(DISTRHO_PLUGIN_TARGET_VST3) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
#if DISTRHO_UI_USES_SIZE_REQUEST
void setSizeFromHost(const uint width, const uint height)
{
puglSetSizeAndDefault(pData->view, width, height);
@@ -295,13 +227,12 @@ protected:
ui->uiScaleFactorChanged(scaleFactor);
}

# if DISTRHO_UI_FILE_BROWSER
#if DISTRHO_UI_FILE_BROWSER
void onFileSelected(const char* filename) override;
# endif
#endif

DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI

// -----------------------------------------------------------------------
// UI callbacks
@@ -320,6 +251,9 @@ struct UI::PrivateData {
// DGL
PluginApplication app;
ScopedPointer<PluginWindow> window;
#if DISTRHO_UI_USE_WEB_VIEW
WebViewHandle webview;
#endif

// DSP
double sampleRate;
@@ -331,7 +265,7 @@ struct UI::PrivateData {
uint fgColor;
double scaleFactor;
uintptr_t winId;
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER
char* uiStateFileKeyRequest;
std::map<std::string,std::string> lastUsedDirnames;
#endif
@@ -352,6 +286,9 @@ struct UI::PrivateData {
PrivateData(const char* const appClassName) noexcept
: app(appClassName),
window(nullptr),
#if DISTRHO_UI_USE_WEB_VIEW
webview(nullptr),
#endif
sampleRate(0),
parameterOffset(0),
dspPtr(nullptr),
@@ -359,7 +296,7 @@ struct UI::PrivateData {
fgColor(0xffffffff),
scaleFactor(1.0),
winId(0),
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER
uiStateFileKeyRequest(nullptr),
#endif
bundlePath(nullptr),
@@ -395,7 +332,7 @@ struct UI::PrivateData {

~PrivateData() noexcept
{
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER
std::free(uiStateFileKeyRequest);
#endif
std::free(bundlePath);
@@ -415,6 +352,9 @@ struct UI::PrivateData {

void setStateCallback(const char* const key, const char* const value)
{
DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);

if (setStateCallbackFunc != nullptr)
setStateCallbackFunc(callbacksPtr, key, value);
}
@@ -427,19 +367,20 @@ struct UI::PrivateData {

void setSizeCallback(const uint width, const uint height)
{
DISTRHO_SAFE_ASSERT_RETURN(width != 0 && height != 0,);

if (setSizeCallbackFunc != nullptr)
setSizeCallbackFunc(callbacksPtr, width, height);
}

// implemented below, after PluginWindow
bool fileRequestCallback(const char* const key);
bool fileRequestCallback(const char* key);

static UI::PrivateData* s_nextPrivateData;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor);
#else
static PluginWindow& createNextWindow(UI* ui, uint width, uint height, bool adjustForScaleFactor);
#endif
static PluginWindow& createNextWindow(UI* ui, uint width, uint height);
#if DISTRHO_UI_USE_WEB_VIEW
static void webViewMessageCallback(void* arg, char* msg);
#endif
};

// -----------------------------------------------------------------------
@@ -450,7 +391,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key)
if (fileRequestCallbackFunc != nullptr)
return fileRequestCallbackFunc(callbacksPtr, key);

#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER
std::free(uiStateFileKeyRequest);
uiStateFileKeyRequest = strdup(key);
DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false);
@@ -472,7 +413,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key)
// -----------------------------------------------------------------------
// PluginWindow onFileSelected that require UI::PrivateData definitions

#if DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_UI_FILE_BROWSER
inline void PluginWindow::onFileSelected(const char* const filename)
{
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
@@ -480,7 +421,7 @@ inline void PluginWindow::onFileSelected(const char* const filename)
if (initializing)
return;

#if DISTRHO_PLUGIN_WANT_STATE && DISTRHO_UI_FILE_BROWSER && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_WANT_STATE
if (char* const key = ui->uiData->uiStateFileKeyRequest)
{
ui->uiData->uiStateFileKeyRequest = nullptr;


+ 9
- 173
dpf/distrho/src/DistrhoUIVST3.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -21,15 +21,6 @@
#include "travesty/host.h"
#include "travesty/view.h"

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# if defined(DISTRHO_OS_MAC)
# include <CoreFoundation/CoreFoundation.h>
# elif defined(DISTRHO_OS_WINDOWS)
# include <winuser.h>
# define DPF_VST3_WIN32_TIMER_ID 1
# endif
#endif

/* TODO items:
* - mousewheel event
* - file request?
@@ -92,10 +83,10 @@ static void applyGeometryConstraints(const uint minimumWidth,
{
// fix width
if (reqRatio > ratio)
rect->right = static_cast<int32_t>(rect->bottom * ratio + 0.5);
rect->right = d_roundToIntPositive(rect->bottom * ratio);
// fix height
else
rect->bottom = static_cast<int32_t>(static_cast<double>(rect->right) / ratio + 0.5);
rect->bottom = d_roundToIntPositive(static_cast<double>(rect->right) / ratio);
}
}

@@ -110,7 +101,6 @@ static void applyGeometryConstraints(const uint minimumWidth,

// --------------------------------------------------------------------------------------------------------------------

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
static uint translateVST3Modifiers(const int64_t modifiers) noexcept
{
using namespace DGL_NAMESPACE;
@@ -134,115 +124,9 @@ static uint translateVST3Modifiers(const int64_t modifiers) noexcept

return dglmods;
}
#endif

// --------------------------------------------------------------------------------------------------------------------

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !DPF_VST3_USING_HOST_RUN_LOOP
/**
* Helper class for getting a native idle timer via native APIs.
*/
class NativeIdleHelper
{
public:
NativeIdleHelper(IdleCallback* const callback)
: fCallback(callback),
#ifdef DISTRHO_OS_MAC
fTimerRef(nullptr)
#else
fTimerWindow(nullptr),
fTimerWindowClassName()
#endif
{
}

void registerNativeIdleCallback()
{
#ifdef DISTRHO_OS_MAC
constexpr const CFTimeInterval interval = DPF_VST3_TIMER_INTERVAL * 0.0001;

CFRunLoopTimerContext context = {};
context.info = this;
fTimerRef = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + interval, interval, 0, 0,
platformIdleTimerCallback, &context);
DISTRHO_SAFE_ASSERT_RETURN(fTimerRef != nullptr,);

CFRunLoopAddTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes);
#else
/*
* Create an invisible window to handle a timer.
* There is no need for implementing a window proc because DefWindowProc already calls the
* callback function when processing WM_TIMER messages.
*/
fTimerWindowClassName = (
#ifdef DISTRHO_PLUGIN_BRAND
DISTRHO_PLUGIN_BRAND
#else
DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE)
#endif
"-" DISTRHO_PLUGIN_NAME "-"
);

char suffix[9];
std::snprintf(suffix, sizeof(suffix), "%08x", std::rand());
suffix[sizeof(suffix)-1] = '\0';
fTimerWindowClassName += suffix;

WNDCLASSEX cls;
ZeroMemory(&cls, sizeof(cls));
cls.cbSize = sizeof(WNDCLASSEX);
cls.cbWndExtra = sizeof(LONG_PTR);
cls.lpszClassName = fTimerWindowClassName.buffer();
cls.lpfnWndProc = DefWindowProc;
RegisterClassEx(&cls);

fTimerWindow = CreateWindowEx(0, cls.lpszClassName, "DPF Timer Helper",
0, 0, 0, 0, 0, HWND_MESSAGE, nullptr, nullptr, nullptr);
DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,);

SetWindowLongPtr(fTimerWindow, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(static_cast<void*>(this)));
SetTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID, DPF_VST3_TIMER_INTERVAL,
static_cast<TIMERPROC>(platformIdleTimerCallback));
#endif
}

void unregisterNativeIdleCallback()
{
#ifdef DISTRHO_OS_MAC
CFRunLoopRemoveTimer(CFRunLoopGetCurrent(), fTimerRef, kCFRunLoopCommonModes);
CFRelease(fTimerRef);
#else
DISTRHO_SAFE_ASSERT_RETURN(fTimerWindow != nullptr,);
KillTimer(fTimerWindow, DPF_VST3_WIN32_TIMER_ID);
DestroyWindow(fTimerWindow);
UnregisterClass(fTimerWindowClassName, nullptr);
#endif
}

private:
IdleCallback* const fCallback;

#ifdef DISTRHO_OS_MAC
CFRunLoopTimerRef fTimerRef;

static void platformIdleTimerCallback(CFRunLoopTimerRef, void* const info)
{
static_cast<NativeIdleHelper*>(info)->fCallback->idleCallback();
}
#else
HWND fTimerWindow;
String fTimerWindowClassName;

static void WINAPI platformIdleTimerCallback(const HWND hwnd, UINT, UINT_PTR, DWORD)
{
reinterpret_cast<NativeIdleHelper*>(GetWindowLongPtr(hwnd, GWLP_USERDATA))->fCallback->idleCallback();
}
#endif
};
#endif

/**
* Helper class for getting a native idle timer, either through pugl or via native APIs.
* Helper class for getting a native idle timer.
*/
#if !DPF_VST3_USING_HOST_RUN_LOOP
class NativeIdleCallback : public IdleCallback
@@ -250,49 +134,25 @@ class NativeIdleCallback : public IdleCallback
public:
NativeIdleCallback(UIExporter& ui)
: fCallbackRegistered(false),
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
fIdleHelper(this)
#else
fUI(ui)
#endif
{
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
// unused
(void)ui;
#endif
}
fUI(ui) {}

void registerNativeIdleCallback()
{
DISTRHO_SAFE_ASSERT_RETURN(!fCallbackRegistered,);
fCallbackRegistered = true;

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
fIdleHelper.registerNativeIdleCallback();
#else
fUI.addIdleCallbackForNativeIdle(this, DPF_VST3_TIMER_INTERVAL);
#endif
}

void unregisterNativeIdleCallback()
{
DISTRHO_SAFE_ASSERT_RETURN(fCallbackRegistered,);
fCallbackRegistered = false;

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
fIdleHelper.unregisterNativeIdleCallback();
#else
fUI.removeIdleCallbackForNativeIdle(this);
#endif
}

private:
bool fCallbackRegistered;
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
NativeIdleHelper fIdleHelper;
#else
UIExporter& fUI;
#endif
};
#endif

@@ -392,7 +252,6 @@ public:
// ----------------------------------------------------------------------------------------------------------------
// v3_plugin_view interface calls

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
v3_result onWheel(float /*distance*/)
{
// TODO
@@ -432,7 +291,6 @@ public:
fUI.notifyFocusChanged(state);
return V3_OK;
}
#endif

v3_result getSize(v3_view_rect* const rect) const noexcept
{
@@ -889,6 +747,7 @@ private:
{
DISTRHO_SAFE_ASSERT_RETURN(fView != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(fFrame != nullptr,);
DISTRHO_SAFE_ASSERT_RETURN(width != 0 && height != 0,);

#ifdef DISTRHO_OS_MAC
const double scaleFactor = fUI.getScaleFactor();
@@ -1463,7 +1322,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp {

static v3_result V3_API on_wheel(void* const self, const float distance)
{
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
d_debug("dpf_plugin_view::on_wheel => %p %f", self, distance);
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self);

@@ -1471,16 +1329,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED);

return uivst3->onWheel(distance);
#else
return V3_NOT_IMPLEMENTED;
// unused
(void)self; (void)distance;
#endif
}

static v3_result V3_API on_key_down(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers)
{
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
d_debug("dpf_plugin_view::on_key_down => %p %i %i %i", self, key_char, key_code, modifiers);
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self);

@@ -1488,16 +1340,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED);

return uivst3->onKeyDown(key_char, key_code, modifiers);
#else
return V3_NOT_IMPLEMENTED;
// unused
(void)self; (void)key_char; (void)key_code; (void)modifiers;
#endif
}

static v3_result V3_API on_key_up(void* const self, const int16_t key_char, const int16_t key_code, const int16_t modifiers)
{
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
d_debug("dpf_plugin_view::on_key_up => %p %i %i %i", self, key_char, key_code, modifiers);
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self);

@@ -1505,11 +1351,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED);

return uivst3->onKeyUp(key_char, key_code, modifiers);
#else
return V3_NOT_IMPLEMENTED;
// unused
(void)self; (void)key_char; (void)key_code; (void)modifiers;
#endif
}

static v3_result V3_API get_size(void* const self, v3_view_rect* const rect)
@@ -1526,10 +1367,10 @@ struct dpf_plugin_view : v3_plugin_view_cpp {

double scaleFactor = view->scale != nullptr ? view->scale->scaleFactor : 0.0;
#if defined(DISTRHO_UI_DEFAULT_WIDTH) && defined(DISTRHO_UI_DEFAULT_HEIGHT)
rect->right = DISTRHO_UI_DEFAULT_WIDTH;
rect->bottom = DISTRHO_UI_DEFAULT_HEIGHT;
if (d_isZero(scaleFactor))
scaleFactor = 1.0;
rect->right = DISTRHO_UI_DEFAULT_WIDTH * scaleFactor;
rect->bottom = DISTRHO_UI_DEFAULT_HEIGHT * scaleFactor;
#else
UIExporter tmpUI(nullptr, 0, view->sampleRate,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, d_nextBundlePath,
@@ -1539,6 +1380,7 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
scaleFactor = tmpUI.getScaleFactor();
tmpUI.quit();
#endif

rect->left = rect->top = 0;
#ifdef DISTRHO_OS_MAC
rect->right /= scaleFactor;
@@ -1567,7 +1409,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp {

static v3_result V3_API on_focus(void* const self, const v3_bool state)
{
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
d_debug("dpf_plugin_view::on_focus => %p %u", self, state);
dpf_plugin_view* const view = *static_cast<dpf_plugin_view**>(self);

@@ -1575,11 +1416,6 @@ struct dpf_plugin_view : v3_plugin_view_cpp {
DISTRHO_SAFE_ASSERT_RETURN(uivst3 != nullptr, V3_NOT_INITIALIZED);

return uivst3->onFocus(state);
#else
return V3_NOT_IMPLEMENTED;
// unused
(void)self; (void)state;
#endif
}

static v3_result V3_API set_frame(void* const self, v3_plugin_frame** const frame)


+ 13
- 5
dpf/distrho/src/DistrhoUtils.cpp View File

@@ -1,6 +1,6 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-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 copyright notice and this
@@ -19,6 +19,7 @@
#endif

#include "../extra/String.hpp"
#include "../DistrhoPluginUtils.hpp"
#include "../DistrhoStandaloneUtils.hpp"

#ifdef DISTRHO_OS_WINDOWS
@@ -49,7 +50,7 @@ BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID)

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------

const char* getBinaryFilename()
{
@@ -77,7 +78,9 @@ const char* getBinaryFilename()

const char* getPluginFormatName() noexcept
{
#if defined(DISTRHO_PLUGIN_TARGET_CARLA)
#if defined(DISTRHO_PLUGIN_TARGET_AU)
return "AudioUnit";
#elif defined(DISTRHO_PLUGIN_TARGET_CARLA)
return "Carla";
#elif defined(DISTRHO_PLUGIN_TARGET_JACK)
#if defined(DISTRHO_OS_WASM)
@@ -110,7 +113,7 @@ const char* getResourcePath(const char* const bundlePath) noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(bundlePath != nullptr, nullptr);

#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
#if defined(DISTRHO_PLUGIN_TARGET_AU) || defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_VST2) || defined(DISTRHO_PLUGIN_TARGET_CLAP)
static String resourcePath;

if (resourcePath.isEmpty())
@@ -163,6 +166,11 @@ 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

+ 2
- 2
dpf/distrho/src/jackbridge/JackBridge.cpp View File

@@ -475,12 +475,12 @@ struct JackBridge {

if (lib == nullptr)
{
fprintf(stderr, "Failed to load JACK DLL, reason:\n%s\n", lib_error(filename));
d_stderr("Failed to load JACK DLL, reason:\n%s", lib_error(filename));
return;
}
else
{
fprintf(stdout, "%s loaded successfully!\n", filename);
d_stdout("%s loaded successfully!", filename);
}

#define JOIN(a, b) a ## b


+ 4
- 4
dpf/distrho/src/jackbridge/NativeBridge.hpp View File

@@ -49,10 +49,10 @@ struct NativeBridge {
uint numMidiOuts;

// JACK callbacks
JackProcessCallback jackProcessCallback = nullptr;
JackBufferSizeCallback bufferSizeCallback = nullptr;
void* jackProcessArg = nullptr;
void* jackBufferSizeArg = nullptr;
JackProcessCallback jackProcessCallback;
JackBufferSizeCallback bufferSizeCallback;
void* jackProcessArg;
void* jackBufferSizeArg;

// Runtime buffers
enum PortMask {


+ 7
- 0
dpf/utils/au-services-restart.sh View File

@@ -0,0 +1,7 @@
#!/bin/bash

rm -f "~/Library/Application Support/AU Lab/com.apple.audio.aulab_componentcache.plist"
rm -rf "~/Library/Caches/AudioUnitCache"
killall -9 AudioComponentRegistrar
sudo killall -9 AudioComponentRegistrar
exit 0

+ 10
- 4
dpf/utils/generate-ttl.sh View File

@@ -1,6 +1,6 @@
#!/bin/bash

# function not available on some systems
# the realpath function is not available on some systems
if ! which realpath &>/dev/null; then
function realpath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
@@ -9,7 +9,13 @@ fi

set -e

if [ ! -d bin ]; then
BIN_DIR=${1}

if [ -z "${BIN_DIR}" ]; then
BIN_DIR=bin
fi

if [ ! -d ${BIN_DIR} ]; then
echo "Please run this script from the source root folder"
exit
fi
@@ -17,7 +23,7 @@ fi
PWD="$(dirname "${0}")"

if [ -f "${PWD}/lv2_ttl_generator.exe" ]; then
GEN="${PWD}/lv2_ttl_generator.exe"
GEN="$(realpath ${PWD}/lv2_ttl_generator.exe)"
EXT=dll
else
GEN="$(realpath ${PWD}/lv2_ttl_generator)"
@@ -28,7 +34,7 @@ else
fi
fi

cd bin
cd ${BIN_DIR}
FOLDERS=`find . -type d -name \*.lv2`

for i in ${FOLDERS}; do


+ 64
- 27
dpf/utils/package-osx-bundles.sh View File

@@ -1,32 +1,63 @@
#!/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

NAME="$(basename $(git rev-parse --show-toplevel))"
SNAME="$(echo ${NAME} | tr -d ' ' | tr '/' '-')"
# can be overridden by environment variables
MACOS_PKG_LICENSE_FILE=${MACOS_PKG_LICENSE_FILE:=""}
MACOS_PKG_NAME=${MACOS_PKG_NAME:="$(basename $(git rev-parse --show-toplevel))"}
MACOS_PKG_SNAME=${MACOS_PKG_SNAME:="$(echo ${MACOS_PKG_NAME} | tr -d ' ' | tr '/' '-')"}
MACOS_PKG_SYMBOL=${MACOS_PKG_SYMBOL:="studio.kx.distrho.plugins.${MACOS_PKG_SNAME}"}
MACOS_PKG_WELCOME_TXT=${MACOS_PKG_WELCOME_TXT:=${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in}

# backwards compat
if [ -n "${WELCOME_TXT}" ]; then
MACOS_PKG_WELCOME_TXT="${WELCOME_TXT}"
fi

SKIP_START="<!--"
SKIP_END="-->"

if [ -n "${MACOS_INSTALLER_DEV_ID}" ]; then
PKG_SIGN_ARGS=(--sign "${MACOS_INSTALLER_DEV_ID}")
fi

rm -rf pkg
mkdir pkg

if [ -z "${MACOS_PKG_LICENSE_FILE}" ]; then
SKIP_LICENSE_START="${SKIP_START}"
SKIP_LICENSE_END="${SKIP_END}"
fi

ENABLE_AU=$(find . -maxdepth 1 -name '*.component' -print -quit | grep -q '.component' && echo 1 || echo)
if [ -n "${ENABLE_AU}" ]; then
mkdir pkg/au
cp -RL *.component pkg/au/
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/au/*.component
pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.components" \
--identifier "${MACOS_PKG_SYMBOL}-components" \
--install-location "/Library/Audio/Plug-Ins/Components/" \
--root "${PWD}/pkg/au/" \
../dpf-${SNAME}-components.pkg
"${PKG_SIGN_ARGS[@]}" \
../dpf-${MACOS_PKG_SNAME}-components.pkg
else
SKIP_AU_START="${SKIP_START}"
SKIP_AU_END="${SKIP_END}"
@@ -36,11 +67,13 @@ ENABLE_CLAP=$(find . -maxdepth 1 -name '*.clap' -print -quit | grep -q '.clap' &
if [ -n "${ENABLE_CLAP}" ]; then
mkdir pkg/clap
cp -RL *.clap pkg/clap/
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/clap/*.clap
pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.clapbundles" \
--identifier "${MACOS_PKG_SYMBOL}-clapbundles" \
--install-location "/Library/Audio/Plug-Ins/CLAP/" \
--root "${PWD}/pkg/clap/" \
../dpf-${SNAME}-clapbundles.pkg
"${PKG_SIGN_ARGS[@]}" \
../dpf-${MACOS_PKG_SNAME}-clapbundles.pkg
else
SKIP_CLAP_START="${SKIP_START}"
SKIP_CLAP_END="${SKIP_END}"
@@ -50,11 +83,13 @@ ENABLE_LV2=$(find . -maxdepth 1 -name '*.lv2' -print -quit | grep -q '.lv2' && e
if [ -n "${ENABLE_LV2}" ]; then
mkdir pkg/lv2
cp -RL *.lv2 pkg/lv2/
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --force --verbose --option=runtime pkg/lv2/*.lv2/*.dylib
pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \
--identifier "${MACOS_PKG_SYMBOL}-lv2bundles" \
--install-location "/Library/Audio/Plug-Ins/LV2/" \
--root "${PWD}/pkg/lv2/" \
../dpf-${SNAME}-lv2bundles.pkg
"${PKG_SIGN_ARGS[@]}" \
../dpf-${MACOS_PKG_SNAME}-lv2bundles.pkg
else
SKIP_LV2_START="${SKIP_START}"
SKIP_LV2_END="${SKIP_END}"
@@ -64,11 +99,13 @@ ENABLE_VST2=$(find . -maxdepth 1 -name '*.vst' -print -quit | grep -q '.vst' &&
if [ -n "${ENABLE_VST2}" ]; then
mkdir pkg/vst2
cp -RL *.vst pkg/vst2/
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/vst2/*.vst
pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.vst2bundles" \
--identifier "${MACOS_PKG_SYMBOL}-vst2bundles" \
--install-location "/Library/Audio/Plug-Ins/VST/" \
--root "${PWD}/pkg/vst2/" \
../dpf-${SNAME}-vst2bundles.pkg
"${PKG_SIGN_ARGS[@]}" \
../dpf-${MACOS_PKG_SNAME}-vst2bundles.pkg
else
SKIP_VST2_START="${SKIP_START}"
SKIP_VST2_END="${SKIP_END}"
@@ -78,11 +115,13 @@ ENABLE_VST3=$(find . -maxdepth 1 -name '*.vst3' -print -quit | grep -q '.vst3' &
if [ -n "${ENABLE_VST3}" ]; then
mkdir pkg/vst3
cp -RL *.vst3 pkg/vst3/
[ -n "${MACOS_APP_DEV_ID}" ] && codesign -s "${MACOS_APP_DEV_ID}" --deep --force --verbose --option=runtime pkg/vst3/*.vst3
pkgbuild \
--identifier "studio.kx.distrho.plugins.${SNAME}.vst3bundles" \
--identifier "${MACOS_PKG_SYMBOL}-vst3bundles" \
--install-location "/Library/Audio/Plug-Ins/VST3/" \
--root "${PWD}/pkg/vst3/" \
../dpf-${SNAME}-vst3bundles.pkg
"${PKG_SIGN_ARGS[@]}" \
../dpf-${MACOS_PKG_SNAME}-vst3bundles.pkg
else
SKIP_VST3_START="${SKIP_START}"
SKIP_VST3_END="${SKIP_END}"
@@ -90,36 +129,34 @@ fi

cd ..

DPF_UTILS_DIR=$(dirname ${0})

# can be overridden by environment variables
WELCOME_TXT=${WELCOME_TXT:=${DPF_UTILS_DIR}/plugin.pkg/welcome.txt.in}

mkdir -p build
sed -e "s|@name@|${NAME}|" "${WELCOME_TXT}" > build/welcome.txt
sed -e "s|@name@|${MACOS_PKG_NAME}|" "${MACOS_PKG_WELCOME_TXT}" > build/welcome.txt
sed -e "s|@builddir@|${PWD}/build|" \
-e "s|@skip_license_start@|${SKIP_LICENSE_START}|" \
-e "s|@skip_au_start@|${SKIP_AU_START}|" \
-e "s|@skip_clap_start@|${SKIP_CLAP_START}|" \
-e "s|@skip_lv2_start@|${SKIP_LV2_START}|" \
-e "s|@skip_vst2_start@|${SKIP_VST2_START}|" \
-e "s|@skip_vst3_start@|${SKIP_VST3_START}|" \
-e "s|@skip_license_end@|${SKIP_LICENSE_END}|" \
-e "s|@skip_au_end@|${SKIP_AU_END}|" \
-e "s|@skip_clap_end@|${SKIP_CLAP_END}|" \
-e "s|@skip_lv2_end@|${SKIP_LV2_END}|" \
-e "s|@skip_vst2_end@|${SKIP_VST2_END}|" \
-e "s|@skip_vst3_end@|${SKIP_VST3_END}|" \
-e "s|@aubundleref@|dpf-${SNAME}-components.pkg|" \
-e "s|@clapbundleref@|dpf-${SNAME}-clapbundles.pkg|" \
-e "s|@lv2bundleref@|dpf-${SNAME}-lv2bundles.pkg|" \
-e "s|@vst2bundleref@|dpf-${SNAME}-vst2bundles.pkg|" \
-e "s|@vst3bundleref@|dpf-${SNAME}-vst3bundles.pkg|" \
-e "s|@name@|${NAME}|g" \
-e "s|@sname@|${SNAME}|g" \
-e "s|@license_file@|${MACOS_PKG_LICENSE_FILE}|" \
-e "s|@name@|${MACOS_PKG_NAME}|g" \
-e "s|@sname@|${MACOS_PKG_SNAME}|g" \
-e "s|@symbol@|${MACOS_PKG_SYMBOL}|g" \
${DPF_UTILS_DIR}/plugin.pkg/package.xml.in > build/package.xml

productbuild \
--distribution build/package.xml \
--identifier "studio.kx.distrho.${SNAME}" \
--identifier "${MACOS_PKG_SYMBOL}" \
--package-path "${PWD}" \
--version 0 \
${SNAME}-macOS.pkg
"${PKG_SIGN_ARGS[@]}" \
${MACOS_PKG_SNAME}-macOS.pkg

# xcrun notarytool submit build/*-macOS.pkg --keychain-profile "build-notary" --wait
# xcrun notarytool log --keychain-profile "build-notary" 00000000-0000-0000-0000-000000000000

+ 17
- 16
dpf/utils/plugin.pkg/package.xml.in View File

@@ -2,39 +2,40 @@
<installer-gui-script minSpecVersion="1">
<title>@name@</title>
<domains enable_anywhere="false" enable_currentUserHome="false" enable_localSystem="true" />
@skip_license_start@<license file="@license_file@" mime-type="text/plain" />@skip_license_end@
<options customize="always" hostArchitectures="arm64,x86_64" require-scripts="false" rootVolumeOnly="true" />
<pkg-ref id="studio.kx.distrho.@sname@" />
<pkg-ref id="@symbol@" />
<welcome file="@builddir@/welcome.txt" mime-type="text/plain" />
@skip_au_start@
<choice id="studio.kx.distrho.@sname@-au" title="AU" description="Install AU plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-components" version="0">@aubundleref@</pkg-ref>
<choice id="@symbol@-au" title="AU" description="Install AU plugins" visible="true">
<pkg-ref id="@symbol@-components" version="0">dpf-@sname@-components.pkg</pkg-ref>
</choice>
@skip_au_end@
@skip_clap_start@
<choice id="studio.kx.distrho.@sname@-clap" title="CLAP" description="Install CLAP plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-clapbundles" version="0">@clapbundleref@</pkg-ref>
<choice id="@symbol@-clap" title="CLAP" description="Install CLAP plugins" visible="true">
<pkg-ref id="@symbol@-clapbundles" version="0">dpf-@sname@-clapbundles.pkg</pkg-ref>
</choice>
@skip_clap_end@
@skip_lv2_start@
<choice id="studio.kx.distrho.@sname@-lv2" title="LV2" description="Install LV2 plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-lv2bundles" version="0">@lv2bundleref@</pkg-ref>
<choice id="@symbol@-lv2" title="LV2" description="Install LV2 plugins" visible="true">
<pkg-ref id="@symbol@-lv2bundles" version="0">dpf-@sname@-lv2bundles.pkg</pkg-ref>
</choice>
@skip_lv2_end@
@skip_vst2_start@
<choice id="studio.kx.distrho.@sname@-vst2" title="VST2" description="Install VST2 plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-vst2bundles" version="0">@vst2bundleref@</pkg-ref>
<choice id="@symbol@-vst2" title="VST2" description="Install VST2 plugins" visible="true">
<pkg-ref id="@symbol@-vst2bundles" version="0">dpf-@sname@-vst2bundles.pkg</pkg-ref>
</choice>
@skip_vst2_end@
@skip_vst3_start@
<choice id="studio.kx.distrho.@sname@-vst3" title="VST3" description="Install VST3 plugins" visible="true">
<pkg-ref id="studio.kx.distrho.@sname@-vst3bundles" version="0">@vst3bundleref@</pkg-ref>
<choice id="@symbol@-vst3" title="VST3" description="Install VST3 plugins" visible="true">
<pkg-ref id="@symbol@-vst3bundles" version="0">dpf-@sname@-vst3bundles.pkg</pkg-ref>
</choice>
@skip_vst3_end@
<choices-outline>
@skip_au_start@<line choice="studio.kx.distrho.@sname@-au"/>@skip_au_end@
@skip_clap_start@<line choice="studio.kx.distrho.@sname@-clap"/>@skip_clap_end@
@skip_lv2_start@<line choice="studio.kx.distrho.@sname@-lv2"/>@skip_lv2_end@
@skip_vst2_start@<line choice="studio.kx.distrho.@sname@-vst2"/>@skip_vst2_end@
@skip_vst3_start@<line choice="studio.kx.distrho.@sname@-vst3"/>@skip_vst3_end@
@skip_au_start@<line choice="@symbol@-au"/>@skip_au_end@
@skip_clap_start@<line choice="@symbol@-clap"/>@skip_clap_end@
@skip_lv2_start@<line choice="@symbol@-lv2"/>@skip_lv2_end@
@skip_vst2_start@<line choice="@symbol@-vst2"/>@skip_vst2_end@
@skip_vst3_start@<line choice="@symbol@-vst3"/>@skip_vst3_end@
</choices-outline>
</installer-gui-script>

+ 1
- 0
dpf/utils/symbols/au.exp View File

@@ -0,0 +1 @@
_PluginAUFactory

+ 0
- 5
plugins/3BandEQ/DistrhoPlugin3BandEQ.hpp View File

@@ -74,11 +74,6 @@ protected:
return d_version(1, 0, 0);
}
int64_t getUniqueId() const noexcept override
{
return d_cconst('D', '3', 'E', 'Q');
}
// -------------------------------------------------------------------
// Init


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save