Browse Source

Merge branch 'falkTX:main' into open_recent

pull/1834/head
kleph GitHub 2 months ago
parent
commit
52004cae90
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
100 changed files with 1599 additions and 3161 deletions
  1. +4
    -3
      .github/workflows/build.yml
  2. +1
    -1
      .github/workflows/dpf.yml
  3. +50
    -0
      .github/workflows/pylint.yml
  4. +17
    -53
      .github/workflows/release.yml
  5. +5
    -50
      Makefile
  6. +8
    -40
      cmake/CMakeLists.txt
  7. +0
    -11
      data/carla-bridge-lv2-modgui
  8. +2
    -2
      data/macos/bundle.py
  9. +23
    -13
      data/update-dpf
  10. +0
    -33
      data/update-juce
  11. +2
    -2
      data/windows/app-gui.py
  12. +0
    -6
      resources/ui/carla_settings.ui
  13. +4
    -5
      source/Makefile.mk
  14. +5
    -0
      source/backend/CarlaBackend.h
  15. +2
    -2
      source/backend/CarlaEngine.hpp
  16. +4
    -2
      source/backend/CarlaHostImpl.hpp
  17. +6
    -2
      source/backend/CarlaPlugin.hpp
  18. +0
    -273
      source/backend/CarlaPluginPtr.hpp
  19. +13
    -10
      source/backend/CarlaStandalone.cpp
  20. +8
    -9
      source/backend/CarlaStandaloneNSM.cpp
  21. +41
    -42
      source/backend/engine/CarlaEngine.cpp
  22. +21
    -20
      source/backend/engine/CarlaEngineBridge.cpp
  23. +5
    -21
      source/backend/engine/CarlaEngineClient.cpp
  24. +2
    -16
      source/backend/engine/CarlaEngineClient.hpp
  25. +8
    -21
      source/backend/engine/CarlaEngineDummy.cpp
  26. +38
    -54
      source/backend/engine/CarlaEngineGraph.cpp
  27. +8
    -22
      source/backend/engine/CarlaEngineInternal.cpp
  28. +7
    -21
      source/backend/engine/CarlaEngineInternal.hpp
  29. +30
    -29
      source/backend/engine/CarlaEngineJack.cpp
  30. +13
    -12
      source/backend/engine/CarlaEngineNative.cpp
  31. +12
    -25
      source/backend/engine/CarlaEngineOsc.hpp
  32. +1
    -1
      source/backend/engine/CarlaEngineOscSend.cpp
  33. +1
    -1
      source/backend/engine/CarlaEnginePorts.cpp
  34. +4
    -4
      source/backend/engine/CarlaEngineRtAudio.cpp
  35. +3
    -17
      source/backend/engine/CarlaEngineSDL.cpp
  36. +28
    -26
      source/backend/plugin/CarlaPlugin.cpp
  37. +9
    -8
      source/backend/plugin/CarlaPluginAU.cpp
  38. +62
    -76
      source/backend/plugin/CarlaPluginBridge.cpp
  39. +12
    -20
      source/backend/plugin/CarlaPluginCLAP.cpp
  40. +8
    -25
      source/backend/plugin/CarlaPluginFluidSynth.cpp
  41. +5
    -18
      source/backend/plugin/CarlaPluginInternal.hpp
  42. +14
    -29
      source/backend/plugin/CarlaPluginJSFX.cpp
  43. +34
    -35
      source/backend/plugin/CarlaPluginJack.cpp
  44. +20
    -36
      source/backend/plugin/CarlaPluginLADSPADSSI.cpp
  45. +49
    -52
      source/backend/plugin/CarlaPluginLV2.cpp
  46. +17
    -34
      source/backend/plugin/CarlaPluginNative.cpp
  47. +6
    -21
      source/backend/plugin/CarlaPluginSFZero.cpp
  48. +7
    -7
      source/backend/plugin/CarlaPluginVST2.cpp
  49. +93
    -22
      source/backend/plugin/CarlaPluginVST3.cpp
  50. +22
    -12
      source/backend/utils/CachedPlugins.cpp
  51. +5
    -5
      source/backend/utils/Information.cpp
  52. +11
    -9
      source/backend/utils/PluginDiscovery.cpp
  53. +9
    -9
      source/bridges-plugin/CarlaBridgePlugin.cpp
  54. +12
    -26
      source/bridges-plugin/CarlaBridgeSingleLV2.cpp
  55. +7
    -20
      source/bridges-ui/CarlaBridgeFormat.cpp
  56. +6
    -19
      source/bridges-ui/CarlaBridgeFormat.hpp
  57. +3
    -17
      source/bridges-ui/CarlaBridgeFormatLV2.cpp
  58. +6
    -19
      source/bridges-ui/CarlaBridgeToolkitNative.cpp
  59. +1
    -1
      source/bridges-ui/Makefile
  60. +18
    -14
      source/discovery/carla-discovery.cpp
  61. +2
    -2
      source/frontend/C++/carla_app.cpp
  62. +13
    -6
      source/frontend/Makefile
  63. +3
    -3
      source/frontend/carla-plugin
  64. +26
    -14
      source/frontend/carla_app.py
  65. +40
    -21
      source/frontend/carla_backend.py
  66. +130
    -17
      source/frontend/carla_frontend.cpp
  67. +14
    -3
      source/frontend/carla_frontend.h
  68. +12
    -2
      source/frontend/carla_frontend.py
  69. +20
    -14
      source/frontend/carla_host.py
  70. +22
    -10
      source/frontend/carla_host_control.py
  71. +0
    -77
      source/frontend/carla_modgui.py
  72. +12
    -10
      source/frontend/carla_settings.py
  73. +38
    -27
      source/frontend/carla_shared.py
  74. +6
    -20
      source/frontend/carla_utils.py
  75. +5
    -138
      source/frontend/carla_widgets.py
  76. +34
    -45
      source/frontend/common/__init__.py
  77. +0
    -19
      source/frontend/dialogs/__init__.py
  78. +147
    -0
      source/frontend/dialogs/aboutdialog.cpp
  79. +39
    -0
      source/frontend/dialogs/aboutdialog.hpp
  80. +4
    -4
      source/frontend/dialogs/aboutdialog.ui
  81. +64
    -146
      source/frontend/dialogs/jackappdialog.cpp
  82. +15
    -19
      source/frontend/dialogs/jackappdialog.hpp
  83. +0
    -221
      source/frontend/dialogs/jackappdialog.py
  84. +0
    -0
      source/frontend/modgui/__init__.py
  85. +0
    -546
      source/frontend/modgui/host.py
  86. +0
    -225
      source/frontend/modgui/webserver.py
  87. +8
    -8
      source/frontend/patchcanvas/theme.py
  88. +4
    -104
      source/frontend/pluginlist/pluginlistdialog.cpp
  89. +29
    -5
      source/frontend/pluginlist/pluginlistdialog.hpp
  90. +41
    -0
      source/frontend/qt_compat.py
  91. +15
    -7
      source/frontend/widgets/canvaspreviewframe.py
  92. +10
    -9
      source/frontend/widgets/draggablegraphicsview.py
  93. +4
    -3
      source/frontend/widgets/paramspinbox.py
  94. +5
    -2
      source/frontend/widgets/pixmapkeyboard.py
  95. +3
    -3
      source/frontend/widgets/racklistwidget.py
  96. +3
    -17
      source/includes/CarlaNativeExtUI.hpp
  97. +9
    -23
      source/includes/CarlaNativePrograms.hpp
  98. +10
    -0
      source/includes/lv2/atom-helpers.h
  99. +0
    -2
      source/includes/lv2_rdf.hpp
  100. +0
    -6
      source/includes/vst3sdk/JUCE_README.md

+ 4
- 3
.github/workflows/build.yml View File

@@ -43,8 +43,9 @@ jobs:
strategy:
matrix:
include:
- target: macos-12
- target: macos-13
- target: macos-14
- target: macos-15
runs-on: ${{ matrix.target }}
steps:
- uses: actions/checkout@v4
@@ -59,7 +60,7 @@ jobs:
run: make -j $(sysctl -n hw.logicalcpu)

wasm:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
@@ -70,7 +71,7 @@ jobs:
with:
path: |
~/emsdk
key: emsdk-v1
key: emsdk-v2
- name: Set up dependencies
run: |
[ -d ~/emsdk ] || git clone https://github.com/emscripten-core/emsdk.git ~/emsdk


+ 1
- 1
.github/workflows/dpf.yml View File

@@ -28,7 +28,7 @@ jobs:
strategy:
matrix:
target: [macos-intel, macos-universal, macos-universal-10.15]
runs-on: macos-12
runs-on: macos-13
steps:
- uses: actions/checkout@v4
with:


+ 50
- 0
.github/workflows/pylint.yml View File

@@ -0,0 +1,50 @@
name: pylint

on: [push]

jobs:
pyqt5:
runs-on: ubuntu-24.04
name: pyqt5
steps:
- uses: actions/checkout@v3
- name: Install deps
run: |
sudo apt install -yqq pyqt5-dev-tools python3-pyqt5 python3-pyqt5.qtsvg python3-virtualenv
virtualenv carla-env
source carla-env/bin/activate
pip3 install pylint pyqt5
- name: Build frontend
run: |
make FRONTEND_TYPE=5 frontend -j $(nproc)
- name: Run pylint
run: |
virtualenv carla-env
source carla-env/bin/activate
pylint -E --extension-pkg-whitelist=PyQt5 source/frontend/carla_app.py
pylint -E --extension-pkg-whitelist=PyQt5 source/frontend/carla_backend.py
pylint -E --extension-pkg-whitelist=PyQt5 source/frontend/carla_shared.py
pylint -E --extension-pkg-whitelist=PyQt5 source/frontend/carla_utils.py

pyqt6:
runs-on: ubuntu-24.04
name: pyqt6
steps:
- uses: actions/checkout@v3
- name: Install deps
run: |
sudo apt install -yqq pyqt6-dev-tools python3-pyqt6 python3-pyqt6.qtsvg python3-virtualenv
virtualenv carla-env
source carla-env/bin/activate
pip3 install pylint pyqt6
- name: Build frontend
run: |
make FRONTEND_TYPE=6 frontend -j $(nproc)
- name: Run pylint
run: |
virtualenv carla-env
source carla-env/bin/activate
pylint -E --extension-pkg-whitelist=PyQt6 source/frontend/carla_app.py
pylint -E --extension-pkg-whitelist=PyQt6 source/frontend/carla_backend.py
pylint -E --extension-pkg-whitelist=PyQt6 source/frontend/carla_shared.py
pylint -E --extension-pkg-whitelist=PyQt6 source/frontend/carla_utils.py

+ 17
- 53
.github/workflows/release.yml View File

@@ -3,22 +3,20 @@ name: release
on: [push, pull_request]

env:
CACHE_VERSION: 1
CACHE_VERSION: 4
DEBIAN_FRONTEND: noninteractive
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
PAWPAW_SKIP_LTO: 1
PAWPAW_SKIP_TESTS: 1
PAWPAW_VERSION: 9534e2b4f9bafc993e05fada89b824f3a2176708
PAWPAW_VERSION: 2606d0d436471b12902d60edd2aeb2390db44e62

jobs:
# macOS native universal build
macos_universal:
runs-on: macos-12
runs-on: macos-13
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up cache
uses: actions/cache@v4
with:
@@ -40,7 +38,7 @@ jobs:
run: |
source PawPaw/local.env macos-universal
make features
make EXTERNAL_PLUGINS=false NOOPT=true ${MAKE_ARGS}
make NOOPT=true ${MAKE_ARGS}
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1
@@ -62,39 +60,22 @@ jobs:

# linux with win32 cross-compilation
win32:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
container:
image: ubuntu:22.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up cache
uses: actions/cache@v4
with:
path: |
~/PawPawBuilds
key: win32-v${{ env.CACHE_VERSION }}
- name: Restore debian packages cache
run: |
if [ -d ~/PawPawBuilds/debs ] && [ "$(ls ~/PawPawBuilds/debs | wc -l)" -ne 0 ]; then \
sudo cp ~/PawPawBuilds/debs/*.deb /var/cache/apt/archives/; \
fi
- name: Fix GitHub's mess
run: |
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo dpkg --add-architecture i386
sudo apt-get update -qq
sudo apt-get install -yqq --allow-downgrades libc6:i386 libgcc-s1:i386 libstdc++6:i386
- name: Set up dependencies
run: |
sudo apt-get install -y build-essential curl cmake jq meson mingw-w64 gperf qttools5-dev qttools5-dev-tools xvfb \
binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 wine-stable
- name: Cache debian packages
run: |
mkdir -p ~/PawPawBuilds/debs
sudo mv /var/cache/apt/archives/*.deb ~/PawPawBuilds/debs/
- name: Bootstrap win32 cross-compiled
shell: bash
run: |
apt-get update -qq
apt-get install -yqq git unzip zip
git clone https://github.com/DISTRHO/PawPaw.git
git -C PawPaw checkout ${{ env.PAWPAW_VERSION }}
./PawPaw/.github/workflows/bootstrap-deps.sh win32
@@ -104,7 +85,7 @@ jobs:
run: |
source PawPaw/local.env win32
make features
make EXTERNAL_PLUGINS=false NOOPT=true ${MAKE_ARGS}
make NOOPT=true ${MAKE_ARGS}
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1
@@ -126,39 +107,22 @@ jobs:

# linux with win64 cross-compilation
win64:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
container:
image: ubuntu:22.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up cache
uses: actions/cache@v4
with:
path: |
~/PawPawBuilds
key: win64-v${{ env.CACHE_VERSION }}
- name: Restore debian packages cache
run: |
if [ -d ~/PawPawBuilds/debs ] && [ "$(ls ~/PawPawBuilds/debs | wc -l)" -ne 0 ]; then \
sudo cp ~/PawPawBuilds/debs/*.deb /var/cache/apt/archives/; \
fi
- name: Fix GitHub's mess
run: |
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo dpkg --add-architecture i386
sudo apt-get update -qq
sudo apt-get install -yqq --allow-downgrades libc6:i386 libgcc-s1:i386 libstdc++6:i386
- name: Set up dependencies
run: |
sudo apt-get install -y build-essential curl cmake jq meson mingw-w64 gperf qttools5-dev qttools5-dev-tools xvfb \
binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64 wine-stable
- name: Cache debian packages
run: |
mkdir -p ~/PawPawBuilds/debs
sudo mv /var/cache/apt/archives/*.deb ~/PawPawBuilds/debs/
- name: Bootstrap win64 cross-compiled
shell: bash
run: |
apt-get update -qq
apt-get install -yqq git unzip zip
git clone https://github.com/DISTRHO/PawPaw.git
git -C PawPaw checkout ${{ env.PAWPAW_VERSION }}
./PawPaw/.github/workflows/bootstrap-deps.sh win64
@@ -168,8 +132,8 @@ jobs:
run: |
source PawPaw/local.env win64
make features
make EXTERNAL_PLUGINS=false NOOPT=true ${MAKE_ARGS}
make EXTERNAL_PLUGINS=false NOOPT=true ${MAKE_ARGS} win32r
make NOOPT=true ${MAKE_ARGS}
make NOOPT=true ${MAKE_ARGS} win32r
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1
make dist ${MAKE_ARGS} TESTING=true -j 1


+ 5
- 50
Makefile View File

@@ -214,6 +214,11 @@ plugin-wine:
else
plugin-wine: $(MODULEDIR)/dgl.wine.a
@$(MAKE) -C source/plugin wine
ifeq ($(CPU_X86_64),true)
@$(MAKE) plugin-wine AR=x86_64-w64-mingw32-ar CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++
else ifeq ($(CPU_I386),true)
@$(MAKE) plugin-wine AR=i686-w64-mingw32-ar CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++
endif
endif

rest: libs
@@ -427,8 +432,6 @@ ifeq ($(HAVE_FRONTEND),true)
install -d $(DESTDIR)$(DATADIR)/mime/packages
install -d $(DESTDIR)$(DATADIR)/carla/resources/translations
install -d $(DESTDIR)$(DATADIR)/carla/common
install -d $(DESTDIR)$(DATADIR)/carla/dialogs
install -d $(DESTDIR)$(DATADIR)/carla/modgui
install -d $(DESTDIR)$(DATADIR)/carla/patchcanvas
install -d $(DESTDIR)$(DATADIR)/carla/utils
install -d $(DESTDIR)$(DATADIR)/carla/widgets
@@ -511,7 +514,6 @@ endif
source/backend/CarlaUtils.h \
source/backend/CarlaEngine.hpp \
source/backend/CarlaPlugin.hpp \
source/backend/CarlaPluginPtr.hpp \
$(DESTDIR)$(INCLUDEDIR)/carla

install -m 644 \
@@ -522,25 +524,6 @@ endif
$(DESTDIR)$(INCLUDEDIR)/carla/includes

install -m 644 \
source/utils/CarlaBackendUtils.hpp \
source/utils/CarlaBase64Utils.hpp \
source/utils/CarlaBinaryUtils.hpp \
source/utils/CarlaBridgeDefines.hpp \
source/utils/CarlaBridgeUtils.hpp \
source/utils/CarlaMacUtils.hpp \
source/utils/CarlaMathUtils.hpp \
source/utils/CarlaMemUtils.hpp \
source/utils/CarlaMutex.hpp \
source/utils/CarlaRingBuffer.hpp \
source/utils/CarlaProcessUtils.hpp \
source/utils/CarlaRunner.hpp \
source/utils/CarlaScopeUtils.hpp \
source/utils/CarlaSemUtils.hpp \
source/utils/CarlaSha1Utils.hpp \
source/utils/CarlaShmUtils.hpp \
source/utils/CarlaString.hpp \
source/utils/CarlaThread.hpp \
source/utils/CarlaTimeUtils.hpp \
source/utils/CarlaUtils.hpp \
$(DESTDIR)$(INCLUDEDIR)/carla/utils

@@ -582,14 +565,6 @@ ifeq ($(HAVE_LIBLO),true)
$(DESTDIR)$(BINDIR)/carla-control
endif

# Install the real modgui bridge
install -m 755 \
data/carla-bridge-lv2-modgui \
$(DESTDIR)$(LIBDIR)/carla

sed $(SED_ARGS) 's?X-PREFIX-X?$(PREFIX)?' \
$(DESTDIR)$(LIBDIR)/carla/carla-bridge-lv2-modgui

# Install frontend
install -m 644 \
source/frontend/carla \
@@ -605,14 +580,6 @@ endif
source/frontend/common/*.py \
$(DESTDIR)$(DATADIR)/carla/common/

install -m 644 \
source/frontend/dialogs/*.py \
$(DESTDIR)$(DATADIR)/carla/dialogs/

install -m 644 \
source/frontend/modgui/*.py \
$(DESTDIR)$(DATADIR)/carla/modgui/

install -m 644 \
source/frontend/patchcanvas/*.py \
$(DESTDIR)$(DATADIR)/carla/patchcanvas/
@@ -690,8 +657,6 @@ endif

# Install resources (re-use python files)
$(LINK) ../common $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) ../dialogs $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) ../modgui $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) ../patchcanvas $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) ../utils $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) ../widgets $(DESTDIR)$(DATADIR)/carla/resources
@@ -799,16 +764,6 @@ ifeq ($(HAVE_FRONTEND),true)
rm -rf $(DESTDIR)$(LIBDIR)/vst/carla.vst/styles
$(LINK) ../../carla/styles $(DESTDIR)$(LIBDIR)/vst/carla.vst/styles
endif
endif

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

ifneq ($(HAVE_FRONTEND),true)
# Remove gui files for non-gui build
rm $(DESTDIR)$(LIBDIR)/carla/carla-bridge-lv2-modgui
ifeq ($(CAN_GENERATE_LV2_TTL),true)
rm $(DESTDIR)$(LIBDIR)/lv2/carla.lv2/carla-bridge-lv2-modgui
endif
endif

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


+ 8
- 40
cmake/CMakeLists.txt View File

@@ -184,6 +184,11 @@ function(set_common_target_properties TARGET)
$<$<BOOL:${MSVC}>:/wd4273>
)

target_include_directories(${TARGET}
PRIVATE
../source/modules/distrho
)

target_link_options(${TARGET}
PRIVATE
$<$<C_COMPILER_ID:GNU>:-Wl,--no-undefined>
@@ -459,6 +464,7 @@ target_sources(carla-native-plugins
../source/native-plugins/bypass.c
../source/native-plugins/cv-to-audio.c
../source/native-plugins/lfo.c
../source/native-plugins/quadpanner.c
../source/native-plugins/midi-channel-filter.c
../source/native-plugins/midi-channel-ab.c
../source/native-plugins/midi-channelize.c
@@ -546,6 +552,7 @@ target_compile_options(carla-water
target_include_directories(carla-water
PRIVATE
../source/includes
../source/modules
../source/utils
)

@@ -581,6 +588,7 @@ target_compile_options(carla-water-files
target_include_directories(carla-water-files
PRIVATE
../source/includes
../source/modules
../source/utils
)

@@ -1228,7 +1236,6 @@ if(${CARLA_BUILD_FRAMEWORKS})
../source/backend/CarlaHost.h
../source/backend/CarlaEngine.hpp
../source/backend/CarlaPlugin.hpp
../source/backend/CarlaPluginPtr.hpp
)

set_target_properties(carla-standalone
@@ -1464,25 +1471,6 @@ if(${CARLA_BUILD_FRAMEWORKS})
DESTINATION ${CMAKE_INSTALL_LIBDIR}/carla-utils.framework/Versions/A/Headers/includes)

install(FILES
../source/utils/CarlaBackendUtils.hpp
../source/utils/CarlaBase64Utils.hpp
../source/utils/CarlaBinaryUtils.hpp
../source/utils/CarlaBridgeDefines.hpp
../source/utils/CarlaBridgeUtils.hpp
../source/utils/CarlaMacUtils.hpp
../source/utils/CarlaMathUtils.hpp
../source/utils/CarlaMemUtils.hpp
../source/utils/CarlaMutex.hpp
../source/utils/CarlaRingBuffer.hpp
../source/utils/CarlaProcessUtils.hpp
../source/utils/CarlaRunner.hpp
../source/utils/CarlaScopeUtils.hpp
../source/utils/CarlaSemUtils.hpp
../source/utils/CarlaSha1Utils.hpp
../source/utils/CarlaShmUtils.hpp
../source/utils/CarlaString.hpp
../source/utils/CarlaThread.hpp
../source/utils/CarlaTimeUtils.hpp
../source/utils/CarlaUtils.hpp
DESTINATION ${CMAKE_INSTALL_LIBDIR}/carla-utils.framework/Versions/A/Headers/utils)

@@ -1538,7 +1526,6 @@ set_property(TARGET carla-headers-backend
../source/backend/CarlaUtils.h
../source/backend/CarlaEngine.hpp
../source/backend/CarlaPlugin.hpp
../source/backend/CarlaPluginPtr.hpp
)

set_property(TARGET carla-headers-includes
@@ -1551,25 +1538,6 @@ set_property(TARGET carla-headers-includes

set_property(TARGET carla-headers-utils
PROPERTY PUBLIC_HEADER
../source/utils/CarlaBackendUtils.hpp
../source/utils/CarlaBase64Utils.hpp
../source/utils/CarlaBinaryUtils.hpp
../source/utils/CarlaBridgeDefines.hpp
../source/utils/CarlaBridgeUtils.hpp
../source/utils/CarlaMacUtils.hpp
../source/utils/CarlaMathUtils.hpp
../source/utils/CarlaMemUtils.hpp
../source/utils/CarlaMutex.hpp
../source/utils/CarlaRingBuffer.hpp
../source/utils/CarlaProcessUtils.hpp
../source/utils/CarlaRunner.hpp
../source/utils/CarlaScopeUtils.hpp
../source/utils/CarlaSemUtils.hpp
../source/utils/CarlaSha1Utils.hpp
../source/utils/CarlaShmUtils.hpp
../source/utils/CarlaString.hpp
../source/utils/CarlaThread.hpp
../source/utils/CarlaTimeUtils.hpp
../source/utils/CarlaUtils.hpp
)



+ 0
- 11
data/carla-bridge-lv2-modgui View File

@@ -1,11 +0,0 @@
#!/bin/sh

PYTHON=$(which python3 2>/dev/null)

if [ ! -f ${PYTHON} ]; then
PYTHON=python
fi

INSTALL_PREFIX="X-PREFIX-X"
export CARLA_LIB_PREFIX="$INSTALL_PREFIX"
exec $PYTHON "$INSTALL_PREFIX"/share/carla/carla_modgui.py "$@"

+ 2
- 2
data/macos/bundle.py View File

@@ -10,7 +10,7 @@ from os import getenv
# ------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)

from carla_host import VERSION
from carla_backend import CARLA_VERSION_STRING

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

@@ -31,7 +31,7 @@ if SCRIPT_NAME in ("Carla", "Carla-Control"):
boptions["custom_info_plist"] = "./data/macos/%s.plist" % SCRIPT_NAME

setup(name = "Carla",
version = VERSION,
version = CARLA_VERSION_STRING,
description = "Carla Plugin Host",
options = {"build_exe": options, "bdist_mac": boptions},
executables = [Executable("./source/frontend/%s" % SCRIPT_NAME)])


+ 23
- 13
data/update-dpf View File

@@ -11,18 +11,23 @@ DPF_DIR=/tmp/dpf-carla
rm -rf ${DPF_DIR}
git clone git@github.com:DISTRHO/DPF.git ${DPF_DIR} --depth=1 --recursive -b develop

cp -v ${DPF_DIR}/dgl/*.hpp ${CARLA_DIR}/source/modules/dgl/
cp -v ${DPF_DIR}/dgl/src/*.cpp ${CARLA_DIR}/source/modules/dgl/src/
cp -v ${DPF_DIR}/dgl/src/*.hpp ${CARLA_DIR}/source/modules/dgl/src/
cp -v ${DPF_DIR}/distrho/*.cpp ${CARLA_DIR}/source/modules/distrho/
cp -v ${DPF_DIR}/distrho/*.hpp ${CARLA_DIR}/source/modules/distrho/
cp -v ${DPF_DIR}/distrho/src/*.cpp ${CARLA_DIR}/source/modules/distrho/src/
cp -v ${DPF_DIR}/distrho/src/*.hpp ${CARLA_DIR}/source/modules/distrho/src/

cp -v ${DPF_DIR}/dgl/*.hpp ${CARLA_DIR}/source/modules/dgl/
cp -v ${DPF_DIR}/dgl/src/*.cpp ${CARLA_DIR}/source/modules/dgl/src/
cp -v ${DPF_DIR}/dgl/src/*.hpp ${CARLA_DIR}/source/modules/dgl/src/
cp -v ${DPF_DIR}/dgl/src/nanovg/*.* ${CARLA_DIR}/source/modules/dgl/src/nanovg/
cp -v ${DPF_DIR}/distrho/*.cpp ${CARLA_DIR}/source/modules/distrho/
cp -v ${DPF_DIR}/distrho/*.hpp ${CARLA_DIR}/source/modules/distrho/
cp -v ${DPF_DIR}/distrho/src/*.cpp ${CARLA_DIR}/source/modules/distrho/src/
cp -v ${DPF_DIR}/distrho/src/*.h ${CARLA_DIR}/source/modules/distrho/src/
cp -v ${DPF_DIR}/distrho/src/*.hpp ${CARLA_DIR}/source/modules/distrho/src/

cp -v ${DPF_DIR}/distrho/extra/Base64.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/LeakDetector.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/ScopedPointer.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/ScopedSafeLocale.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/Sleep.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/String.hpp ${CARLA_DIR}/source/modules/distrho/extra/
cp -v ${DPF_DIR}/distrho/extra/Time.hpp ${CARLA_DIR}/source/modules/distrho/extra/

cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/include ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/
cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/src ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/
@@ -31,20 +36,25 @@ cp -r -v ${DPF_DIR}/dgl/src/pugl-upstream/COPYING ${CARLA_DIR}/source/modules/dg

rm ${CARLA_DIR}/source/modules/dgl/Cairo.hpp
rm ${CARLA_DIR}/source/modules/dgl/FileBrowserDialog.hpp
rm ${CARLA_DIR}/source/modules/dgl/Layout.hpp
rm ${CARLA_DIR}/source/modules/dgl/Vulkan.hpp
rm ${CARLA_DIR}/source/modules/dgl/WebView.hpp
rm ${CARLA_DIR}/source/modules/dgl/src/Cairo.cpp
rm ${CARLA_DIR}/source/modules/dgl/src/Vulkan.cpp
rm ${CARLA_DIR}/source/modules/dgl/src/Layout.cpp
rm ${CARLA_DIR}/source/modules/dgl/src/Resources.{cpp,hpp}
rm ${CARLA_DIR}/source/modules/dgl/src/Stub.cpp
rm ${CARLA_DIR}/source/modules/dgl/src/Vulkan.cpp
rm ${CARLA_DIR}/source/modules/dgl/src/WebViewWin32.cpp

rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/src/.clang-tidy
rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/.clang-tidy
rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/meson.build
rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/pugl/cairo.h
rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/include/pugl/vulkan.h
rm ${CARLA_DIR}/source/modules/dgl/src/pugl-upstream/src/.clang-tidy

rm ${CARLA_DIR}/source/modules/distrho/DistrhoInfo.hpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPlugin{JACK,LADSPA+DSSI,LV2,LV2export,VST2,VST3}.cpp
rm ${CARLA_DIR}/source/modules/distrho/DistrhoUI_win32.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPlugin{AU,CLAP,Export,JACK,LADSPA+DSSI,LV2,LV2export,MAPI,Stub,VST2,VST3}.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoPluginVST.hpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoUI{DSSI,LV2,VST3}.cpp
rm ${CARLA_DIR}/source/modules/distrho/src/DistrhoUI{DSSI,LV2,Stub,VST3}.cpp

rm -rf ${DPF_DIR}

+ 0
- 33
data/update-juce View File

@@ -1,33 +0,0 @@
#!/bin/bash

set -e

cd $(dirname ${0})
cd ..

CARLA_DIR=$(pwd)
DISTRHO_PORTS_DIR=/tmp/distrho-ports-carla

rm -rf ${DISTRHO_PORTS_DIR}
git clone git@github.com:DISTRHO/DISTRHO-Ports.git ${DISTRHO_PORTS_DIR} --depth=1

CARLA_MODULES_DIR=${CARLA_DIR}/source/modules
JUCE_MODULES_DIR=${DISTRHO_PORTS_DIR}/libs/juce7/source/modules

MODULES=("juce_audio_basics juce_audio_devices juce_audio_formats juce_audio_processors juce_core juce_data_structures juce_dsp juce_events juce_graphics juce_gui_basics juce_gui_extra")

for M in ${MODULES}; do
echo ${CARLA_MODULES_DIR}/${M};
rm -f ${CARLA_MODULES_DIR}/${M}/juce_*
rm -rf ${CARLA_MODULES_DIR}/${M}/{a..z}*
cp -r -v ${JUCE_MODULES_DIR}/${M}/* ${CARLA_MODULES_DIR}/${M}/
rm ${CARLA_MODULES_DIR}/${M}/juce_*.mm
done

find ${CARLA_MODULES_DIR} -name juce_module_info -delete

rm -rf ${CARLA_MODULES_DIR}/../includes/vst3sdk
mv ${CARLA_MODULES_DIR}/juce_audio_processors/format_types/VST3_SDK ${CARLA_MODULES_DIR}/../includes/vst3sdk
rm -rf ${CARLA_MODULES_DIR}/../includes/vst3sdk/*.pdf

# rm -rf ${DISTRHO_PORTS_DIR}

+ 2
- 2
data/windows/app-gui.py View File

@@ -9,7 +9,7 @@ from cx_Freeze import setup, Executable
# ------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)

from carla_host import VERSION
from carla_backend import CARLA_VERSION_STRING
from os import getenv

# ------------------------------------------------------------------------------------------------------------
@@ -43,7 +43,7 @@ exe_options = {
}

setup(name = name,
version = VERSION,
version = CARLA_VERSION_STRING,
description = description,
options = {"build_exe": options},
executables = [Executable(**exe_options)])


+ 0
- 6
resources/ui/carla_settings.ui View File

@@ -1444,9 +1444,6 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Maximum number of parameters to allow in the built-in 'Edit' dialog</string>
</property>
<property name="minimum">
<number>1024</number>
</property>
@@ -1515,9 +1512,6 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Maximum number of parameters to allow in the built-in 'Edit' dialog</string>
</property>
<property name="minimum">
<number>1024</number>
</property>


+ 4
- 5
source/Makefile.mk View File

@@ -175,9 +175,6 @@ BASE_FLAGS += -DHAVE_DGL
BASE_FLAGS += -DHAVE_OPENGL
BASE_FLAGS += -DDGL_OPENGL
BASE_FLAGS += -DDONT_SET_USING_DGL_NAMESPACE
ifeq ($(USING_CUSTOM_DPF),true)
BASE_FLAGS += -DDISTRHO_UI_FILE_BROWSER=0
endif
ifneq ($(DGL_NAMESPACE),)
BASE_FLAGS += -DDGL_NAMESPACE=$(DGL_NAMESPACE)
else
@@ -185,9 +182,11 @@ BASE_FLAGS += -DDGL_NAMESPACE=CarlaDGL
endif
endif

ifneq ($(USING_CUSTOM_DPF),true)
BASE_FLAGS += -DDGL_FILE_BROWSER_DISABLED
ifeq ($(USING_CUSTOM_DPF),true)
BASE_FLAGS += -I$(CUSTOM_DPF_PATH)/distrho
else
BASE_FLAGS += -DDGL_NO_SHARED_RESOURCES
BASE_FLAGS += -I$(CWD)/modules/distrho
endif

ifeq ($(HAVE_FLUIDSYNTH),true)


+ 5
- 0
source/backend/CarlaBackend.h View File

@@ -210,6 +210,11 @@ static constexpr const uint PLUGIN_HAS_CUSTOM_UI_USING_FILE_OPEN = 0x2000;
*/
static constexpr const uint PLUGIN_NEEDS_MAIN_THREAD_IDLE = 0x4000;

/*!
* Plugin has its own custom UI which is user resizable.
*/
static constexpr const uint PLUGIN_HAS_CUSTOM_RESIZABLE_UI = 0x8000;

/** @} */

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


+ 2
- 2
source/backend/CarlaEngine.hpp View File

@@ -1,11 +1,11 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_ENGINE_HPP_INCLUDED
#define CARLA_ENGINE_HPP_INCLUDED

#include "CarlaBackend.h"
#include "CarlaPluginPtr.hpp"
#include "CarlaPlugin.hpp"

namespace water {
class MemoryOutputStream;


+ 4
- 2
source/backend/CarlaHostImpl.hpp View File

@@ -20,13 +20,15 @@

#include "CarlaHost.h"
#include "CarlaUtils.h"

#include "CarlaEngine.hpp"
#include "CarlaUtils.hpp"

#if !(defined(BUILD_BRIDGE) || defined(CARLA_OS_WASM))
# define CARLA_CAN_USE_LOG_THREAD
# include "CarlaLogThread.hpp"
#else
# include "CarlaString.hpp"
# include "extra/String.hpp"
#endif

namespace CB = CARLA_BACKEND_NAMESPACE;
@@ -64,7 +66,7 @@ struct CarlaHostStandalone : CarlaHostHandleImpl {
bool logThreadEnabled;
#endif

CarlaString lastError;
String lastError;

CarlaHostStandalone() noexcept
: CarlaHostHandleImpl(),


+ 6
- 2
source/backend/CarlaPlugin.hpp View File

@@ -1,11 +1,12 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_PLUGIN_HPP_INCLUDED
#define CARLA_PLUGIN_HPP_INCLUDED

#include "CarlaBackend.h"
#include "CarlaPluginPtr.hpp"

#include <memory>

// -----------------------------------------------------------------------
// Avoid including extra libs here
@@ -37,9 +38,12 @@ class CarlaEngineCVPort;
class CarlaEngineEventPort;
class CarlaEngineCVSourcePorts;
class CarlaEngineBridge;
class CarlaPlugin;
struct CarlaStateSave;
struct EngineEvent;

typedef std::shared_ptr<CarlaPlugin> CarlaPluginPtr;

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

/*!


+ 0
- 273
source/backend/CarlaPluginPtr.hpp View File

@@ -1,273 +0,0 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/

#ifndef CARLA_CPP_COMPAT_HPP_INCLUDED
#define CARLA_CPP_COMPAT_HPP_INCLUDED

#include "CarlaDefines.h"

#ifdef CARLA_PROPER_CPP11_SUPPORT
# include <memory>
#else
# include <algorithm>
# include "CarlaUtils.hpp"
#endif

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

#ifndef CARLA_PROPER_CPP11_SUPPORT
namespace std {

/* This code is part of shared_ptr.hpp:
* minimal implementation of smart pointer, a subset of the C++11 std::shared_ptr or boost::shared_ptr.
* Copyright (c) 2013-2019 Sebastien Rombauts (sebastien.rombauts@gmail.com)
* Distributed under the MIT License (MIT)
*/
class shared_ptr_count
{
public:
shared_ptr_count() : pn(nullptr) {}
shared_ptr_count(const shared_ptr_count& count) : pn(count.pn) {}
void swap(shared_ptr_count& lhs) noexcept { std::swap(pn, lhs.pn); }

long use_count(void) const noexcept
{
long count = 0;
if (nullptr != pn)
{
count = *pn;
}
return count;
}

template<class U>
void acquire(U* p)
{
if (nullptr != p)
{
if (nullptr == pn)
{
try
{
pn = new volatile long(1);
}
catch (std::bad_alloc&)
{
delete p;
throw;
}
}
else
{
++(*pn);
}
}
}

template<class U>
void release(U* p) noexcept
{
if (nullptr != pn)
{
--(*pn);
if (0 == *pn)
{
delete p;
delete pn;
}
pn = nullptr;
}
}

public:
volatile long* pn;
};

template<class T>
class shared_ptr
{
public:
typedef T element_type;

shared_ptr(void) noexcept
: px(nullptr),
pn() {}

/*explicit*/ shared_ptr(T* p)
: px(nullptr),
pn()
{
acquire(p);
}

template <class U>
shared_ptr(const shared_ptr<U>& ptr, T* p) :
px(nullptr),
pn(ptr.pn)
{
acquire(p);
}

template <class U>
shared_ptr(const shared_ptr<U>& ptr) noexcept :
px(nullptr),
pn(ptr.pn)
{
CARLA_SAFE_ASSERT_RETURN(nullptr == ptr.px || 0 != ptr.pn.use_count(),);
acquire(static_cast<typename shared_ptr<T>::element_type*>(ptr.px));
}

shared_ptr(const shared_ptr& ptr) noexcept :
px(nullptr),
pn(ptr.pn)
{
CARLA_SAFE_ASSERT_RETURN(nullptr == ptr.px || 0 != ptr.pn.use_count(),);
acquire(ptr.px);
}

shared_ptr& operator=(shared_ptr ptr) noexcept
{
swap(ptr);
return *this;
}

~shared_ptr(void) noexcept
{
release();
}

void reset(void) noexcept
{
release();
}

void swap(shared_ptr& lhs) noexcept
{
std::swap(px, lhs.px);
pn.swap(lhs.pn);
}

operator bool() const noexcept
{
return (0 < pn.use_count());
}
long use_count(void) const noexcept
{
return pn.use_count();
}

// underlying pointer operations :
T& operator*() const noexcept
{
return *px;
}
T* operator->() const noexcept
{
return px;
}
T* get(void) const noexcept
{
return px;
}

private:
void acquire(T* p)
{
pn.acquire(p);
px = p;
}

void release(void) noexcept
{
pn.release(px);
px = nullptr;
}

private:
template<class U>
friend class shared_ptr;

private:
T* px;
shared_ptr_count pn;
};

template<class T, class U> bool operator==(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() == r.get());
}
template<class T, class U> bool operator!=(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() != r.get());
}
template<class T, class U> bool operator<=(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() <= r.get());
}
template<class T, class U> bool operator<(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() < r.get());
}
template<class T, class U> bool operator>=(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() >= r.get());
}
template<class T, class U> bool operator>(const shared_ptr<T>& l, const shared_ptr<U>& r) noexcept
{
return (l.get() > r.get());
}
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& ptr)
{
return shared_ptr<T>(ptr, static_cast<typename shared_ptr<T>::element_type*>(ptr.get()));
}
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& ptr)
{
T* p = dynamic_cast<typename shared_ptr<T>::element_type*>(ptr.get());
if (nullptr != p)
{
return shared_ptr<T>(ptr, p);
}
else
{
return shared_ptr<T>();
}
}
template<class T>
bool operator==(const shared_ptr<T>& pointer1, T* const pointer2) noexcept
{
return static_cast<T*>(pointer1) == pointer2;
}
template<class T>
bool operator!=(const shared_ptr<T>& pointer1, T* const pointer2) noexcept
{
return static_cast<T*>(pointer1) != pointer2;
}

} // namespace std
#endif // CARLA_PROPER_CPP11_SUPPORT

CARLA_BACKEND_START_NAMESPACE

typedef std::shared_ptr<CarlaPlugin> CarlaPluginPtr;

CARLA_BACKEND_END_NAMESPACE

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

#endif // CARLA_CPP_COMPAT_HPP_INCLUDED

+ 13
- 10
source/backend/CarlaStandalone.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

// TODO:
@@ -11,9 +11,11 @@
#include "CarlaPlugin.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "ThreadSafeFFTW.hpp"

#include "extra/Base64.hpp"
#include "extra/ScopedPointer.hpp"

#include "water/files/File.h"

#define CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(cond, msg, ret) \
@@ -455,10 +457,10 @@ bool carla_engine_init_bridge(CarlaHostHandle handle,
CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->isStandalone, "Must be a standalone host handle", false);
CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(handle->engine == nullptr, "Engine is already initialized", false);

CarlaScopedPointer<CarlaEngine> engine(CB::EngineInit::newBridge(audioBaseName,
rtClientBaseName,
nonRtClientBaseName,
nonRtServerBaseName));
ScopedPointer<CarlaEngine> engine(CB::EngineInit::newBridge(audioBaseName,
rtClientBaseName,
nonRtClientBaseName,
nonRtServerBaseName));

CARLA_SAFE_ASSERT_WITH_LAST_ERROR_RETURN(engine != nullptr, "The selected audio driver is not available", false);

@@ -1725,7 +1727,7 @@ const char* carla_get_custom_data_value(CarlaHostHandle handle, uint pluginId, c
if (count == 0)
return gNullCharPtr;

static CarlaString customDataValue;
static String customDataValue;

for (uint32_t i=0; i<count; ++i)
{
@@ -1756,9 +1758,9 @@ const char* carla_get_chunk_data(CarlaHostHandle handle, uint pluginId)
const std::size_t dataSize(plugin->getChunkData(&data));
CARLA_SAFE_ASSERT_RETURN(data != nullptr && dataSize > 0, gNullCharPtr);

static CarlaString chunkData;
static String chunkData;

chunkData = CarlaString::asBase64(data, static_cast<std::size_t>(dataSize));
chunkData = String::asBase64(data, static_cast<std::size_t>(dataSize));
return chunkData.buffer();
}

@@ -2218,7 +2220,8 @@ void carla_set_chunk_data(CarlaHostHandle handle, uint pluginId, const char* chu
{
CARLA_SAFE_ASSERT_RETURN(plugin->getOptionsEnabled() & CB::PLUGIN_OPTION_USE_CHUNKS,);

std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkData));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, chunkData);
#ifdef CARLA_PROPER_CPP11_SUPPORT
plugin->setChunkData(chunk.data(), chunk.size());
#else


+ 8
- 9
source/backend/CarlaStandaloneNSM.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaHostImpl.hpp"
@@ -14,7 +14,6 @@
#define NSM_CLIENT_FEATURES ":switch:optional-gui:"

#include "CarlaOscUtils.hpp"
#include "CarlaString.hpp"

#include "water/files/File.h"

@@ -289,7 +288,7 @@ protected:
projectPath);

for (; ! fReadyActionOpen;)
carla_msleep(10);
d_msleep(10);
}
else
{
@@ -343,7 +342,7 @@ protected:
0, 0, 0.0f, nullptr);

for (; ! fReadyActionSave;)
carla_msleep(10);
d_msleep(10);
}
else
{
@@ -471,7 +470,7 @@ protected:
const CarlaPluginInfo* const pluginInfo(carla_get_plugin_info(i));
CARLA_SAFE_ASSERT_CONTINUE(pluginInfo != nullptr);

/*const*/ CarlaString pluginNameId(fClientNameId + "/" + CarlaString(pluginInfo->name).replace('/','_') + "/");
/*const*/ String pluginNameId(fClientNameId + "/" + String(pluginInfo->name).replace('/','_') + "/");

for (uint32_t j=0, paramCount = carla_get_parameter_count(i); j < paramCount; ++j)
{
@@ -493,8 +492,8 @@ protected:
if (paramData->hints & CB::PARAMETER_IS_READ_ONLY)
continue;

const char* const dir = paramData->type == CB::PARAMETER_INPUT ? "in" : "out";
const CarlaString paramNameId = pluginNameId + CarlaString(paramInfo->name).replace('/','_');
const char* const dir = paramData->type == CB::PARAMETER_INPUT ? "in" : "out";
const String paramNameId = pluginNameId + String(paramInfo->name).replace('/','_');

const float defNorm = paramRanges->getNormalizedValue(paramRanges->def);

@@ -530,8 +529,8 @@ private:
lo_server_thread fServerThread;
char* fServerURL;

CarlaString fClientNameId;
CarlaString fProjectPath;
String fClientNameId;
String fProjectPath;

bool fHasBroadcast;
bool fHasOptionalGui;


+ 41
- 42
source/backend/engine/CarlaEngine.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

/* TODO:
@@ -46,7 +46,6 @@ using water::Array;
using water::CharPointer_UTF8;
using water::File;
using water::MemoryOutputStream;
using water::String;
using water::StringArray;
using water::XmlDocument;
using water::XmlElement;
@@ -535,7 +534,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype,
};

CarlaPluginPtr plugin;
CarlaString bridgeBinary(pData->options.binaryDir);
String bridgeBinary(pData->options.binaryDir);

if (bridgeBinary.isNotEmpty())
{
@@ -1131,19 +1130,19 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) const
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr);
carla_debug("CarlaEngine::getUniquePluginName(\"%s\")", name);

CarlaString sname;
String sname;
sname = name;

if (sname.isEmpty())
{
sname = "(No name)";
return sname.dup();
return carla_strdup(sname);
}

const std::size_t maxNameSize(carla_minConstrained<uint>(getMaxClientNameSize(), 0xff, 6U) - 6); // 6 = strlen(" (10)") + 1

if (maxNameSize == 0 || ! isRunning())
return sname.dup();
return carla_strdup(sname);

sname.truncate(maxNameSize);
sname.replace(':', '.'); // ':' is used in JACK1 to split client/port names
@@ -1208,7 +1207,7 @@ const char* CarlaEngine::getUniquePluginName(const char* const name) const
sname += " (2)";
}

return sname.dup();
return carla_strdup(sname);
}

// -----------------------------------------------------------------------
@@ -1223,8 +1222,8 @@ bool CarlaEngine::loadFile(const char* const filename)
File file(filename);
CARLA_SAFE_ASSERT_RETURN_ERR(file.exists(), "Requested file does not exist or is not a readable");

CarlaString baseName(file.getFileNameWithoutExtension().toRawUTF8());
CarlaString extension(file.getFileExtension().replace(".","").toLowerCase().toRawUTF8());
String baseName(file.getFileNameWithoutExtension().toRawUTF8());
String extension(file.getFileExtension().replace(".","").toLowerCase().toRawUTF8());

const uint curPluginId(pData->nextPluginId < pData->curPluginCount ? pData->nextPluginId : pData->curPluginCount);

@@ -1331,7 +1330,7 @@ bool CarlaEngine::loadFile(const char* const filename)
if (extension == "xmz" || extension == "xiz")
{
#ifdef HAVE_ZYN_DEPS
CarlaString nicerName("Zyn - ");
String nicerName("Zyn - ");

const std::size_t sep(baseName.find('-')+1);

@@ -2110,7 +2109,7 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch

if (value != 0)
{
CarlaString interposerPath(CarlaString(pData->options.binaryDir) + "/libcarla_interposer-safe.so");
String interposerPath(String(pData->options.binaryDir) + "/libcarla_interposer-safe.so");
::setenv("LD_PRELOAD", interposerPath.buffer(), 1);
}
else
@@ -2367,8 +2366,8 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons
outSettings << " <PreferUiBridges>" << bool2str(options.preferUiBridges) << "</PreferUiBridges>\n";
outSettings << " <UIsAlwaysOnTop>" << bool2str(options.uisAlwaysOnTop) << "</UIsAlwaysOnTop>\n";

outSettings << " <MaxParameters>" << String(options.maxParameters) << "</MaxParameters>\n";
outSettings << " <UIBridgesTimeout>" << String(options.uiBridgesTimeout) << "</UIBridgesTimeout>\n";
outSettings << " <MaxParameters>" << water::String(options.maxParameters) << "</MaxParameters>\n";
outSettings << " <UIBridgesTimeout>" << water::String(options.uiBridgesTimeout) << "</UIBridgesTimeout>\n";

if (isPlugin)
{
@@ -2585,12 +2584,12 @@ void CarlaEngine::saveProjectInternal(water::MemoryOutputStream& outStream) cons
outStream << "</CARLA-PROJECT>\n";
}

static String findBinaryInCustomPath(const char* const searchPath, const char* const binary)
static water::String findBinaryInCustomPath(const char* const searchPath, const char* const binary)
{
const StringArray searchPaths(StringArray::fromTokens(searchPath, CARLA_OS_SPLIT_STR, ""));

// try direct filename first
String jbinary(binary);
water::String jbinary(binary);

// adjust for current platform
#ifdef CARLA_OS_WIN
@@ -2601,7 +2600,7 @@ static String findBinaryInCustomPath(const char* const searchPath, const char* c
jbinary = jbinary.substring(2).replaceCharacter('\\', '/');
#endif

String filename = File(jbinary.toRawUTF8()).getFileName();
water::String filename = File(jbinary.toRawUTF8()).getFileName();

int searchFlags = File::findFiles|File::ignoreHiddenFiles;

@@ -2613,7 +2612,7 @@ static String findBinaryInCustomPath(const char* const searchPath, const char* c
#endif

std::vector<File> results;
for (const String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
for (const water::String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
{
const File path(it->toRawUTF8());

@@ -2636,9 +2635,9 @@ static String findBinaryInCustomPath(const char* const searchPath, const char* c
filename = File(jbinary.toRawUTF8()).getFileNameWithoutExtension() + ".so";
#endif
else
return String();
return {};

for (const String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
for (const water::String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
{
const File path(it->toRawUTF8());

@@ -2649,17 +2648,17 @@ static String findBinaryInCustomPath(const char* const searchPath, const char* c
return results.front().getFullPathName();
}

return String();
return {};
}

bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alwaysLoadConnections)
{
carla_debug("CarlaEngine::loadProjectInternal(%p, %s) - START", &xmlDoc, bool2str(alwaysLoadConnections));

CarlaScopedPointer<XmlElement> xmlElement(xmlDoc.getDocumentElement(true));
ScopedPointer<XmlElement> xmlElement(xmlDoc.getDocumentElement(true));
CARLA_SAFE_ASSERT_RETURN_ERR(xmlElement != nullptr, "Failed to parse project file");

const String& xmlType(xmlElement->getTagName());
const water::String& xmlType(xmlElement->getTagName());
const bool isPreset(xmlType.equalsIgnoreCase("carla-preset"));

if (! (xmlType.equalsIgnoreCase("carla-project") || isPreset))
@@ -2713,8 +2712,8 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
{
for (XmlElement* settElem = elem->getFirstChildElement(); settElem != nullptr; settElem = settElem->getNextElement())
{
const String& tag(settElem->getTagName());
const String text(settElem->getAllSubText().trim());
const water::String& tag(settElem->getTagName());
const water::String text(settElem->getAllSubText().trim());

/** some settings might be incorrect or require extra work,
so we call setOption rather than modifying them direly */
@@ -2847,7 +2846,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
{
if (XmlElement* const bpmElem = elem->getChildByName("BeatsPerMinute"))
{
const String bpmText(bpmElem->getAllSubText().trim());
const water::String bpmText(bpmElem->getAllSubText().trim());
const double bpm = bpmText.getDoubleValue();

// some sane limits
@@ -2868,7 +2867,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
// and we handle plugins
for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{
const String& tagName(elem->getTagName());
const water::String& tagName(elem->getTagName());

if (isPreset || tagName == "Plugin")
{
@@ -2906,7 +2905,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
return false;
}

String lsState;
water::String lsState;
lsState << "0.35\n";
lsState << "18 0 Chromatic\n";
lsState << "18 1 Drum Kits\n";
@@ -3013,7 +3012,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
switch (ptype)
{
case PLUGIN_SF2:
if (CarlaString(stateSave.label).endsWith(" (16 outs)"))
if (String(stateSave.label).endsWith(" (16 outs)"))
extraStuff = kTrue;
// fall through
case PLUGIN_LADSPA:
@@ -3046,7 +3045,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
carla_stderr("Plugin binary '%s' doesn't exist on this filesystem, let's look for it...",
stateSave.binary);

String result = findBinaryInCustomPath(searchPath, stateSave.binary);
water::String result = findBinaryInCustomPath(searchPath, stateSave.binary);

if (result.isEmpty())
{
@@ -3198,12 +3197,12 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

if (XmlElement* const elemPositions = elemPatchbay->getChildByName("Positions"))
{
String name;
water::String name;
PatchbayPosition ppos = { nullptr, -1, 0, 0, 0, 0, false };

for (XmlElement* patchElem = elemPositions->getFirstChildElement(); patchElem != nullptr; patchElem = patchElem->getNextElement())
{
const String& patchTag(patchElem->getTagName());
const water::String& patchTag(patchElem->getTagName());

if (patchTag != "Position")
continue;
@@ -3211,7 +3210,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
XmlElement* const patchName = patchElem->getChildByName("Name");
CARLA_SAFE_ASSERT_CONTINUE(patchName != nullptr);

const String nameText(patchName->getAllSubText().trim());
const water::String nameText(patchName->getAllSubText().trim());
name = xmlSafeString(nameText, false);

ppos.name = name.toRawUTF8();
@@ -3256,12 +3255,12 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
{
if (XmlElement* const elemPositions = elemPatchbay->getChildByName("Positions"))
{
String name;
water::String name;
PatchbayPosition ppos = { nullptr, -1, 0, 0, 0, 0, false };

for (XmlElement* patchElem = elemPositions->getFirstChildElement(); patchElem != nullptr; patchElem = patchElem->getNextElement())
{
const String& patchTag(patchElem->getTagName());
const water::String& patchTag(patchElem->getTagName());

if (patchTag != "Position")
continue;
@@ -3269,7 +3268,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw
XmlElement* const patchName = patchElem->getChildByName("Name");
CARLA_SAFE_ASSERT_CONTINUE(patchName != nullptr);

const String nameText(patchName->getAllSubText().trim());
const water::String nameText(patchName->getAllSubText().trim());
name = xmlSafeString(nameText, false);

ppos.name = name.toRawUTF8();
@@ -3327,7 +3326,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

for (XmlElement* patchElem = elem->getFirstChildElement(); patchElem != nullptr; patchElem = patchElem->getNextElement())
{
const String& patchTag(patchElem->getTagName());
const water::String& patchTag(patchElem->getTagName());

if (patchTag != "Connection")
continue;
@@ -3337,8 +3336,8 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

for (XmlElement* connElem = patchElem->getFirstChildElement(); connElem != nullptr; connElem = connElem->getNextElement())
{
const String& tag(connElem->getTagName());
const String text(connElem->getAllSubText().trim());
const water::String& tag(connElem->getTagName());
const water::String text(connElem->getAllSubText().trim());

/**/ if (tag == "Source")
sourcePort = xmlSafeString(text, false);
@@ -3401,7 +3400,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

for (XmlElement* elem = xmlElement->getFirstChildElement(); elem != nullptr; elem = elem->getNextElement())
{
const String& tagName(elem->getTagName());
const water::String& tagName(elem->getTagName());

// check if we want to load patchbay-mode connections into an external (multi-client) graph
if (tagName == "Patchbay")
@@ -3427,7 +3426,7 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

for (XmlElement* patchElem = elem->getFirstChildElement(); patchElem != nullptr; patchElem = patchElem->getNextElement())
{
const String& patchTag(patchElem->getTagName());
const water::String& patchTag(patchElem->getTagName());

if (patchTag != "Connection")
continue;
@@ -3437,8 +3436,8 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc, const bool alw

for (XmlElement* connElem = patchElem->getFirstChildElement(); connElem != nullptr; connElem = connElem->getNextElement())
{
const String& tag(connElem->getTagName());
const String text(connElem->getAllSubText().trim());
const water::String& tag(connElem->getTagName());
const water::String text(connElem->getAllSubText().trim());

/**/ if (tag == "Source")
sourcePort = xmlSafeString(text, false);


+ 21
- 20
source/backend/engine/CarlaEngineBridge.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef BUILD_BRIDGE
@@ -16,15 +16,16 @@
#include "CarlaEngineInit.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "CarlaBridgeUtils.hpp"
#include "CarlaTimeUtils.hpp"
#include "CarlaMIDI.h"

#ifdef __SSE2_MATH__
# include <xmmintrin.h>
#endif

#include "extra/Base64.hpp"
#include "extra/Time.hpp"

#include "water/files/File.h"
#include "water/misc/Time.h"

@@ -33,7 +34,6 @@

using water::File;
using water::MemoryBlock;
using water::String;

CARLA_BACKEND_START_NAMESPACE

@@ -368,7 +368,7 @@ public:
if (wasFirstIdle)
{
fFirstIdle = false;
fLastPingTime = carla_gettime_ms();
fLastPingTime = d_gettime_ms();

char bufStr[STR_MAX+1];
carla_zeroChars(bufStr, STR_MAX+1);
@@ -643,7 +643,7 @@ public:
fShmNonRtServerControl.waitIfDataIsReachingLimit();

carla_stdout("Carla Bridge Ready!");
fLastPingTime = carla_gettime_ms();
fLastPingTime = d_gettime_ms();
}

// send parameter outputs
@@ -672,7 +672,7 @@ public:
handleNonRtData();
} CARLA_SAFE_EXCEPTION("handleNonRtData");

if (fLastPingTime != UINT32_MAX && carla_gettime_ms() > fLastPingTime + 30000 && ! wasFirstIdle)
if (fLastPingTime != UINT32_MAX && d_gettime_ms() > fLastPingTime + 30000 && ! wasFirstIdle)
{
carla_stderr("Did not receive ping message from server for 30 secs, closing...");
signalThreadShouldExit();
@@ -811,7 +811,7 @@ public:

if (opcode != kPluginBridgeNonRtClientNull &&
opcode != kPluginBridgeNonRtClientPingOnOff && fLastPingTime != UINT32_MAX)
fLastPingTime = carla_gettime_ms();
fLastPingTime = d_gettime_ms();

switch (opcode)
{
@@ -832,7 +832,7 @@ public:
} break;

case kPluginBridgeNonRtClientPingOnOff:
fLastPingTime = fShmNonRtClientControl.readBool() ? carla_gettime_ms() : UINT32_MAX;
fLastPingTime = fShmNonRtClientControl.readBool() ? d_gettime_ms() : UINT32_MAX;
break;

case kPluginBridgeNonRtClientActivate:
@@ -925,7 +925,7 @@ public:
CARLA_SAFE_ASSERT_BREAK(bigValueFilePathTry.text[0] != '\0');
if (! plugin->isEnabled()) break;

String bigValueFilePath(bigValueFilePathTry.text);
water::String bigValueFilePath(bigValueFilePathTry.text);

#ifdef CARLA_OS_WIN
// check if running under Wine
@@ -966,7 +966,7 @@ public:
CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry.text[0] != '\0');
if (! plugin->isEnabled()) break;

String chunkFilePath(chunkFilePathTry.text);
water::String chunkFilePath(chunkFilePathTry.text);

#ifdef CARLA_OS_WIN
// check if running under Wine
@@ -977,11 +977,12 @@ public:
File chunkFile(chunkFilePath.toRawUTF8());
CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());

String chunkDataBase64(chunkFile.loadFileAsString());
water::String chunkDataBase64(chunkFile.loadFileAsString());
chunkFile.deleteFile();
CARLA_SAFE_ASSERT_BREAK(chunkDataBase64.isNotEmpty());

std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkDataBase64.toRawUTF8()));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, chunkDataBase64.toRawUTF8());

#ifdef CARLA_PROPER_CPP11_SUPPORT
plugin->setChunkData(chunk.data(), chunk.size());
@@ -1103,7 +1104,7 @@ public:
{
if (valueLen > maxLocalValueLen)
{
String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
water::String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());

filePath += CARLA_OS_SEP_STR ".CarlaCustomData_";
filePath += fShmAudioPool.getFilenameSuffix();
@@ -1138,10 +1139,10 @@ public:
{
CARLA_SAFE_ASSERT_BREAK(data != nullptr);

CarlaString dataBase64 = CarlaString::asBase64(data, dataSize);
String dataBase64 = String::asBase64(data, dataSize);
CARLA_SAFE_ASSERT_BREAK(dataBase64.length() > 0);

String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
water::String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());

filePath += CARLA_OS_SEP_STR ".CarlaChunk_";
filePath += fShmAudioPool.getFilenameSuffix();
@@ -1664,10 +1665,10 @@ private:
BridgeNonRtClientControl fShmNonRtClientControl;
BridgeNonRtServerControl fShmNonRtServerControl;

CarlaString fBaseNameAudioPool;
CarlaString fBaseNameRtClientControl;
CarlaString fBaseNameNonRtClientControl;
CarlaString fBaseNameNonRtServerControl;
String fBaseNameAudioPool;
String fBaseNameRtClientControl;
String fBaseNameNonRtClientControl;
String fBaseNameNonRtServerControl;

bool fClosingDown;
bool fIsOffline;


+ 5
- 21
source/backend/engine/CarlaEngineClient.cpp View File

@@ -1,30 +1,14 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineClient.hpp"
#include "CarlaEngineUtils.hpp"

#include "CarlaString.hpp"

CARLA_BACKEND_START_NAMESPACE

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

static void _getUniquePortName(CarlaString& sname, const CarlaStringList& list)
static void _getUniquePortName(String& sname, const CarlaStringList& list)
{
for (CarlaStringList::Itenerator it = list.begin2(); it.valid(); it.next())
{
@@ -144,7 +128,7 @@ const char* CarlaEngineClient::ProtectedData::getUniquePortName(const char* cons
{
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr);

CarlaString sname;
String sname;
sname = name;

_getUniquePortName(sname, audioInList);
@@ -154,7 +138,7 @@ const char* CarlaEngineClient::ProtectedData::getUniquePortName(const char* cons
_getUniquePortName(sname, eventInList);
_getUniquePortName(sname, eventOutList);

return sname.dup();
return carla_strdup(sname);
}

void CarlaEngineClient::ProtectedData::clearPorts()


+ 2
- 16
source/backend/engine/CarlaEngineClient.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_ENGINE_CLIENT_HPP_INCLUDED
#define CARLA_ENGINE_CLIENT_HPP_INCLUDED


+ 8
- 21
source/backend/engine/CarlaEngineDummy.cpp View File

@@ -1,24 +1,11 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the GPL.txt file
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineGraph.hpp"
#include "CarlaEngineInit.hpp"
#include "CarlaEngineInternal.hpp"
#include "CarlaTimeUtils.hpp"

#include "extra/Time.hpp"

CARLA_BACKEND_START_NAMESPACE

@@ -227,9 +214,9 @@ protected:
while (! shouldThreadExit())
{
if (delay > 0)
carla_sleep(static_cast<uint>(delay));
d_sleep(static_cast<uint>(delay));

oldTime = carla_gettime_us();
oldTime = d_gettime_us();

const PendingRtEventsRunner prt(this, bufferSize, true);

@@ -239,7 +226,7 @@ protected:

pData->graph.process(pData, audioIns, audioOuts, bufferSize);

newTime = carla_gettime_us();
newTime = d_gettime_us();
CARLA_SAFE_ASSERT_CONTINUE(newTime >= oldTime);

const int64_t remainingTime = cycleTime - (newTime - oldTime);
@@ -253,7 +240,7 @@ protected:
else if (remainingTime >= 1000)
{
CARLA_SAFE_ASSERT_CONTINUE(remainingTime < 1000000); // 1 sec
carla_msleep(static_cast<uint>(remainingTime / 1000));
d_msleep(static_cast<uint>(remainingTime / 1000));
}
}



+ 38
- 54
source/backend/engine/CarlaEngineGraph.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineGraph.hpp"
#include "CarlaEngineInternal.hpp"
@@ -28,8 +14,6 @@ using water::jmax;
using water::jmin;
using water::AudioProcessor;
using water::MidiBuffer;
using water::String;
using water::StringArray;

#define MAX_GRAPH_AUDIO_IO 64U
#define MAX_GRAPH_CV_IO 32U
@@ -442,7 +426,7 @@ void ExternalGraph::refresh(const bool sendHost, const bool sendOSC, const char*
0, 0.0f,
strBuf);

const CarlaString groupNameIn(strBuf);
const String groupNameIn(strBuf);

for (LinkedList<PortNameToId>::Itenerator it = audioPorts.ins.begin2(); it.valid(); it.next())
{
@@ -474,7 +458,7 @@ void ExternalGraph::refresh(const bool sendHost, const bool sendOSC, const char*
0, 0.0f,
strBuf);

const CarlaString groupNameOut(strBuf);
const String groupNameOut(strBuf);

for (LinkedList<PortNameToId>::Itenerator it = audioPorts.outs.begin2(); it.valid(); it.next())
{
@@ -503,7 +487,7 @@ void ExternalGraph::refresh(const bool sendHost, const bool sendOSC, const char*
0, 0.0f,
"Readable MIDI ports");

const CarlaString groupNamePlus("Readable MIDI ports:");
const String groupNamePlus("Readable MIDI ports:");

for (LinkedList<PortNameToId>::Itenerator it = midiPorts.ins.begin2(); it.valid(); it.next())
{
@@ -532,7 +516,7 @@ void ExternalGraph::refresh(const bool sendHost, const bool sendOSC, const char*
0, 0.0f,
"Writable MIDI ports");

const CarlaString groupNamePlus("Writable MIDI ports:");
const String groupNamePlus("Writable MIDI ports:");

for (LinkedList<PortNameToId>::Itenerator it = midiPorts.outs.begin2(); it.valid(); it.next())
{
@@ -1271,53 +1255,53 @@ bool adjustPatchbayPortIdForWater(AudioProcessor::ChannelType& channelType, uint
}

static inline
const String getProcessorFullPortName(AudioProcessor* const proc, const uint32_t portId)
const water::String getProcessorFullPortName(AudioProcessor* const proc, const uint32_t portId)
{
CARLA_SAFE_ASSERT_RETURN(proc != nullptr, String());
CARLA_SAFE_ASSERT_RETURN(portId >= kAudioInputPortOffset, String());
CARLA_SAFE_ASSERT_RETURN(portId < kMaxPortOffset, String());
CARLA_SAFE_ASSERT_RETURN(proc != nullptr, {});
CARLA_SAFE_ASSERT_RETURN(portId >= kAudioInputPortOffset, {});
CARLA_SAFE_ASSERT_RETURN(portId < kMaxPortOffset, {});

String fullPortName(proc->getName());
water::String fullPortName(proc->getName());

/**/ if (portId >= kMidiOutputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeMIDI) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeMIDI) > 0, {});
fullPortName += ":" + proc->getOutputChannelName(AudioProcessor::ChannelTypeMIDI,
portId-kMidiOutputPortOffset);
}
else if (portId >= kMidiInputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeMIDI) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeMIDI) > 0, {});
fullPortName += ":" + proc->getInputChannelName(AudioProcessor::ChannelTypeMIDI,
portId-kMidiInputPortOffset);
}
else if (portId >= kCVOutputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeCV) > 0, {});
fullPortName += ":" + proc->getOutputChannelName(AudioProcessor::ChannelTypeCV,
portId-kCVOutputPortOffset);
}
else if (portId >= kCVInputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeCV) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeCV) > 0, {});
fullPortName += ":" + proc->getInputChannelName(AudioProcessor::ChannelTypeCV,
portId-kCVInputPortOffset);
}
else if (portId >= kAudioOutputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumOutputChannels(AudioProcessor::ChannelTypeAudio) > 0, {});
fullPortName += ":" + proc->getOutputChannelName(AudioProcessor::ChannelTypeAudio,
portId-kAudioOutputPortOffset);
}
else if (portId >= kAudioInputPortOffset)
{
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeAudio) > 0, String());
CARLA_SAFE_ASSERT_RETURN(proc->getTotalNumInputChannels(AudioProcessor::ChannelTypeAudio) > 0, {});
fullPortName += ":" + proc->getInputChannelName(AudioProcessor::ChannelTypeAudio,
portId-kAudioInputPortOffset);
}
else
{
return String();
return {};
}

return fullPortName;
@@ -1539,10 +1523,10 @@ public:

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

const String getName() const override
const water::String getName() const override
{
const CarlaPluginPtr plugin = fPlugin;
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, String());
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, {});

return plugin->getName();
}
@@ -1652,10 +1636,10 @@ public:
plugin->unlock();
}

const String getInputChannelName(ChannelType t, uint i) const override
const water::String getInputChannelName(ChannelType t, uint i) const override
{
const CarlaPluginPtr plugin = fPlugin;
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, String());
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, {});

CarlaEngineClient* const client = plugin->getEngineClient();

@@ -1669,13 +1653,13 @@ public:
return client->getEventPortName(true, i);
}

return String();
return {};
}

const String getOutputChannelName(ChannelType t, uint i) const override
const water::String getOutputChannelName(ChannelType t, uint i) const override
{
const CarlaPluginPtr plugin = fPlugin;
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, String());
CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr, {});

CarlaEngineClient* const client(plugin->getEngineClient());

@@ -1689,7 +1673,7 @@ public:
return client->getEventPortName(false, i);
}

return String();
return {};
}

void prepareToPlay(double, int) override {}
@@ -1729,23 +1713,23 @@ public:
inputNames(),
outputNames() {}

const String getInputChannelName (ChannelType, uint _index) const override
const water::String getInputChannelName (ChannelType, uint _index) const override
{
const int index = static_cast<int>(_index); // FIXME
if (index < inputNames.size())
return inputNames[index];
return String("Playback ") + String(index+1);
return water::String("Playback ") + String(index+1);
}

const String getOutputChannelName (ChannelType, uint _index) const override
const water::String getOutputChannelName (ChannelType, uint _index) const override
{
const int index = static_cast<int>(_index); // FIXME
if (index < outputNames.size())
return outputNames[index];
return String("Capture ") + String(index+1);
return water::String("Capture ") + String(index+1);
}

void setNames(const bool setInputNames, const StringArray& names)
void setNames(const bool setInputNames, const water::StringArray& names)
{
if (setInputNames)
inputNames = names;
@@ -1754,8 +1738,8 @@ public:
}

private:
StringArray inputNames;
StringArray outputNames;
water::StringArray inputNames;
water::StringArray outputNames;
};

PatchbayGraph::PatchbayGraph(CarlaEngine* const engine,
@@ -1795,7 +1779,7 @@ PatchbayGraph::PatchbayGraph(CarlaEngine* const engine,
midiBuffer.ensureSize(kMaxEngineEventInternalCount*2);
midiBuffer.clear();

StringArray channelNames;
water::StringArray channelNames;

switch (numAudioIns)
{
@@ -2378,10 +2362,10 @@ const char* const* PatchbayGraph::getConnections(const bool external) const
AudioProcessor* const procB(nodeB->getProcessor());
CARLA_SAFE_ASSERT_CONTINUE(procB != nullptr);

String fullPortNameA(getProcessorFullPortName(procA, connectionToId.portA));
water::String fullPortNameA(getProcessorFullPortName(procA, connectionToId.portA));
CARLA_SAFE_ASSERT_CONTINUE(fullPortNameA.isNotEmpty());

String fullPortNameB(getProcessorFullPortName(procB, connectionToId.portB));
water::String fullPortNameB(getProcessorFullPortName(procB, connectionToId.portB));
CARLA_SAFE_ASSERT_CONTINUE(fullPortNameB.isNotEmpty());

connList.append(fullPortNameA.toRawUTF8());
@@ -2512,8 +2496,8 @@ bool PatchbayGraph::getGroupAndPortIdFromFullName(const bool external, const cha
if (external)
return extGraph.getGroupAndPortIdFromFullName(fullPortName, groupId, portId);

String groupName(String(fullPortName).upToFirstOccurrenceOf(":", false, false));
String portName(String(fullPortName).fromFirstOccurrenceOf(":", false, false));
water::String groupName(water::String(fullPortName).upToFirstOccurrenceOf(":", false, false));
water::String portName(water::String(fullPortName).fromFirstOccurrenceOf(":", false, false));

for (int i=0, count=graph.getNumNodes(); i<count; ++i)
{


+ 8
- 22
source/backend/engine/CarlaEngineInternal.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineInternal.hpp"
#include "CarlaPlugin.hpp"
@@ -74,7 +60,7 @@ static const double kTicksPerBeat = 1920.0;
#if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
static uint32_t calculate_link_latency(const double bufferSize, const double sampleRate) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate), 0);
CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate), 0);

const long long int latency = llround(1.0e6 * bufferSize / sampleRate);
CARLA_SAFE_ASSERT_RETURN(latency >= 0 && latency < UINT32_MAX, 0);
@@ -179,7 +165,7 @@ void EngineInternalTime::relocate(const uint64_t frame) noexcept

void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),);
CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate),);
CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);

double ticktmp;
@@ -262,7 +248,7 @@ void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept

void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint32_t newFrames) noexcept
{
CARLA_SAFE_ASSERT_RETURN(carla_isNotZero(sampleRate),);
CARLA_SAFE_ASSERT_RETURN(d_isNotZero(sampleRate),);
CARLA_SAFE_ASSERT_RETURN(newFrames > 0,);
CARLA_SAFE_ASSERT(transportMode == ENGINE_TRANSPORT_MODE_JACK);

@@ -294,12 +280,12 @@ void EngineInternalTime::preProcess(const uint32_t numFrames)
const double new_bpb = hylia.timeInfo.beatsPerBar;
const double new_bpm = hylia.timeInfo.beatsPerMinute;

if (new_bpb >= 1.0 && carla_isNotEqual(beatsPerBar, new_bpb))
if (new_bpb >= 1.0 && d_isNotEqual(beatsPerBar, new_bpb))
{
beatsPerBar = new_bpb;
needsReset = true;
}
if (new_bpm > 0.0 && carla_isNotEqual(beatsPerMinute, new_bpm))
if (new_bpm > 0.0 && d_isNotEqual(beatsPerMinute, new_bpm))
{
beatsPerMinute = new_bpm;
needsReset = true;
@@ -805,7 +791,7 @@ ScopedActionLock::ScopedActionLock(CarlaEngine* const engine,
}
else
{
carla_msleep(200);
d_msleep(200);
}

if (! engine->isRunning())


+ 7
- 21
source/backend/engine/CarlaEngineInternal.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_ENGINE_INTERNAL_HPP_INCLUDED
#define CARLA_ENGINE_INTERNAL_HPP_INCLUDED
@@ -284,8 +270,8 @@ struct CarlaEngine::ProtectedData {
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
bool loadingProject;
bool ignoreClientPrefix; // backwards compat only
CarlaString currentProjectFilename;
CarlaString currentProjectFolder;
String currentProjectFilename;
String currentProjectFolder;
#endif

uint32_t bufferSize;
@@ -297,9 +283,9 @@ struct CarlaEngine::ProtectedData {
uint maxPluginNumber; // number of plugins allowed (0, 16, 99 or 255)
uint nextPluginId; // invalid if == maxPluginNumber

CarlaMutex envMutex;
CarlaString lastError;
CarlaString name;
CarlaMutex envMutex;
String lastError;
String name;
EngineOptions options;
EngineTimeInfo timeInfo;



+ 30
- 29
source/backend/engine/CarlaEngineJack.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineClient.hpp"
@@ -12,6 +12,7 @@
#include "CarlaMIDI.h"
#include "CarlaPatchbayUtils.hpp"
#include "CarlaStringList.hpp"
#include "extra/ScopedPointer.hpp"

#include "jackey.h"

@@ -23,7 +24,7 @@
#include "jackbridge/JackBridge.hpp"

#ifdef JACKBRIDGE_DIRECT
# define JackPortIsControlVoltage 0x100
# define JackPortIsCV 0x20
#endif

#define URI_CANVAS_ICON "http://kxstudio.sf.net/ns/canvas/icon"
@@ -65,7 +66,7 @@ struct CarlaJackPortHints {
ph.isCV = false;
ph.isOSC = false;

if (ph.isAudio && portFlags & JackPortIsControlVoltage)
if (ph.isAudio && portFlags & JackPortIsCV)
{
ph.isAudio = false;
ph.isCV = true;
@@ -769,13 +770,13 @@ public:
EngineInternalGraph& egraph,
CarlaRecursiveMutex& rmutex,
const CarlaPluginPtr plugin,
const CarlaString& mainClientName,
const String& mainClientName,
jack_client_t* const jackClient)
: CarlaEngineClientForSubclassing(engine, egraph, plugin),
#else
CarlaEngineJackClient(const CarlaEngine& engine,
CarlaRecursiveMutex& rmutex,
const CarlaString& mainClientName,
const String& mainClientName,
jack_client_t* const jackClient)
: CarlaEngineClientForSubclassing(engine),
#endif
@@ -973,7 +974,7 @@ public:
jackPort = jackbridge_port_register(fJackClient,
realName,
JACK_DEFAULT_AUDIO_TYPE,
static_cast<uint64_t>(JackPortIsControlVoltage |
static_cast<uint64_t>(JackPortIsCV |
(isInput ? JackPortIsInput
: JackPortIsOutput)),
0);
@@ -1108,23 +1109,23 @@ public:
}

#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
bool renameInSingleClient(const CarlaString& newClientName)
bool renameInSingleClient(const String& newClientName)
{
const CarlaString clientNamePrefix(newClientName + ":");
const String clientNamePrefix(newClientName + ":");

return _renamePorts(fAudioPorts, clientNamePrefix) &&
_renamePorts(fCVPorts, clientNamePrefix) &&
_renamePorts(fEventPorts, clientNamePrefix);
}

void closeForRename(jack_client_t* const newClient, const CarlaString& newClientName) noexcept
void closeForRename(jack_client_t* const newClient, const String& newClientName) noexcept
{
if (fJackClient != nullptr)
{
if (isActive())
{
{
const CarlaString clientNamePrefix(newClientName + ":");
const String clientNamePrefix(newClientName + ":");

// store current client connections
const CarlaMutexLocker cml(fPreRenameMutex);
@@ -1203,13 +1204,13 @@ private:

CarlaMutex fPreRenameMutex;
CarlaStringList fPreRenameConnections;
CarlaString fPreRenamePluginId;
CarlaString fPreRenamePluginIcon;
String fPreRenamePluginId;
String fPreRenamePluginIcon;

CarlaScopedPointer<CarlaPluginPtr> fReservedPluginPtr;
ScopedPointer<CarlaPluginPtr> fReservedPluginPtr;

template<typename T>
bool _renamePorts(const LinkedList<T*>& t, const CarlaString& clientNamePrefix)
bool _renamePorts(const LinkedList<T*>& t, const String& clientNamePrefix)
{
for (typename LinkedList<T*>::Itenerator it = t.begin2(); it.valid(); it.next())
{
@@ -1225,7 +1226,7 @@ private:

shortPortName += oldClientNameSep-shortPortName + 1;

const CarlaString newPortName(clientNamePrefix + shortPortName);
const String newPortName(clientNamePrefix + shortPortName);

if (! jackbridge_port_rename(fJackClient, port->fJackPort, newPortName))
return false;
@@ -1235,7 +1236,7 @@ private:
}

template<typename T>
void _savePortsConnections(const LinkedList<T*>& t, const CarlaString& clientNamePrefix)
void _savePortsConnections(const LinkedList<T*>& t, const String& clientNamePrefix)
{
for (typename LinkedList<T*>::Itenerator it = t.begin2(); it.valid(); it.next())
{
@@ -1246,7 +1247,7 @@ private:
const char* const shortPortName(jackbridge_port_short_name(port->fJackPort));
CARLA_SAFE_ASSERT_CONTINUE(shortPortName != nullptr && shortPortName[0] != '\0');

const CarlaString portName(clientNamePrefix + shortPortName);
const String portName(clientNamePrefix + shortPortName);

if (const char** const connections = jackbridge_port_get_all_connections(fJackClient, port->fJackPort))
{
@@ -1311,7 +1312,7 @@ private:
#endif // BUILD_BRIDGE_ALTERNATIVE_ARCH

CarlaRecursiveMutex& fThreadSafeMetadataMutex;
const CarlaString& fMainClientName;
const String& fMainClientName;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackClient)
};
@@ -1424,7 +1425,7 @@ public:
fExternalPatchbayHost = true;
fExternalPatchbayOsc = true;

CarlaString truncatedClientName;
String truncatedClientName;

if (fClient == nullptr && clientName != nullptr)
{
@@ -1559,8 +1560,8 @@ public:

# ifdef HAVE_LIBLO
{
const CarlaString& tcp(pData->osc.getServerPathTCP());
const CarlaString& udp(pData->osc.getServerPathUDP());
const String& tcp(pData->osc.getServerPathTCP());
const String& udp(pData->osc.getServerPathUDP());

if (tcp.isNotEmpty() || udp.isNotEmpty())
{
@@ -2126,7 +2127,7 @@ public:
saveStatePtr = &saveState;
}

CarlaString uniqueName;
String uniqueName;

try {
const char* const tmpName = getUniquePluginName(newName);
@@ -2747,7 +2748,7 @@ public:
if (groupId != 0)
break;

carla_msleep(100);
d_msleep(100);
callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
}
}
@@ -3233,7 +3234,7 @@ protected:
const CarlaJackPortHints& jackPortHints)
{
bool groupFound;
CarlaString groupName(portName);
String groupName(portName);
groupName.truncate(groupName.rfind(shortPortName, &groupFound)-1);
CARLA_SAFE_ASSERT_RETURN(groupFound,);

@@ -3463,7 +3464,7 @@ protected:
CARLA_SAFE_ASSERT_RETURN(newFullName != nullptr && newFullName[0] != '\0',);

bool found;
CarlaString groupName(newFullName);
String groupName(newFullName);
groupName.truncate(groupName.rfind(newShortName, &found)-1);
CARLA_SAFE_ASSERT_RETURN(found,);

@@ -3571,7 +3572,7 @@ private:
bool fExternalPatchbayOsc;
bool fFreewheel;

CarlaString fClientName;
String fClientName;
CarlaRecursiveMutex fThreadSafeMetadataMutex;

// -------------------------------------------------------------------
@@ -3579,7 +3580,7 @@ private:
#ifdef BUILD_BRIDGE
bool fIsRunning;
#else
CarlaString fClientNamePrefix;
String fClientNamePrefix;

enum RackPorts {
kRackPortAudioIn1 = 0,
@@ -3798,7 +3799,7 @@ private:
uint groupId = 0;

bool found;
CarlaString groupName(fullPortName);
String groupName(fullPortName);
groupName.truncate(groupName.rfind(shortPortName, &found)-1);

CARLA_SAFE_ASSERT_CONTINUE(found);
@@ -4214,7 +4215,7 @@ private:
if (fClient == nullptr)
break;

carla_msleep(200);
d_msleep(200);
}
}
#endif // BUILD_BRIDGE


+ 13
- 12
source/backend/engine/CarlaEngineNative.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaDefines.h"
@@ -16,7 +16,6 @@
#include "CarlaPlugin.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "CarlaBinaryUtils.hpp"
#include "CarlaMathUtils.hpp"
#include "CarlaStateUtils.hpp"
@@ -26,6 +25,8 @@
#include "CarlaNative.hpp"
#include "CarlaNativePlugin.h"

#include "extra/Base64.hpp"

#include "water/files/File.h"
#include "water/streams/MemoryOutputStream.h"
#include "water/xml/XmlDocument.h"
@@ -37,7 +38,6 @@

using water::File;
using water::MemoryOutputStream;
using water::String;
using water::XmlDocument;
using water::XmlElement;

@@ -424,7 +424,7 @@ protected:
carla_zeroChars(tmpBuf, STR_MAX+1);

{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
std::snprintf(tmpBuf, STR_MAX, "%.12g\n", newSampleRate);
}

@@ -527,7 +527,7 @@ protected:
carla_zeroChars(tmpBuf, STR_MAX+1);

const CarlaMutexLocker cml(fUiServer.getPipeLock());
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;

const uint pluginId(plugin->getId());

@@ -786,7 +786,7 @@ protected:
CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),);

{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
std::snprintf(tmpBuf, STR_MAX, "%.12g\n", static_cast<double>(valuef));
}
CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),);
@@ -826,7 +826,7 @@ protected:

CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage("sample-rate\n"),);
{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
std::snprintf(tmpBuf, STR_MAX, "%.12g\n", pData->sampleRate);
}
CARLA_SAFE_ASSERT_RETURN(fUiServer.writeMessage(tmpBuf),);
@@ -1233,7 +1233,7 @@ protected:
return;
}

CarlaString path(pHost->resourceDir);
String path(pHost->resourceDir);

if (kIsPatchbay)
path += CARLA_OS_SEP_STR "carla-plugin-patchbay";
@@ -1404,7 +1404,7 @@ protected:
carla_zeroChars(tmpBuf, STR_MAX+1);

const CarlaMutexLocker cml(fUiServer.getPipeLock());
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
const EngineTimeInfo& timeInfo(pData->timeInfo);

// ------------------------------------------------------------------------------------------------------------
@@ -1519,7 +1519,7 @@ protected:
pData->runner.start();

fOptionsForced = true;
const String state(data);
const water::String state(data);
XmlDocument xml(state);
loadProjectInternal(xml, true);

@@ -1719,7 +1719,7 @@ private:
float fLastScaleFactor;

float fParameters[kNumInParams+kNumOutParams];
CarlaString fLastProjectFolder;
String fLastProjectFolder;
CarlaMutex fPluginDeleterMutex;

bool fOptionsForced;
@@ -2248,7 +2248,8 @@ bool CarlaEngineNativeUI::msgReceived(const char* const msg) noexcept

if (const CarlaPluginPtr plugin = fEngine->getPlugin(pluginId))
{
std::vector<uint8_t> chunk(carla_getChunkFromBase64String(cdata));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, cdata);
#ifdef CARLA_PROPER_CPP11_SUPPORT
plugin->setChunkData(chunk.data(), chunk.size());
#else


+ 12
- 25
source/backend/engine/CarlaEngineOsc.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_ENGINE_OSC_HPP_INCLUDED
#define CARLA_ENGINE_OSC_HPP_INCLUDED
@@ -23,10 +9,11 @@
#ifdef HAVE_LIBLO

#include "CarlaBackend.h"
#include "CarlaPlugin.hpp"
#include "CarlaJuceUtils.hpp"
#include "CarlaPluginPtr.hpp"
#include "CarlaOscUtils.hpp"
#include "CarlaString.hpp"

#include "extra/String.hpp"

#define CARLA_ENGINE_OSC_HANDLE_ARGS const CarlaPluginPtr& plugin, \
const int argc, const lo_arg* const* const argv, const char* const types
@@ -70,12 +57,12 @@ public:

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

const CarlaString& getServerPathTCP() const noexcept
const String& getServerPathTCP() const noexcept
{
return fServerPathTCP;
}

const CarlaString& getServerPathUDP() const noexcept
const String& getServerPathUDP() const noexcept
{
return fServerPathUDP;
}
@@ -127,11 +114,11 @@ private:
CarlaOscData fControlDataTCP;
CarlaOscData fControlDataUDP;

CarlaString fName;
CarlaString fServerPathTCP;
CarlaString fServerPathUDP;
lo_server fServerTCP;
lo_server fServerUDP;
String fName;
String fServerPathTCP;
String fServerPathUDP;
lo_server fServerTCP;
lo_server fServerUDP;

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



+ 1
- 1
source/backend/engine/CarlaEngineOscSend.cpp View File

@@ -216,7 +216,7 @@ void CarlaEngineOsc::sendPluginProgramCount(const CarlaPluginPtr& plugin) const
CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
carla_stdout("CarlaEngineOsc::sendPluginDataCount(%p)", plugin.get());

char targetPath[std::strlen(fControlDataTCP.path)+7];
char targetPath[std::strlen(fControlDataTCP.path)+8];
std::strcpy(targetPath, fControlDataTCP.path);
std::strcat(targetPath, "/pcount");
try_lo_send(fControlDataTCP.target, targetPath, "iii",


+ 1
- 1
source/backend/engine/CarlaEnginePorts.cpp View File

@@ -106,7 +106,7 @@ void CarlaEngineCVPort::setRange(const float min, const float max) noexcept
carla_zeroChars(strBufMax, STR_MAX);

{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
std::snprintf(strBufMin, STR_MAX-1, "%.12g", static_cast<double>(min));
std::snprintf(strBufMax, STR_MAX-1, "%.12g", static_cast<double>(max));
}


+ 4
- 4
source/backend/engine/CarlaEngineRtAudio.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineGraph.hpp"
@@ -861,7 +861,7 @@ protected:
return CarlaEngine::connectExternalGraphPort(connectionType, portId, portName);

case kExternalGraphConnectionMidiInput: {
CarlaString newRtMidiPortName;
String newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;
@@ -913,7 +913,7 @@ protected:
} break;

case kExternalGraphConnectionMidiOutput: {
CarlaString newRtMidiPortName;
String newRtMidiPortName;
newRtMidiPortName += getName();
newRtMidiPortName += ":";
newRtMidiPortName += portName;
@@ -1037,7 +1037,7 @@ private:
uint64_t fLastEventTime;

// current device name
CarlaString fDeviceName;
String fDeviceName;

// temp buffer for interleaved audio
float* fAudioIntBufIn;


+ 3
- 17
source/backend/engine/CarlaEngineSDL.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaEngineGraph.hpp"
#include "CarlaEngineInit.hpp"
@@ -414,7 +400,7 @@ private:
SDL_AudioDeviceID fDeviceId;

// current device name
CarlaString fDeviceName;
String fDeviceName;

// deinterleaved buffers
uint fAudioOutCount;


+ 28
- 26
source/backend/plugin/CarlaPlugin.cpp View File

@@ -1,19 +1,21 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "CarlaMathUtils.hpp"
#include "CarlaMIDI.h"
#include "CarlaPluginUI.hpp"
#include "CarlaScopeUtils.hpp"
// #include "CarlaScopeUtils.hpp"
#include "CarlaStringList.hpp"

#include <ctime>

#include "extra/Base64.hpp"
#include "extra/ScopedPointer.hpp"

#include "water/files/File.h"
#include "water/streams/MemoryOutputStream.h"
#include "water/xml/XmlDocument.h"
@@ -23,7 +25,6 @@ using water::CharPointer_UTF8;
using water::File;
using water::MemoryOutputStream;
using water::Result;
using water::String;
using water::XmlDocument;
using water::XmlElement;

@@ -557,7 +558,7 @@ const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave)

if (data != nullptr && dataSize > 0)
{
pData->stateSave.chunk = CarlaString::asBase64(data, dataSize).dup();
pData->stateSave.chunk = carla_strdup(String::asBase64(data, dataSize));

if (pluginType != PLUGIN_INTERNAL && pluginType != PLUGIN_JSFX)
usingChunk = true;
@@ -924,7 +925,8 @@ void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave)

if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
{
std::vector<uint8_t> chunk(carla_getChunkFromBase64String(stateSave.chunk));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, stateSave.chunk);
#ifdef CARLA_PROPER_CPP11_SUPPORT
setChunkData(chunk.data(), chunk.size());
#else
@@ -993,7 +995,7 @@ bool CarlaPlugin::loadStateFromFile(const char* const filename)
CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(), false);

XmlDocument xml(file);
CarlaScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
ScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
CARLA_SAFE_ASSERT_RETURN(xmlElement->getTagName().equalsIgnoreCase("carla-preset"), false);

@@ -1016,7 +1018,7 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
carla_debug("CarlaPlugin::exportAsLV2(\"%s\")", lv2path);

CarlaString bundlepath(lv2path);
String bundlepath(lv2path);

if (! bundlepath.endsWith(".lv2"))
bundlepath += ".lv2";
@@ -1040,11 +1042,11 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
}
}

CarlaString symbol(pData->name);
String symbol(pData->name);
symbol.toBasic();

{
const CarlaString pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");
const String pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");

if (! saveStateToFile(pluginFilename))
return false;
@@ -1070,7 +1072,7 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
manifestStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .\n";
manifestStream << "\n";

const CarlaString manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
const String manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
const File manifestFile(manifestFilename.buffer());

if (! manifestFile.replaceWithData(manifestStream.getData(), manifestStream.getDataSize()))
@@ -1124,8 +1126,8 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)

for (uint32_t i=1; i<midiIns; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);
const water::String portIndexNum(portIndex++);
const water::String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
@@ -1150,8 +1152,8 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)

for (uint32_t i=0; i<midiOuts; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(portIndex);
const water::String portIndexNum(portIndex++);
const water::String portIndexLabel(portIndex);

mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
@@ -1178,8 +1180,8 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)

for (uint32_t i=0; i<pData->audioIn.count; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(i+1);
const water::String portIndexNum(portIndex++);
const water::String portIndexLabel(i+1);

mainStream << " lv2:port [\n";
mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
@@ -1191,8 +1193,8 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)

for (uint32_t i=0; i<pData->audioOut.count; ++i)
{
const String portIndexNum(portIndex++);
const String portIndexLabel(i+1);
const water::String portIndexNum(portIndex++);
const water::String portIndexLabel(i+1);

mainStream << " lv2:port [\n";
mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
@@ -1214,7 +1216,7 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
const ParameterData& paramData(pData->param.data[i]);
const ParameterRanges& paramRanges(pData->param.ranges[i]);

const String portIndexNum(portIndex++);
const water::String portIndexNum(portIndex++);

mainStream << " lv2:port [\n";

@@ -1238,7 +1240,7 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)

if (strBufSymbol[0] == '\0')
{
CarlaString s(strBufName);
String s(strBufName);
s.toBasic();
std::memcpy(strBufSymbol, s.buffer(), s.length()+1);

@@ -1277,7 +1279,7 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
mainStream << " doap:maintainer [ foaf:name \"\"\"" << strBuf << "\"\"\" ] .\n";
mainStream << "\n";

const CarlaString mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
const String mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
const File mainFile(mainFilename.buffer());

if (! mainFile.replaceWithData(mainStream.getData(), mainStream.getDataSize()))
@@ -1287,15 +1289,15 @@ bool CarlaPlugin::exportAsLV2(const char* const lv2path)
}
}

const CarlaString binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);
const String binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);

const File binaryFileSource(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("carla-bridge-lv2" CARLA_LIB_EXT));
const File binaryFileTarget(binaryFilename.buffer());

const EngineOptions& opts(pData->engine->getOptions());

const CarlaString binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
const CarlaString resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");
const String binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
const String resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");

if (! binaryFileSource.copyFileTo(binaryFileTarget))
{
@@ -2489,7 +2491,7 @@ void CarlaPlugin::uiIdle()

carla_stdout("Trying to get window...");

CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{


+ 9
- 8
source/backend/plugin/CarlaPluginAU.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
@@ -8,6 +8,7 @@
# include "CarlaBackendUtils.hpp"
# include "CarlaPluginUI.hpp"
# include "CarlaMacUtils.hpp"
# include "CarlaMathUtils.hpp"
# include <AudioToolbox/AudioUnit.h>
# include <Foundation/Foundation.h>
#endif
@@ -248,7 +249,7 @@ public:
bool needsCtrlIn, needsCtrlOut, hasMidiIn, hasMidiOut;
needsCtrlIn = needsCtrlOut = hasMidiIn = hasMidiOut = false;

CarlaString portName;
String portName;
const uint portNameSize = pData->engine->getMaxPortNameSize();

UInt32 outDataSize;
@@ -400,7 +401,7 @@ public:
if (audioIns > 1)
{
portName += "input_";
portName += CarlaString(i + 1);
portName += String(i + 1);
}
else
portName += "input";
@@ -425,7 +426,7 @@ public:
if (audioOuts > 1)
{
portName += "output_";
portName += CarlaString(i + 1);
portName += String(i + 1);
}
else
portName += "output";
@@ -496,7 +497,7 @@ public:
if (min > max)
max = min;

if (carla_isEqual(min, max))
if (d_isEqual(min, max))
{
carla_stderr2("WARNING - Broken plugin parameter '%s': max == min", info.name);
max = min + 0.1f;
@@ -1037,9 +1038,9 @@ private:
BundleLoader fBundleLoader;
AudioComponentPlugInInterface* fInterface;
AudioBufferList* fAudioBufferData;
CarlaString fName;
CarlaString fLabel;
CarlaString fMaker;
String fName;
String fLabel;
String fMaker;

struct Functions {
InitializeFn initialize;


+ 62
- 76
source/backend/plugin/CarlaPluginBridge.cpp View File

@@ -1,37 +1,25 @@
/*
* Carla Plugin Bridge
* Copyright (C) 2011-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 General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "CarlaBridgeUtils.hpp"
#include "CarlaEngineUtils.hpp"
#include "CarlaMathUtils.hpp"
#include "CarlaPipeUtils.hpp"
#include "CarlaScopeUtils.hpp"
#include "CarlaShmUtils.hpp"
#include "CarlaTimeUtils.hpp"
#include "CarlaThread.hpp"

#include "jackbridge/JackBridge.hpp"

#include <ctime>

#include "extra/Base64.hpp"
#include "extra/ScopedPointer.hpp"
#include "extra/Time.hpp"

#include "water/files/File.h"
#include "water/misc/Time.h"
#include "water/threads/ChildProcess.h"
@@ -40,8 +28,6 @@

using water::ChildProcess;
using water::File;
using water::String;
using water::StringArray;

CARLA_BACKEND_START_NAMESPACE

@@ -53,17 +39,17 @@ static const ExternalMidiNote kExternalMidiNoteFallback = { -1, 0, 0 };
// --------------------------------------------------------------------------------------------------------------------

#ifndef CARLA_OS_WIN
static String findWinePrefix(const String filename, const int recursionLimit = 10)
static water::String findWinePrefix(const water::String filename, const int recursionLimit = 10)
{
if (recursionLimit == 0 || filename.length() < 5 || ! filename.contains("/"))
return "";
return {};

const String path(filename.upToLastOccurrenceOf("/", false, false));
const water::String path(filename.upToLastOccurrenceOf("/", false, false));

if (File(String(path + "/dosdevices").toRawUTF8()).isDirectory())
if (File(water::String(path + "/dosdevices").toRawUTF8()).isDirectory())
return path;

return findWinePrefix(path, recursionLimit-1);
return findWinePrefix(path, recursionLimit - 1);
}
#endif

@@ -71,9 +57,9 @@ static String findWinePrefix(const String filename, const int recursionLimit = 1

struct BridgeParamInfo {
float value;
CarlaString name;
CarlaString symbol;
CarlaString unit;
String name;
String symbol;
String unit;

BridgeParamInfo() noexcept
: value(0.0f),
@@ -185,18 +171,18 @@ protected:

const EngineOptions& options(kEngine->getOptions());

String filename(kPlugin->getFilename());
water::String filename(kPlugin->getFilename());

if (filename.isEmpty())
filename = "(none)";

StringArray arguments;
water::StringArray arguments;

#ifndef CARLA_OS_WIN
// start with "wine" if needed
if (fBridgeBinary.endsWithIgnoreCase(".exe"))
{
String wineCMD;
water::String wineCMD;

if (options.wine.executable != nullptr && options.wine.executable[0] != '\0')
{
@@ -204,7 +190,7 @@ protected:

if (fBridgeBinary.endsWithIgnoreCase("64.exe")
&& options.wine.executable[0] == CARLA_OS_SEP
&& File(String(wineCMD + "64").toRawUTF8()).existsAsFile())
&& File(water::String(wineCMD + "64").toRawUTF8()).existsAsFile())
wineCMD += "64";
}
else
@@ -240,7 +226,7 @@ protected:
arguments.add(fLabel);

// uniqueId
arguments.add(String(static_cast<water::int64>(kPlugin->getUniqueId())));
arguments.add(water::String(static_cast<water::int64>(kPlugin->getUniqueId())));

bool started;

@@ -386,7 +372,7 @@ protected:
}

for (; fProcess->isRunning() && ! shouldThreadExit();)
carla_sleep(1);
d_msleep(100);

// we only get here if bridge crashed or thread asked to exit
if (fProcess->isRunning() && shouldThreadExit())
@@ -410,9 +396,9 @@ protected:
{
carla_stderr("CarlaPluginBridgeThread::run() - bridge crashed");

CarlaString errorString("Plugin '" + CarlaString(kPlugin->getName()) + "' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.");
String errorString("Plugin '" + String(kPlugin->getName()) + "' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.");
kEngine->callback(true, true,
ENGINE_CALLBACK_ERROR, kPlugin->getId(), 0, 0, 0, 0.0f, errorString);
}
@@ -425,15 +411,15 @@ private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;

String fBinaryArchName;
String fBridgeBinary;
String fLabel;
String fShmIds;
water::String fBinaryArchName;
water::String fBridgeBinary;
water::String fLabel;
water::String fShmIds;
#ifndef CARLA_OS_WIN
CarlaString fWinePrefix;
String fWinePrefix;
#endif

CarlaScopedPointer<ChildProcess> fProcess;
ScopedPointer<ChildProcess> fProcess;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridgeThread)
};
@@ -690,10 +676,10 @@ public:
if (fReceivingParamText.wasDataReceived(&success))
return success;

const uint32_t timeoutEnd = carla_gettime_ms() + 500; // 500 ms
const uint32_t timeoutEnd = d_gettime_ms() + 500; // 500 ms
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;

for (; carla_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
for (; d_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
{
if (fReceivingParamText.wasDataReceived(&success))
return success;
@@ -701,7 +687,7 @@ public:
if (needsEngineIdle)
pData->engine->idle();

carla_msleep(5);
d_msleep(5);
}

if (! fBridgeThread.isThreadRunning())
@@ -720,10 +706,10 @@ public:
return;

// TODO: only wait 1 minute for NI plugins
const uint32_t timeoutEnd = carla_gettime_ms() + 60*1000; // 60 secs, 1 minute
const uint32_t timeoutEnd = d_gettime_ms() + 60*1000; // 60 secs, 1 minute
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;

for (; carla_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
for (; d_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
{
pData->engine->callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);

@@ -733,7 +719,7 @@ public:
if (fSaved)
break;

carla_msleep(20);
d_msleep(20);
}

if (! fBridgeThread.isThreadRunning())
@@ -991,7 +977,7 @@ public:
{
if (valueLen > maxLocalValueLen)
{
String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
water::String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());

filePath += CARLA_OS_SEP_STR ".CarlaCustomData_";
filePath += fShmAudioPool.getFilenameSuffix();
@@ -1026,10 +1012,10 @@ public:
CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);

CarlaString dataBase64(CarlaString::asBase64(data, dataSize));
String dataBase64(String::asBase64(data, dataSize));
CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0,);

String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
water::String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());

filePath += CARLA_OS_SEP_STR ".CarlaChunk_";
filePath += fShmAudioPool.getFilenameSuffix();
@@ -1116,10 +1102,10 @@ public:
fShmNonRtClientControl.commitWrite();
}

const uint32_t timeoutEnd = carla_gettime_ms() + 15*1000; // 15 secs
const uint32_t timeoutEnd = d_gettime_ms() + 15*1000; // 15 secs
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;

for (; carla_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
for (; d_gettime_ms() < timeoutEnd && fBridgeThread.isThreadRunning();)
{
pData->engine->callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);

@@ -1133,7 +1119,7 @@ public:
break;
}

carla_msleep(20);
d_msleep(20);
}

return reinterpret_cast<void*>(fPendingEmbedCustomUI);
@@ -1219,7 +1205,7 @@ public:
needsCtrlOut = true;

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

// Audio Ins
for (uint32_t j=0; j < fInfo.aIns; ++j)
@@ -1239,7 +1225,7 @@ public:
else if (fInfo.aIns > 1)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -1268,7 +1254,7 @@ public:
else if (fInfo.aOuts > 1)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -1299,7 +1285,7 @@ public:
else if (fInfo.cvIns > 1)
{
portName += "cv_input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_input";
@@ -1328,7 +1314,7 @@ public:
else if (fInfo.cvOuts > 1)
{
portName += "cv_output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_output";
@@ -2207,7 +2193,7 @@ public:
if (fBridgeVersion < 9 || fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64)
#endif
{
pData->hints &= ~PLUGIN_HAS_CUSTOM_EMBED_UI;
pData->hints &= ~(PLUGIN_HAS_CUSTOM_EMBED_UI|PLUGIN_HAS_CUSTOM_RESIZABLE_UI);
}

fInfo.category = static_cast<PluginCategory>(category);
@@ -2531,13 +2517,13 @@ public:
{
const BridgeTextReader bigValueFilePath(fShmNonRtServerControl);

String realBigValueFilePath(bigValueFilePath.text);
water::String realBigValueFilePath(bigValueFilePath.text);

#ifndef CARLA_OS_WIN
// Using Wine, fix temp dir
if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64)
{
const StringArray driveLetterSplit(StringArray::fromTokens(realBigValueFilePath, ":/", ""));
const water::StringArray driveLetterSplit(water::StringArray::fromTokens(realBigValueFilePath, ":/", ""));
carla_stdout("big value save path BEFORE => '%s' | using wineprefix '%s'", realBigValueFilePath.toRawUTF8(), fWinePrefix.buffer());

realBigValueFilePath = fWinePrefix.buffer();
@@ -2572,13 +2558,13 @@ public:
// chunkFilePath
const BridgeTextReader chunkFilePath(fShmNonRtServerControl);

String realChunkFilePath(chunkFilePath.text);
water::String realChunkFilePath(chunkFilePath.text);

#ifndef CARLA_OS_WIN
// Using Wine, fix temp dir
if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64)
{
const StringArray driveLetterSplit(StringArray::fromTokens(realChunkFilePath, ":/", ""));
const water::StringArray driveLetterSplit(water::StringArray::fromTokens(realChunkFilePath, ":/", ""));
carla_stdout("chunk save path BEFORE => '%s' | using wineprefix '%s'", realChunkFilePath.toRawUTF8(), fWinePrefix.buffer());

realChunkFilePath = fWinePrefix.buffer();
@@ -2594,7 +2580,7 @@ public:
const File chunkFile(realChunkFilePath.toRawUTF8());
CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());

fInfo.chunk = carla_getChunkFromBase64String(chunkFile.loadFileAsString().toRawUTF8());
d_getChunkFromBase64String_impl(fInfo.chunk, chunkFile.loadFileAsString().toRawUTF8());
chunkFile.deleteFile();
} break;

@@ -2912,7 +2898,7 @@ private:
uint fProcWaitTime;
uint64_t fPendingEmbedCustomUI;

CarlaString fBridgeBinary;
String fBridgeBinary;
CarlaPluginBridgeThread fBridgeThread;

BridgeAudioPool fShmAudioPool;
@@ -2921,7 +2907,7 @@ private:
BridgeNonRtServerControl fShmNonRtServerControl;

#ifndef CARLA_OS_WIN
CarlaString fWinePrefix;
String fWinePrefix;
#endif

class ReceivingParamText {
@@ -2989,10 +2975,10 @@ private:
uint32_t mIns, mOuts;
PluginCategory category;
uint optionsAvailable;
CarlaString name;
CarlaString label;
CarlaString maker;
CarlaString copyright;
String name;
String label;
String maker;
String copyright;
const char** aInNames;
const char** aOutNames;
const char** cvInNames;
@@ -3204,7 +3190,7 @@ private:
if (pData->engine->isAboutToClose() || pData->engine->wasActionCanceled())
break;

carla_msleep(5);
d_msleep(5);
}

#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
@@ -3237,10 +3223,10 @@ private:
#else
void* data = &fInfo.chunk.front();
#endif
CarlaString dataBase64(CarlaString::asBase64(data, dataSize));
String dataBase64(String::asBase64(data, dataSize));
CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0, true);

String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
water::String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());

filePath += CARLA_OS_SEP_STR ".CarlaChunk_";
filePath += fShmAudioPool.getFilenameSuffix();
@@ -3263,7 +3249,7 @@ private:

void _setUiTitleFromName()
{
CarlaString uiName(pData->name);
String uiName(pData->name);
uiName += " (GUI)";

const uint32_t size = static_cast<uint32_t>(uiName.length());


+ 12
- 20
source/backend/plugin/CarlaPluginCLAP.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla CLAP Plugin
* Copyright (C) 2022-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
@@ -685,6 +671,10 @@ struct carla_clap_output_events : clap_output_events_t, CarlaPluginClapEventData
case CLAP_EVENT_MIDI:
e.midi = *static_cast<const clap_event_midi_t*>(static_cast<const void*>(event));
break;
case CLAP_EVENT_PARAM_GESTURE_BEGIN:
case CLAP_EVENT_PARAM_GESTURE_END:
// TODO for now be nice to the plugins that require this
return true;
default:
return false;
}
@@ -1085,7 +1075,7 @@ public:
if (!fUI.isCreated)
return;

CarlaString uiTitle;
String uiTitle;

if (title != nullptr)
{
@@ -1552,7 +1542,7 @@ public:

const EngineProcessMode processMode = pData->engine->getProccessMode();
const uint portNameSize = pData->engine->getMaxPortNameSize();
CarlaString portName;
String portName;

// Audio Ins
for (uint32_t j=0; j < aIns; ++j)
@@ -1568,7 +1558,7 @@ public:
if (aIns > 1)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -1594,7 +1584,7 @@ public:
if (aOuts > 1)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -1825,6 +1815,8 @@ public:
pData->hints |= PLUGIN_HAS_CUSTOM_UI;
pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
if (guiExt->can_resize(fPlugin))
pData->hints |= PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
}
else if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, true))
{


+ 8
- 25
source/backend/plugin/CarlaPluginFluidSynth.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla FluidSynth Plugin
* Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
@@ -29,9 +15,6 @@

#define FLUID_DEFAULT_POLYPHONY 64

using water::String;
using water::StringArray;

CARLA_BACKEND_START_NAMESPACE

// -------------------------------------------------------------------------------------------------------------------
@@ -519,12 +502,12 @@ public:
if (std::strcmp(key, "midiPrograms") != 0)
return carla_stderr2("CarlaPluginFluidSynth::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string", type, key, value, bool2str(sendGui));

StringArray midiProgramList(StringArray::fromTokens(value, ":", ""));
water::StringArray midiProgramList(water::StringArray::fromTokens(value, ":", ""));

if (midiProgramList.size() == MAX_MIDI_CHANNELS)
{
uint8_t channel = 0;
for (String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
for (water::String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
{
const int index(it->getIntValue());

@@ -649,7 +632,7 @@ public:
pData->param.createNew(params, false);

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

// ---------------------------------------
// Audio Outputs
@@ -671,7 +654,7 @@ public:
if ((i+2)/2 < 9)
portName += "0";

portName += CarlaString((i+2)/2);
portName += String((i+2)/2);

if (i % 2 == 0)
portName += "L";
@@ -1719,12 +1702,12 @@ public:
// ---------------------------------------------------------------
// get info

CarlaString label2(label);
String label2(label);

if (kUse16Outs && ! label2.endsWith(" (16 outs)"))
label2 += " (16 outs)";

fLabel = label2.dup();
fLabel = carla_strdup(label2);
pData->filename = carla_strdup(filename);

if (name != nullptr && name[0] != '\0')


+ 5
- 18
source/backend/plugin/CarlaPluginInternal.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_PLUGIN_INTERNAL_HPP_INCLUDED
#define CARLA_PLUGIN_INTERNAL_HPP_INCLUDED
@@ -26,9 +12,10 @@

#include "CarlaMIDI.h"
#include "CarlaMutex.hpp"
#include "CarlaString.hpp"
#include "RtLinkedList.hpp"

#include "extra/String.hpp"

CARLA_BACKEND_START_NAMESPACE

// -----------------------------------------------------------------------
@@ -286,7 +273,7 @@ struct CarlaPlugin::ProtectedData {

CarlaStateSave stateSave;

CarlaString uiTitle;
String uiTitle;

struct ExternalNotes {
CarlaMutex mutex;


+ 14
- 29
source/backend/plugin/CarlaPluginJSFX.cpp View File

@@ -1,19 +1,6 @@
/*
* Carla JSFX Plugin
* Copyright (C) 2021-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 General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2021 Jean Pierre Cimalando
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

// TODO(jsfx) graphics section

@@ -35,8 +22,6 @@

using water::CharPointer_UTF8;
using water::File;
using water::String;
using water::StringArray;

CARLA_BACKEND_START_NAMESPACE

@@ -332,7 +317,7 @@ public:
}

const uint portNameSize = pData->engine->getMaxPortNameSize();
CarlaString portName;
String portName;

// Audio Ins
for (uint32_t j = 0; j < aIns; ++j)
@@ -353,7 +338,7 @@ public:
else if (aIns > 1)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -383,7 +368,7 @@ public:
else if (aOuts > 1)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -414,13 +399,13 @@ public:

// only use values as integer if we have a proper range
const bool isEnum = ysfx_slider_is_enum(fEffect, rindex) &&
carla_isZero(min) &&
d_isZero(min) &&
max >= 0.0f &&
carla_isEqual(max + 1.0f, static_cast<float>(ysfx_slider_get_enum_names(fEffect, rindex, nullptr, 0)));
d_isEqual(max + 1.0f, static_cast<float>(ysfx_slider_get_enum_names(fEffect, rindex, nullptr, 0)));

// NOTE: in case of incomplete slider specification without <min,max,step>;
// these are usually output-only sliders.
if (carla_isEqual(min, max))
if (d_isEqual(min, max))
{
// replace with a dummy range
min = 0.0f;
@@ -929,10 +914,10 @@ public:
fUnit = CarlaJsfxUnit();

{
StringArray splitPaths;
water::StringArray splitPaths;

if (const char* paths = pData->engine->getOptions().pathJSFX)
splitPaths = StringArray::fromTokens(CharPointer_UTF8(paths), CARLA_OS_SPLIT_STR, "");
splitPaths = water::StringArray::fromTokens(CharPointer_UTF8(paths), CARLA_OS_SPLIT_STR, "");

File file;
if (filename && filename[0] != '\0')
@@ -977,8 +962,8 @@ public:
ysfx_config_u config(ysfx_config_new());
CARLA_SAFE_ASSERT_RETURN(config != nullptr, false);

const CarlaString rootPath = fUnit.getRootPath();
const CarlaString filePath = fUnit.getFilePath();
const String rootPath = fUnit.getRootPath();
const String filePath = fUnit.getFilePath();

ysfx_register_builtin_audio_formats(config.get());
ysfx_set_import_root(config.get(), rootPath);
@@ -1021,7 +1006,7 @@ public:
pData->name = carla_strdup(ysfx_get_name(fEffect));
}

pData->filename = filePath.dup();
pData->filename = carla_strdup(filePath);

// ---------------------------------------------------------------
// register client


+ 34
- 35
source/backend/plugin/CarlaPluginJack.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
@@ -22,6 +22,7 @@
# warning No liblo support, NSM (session state) will not be available
#endif

#include "extra/ScopedPointer.hpp"
#include "water/files/File.h"
#include "water/misc/Time.h"
#include "water/text/StringArray.h"
@@ -36,8 +37,6 @@

using water::ChildProcess;
using water::File;
using water::String;
using water::StringArray;

CARLA_BACKEND_START_NAMESPACE

@@ -126,12 +125,12 @@ public:
char* getEnvVarsToExport()
{
const EngineOptions& options(kEngine->getOptions());
CarlaString binaryDir(options.binaryDir);
String binaryDir(options.binaryDir);
#ifdef HAVE_LIBLO
const int sessionManager = fSetupLabel[4U] - '0';
#endif

CarlaString ret;
String ret;
#ifdef CARLA_OS_MAC
ret += "export DYLD_LIBRARY_PATH=" + binaryDir + "/jack\n";
ret += "export DYLD_INSERT_LIBRARIES=" + binaryDir + "/libcarla_interposer-jack-x11.dylib\n";
@@ -144,7 +143,7 @@ public:
if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
{
for (int i=50; fOscServer == nullptr && --i>=0;)
carla_msleep(100);
d_msleep(100);

ret += "export NSM_URL=";
ret += lo_server_get_url(fOscServer);
@@ -153,12 +152,12 @@ public:
#endif

if (kPlugin->getHints() & PLUGIN_HAS_CUSTOM_UI)
ret += "export CARLA_FRONTEND_WIN_ID=" + CarlaString(options.frontendWinId) + "\n";
ret += "export CARLA_FRONTEND_WIN_ID=" + String(options.frontendWinId) + "\n";

ret += "export CARLA_LIBJACK_SETUP=" + fSetupLabel + "\n";
ret += "export CARLA_SHM_IDS=" + fShmIds + "\n";

return ret.releaseBufferPointer();
return ret.getAndReleaseBuffer();
}

protected:
@@ -333,15 +332,15 @@ protected:
carla_stderr("CarlaPluginJackThread::run() - already running");
}

String name(kPlugin->getName());
String filename(kPlugin->getFilename());
water::String name(kPlugin->getName());
water::String filename(kPlugin->getFilename());

if (name.isEmpty())
name = "(none)";

CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(),);

StringArray arguments;
water::StringArray arguments;

// binary
arguments.addTokens(filename, true);
@@ -352,11 +351,11 @@ protected:
std::snprintf(winIdStr, STR_MAX, P_UINTPTR, options.frontendWinId);
winIdStr[STR_MAX] = '\0';

const CarlaString libjackdir(CarlaString(options.binaryDir) + "/jack");
const String libjackdir(String(options.binaryDir) + "/jack");
#ifdef CARLA_OS_MAC
const CarlaString ldpreload(CarlaString(options.binaryDir) + "/libcarla_interposer-jack-x11.dylib");
const String ldpreload(String(options.binaryDir) + "/libcarla_interposer-jack-x11.dylib");
#else
const CarlaString ldpreload(CarlaString(options.binaryDir) + "/libcarla_interposer-jack-x11.so");
const String ldpreload(String(options.binaryDir) + "/libcarla_interposer-jack-x11.so");
#endif

const ScopedEngineEnvironmentLocker _seel(kEngine);
@@ -399,7 +398,7 @@ protected:
else
#endif
{
carla_msleep(50);
d_msleep(50);
}
}

@@ -437,7 +436,7 @@ protected:
{
carla_stderr("CarlaPluginJackThread::run() - application crashed");

CarlaString errorString("Plugin '" + CarlaString(kPlugin->getName()) + "' has crashed!\n"
String errorString("Plugin '" + String(kPlugin->getName()) + "' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.");
kEngine->callback(true, true,
@@ -457,8 +456,8 @@ private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;

CarlaString fShmIds;
CarlaString fSetupLabel;
String fShmIds;
String fSetupLabel;

#ifdef HAVE_LIBLO
lo_address fOscClientAddress;
@@ -466,10 +465,10 @@ private:
bool fHasOptionalGui;

struct ProjectData {
CarlaString appName;
CarlaString path;
CarlaString display;
CarlaString clientName;
String appName;
String path;
String display;
String clientName;

ProjectData()
: appName(),
@@ -485,7 +484,7 @@ private:
CARLA_SAFE_ASSERT_RETURN(uniqueCodeID != nullptr && uniqueCodeID[0] != '\0', false);
CARLA_SAFE_ASSERT_RETURN(appName.isNotEmpty(), false);

CarlaString child(pluginName);
String child(pluginName);
child += ".";
child += uniqueCodeID;

@@ -502,7 +501,7 @@ private:
} fProject;
#endif

CarlaScopedPointer<ChildProcess> fProcess;
ScopedPointer<ChildProcess> fProcess;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginJackThread)
};
@@ -849,7 +848,7 @@ public:
needsCtrlOut = true;

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

// Audio Ins
for (uint8_t j=0; j < fInfo.aIns; ++j)
@@ -865,7 +864,7 @@ public:
if (fInfo.aIns > 1)
{
portName += "audio_in_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
{
@@ -892,7 +891,7 @@ public:
if (fInfo.aOuts > 1)
{
portName += "audio_out_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
{
@@ -1140,7 +1139,7 @@ public:
break;

case kEngineControlEventTypeMidiBank:
if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
{
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventMidiBank);
fShmRtClientControl.writeUInt(event.time);
@@ -1151,7 +1150,7 @@ public:
break;

case kEngineControlEventTypeMidiProgram:
if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
{
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientControlEventMidiProgram);
fShmRtClientControl.writeUInt(event.time);
@@ -1809,7 +1808,7 @@ private:
struct Info {
uint8_t aIns, aOuts;
uint8_t mIns, mOuts;
CarlaString setupLabel;
String setupLabel;
std::vector<uint8_t> chunk;

Info()
@@ -1872,7 +1871,7 @@ private:
char code[6];
code[5] = '\0';

CarlaString child;
String child;

for (;;)
{
@@ -1951,21 +1950,21 @@ private:
const bool needsCancelableAction = ! pData->engine->isLoadingProject();
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;

CarlaString actionName;
String actionName;

if (needsCancelableAction)
{
if (fSetupHints & LIBJACK_FLAG_EXTERNAL_START)
{
const EngineOptions& options(pData->engine->getOptions());
CarlaString binaryDir(options.binaryDir);
String binaryDir(options.binaryDir);

char* const hwVars = fBridgeThread.getEnvVarsToExport();

actionName = "Waiting for external JACK application start, please use the following environment variables:\n";
actionName += hwVars;

delete[] hwVars;
std::free(hwVars);
}
else
{
@@ -1995,7 +1994,7 @@ private:
if (pData->engine->isAboutToClose() || pData->engine->wasActionCanceled())
break;

carla_msleep(5);
d_msleep(5);
}

if (needsCancelableAction)


+ 20
- 36
source/backend/plugin/CarlaPluginLADSPADSSI.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Plugin, LADSPA/DSSI implementation
* Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngineUtils.hpp"
@@ -28,13 +14,11 @@
# include "CarlaOscUtils.hpp"
# include "CarlaScopeUtils.hpp"
# include "CarlaThread.hpp"
# include "extra/ScopedPointer.hpp"
# include "water/threads/ChildProcess.h"
using water::ChildProcess;
#endif

using water::String;
using water::StringArray;

#define CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \
/* check argument count */ \
if (argc != argcToCompare) \
@@ -135,8 +119,8 @@ public:
return;
}

String name(kPlugin->getName());
String filename(kPlugin->getFilename());
water::String name(kPlugin->getName());
water::String filename(kPlugin->getFilename());

if (name.isEmpty())
name = "(none)";
@@ -144,13 +128,13 @@ public:
if (filename.isEmpty())
filename = "\"\"";

StringArray arguments;
water::StringArray arguments;

// binary
arguments.add(fBinary.buffer());

// osc-url
arguments.add(String(kEngine->getOscServerPathUDP()) + String("/") + String(kPlugin->getId()));
arguments.add(String(kEngine->getOscServerPathUDP()) + water::String("/") + water::String(kPlugin->getId()));

// filename
arguments.add(filename);
@@ -176,12 +160,12 @@ public:
winIdStr[STR_MAX] = '\0';

// for LD_PRELOAD
CarlaString ldPreloadValue;
String ldPreloadValue;

if (winId != 0)
{
std::snprintf(winIdStr, STR_MAX, P_UINTPTR, winId);
ldPreloadValue = (CarlaString(kEngine->getOptions().binaryDir)
ldPreloadValue = (String(kEngine->getOptions().binaryDir)
+ "/libcarla_interposer-x11.so");
}
else
@@ -209,7 +193,7 @@ public:
if (waitForOscGuiShow())
{
for (; fProcess->isRunning() && ! shouldThreadExit();)
carla_sleep(1);
d_msleep(100);

// we only get here if UI was closed or thread asked to exit
if (fProcess->isRunning() && shouldThreadExit())
@@ -251,12 +235,12 @@ private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;

CarlaString fBinary;
CarlaString fLabel;
CarlaString fUiTitle;
String fBinary;
String fLabel;
String fUiTitle;

const CarlaOscData& fOscData;
CarlaScopedPointer<ChildProcess> fProcess;
ScopedPointer<ChildProcess> fProcess;

bool waitForOscGuiShow()
{
@@ -274,7 +258,7 @@ private:
}

if (fProcess != nullptr && fProcess->isRunning() && ! shouldThreadExit())
carla_msleep(100);
d_msleep(100);
else
return false;
}
@@ -990,7 +974,7 @@ public:
}

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iCtrl=0; i < portCount; ++i)
{
@@ -1019,7 +1003,7 @@ public:
if (aIns > 1)
{
portName += "audio-in_";
portName += CarlaString(iAudioIn+1);
portName += String(iAudioIn+1);
}
else
portName += "audio-in";
@@ -1029,7 +1013,7 @@ public:
if (aOuts > 1)
{
portName += "audio-out_";
portName += CarlaString(iAudioOut+1);
portName += String(iAudioOut+1);
}
else
portName += "audio-out";
@@ -2896,7 +2880,7 @@ public:
// ---------------------------------------------------------------
// check for fixed buffer size requirement

fNeedsFixedBuffers = CarlaString(filename).contains("dssi-vst", true);
fNeedsFixedBuffers = String(filename).contains("dssi-vst", true);

if (fNeedsFixedBuffers && ! pData->engine->usesConstantBufferSize())
{
@@ -2997,7 +2981,7 @@ public:
{
fUiFilename = guiFilename;

CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{


+ 49
- 52
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

// testing macros
@@ -11,13 +11,14 @@
#include "CarlaLv2Utils.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp"
#include "CarlaEngineUtils.hpp"
#include "CarlaPipeUtils.hpp"
#include "CarlaPluginUI.hpp"
#include "CarlaScopeUtils.hpp"
#include "Lv2AtomRingBuffer.hpp"

#include "extra/Base64.hpp"

#include "../modules/lilv/config/lilv_config.h"

extern "C" {
@@ -545,7 +546,7 @@ public:
{
char sampleRateStr[32];
{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
std::snprintf(sampleRateStr, 31, "%.12g", kEngine->getSampleRate());
}
sampleRateStr[31] = '\0';
@@ -582,10 +583,10 @@ private:
CarlaEngine* const kEngine;
CarlaPluginLV2* const kPlugin;

CarlaString fFilename;
CarlaString fPluginURI;
CarlaString fUiURI;
UiState fUiState;
String fFilename;
String fPluginURI;
String fUiURI;
UiState fUiState;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeServerLV2)
};
@@ -1476,7 +1477,7 @@ public:

void setWindowTitle(const char* const title) noexcept
{
CarlaString uiTitle;
String uiTitle;

if (title != nullptr)
{
@@ -1489,7 +1490,7 @@ public:
}

std::free(const_cast<char*>(fLv2Options.windowTitle));
fLv2Options.windowTitle = uiTitle.releaseBufferPointer();
fLv2Options.windowTitle = uiTitle.getAndReleaseBuffer();

fLv2Options.opts[CarlaPluginLV2Options::WindowTitle].size = (uint32_t)std::strlen(fLv2Options.windowTitle);
fLv2Options.opts[CarlaPluginLV2Options::WindowTitle].value = fLv2Options.windowTitle;
@@ -1651,7 +1652,8 @@ public:
if (parameterId == UINT32_MAX)
break;

std::vector<uint8_t> chunk(carla_getChunkFromBase64String(value));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, value);
CARLA_SAFE_ASSERT_RETURN(chunk.size() > 0,);

#ifdef CARLA_PROPER_CPP11_SUPPORT
@@ -1843,7 +1845,7 @@ public:
tmpBuf[0xfe] = '\0';

const CarlaMutexLocker cml(fPipeServer.getPipeLock());
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;

// write URI mappings
uint32_t u = 0;
@@ -1938,11 +1940,6 @@ public:

fPipeServer.syncMessages();
}

#ifndef BUILD_BRIDGE
if (fUI.rdfDescriptor->Type == LV2_UI_MOD)
pData->tryTransient();
#endif
}
else
{
@@ -2547,7 +2544,7 @@ public:
}

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;
uint32_t iCtrl = 0;

for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iCvIn=0, iCvOut=0, iEvIn=0, iEvOut=0; i < portCount; ++i)
@@ -3318,7 +3315,18 @@ public:
case LV2_UI_OLD_EXTERNAL:
break;
default:
pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI|PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
for (uint32_t i = 0; i < fUI.rdfDescriptor->ExtensionCount; ++i)
{
const char* const extension = fUI.rdfDescriptor->Extensions[i];
CARLA_SAFE_ASSERT_CONTINUE(extension != nullptr);

if (std::strcmp(extension, LV2_UI__noUserResize) == 0)
{
pData->hints &= ~PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
break;
}
}
break;
}
}
@@ -5364,7 +5372,7 @@ public:

const char* getUiBridgeBinary(const LV2_Property type) const
{
CarlaString bridgeBinary(pData->engine->getOptions().binaryDir);
String bridgeBinary(pData->engine->getOptions().binaryDir);

if (bridgeBinary.isEmpty())
return nullptr;
@@ -5392,9 +5400,6 @@ public:
case LV2_UI_X11:
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-lv2-x11";
break;
case LV2_UI_MOD:
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-lv2-modgui";
break;
#if 0
case LV2_UI_EXTERNAL:
case LV2_UI_OLD_EXTERNAL:
@@ -5412,7 +5417,7 @@ public:
if (! File(bridgeBinary.buffer()).existsAsFile())
return nullptr;

return bridgeBinary.dupSafe();
return carla_strdup_safe(bridgeBinary);
}

// -------------------------------------------------------------------
@@ -5839,7 +5844,7 @@ public:
return nullptr;
}

CarlaString basedir(pData->engine->getName());
String basedir(pData->engine->getName());

if (temporary)
basedir += ".tmp";
@@ -5902,7 +5907,7 @@ public:
return File();
}

CarlaString basedir(pData->engine->getName());
String basedir(pData->engine->getName());

if (temporary)
basedir += ".tmp";
@@ -5974,7 +5979,7 @@ public:
if (type == kUridAtomString || type == kUridAtomPath)
cData.value = carla_strdup((const char*)value);
else
cData.value = CarlaString::asBase64(value, size).dup();
cData.value = carla_strdup(String::asBase64(value, size));

return LV2_STATE_SUCCESS;
}
@@ -5988,7 +5993,7 @@ public:
if (type == kUridAtomString || type == kUridAtomPath)
newData.value = carla_strdup((const char*)value);
else
newData.value = CarlaString::asBase64(value, size).dup();
newData.value = carla_strdup(String::asBase64(value, size));

pData->custom.append(newData);

@@ -6047,7 +6052,8 @@ public:
fLastStateChunk = nullptr;
}

std::vector<uint8_t> chunk(carla_getChunkFromBase64String(stringData));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, stringData);
CARLA_SAFE_ASSERT_RETURN(chunk.size() > 0, nullptr);

fLastStateChunk = std::malloc(chunk.size());
@@ -6662,7 +6668,7 @@ public:
}
else if (feature.Required && ! is_lv2_feature_supported(feature.URI))
{
CarlaString msg("Plugin wants a feature that is not supported:\n");
String msg("Plugin wants a feature that is not supported:\n");
msg += feature.URI;

canContinue = false;
@@ -6987,8 +6993,8 @@ public:
// ---------------------------------------------------------------
// find the most appropriate ui

int eQt4, eQt5, eGtk2, eGtk3, eCocoa, eWindows, eX11, eMod, iCocoa, iWindows, iX11, iExt, iFinal;
eQt4 = eQt5 = eGtk2 = eGtk3 = eCocoa = eWindows = eX11 = eMod = iCocoa = iWindows = iX11 = iExt = iFinal = -1;
int eQt4, eQt5, eGtk2, eGtk3, eCocoa, eWindows, eX11, iCocoa, iWindows, iX11, iExt, iFinal;
eQt4 = eQt5 = eGtk2 = eGtk3 = eCocoa = eWindows = eX11 = iCocoa = iWindows = iX11 = iExt = iFinal = -1;

#if defined(LV2_UIS_ONLY_BRIDGES)
const bool preferUiBridges = true;
@@ -7046,9 +7052,6 @@ public:
case LV2_UI_OLD_EXTERNAL:
iExt = ii;
break;
case LV2_UI_MOD:
eMod = ii;
break;
default:
break;
}
@@ -7115,14 +7118,8 @@ public:

if (iFinal < 0)
{
if (eMod < 0)
{
carla_stderr("Failed to find an appropriate LV2 UI for this plugin");
return;
}

// use MODGUI as last resort
iFinal = eMod;
carla_stderr("Failed to find an appropriate LV2 UI for this plugin");
return;
}
}

@@ -7176,8 +7173,7 @@ public:
iFinal == eGtk3 ||
iFinal == eCocoa ||
iFinal == eWindows ||
iFinal == eX11 ||
iFinal == eMod)
iFinal == eX11)
#ifdef BUILD_BRIDGE
&& ! hasShowInterface
#endif
@@ -7190,7 +7186,7 @@ public:
{
carla_stdout("Will use UI-Bridge for '%s', binary: \"%s\"", pData->name, bridgeBinary);

CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{
@@ -7202,7 +7198,7 @@ public:
uiTitle += " (GUI)";
}

fLv2Options.windowTitle = uiTitle.releaseBufferPointer();
fLv2Options.windowTitle = uiTitle.getAndReleaseBuffer();

fUI.type = UI::TYPE_BRIDGE;
fPipeServer.setData(bridgeBinary, fRdfDescriptor->URI, fUI.rdfDescriptor->URI);
@@ -7211,7 +7207,7 @@ public:
return;
}

if (iFinal == eQt4 || iFinal == eQt5 || iFinal == eGtk2 || iFinal == eGtk3 || iFinal == eMod)
if (iFinal == eQt4 || iFinal == eQt5 || iFinal == eGtk2 || iFinal == eGtk3)
{
carla_stderr2("Failed to find UI bridge binary for '%s', cannot use UI", pData->name);
fUI.rdfDescriptor = nullptr;
@@ -7336,7 +7332,7 @@ public:
// initialize ui data

{
CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{
@@ -7348,7 +7344,7 @@ public:
uiTitle += " (GUI)";
}

fLv2Options.windowTitle = uiTitle.releaseBufferPointer();
fLv2Options.windowTitle = uiTitle.getAndReleaseBuffer();
}

fLv2Options.opts[CarlaPluginLV2Options::WindowTitle].size = (uint32_t)std::strlen(fLv2Options.windowTitle);
@@ -7572,7 +7568,7 @@ private:
EngineTimeInfo fLastTimeInfo;

// if plugin provides path parameter, use it as fake "gui"
CarlaString fFilePathURI;
String fFilePathURI;

struct Extensions {
const LV2_Options_Interface* options;
@@ -8344,7 +8340,8 @@ bool CarlaPipeServerLV2::msgReceived(const char* const msg) noexcept
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true);
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true);

std::vector<uint8_t> chunk(carla_getChunkFromBase64String(base64atom));
std::vector<uint8_t> chunk;
d_getChunkFromBase64String_impl(chunk, base64atom);
CARLA_SAFE_ASSERT_UINT2_RETURN(chunk.size() >= sizeof(LV2_Atom), chunk.size(), sizeof(LV2_Atom), true);

#ifdef CARLA_PROPER_CPP11_SUPPORT
@@ -8442,7 +8439,7 @@ CarlaPluginPtr CarlaPlugin::newLV2(const Initializer& init)
#ifndef CARLA_OS_WASM
if (needsArchBridge != nullptr)
{
CarlaString bridgeBinary(init.engine->getOptions().binaryDir);
String bridgeBinary(init.engine->getOptions().binaryDir);
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-native";

return CarlaPlugin::newBridge(init, BINARY_NATIVE, PLUGIN_LV2, needsArchBridge, bridgeBinary);


+ 17
- 34
source/backend/plugin/CarlaPluginNative.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Native Plugin
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
@@ -25,9 +11,6 @@
#include "water/misc/Time.h"
#include "water/text/StringArray.h"

using water::String;
using water::StringArray;

// -----------------------------------------------------------------------
// used in carla-base.cpp

@@ -715,7 +698,7 @@ public:

void setWindowTitle(const char* const title) noexcept
{
CarlaString uiName;
String uiName;

if (title != nullptr)
{
@@ -728,7 +711,7 @@ public:
}

std::free(const_cast<char*>(fHost.uiName));
fHost.uiName = uiName.releaseBufferPointer();
fHost.uiName = uiName.getAndReleaseBuffer();

if (fDescriptor->dispatcher != nullptr && fIsUiVisible)
{
@@ -819,12 +802,12 @@ public:
}
else if (std::strcmp(key, "midiPrograms") == 0 && fDescriptor->set_midi_program != nullptr)
{
StringArray midiProgramList(StringArray::fromTokens(value, ":", ""));
water::StringArray midiProgramList(water::StringArray::fromTokens(value, ":", ""));

if (midiProgramList.size() == MAX_MIDI_CHANNELS)
{
uint8_t channel = 0;
for (String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
for (water::String *it=midiProgramList.begin(), *end=midiProgramList.end(); it != end; ++it)
{
const int index(it->getIntValue());

@@ -1160,7 +1143,7 @@ public:
}

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

// Audio Ins
for (j=0; j < aIns; ++j)
@@ -1180,7 +1163,7 @@ public:
else if (aIns > 1 && ! forcedStereoIn)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -1217,7 +1200,7 @@ public:
else if (aOuts > 1 && ! forcedStereoOut)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -1254,7 +1237,7 @@ public:
else if (cvIns > 1)
{
portName += "cv_input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_input";
@@ -1296,7 +1279,7 @@ public:
else if (cvOuts > 1)
{
portName += "cv_output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_output";
@@ -1334,7 +1317,7 @@ public:
}

portName += "midi-in_";
portName += CarlaString(j+1);
portName += String(j+1);
portName.truncate(portNameSize);

fMidiIn.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, j);
@@ -1358,7 +1341,7 @@ public:
}

portName += "midi-out_";
portName += CarlaString(j+1);
portName += String(j+1);
portName.truncate(portNameSize);

fMidiOut.ports[j] = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, j);
@@ -2967,7 +2950,7 @@ public:
{
CARLA_ASSERT(fHost.uiName == nullptr);

CarlaString uiName;
String uiName;

if (pData->uiTitle.isNotEmpty())
{
@@ -2979,7 +2962,7 @@ public:
uiName += " (GUI)";
}

fHost.uiName = uiName.releaseBufferPointer();
fHost.uiName = uiName.getAndReleaseBuffer();
}

// ---------------------------------------------------------------
@@ -3085,8 +3068,8 @@ private:
bool fInlineDisplayNeedsRedraw;
int64_t fInlineDisplayLastRedrawTime;

CarlaString fLastProjectFilename;
CarlaString fLastProjectFolder;
String fLastProjectFilename;
String fLastProjectFolder;

float** fAudioAndCvInBuffers;
float** fAudioAndCvOutBuffers;


+ 6
- 21
source/backend/plugin/CarlaPluginSFZero.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla SFZero Plugin
* Copyright (C) 2018-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
#include "CarlaEngine.hpp"
@@ -35,7 +21,6 @@
using water::AudioSampleBuffer;
using water::File;
using water::MidiMessage;
using water::String;

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

@@ -229,7 +214,7 @@ public:
pData->param.createNew(1, false);

const uint portNameSize(pData->engine->getMaxPortNameSize());
CarlaString portName;
String portName;

// ---------------------------------------
// Audio Outputs
@@ -713,11 +698,11 @@ public:

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

const String basename(File(filename).getFileNameWithoutExtension());
const water::String basename(File(filename).getFileNameWithoutExtension());

CarlaString label2(label != nullptr ? label : basename.toRawUTF8());
String label2(label != nullptr ? label : basename.toRawUTF8());

fLabel = label2.dup();
fLabel = carla_strdup(label2);
fRealName = carla_strdup(basename.toRawUTF8());

pData->filename = carla_strdup(filename);


+ 7
- 7
source/backend/plugin/CarlaPluginVST2.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaPluginInternal.hpp"
@@ -369,7 +369,7 @@ public:
if (fUI.window == nullptr || pData->uiTitle.isNotEmpty())
return;

CarlaString uiTitle(pData->name);
String uiTitle(pData->name);
uiTitle += " (GUI)";
fUI.window->setTitle(uiTitle.buffer());
}
@@ -501,7 +501,7 @@ public:

if (yesNo)
{
CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{
@@ -733,7 +733,7 @@ public:

const EngineProcessMode processMode = pData->engine->getProccessMode();
const uint portNameSize = pData->engine->getMaxPortNameSize();
CarlaString portName;
String portName;

// Audio Ins
for (uint32_t j=0; j < aIns; ++j)
@@ -749,7 +749,7 @@ public:
if (aIns > 1)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -774,7 +774,7 @@ public:
if (aOuts > 1)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -2465,7 +2465,7 @@ public:
VST_Function vstFn;

#ifdef CARLA_OS_MAC
CarlaString filenameCheck(filename);
String filenameCheck(filename);
filenameCheck.toLower();

if (filenameCheck.endsWith(".vst") || filenameCheck.endsWith(".vst/"))


+ 93
- 22
source/backend/plugin/CarlaPluginVST3.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

/* TODO list
@@ -9,6 +9,7 @@
#include "CarlaEngine.hpp"

#include "CarlaBackendUtils.hpp"
#include "CarlaMathUtils.hpp"
#include "CarlaVst3Utils.hpp"

#include "CarlaPluginUI.hpp"
@@ -895,7 +896,12 @@ private:
// --------------------------------------------------------------------------------------------------------------------

struct carla_v3_output_event_list : v3_event_list_cpp {
v3_event* const events;
uint16_t numEvents;

carla_v3_output_event_list()
: events(new v3_event[kPluginMaxMidiEvents]),
numEvents(0)
{
query_interface = v3_query_interface_static<v3_event_list_iid>;
ref = v3_ref_static;
@@ -905,6 +911,11 @@ struct carla_v3_output_event_list : v3_event_list_cpp {
list.add_event = add_event;
}

~carla_v3_output_event_list()
{
delete[] events;
}

private:
static uint32_t V3_API get_event_count(void*)
{
@@ -920,10 +931,13 @@ private:
return V3_NOT_IMPLEMENTED;
}

static v3_result V3_API add_event(void*, v3_event*)
static v3_result V3_API add_event(void* const self, v3_event* const event)
{
carla_debug("TODO %s", __PRETTY_FUNCTION__);
return V3_NOT_IMPLEMENTED;
carla_v3_output_event_list* const me = *static_cast<carla_v3_output_event_list**>(self);
if (me->numEvents >= kPluginMaxMidiEvents)
return V3_NOMEM;
std::memcpy(&me->events[me->numEvents++], event, sizeof(v3_event));
return V3_OK;
}

CARLA_DECLARE_NON_COPYABLE(carla_v3_output_event_list)
@@ -1620,7 +1634,7 @@ public:

if (yesNo)
{
CarlaString uiTitle;
String uiTitle;

if (pData->uiTitle.isNotEmpty())
{
@@ -1658,7 +1672,7 @@ public:
fUI.window->setTitle(uiTitle.buffer());

#ifndef CARLA_OS_MAC
if (carla_isNotZero(opts.uiScale))
if (d_isNotZero(opts.uiScale))
{
// TODO inform plugin of what UI scale we use
}
@@ -1762,7 +1776,7 @@ public:
#ifndef CARLA_OS_MAC
const EngineOptions& opts(pData->engine->getOptions());

if (carla_isNotZero(opts.uiScale))
if (d_isNotZero(opts.uiScale))
{
// TODO
}
@@ -2060,7 +2074,7 @@ public:

const EngineProcessMode processMode = pData->engine->getProccessMode();
const uint portNameSize = pData->engine->getMaxPortNameSize();
CarlaString portName;
String portName;

// Audio Ins
for (uint32_t j=0; j < aIns; ++j)
@@ -2076,7 +2090,7 @@ public:
if (aIns > 1)
{
portName += "input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "input";
@@ -2102,7 +2116,7 @@ public:
if (aOuts > 1)
{
portName += "output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "output";
@@ -2128,7 +2142,7 @@ public:
if (cvIns > 1)
{
portName += "cv_input_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_input";
@@ -2154,7 +2168,7 @@ public:
if (cvOuts > 1)
{
portName += "cv_output_";
portName += CarlaString(j+1);
portName += String(j+1);
}
else
portName += "cv_output";
@@ -2305,6 +2319,8 @@ public:
pData->hints |= PLUGIN_HAS_CUSTOM_UI;
pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
if (v3_cpp_obj(fV3.view)->can_resize(fV3.view) == V3_TRUE)
pData->hints |= PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
}
#endif

@@ -3016,15 +3032,6 @@ public:

} // End of Plugin processing (no events)

// ------------------------------------------------------------------------------------------------------------
// MIDI Output

if (pData->event.portOut != nullptr)
{
// TODO

} // End of MIDI Output

fFirstActive = false;

// ------------------------------------------------------------------------------------------------------------
@@ -3131,6 +3138,67 @@ public:
v3_cpp_obj(fV3.processor)->process(fV3.processor, &processData);
} CARLA_SAFE_EXCEPTION("process");

// ------------------------------------------------------------------------------------------------------------
// Handle MIDI output

int32_t minPortOutOffset = 0;

if (fEvents.eventOutputs != nullptr)
{
uint8_t midiData[3], midiSize;

for (uint32_t i=0; i < fEvents.eventOutputs->numEvents; ++i)
{
v3_event& v3event(fEvents.eventOutputs->events[i]);

if (v3event.bus_index != 0)
continue;

switch (v3event.type)
{
case V3_EVENT_NOTE_OFF:
midiData[0] = MIDI_STATUS_NOTE_OFF | (v3event.note_off.channel & MIDI_CHANNEL_BIT);
midiData[1] = v3event.note_off.pitch;
midiData[2] = carla_fixedValue<uint8_t>(0,
MAX_MIDI_VALUE - 1,
v3event.note_off.velocity * MAX_MIDI_VALUE);
midiSize = 3;
break;
case V3_EVENT_NOTE_ON:
midiData[0] = MIDI_STATUS_NOTE_ON | (v3event.note_on.channel & MIDI_CHANNEL_BIT);
midiData[1] = v3event.note_on.pitch;
midiData[2] = carla_fixedValue<uint8_t>(0,
MAX_MIDI_VALUE - 1,
v3event.note_on.velocity * MAX_MIDI_VALUE);
midiSize = 3;
break;
case V3_EVENT_POLY_PRESSURE:
midiData[0] = MIDI_STATUS_POLYPHONIC_AFTERTOUCH | (v3event.poly_pressure.channel & MIDI_CHANNEL_BIT);
midiData[1] = v3event.poly_pressure.pitch;
midiData[2] = carla_fixedValue<uint8_t>(0,
MAX_MIDI_VALUE - 1,
v3event.poly_pressure.pressure * MAX_MIDI_VALUE);
midiSize = 3;
break;
case V3_EVENT_LEGACY_MIDI_CC_OUT:
midiData[0] = MIDI_STATUS_CONTROL_CHANGE | (v3event.midi_cc_out.channel & MIDI_CHANNEL_BIT);
midiData[1] = v3event.midi_cc_out.cc_number;
midiData[2] = v3event.midi_cc_out.value;
midiSize = 3;
break;
default:
continue;
}

if (! pData->event.portOut->writeMidiEvent(static_cast<uint32_t>(v3event.sample_offset) + timeOffset,
midiSize,
midiData))
break;

minPortOutOffset = v3event.sample_offset;
}
}

// ------------------------------------------------------------------------------------------------------------
// Handle parameter outputs

@@ -3157,7 +3225,7 @@ public:
channel = pData->param.data[i].midiChannel;
param = static_cast<uint16_t>(pData->param.data[i].mappedControlIndex);

pData->event.portOut->writeControlEvent(queue->offset,
pData->event.portOut->writeControlEvent(std::max(minPortOutOffset, queue->offset) + timeOffset,
channel,
kEngineControlEventTypeParameter,
param,
@@ -4168,6 +4236,9 @@ private:

if (eventInputs != nullptr)
eventInputs->numEvents = 0;

if (eventOutputs != nullptr)
eventOutputs->numEvents = 0;
}

void prepare()


+ 22
- 12
source/backend/utils/CachedPlugins.cpp View File

@@ -1,10 +1,9 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaUtils.h"

#include "CarlaNative.h"
#include "CarlaString.hpp"
#include "CarlaBackendUtils.hpp"
#include "CarlaLv2Utils.hpp"

@@ -178,7 +177,7 @@ static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2Worl
// text data

{
static CarlaString suri, sname, smaker, slicense;
static String suri, sname, smaker, slicense;
suri.clear(); sname.clear(); smaker.clear(); slicense.clear();

suri = lilvPlugin.get_uri().as_uri();
@@ -263,15 +262,26 @@ static const CarlaCachedPluginInfo* get_cached_plugin_lv2(Lv2WorldClass& lv2Worl
if (false)
#endif
{
info.hints |= CB::PLUGIN_HAS_CUSTOM_EMBED_UI;
info.hints |= CB::PLUGIN_HAS_CUSTOM_EMBED_UI|CB::PLUGIN_HAS_CUSTOM_RESIZABLE_UI;

Lilv::Nodes lilvSupportedFeatureNodes(lilvUI.get_supported_features());
LILV_FOREACH(nodes, it, lilvSupportedFeatureNodes)
{
Lilv::Node lilvFeatureNode(lilvSupportedFeatureNodes.get(it));
const char* const featureURI(lilvFeatureNode.as_uri());
CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);

if (std::strcmp(featureURI, LV2_UI__noUserResize) == 0)
{
info.hints &= ~CB::PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
break;
}
}
lilv_nodes_free(const_cast<LilvNodes*>(lilvSupportedFeatureNodes.me));
break;
}
}
}
#ifdef CARLA_OS_LINUX
else if (lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr)
info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
#endif

lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));
}
@@ -589,7 +599,7 @@ static const CarlaCachedPluginInfo* get_cached_plugin_sfz(const water::File& fil
{
static CarlaCachedPluginInfo info;

static CarlaString name, filename;
static String name, filename;

name = file.getFileNameWithoutExtension().toRawUTF8();
name.replace('_',' ');
@@ -627,8 +637,8 @@ static const CarlaCachedPluginInfo* get_cached_plugin_jsfx(const CB::CarlaJsfxUn

ysfx_config_u config(ysfx_config_new());

const CarlaString rootPath = unit.getRootPath();
const CarlaString filePath = unit.getFilePath();
const String rootPath = unit.getRootPath();
const String filePath = unit.getFilePath();

ysfx_register_builtin_audio_formats(config.get());
ysfx_set_import_root(config.get(), rootPath);
@@ -653,7 +663,7 @@ static const CarlaCachedPluginInfo* get_cached_plugin_jsfx(const CB::CarlaJsfxUn
return &info;
}

static CarlaString name, label, maker;
static String name, label, maker;
label = unit.getFileId();
name = ysfx_get_name(effect.get());
maker = ysfx_get_author(effect.get());


+ 5
- 5
source/backend/utils/Information.cpp View File

@@ -1,8 +1,7 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaUtils.h"
#include "CarlaString.hpp"

#if defined(HAVE_FLUIDSYNTH) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
# include <fluidsynth.h>
@@ -26,6 +25,7 @@
# pragma GCC diagnostic pop
#endif

#include "extra/String.hpp"
#include "water/files/File.h"

// -------------------------------------------------------------------------------------------------------------------
@@ -34,7 +34,7 @@ const char* carla_get_complete_license_text()
{
carla_debug("carla_get_complete_license_text()");

static CarlaString retText;
static String retText;

if (retText.isEmpty())
{
@@ -196,7 +196,7 @@ const char* carla_get_library_filename()
{
carla_debug("carla_get_library_filename()");

static CarlaString ret;
static String ret;

if (ret.isEmpty())
{
@@ -211,7 +211,7 @@ const char* carla_get_library_folder()
{
carla_debug("carla_get_library_folder()");

static CarlaString ret;
static String ret;

if (ret.isEmpty())
{


+ 11
- 9
source/backend/utils/PluginDiscovery.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaUtils.h"
@@ -7,8 +7,10 @@
#include "CarlaBinaryUtils.hpp"
#include "CarlaJuceUtils.hpp"
#include "CarlaPipeUtils.hpp"
#include "CarlaScopeUtils.hpp"
#include "CarlaSha1Utils.hpp"
#include "CarlaTimeUtils.hpp"

#include "extra/Time.hpp"

#include "water/files/File.h"
#include "water/files/FileInputStream.h"
@@ -68,8 +70,8 @@ struct CarlaPluginDiscoveryOptions {
#if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN)
struct {
bool autoPrefix;
CarlaString executable;
CarlaString fallbackPrefix;
String executable;
String fallbackPrefix;
} wine;
#endif

@@ -152,7 +154,7 @@ public:
idlePipe();

// automatically skip a plugin if 30s passes without a reply
const uint32_t timeNow = carla_gettime_ms();
const uint32_t timeNow = d_gettime_ms();

if (timeNow - fLastMessageTime < 30000)
return true;
@@ -189,7 +191,7 @@ public:
protected:
bool msgReceived(const char* const msg) noexcept
{
fLastMessageTime = carla_gettime_ms();
fLastMessageTime = d_gettime_ms();

if (std::strcmp(msg, "warning") == 0 || std::strcmp(msg, "error") == 0)
{
@@ -381,12 +383,12 @@ private:
uint fBinaryIndex;
const uint fBinaryCount;
const std::vector<water::File> fBinaries;
const CarlaString fDiscoveryTool;
const String fDiscoveryTool;

uint32_t fLastMessageTime;

CarlaPluginDiscoveryInfo fNextInfo;
CarlaString fNextSha1Sum;
String fNextSha1Sum;
char* fNextLabel;
char* fNextMaker;
char* fNextName;
@@ -396,7 +398,7 @@ private:
using water::File;
using water::String;

fLastMessageTime = carla_gettime_ms();
fLastMessageTime = d_gettime_ms();
fPluginsFoundInBinary = false;
fNextSha1Sum.clear();



+ 9
- 9
source/bridges-plugin/CarlaBridgePlugin.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef BUILD_BRIDGE
@@ -12,7 +12,6 @@
#include "CarlaBackendUtils.hpp"
#include "CarlaJuceUtils.hpp"
#include "CarlaMainLoop.hpp"
#include "CarlaTimeUtils.hpp"

#include "CarlaMIDI.h"

@@ -38,6 +37,8 @@
# include <X11/Xlib.h>
#endif

#include "extra/Sleep.hpp"

#include "water/files/File.h"
#include "water/misc/Time.h"

@@ -51,7 +52,6 @@ using CARLA_BACKEND_NAMESPACE::runMainLoopOnce;

using water::CharPointer_UTF8;
using water::File;
using water::String;

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

@@ -112,7 +112,7 @@ static void initSignalHandler()
// -------------------------------------------------------------------------

static CarlaHostHandle gHostHandle;
static CarlaString gProjectFilename;
static String gProjectFilename;

static void gIdle()
{
@@ -230,9 +230,9 @@ public:
gIdle();
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
// MacOS and Win32 have event-loops to run, so minimize sleep time
carla_msleep(1);
d_msleep(1);
#else
carla_msleep(5);
d_msleep(5);
#endif
if (testing && timeToEnd - water::Time::currentTimeMillis() < 0)
break;
@@ -418,7 +418,7 @@ int main(int argc, char* argv[])
// ---------------------------------------------------------------------
// Set client name

CarlaString clientName;
String clientName;

if (name != nullptr)
{
@@ -430,7 +430,7 @@ int main(int argc, char* argv[])
CARLA_SAFE_ASSERT_RETURN(label != nullptr && label[0] != '\0', 1);

// LV2 URI is not usable as client name, create a usable name from URI
CarlaString label2(label);
String label2(label);

// truncate until last valid char
for (std::size_t i=label2.length()-1; i != 0; --i)
@@ -544,7 +544,7 @@ int main(int argc, char* argv[])
{
if (sched_setscheduler(0, SCHED_RR|SCHED_RESET_ON_FORK, &sparam) < 0)
{
CarlaString error(std::strerror(errno));
String error(std::strerror(errno));
carla_stderr("Failed to set high priority, error %i: %s", errno, error.buffer());
}
}


+ 12
- 26
source/bridges-plugin/CarlaBridgeSingleLV2.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla LV2 Single Plugin
* Copyright (C) 2017-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 General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef BUILD_BRIDGE
# error This file should not be compiled if not building bridge
@@ -57,10 +43,10 @@ public:
return;

// xxxxx
CarlaString binaryDir(bundlePath);
String binaryDir(bundlePath);
binaryDir += CARLA_OS_SEP_STR "bin" CARLA_OS_SEP_STR;

CarlaString resourceDir(bundlePath);
String resourceDir(bundlePath);
resourceDir += CARLA_OS_SEP_STR "res" CARLA_OS_SEP_STR;

pData->bufferSize = fBufferSize;
@@ -79,8 +65,8 @@ public:
if (pData->options.binaryDir != nullptr)
delete[] pData->options.binaryDir;

pData->options.binaryDir = binaryDir.dup();
pData->options.resourceDir = resourceDir.dup();
pData->options.binaryDir = carla_strdup(binaryDir);
pData->options.resourceDir = carla_strdup(resourceDir);

setCallback(_engine_callback, this);

@@ -695,17 +681,17 @@ const LV2_Descriptor* lv2_descriptor(uint32_t index)
if (index != 0)
return nullptr;

static CarlaString ret;
static String ret;

if (ret.isEmpty())
{
using namespace water;
const File file(File::getSpecialLocation(File::currentExecutableFile).withFileExtension("ttl"));
#ifdef CARLA_OS_WIN
ret = String("file:///" + file.getFullPathName()).toRawUTF8();
ret = water::String("file:///" + file.getFullPathName()).toRawUTF8();
ret.replace('\\','/');
#else
ret = String("file://" + file.getFullPathName()).toRawUTF8();
ret = water::String("file://" + file.getFullPathName()).toRawUTF8();
#endif
}

@@ -730,16 +716,16 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
{
carla_debug("lv2ui_descriptor(%i)", index);

static CarlaString ret;
static String ret;

{
using namespace water;
const File file(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("ext-ui"));
#ifdef CARLA_OS_WIN
ret = String("file:///" + file.getFullPathName()).toRawUTF8();
ret = water::String("file:///" + file.getFullPathName()).toRawUTF8();
ret.replace('\\','/');
#else
ret = String("file://" + file.getFullPathName()).toRawUTF8();
ret = water::String("file://" + file.getFullPathName()).toRawUTF8();
#endif
}



+ 7
- 20
source/bridges-ui/CarlaBridgeFormat.cpp View File

@@ -1,29 +1,16 @@
/*
* Carla Bridge UI
* Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaBridgeFormat.hpp"
#include "CarlaBridgeToolkit.hpp"

#include "CarlaBase64Utils.hpp"
#include "CarlaProcessUtils.hpp"
#include "CarlaTimeUtils.hpp"

#include "CarlaMIDI.h"

#include "extra/Base64.hpp"
#include "extra/Sleep.hpp"

// needed for atom-util
#ifndef nullptr
# undef NULL
@@ -127,7 +114,7 @@ bool CarlaBridgeFormat::msgReceived(const char* const msg) noexcept
CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(base64Size), true);
CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(base64atom, false, base64Size), true);

carla_getChunkFromBase64String_impl(fBase64ReservedChunk, base64atom);
d_getChunkFromBase64String_impl(fBase64ReservedChunk, base64atom);
CARLA_SAFE_ASSERT_UINT2_RETURN(fBase64ReservedChunk.size() >= sizeof(LV2_Atom),
fBase64ReservedChunk.size(), sizeof(LV2_Atom), true);

@@ -320,7 +307,7 @@ bool CarlaBridgeFormat::init(const int argc, const char* argv[])
for (; ++fLastMsgTimer < 50 && ! fGotOptions;)
{
idlePipe(true);
carla_msleep(20);
d_msleep(20);
}

if (! fGotOptions)


+ 6
- 19
source/bridges-ui/CarlaBridgeFormat.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Bridge UI
* Copyright (C) 2011-2021 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_BRIDGE_FORMAT_HPP_INCLUDED
#define CARLA_BRIDGE_FORMAT_HPP_INCLUDED
@@ -22,7 +8,8 @@

#include "CarlaLibUtils.hpp"
#include "CarlaPipeUtils.hpp"
#include "CarlaString.hpp"

#include "extra/String.hpp"

#include "lv2/atom.h"
#include "lv2/urid.h"
@@ -144,7 +131,7 @@ public:
/*!
* Window title.
*/
CarlaString windowTitle;
String windowTitle;

/*!
* Transient window id (parent), zero if unset.
@@ -177,7 +164,7 @@ protected:
CarlaBridgeToolkit* fToolkit;

lib_t fLib;
CarlaString fLibFilename;
String fLibFilename;
std::vector<uint8_t> fBase64ReservedChunk;

/*! @internal */


+ 3
- 17
source/bridges-ui/CarlaBridgeFormatLV2.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla Bridge UI
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaBridgeFormat.hpp"
#include "CarlaBridgeToolkit.hpp"
@@ -1555,7 +1541,7 @@ int main(int argc, const char* argv[])
// try to get sampleRate value
if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
{
const CarlaScopedLocale csl;
const ScopedSafeLocale ssl;
gInitialSampleRate = std::atof(sampleRateStr);
}



+ 6
- 19
source/bridges-ui/CarlaBridgeToolkitNative.cpp View File

@@ -1,32 +1,19 @@
/*
* Carla Bridge UI
* Copyright (C) 2014-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaBridgeFormat.hpp"
#include "CarlaBridgeToolkit.hpp"

#include "CarlaMainLoop.hpp"
#include "CarlaPluginUI.hpp"
#include "CarlaTimeUtils.hpp"
#include "CarlaUtils.h"

#if defined(CARLA_OS_MAC) && defined(BRIDGE_COCOA)
# include "CarlaMacUtils.hpp"
#endif

#include "extra/Sleep.hpp"

#if defined(HAVE_X11) && defined(BRIDGE_X11)
# include <X11/Xlib.h>
#endif
@@ -118,9 +105,9 @@ public:
fHostUI->idle();
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
// MacOS and Win32 have event-loops to run, so minimize sleep time
carla_msleep(1);
d_msleep(1);
#else
carla_msleep(33);
d_msleep(33);
#endif
}
}


+ 1
- 1
source/bridges-ui/Makefile View File

@@ -22,7 +22,7 @@ endif

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

BUILD_CXX_FLAGS += -DBUILD_BRIDGE -DBUILD_BRIDGE_UI -I. -I$(CWD)/backend -I$(CWD)/includes -I$(CWD)/utils -I$(CWD)/modules
BUILD_CXX_FLAGS += -DBUILD_BRIDGE -DBUILD_BRIDGE_UI -I. -I$(CWD)/backend -I$(CWD)/includes -I$(CWD)/modules -I$(CWD)/utils
LINK_FLAGS += $(WATER_LIBS)

ifneq ($(WASM),true)


+ 18
- 14
source/discovery/carla-discovery.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "CarlaBackendUtils.hpp"
@@ -16,6 +16,8 @@
#include "CarlaVst3Utils.hpp"
#include "CarlaClapUtils.hpp"

#include "extra/ScopedPointer.hpp"

#ifndef BUILDING_CARLA_FOR_WINE
# include "CarlaPipeUtils.cpp"
#endif
@@ -152,7 +154,7 @@ public:
};
#endif

CarlaScopedPointer<DiscoveryPipe> gPipe;
ScopedPointer<DiscoveryPipe> gPipe;

// --------------------------------------------------------------------------------------------------------------------
// Don't print ELF/EXE related errors since discovery can find multi-architecture binaries
@@ -799,7 +801,7 @@ static void do_lv2_check(const char* const bundle, const bool doInit)
Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, bundle));
CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(),);

CarlaString sBundle(bundleNode.as_uri());
String sBundle(bundleNode.as_uri());

if (! sBundle.endsWith("/"))
sBundle += "/";
@@ -833,7 +835,7 @@ static void do_lv2_check(const char* const bundle, const bool doInit)
const char* const URI = it.getValue(nullptr);
CARLA_SAFE_ASSERT_CONTINUE(URI != nullptr);

CarlaScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));
ScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));

if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr)
{
@@ -1155,9 +1157,9 @@ static bool do_vst2_check(lib_t& libHandle, const char* const filename, const bo
gVstCurrentUniqueId = effect->uniqueID;

char strBuf[STR_MAX+1];
CarlaString cName;
CarlaString cProduct;
CarlaString cVendor;
String cName;
String cProduct;
String cVendor;
PluginCategory category;
LinkedList<intptr_t> uniqueIds;

@@ -1822,9 +1824,9 @@ static bool do_vst3_check(lib_t& libHandle, const char* const filename, const bo
if (v3_cpp_obj(view)->is_platform_type_supported(view, V3_VIEW_PLATFORM_TYPE_NATIVE) == V3_TRUE)
{
hints |= PLUGIN_HAS_CUSTOM_UI;
#ifndef BUILD_BRIDGE
hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
#endif
if (v3_cpp_obj(view)->can_resize(view) == V3_TRUE)
hints |= PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
}

v3_cpp_obj_unref(view);
@@ -2632,10 +2634,12 @@ static bool do_clap_check(lib_t& libHandle, const char* const filename, const bo
if (gui != nullptr)
{
hints |= PLUGIN_HAS_CUSTOM_UI;
#ifndef BUILD_BRIDGE
if (gui->is_api_supported(plugin, CLAP_WINDOW_API_NATIVE, false))
{
hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
#endif
if (gui->can_resize(plugin))
hints |= PLUGIN_HAS_CUSTOM_RESIZABLE_UI;
}
}
#endif

@@ -2739,8 +2743,8 @@ static void do_fluidsynth_check(const char* const filename, const PluginType typ
delete_fluid_settings(f_settings);
}

CarlaString name(file.getFileNameWithoutExtension().toRawUTF8());
CarlaString label(name);
String name(file.getFileNameWithoutExtension().toRawUTF8());
String label(name);

// 2 channels
DISCOVERY_OUT("init", "------------");
@@ -2852,7 +2856,7 @@ int main(int argc, const char* argv[])
const char* const filename = argv[2];
const PluginType type = getPluginTypeFromString(stype);

CarlaString filenameCheck(filename);
String filenameCheck(filename);
filenameCheck.toLower();

bool openLib;


+ 2
- 2
source/frontend/C++/carla_app.cpp View File

@@ -58,8 +58,8 @@ CarlaApplication::CarlaApplication(const QString appName, int& argc, char* argv[
QApplication.addLibraryPath(CWD)

// Needed for local wine build
if WINDOWS and CWD.endswith(("frontend", "resources")) and os.getenv("CXFREEZE") is None:
if kIs64bit:
if CARLA_OS_WIN and CWD.endswith(("frontend", "resources")) and os.getenv("CXFREEZE") is None:
if CARLA_OS_64BIT:
path = "H:\\builds\\msys2-x86_64\\mingw64\\share\\qt5\\plugins"
else:
path = "H:\\builds\\msys2-i686\\mingw32\\share\\qt5\\plugins"


+ 13
- 6
source/frontend/Makefile View File

@@ -34,12 +34,24 @@ else
NON_STATIC_LINK_FLAGS = $(LINK_FLAGS)
endif

ifeq ($(STATIC_PLUGIN_TARGET),true)

ifeq ($(WINDOWS),true)
QT_LINK_FLAGS += -L$(BINDIR) $(BINDIR)/libcarla_utils.dll
else
QT_LINK_FLAGS += -L$(BINDIR) -lcarla_utils
endif

else

ifeq ($(WINDOWS),true)
QT_LINK_FLAGS += -L$(BINDIR) $(BINDIR)/libcarla_standalone2.dll $(BINDIR)/libcarla_utils.dll
else
QT_LINK_FLAGS += -L$(BINDIR) -lcarla_standalone2 -lcarla_utils
endif

endif

ifeq ($(MACOS),true)
QT_LINK_FLAGS += -install_name @rpath/libcarla_frontend.dylib
# FIXME this does not work: -Wl,-rpath,@loader_path
@@ -58,6 +70,7 @@ QMs = $(patsubst %,translations/carla_%.qm,$(I18N_LANGUAGES))

CPP_FILES = \
carla_frontend.cpp \
dialogs/aboutdialog.cpp \
dialogs/jackappdialog.cpp \
pluginlist/pluginlistdialog.cpp

@@ -69,7 +82,6 @@ OBJS = $(CPP_FILES:%=$(OBJDIR)/%.o)
RES = \
qt_config.py \
resources_rc.py \
$(BINDIR)/resources/modgui \
$(BINDIR)/resources/patchcanvas \
$(BINDIR)/resources/widgets \
$(BINDIR)/resources/bigmeter-ui \
@@ -80,7 +92,6 @@ RES = \
$(BINDIR)/resources/carla_backend_qt.py \
$(BINDIR)/resources/carla_host.py \
$(BINDIR)/resources/carla_host_control.py \
$(BINDIR)/resources/carla_modgui.py \
$(BINDIR)/resources/carla_settings.py \
$(BINDIR)/resources/carla_skin.py \
$(BINDIR)/resources/carla_shared.py \
@@ -91,7 +102,6 @@ RES = \
$(BINDIR)/resources/notes-ui \
$(BINDIR)/resources/xycontroller-ui \
$(BINDIR)/resources/resources_rc.py \
$(BINDIR)/resources/ui_carla_about.py \
$(BINDIR)/resources/ui_carla_edit.py \
$(BINDIR)/resources/ui_carla_host.py \
$(BINDIR)/resources/ui_carla_osc_connect.py \
@@ -124,11 +134,8 @@ PLUGINLIST_UI_FILES = $(wildcard pluginlist/*.ui)
UIs = $(DIALOG_UI_FILES:dialogs/%.ui=dialogs/ui_%.h)
UIs += $(PLUGINLIST_UI_FILES:pluginlist/%.ui=pluginlist/ui_%.h)

UIs += $(DIALOG_UI_FILES:%.ui=%_ui.py)

# old stuff, not yet converted
UIs += \
ui_carla_about.py \
ui_carla_edit.py \
ui_carla_host.py \
ui_carla_osc_connect.py \


+ 3
- 3
source/frontend/carla-plugin View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -541,7 +541,7 @@ class CarlaEmbedW(QEmbedWidget):

# set our gui as parent for all plugins UIs
if self.host.manageUIs:
if MACOS:
if CARLA_OS_MAC:
nsViewPtr = int(self.fWinId)
winIdStr = "%x" % gCarla.utils.cocoa_get_window(nsViewPtr)
else:
@@ -579,7 +579,7 @@ if __name__ == '__main__':
except:
winId = 0

usingEmbed = bool(LINUX and winId != 0)
usingEmbed = bool(CARLA_OS_LINUX and winId != 0)

# -------------------------------------------------------------
# Init host backend (part 1)


+ 26
- 14
source/frontend/carla_app.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -18,6 +18,8 @@ from ctypes import CDLL, RTLD_GLOBAL

from qt_compat import qt_config

# pylint: disable=import-error

if qt_config == 5:
from PyQt5.QtCore import QT_VERSION, Qt, QCoreApplication, QLibraryInfo, QLocale, QTranslator
from PyQt5.QtGui import QColor, QIcon, QPalette
@@ -27,17 +29,26 @@ elif qt_config == 6:
from PyQt6.QtGui import QColor, QIcon, QPalette
from PyQt6.QtWidgets import QApplication

# pylint: enable=import-error
# pylint: disable=possibly-used-before-assignment

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

from carla_backend import kIs64bit, LINUX, MACOS, WINDOWS
from carla_backend import (
CARLA_OS_64BIT,
CARLA_OS_LINUX,
CARLA_OS_MAC,
CARLA_OS_WIN,
CARLA_VERSION_STRING,
)

from carla_shared import (
CARLA_KEY_MAIN_USE_PRO_THEME,
CARLA_KEY_MAIN_PRO_THEME_COLOR,
CARLA_DEFAULT_MAIN_USE_PRO_THEME,
CARLA_DEFAULT_MAIN_PRO_THEME_COLOR,
CWD, VERSION,
CWD,
getPaths,
gCarla
)
@@ -50,13 +61,13 @@ class CarlaApplication():
def __init__(self, appName = "Carla2", libPrefix = None):
pathBinaries, pathResources = getPaths(libPrefix)

# Needed for MacOS and Windows
if os.path.exists(CWD) and (MACOS or WINDOWS):
# Needed for macOS and Windows
if os.path.exists(CWD) and (CARLA_OS_MAC or CARLA_OS_WIN):
QApplication.addLibraryPath(CWD)

# Needed for local wine build
if WINDOWS and CWD.endswith(("frontend", "resources")) and os.getenv("CXFREEZE") is None:
if kIs64bit:
if CARLA_OS_WIN and CWD.endswith(("frontend", "resources")) and os.getenv("CXFREEZE") is None:
if CARLA_OS_64BIT:
path = "H:\\PawPawBuilds\\targets\\win64\\lib\\qt5\\plugins"
else:
path = "H:\\PawPawBuilds\\targets\\win32\\lib\\qt5\\plugins"
@@ -94,7 +105,7 @@ class CarlaApplication():

# base settings
settings = QSafeSettings("falkTX", appName)
useProTheme = MACOS or settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, CARLA_DEFAULT_MAIN_USE_PRO_THEME, bool)
useProTheme = CARLA_OS_MAC or settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, CARLA_DEFAULT_MAIN_USE_PRO_THEME, bool)

if not useProTheme:
self.createApp(appName)
@@ -111,7 +122,7 @@ class CarlaApplication():

self.fApp.setStyle("carla" if stylesDir else "fusion")

if WINDOWS:
if CARLA_OS_WIN:
carlastyle1 = os.path.join(pathBinaries, "styles", "carlastyle.dll")
carlastyle2 = os.path.join(pathResources, "styles", "carlastyle.dll")
carlastyle = carlastyle2 if os.path.exists(carlastyle2) else carlastyle1
@@ -123,14 +134,14 @@ class CarlaApplication():
# set palette
proThemeColor = settings.value(CARLA_KEY_MAIN_PRO_THEME_COLOR, CARLA_DEFAULT_MAIN_PRO_THEME_COLOR, str).lower()

if MACOS or proThemeColor == "black":
if CARLA_OS_MAC or proThemeColor == "black":
self.createPaletteBlack()

elif proThemeColor == "blue":
self.createPaletteBlue()

def createApp(self, appName):
if qt_config == 5 and LINUX:
if qt_config == 5 and CARLA_OS_LINUX:
# AA_X11InitThreads is not available on old PyQt versions
try:
attr = Qt.AA_X11InitThreads
@@ -142,17 +153,17 @@ class CarlaApplication():
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

if MACOS:
if CARLA_OS_MAC:
QApplication.setAttribute(Qt.AA_DontShowIconsInMenus)

args = sys.argv[:]

if WINDOWS:
if CARLA_OS_WIN:
args += ["-platform", "windows:fontengine=freetype"]

self.fApp = QCoreApplication(args) if gCarla.nogui else QApplication(args)
self.fApp.setApplicationName(appName)
self.fApp.setApplicationVersion(VERSION)
self.fApp.setApplicationVersion(CARLA_VERSION_STRING)
self.fApp.setOrganizationName("falkTX")

if self.fAppTranslator is not None:
@@ -306,3 +317,4 @@ class CarlaApplication():
self.fApp.quit()

# ------------------------------------------------------------------------------------------------------------
# pylint: enable=possibly-used-before-assignment

+ 40
- 21
source/frontend/carla_backend.py View File

@@ -1,20 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla Backend code
# Copyright (C) 2011-2021 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Global)
@@ -36,14 +22,27 @@ from ctypes import (
# Imports (Custom)

from common import (
kIs64bit, HAIKU, LINUX, MACOS, WINDOWS, VERSION
CARLA_OS_64BIT,
CARLA_OS_BSD,
CARLA_OS_GNU_HURD,
CARLA_OS_HAIKU,
CARLA_OS_LINUX,
CARLA_OS_MAC,
CARLA_OS_UNIX,
CARLA_OS_WASM,
CARLA_OS_WIN,
CARLA_OS_WIN32,
CARLA_OS_WIN64,
CARLA_VERSION_HEX,
CARLA_VERSION_STRING,
CARLA_VERSION_STRMIN,
)

# ---------------------------------------------------------------------------------------------------------------------
# Define custom types

c_enum = c_int
c_uintptr = c_uint64 if kIs64bit else c_uint32
c_uintptr = c_uint64 if CARLA_OS_64BIT else c_uint32

# ---------------------------------------------------------------------------------------------------------------------
# Convert a ctypes c_char_p into a python string
@@ -208,6 +207,21 @@ PLUGIN_USES_MULTI_PROGS = 0x400
# Plugin can make use of inline display API.
PLUGIN_HAS_INLINE_DISPLAY = 0x800

# Plugin has its own custom UI which can be embed into another Window.
# @see carla_embed_custom_ui()
# @note This is very experimental and subject to change at this point
PLUGIN_HAS_CUSTOM_EMBED_UI = 0x1000

# Plugin custom UI is a fake one that simply invokes an open file browser dialog.
PLUGIN_HAS_CUSTOM_UI_USING_FILE_OPEN = 0x2000

# Plugin needs all idle events in the main thread.
# @note Not possible on all engine implementations.
PLUGIN_NEEDS_MAIN_THREAD_IDLE = 0x4000

# Plugin has its own custom UI which is user resizable.
PLUGIN_HAS_CUSTOM_RESIZABLE_UI = 0x8000

# ---------------------------------------------------------------------------------------------------------------------
# Plugin Options
# Various plugin options.
@@ -1513,10 +1527,14 @@ PyCarlaRuntimeEngineDriverDeviceInfo = {
# ---------------------------------------------------------------------------------------------------------------------
# Set BINARY_NATIVE

if WINDOWS:
BINARY_NATIVE = BINARY_WIN64 if kIs64bit else BINARY_WIN32
if CARLA_OS_WIN64:
BINARY_NATIVE = BINARY_WIN64
elif CARLA_OS_WIN32:
BINARY_NATIVE = BINARY_WIN32
elif CARLA_OS_64BIT:
BINARY_NATIVE = BINARY_POSIX64
else:
BINARY_NATIVE = BINARY_POSIX64 if kIs64bit else BINARY_POSIX32
BINARY_NATIVE = BINARY_POSIX32

# ---------------------------------------------------------------------------------------------------------------------
# Carla Host object (Meta)
@@ -1528,6 +1546,7 @@ class CarlaHostMeta():
self.isPlugin = False
self.isRemote = False
self.nsmOK = False
self.handle = None

# settings
self.processMode = ENGINE_PROCESS_MODE_PATCHBAY


+ 130
- 17
source/frontend/carla_frontend.cpp View File

@@ -1,23 +1,136 @@
/*
* Carla Plugin Host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "carla_frontend.h"

// -------------------------------------------------------------------------------------------------------------------
// common files

#include "utils/qsafesettings.cpp"

// -------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// aboutdialog

#include "dialogs/aboutdialog.hpp"

void carla_frontend_createAndExecAboutDialog(QWidget* const parent,
const CarlaHostHandle hostHandle,
const bool isControl,
const bool isPlugin)
{
AboutDialog(parent, hostHandle, isControl, isPlugin).exec();
}

// --------------------------------------------------------------------------------------------------------------------
// jackappdialog

#include "dialogs/jackappdialog.hpp"
#include "extra/String.hpp"

const JackAppDialogResults*
carla_frontend_createAndExecJackAppDialog(QWidget* const parent, const char* const projectFilename)
{
JackAppDialog gui(parent, projectFilename);

if (gui.exec())
{
static JackAppDialogResults ret = {};
static String retCommand;
static String retName;
static String retLabelSetup;

const JackAppDialog::CommandAndFlags cafs = gui.getCommandAndFlags();
retCommand = cafs.command.toUtf8().constData();
retName = cafs.name.toUtf8().constData();
retLabelSetup = cafs.labelSetup.toUtf8().constData();

ret.command = retCommand;
ret.name = retName;
ret.labelSetup = retLabelSetup;

return &ret;
}

return nullptr;
}

// --------------------------------------------------------------------------------------------------------------------
// pluginlistdialog

#include "pluginlist/pluginlistdialog.hpp"
#include "CarlaUtils.h"

PluginListDialog*
carla_frontend_createPluginListDialog(QWidget* const parent, const HostSettings* const hostSettings)
{
return new PluginListDialog(parent, hostSettings);
}

void
carla_frontend_destroyPluginListDialog(PluginListDialog* const dialog)
{
dialog->close();
delete dialog;
}

void
carla_frontend_setPluginListDialogPath(PluginListDialog* const dialog, const int ptype, const char* const path)
{
dialog->setPluginPath(static_cast<PluginType>(ptype), path);
}

const PluginListDialogResults*
carla_frontend_execPluginListDialog(PluginListDialog* const dialog)
{
if (dialog->exec())
{
static PluginListDialogResults ret;
static String category;
static String filename;
static String name;
static String label;
static String maker;

const PluginInfo& plugin(dialog->getSelectedPluginInfo());

category = plugin.category.toUtf8();
filename = plugin.filename.toUtf8();
name = plugin.name.toUtf8();
label = plugin.label.toUtf8();
maker = plugin.maker.toUtf8();

ret.build = plugin.build;
ret.type = plugin.type;
ret.hints = plugin.hints;
ret.category = category;
ret.filename = filename;
ret.name = name;
ret.label = label;
ret.maker = maker;
ret.uniqueId = plugin.uniqueId;
ret.audioIns = plugin.audioIns;
ret.audioOuts = plugin.audioOuts;
ret.cvIns = plugin.cvIns;
ret.cvOuts = plugin.cvOuts;
ret.midiIns = plugin.midiIns;
ret.midiOuts = plugin.midiOuts;
ret.parameterIns = plugin.parameterIns;
ret.parameterOuts = plugin.parameterOuts;

return &ret;
}

return nullptr;
}

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

// const PluginListDialogResults*
// carla_frontend_createAndExecPluginListDialog(void* const parent, const HostSettings* const hostSettings)
// {
// PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings);
//
// return carla_frontend_execPluginListDialog(&gui);
// }

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

source/frontend/CarlaFrontend.h → source/frontend/carla_frontend.h View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once
@@ -10,6 +10,8 @@ using CARLA_BACKEND_NAMESPACE::PluginType;
extern "C" {
#endif

typedef struct _CarlaHostHandle* CarlaHostHandle;

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

typedef struct {
@@ -49,17 +51,26 @@ typedef struct {

#ifdef __cplusplus
class PluginListDialog;
class QWidget;
#else
struct PluginListDialog;
struct QWidget;
#endif

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

CARLA_PLUGIN_EXPORT void
carla_frontend_createAndExecAboutDialog(QWidget* parent, CarlaHostHandle hostHandle, bool isControl, bool isPlugin);

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

CARLA_PLUGIN_EXPORT const JackAppDialogResults*
carla_frontend_createAndExecJackAppDialog(void* parent, const char* projectFilename);
carla_frontend_createAndExecJackAppDialog(QWidget* parent, const char* projectFilename);

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

CARLA_PLUGIN_EXPORT PluginListDialog*
carla_frontend_createPluginListDialog(void* parent, const HostSettings* hostSettings);
carla_frontend_createPluginListDialog(QWidget* parent, const HostSettings* hostSettings);

CARLA_PLUGIN_EXPORT void
carla_frontend_destroyPluginListDialog(PluginListDialog* dialog);

+ 12
- 2
source/frontend/carla_frontend.py View File

@@ -81,6 +81,9 @@ class CarlaFrontendLib():
def __init__(self, filename):
self.lib = cdll.LoadLibrary(filename)

self.lib.carla_frontend_createAndExecAboutDialog.argtypes = (c_void_p, c_void_p, c_bool, c_bool)
self.lib.carla_frontend_createAndExecAboutDialog.restype = None

self.lib.carla_frontend_createAndExecJackAppDialog.argtypes = (c_void_p, c_char_p)
self.lib.carla_frontend_createAndExecJackAppDialog.restype = POINTER(JackApplicationDialogResults)

@@ -98,9 +101,16 @@ class CarlaFrontendLib():

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

def createAndExecAboutDialog(self, parent, hostHandle, isControl, isPlugin):
return structToDictOrNull(self.lib.carla_frontend_createAndExecAboutDialog(unwrapinstance(parent),
hostHandle,
isControl,
isPlugin))

def createAndExecJackAppDialog(self, parent, projectFilename):
return structToDictOrNull(self.lib.carla_frontend_createAndExecJackAppDialog(unwrapinstance(parent),
projectFilename.encode("utf-8")))
return structToDictOrNull(
self.lib.carla_frontend_createAndExecJackAppDialog(unwrapinstance(parent),
projectFilename.encode("utf-8")))

def createPluginListDialog(self, parent, hostSettings):
hostSettingsC = HostSettings()


+ 20
- 14
source/frontend/carla_host.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -110,7 +110,10 @@ from widgets.pixmapkeyboard import PixmapKeyboardHArea
# Try Import OpenGL

try:
from PyQt5.QtOpenGL import QGLWidget
if qt_config == 5:
from PyQt5.QtOpenGL import QGLWidget
elif qt_config == 6:
from PyQt6.QtOpenGL import QGLWidget
hasGL = True
except:
hasGL = False
@@ -220,7 +223,7 @@ class HostWindow(QMainWindow):
self.fOscAddressTCP = ""
self.fOscAddressUDP = ""

if MACOS:
if CARLA_OS_MAC:
self.fMacClosingHelper = True

# CancelableActionCallback Box
@@ -304,7 +307,7 @@ class HostWindow(QMainWindow):
else:
self.ui.act_engine_start.setEnabled(True)

if WINDOWS:
if CARLA_OS_WIN:
self.ui.tabWidget.removeTab(2)

if self.host.isControl:
@@ -356,7 +359,7 @@ class HostWindow(QMainWindow):
self.ui.menu_Canvas.menuAction().setVisible(False)
self.ui.tw_miniCanvas.hide()
self.ui.tabWidget.removeTab(1)
if WINDOWS:
if CARLA_OS_WIN:
self.ui.tabWidget.tabBar().hide()

# ----------------------------------------------------------------------------------------------------
@@ -471,7 +474,7 @@ class HostWindow(QMainWindow):
# ----------------------------------------------------------------------------------------------------
# Set up GUI (special stuff for Mac OS)

if MACOS:
if CARLA_OS_MAC:
self.ui.act_file_quit.setMenuRole(QAction.QuitRole)
self.ui.act_settings_configure.setMenuRole(QAction.PreferencesRole)
self.ui.act_help_about.setMenuRole(QAction.AboutRole)
@@ -2102,7 +2105,7 @@ class HostWindow(QMainWindow):
folder = diskFolders[i]
self.ui.cb_disk.addItem(os.path.basename(folder), folder)

#if MACOS and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, True, bool):
#if CARLA_OS_MAC and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, True, bool):
# self.setUnifiedTitleAndToolBarOnMac(True)

showMeters = settings.value("ShowMeters", True, bool)
@@ -2288,7 +2291,10 @@ class HostWindow(QMainWindow):

@pyqtSlot()
def slot_aboutCarla(self):
CarlaAboutW(self.fParentOrSelf, self.host).exec_()
gCarla.felib.createAndExecAboutDialog(self.fParentOrSelf,
self.host.handle,
self.host.isControl,
self.host.isPlugin)

@pyqtSlot()
def slot_aboutQt(self):
@@ -2912,10 +2918,10 @@ class HostWindow(QMainWindow):

# set our gui as parent for all plugins UIs
if self.host.manageUIs and not self.host.isControl:
if MACOS:
if CARLA_OS_MAC:
nsViewPtr = int(self.winId())
winIdStr = "%x" % gCarla.utils.cocoa_get_window(nsViewPtr)
elif WINDOWS or QApplication.platformName() == "xcb":
elif CARLA_OS_WIN or QApplication.platformName() == "xcb":
winIdStr = "%x" % int(self.winId())
else:
winIdStr = "0"
@@ -3077,7 +3083,7 @@ class HostWindow(QMainWindow):
#def paintEvent(self, event):
#QMainWindow.paintEvent(self, event)

#if MACOS or not self.fSavedSettings[CARLA_KEY_CUSTOM_PAINTING]:
#if CARLA_OS_MAC or not self.fSavedSettings[CARLA_KEY_CUSTOM_PAINTING]:
#return

#painter = QPainter(self)
@@ -3113,7 +3119,7 @@ class HostWindow(QMainWindow):

patchcanvas.handleAllPluginsRemoved()

if MACOS and self.fMacClosingHelper and not (self.host.isControl or self.host.isPlugin):
if CARLA_OS_MAC and self.fMacClosingHelper and not (self.host.isControl or self.host.isPlugin):
self.fCustomStopAction = self.CUSTOM_ACTION_APP_CLOSE
self.fMacClosingHelper = False
event.ignore()
@@ -3423,7 +3429,7 @@ def initHost(initName, libPrefix, isControl, isPlugin, failError, HostClass = No
# Print info

if not (gCarla.nogui and isinstance(gCarla.nogui, int)):
print("Carla %s started, status:" % VERSION)
print("Carla %s started, status:" % CARLA_VERSION_STRING)
print(" Python version: %s" % sys.version.split(" ",1)[0])
print(" Qt version: %s" % QT_VERSION_STR)
print(" PyQt version: %s" % PYQT_VERSION_STR)
@@ -3502,7 +3508,7 @@ def loadHostSettings(host):
host.preferPluginBridges = settings.value(CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES, CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, bool)
host.preferUIBridges = settings.value(CARLA_KEY_ENGINE_PREFER_UI_BRIDGES, CARLA_DEFAULT_PREFER_UI_BRIDGES, bool)
host.preventBadBehaviour = settings.value(CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR, CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR, bool)
host.showLogs = settings.value(CARLA_KEY_MAIN_SHOW_LOGS, CARLA_DEFAULT_MAIN_SHOW_LOGS, bool) and not WINDOWS
host.showLogs = settings.value(CARLA_KEY_MAIN_SHOW_LOGS, CARLA_DEFAULT_MAIN_SHOW_LOGS, bool) and not CARLA_OS_WIN
host.showPluginBridges = settings.value(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES, bool)
host.showWineBridges = settings.value(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES, bool)
host.uiBridgesTimeout = settings.value(CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT, CARLA_DEFAULT_UI_BRIDGES_TIMEOUT, int)


+ 22
- 10
source/frontend/carla_host_control.py View File

@@ -23,16 +23,28 @@ from carla_host import *
# ------------------------------------------------------------------------------------------------------------
# Imports (liblo)

from liblo import (
Address,
AddressError,
ServerError,
Server,
make_method,
send as lo_send,
TCP as LO_TCP,
UDP as LO_UDP,
)
try:
from pyliblo3 import (
Address,
AddressError,
ServerError,
Server,
make_method,
send as lo_send,
TCP as LO_TCP,
UDP as LO_UDP,
)
except ModuleNotFoundError:
from liblo import (
Address,
AddressError,
ServerError,
Server,
make_method,
send as lo_send,
TCP as LO_TCP,
UDP as LO_UDP,
)

from random import random



+ 0
- 77
source/frontend/carla_modgui.py View File

@@ -1,77 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla bridge for LV2 modguis
# Copyright (C) 2015-2019 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

import os
import sys

# ------------------------------------------------------------------------------------------------------------
# Imports (local)

from carla_app import CarlaApplication, gCarla, getPaths
from carla_shared import DLL_EXTENSION, setUpSignals
from carla_utils import CarlaUtils

from modgui.host import HostWindow

# ------------------------------------------------------------------------------------------------------------
# Main

if __name__ == '__main__':
# -------------------------------------------------------------
# Read CLI args

if len(sys.argv) < 2:
print("usage: %s <plugin-uri>" % sys.argv[0])
sys.exit(1)

libPrefix = os.getenv("CARLA_LIB_PREFIX")

# -------------------------------------------------------------
# App initialization

app = CarlaApplication("Carla2-MODGUI", libPrefix)

# -------------------------------------------------------------
# Init utils

pathBinaries, pathResources = getPaths(libPrefix)

utilsname = "libcarla_utils.%s" % (DLL_EXTENSION)

gCarla.utils = CarlaUtils(os.path.join(pathBinaries, utilsname))
gCarla.utils.set_process_name("carla-bridge-lv2-modgui")

# -------------------------------------------------------------
# Set-up custom signal handling

setUpSignals()

# -------------------------------------------------------------
# Create GUI

gui = HostWindow()

# --------------------------------------------------------------------------------------------------------
# App-Loop

app.exit_exec()

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

+ 12
- 10
source/frontend/carla_settings.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
@@ -21,7 +21,9 @@ import ui_carla_settings
import ui_carla_settings_driver

from carla_backend import (
LINUX, MACOS, WINDOWS,
CARLA_OS_LINUX,
CARLA_OS_MAC,
CARLA_OS_WIN,
ENGINE_DRIVER_DEVICE_HAS_CONTROL_PANEL,
ENGINE_DRIVER_DEVICE_CAN_TRIPLE_BUFFER,
ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE,
@@ -215,7 +217,7 @@ class DriverSettingsW(QDialog):

self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

if MACOS:
if CARLA_OS_MAC:
self.setWindowModality(Qt.WindowModal)

# -------------------------------------------------------------------------------------------------------------
@@ -406,7 +408,7 @@ class RuntimeDriverSettingsW(QDialog):
self.adjustSize()
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

if MACOS:
if CARLA_OS_MAC:
self.setWindowModality(Qt.WindowModal)

# -------------------------------------------------------------------------------------------------------------
@@ -533,11 +535,11 @@ class CarlaSettingsW(QDialog):
for i in range(Theme.THEME_MAX):
self.ui.cb_canvas_theme.addItem(getThemeName(i))

if MACOS:
if CARLA_OS_MAC:
self.ui.group_main_theme.setEnabled(False)
self.ui.group_main_theme.setVisible(False)

if WINDOWS or host.isControl:
if CARLA_OS_WIN or host.isControl:
self.ui.ch_main_show_logs.setEnabled(False)
self.ui.ch_main_show_logs.setVisible(False)

@@ -576,15 +578,15 @@ class CarlaSettingsW(QDialog):
self.ui.lw_page.hideRow(self.TAB_INDEX_OSC)
self.ui.lw_page.hideRow(self.TAB_INDEX_WINE)

if not LINUX:
if not CARLA_OS_LINUX:
self.ui.ch_exp_wine_bridges.setVisible(False)
self.ui.ch_exp_prevent_bad_behaviour.setVisible(False)
self.ui.lw_page.hideRow(self.TAB_INDEX_WINE)

if not MACOS:
if not CARLA_OS_MAC:
self.ui.label_engine_ui_bridges_mac_note.setVisible(False)

if not (LINUX or MACOS):
if not (CARLA_OS_LINUX or CARLA_OS_MAC):
self.ui.ch_exp_jack_apps.setVisible(False)

# FIXME, not implemented yet
@@ -599,7 +601,7 @@ class CarlaSettingsW(QDialog):

self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

if MACOS:
if CARLA_OS_MAC:
self.setWindowModality(Qt.WindowModal)

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


+ 38
- 27
source/frontend/carla_shared.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -26,6 +26,8 @@ except:

from qt_compat import qt_config

# pylint: disable=import-error

if qt_config == 5:
# import changed in PyQt 5.15.8, so try both
try:
@@ -42,19 +44,25 @@ elif qt_config == 6:
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QFileDialog, QMessageBox

# pylint: enable=import-error
# pylint: disable=possibly-used-before-assignment

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

from carla_backend import (
CARLA_OS_64BIT,
CARLA_OS_HAIKU,
CARLA_OS_MAC,
CARLA_OS_WIN,
CARLA_VERSION_STRING,
MAX_DEFAULT_PARAMETERS,
ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,
ENGINE_PROCESS_MODE_PATCHBAY,
ENGINE_TRANSPORT_MODE_INTERNAL,
ENGINE_TRANSPORT_MODE_JACK
ENGINE_TRANSPORT_MODE_JACK,
)

from common import kIs64bit, HAIKU, LINUX, MACOS, WINDOWS, VERSION

# ------------------------------------------------------------------------------------------------------------
# Config

@@ -65,7 +73,7 @@ X_DATADIR_X = None
# ------------------------------------------------------------------------------------------------------------
# Platform specific stuff

if WINDOWS:
if CARLA_OS_WIN:
WINDIR = os.getenv("WINDIR")

# ------------------------------------------------------------------------------------------------------------
@@ -74,7 +82,7 @@ if WINDOWS:
envTMP = os.getenv("TMP")

if envTMP is None:
if WINDOWS:
if CARLA_OS_WIN:
qWarning("TMP variable not set")
TMP = QDir.tempPath()
else:
@@ -92,7 +100,7 @@ del envTMP
envHOME = os.getenv("HOME")

if envHOME is None:
if not WINDOWS:
if not CARLA_OS_WIN:
qWarning("HOME variable not set")
HOME = QDir.toNativeSeparators(QDir.homePath())
else:
@@ -111,9 +119,9 @@ envPATH = os.getenv("PATH")

if envPATH is None:
qWarning("PATH variable not set")
if MACOS:
if CARLA_OS_MAC:
PATH = ("/opt/local/bin", "/usr/local/bin", "/usr/bin", "/bin")
elif WINDOWS:
elif CARLA_OS_WIN:
PATH = (os.path.join(WINDIR, "system32"), WINDIR)
else:
PATH = ("/usr/local/bin", "/usr/bin", "/bin")
@@ -262,7 +270,7 @@ CARLA_DEFAULT_MAIN_PRO_THEME_COLOR = "Black"
CARLA_DEFAULT_MAIN_REFRESH_INTERVAL = 20
CARLA_DEFAULT_MAIN_CONFIRM_EXIT = True
CARLA_DEFAULT_MAIN_CLASSIC_SKIN = False
CARLA_DEFAULT_MAIN_SHOW_LOGS = bool(not WINDOWS)
CARLA_DEFAULT_MAIN_SHOW_LOGS = bool(not CARLA_OS_WIN)
CARLA_DEFAULT_MAIN_SYSTEM_ICONS = False
CARLA_DEFAULT_MAIN_EXPERIMENTAL = False

@@ -296,11 +304,11 @@ CARLA_DEFAULT_AUDIO_BUFFER_SIZE = 512
CARLA_DEFAULT_AUDIO_SAMPLE_RATE = 44100
CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER = False

if HAIKU:
if CARLA_OS_HAIKU:
CARLA_DEFAULT_AUDIO_DRIVER = "SDL"
elif MACOS:
elif CARLA_OS_MAC:
CARLA_DEFAULT_AUDIO_DRIVER = "CoreAudio"
elif WINDOWS:
elif CARLA_OS_WIN:
CARLA_DEFAULT_AUDIO_DRIVER = "Windows Audio"
elif os.path.exists("/usr/bin/jackd") or os.path.exists("/usr/bin/jackdbus") or os.path.exists("/usr/bin/pw-jack"):
CARLA_DEFAULT_AUDIO_DRIVER = "JACK"
@@ -315,7 +323,7 @@ else:
CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL

# OSC
CARLA_DEFAULT_OSC_ENABLED = not (MACOS or WINDOWS)
CARLA_DEFAULT_OSC_ENABLED = not (CARLA_OS_MAC or CARLA_OS_WIN)
CARLA_DEFAULT_OSC_TCP_PORT_ENABLED = True
CARLA_DEFAULT_OSC_TCP_PORT_NUMBER = 22752
CARLA_DEFAULT_OSC_TCP_PORT_RANDOM = False
@@ -358,7 +366,7 @@ DEFAULT_SF2_PATH = ""
DEFAULT_SFZ_PATH = ""
DEFAULT_JSFX_PATH = ""

if WINDOWS:
if CARLA_OS_WIN:
splitter = ";"

APPDATA = os.getenv("APPDATA")
@@ -396,7 +404,7 @@ if WINDOWS:
DEFAULT_JSFX_PATH = APPDATA + "\\REAPER\\Effects"
#DEFAULT_JSFX_PATH += ";" + PROGRAMFILES + "\\REAPER\\InstallData\\Effects"

if kIs64bit:
if CARLA_OS_64BIT:
DEFAULT_VST2_PATH += ";" + COMMONPROGRAMFILES + "\\VST2"

DEFAULT_VST3_PATH = COMMONPROGRAMFILES + "\\VST3"
@@ -419,7 +427,7 @@ if WINDOWS:
DEFAULT_VST3_PATH += COMMONPROGRAMFILESx86 + "\\VST3"
DEFAULT_CLAP_PATH += COMMONPROGRAMFILESx86 + "\\CLAP"

elif HAIKU:
elif CARLA_OS_HAIKU:
splitter = ":"

DEFAULT_LADSPA_PATH = HOME + "/.ladspa"
@@ -442,7 +450,7 @@ elif HAIKU:
DEFAULT_CLAP_PATH = HOME + "/.clap"
DEFAULT_CLAP_PATH += ":/system/add-ons/media/clapplugins"

elif MACOS:
elif CARLA_OS_MAC:
splitter = ":"

DEFAULT_LADSPA_PATH = HOME + "/Library/Audio/Plug-Ins/LADSPA"
@@ -511,7 +519,7 @@ else:
DEFAULT_JSFX_PATH = CONFIG_HOME + "/REAPER/Effects"
#DEFAULT_JSFX_PATH += ":" + "/opt/REAPER/InstallData/Effects"

if not WINDOWS:
if not CARLA_OS_WIN:
winePrefix = os.getenv("WINEPREFIX")

if not winePrefix:
@@ -525,7 +533,7 @@ if not WINDOWS:
DEFAULT_VST3_PATH += ":" + winePrefix + "/drive_c/Program Files/Common Files/VST3"
DEFAULT_CLAP_PATH += ":" + winePrefix + "/drive_c/Program Files/Common Files/CLAP"

if kIs64bit:
if CARLA_OS_64BIT:
DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/VstPlugins"
DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/VSTPlugins"
DEFAULT_VST2_PATH += ":" + winePrefix + "/drive_c/Program Files (x86)/Steinberg/VstPlugins"
@@ -540,7 +548,7 @@ if not WINDOWS:

readEnvVars = True

if WINDOWS:
if CARLA_OS_WIN:
# Check if running Wine. If yes, ignore env vars
# pylint: disable=import-error
from winreg import ConnectRegistry, OpenKey, CloseKey, HKEY_CURRENT_USER
@@ -620,7 +628,7 @@ if os.path.isfile(CWD):
if CWD.endswith("/lib"):
CWD = CWD.rsplit("/lib",1)[0]
CXFREEZE = True
if not WINDOWS:
if not CARLA_OS_WIN:
os.environ['CARLA_MAGIC_FILE'] = os.path.join(CWD, "magic.mgc")
else:
CXFREEZE = False
@@ -628,9 +636,9 @@ else:
# ------------------------------------------------------------------------------------------------------------
# Set DLL_EXTENSION

if WINDOWS:
if CARLA_OS_WIN:
DLL_EXTENSION = "dll"
elif MACOS:
elif CARLA_OS_MAC:
DLL_EXTENSION = "dylib"
else:
DLL_EXTENSION = "so"
@@ -708,7 +716,7 @@ def handleInitialCommandLineArguments(file):
elif arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui"):
gCarla.nogui = True

elif MACOS and arg.startswith("-psn_"):
elif CARLA_OS_MAC and arg.startswith("-psn_"):
pass

elif arg in ("-h", "--h", "-help", "--help"):
@@ -737,7 +745,7 @@ def handleInitialCommandLineArguments(file):
elif arg in ("-v", "--v", "-version", "--version"):
pathBinaries, pathResources = getPaths(libPrefix)

print("Using Carla version %s" % VERSION)
print("Using Carla version %s" % CARLA_VERSION_STRING)
print(" Python version: %s" % sys.version.split(" ",1)[0])
print(" Qt version: %s" % QT_VERSION_STR)
print(" PyQt version: %s" % PYQT_VERSION_STR)
@@ -785,7 +793,7 @@ def getInitialProjectFile(skipExistCheck = False):
continue
if arg in ("-n", "--n", "-no-gui", "--no-gui", "-nogui", "--nogui", "--gdb"):
continue
if MACOS and arg.startswith("-psn_"):
if CARLA_OS_MAC and arg.startswith("-psn_"):
continue
arg = os.path.expanduser(arg)
if skipExistCheck or os.path.exists(arg):
@@ -914,7 +922,10 @@ def CustomMessageBox(parent, icon, title, text,
msgBox.setInformativeText(extraText)
msgBox.setStandardButtons(buttons)
msgBox.setDefaultButton(defButton)
# pylint: disable=no-value-for-parameter
return msgBox.exec_()
# pylint: enable=no-value-for-parameter
# pylint: enable=too-many-arguments

# ------------------------------------------------------------------------------------------------------------
# pylint: enable=possibly-used-before-assignment

+ 6
- 20
source/frontend/carla_utils.py View File

@@ -1,20 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla Backend utils
# Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)
@@ -35,6 +21,7 @@ from ctypes import (
# Imports (Custom)

from carla_backend import (
CARLA_OS_WIN,
PLUGIN_NONE,
PLUGIN_INTERNAL,
PLUGIN_LADSPA,
@@ -60,7 +47,6 @@ from carla_backend import (
PLUGIN_CATEGORY_MODULATOR,
PLUGIN_CATEGORY_UTILITY,
PLUGIN_CATEGORY_OTHER,
WINDOWS,
c_enum, c_uintptr,
charPtrToString,
charPtrPtrToStringList,
@@ -347,7 +333,7 @@ class CarlaUtils():
self._pipeClientCallback = None

# use _putenv on windows
if not WINDOWS:
if not CARLA_OS_WIN:
self.msvcrt = None
return

@@ -363,7 +349,7 @@ class CarlaUtils():
def setenv(self, key, value):
environ[key] = value

if WINDOWS:
if CARLA_OS_WIN:
keyvalue = "%s=%s" % (key, value)
# pylint: disable=protected-access
self.msvcrt._putenv(keyvalue.encode("utf-8"))
@@ -374,7 +360,7 @@ class CarlaUtils():
if environ.get(key) is not None:
environ.pop(key)

if WINDOWS:
if CARLA_OS_WIN:
keyrm = "%s=" % key
# pylint: disable=protected-access
self.msvcrt._putenv(keyrm.encode("utf-8"))


+ 5
- 138
source/frontend/carla_widgets.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -42,13 +42,14 @@ elif qt_config == 6:
# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

import ui_carla_about
import ui_carla_edit
import ui_carla_parameter

from carla_backend import (
MACOS, WINDOWS,
BINARY_NATIVE,
CARLA_VERSION_STRING,
CARLA_OS_MAC,
CARLA_OS_WIN,
PLUGIN_INTERNAL,
PLUGIN_DSSI,
PLUGIN_LV2,
@@ -92,7 +93,6 @@ from carla_backend import (

from carla_shared import (
MIDI_CC_LIST, MAX_MIDI_CC_LIST_ITEM,
VERSION,
countDecimalPoints,
fontMetricsHorizontalAdvance,
setUpSignals,
@@ -100,7 +100,6 @@ from carla_shared import (
)

from carla_utils import getPluginTypeAsString
#)

from widgets.collapsablewidget import CollapsibleBox
from widgets.pixmapkeyboard import PixmapKeyboardHArea
@@ -113,135 +112,6 @@ ICON_STATE_WAIT = 2 # nothing, sets as off
ICON_STATE_OFF = 1 # turns off, sets as null
ICON_STATE_NULL = 0 # nothing

# ------------------------------------------------------------------------------------------------------------
# Carla About dialog

class CarlaAboutW(QDialog):
def __init__(self, parent, host):
QDialog.__init__(self, parent)
self.ui = ui_carla_about.Ui_CarlaAboutW()
self.ui.setupUi(self)

if host.isControl:
extraInfo = " - <b>%s</b>" % self.tr("OSC Bridge Version")
elif host.isPlugin:
extraInfo = " - <b>%s</b>" % self.tr("Plugin Version")
else:
extraInfo = ""

self.ui.l_about.setText(self.tr(""
"<br>Version %s"
"<br>Carla is a fully-featured audio plugin host%s.<br>"
"<br>Copyright (C) 2011-2022 falkTX<br>"
"" % (VERSION, extraInfo)))

if self.ui.about.palette().color(QPalette.Background).blackF() < 0.5:
self.ui.l_icons.setPixmap(QPixmap(":/bitmaps/carla_about_black.png"))
self.ui.ico_example_edit.setPixmap(QPixmap(":/bitmaps/button_file-black.png"))
self.ui.ico_example_file.setPixmap(QPixmap(":/scalable/button_edit-black.svg"))
self.ui.ico_example_gui.setPixmap(QPixmap(":/bitmaps/button_gui-black.png"))

if host.isControl:
self.ui.l_extended.hide()
self.ui.tabWidget.removeTab(3)
self.ui.tabWidget.removeTab(2)

self.ui.l_extended.setText(gCarla.utils.get_complete_license_text())

if host.is_engine_running() and not host.isControl:
self.ui.le_osc_url_tcp.setText(host.get_host_osc_url_tcp())
self.ui.le_osc_url_udp.setText(host.get_host_osc_url_udp())
else:
self.ui.le_osc_url_tcp.setText(self.tr("(Engine not running)"))
self.ui.le_osc_url_udp.setText(self.tr("(Engine not running)"))

# pylint: disable=line-too-long
self.ui.l_osc_cmds.setText("<table>"
"<tr><td>" "/set_active" "&nbsp;</td><td>&lt;i-value&gt;</td></tr>"
"<tr><td>" "/set_drywet" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_volume" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_balance_left" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_balance_right" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_panning" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_parameter_value" "&nbsp;</td><td>&lt;i-index&gt; &lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_parameter_midi_cc" "&nbsp;</td><td>&lt;i-index&gt; &lt;i-cc&gt;</td></tr>"
"<tr><td>" "/set_parameter_midi_channel" "&nbsp;</td><td>&lt;i-index&gt; &lt;i-channel&gt;</td></tr>"
"<tr><td>" "/set_program" "&nbsp;</td><td>&lt;i-index&gt;</td></tr>"
"<tr><td>" "/set_midi_program" "&nbsp;</td><td>&lt;i-index&gt;</td></tr>"
"<tr><td>" "/note_on" "&nbsp;</td><td>&lt;i-channel&gt; &lt;i-note&gt; &lt;i-velo&gt;</td></tr>"
"<tr><td>" "/note_off" "&nbsp;</td><td>&lt;i-channel&gt; &lt;i-note</td></tr>"
"</table>"
)

self.ui.l_example.setText("/Carla/2/set_parameter_value 5 1.0")
self.ui.l_example_help.setText("<i>(as in this example, \"2\" is the plugin number and \"5\" the parameter)</i>")
# pylint: enable=line-too-long

self.ui.l_ladspa.setText(self.tr("Everything! (Including LRDF)"))
self.ui.l_dssi.setText(self.tr("Everything! (Including CustomData/Chunks)"))
self.ui.l_lv2.setText(self.tr("About 110&#37; complete (using custom extensions)<br/>"
"Implemented Feature/Extensions:"
"<ul>"
"<li>http://lv2plug.in/ns/ext/atom</li>"
"<li>http://lv2plug.in/ns/ext/buf-size</li>"
"<li>http://lv2plug.in/ns/ext/data-access</li>"
#"<li>http://lv2plug.in/ns/ext/dynmanifest</li>"
"<li>http://lv2plug.in/ns/ext/event</li>"
"<li>http://lv2plug.in/ns/ext/instance-access</li>"
"<li>http://lv2plug.in/ns/ext/log</li>"
"<li>http://lv2plug.in/ns/ext/midi</li>"
#"<li>http://lv2plug.in/ns/ext/morph</li>"
"<li>http://lv2plug.in/ns/ext/options</li>"
"<li>http://lv2plug.in/ns/ext/parameters</li>"
#"<li>http://lv2plug.in/ns/ext/patch</li>"
"<li>http://lv2plug.in/ns/ext/port-props</li>"
"<li>http://lv2plug.in/ns/ext/presets</li>"
"<li>http://lv2plug.in/ns/ext/resize-port</li>"
"<li>http://lv2plug.in/ns/ext/state</li>"
"<li>http://lv2plug.in/ns/ext/time</li>"
"<li>http://lv2plug.in/ns/ext/uri-map</li>"
"<li>http://lv2plug.in/ns/ext/urid</li>"
"<li>http://lv2plug.in/ns/ext/worker</li>"
"<li>http://lv2plug.in/ns/extensions/ui</li>"
"<li>http://lv2plug.in/ns/extensions/units</li>"
"<li>http://home.gna.org/lv2dynparam/rtmempool/v1</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/external-ui</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/programs</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/props</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/rtmempool</li>"
"<li>http://ll-plugins.nongnu.org/lv2/ext/midimap</li>"
"<li>http://ll-plugins.nongnu.org/lv2/ext/miditype</li>"
"</ul>"))

self.ui.l_vst2.setText(self.tr("About 85&#37; complete (missing vst bank/presets and some minor stuff)"))
self.ui.l_vst3.setText(self.tr("About 66&#37; complete"))

if MACOS:
self.ui.l_au.setText(self.tr("About 20&#37; complete"))
else:
self.ui.line_vst3.hide()
self.ui.l_au.hide()
self.ui.lid_au.hide()

# 3rd tab is usually longer than the 1st
# adjust appropriately
self.ui.tabWidget.setCurrentIndex(2)
self.adjustSize()
self.ui.tabWidget.setCurrentIndex(0)

self.setFixedSize(self.size())

flags = self.windowFlags()
flags &= ~Qt.WindowContextHelpButtonHint

if WINDOWS:
flags |= Qt.MSWindowsFixedSizeDialogHint

self.setWindowFlags(flags)

if MACOS:
self.setWindowModality(Qt.WindowModal)

# ------------------------------------------------------------------------------------------------------------
# Plugin Parameter

@@ -1281,7 +1151,7 @@ class PluginEdit(QDialog):

QDialog.setVisible(self, yesNo)

if MACOS and yesNo:
if CARLA_OS_MAC and yesNo:
parent = self.parent()
if parent is None:
return
@@ -1852,9 +1722,6 @@ if __name__ == '__main__':
_host.add_plugin(BINARY_NATIVE, PLUGIN_DSSI, "/usr/lib/dssi/karplong.so", "karplong", "karplong", 0, None, 0x0)
_host.set_active(0, True)

gui1 = CarlaAboutW(None, _host)
gui1.show()

gui2 = PluginEdit(None, _host, 0)
gui2.testTimer()
gui2.show()


+ 34
- 45
source/frontend/common/__init__.py View File

@@ -1,20 +1,6 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Common Carla code
# Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Global)
@@ -25,40 +11,43 @@ from sys import platform, maxsize
# ---------------------------------------------------------------------------------------------------------------------
# Set Version

VERSION = "2.6.0-alpha1"
CARLA_VERSION_HEX = 0x020591
CARLA_VERSION_STRING = "2.6.0-alpha1"
CARLA_VERSION_STRMIN = "2.6"

# ---------------------------------------------------------------------------------------------------------------------
# 64bit check
# Set Platform

CARLA_OS_BSD = False
CARLA_OS_GNU_HURD = False
CARLA_OS_HAIKU = False
CARLA_OS_LINUX = False
CARLA_OS_MAC = False
CARLA_OS_UNIX = False
CARLA_OS_WASM = False
CARLA_OS_WIN = False
CARLA_OS_WIN32 = False
CARLA_OS_WIN64 = False

kIs64bit = bool(architecture()[0] == "64bit" and maxsize > 2**32)
if platform == "darwin":
CARLA_OS_MAC = True
elif platform == "haiku":
CARLA_OS_HAIKU = True
elif platform == "linux":
CARLA_OS_LINUX = True
elif platform == "win32":
CARLA_OS_WIN32 = True
elif platform == "win64":
CARLA_OS_WIN64 = True

if CARLA_OS_WIN32 and CARLA_OS_WIN64:
CARLA_OS_WIN = True
elif CARLA_OS_BSD or CARLA_OS_GNU_HURD or CARLA_OS_LINUX or CARLA_OS_MAC:
CARLA_OS_UNIX = True

# ---------------------------------------------------------------------------------------------------------------------
# Set Platform
# 64bit check

if platform == "darwin":
HAIKU = False
LINUX = False
MACOS = True
WINDOWS = False
elif "haiku" in platform:
HAIKU = True
LINUX = False
MACOS = False
WINDOWS = False
elif "linux" in platform:
HAIKU = False
LINUX = True
MACOS = False
WINDOWS = False
elif platform in ("win32", "win64", "cygwin"):
HAIKU = False
LINUX = False
MACOS = False
WINDOWS = True
else:
HAIKU = False
LINUX = False
MACOS = False
WINDOWS = False
CARLA_OS_64BIT = bool(architecture()[0] == "64bit" and maxsize > 2**32)

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

+ 0
- 19
source/frontend/dialogs/__init__.py View File

@@ -1,19 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin host
# Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

from .jackappdialog import JackAppDialog

+ 147
- 0
source/frontend/dialogs/aboutdialog.cpp View File

@@ -0,0 +1,147 @@
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "aboutdialog.hpp"

#include "CarlaHost.h"

// --------------------------------------------------------------------------------------------------------------------
// About Dialog

AboutDialog::AboutDialog(QWidget* const parent,
const CarlaHostHandle hostHandle,
const bool isControl,
const bool isPlugin)
: QDialog(parent)
{
ui.setupUi(this);

QString extraInfo;
if (isControl)
extraInfo = QString(" - <b>%1</b>").arg(tr("OSC Bridge Version"));
else if (isPlugin)
extraInfo = QString(" - <b>%1</b>").arg(tr("Plugin Version"));

ui.l_about->setText(tr(""
"<br>Version %1"
"<br>Carla is a fully-featured audio plugin host%2.<br>"
"<br>Copyright (C) 2011-2025 falkTX<br>"
"").arg(CARLA_VERSION_STRING).arg(extraInfo));

if (ui.about->palette().color(QPalette::Window).blackF() < 0.5)
{
ui.l_icons->setPixmap(QPixmap(":/bitmaps/carla_about_black.png"));
ui.ico_example_edit->setPixmap(QPixmap(":/bitmaps/button_file-black.png"));
ui.ico_example_file->setPixmap(QPixmap(":/scalable/button_edit-black.svg"));
ui.ico_example_gui->setPixmap(QPixmap(":/bitmaps/button_gui-black.png"));
}

if (isControl || isPlugin)
{
ui.l_extended->hide();
ui.tabWidget->removeTab(3);
ui.tabWidget->removeTab(2);
}
#ifndef STATIC_PLUGIN_TARGET
else if (carla_is_engine_running(hostHandle))
{
ui.le_osc_url_tcp->setText(carla_get_host_osc_url_tcp(hostHandle));
ui.le_osc_url_udp->setText(carla_get_host_osc_url_udp(hostHandle));
}
#endif
else
{
ui.le_osc_url_tcp->setText(tr("(Engine not running)"));
ui.le_osc_url_udp->setText(tr("(Engine not running)"));
}

ui.l_extended->setText(carla_get_complete_license_text());

ui.l_osc_cmds->setText("<table>"
"<tr><td>" "/set_active" "&nbsp;</td><td>&lt;i-value&gt;</td></tr>"
"<tr><td>" "/set_drywet" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_volume" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_balance_left" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_balance_right" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_panning" "&nbsp;</td><td>&lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_parameter_value" "&nbsp;</td><td>&lt;i-index&gt; &lt;f-value&gt;</td></tr>"
"<tr><td>" "/set_parameter_midi_cc" "&nbsp;</td><td>&lt;i-index&gt; &lt;i-cc&gt;</td></tr>"
"<tr><td>" "/set_parameter_midi_channel" "&nbsp;</td><td>&lt;i-index&gt; &lt;i-channel&gt;</td></tr>"
"<tr><td>" "/set_program" "&nbsp;</td><td>&lt;i-index&gt;</td></tr>"
"<tr><td>" "/set_midi_program" "&nbsp;</td><td>&lt;i-index&gt;</td></tr>"
"<tr><td>" "/note_on" "&nbsp;</td><td>&lt;i-channel&gt; &lt;i-note&gt; &lt;i-velo&gt;</td></tr>"
"<tr><td>" "/note_off" "&nbsp;</td><td>&lt;i-channel&gt; &lt;i-note</td></tr>"
"</table>");

ui.l_example->setText("/Carla/2/set_parameter_value 5 1.0");
ui.l_example_help->setText("<i>(as in this example, \"2\" is the plugin number and \"5\" the parameter)</i>");

ui.l_ladspa->setText(tr("Everything! (Including LRDF)"));
ui.l_dssi->setText(tr("Everything! (Including CustomData/Chunks)"));
ui.l_lv2->setText(tr("About 110&#37; complete (using custom extensions)<br/>"
"Implemented Feature/Extensions:"
"<ul>"
"<li>http://lv2plug.in/ns/ext/atom</li>"
"<li>http://lv2plug.in/ns/ext/buf-size</li>"
"<li>http://lv2plug.in/ns/ext/data-access</li>"
// "<li>http://lv2plug.in/ns/ext/dynmanifest</li>"
"<li>http://lv2plug.in/ns/ext/event</li>"
"<li>http://lv2plug.in/ns/ext/instance-access</li>"
"<li>http://lv2plug.in/ns/ext/log</li>"
"<li>http://lv2plug.in/ns/ext/midi</li>"
// "<li>http://lv2plug.in/ns/ext/morph</li>"
"<li>http://lv2plug.in/ns/ext/options</li>"
"<li>http://lv2plug.in/ns/ext/parameters</li>"
// "<li>http://lv2plug.in/ns/ext/patch</li>"
// "<li>http://lv2plug.in/ns/ext/port-groups</li>"
"<li>http://lv2plug.in/ns/ext/port-props</li>"
"<li>http://lv2plug.in/ns/ext/presets</li>"
"<li>http://lv2plug.in/ns/ext/resize-port</li>"
"<li>http://lv2plug.in/ns/ext/state</li>"
"<li>http://lv2plug.in/ns/ext/time</li>"
"<li>http://lv2plug.in/ns/ext/uri-map</li>"
"<li>http://lv2plug.in/ns/ext/urid</li>"
"<li>http://lv2plug.in/ns/ext/worker</li>"
"<li>http://lv2plug.in/ns/extensions/ui</li>"
"<li>http://lv2plug.in/ns/extensions/units</li>"
"<li>http://home.gna.org/lv2dynparam/rtmempool/v1</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/external-ui</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/programs</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/props</li>"
"<li>http://kxstudio.sf.net/ns/lv2ext/rtmempool</li>"
"<li>http://ll-plugins.nongnu.org/lv2/ext/midimap</li>"
"<li>http://ll-plugins.nongnu.org/lv2/ext/miditype</li>"
"</ul>"));

ui.l_vst2->setText(tr("About 85&#37; complete (missing vst bank/presets and some minor stuff)"));
ui.l_vst3->setText(tr("About 66&#37; complete"));

#ifdef CARLA_OS_MAC
ui.l_au->setText(tr("About 20&#37; complete"));
#else
ui.line_vst3->hide();
ui.l_au->hide();
ui.lid_au->hide();
#endif

// 3rd tab is usually longer than the 1st, adjust appropriately
ui.tabWidget->setCurrentIndex(2);
adjustSize();
ui.tabWidget->setCurrentIndex(0);

setFixedSize(size());

Qt::WindowFlags flags = windowFlags();
flags &= ~Qt::WindowContextHelpButtonHint;
#ifdef CARLA_OS_WIN
flags |= Qt::MSWindowsFixedSizeDialogHint;
#endif
setWindowFlags(flags);

#ifdef CARLA_OS_MAC
if (parent != nullptr)
setWindowModality(Qt::WindowModal);
#endif
}

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

+ 39
- 0
source/frontend/dialogs/aboutdialog.hpp View File

@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "carla_frontend.h"

#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
# pragma clang diagnostic ignored "-Wdeprecated-register"
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include "ui_aboutdialog.h"

#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__) && __GNUC__ >= 8
# pragma GCC diagnostic pop
#endif

// --------------------------------------------------------------------------------------------------------------------
// About Dialog

class AboutDialog : public QDialog
{
Ui_AboutDialog ui;

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

public:
explicit AboutDialog(QWidget* parent, CarlaHostHandle hostHandle, bool isControl, bool isPlugin);
};

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

resources/ui/carla_about.ui → source/frontend/dialogs/aboutdialog.ui View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CarlaAboutW</class>
<widget class="QDialog" name="CarlaAboutW">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
@@ -1425,7 +1425,7 @@ POSSIBILITY OF SUCH DAMAGES.
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>CarlaAboutW</receiver>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
@@ -1441,7 +1441,7 @@ POSSIBILITY OF SUCH DAMAGES.
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>CarlaAboutW</receiver>
<receiver>AboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">

+ 64
- 146
source/frontend/dialogs/jackappdialog.cpp View File

@@ -1,19 +1,5 @@
/*
* Carla plugin host
* Copyright (C) 2011-2023 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "jackappdialog.hpp"

@@ -27,9 +13,7 @@
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include "ui_jackappdialog.h"
#include <QtCore/QFileInfo>
#include <QtCore/QVector>
#include <QtWidgets/QPushButton>

#ifdef __clang__
@@ -40,43 +24,28 @@

#include "qsafesettings.hpp"

#include "CarlaFrontend.h"
#include "CarlaLibJackHints.h"
#include "CarlaString.hpp"

// --------------------------------------------------------------------------------------------------------------------
// Jack Application Dialog

enum {
UI_SESSION_NONE = 0,
UI_SESSION_LADISH = 1,
UI_SESSION_NSM = 2,
};

struct JackAppDialog::Self {
Ui_JackAppDialog ui;
struct JackAppDialog::PrivateData {
const QString fProjectFilename;

Self(const char* const projectFilename)
PrivateData(const char* const projectFilename)
: fProjectFilename(projectFilename) {}

static Self& create(const char* const projectFilename)
{
Self* const self = new Self(projectFilename);
return *self;
}
};

JackAppDialog::JackAppDialog(QWidget* const parent, const char* const projectFilename)
: QDialog(parent),
self(Self::create(projectFilename))
p(new PrivateData(projectFilename))
{
self.ui.setupUi(this);
ui.setupUi(this);

// -------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// UI setup

self.ui.group_error->setVisible(false);
ui.group_error->setVisible(false);

adjustSize();
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -86,34 +55,34 @@ JackAppDialog::JackAppDialog(QWidget* const parent, const char* const projectFil
setWindowModality(Qt::WindowModal);
#endif

// -------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// Load settings

loadSettings();

// -------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// Set-up connections

connect(this, &QDialog::finished,
this, &JackAppDialog::slot_saveSettings);
connect(self.ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
connect(ui.cb_session_mgr, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
this, &JackAppDialog::slot_sessionManagerChanged);
connect(self.ui.le_command, &QLineEdit::textChanged,
connect(ui.le_command, &QLineEdit::textChanged,
this, &JackAppDialog::slot_commandChanged);
}

JackAppDialog::~JackAppDialog()
{
delete &self;
delete p;
}

// -----------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// public methods

JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const
{
const QString command = self.ui.le_command->text();
QString name = self.ui.le_name->text();
const QString command = ui.le_command->text();
QString name = ui.le_name->text();

if (name.isEmpty())
{
@@ -122,7 +91,7 @@ JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const
}

SessionManager smgr;
switch (self.ui.cb_session_mgr->currentIndex())
switch (ui.cb_session_mgr->currentIndex())
{
case UI_SESSION_LADISH:
smgr = LIBJACK_SESSION_MANAGER_LADISH;
@@ -136,28 +105,28 @@ JackAppDialog::CommandAndFlags JackAppDialog::getCommandAndFlags() const
}

uint flags = 0x0;
if (self.ui.cb_manage_window->isChecked())
if (ui.cb_manage_window->isChecked())
flags |= LIBJACK_FLAG_CONTROL_WINDOW;
if (self.ui.cb_capture_first_window->isChecked())
if (ui.cb_capture_first_window->isChecked())
flags |= LIBJACK_FLAG_CAPTURE_FIRST_WINDOW;
if (self.ui.cb_buffers_addition_mode->isChecked())
if (ui.cb_buffers_addition_mode->isChecked())
flags |= LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION;
if (self.ui.cb_out_midi_mixdown->isChecked())
if (ui.cb_out_midi_mixdown->isChecked())
flags |= LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN;
if (self.ui.cb_external_start->isChecked())
if (ui.cb_external_start->isChecked())
flags |= LIBJACK_FLAG_EXTERNAL_START;

const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + self.ui.sb_audio_ins->value()))
.arg(QChar('0' + self.ui.sb_audio_outs->value()))
.arg(QChar('0' + self.ui.sb_midi_ins->value()))
.arg(QChar('0' + self.ui.sb_midi_outs->value()))
const QString labelSetup(QString("%1%2%3%4%5%6").arg(QChar('0' + ui.sb_audio_ins->value()))
.arg(QChar('0' + ui.sb_audio_outs->value()))
.arg(QChar('0' + ui.sb_midi_ins->value()))
.arg(QChar('0' + ui.sb_midi_outs->value()))
.arg(QChar('0' + smgr))
.arg(QChar('0' + flags)));

return {command, name, labelSetup};
}

// -----------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// private methods

void JackAppDialog::checkIfButtonBoxShouldBeEnabled(const int index, const QCarlaString& command)
@@ -166,28 +135,28 @@ void JackAppDialog::checkIfButtonBoxShouldBeEnabled(const int index, const QCarl
QCarlaString showErr;

// NSM applications must not be abstract or absolute paths, and must not contain arguments
if (enabled and index == UI_SESSION_NSM)
if (enabled && index == UI_SESSION_NSM)
{
if (QVector<QChar>{'.', '/'}.contains(command[0]))
if (command[0] == '.' || command[0] == '/')
showErr = tr("NSM applications cannot use abstract or absolute paths");
else if (command.contains(' ') or command.contains(';') or command.contains('&'))
showErr = tr("NSM applications cannot use CLI arguments");
else if (self.fProjectFilename.isEmpty())
else if (p->fProjectFilename.isEmpty())
showErr = tr("You need to save the current Carla project before NSM can be used");
}

if (showErr.isNotEmpty())
{
enabled = false;
self.ui.l_error->setText(showErr);
self.ui.group_error->setVisible(true);
ui.l_error->setText(showErr);
ui.group_error->setVisible(true);
}
else
{
self.ui.group_error->setVisible(false);
ui.group_error->setVisible(false);
}

if (QPushButton* const button = self.ui.buttonBox->button(QDialogButtonBox::Ok))
if (QPushButton* const button = ui.buttonBox->button(QDialogButtonBox::Ok))
button->setEnabled(enabled);
}

@@ -198,104 +167,53 @@ void JackAppDialog::loadSettings()
const QString smName = settings.valueString("SessionManager", "");

if (smName == "LADISH (SIGUSR1)")
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH);
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_LADISH);
else if (smName == "NSM")
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM);
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NSM);
else
self.ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE);
self.ui.le_command->setText(settings.valueString("Command", ""));
self.ui.le_name->setText(settings.valueString("Name", ""));
self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
self.ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
self.ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2));
self.ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0));
self.ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0));
self.ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true));
self.ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false));
self.ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false));
checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(),
self.ui.le_command->text());
ui.cb_session_mgr->setCurrentIndex(UI_SESSION_NONE);
ui.le_command->setText(settings.valueString("Command", ""));
ui.le_name->setText(settings.valueString("Name", ""));
ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
ui.sb_audio_ins->setValue(settings.valueIntPositive("NumAudioIns", 2));
ui.sb_audio_outs->setValue(settings.valueIntPositive("NumAudioOuts", 2));
ui.sb_midi_ins->setValue(settings.valueIntPositive("NumMidiIns", 0));
ui.sb_midi_outs->setValue(settings.valueIntPositive("NumMidiOuts", 0));
ui.cb_manage_window->setChecked(settings.valueBool("ManageWindow", true));
ui.cb_capture_first_window->setChecked(settings.valueBool("CaptureFirstWindow", false));
ui.cb_out_midi_mixdown->setChecked(settings.valueBool("MidiOutMixdown", false));
checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(),
ui.le_command->text());
}

// -----------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// private slots

void JackAppDialog::slot_commandChanged(const QString& command)
{
checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr->currentIndex(), command);
checkIfButtonBoxShouldBeEnabled(ui.cb_session_mgr->currentIndex(), command);
}

void JackAppDialog::slot_sessionManagerChanged(const int index)
{
checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command->text());
checkIfButtonBoxShouldBeEnabled(index, ui.le_command->text());
}

void JackAppDialog::slot_saveSettings()
{
QSafeSettings settings("falkTX", "CarlaAddJackApp");
settings.setValue("Command", self.ui.le_command->text());
settings.setValue("Name", self.ui.le_name->text());
settings.setValue("SessionManager", self.ui.cb_session_mgr->currentText());
settings.setValue("NumAudioIns", self.ui.sb_audio_ins->value());
settings.setValue("NumAudioOuts", self.ui.sb_audio_outs->value());
settings.setValue("NumMidiIns", self.ui.sb_midi_ins->value());
settings.setValue("NumMidiOuts", self.ui.sb_midi_outs->value());
settings.setValue("ManageWindow", self.ui.cb_manage_window->isChecked());
settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window->isChecked());
settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown->isChecked());
settings.setValue("Command", ui.le_command->text());
settings.setValue("Name", ui.le_name->text());
settings.setValue("SessionManager", ui.cb_session_mgr->currentText());
settings.setValue("NumAudioIns", ui.sb_audio_ins->value());
settings.setValue("NumAudioOuts", ui.sb_audio_outs->value());
settings.setValue("NumMidiIns", ui.sb_midi_ins->value());
settings.setValue("NumMidiOuts", ui.sb_midi_outs->value());
settings.setValue("ManageWindow", ui.cb_manage_window->isChecked());
settings.setValue("CaptureFirstWindow", ui.cb_capture_first_window->isChecked());
settings.setValue("MidiOutMixdown", ui.cb_out_midi_mixdown->isChecked());
}

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

const JackAppDialogResults*
carla_frontend_createAndExecJackAppDialog(void* const parent, const char* const projectFilename)
{
JackAppDialog gui(reinterpret_cast<QWidget*>(parent), projectFilename);

if (gui.exec())
{
static JackAppDialogResults ret = {};
static CarlaString retCommand;
static CarlaString retName;
static CarlaString retLabelSetup;

const JackAppDialog::CommandAndFlags cafs = gui.getCommandAndFlags();
retCommand = cafs.command.toUtf8().constData();
retName = cafs.name.toUtf8().constData();
retLabelSetup = cafs.labelSetup.toUtf8().constData();

ret.command = retCommand;
ret.name = retName;
ret.labelSetup = retLabelSetup;

return &ret;
}

return nullptr;
}

#if 0
// --------------------------------------------------------------------------------------------------------------------
// Testing

#include "../utils/qsafesettings.cpp"

int main(int argc, char* argv[])
{
QApplication app(argc, argv);

if (JackAppDialogResults* const res = carla_frontend_createAndExecJackAppDialog(nullptr, ""))
{
printf("Results:\n");
printf("\tCommand: %s\n", res->command);
printf("\tName: %s\n", res->name);
printf("\tLabelSetup: %s\n", res->labelSetup);
}

return 0;
}
#endif

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

+ 15
- 19
source/frontend/dialogs/jackappdialog.hpp View File

@@ -1,22 +1,10 @@
/*
* Carla plugin host
* Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "carla_frontend.h"

#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-copy-with-user-provided-copy"
@@ -27,7 +15,7 @@
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include <QtWidgets/QDialog>
#include "ui_jackappdialog.h"

#ifdef __clang__
# pragma clang diagnostic pop
@@ -42,8 +30,16 @@

class JackAppDialog : public QDialog
{
struct Self;
Self& self;
enum {
UI_SESSION_NONE,
UI_SESSION_LADISH,
UI_SESSION_NSM,
};

struct PrivateData;
PrivateData* const p;

Ui_JackAppDialog ui;

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



+ 0
- 221
source/frontend/dialogs/jackappdialog.py View File

@@ -1,221 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla plugin host
# Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Global)

import os

from PyQt5.QtCore import pyqtSlot, Qt
from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QWidget

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Carla)

from utils import QSafeSettings

# ---------------------------------------------------------------------------------------------------------------------
# Imports (Local)

from jackappdialog_ui import Ui_JackAppDialog

# ---------------------------------------------------------------------------------------------------------------------
# Imports (API)

SESSION_MGR_NONE = 0
SESSION_MGR_AUTO = 1
SESSION_MGR_JACK = 2
SESSION_MGR_LADISH = 3
SESSION_MGR_NSM = 4

FLAG_CONTROL_WINDOW = 0x01
FLAG_CAPTURE_FIRST_WINDOW = 0x02
FLAG_BUFFERS_ADDITION_MODE = 0x10
FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20
FLAG_EXTERNAL_START = 0x40

# ---------------------------------------------------------------------------------------------------------------------
# Jack Application Dialog

UI_SESSION_NONE = 0
UI_SESSION_LADISH = 1
UI_SESSION_NSM = 2

class JackAppDialog(QDialog):
def __init__(self, parent: QWidget, projectFilename: str):
QDialog.__init__(self, parent)
self.ui = Ui_JackAppDialog()
self.ui.setupUi(self)

self.fProjectFilename = projectFilename

# --------------------------------------------------------------------------------------------------------------
# UI setup

self.ui.group_error.setVisible(False)
self.adjustSize()
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)

# --------------------------------------------------------------------------------------------------------------
# Load settings

self._loadSettings()

# --------------------------------------------------------------------------------------------------------------
# Set-up connections

self.finished.connect(self._slot_saveSettings)
self.ui.cb_session_mgr.currentIndexChanged.connect(self._slot_sessionManagerChanged)
self.ui.le_command.textChanged.connect(self._slot_commandChanged)

# -----------------------------------------------------------------------------------------------------------------
# public methods

def getCommandAndFlags(self):
name = self.ui.le_name.text()
command = self.ui.le_command.text()
smgr = SESSION_MGR_NONE
flags = 0x0

if not name:
name = os.path.basename(command.split(" ",1)[0]).title()

uiSessionMgrIndex = self.ui.cb_session_mgr.currentIndex()
if uiSessionMgrIndex == UI_SESSION_LADISH:
smgr = SESSION_MGR_LADISH
elif uiSessionMgrIndex == UI_SESSION_NSM:
smgr = SESSION_MGR_NSM

if self.ui.cb_manage_window.isChecked():
flags |= FLAG_CONTROL_WINDOW
if self.ui.cb_capture_first_window.isChecked():
flags |= FLAG_CAPTURE_FIRST_WINDOW
if self.ui.cb_buffers_addition_mode.isChecked():
flags |= FLAG_BUFFERS_ADDITION_MODE
if self.ui.cb_out_midi_mixdown.isChecked():
flags |= FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN
if self.ui.cb_external_start.isChecked():
flags |= FLAG_EXTERNAL_START

bv = ord('0')
v1 = chr(bv + self.ui.sb_audio_ins.value())
v2 = chr(bv + self.ui.sb_audio_outs.value())
v3 = chr(bv + self.ui.sb_midi_ins.value())
v4 = chr(bv + self.ui.sb_midi_outs.value())
v5 = chr(bv + smgr)
v6 = chr(bv + flags)
labelSetup = f"{v1}{v2}{v3}{v4}{v5}{v6}"

return (command, name, labelSetup)

# -----------------------------------------------------------------------------------------------------------------
# private methods

def _checkIfButtonBoxShouldBeEnabled(self, index: int, command: str):
enabled = len(command) > 0
showErr = ""

# NSM applications must not be abstract or absolute paths, and must not contain arguments
if enabled and index == UI_SESSION_NSM:
if command[0] in (".", "/"):
showErr = self.tr("NSM applications cannot use abstract or absolute paths")
elif " " in command or ";" in command or "&" in command:
showErr = self.tr("NSM applications cannot use CLI arguments")
elif not self.fProjectFilename:
showErr = self.tr("You need to save the current Carla project before NSM can be used")

if showErr:
enabled = False
self.ui.l_error.setText(showErr)
self.ui.group_error.setVisible(True)
else:
self.ui.group_error.setVisible(False)

self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled)

def _loadSettings(self):
settings = QSafeSettings("falkTX", "CarlaAddJackApp")

smName = settings.value("SessionManager", "", str)

if smName == "LADISH (SIGUSR1)":
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_LADISH)
elif smName == "NSM":
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NSM)
else:
self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NONE)

self.ui.le_command.setText(settings.value("Command", "", str))
self.ui.le_name.setText(settings.value("Name", "", str))
self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int))
self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int))
self.ui.sb_audio_outs.setValue(settings.value("NumAudioOuts", 2, int))
self.ui.sb_midi_ins.setValue(settings.value("NumMidiIns", 0, int))
self.ui.sb_midi_outs.setValue(settings.value("NumMidiOuts", 0, int))
self.ui.cb_manage_window.setChecked(settings.value("ManageWindow", True, bool))
self.ui.cb_capture_first_window.setChecked(settings.value("CaptureFirstWindow", False, bool))
self.ui.cb_out_midi_mixdown.setChecked(settings.value("MidiOutMixdown", False, bool))

self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(),
self.ui.le_command.text())

# -----------------------------------------------------------------------------------------------------------------
# private slots

@pyqtSlot(str)
def _slot_commandChanged(self, command: str):
self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), command)

@pyqtSlot(int)
def _slot_sessionManagerChanged(self, index: int):
self._checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command.text())

@pyqtSlot()
def _slot_saveSettings(self):
settings = QSafeSettings("falkTX", "CarlaAddJackApp")
settings.setValue("Command", self.ui.le_command.text())
settings.setValue("Name", self.ui.le_name.text())
settings.setValue("SessionManager", self.ui.cb_session_mgr.currentText())
settings.setValue("NumAudioIns", self.ui.sb_audio_ins.value())
settings.setValue("NumAudioOuts", self.ui.sb_audio_outs.value())
settings.setValue("NumMidiIns", self.ui.sb_midi_ins.value())
settings.setValue("NumMidiOuts", self.ui.sb_midi_outs.value())
settings.setValue("ManageWindow", self.ui.cb_manage_window.isChecked())
settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window.isChecked())
settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown.isChecked())

# ---------------------------------------------------------------------------------------------------------------------
# Testing

if __name__ == '__main__':
import sys
# pylint: disable=ungrouped-imports
from PyQt5.QtWidgets import QApplication
# pylint: enable=ungrouped-imports

_app = QApplication(sys.argv)
_gui = JackAppDialog(None, "")

if _gui.exec_():
_command, _name, _labelSetup = _gui.getCommandAndFlags()
print("Results:")
print(f"\tCommand: {_command}")
print(f"\tName: {_name}")
print(f"\tLabelSetup: {_labelSetup}")

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

+ 0
- 0
source/frontend/modgui/__init__.py View File


+ 0
- 546
source/frontend/modgui/host.py View File

@@ -1,546 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla bridge for LV2 modguis
# Copyright (C) 2015-2019 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QPoint, QSize, QUrl
from PyQt5.QtGui import QImage, QPainter, QPalette
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtWebKitWidgets import QWebView

import sys

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

from carla_host import charPtrToString, gCarla
from .webserver import WebServerThread, PORT

# ------------------------------------------------------------------------------------------------------------
# Imports (MOD)

from modtools.utils import get_plugin_info, init as lv2_init

# ------------------------------------------------------------------------------------------------------------
# Host Window

class HostWindow(QMainWindow):
# signals
SIGTERM = pyqtSignal()
SIGUSR1 = pyqtSignal()

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

def __init__(self):
QMainWindow.__init__(self)
gCarla.gui = self

URI = sys.argv[1]

# ----------------------------------------------------------------------------------------------------
# Internal stuff

self.fCurrentFrame = None
self.fDocElemement = None
self.fCanSetValues = False
self.fNeedsShow = False
self.fSizeSetup = False
self.fQuitReceived = False
self.fWasRepainted = False

lv2_init()

self.fPlugin = get_plugin_info(URI)
self.fPorts = self.fPlugin['ports']
self.fPortSymbols = {}
self.fPortValues = {}
self.fParamTypes = {}
self.fParamValues = {}

for port in self.fPorts['control']['input']:
self.fPortSymbols[port['index']] = (port['symbol'], False)
self.fPortValues [port['index']] = port['ranges']['default']

for port in self.fPorts['control']['output']:
self.fPortSymbols[port['index']] = (port['symbol'], True)
self.fPortValues [port['index']] = port['ranges']['default']

for parameter in self.fPlugin['parameters']:
if parameter['ranges'] is None:
continue
if parameter['type'] == "http://lv2plug.in/ns/ext/atom#Bool":
paramtype = 'b'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#Int":
paramtype = 'i'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#Long":
paramtype = 'l'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#Float":
paramtype = 'f'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#Double":
paramtype = 'g'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#String":
paramtype = 's'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#Path":
paramtype = 'p'
elif parameter['type'] == "http://lv2plug.in/ns/ext/atom#URI":
paramtype = 'u'
else:
continue
if paramtype not in ('s','p','u') and parameter['ranges']['minimum'] == parameter['ranges']['maximum']:
continue
self.fParamTypes [parameter['uri']] = paramtype
self.fParamValues[parameter['uri']] = parameter['ranges']['default']

# ----------------------------------------------------------------------------------------------------
# Init pipe

if len(sys.argv) == 7:
self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg))
else:
self.fPipeClient = None

# ----------------------------------------------------------------------------------------------------
# Init Web server

self.fWebServerThread = WebServerThread(self)
self.fWebServerThread.start()

# ----------------------------------------------------------------------------------------------------
# Set up GUI

self.setContentsMargins(0, 0, 0, 0)

self.fWebview = QWebView(self)
#self.fWebview.setAttribute(Qt.WA_OpaquePaintEvent, False)
#self.fWebview.setAttribute(Qt.WA_TranslucentBackground, True)
self.setCentralWidget(self.fWebview)

page = self.fWebview.page()
page.setViewportSize(QSize(980, 600))

mainFrame = page.mainFrame()
mainFrame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
mainFrame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

palette = self.fWebview.palette()
palette.setBrush(QPalette.Base, palette.brush(QPalette.Window))
page.setPalette(palette)
self.fWebview.setPalette(palette)

settings = self.fWebview.settings()
settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

self.fWebview.loadFinished.connect(self.slot_webviewLoadFinished)

url = "http://127.0.0.1:%s/icon.html#%s" % (PORT, URI)
print("url:", url)
self.fWebview.load(QUrl(url))

# ----------------------------------------------------------------------------------------------------
# Connect actions to functions

self.SIGTERM.connect(self.slot_handleSIGTERM)

# ----------------------------------------------------------------------------------------------------
# Final setup

self.fIdleTimer = self.startTimer(30)

if self.fPipeClient is None:
# testing, show UI only
self.setWindowTitle("TestUI")
self.fNeedsShow = True

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

def closeExternalUI(self):
self.fWebServerThread.stopWait()

if self.fPipeClient is None:
return

if not self.fQuitReceived:
self.send(["exiting"])

gCarla.utils.pipe_client_destroy(self.fPipeClient)
self.fPipeClient = None

def idleStuff(self):
if self.fPipeClient is not None:
gCarla.utils.pipe_client_idle(self.fPipeClient)
self.checkForRepaintChanges()

if self.fSizeSetup:
return
if self.fDocElemement is None or self.fDocElemement.isNull():
return

pedal = self.fDocElemement.findFirst(".mod-pedal")

if pedal.isNull():
return

size = pedal.geometry().size()

if size.width() <= 10 or size.height() <= 10:
return

# render web frame to image
image = QImage(self.fWebview.page().viewportSize(), QImage.Format_ARGB32_Premultiplied)
image.fill(Qt.transparent)

painter = QPainter(image)
self.fCurrentFrame.render(painter)
painter.end()

#image.save("/tmp/test.png")

# get coordinates and size from image
#x = -1
#y = -1
#lastx = -1
#lasty = -1
#bgcol = self.fHostColor.rgba()

#for h in range(0, image.height()):
#hasNonTransPixels = False

#for w in range(0, image.width()):
#if image.pixel(w, h) not in (0, bgcol): # 0xff070707):
#hasNonTransPixels = True
#if x == -1 or x > w:
#x = w
#lastx = max(lastx, w)

#if hasNonTransPixels:
##if y == -1:
##y = h
#lasty = h

# set size and position accordingly
#if -1 not in (x, lastx, lasty):
#self.setFixedSize(lastx-x, lasty)
#self.fCurrentFrame.setScrollPosition(QPoint(x, 0))
#else:

# TODO that^ needs work
if True:
self.setFixedSize(size)

# set initial values
self.fCurrentFrame.evaluateJavaScript("icongui.setPortWidgetsValue(':bypass', 0, null)")

for index in self.fPortValues.keys():
symbol, isOutput = self.fPortSymbols[index]
value = self.fPortValues[index]
if isOutput:
self.fCurrentFrame.evaluateJavaScript("icongui.setOutputPortValue('%s', %f)" % (symbol, value))
else:
self.fCurrentFrame.evaluateJavaScript("icongui.setPortWidgetsValue('%s', %f, null)" % (symbol, value))

for uri in self.fParamValues.keys():
ptype = self.fParamTypes[uri]
value = str(self.fParamValues[uri])
print("icongui.setWritableParameterValue('%s', '%c', %s, 'from-carla')" % (uri, ptype, value))
self.fCurrentFrame.evaluateJavaScript("icongui.setWritableParameterValue('%s', '%c', %s, 'from-carla')" % (
uri, ptype, value))

# final setup
self.fCanSetValues = True
self.fSizeSetup = True
self.fDocElemement = None

if self.fNeedsShow:
self.show()

def checkForRepaintChanges(self):
if not self.fWasRepainted:
return

self.fWasRepainted = False

if not self.fCanSetValues:
return

for index in self.fPortValues.keys():
symbol, isOutput = self.fPortSymbols[index]

if isOutput:
continue

oldValue = self.fPortValues[index]
newValue = self.fCurrentFrame.evaluateJavaScript("icongui.controls['%s'].value" % (symbol,))

if oldValue != newValue:
self.fPortValues[index] = newValue
self.send(["control", index, newValue])

for uri in self.fParamValues.keys():
oldValue = self.fParamValues[uri]
newValue = self.fCurrentFrame.evaluateJavaScript("icongui.parameters['%s'].value" % (uri,))

if oldValue != newValue:
self.fParamValues[uri] = newValue
self.send(["pcontrol", uri, newValue])

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

@pyqtSlot(bool)
def slot_webviewLoadFinished(self, ok):
page = self.fWebview.page()
page.repaintRequested.connect(self.slot_repaintRequested)

self.fCurrentFrame = page.currentFrame()
self.fDocElemement = self.fCurrentFrame.documentElement()

def slot_repaintRequested(self):
if self.fCanSetValues:
self.fWasRepainted = True

# --------------------------------------------------------------------------------------------------------
# Callback

def msgCallback(self, msg):
msg = charPtrToString(msg)

if msg == "control":
index = self.readlineblock_int()
value = self.readlineblock_float()
self.dspControlChanged(index, value)

elif msg == "parameter":
uri = self.readlineblock()
value = self.readlineblock_float()
self.dspParameterChanged(uri, value)

elif msg == "program":
index = self.readlineblock_int()
self.dspProgramChanged(index)

elif msg == "midiprogram":
bank = self.readlineblock_int()
program = self.readlineblock_int()
self.dspMidiProgramChanged(bank, program)

elif msg == "configure":
key = self.readlineblock()
value = self.readlineblock()
self.dspStateChanged(key, value)

elif msg == "note":
onOff = self.readlineblock_bool()
channel = self.readlineblock_int()
note = self.readlineblock_int()
velocity = self.readlineblock_int()
self.dspNoteReceived(onOff, channel, note, velocity)

elif msg == "atom":
index = self.readlineblock_int()
atomsize = self.readlineblock_int()
base64size = self.readlineblock_int()
base64atom = self.readlineblock()
# nothing to do yet

elif msg == "urid":
urid = self.readlineblock_int()
size = self.readlineblock_int()
uri = self.readlineblock()
# nothing to do yet

elif msg == "uiOptions":
sampleRate = self.readlineblock_float()
bgColor = self.readlineblock_int()
fgColor = self.readlineblock_int()
uiScale = self.readlineblock_float()
useTheme = self.readlineblock_bool()
useThemeColors = self.readlineblock_bool()
windowTitle = self.readlineblock()
transWindowId = self.readlineblock_int()
self.uiTitleChanged(windowTitle)

elif msg == "show":
self.uiShow()

elif msg == "focus":
self.uiFocus()

elif msg == "hide":
self.uiHide()

elif msg == "quit":
self.fQuitReceived = True
self.uiQuit()

elif msg == "uiTitle":
uiTitle = self.readlineblock()
self.uiTitleChanged(uiTitle)

else:
print("unknown message: \"" + msg + "\"")

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

def dspControlChanged(self, index, value):
self.fPortValues[index] = value

if self.fCurrentFrame is None or not self.fCanSetValues:
return

symbol, isOutput = self.fPortSymbols[index]

if isOutput:
self.fCurrentFrame.evaluateJavaScript("icongui.setOutputPortValue('%s', %f)" % (symbol, value))
else:
self.fCurrentFrame.evaluateJavaScript("icongui.setPortWidgetsValue('%s', %f, null)" % (symbol, value))

def dspParameterChanged(self, uri, value):
print("dspParameterChanged", uri, value)
if uri not in self.fParamValues:
return

self.fParamValues[uri] = value

if self.fCurrentFrame is None or not self.fCanSetValues:
return

ptype = self.fParamTypes[uri]

self.fCurrentFrame.evaluateJavaScript("icongui.setWritableParameterValue('%s', '%c', %f, 'from-carla')" % (
uri, ptype, value))

def dspProgramChanged(self, index):
return

def dspMidiProgramChanged(self, bank, program):
return

def dspStateChanged(self, key, value):
return

def dspNoteReceived(self, onOff, channel, note, velocity):
return

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

def uiShow(self):
if self.fSizeSetup:
self.show()
else:
self.fNeedsShow = True

def uiFocus(self):
if not self.fSizeSetup:
return

self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive)
self.show()

self.raise_()
self.activateWindow()

def uiHide(self):
self.hide()

def uiQuit(self):
self.closeExternalUI()
self.close()
QApplication.instance().quit()

def uiTitleChanged(self, uiTitle):
self.setWindowTitle(uiTitle)

# --------------------------------------------------------------------------------------------------------
# Qt events

def closeEvent(self, event):
self.closeExternalUI()
QMainWindow.closeEvent(self, event)

# there might be other qt windows open which will block carla-modgui from quitting
QApplication.instance().quit()

def timerEvent(self, event):
if event.timerId() == self.fIdleTimer:
self.idleStuff()

QMainWindow.timerEvent(self, event)

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

@pyqtSlot()
def slot_handleSIGTERM(self):
print("Got SIGTERM -> Closing now")
self.close()

# --------------------------------------------------------------------------------------------------------
# Internal stuff

def readlineblock(self):
if self.fPipeClient is None:
return ""

return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 5000)

def readlineblock_bool(self):
if self.fPipeClient is None:
return False

return gCarla.utils.pipe_client_readlineblock_bool(self.fPipeClient, 5000)

def readlineblock_int(self):
if self.fPipeClient is None:
return 0

return gCarla.utils.pipe_client_readlineblock_int(self.fPipeClient, 5000)

def readlineblock_float(self):
if self.fPipeClient is None:
return 0.0

return gCarla.utils.pipe_client_readlineblock_float(self.fPipeClient, 5000)

def send(self, lines):
if self.fPipeClient is None or len(lines) == 0:
return

gCarla.utils.pipe_client_lock(self.fPipeClient)

# this must never fail, we need to unlock at the end
try:
for line in lines:
if line is None:
line2 = "(null)"
elif isinstance(line, str):
line2 = line.replace("\n", "\r")
elif isinstance(line, bool):
line2 = "true" if line else "false"
elif isinstance(line, int):
line2 = "%i" % line
elif isinstance(line, float):
line2 = "%.10f" % line
else:
print("unknown data type to send:", type(line))
return

gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n")
except:
pass

gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient)

+ 0
- 225
source/frontend/modgui/webserver.py View File

@@ -1,225 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla bridge for LV2 modguis
# Copyright (C) 2015-2020 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

import os

from PyQt5.QtCore import pyqtSignal, QThread

# ------------------------------------------------------------------------------------------------------------
# Generate a random port number between 9000 and 18000

from random import random

PORTn = 8998 + int(random()*9000)

# ------------------------------------------------------------------------------------------------------------
# Imports (asyncio)

try:
from asyncio import new_event_loop, set_event_loop
haveAsyncIO = True
except:
haveAsyncIO = False

# ------------------------------------------------------------------------------------------------------------
# Imports (tornado)

from tornado.log import enable_pretty_logging
from tornado.ioloop import IOLoop
from tornado.util import unicode_type
from tornado.web import HTTPError
from tornado.web import Application, RequestHandler, StaticFileHandler

# ------------------------------------------------------------------------------------------------------------
# Set up environment for the webserver

PORT = str(PORTn)
ROOT = "/usr/share/mod"
DATA_DIR = os.path.expanduser("~/.local/share/mod-data/")
HTML_DIR = os.path.join(ROOT, "html")

os.environ['MOD_DEV_HOST'] = "1"
os.environ['MOD_DEV_HMI'] = "1"
os.environ['MOD_DESKTOP'] = "1"

os.environ['MOD_DATA_DIR'] = DATA_DIR
os.environ['MOD_HTML_DIR'] = HTML_DIR
os.environ['MOD_KEY_PATH'] = os.path.join(DATA_DIR, "keys")
os.environ['MOD_CLOUD_PUB'] = os.path.join(ROOT, "keys", "cloud_key.pub")
os.environ['MOD_PLUGIN_LIBRARY_DIR'] = os.path.join(DATA_DIR, "lib")

os.environ['MOD_PHANTOM_BINARY'] = "/usr/bin/phantomjs"
os.environ['MOD_SCREENSHOT_JS'] = os.path.join(ROOT, "screenshot.js")
os.environ['MOD_DEVICE_WEBSERVER_PORT'] = PORT

# ------------------------------------------------------------------------------------------------------------
# Imports (MOD)

from modtools.utils import get_plugin_info, get_plugin_gui, get_plugin_gui_mini

# ------------------------------------------------------------------------------------------------------------
# MOD related classes

class JsonRequestHandler(RequestHandler):
def write(self, data):
if isinstance(data, (bytes, unicode_type, dict)):
RequestHandler.write(self, data)
self.finish()
return

elif data is True:
data = "true"
self.set_header("Content-Type", "application/json; charset=UTF-8")

elif data is False:
data = "false"
self.set_header("Content-Type", "application/json; charset=UTF-8")

else:
data = json.dumps(data)
self.set_header("Content-Type", "application/json; charset=UTF-8")

RequestHandler.write(self, data)
self.finish()

class EffectGet(JsonRequestHandler):
def get(self):
uri = self.get_argument('uri')

try:
data = get_plugin_info(uri)
except:
print("ERROR: get_plugin_info for '%s' failed" % uri)
raise HTTPError(404)

self.write(data)

class EffectFile(StaticFileHandler):
def initialize(self):
# return custom type directly. The browser will do the parsing
self.custom_type = None

uri = self.get_argument('uri')

try:
self.modgui = get_plugin_gui(uri)
except:
raise HTTPError(404)

try:
root = self.modgui['resourcesDirectory']
except:
raise HTTPError(404)

return StaticFileHandler.initialize(self, root)

def parse_url_path(self, prop):
try:
path = self.modgui[prop]
except:
raise HTTPError(404)

if prop in ("iconTemplate", "settingsTemplate", "stylesheet", "javascript"):
self.custom_type = "text/plain"

return path

def get_content_type(self):
if self.custom_type is not None:
return self.custom_type
return StaticFileHandler.get_content_type(self)

class EffectResource(StaticFileHandler):

def initialize(self):
# Overrides StaticFileHandler initialize
pass

def get(self, path):
try:
uri = self.get_argument('uri')
except:
return self.shared_resource(path)

try:
modgui = get_plugin_gui_mini(uri)
except:
raise HTTPError(404)

try:
root = modgui['resourcesDirectory']
except:
raise HTTPError(404)

try:
super(EffectResource, self).initialize(root)
return super(EffectResource, self).get(path)
except HTTPError as e:
if e.status_code != 404:
raise e
return self.shared_resource(path)
except IOError:
raise HTTPError(404)

def shared_resource(self, path):
super(EffectResource, self).initialize(os.path.join(HTML_DIR, 'resources'))
return super(EffectResource, self).get(path)

# ------------------------------------------------------------------------------------------------------------
# WebServer Thread

class WebServerThread(QThread):
# signals
running = pyqtSignal()

def __init__(self, parent=None):
QThread.__init__(self, parent)

self.fApplication = Application(
[
(r"/effect/get/?", EffectGet),
(r"/effect/file/(.*)", EffectFile),
(r"/resources/(.*)", EffectResource),
(r"/(.*)", StaticFileHandler, {"path": HTML_DIR}),
],
debug=True)

self.fPrepareWasCalled = False
self.fEventLoop = None

def run(self):
if not self.fPrepareWasCalled:
self.fPrepareWasCalled = True
if haveAsyncIO:
self.fEventLoop = new_event_loop()
set_event_loop(self.fEventLoop)
self.fApplication.listen(PORT, address="0.0.0.0")
if int(os.getenv("MOD_LOG", "0")):
enable_pretty_logging()

self.running.emit()
IOLoop.instance().start()

def stopWait(self):
IOLoop.instance().stop()
if self.fEventLoop is not None:
self.fEventLoop.call_soon_threadsafe(self.fEventLoop.stop)
return self.wait(5000)

+ 8
- 8
source/frontend/patchcanvas/theme.py View File

@@ -317,14 +317,14 @@ class Theme(object):
self.port_font_state = QFont.Normal
self.port_mode = self.THEME_PORT_SQUARE

self.port_audio_jack_pen = QPen(QColor(35, 61, 99), Qt.NoPen, 0)
self.port_audio_jack_pen_sel = QPen(QColor(255, 0, 0), Qt.NoPen, 0)
self.port_midi_jack_pen = QPen(QColor(120, 15, 16), Qt.NoPen, 0)
self.port_midi_jack_pen_sel = QPen(QColor(255, 0, 0), Qt.NoPen, 0)
self.port_midi_alsa_pen = QPen(QColor(63, 112, 19), Qt.NoPen, 0)
self.port_midi_alsa_pen_sel = QPen(QColor(255, 0, 0), Qt.NoPen, 0)
self.port_parameter_pen = QPen(QColor(101, 47, 17), Qt.NoPen, 0)
self.port_parameter_pen_sel = QPen(QColor(255, 0, 0), Qt.NoPen, 0)
self.port_audio_jack_pen = QPen(QColor(35, 61, 99), 0, Qt.NoPen)
self.port_audio_jack_pen_sel = QPen(QColor(255, 0, 0), 0, Qt.NoPen)
self.port_midi_jack_pen = QPen(QColor(120, 15, 16), 0, Qt.NoPen)
self.port_midi_jack_pen_sel = QPen(QColor(255, 0, 0), 0, Qt.NoPen)
self.port_midi_alsa_pen = QPen(QColor(63, 112, 19), 0, Qt.NoPen)
self.port_midi_alsa_pen_sel = QPen(QColor(255, 0, 0), 0, Qt.NoPen)
self.port_parameter_pen = QPen(QColor(101, 47, 17), 0, Qt.NoPen)
self.port_parameter_pen_sel = QPen(QColor(255, 0, 0), 0, Qt.NoPen)

self.port_audio_jack_bg = QColor(35, 61, 99)
self.port_audio_jack_bg_sel = QColor(255, 0, 0)


+ 4
- 104
source/frontend/pluginlist/pluginlistdialog.cpp View File

@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "pluginlistdialog.hpp"
@@ -32,7 +32,7 @@
#include "CarlaJuceUtils.hpp"
#include "CarlaUtils.h"

#include "CarlaString.hpp"
#include "extra/ScopedPointer.hpp"

#include <cstdlib>

@@ -382,31 +382,6 @@ int fontMetricsHorizontalAdvance(const QFontMetrics& fontMetrics, const QString&
// --------------------------------------------------------------------------------------------------------------------
// Qt-compatible plugin info

// base details, nicely packed and POD-only so we can directly use as binary
struct PluginInfoHeader {
uint16_t build;
uint16_t type;
uint32_t hints;
uint64_t uniqueId;
uint16_t audioIns;
uint16_t audioOuts;
uint16_t cvIns;
uint16_t cvOuts;
uint16_t midiIns;
uint16_t midiOuts;
uint16_t parameterIns;
uint16_t parameterOuts;
};

// full details, now with non-POD types
struct PluginInfo : PluginInfoHeader {
QString category;
QString filename;
QString name;
QString label;
QString maker;
};

// convert PluginInfo to Qt types
static QVariant asByteArray(const PluginInfo& info)
{
@@ -672,7 +647,7 @@ struct PluginListDialog::PrivateData {
bool useWineBridges = false;
CarlaPluginDiscoveryHandle handle = nullptr;
QCarlaString tool;
CarlaScopedPointer<PluginRefreshDialog> dialog;
ScopedPointer<PluginRefreshDialog> dialog;
Discovery()
{
restart();
@@ -908,7 +883,7 @@ PluginListDialog::PluginListDialog(QWidget* const parent, const HostSettings* co

#if 0
// NOTE: We Assume win32 carla build will not run win64 plugins
if (WINDOWS and not kIs64bit) or not host.showPluginBridges:
if (CARLA_OS_WIN and not CARLA_OS_64BIT) or not host.showPluginBridges:
ui.ch_native.setChecked(True)
ui.ch_native.setEnabled(False)
ui.ch_native.setVisible(True)
@@ -2090,78 +2065,3 @@ void PluginListDialog::saveSettings()
}

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

PluginListDialog*
carla_frontend_createPluginListDialog(void* const parent, const HostSettings* const hostSettings)
{
return new PluginListDialog(reinterpret_cast<QWidget*>(parent), hostSettings);
}

void
carla_frontend_destroyPluginListDialog(PluginListDialog* const dialog)
{
dialog->close();
delete dialog;
}

void
carla_frontend_setPluginListDialogPath(PluginListDialog* const dialog, const int ptype, const char* const path)
{
dialog->setPluginPath(static_cast<PluginType>(ptype), path);
}

const PluginListDialogResults*
carla_frontend_execPluginListDialog(PluginListDialog* const dialog)
{
if (dialog->exec())
{
static PluginListDialogResults ret;
static CarlaString category;
static CarlaString filename;
static CarlaString name;
static CarlaString label;
static CarlaString maker;

const PluginInfo& plugin(dialog->getSelectedPluginInfo());

category = plugin.category.toUtf8();
filename = plugin.filename.toUtf8();
name = plugin.name.toUtf8();
label = plugin.label.toUtf8();
maker = plugin.maker.toUtf8();

ret.build = plugin.build;
ret.type = plugin.type;
ret.hints = plugin.hints;
ret.category = category;
ret.filename = filename;
ret.name = name;
ret.label = label;
ret.maker = maker;
ret.uniqueId = plugin.uniqueId;
ret.audioIns = plugin.audioIns;
ret.audioOuts = plugin.audioOuts;
ret.cvIns = plugin.cvIns;
ret.cvOuts = plugin.cvOuts;
ret.midiIns = plugin.midiIns;
ret.midiOuts = plugin.midiOuts;
ret.parameterIns = plugin.parameterIns;
ret.parameterOuts = plugin.parameterOuts;

return &ret;
}

return nullptr;
}

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

// const PluginListDialogResults*
// carla_frontend_createAndExecPluginListDialog(void* const parent, const HostSettings* const hostSettings)
// {
// PluginListDialog gui(reinterpret_cast<QWidget*>(parent), hostSettings);
//
// return carla_frontend_execPluginListDialog(&gui);
// }

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

+ 29
- 5
source/frontend/pluginlist/pluginlistdialog.hpp View File

@@ -1,9 +1,9 @@
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "CarlaFrontend.h"
#include "carla_frontend.h"

#ifdef __clang__
# pragma clang diagnostic push
@@ -15,7 +15,6 @@
# pragma GCC diagnostic ignored "-Wdeprecated-copy"
#endif

#include <QtWidgets/QDialog>
#include "ui_pluginlistdialog.h"

#ifdef __clang__
@@ -24,10 +23,35 @@
# pragma GCC diagnostic pop
#endif

class QSafeSettings;
typedef struct _CarlaPluginDiscoveryInfo CarlaPluginDiscoveryInfo;
typedef struct _HostSettings HostSettings;
struct PluginInfo;

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

// base details, nicely packed and POD-only so we can directly use as binary
struct PluginInfoHeader {
uint16_t build;
uint16_t type;
uint32_t hints;
uint64_t uniqueId;
uint16_t audioIns;
uint16_t audioOuts;
uint16_t cvIns;
uint16_t cvOuts;
uint16_t midiIns;
uint16_t midiOuts;
uint16_t parameterIns;
uint16_t parameterOuts;
};

// full details, now with non-POD types
struct PluginInfo : PluginInfoHeader {
QString category;
QString filename;
QString name;
QString label;
QString maker;
};

// --------------------------------------------------------------------------------------------------------------------
// Plugin List Dialog


+ 41
- 0
source/frontend/qt_compat.py View File

@@ -21,13 +21,16 @@ elif qt_config == 6:
QDialog,
QDialogButtonBox,
QFileDialog,
QFrame,
QGraphicsItem,
QGraphicsScene,
QGraphicsView,
QHeaderView,
QLineEdit,
QListWidgetItem,
QMenu,
QMessageBox,
QSizePolicy,
QStyle,
)

@@ -36,11 +39,16 @@ elif qt_config == 6:

Qt.AA_DontShowIconsInMenus = Qt.ApplicationAttribute.AA_DontShowIconsInMenus

Qt.DownArrow = Qt.ArrowType.DownArrow
Qt.RightArrow = Qt.ArrowType.RightArrow

Qt.IgnoreAspectRatio = Qt.AspectRatioMode.IgnoreAspectRatio
Qt.KeepAspectRatio = Qt.AspectRatioMode.KeepAspectRatio

Qt.NoBrush = Qt.BrushStyle.NoBrush

Qt.ToolButtonTextBesideIcon = Qt.ToolButtonStyle.ToolButtonTextBesideIcon

Qt.Checked = Qt.CheckState.Checked
Qt.Unchecked = Qt.CheckState.Unchecked

@@ -83,6 +91,8 @@ elif qt_config == 6:
Qt.Key_E = Qt.Key.Key_E
Qt.Key_Eacute = Qt.Key.Key_Eacute
Qt.Key_Egrave = Qt.Key.Key_Egrave
Qt.Key_End = Qt.Key.Key_End
Qt.Key_Enter = Qt.Key.Key_Enter
Qt.Key_Escape = Qt.Key.Key_Escape
Qt.Key_F = Qt.Key.Key_F
Qt.Key_G = Qt.Key.Key_G
@@ -95,12 +105,16 @@ elif qt_config == 6:
Qt.Key_N = Qt.Key.Key_N
Qt.Key_O = Qt.Key.Key_O
Qt.Key_P = Qt.Key.Key_P
Qt.Key_PageDown = Qt.Key.Key_PageDown
Qt.Key_PageUp = Qt.Key.Key_PageUp
Qt.Key_ParenLeft = Qt.Key.Key_ParenLeft
Qt.Key_Plus = Qt.Key.Key_Plus
Qt.Key_Q = Qt.Key.Key_Q
Qt.Key_QuoteDbl = Qt.Key.Key_QuoteDbl
Qt.Key_R = Qt.Key.Key_R
Qt.Key_Return = Qt.Key.Key_Return
Qt.Key_S = Qt.Key.Key_S
Qt.Key_Space = Qt.Key.Key_Space
Qt.Key_T = Qt.Key.Key_T
Qt.Key_U = Qt.Key.Key_U
Qt.Key_V = Qt.Key.Key_V
@@ -132,8 +146,10 @@ elif qt_config == 6:
Qt.Horizontal = Qt.Orientation.Horizontal

Qt.FlatCap = Qt.PenCapStyle.FlatCap
Qt.RoundCap = Qt.PenCapStyle.RoundCap

Qt.MiterJoin = Qt.PenJoinStyle.MiterJoin
Qt.RoundJoin = Qt.PenJoinStyle.RoundJoin

Qt.DashLine = Qt.PenStyle.DashLine
Qt.NoPen = Qt.PenStyle.NoPen
@@ -144,6 +160,11 @@ elif qt_config == 6:

Qt.AscendingOrder = Qt.SortOrder.AscendingOrder

Qt.TextSelectableByMouse = Qt.TextInteractionFlag.TextSelectableByMouse

Qt.ToolButtonIconOnly = Qt.ToolButtonStyle.ToolButtonIconOnly
Qt.ToolButtonTextBesideIcon = Qt.ToolButtonStyle.ToolButtonTextBesideIcon

Qt.SmoothTransformation = Qt.TransformationMode.SmoothTransformation

Qt.WA_OpaquePaintEvent = Qt.WidgetAttribute.WA_OpaquePaintEvent
@@ -173,6 +194,7 @@ elif qt_config == 6:

QDialog.exec_ = lambda d: d.exec()

QDialogButtonBox.Ok = QDialogButtonBox.StandardButton.Ok
QDialogButtonBox.Reset = QDialogButtonBox.StandardButton.Reset

QEvent.EnabledChange = QEvent.Type.EnabledChange
@@ -195,6 +217,12 @@ elif qt_config == 6:
QFont.Bold = QFont.Weight.Bold
QFont.Normal = QFont.Weight.Normal

QFrame.HLine = QFrame.Shape.HLine
QFrame.StyledPanel = QFrame.Shape.StyledPanel

QFrame.Raised = QFrame.Shadow.Raised
QFrame.Sunken = QFrame.Shadow.Sunken

QGraphicsItem.ItemSelectedHasChanged = QGraphicsItem.GraphicsItemChange.ItemSelectedHasChanged

QGraphicsItem.ItemIsFocusable = QGraphicsItem.GraphicsItemFlag.ItemIsFocusable
@@ -211,6 +239,9 @@ elif qt_config == 6:
QGraphicsView.MinimalViewportUpdate = QGraphicsView.ViewportUpdateMode.MinimalViewportUpdate

QHeaderView.Fixed = QHeaderView.ResizeMode.Fixed
QHeaderView.ResizeToContents = QHeaderView.ResizeMode.ResizeToContents

QLineEdit.Normal = QLineEdit.EchoMode.Normal

QListWidgetItem.UserType = QListWidgetItem.ItemType.UserType

@@ -218,9 +249,15 @@ elif qt_config == 6:

QMessageBox.exec_ = lambda mb: mb.exec()

QMessageBox.Cancel = QMessageBox.StandardButton.Cancel
QMessageBox.No = QMessageBox.StandardButton.No
QMessageBox.Ok = QMessageBox.StandardButton.Ok
QMessageBox.Yes = QMessageBox.StandardButton.Yes

QMessageBox.Critical = QMessageBox.Icon.Critical
QMessageBox.Information = QMessageBox.Icon.Information
QMessageBox.Warning = QMessageBox.Icon.Warning

QPainter.CompositionMode_Difference = QPainter.CompositionMode.CompositionMode_Difference
QPainter.CompositionMode_Multiply = QPainter.CompositionMode.CompositionMode_Multiply
QPainter.CompositionMode_Plus = QPainter.CompositionMode.CompositionMode_Plus
@@ -256,6 +293,10 @@ elif qt_config == 6:
QPalette.Window = QPalette.ColorRole.Window
QPalette.WindowText = QPalette.ColorRole.WindowText

# TODO remove this QPalette.Background is deprecated already in Qt5
QPalette.Background = QPalette.Window

QSizePolicy.Expanding = QSizePolicy.Policy.Expanding
QSizePolicy.Preferred = QSizePolicy.Policy.Preferred

QStyle.State_Selected = QStyle.StateFlag.State_Selected

+ 15
- 7
source/frontend/widgets/canvaspreviewframe.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
@@ -199,7 +199,11 @@ class CanvasPreviewFrame(QFrame):
return
if self.fMouseMode == self._MOUSE_MODE_SCALE:
event.accept()
self._scaleViewRect(event.globalY())
if qt_config == 5:
y = event.globalY()
else:
y = event.globalPosition().y()
self._scaleViewRect(y)
return
QFrame.mouseMoveEvent(self, event)

@@ -384,24 +388,28 @@ class CanvasPreviewFrame(QFrame):
self.setCursor(self.fZoomCursors[self._kCursorZoomIn if dy > 0 else self._kCursorZoomOut])
self.fScene.zoom_wheel(dy)

# FIXME do not rely on this
self.cursor().setPos(self.fMouseInitialZoomPos)

def _updateMouseMode(self, event):
if self.fMouseLeftDown and self.fMouseRightDown:
self.fMouseInitialZoomPos = event.globalPos()
if qt_config == 5:
self.fMouseInitialZoomPos = event.globalPos()
else:
self.fMouseInitialZoomPos = event.globalPosition().toPoint()
self.setCursor(self.fZoomCursors[self._kCursorZoom])
self.fMouseMode = self._MOUSE_MODE_SCALE

elif self.fMouseLeftDown:
self.setCursor(QCursor(Qt.SizeAllCursor))
if self.fMouseMode == self._MOUSE_MODE_NONE:
if QT_VERSION >= 0x60000:
if qt_config == 5:
x = event.x()
y = event.y()
else:
pos = event.position()
x = pos.x()
y = pos.y()
else:
x = event.x()
y = event.y()
self._moveViewRect(x, y)
self.fMouseMode = self._MOUSE_MODE_MOVE



+ 10
- 9
source/frontend/widgets/draggablegraphicsview.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
@@ -21,7 +21,8 @@ elif qt_config == 6:
# ---------------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)

from carla_shared import MACOS, CustomMessageBox, gCarla
from carla_backend import CARLA_OS_MAC
from carla_shared import CustomMessageBox, gCarla

# ---------------------------------------------------------------------------------------------------------------------
# Widget Class
@@ -47,7 +48,7 @@ class DraggableGraphicsView(QGraphicsView):
if os.path.isdir(filename):
#if os.path.exists(os.path.join(filename, "manifest.ttl")):
#return True
if MACOS and lfilename.endswith(".vst"):
if CARLA_OS_MAC and lfilename.endswith(".vst"):
return True
if lfilename.endswith(".vst3") and ".vst3" in self.fSupportedExtensions:
return True
@@ -119,18 +120,18 @@ class DraggableGraphicsView(QGraphicsView):
if timestamp is None:
return

if QT_VERSION >= 0x60000:
event = QMouseEvent(QEvent.MouseButtonPress,
event.position(), event.scenePosition(), event.globalPosition(),
Qt.LeftButton, Qt.LeftButton,
Qt.NoModifier)
else:
if qt_config == 5:
event = QMouseEvent(QEvent.MouseButtonPress,
event.localPos(), event.windowPos(), event.screenPos(),
Qt.LeftButton, Qt.LeftButton,
Qt.NoModifier,
Qt.MouseEventSynthesizedByApplication)
event.setTimestamp(timestamp)
else:
event = QMouseEvent(QEvent.MouseButtonPress,
event.position(), event.scenePosition(), event.globalPosition(),
Qt.LeftButton, Qt.LeftButton,
Qt.NoModifier)

QGraphicsView.mousePressEvent(self, event)



+ 4
- 3
source/frontend/widgets/paramspinbox.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -24,7 +24,8 @@ elif qt_config == 6:

import ui_inputdialog_value

from carla_shared import countDecimalPoints, MACOS
from carla_backend import CARLA_OS_MAC
from carla_shared import countDecimalPoints

# ------------------------------------------------------------------------------------------------------------
# Get a fixed value within min/max bounds
@@ -59,7 +60,7 @@ class CustomInputDialog(QDialog):
self.ui.doubleSpinBox.setPrefix(prefix)
self.ui.doubleSpinBox.setSuffix(suffix)

if MACOS:
if CARLA_OS_MAC:
self.setWindowModality(Qt.WindowModal)

if not scalePoints:


+ 5
- 2
source/frontend/widgets/pixmapkeyboard.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ---------------------------------------------------------------------------------------------------------------------
@@ -408,7 +408,10 @@ class PixmapKeyboard(QWidget):
if self.fPcKeybOffset == 0:
actOctaveDown.setEnabled(False)

actSelected = menu.exec_(event.screenPos().toPoint())
if qt_config == 5:
actSelected = menu.exec_(event.screenPos().toPoint())
else:
actSelected = menu.exec_(event.globalPosition().toPoint())

if not actSelected:
return


+ 3
- 3
source/frontend/widgets/racklistwidget.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
# SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
# SPDX-License-Identifier: GPL-2.0-or-later

# ------------------------------------------------------------------------------------------------------------
@@ -24,7 +24,7 @@ elif qt_config == 6:
# ------------------------------------------------------------------------------------------------------------
# Imports (Custom Stuff)

from carla_backend import CUSTOM_DATA_TYPE_PROPERTY, MACOS
from carla_backend import CARLA_OS_MAC, CUSTOM_DATA_TYPE_PROPERTY
from carla_shared import gCarla, CustomMessageBox
from carla_skin import createPluginSlot

@@ -259,7 +259,7 @@ class RackListWidget(QListWidget):
if os.path.isdir(filename):
#if os.path.exists(os.path.join(filename, "manifest.ttl")):
#return True
if MACOS and lfilename.endswith(".vst"):
if CARLA_OS_MAC and lfilename.endswith(".vst"):
return True
if lfilename.endswith(".vst3") and ".vst3" in self.fSupportedExtensions:
return True


+ 3
- 17
source/includes/CarlaNativeExtUI.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Native Plugin API (C++)
* Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_NATIVE_EXTERNAL_UI_HPP_INCLUDED
#define CARLA_NATIVE_EXTERNAL_UI_HPP_INCLUDED
@@ -220,7 +206,7 @@ protected:
#endif

private:
CarlaString fExtUiPath;
String fExtUiPath;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePluginAndUiClass)
};


+ 9
- 23
source/includes/CarlaNativePrograms.hpp View File

@@ -1,19 +1,5 @@
/*
* Carla Native Plugin API (C++)
* 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 General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the doc/GPL.txt file.
*/
// SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef CARLA_NATIVE_PROGRAMS_HPP_INCLUDED
#define CARLA_NATIVE_PROGRAMS_HPP_INCLUDED
@@ -23,14 +9,14 @@
#include "CarlaMathUtils.hpp"
#include "CarlaMutex.hpp"

#include "extra/String.hpp"

#include "water/files/File.h"
#include "water/memory/SharedResourcePointer.h"
#include "water/text/StringArray.h"

using water::File;
using water::SharedResourcePointer;
using water::String;
using water::StringArray;

/*!
* @defgroup CarlaNativeAPI Carla Native API
@@ -48,7 +34,7 @@ enum FileType {

template <FileType fileType>
struct NativePluginPresetManager {
StringArray filenames;
water::StringArray filenames;

NativePluginPresetManager(const char* const paths, const char* const wildcard)
: filenames()
@@ -58,9 +44,9 @@ struct NativePluginPresetManager {
if (paths == nullptr || paths[0] == '\0' || wildcard[0] == '\0')
return;

const StringArray splitPaths(StringArray::fromTokens(paths, CARLA_OS_SPLIT_STR, ""));
const water::StringArray splitPaths(water::StringArray::fromTokens(paths, CARLA_OS_SPLIT_STR, ""));

for (String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
for (water::String *it = splitPaths.begin(), *end = splitPaths.end(); it != end; ++it)
{
std::vector<File> results;

@@ -126,11 +112,11 @@ protected:
const NativePluginPresetManagerType& pm(kPrograms.get());
CARLA_SAFE_ASSERT_RETURN(index < pm.filenames.size(), nullptr);

fRetMidiProgramName = File(pm.filenames.strings.getUnchecked(index).toRawUTF8()).getFileNameWithoutExtension();
fRetMidiProgramName = File(pm.filenames.strings.getUnchecked(index).toRawUTF8()).getFileNameWithoutExtension().toRawUTF8();

fRetMidiProgram.bank = 0;
fRetMidiProgram.program = uindex;
fRetMidiProgram.name = fRetMidiProgramName.toRawUTF8();
fRetMidiProgram.name = fRetMidiProgramName;

return &fRetMidiProgram;
}


+ 10
- 0
source/includes/lv2/atom-helpers.h View File

@@ -54,6 +54,7 @@ struct _LV2_Atom_Buffer
uint32_t capacity;
uint32_t chunk_type;
uint32_t sequence_type;
uint32_t _alignment_padding;
LV2_Atom_Sequence atoms;

} LV2_Atom_Buffer;
@@ -209,6 +210,11 @@ LV2_Atom_Event *lv2_atom_buffer_get (

// Write an event at a LV2 atom:Sequence buffer iterator.

#if defined(__GNUC__) && __GNUC__ > 7
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstringop-overflow"
#endif

static inline
bool lv2_atom_buffer_write (
LV2_Atom_Buffer_Iterator *iter,
@@ -240,6 +246,10 @@ bool lv2_atom_buffer_write (
return true;
}

#if defined(__GNUC__) && __GNUC__ > 7
# pragma GCC diagnostic pop
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif


+ 0
- 2
source/includes/lv2_rdf.hpp View File

@@ -242,7 +242,6 @@ typedef uint32_t LV2_Property;
#define LV2_UI_X11 7
#define LV2_UI_EXTERNAL 8
#define LV2_UI_OLD_EXTERNAL 9
#define LV2_UI_MOD 10

#define LV2_IS_UI_GTK2(x) ((x) == LV2_UI_GTK2)
#define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3)
@@ -253,7 +252,6 @@ typedef uint32_t LV2_Property;
#define LV2_IS_UI_X11(x) ((x) == LV2_UI_X11)
#define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL)
#define LV2_IS_UI_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL)
#define LV2_IS_UI_MOD(x) ((x) == LV2_UI_MOD)

// Plugin Types
#define LV2_PLUGIN_DELAY 0x000001


+ 0
- 6
source/includes/vst3sdk/JUCE_README.md View File

@@ -1,6 +0,0 @@
This list details modifications made to the VST3 SDK in order to facilitate
inclusion in JUCE.

- `#warning` directives were removed from fstring.cpp, as these cannot be
silenced with a `pragma GCC diagnostic ignored "-Wcpp"` when building with
g++.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save