From e2b8b21967d3f809b2c7f26458a961f1efb46e4f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 29 Aug 2020 04:54:18 +0200 Subject: [PATCH 01/24] Separate the editor code from VST --- .gitmodules | 2 +- .travis.yml | 2 + .travis/script_mingw.sh | 4 +- .travis/script_moddevices.sh | 2 +- .travis/script_plugins.sh | 3 +- .travis/script_test.sh | 2 +- CMakeLists.txt | 13 +- cmake/LV2Config.cmake | 16 + cmake/SfizzConfig.cmake | 12 +- editor/CMakeLists.txt | 16 + editor/cmake/Vstgui.cmake | 209 ++++ .../VST3_SDK => editor/external}/vstgui4 | 0 editor/src/editor/EditIds.cpp | 32 + editor/src/editor/EditIds.h | 37 + editor/src/editor/Editor.cpp | 977 ++++++++++++++++++ editor/src/editor/Editor.h | 30 + editor/src/editor/EditorController.h | 43 + {vst => editor/src/editor}/GUIComponents.cpp | 3 + {vst => editor/src/editor}/GUIComponents.h | 3 + editor/src/editor/utility/vstgui_after.h | 9 + editor/src/editor/utility/vstgui_before.h | 12 + lv2/CMakeLists.txt | 2 +- vst/CMakeLists.txt | 5 +- vst/SfizzVstController.cpp | 18 +- vst/SfizzVstEditor.cpp | 842 ++------------- vst/SfizzVstEditor.h | 94 +- vst/SfizzVstProcessor.cpp | 6 +- vst/SfizzVstState.h | 6 +- vst/cmake/Vst3.cmake | 219 +--- 29 files changed, 1557 insertions(+), 1062 deletions(-) create mode 100644 editor/CMakeLists.txt create mode 100644 editor/cmake/Vstgui.cmake rename {vst/external/VST_SDK/VST3_SDK => editor/external}/vstgui4 (100%) create mode 100644 editor/src/editor/EditIds.cpp create mode 100644 editor/src/editor/EditIds.h create mode 100644 editor/src/editor/Editor.cpp create mode 100644 editor/src/editor/Editor.h create mode 100644 editor/src/editor/EditorController.h rename {vst => editor/src/editor}/GUIComponents.cpp (93%) rename {vst => editor/src/editor}/GUIComponents.h (91%) create mode 100644 editor/src/editor/utility/vstgui_after.h create mode 100644 editor/src/editor/utility/vstgui_before.h diff --git a/.gitmodules b/.gitmodules index 7a652206..1247ca5f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,6 +16,6 @@ url = https://github.com/sfztools/vst3_public_sdk.git shallow = true [submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"] - path = vst/external/VST_SDK/VST3_SDK/vstgui4 + path = editor/external/vstgui4 url = https://github.com/sfztools/vstgui.git shallow = true diff --git a/.travis.yml b/.travis.yml index 7286a566..1fb67fdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -110,6 +110,7 @@ jobs: env: - INSTALL_DIR="sfizz-plugins-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - ENABLE_VST_PLUGIN=OFF + - ENABLE_LV2_UI=OFF addons: apt: packages: @@ -125,6 +126,7 @@ jobs: env: - INSTALL_DIR="sfizz-plugins-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}" - ENABLE_VST_PLUGIN=ON + - ENABLE_LV2_UI=ON addons: apt: packages: diff --git a/.travis/script_mingw.sh b/.travis/script_mingw.sh index 2f1f545f..e09db92a 100755 --- a/.travis/script_mingw.sh +++ b/.travis/script_mingw.sh @@ -9,7 +9,7 @@ if [[ ${CROSS_COMPILE} == "mingw32" ]]; then -DENABLE_LTO=OFF \ -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ - -DSFIZZ_STATIC_LIBSNDFILE=ON \ + -DSFIZZ_STATIC_DEPENDENCIES=ON \ -DCMAKE_CXX_STANDARD=17 \ .. buildenv make -j$(nproc) @@ -18,7 +18,7 @@ elif [[ ${CROSS_COMPILE} == "mingw64" ]]; then -DENABLE_LTO=OFF \ -DSFIZZ_JACK=OFF \ -DSFIZZ_VST=ON \ - -DSFIZZ_STATIC_LIBSNDFILE=ON \ + -DSFIZZ_STATIC_DEPENDENCIES=ON \ -DCMAKE_CXX_STANDARD=17 \ .. buildenv make -j$(nproc) diff --git a/.travis/script_moddevices.sh b/.travis/script_moddevices.sh index 649dbb3d..278b7045 100755 --- a/.travis/script_moddevices.sh +++ b/.travis/script_moddevices.sh @@ -7,5 +7,5 @@ mkdir -p build/${INSTALL_DIR} && cd build buildenv mod-plugin-builder /usr/local/bin/cmake \ -DSFIZZ_SYSTEM_PROCESSOR=armv7-a \ - -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF .. + -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_LV2_UI=OFF .. buildenv mod-plugin-builder make -j$(nproc) diff --git a/.travis/script_plugins.sh b/.travis/script_plugins.sh index 89eaf8ac..66e6b09f 100755 --- a/.travis/script_plugins.sh +++ b/.travis/script_plugins.sh @@ -5,9 +5,10 @@ mkdir -p build/${INSTALL_DIR} && cd build cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_JACK=OFF \ -DSFIZZ_VST="$ENABLE_VST_PLUGIN" \ + -DSFIZZ_LV2_UI="$ENABLE_LV2_UI" \ -DSFIZZ_TESTS=OFF \ -DSFIZZ_SHARED=OFF \ - -DSFIZZ_STATIC_LIBSNDFILE=ON \ + -DSFIZZ_STATIC_DEPENDENCIES=ON \ -DCMAKE_CXX_STANDARD=17 \ .. make -j$(nproc) diff --git a/.travis/script_test.sh b/.travis/script_test.sh index 844ec9b9..1a23a092 100755 --- a/.travis/script_test.sh +++ b/.travis/script_test.sh @@ -6,7 +6,7 @@ cmake -DCMAKE_BUILD_TYPE=Release \ -DSFIZZ_JACK=OFF \ -DSFIZZ_TESTS=ON \ -DSFIZZ_SHARED=OFF \ - -DSFIZZ_STATIC_LIBSNDFILE=OFF \ + -DSFIZZ_STATIC_DEPENDENCIES=OFF \ -DSFIZZ_LV2=OFF \ -DCMAKE_CXX_STANDARD=17 \ .. diff --git a/CMakeLists.txt b/CMakeLists.txt index cbc3945b..0158e93a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,16 +19,11 @@ include (SfizzConfig) # Build Options set (BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests [default: OFF]") -# On macOS add the needed directories for both library and jack client -if (APPLE) - include_directories (SYSTEM /usr/local/opt/libsndfile/include) - link_directories (/usr/local/opt/libsndfile/lib) -endif() - option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON) option (SFIZZ_JACK "Enable JACK stand-alone build [default: ON]" ON) option (SFIZZ_RENDER "Enable renderer of SMF files [default: ON]" ON) option (SFIZZ_LV2 "Enable LV2 plug-in build [default: ON]" ON) +option (SFIZZ_LV2_UI "Enable LV2 plug-in user interface [default: ON]" ON) option (SFIZZ_VST "Enable VST plug-in build [default: OFF]" OFF) option (SFIZZ_AU "Enable AU plug-in build [default: OFF]" OFF) option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF) @@ -36,7 +31,7 @@ option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF) option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF) option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON) option (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF) -option (SFIZZ_STATIC_LIBSNDFILE "Link libsndfile statically [default: OFF]" OFF) +option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" OFF) option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF) # Don't use IPO in non Release builds @@ -51,6 +46,10 @@ add_subdirectory (src) # Optional targets add_subdirectory (clients) +if ((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST) + add_subdirectory (editor) +endif() + if (SFIZZ_LV2) add_subdirectory (lv2) endif() diff --git a/cmake/LV2Config.cmake b/cmake/LV2Config.cmake index 95c54bdf..6b9d9b76 100644 --- a/cmake/LV2Config.cmake +++ b/cmake/LV2Config.cmake @@ -14,6 +14,22 @@ else() set (LV2PLUGIN_SPDX_LICENSE_ID "ISC") endif() +if(SFIZZ_LV2_UI) + set(LV2PLUGIN_IF_ENABLE_UI "") +else() + set(LV2PLUGIN_IF_ENABLE_UI "#") +endif() + +if(WIN32) + set(LV2_UI_TYPE "WindowsUI") +elseif(APPLE) + set(LV2_UI_TYPE "CocoaUI") +elseif(HAIKU) + set(LV2_UI_TYPE "BeUI") +else() + set(LV2_UI_TYPE "X11UI") +endif() + if (MSVC) set (LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lv2" CACHE STRING "Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lv2}]") diff --git a/cmake/SfizzConfig.cmake b/cmake/SfizzConfig.cmake index 95b462e6..ae6aec60 100644 --- a/cmake/SfizzConfig.cmake +++ b/cmake/SfizzConfig.cmake @@ -17,6 +17,11 @@ if (WIN32) add_compile_definitions(_WIN32_WINNT=0x601) endif() +# Do not define macros `min` and `max` +if (WIN32) + add_compile_definitions(NOMINMAX) +endif() + # The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio... # see https://gitlab.kitware.com/cmake/cmake/issues/15170 @@ -48,6 +53,7 @@ function(sfizz_enable_fast_math NAME) endif() endfunction() +# The sndfile library add_library(sfizz-sndfile INTERFACE) if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") @@ -59,11 +65,12 @@ else() find_package(PkgConfig REQUIRED) pkg_check_modules(SNDFILE "sndfile" REQUIRED) target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS}) - if (SFIZZ_STATIC_LIBSNDFILE) + if (SFIZZ_STATIC_DEPENDENCIES) target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES}) else() target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES}) endif() + link_directories(${SNDFILE_LIBRARY_DIRS}) endif() @@ -112,12 +119,13 @@ Build using LTO: ${ENABLE_LTO} Build as shared library: ${SFIZZ_SHARED} Build JACK stand-alone client: ${SFIZZ_JACK} Build LV2 plug-in: ${SFIZZ_LV2} +Build LV2 user interface: ${SFIZZ_LV2_UI} Build VST plug-in: ${SFIZZ_VST} Build AU plug-in: ${SFIZZ_AU} Build benchmarks: ${SFIZZ_BENCHMARKS} Build tests: ${SFIZZ_TESTS} Use vcpkg: ${SFIZZ_USE_VCPKG} -Statically link libsndfile: ${SFIZZ_STATIC_LIBSNDFILE} +Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES} Link libatomic: ${SFIZZ_LINK_LIBATOMIC} Use clang libc++: ${USE_LIBCPP} Release asserts: ${SFIZZ_RELEASE_ASSERTS} diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt new file mode 100644 index 00000000..977f36a4 --- /dev/null +++ b/editor/CMakeLists.txt @@ -0,0 +1,16 @@ +set(VSTGUI_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/vstgui4") +include("cmake/Vstgui.cmake") + +# editor +add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL + src/editor/EditIds.h + src/editor/EditIds.cpp + src/editor/Editor.h + src/editor/Editor.cpp + src/editor/EditorController.h + src/editor/GUIComponents.h + src/editor/GUIComponents.cpp + src/editor/utility/vstgui_after.h + src/editor/utility/vstgui_before.h) +target_include_directories(sfizz_editor PUBLIC "src") +target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui absl::strings) diff --git a/editor/cmake/Vstgui.cmake b/editor/cmake/Vstgui.cmake new file mode 100644 index 00000000..92f85f03 --- /dev/null +++ b/editor/cmake/Vstgui.cmake @@ -0,0 +1,209 @@ +add_library(sfizz-vstgui STATIC EXCLUDE_FROM_ALL + "${VSTGUI_BASEDIR}/vstgui/lib/animation/animations.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/animation/animator.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/animation/timingfunctions.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cbitmap.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cbitmapfilter.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/ccolor.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cdatabrowser.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cdrawcontext.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cdrawmethods.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cdropsource.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cfileselector.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cfont.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cframe.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cgradientview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cgraphicspath.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/clayeredviewcontainer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/clinestyle.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/coffscreencontext.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cautoanimation.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cbuttons.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/ccolorchooser.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/ccontrol.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cfontchooser.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cknob.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/clistcontrol.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cmoviebitmap.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cmoviebutton.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/coptionmenu.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cparamdisplay.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cscrollbar.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/csearchtextedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/csegmentbutton.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cslider.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cspecialdigit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/csplashscreen.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cstringlist.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cswitch.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/ctextedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/ctextlabel.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cvumeter.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/controls/cxypad.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/copenglview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cpoint.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/crect.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/crowcolumnview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cscrollview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cshadowviewcontainer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/csplitview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cstring.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/ctabview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/ctooltipsupport.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cviewcontainer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/cvstguitimer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/genericstringlistdatabrowsersource.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/genericoptionmenu.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/vstguidebug.cpp") + +if(WIN32) + target_sources(sfizz-vstgui PRIVATE + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2dbitmap.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2ddrawcontext.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2dfont.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2dgraphicspath.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32datapackage.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32dragging.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32frame.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32openglview.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32optionmenu.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32support.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/win32textedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/winfileselector.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/winstring.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/wintimer.cpp") +elseif(APPLE) + target_sources(sfizz-vstgui PRIVATE + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/genericoptionmenu.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/generictextedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/carbon/hiviewframe.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/carbon/hiviewoptionmenu.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/carbon/hiviewtextedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/caviewlayer.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cfontmac.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cgbitmap.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cgdrawcontext.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/autoreleasepool.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/cocoahelpers.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/cocoaopenglview.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/cocoatextedit.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/nsviewframe.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/cocoa/nsviewoptionmenu.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/macclipboard.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/macfileselector.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/macglobals.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/macstring.mm" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/mactimer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/quartzgraphicspath.cpp") +else() + target_sources(sfizz-vstgui PRIVATE + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/fileresourceinputstream.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/common/generictextedit.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairobitmap.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairocontext.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairofont.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairogradient.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/cairopath.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/linuxstring.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11fileselector.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11frame.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11platform.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11timer.cpp" + "${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11utils.cpp") +endif() + +target_include_directories(sfizz-vstgui PUBLIC "${VSTGUI_BASEDIR}") + +if(WIN32) + if (NOT MSVC) + # autolinked on MSVC with pragmas + find_library(OPENGL32_LIBRARY "opengl32") + find_library(D2D1_LIBRARY "d2d1") + find_library(DWRITE_LIBRARY "dwrite") + find_library(DWMAPI_LIBRARY "dwmapi") + find_library(WINDOWSCODECS_LIBRARY "windowscodecs") + find_library(SHLWAPI_LIBRARY "shlwapi") + target_link_libraries(sfizz-vstgui PRIVATE + "${OPENGL32_LIBRARY}" + "${D2D1_LIBRARY}" + "${DWRITE_LIBRARY}" + "${DWMAPI_LIBRARY}" + "${WINDOWSCODECS_LIBRARY}" + "${SHLWAPI_LIBRARY}") + endif() +elseif(APPLE) + find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") + find_library(APPLE_FOUNDATION_LIBRARY "Foundation") + find_library(APPLE_COCOA_LIBRARY "Cocoa") + find_library(APPLE_OPENGL_LIBRARY "OpenGL") + find_library(APPLE_ACCELERATE_LIBRARY "Accelerate") + find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore") + find_library(APPLE_CARBON_LIBRARY "Carbon") + find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox") + find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio") + find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI") + target_link_libraries(sfizz-vstgui PRIVATE + "${APPLE_COREFOUNDATION_LIBRARY}" + "${APPLE_FOUNDATION_LIBRARY}" + "${APPLE_COCOA_LIBRARY}" + "${APPLE_OPENGL_LIBRARY}" + "${APPLE_ACCELERATE_LIBRARY}" + "${APPLE_QUARTZCORE_LIBRARY}" + "${APPLE_CARBON_LIBRARY}" + "${APPLE_AUDIOTOOLBOX_LIBRARY}" + "${APPLE_COREAUDIO_LIBRARY}" + "${APPLE_COREMIDI_LIBRARY}") +else() + find_package(X11 REQUIRED) + find_package(Freetype REQUIRED) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBXCB REQUIRED xcb) + pkg_check_modules(LIBXCB_UTIL REQUIRED xcb-util) + pkg_check_modules(LIBXCB_CURSOR REQUIRED xcb-cursor) + pkg_check_modules(LIBXCB_KEYSYMS REQUIRED xcb-keysyms) + pkg_check_modules(LIBXCB_XKB REQUIRED xcb-xkb) + pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) + pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) + pkg_check_modules(CAIRO REQUIRED cairo) + pkg_check_modules(FONTCONFIG REQUIRED fontconfig) + target_include_directories(sfizz-vstgui PRIVATE + ${X11_INCLUDE_DIRS} + ${FREETYPE_INCLUDE_DIRS} + ${LIBXCB_INCLUDE_DIRS} + ${LIBXCB_UTIL_INCLUDE_DIRS} + ${LIBXCB_CURSOR_INCLUDE_DIRS} + ${LIBXCB_KEYSYMS_INCLUDE_DIRS} + ${LIBXCB_XKB_INCLUDE_DIRS} + ${LIBXKB_COMMON_INCLUDE_DIRS} + ${LIBXKB_COMMON_X11_INCLUDE_DIRS} + ${CAIRO_INCLUDE_DIRS} + ${FONTCONFIG_INCLUDE_DIRS}) + target_link_libraries(sfizz-vstgui PRIVATE + ${X11_LIBRARIES} + ${FREETYPE_LIBRARIES} + ${LIBXCB_LIBRARIES} + ${LIBXCB_UTIL_LIBRARIES} + ${LIBXCB_CURSOR_LIBRARIES} + ${LIBXCB_KEYSYMS_LIBRARIES} + ${LIBXCB_XKB_LIBRARIES} + ${LIBXKB_COMMON_LIBRARIES} + ${LIBXKB_COMMON_X11_LIBRARIES} + ${CAIRO_LIBRARIES} + ${FONTCONFIG_LIBRARIES}) + find_library(DL_LIBRARY "dl") + if(DL_LIBRARY) + target_link_libraries(sfizz-vstgui PRIVATE "${DL_LIBRARY}") + endif() +endif() + +if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + target_compile_definitions(sfizz-vstgui PRIVATE "DEVELOPMENT") +endif() + +if(${CMAKE_BUILD_TYPE} MATCHES "Release") + target_compile_definitions(sfizz-vstgui PRIVATE "RELEASE") +endif() diff --git a/vst/external/VST_SDK/VST3_SDK/vstgui4 b/editor/external/vstgui4 similarity index 100% rename from vst/external/VST_SDK/VST3_SDK/vstgui4 rename to editor/external/vstgui4 diff --git a/editor/src/editor/EditIds.cpp b/editor/src/editor/EditIds.cpp new file mode 100644 index 00000000..1d148fb0 --- /dev/null +++ b/editor/src/editor/EditIds.cpp @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "EditIds.h" + +EditRange EditRange::get(EditId id) +{ + switch (id) { + default: + assert(false); + return {}; + case EditId::Volume: + return { 0, -60, 6 }; + case EditId::Polyphony: + return { 64, 1, 256 }; + case EditId::Oversampling: + return { 0, 0, 3 }; + case EditId::PreloadSize: + return { 8192, 1024, 65536 }; + case EditId::ScalaRootKey: + return { 60, 0, 127 }; + case EditId::TuningFrequency: + return { 440, 300, 500 }; + case EditId::StretchTuning: + return { 0, 0, 1 }; + case EditId::UIActivePanel: + return { 0, 0, 255 }; + } +} diff --git a/editor/src/editor/EditIds.h b/editor/src/editor/EditIds.h new file mode 100644 index 00000000..660853db --- /dev/null +++ b/editor/src/editor/EditIds.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include + +enum class EditId : int { + SfzFile, + Volume, + Polyphony, + Oversampling, + PreloadSize, + ScalaFile, + ScalaRootKey, + TuningFrequency, + StretchTuning, + UINumCurves, + UINumMasters, + UINumGroups, + UINumRegions, + UINumPreloadedSamples, + UINumActiveVoices, + UIActivePanel, +}; + +struct EditRange { + float def = 0.0; + float min = 0.0; + float max = 1.0; + constexpr EditRange() = default; + constexpr EditRange(float def, float min, float max) + : def(def), min(min), max(max) {} + static EditRange get(EditId id); +}; diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp new file mode 100644 index 00000000..c4d247c8 --- /dev/null +++ b/editor/src/editor/Editor.cpp @@ -0,0 +1,977 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#include "Editor.h" +#include "EditorController.h" +#include "EditIds.h" +#include "GUIComponents.h" +#include +#include +#include + +#include "utility/vstgui_before.h" +#include "vstgui/vstgui.h" +#include "utility/vstgui_after.h" + +using namespace VSTGUI; + +const int Editor::viewWidth { 482 }; +const int Editor::viewHeight { 225 }; + +struct Editor::Impl : EditorController::Receiver, IControlListener { + EditorController* ctrl_ = nullptr; + CFrame* frame_ = nullptr; + SharedPointer view_; + + enum { + kPanelGeneral, + // kPanelControls, + kPanelSettings, + kPanelTuning, + kPanelInfo, + kNumPanels, + }; + + unsigned activePanel_ = 0; + CViewContainer* subPanels_[kNumPanels] = {}; + + enum { + kTagLoadSfzFile, + kTagSetVolume, + kTagSetNumVoices, + kTagSetOversampling, + kTagSetPreloadSize, + kTagLoadScalaFile, + kTagSetScalaRootKey, + kTagSetTuningFrequency, + kTagSetStretchedTuning, + kTagFirstChangePanel, + kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, + }; + + CTextLabel* sfzFileLabel_ = nullptr; + CTextLabel* scalaFileLabel_ = nullptr; + CSliderBase *volumeSlider_ = nullptr; + CTextLabel* volumeLabel_ = nullptr; + CSliderBase *numVoicesSlider_ = nullptr; + CTextLabel* numVoicesLabel_ = nullptr; + CSliderBase *oversamplingSlider_ = nullptr; + CTextLabel* oversamplingLabel_ = nullptr; + CSliderBase *preloadSizeSlider_ = nullptr; + CTextLabel* preloadSizeLabel_ = nullptr; + CSliderBase *scalaRootKeySlider_ = nullptr; + CTextLabel* scalaRootKeyLabel_ = nullptr; + CSliderBase *tuningFrequencySlider_ = nullptr; + CTextLabel* tuningFrequencyLabel_ = nullptr; + CSliderBase *stretchedTuningSlider_ = nullptr; + CTextLabel* stretchedTuningLabel_ = nullptr; + + CTextLabel* infoCurvesLabel_ = nullptr; + CTextLabel* infoMastersLabel_ = nullptr; + CTextLabel* infoGroupsLabel_ = nullptr; + CTextLabel* infoRegionsLabel_ = nullptr; + CTextLabel* infoSamplesLabel_ = nullptr; + CTextLabel* infoVoicesLabel_ = nullptr; + + void uiReceiveValue(EditId id, const EditValue& v) override; + + void createFrameContents(); + + template + void adjustMinMaxToEditRange(Control* c, EditId id) + { + const EditRange er = EditRange::get(id); + c->setMin(er.min); + c->setMax(er.max); + c->setDefaultValue(er.def); + } + + void chooseSfzFile(); + void chooseScalaFile(); + + void updateSfzFileLabel(const std::string& filePath); + void updateScalaFileLabel(const std::string& filePath); + static void updateLabelWithFileName(CTextLabel* label, const std::string& filePath); + void updateVolumeLabel(float volume); + void updateNumVoicesLabel(int numVoices); + void updateOversamplingLabel(int oversamplingLog2); + void updatePreloadSizeLabel(int preloadSize); + void updateScalaRootKeyLabel(int rootKey); + void updateTuningFrequencyLabel(float tuningFrequency); + void updateStretchedTuningLabel(float stretchedTuning); + + void setActivePanel(unsigned panelId); + + static void formatLabel(CTextLabel* label, const char* fmt, ...); + static void vformatLabel(CTextLabel* label, const char* fmt, va_list ap); + + // IControlListener + void valueChanged(CControl* ctl) override; + void enterOrLeaveEdit(CControl* ctl, bool enter); + void controlBeginEdit(CControl* ctl) override; + void controlEndEdit(CControl* ctl) override; +}; + +Editor::Editor(EditorController& ctrl) + : impl_(new Impl) +{ + Impl& impl = *impl_; + + impl.ctrl_ = &ctrl; + + ctrl.decorate(&impl); + + impl.createFrameContents(); +} + +Editor::~Editor() +{ + Impl& impl = *impl_; + + EditorController& ctrl = *impl.ctrl_; + ctrl.decorate(nullptr); +} + +void Editor::open(CFrame& frame) +{ + Impl& impl = *impl_; + + impl.frame_ = &frame; + frame.addView(impl.view_.get()); +} + +void Editor::close() +{ + Impl& impl = *impl_; + + if (impl.frame_) { + impl.frame_->removeView(impl.view_.get()); + impl.frame_ = nullptr; + } +} + +void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) +{ + switch (id) { + case EditId::SfzFile: + { + const std::string& value = absl::get(v); + updateSfzFileLabel(value); + } + break; + case EditId::Volume: + { + const float value = absl::get(v); + if (volumeSlider_) + volumeSlider_->setValue(value); + updateVolumeLabel(value); + } + break; + case EditId::Polyphony: + { + const int value = static_cast(absl::get(v)); + if (numVoicesSlider_) + numVoicesSlider_->setValue(value); + updateNumVoicesLabel(value); + } + break; + case EditId::Oversampling: + { + const int value = static_cast(absl::get(v)); + + int log2Value = 0; + for (int f = value; f > 1; f /= 2) + ++log2Value; + + if (oversamplingSlider_) + oversamplingSlider_->setValue(log2Value); + updateOversamplingLabel(log2Value); + } + break; + case EditId::PreloadSize: + { + const int value = static_cast(absl::get(v)); + if (preloadSizeSlider_) + preloadSizeSlider_->setValue(value); + updatePreloadSizeLabel(value); + } + break; + case EditId::ScalaFile: + { + const std::string& value = absl::get(v); + updateScalaFileLabel(value); + } + break; + case EditId::ScalaRootKey: + { + const int value = static_cast(absl::get(v)); + if (scalaRootKeySlider_) + scalaRootKeySlider_->setValue(value); + updateScalaRootKeyLabel(value); + } + break; + case EditId::TuningFrequency: + { + const float value = absl::get(v); + if (tuningFrequencySlider_) + tuningFrequencySlider_->setValue(value); + updateTuningFrequencyLabel(value); + } + break; + case EditId::StretchTuning: + { + const float value = absl::get(v); + if (stretchedTuningSlider_) + stretchedTuningSlider_->setValue(value); + updateStretchedTuningLabel(value); + } + break; + case EditId::UINumCurves: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoCurvesLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UINumMasters: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoMastersLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UINumGroups: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoGroupsLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UINumRegions: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoRegionsLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UINumPreloadedSamples: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoSamplesLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UINumActiveVoices: + { + const int value = static_cast(absl::get(v)); + if (CTextLabel* label = infoVoicesLabel_) + formatLabel(label, "%u", value); + } + break; + case EditId::UIActivePanel: + { + const int value = static_cast(absl::get(v)); + setActivePanel(value); + } + break; + } +} + +void Editor::Impl::createFrameContents() +{ + const CRect bounds { 0.0, 0.0, viewWidth, viewHeight }; + CViewContainer* view = new CViewContainer(bounds); + view_ = view; + + view->setBackgroundColor(CColor(0xff, 0xff, 0xff)); + + SharedPointer logo = new CBitmap("logo.png"); + + CRect bottomRow = bounds; + bottomRow.top = bottomRow.bottom - 30; + + CRect topRow = bounds; + topRow.bottom = topRow.top + 30; + + CViewContainer* panel; + activePanel_ = 0; + + CRect topLeftLabelBox = topRow; + topLeftLabelBox.right -= 20 * kNumPanels; + + // general panel + { + panel = new CViewContainer(bounds); + view->addView(panel); + panel->setTransparency(true); + + CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, logo); + panel->addView(sfizzButton); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "No file loaded"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + sfzFileLabel_ = topLeftLabel; + + subPanels_[kPanelGeneral] = panel; + } + + // settings panel + { + panel = new CViewContainer(bounds); + view->addView(panel); + panel->setTransparency(true); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Settings"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + + CRect row = topRow; + row.top += 45.0; + row.bottom += 45.0; + row.left += 20.0; + row.right -= 20.0; + + static const CCoord interRow = 35.0; + static const CCoord interColumn = 20.0; + static const int numColumns = 3; + + auto nthColumn = [&row](int colIndex) -> CRect { + CRect div = row; + CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; + div.left = div.left + colIndex * (columnWidth + interColumn); + div.right = div.left + columnWidth; + return div; + }; + + CTextLabel* label; + SimpleSlider* slider; + + label = new CTextLabel(nthColumn(0), "Volume"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetVolume); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::Volume); + volumeSlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + volumeLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Polyphony"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetNumVoices); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::Polyphony); + numVoicesSlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + numVoicesLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Oversampling"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetOversampling); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::Oversampling); + oversamplingSlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + oversamplingLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Preload size"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetPreloadSize); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::PreloadSize); + preloadSizeSlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + preloadSizeLabel_ = label; + panel->addView(label); + + subPanels_[kPanelSettings] = panel; + } + + // tuning panel + { + panel = new CViewContainer(bounds); + view->addView(panel); + panel->setTransparency(true); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Tuning"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + + CRect row = topRow; + row.top += 45.0; + row.bottom += 45.0; + row.left += 20.0; + row.right -= 20.0; + + static const CCoord interRow = 35.0; + static const CCoord interColumn = 20.0; + static const int numColumns = 3; + + auto nthColumn = [&row](int colIndex) -> CRect { + CRect div = row; + CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; + div.left = div.left + colIndex * (columnWidth + interColumn); + div.right = div.left + columnWidth; + return div; + }; + + CTextLabel* label; + SimpleSlider* slider; + CTextButton* textbutton; + + label = new CTextLabel(nthColumn(0), "Scala file"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + textbutton = new CTextButton(nthColumn(1), this, kTagLoadScalaFile, "Choose"); + panel->addView(textbutton); + label = new CTextLabel(nthColumn(2), ""); + scalaFileLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Scala root key"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetScalaRootKey); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::ScalaRootKey); + scalaRootKeySlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + scalaRootKeyLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Tuning frequency"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetTuningFrequency); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::TuningFrequency); + tuningFrequencySlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + tuningFrequencyLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Stretched tuning"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + slider = new SimpleSlider(nthColumn(1), this, kTagSetStretchedTuning); + panel->addView(slider); + adjustMinMaxToEditRange(slider, EditId::StretchTuning); + stretchedTuningSlider_ = slider; + label = new CTextLabel(nthColumn(2), ""); + stretchedTuningLabel_ = label; + panel->addView(label); + + subPanels_[kPanelTuning] = panel; + } + + // info panel + { + panel = new CViewContainer(bounds); + view->addView(panel); + panel->setTransparency(true); + + CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Information"); + topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(topLeftLabel); + + CRect row = topRow; + row.top += 45.0; + row.bottom += 45.0; + row.left += 20.0; + row.right -= 20.0; + + static const CCoord interRow = 20.0; + static const CCoord interColumn = 20.0; + static const int numColumns = 3; + + auto nthColumn = [&row](int colIndex) -> CRect { + CRect div = row; + CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; + div.left = div.left + colIndex * (columnWidth + interColumn); + div.right = div.left + columnWidth; + return div; + }; + + CTextLabel* label; + + label = new CTextLabel(nthColumn(0), "Curves"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoCurvesLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Masters"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoMastersLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Groups"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoGroupsLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Regions"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoRegionsLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Samples"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoSamplesLabel_ = label; + panel->addView(label); + + row.top += interRow; + row.bottom += interRow; + + label = new CTextLabel(nthColumn(0), "Voices"); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + panel->addView(label); + label = new CTextLabel(nthColumn(1), ""); + label->setFontColor(CColor(0x00, 0x00, 0x00)); + label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + label->setHoriAlign(kLeftText); + infoVoicesLabel_ = label; + panel->addView(label); + + subPanels_[kPanelInfo] = panel; + } + + // all panels + for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) { + panel = subPanels_[currentPanel]; + + CTextLabel* descLabel = new CTextLabel( + bottomRow, "Paul Ferrand and the SFZ Tools work group"); + descLabel->setFontColor(CColor(0x00, 0x00, 0x00)); + descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); + panel->addView(descLabel); + + for (unsigned i = 0; i < kNumPanels; ++i) { + CRect btnRect = topRow; + btnRect.left = topRow.right - (kNumPanels - i) * 50; + btnRect.right = btnRect.left + 50; + + const char *text; + switch (i) { + case kPanelGeneral: text = "File"; break; + case kPanelSettings: text = "Setup"; break; + case kPanelTuning: text = "Tuning"; break; + case kPanelInfo: text = "Info"; break; + default: text = "?"; break; + } + + CTextButton* changePanelButton = new CTextButton(btnRect, this, kTagFirstChangePanel + i, text); + panel->addView(changePanelButton); + + changePanelButton->setRoundRadius(0.0); + } + + panel->setVisible(currentPanel == activePanel_); + } +} + +void Editor::Impl::chooseSfzFile() +{ + SharedPointer fs(CNewFileSelector::create(frame_)); + + fs->setTitle("Load SFZ file"); + fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + + if (fs->runModal()) { + UTF8StringPtr file = fs->getSelectedFile(0); + if (file) { + std::string str(file); + ctrl_->uiSendValue(EditId::SfzFile, str); + updateSfzFileLabel(str); + } + } +} + +void Editor::Impl::chooseScalaFile() +{ + SharedPointer fs(CNewFileSelector::create(frame_)); + + fs->setTitle("Load Scala file"); + fs->setDefaultExtension(CFileExtension("SCL", "scl")); + + if (fs->runModal()) { + UTF8StringPtr file = fs->getSelectedFile(0); + if (file) { + std::string str(file); + ctrl_->uiSendValue(EditId::ScalaFile, str); + updateScalaFileLabel(str); + } + } +} + +void Editor::Impl::updateSfzFileLabel(const std::string& filePath) +{ + updateLabelWithFileName(sfzFileLabel_, filePath); +} + +void Editor::Impl::updateScalaFileLabel(const std::string& filePath) +{ + updateLabelWithFileName(scalaFileLabel_, filePath); +} + +void Editor::Impl::updateLabelWithFileName(CTextLabel* label, const std::string& filePath) +{ + if (!label) + return; + + std::string fileName; + if (filePath.empty()) + fileName = ""; + else { +#if defined (_WIN32) + size_t pos = filePath.find_last_of("/\\"); +#else + size_t pos = filePath.rfind('/'); +#endif + fileName = (pos != filePath.npos) ? + filePath.substr(pos + 1) : filePath; + } + label->setText(fileName.c_str()); +} + +void Editor::Impl::updateVolumeLabel(float volume) +{ + CTextLabel* label = volumeLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f dB", volume); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::updateNumVoicesLabel(int numVoices) +{ + CTextLabel* label = numVoicesLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%d", numVoices); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::updateOversamplingLabel(int oversamplingLog2) +{ + CTextLabel* label = oversamplingLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%dx", 1 << oversamplingLog2); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::updatePreloadSizeLabel(int preloadSize) +{ + CTextLabel* label = preloadSizeLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f kB", preloadSize * (1.0 / 1024)); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::updateScalaRootKeyLabel(int rootKey) +{ + CTextLabel* label = scalaRootKeyLabel_; + if (!label) + return; + + static const char *octNoteNames[12] = { + "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", + }; + + auto noteName = [](int key) -> std::string + { + int octNum; + int octNoteNum; + if (key >= 0) { + octNum = key / 12 - 1; + octNoteNum = key % 12; + } + else { + octNum = -2 - (key + 1) / -12; + octNoteNum = (key % 12 + 12) % 12; + } + return std::string(octNoteNames[octNoteNum]) + std::to_string(octNum); + }; + + label->setText(noteName(rootKey)); +} + +void Editor::Impl::updateTuningFrequencyLabel(float tuningFrequency) +{ + CTextLabel* label = tuningFrequencyLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%.1f", tuningFrequency); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::updateStretchedTuningLabel(float stretchedTuning) +{ + CTextLabel* label = stretchedTuningLabel_; + if (!label) + return; + + char text[64]; + sprintf(text, "%.3f", stretchedTuning); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::setActivePanel(unsigned panelId) +{ + panelId = std::max(0, std::min(kNumPanels - 1, static_cast(panelId))); + + if (activePanel_ != panelId) { + subPanels_[activePanel_]->setVisible(false); + activePanel_ = panelId; + subPanels_[panelId]->setVisible(true); + } +} + +void Editor::Impl::formatLabel(CTextLabel* label, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vformatLabel(label, fmt, ap); + va_end(ap); +} + +void Editor::Impl::vformatLabel(CTextLabel* label, const char* fmt, va_list ap) +{ + char text[256]; + vsprintf(text, fmt, ap); + text[sizeof(text) - 1] = '\0'; + label->setText(text); +} + +void Editor::Impl::valueChanged(CControl* ctl) +{ + int32_t tag = ctl->getTag(); + float value = ctl->getValue(); + EditorController& ctrl = *ctrl_; + + switch (tag) { + case kTagLoadSfzFile: + if (value != 1) + break; + + Call::later([this]() { chooseSfzFile(); }); + break; + + case kTagLoadScalaFile: + if (value != 1) + break; + + Call::later([this]() { chooseScalaFile(); }); + break; + + case kTagSetVolume: + ctrl.uiSendValue(EditId::Volume, value); + updateVolumeLabel(value); + break; + + case kTagSetNumVoices: + ctrl.uiSendValue(EditId::Polyphony, value); + updateNumVoicesLabel(static_cast(value)); + break; + + case kTagSetOversampling: + ctrl.uiSendValue(EditId::Oversampling, 1 << static_cast(value)); + updateOversamplingLabel(static_cast(value)); + break; + + case kTagSetPreloadSize: + ctrl.uiSendValue(EditId::PreloadSize, value); + updatePreloadSizeLabel(static_cast(value)); + break; + + case kTagSetScalaRootKey: + ctrl.uiSendValue(EditId::ScalaRootKey, value); + updateScalaRootKeyLabel(static_cast(value)); + break; + + case kTagSetTuningFrequency: + ctrl.uiSendValue(EditId::TuningFrequency, value); + updateTuningFrequencyLabel(value); + break; + + case kTagSetStretchedTuning: + ctrl.uiSendValue(EditId::StretchTuning, value); + updateStretchedTuningLabel(value); + break; + + default: + if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) { + int panelId = tag - kTagFirstChangePanel; + ctrl.uiSendValue(EditId::UIActivePanel, panelId); + setActivePanel(panelId); + } + break; + } +} + +void Editor::Impl::enterOrLeaveEdit(CControl* ctl, bool enter) +{ + int32_t tag = ctl->getTag(); + EditId id; + + switch (tag) { + case kTagSetVolume: id = EditId::Volume; break; + case kTagSetNumVoices: id = EditId::Polyphony; break; + case kTagSetOversampling: id = EditId::Oversampling; break; + case kTagSetPreloadSize: id = EditId::PreloadSize; break; + case kTagSetScalaRootKey: id = EditId::ScalaRootKey; break; + case kTagSetTuningFrequency: id = EditId::TuningFrequency; break; + case kTagSetStretchedTuning: id = EditId::StretchTuning; break; + default: return; + } + + EditorController& ctrl = *ctrl_; + if (enter) + ctrl.uiBeginSend(id); + else + ctrl.uiEndSend(id); +} + +void Editor::Impl::controlBeginEdit(CControl* ctl) +{ + enterOrLeaveEdit(ctl, true); +} + +void Editor::Impl::controlEndEdit(CControl* ctl) +{ + enterOrLeaveEdit(ctl, false); +} diff --git a/editor/src/editor/Editor.h b/editor/src/editor/Editor.h new file mode 100644 index 00000000..0c0ae1de --- /dev/null +++ b/editor/src/editor/Editor.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +class EditorController; + +#include "utility/vstgui_before.h" +#include "vstgui/lib/vstguifwd.h" +#include "utility/vstgui_after.h" +using VSTGUI::CFrame; + +class Editor { +public: + static const int viewWidth; + static const int viewHeight; + + explicit Editor(EditorController& ctrl); + ~Editor(); + + void open(CFrame& frame); + void close(); + +private: + struct Impl; + std::unique_ptr impl_; +}; diff --git a/editor/src/editor/EditorController.h b/editor/src/editor/EditorController.h new file mode 100644 index 00000000..6b6988c1 --- /dev/null +++ b/editor/src/editor/EditorController.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include +enum class EditId : int; +typedef absl::variant EditValue; + +class EditorController { +public: + virtual ~EditorController() {} + + // called by Editor + virtual void uiSendValue(EditId id, const EditValue& v) = 0; + virtual void uiBeginSend(EditId id) = 0; + virtual void uiEndSend(EditId id) = 0; + virtual void uiSendMIDI(const uint8_t* msg, uint32_t len) = 0; + class Receiver; + void decorate(Receiver* r) { r_ = r; } + + class Receiver { + public: + virtual ~Receiver() {} + virtual void uiReceiveValue(EditId id, const EditValue& v) = 0; + }; + + // called by DSP + void uiReceiveValue(EditId id, const EditValue& v); + +private: + Receiver* r_ = nullptr; +}; + +inline void EditorController::uiReceiveValue(EditId id, const EditValue& v) +{ + if (r_) + r_->uiReceiveValue(id, v); +} diff --git a/vst/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp similarity index 93% rename from vst/GUIComponents.cpp rename to editor/src/editor/GUIComponents.cpp index 314ba642..56fb6f8e 100644 --- a/vst/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -5,7 +5,10 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "GUIComponents.h" + +#include "utility/vstgui_before.h" #include "vstgui/lib/cdrawcontext.h" +#include "utility/vstgui_after.h" SimpleSlider::SimpleSlider(const CRect& bounds, IControlListener* listener, int32_t tag) : CSliderBase(bounds, listener, tag) diff --git a/vst/GUIComponents.h b/editor/src/editor/GUIComponents.h similarity index 91% rename from vst/GUIComponents.h rename to editor/src/editor/GUIComponents.h index 003d219b..c76c2e44 100644 --- a/vst/GUIComponents.h +++ b/editor/src/editor/GUIComponents.h @@ -5,8 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once + +#include "utility/vstgui_before.h" #include "vstgui/lib/controls/cslider.h" #include "vstgui/lib/ccolor.h" +#include "utility/vstgui_after.h" using namespace VSTGUI; diff --git a/editor/src/editor/utility/vstgui_after.h b/editor/src/editor/utility/vstgui_after.h new file mode 100644 index 00000000..69e3b4db --- /dev/null +++ b/editor/src/editor/utility/vstgui_after.h @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif diff --git a/editor/src/editor/utility/vstgui_before.h b/editor/src/editor/utility/vstgui_before.h new file mode 100644 index 00000000..bb01d0c3 --- /dev/null +++ b/editor/src/editor/utility/vstgui_before.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#pragma GCC diagnostic ignored "-Wdeprecated-copy" +#endif diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index 73de6ee5..4104eb25 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -45,7 +45,7 @@ file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}) configure_file (manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl) configure_file (${PROJECT_NAME}.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ttl) configure_file (LICENSE.md.in ${PROJECT_BINARY_DIR}/LICENSE.md) -if (SFIZZ_USE_VCPKG OR SFIZZ_STATIC_LIBSNDFILE OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") +if (SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR}) endif() diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 0c14922d..5d0301e6 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -17,7 +17,6 @@ set(VSTPLUGIN_SOURCES SfizzVstController.cpp SfizzVstEditor.cpp SfizzVstState.cpp - GUIComponents.cpp VstPluginFactory.cpp X11RunLoop.cpp) @@ -26,7 +25,6 @@ set(VSTPLUGIN_HEADERS SfizzVstController.h SfizzVstEditor.h SfizzVstState.h - GUIComponents.h X11RunLoop.h) set(VSTPLUGIN_RESOURCES @@ -40,7 +38,8 @@ if(WIN32) target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE vst3.def) endif() target_link_libraries(${VSTPLUGIN_PRJ_NAME} - PRIVATE ${PROJECT_NAME}::${PROJECT_NAME}) + PRIVATE ${PROJECT_NAME}::${PROJECT_NAME} + PRIVATE sfizz_editor) target_include_directories(${VSTPLUGIN_PRJ_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES diff --git a/vst/SfizzVstController.cpp b/vst/SfizzVstController.cpp index 8f13bab2..35eba7a0 100644 --- a/vst/SfizzVstController.cpp +++ b/vst/SfizzVstController.cpp @@ -35,15 +35,15 @@ tresult PLUGIN_API SfizzVstControllerNoUi::initialize(FUnknown* context) Steinberg::String("Preload size"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamScalaRootKey.createParameter( + kParamScalaRootKeyRange.createParameter( Steinberg::String("Scala root key"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamTuningFrequency.createParameter( + kParamTuningFrequencyRange.createParameter( Steinberg::String("Tuning frequency"), pid++, Steinberg::String("Hz"), 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); parameters.addParameter( - kParamStretchedTuning.createParameter( + kParamStretchedTuningRange.createParameter( Steinberg::String("Stretched tuning"), pid++, nullptr, 0, Vst::ParameterInfo::kCanAutomate, Vst::kRootUnitId)); @@ -175,17 +175,17 @@ tresult PLUGIN_API SfizzVstController::setParamNormalized(Vst::ParamID tag, Vst: } case kPidScalaRootKey: { slotI32 = &_state.scalaRootKey; - value = kParamScalaRootKey.denormalize(normValue); + value = kParamScalaRootKeyRange.denormalize(normValue); break; } case kPidTuningFrequency: { slotF32 = &_state.tuningFrequency; - value = kParamTuningFrequency.denormalize(normValue); + value = kParamTuningFrequencyRange.denormalize(normValue); break; } case kPidStretchedTuning: { slotF32 = &_state.stretchedTuning; - value = kParamStretchedTuning.denormalize(normValue); + value = kParamStretchedTuningRange.denormalize(normValue); break; } } @@ -244,9 +244,9 @@ tresult PLUGIN_API SfizzVstController::setComponentState(IBStream* state) setParamNormalized(kPidNumVoices, kParamNumVoicesRange.normalize(s.numVoices)); setParamNormalized(kPidOversampling, kParamOversamplingRange.normalize(s.oversamplingLog2)); setParamNormalized(kPidPreloadSize, kParamPreloadSizeRange.normalize(s.preloadSize)); - setParamNormalized(kPidScalaRootKey, kParamScalaRootKey.normalize(s.scalaRootKey)); - setParamNormalized(kPidTuningFrequency, kParamTuningFrequency.normalize(s.tuningFrequency)); - setParamNormalized(kPidStretchedTuning, kParamStretchedTuning.normalize(s.stretchedTuning)); + setParamNormalized(kPidScalaRootKey, kParamScalaRootKeyRange.normalize(s.scalaRootKey)); + setParamNormalized(kPidTuningFrequency, kParamTuningFrequencyRange.normalize(s.tuningFrequency)); + setParamNormalized(kPidStretchedTuning, kParamStretchedTuningRange.normalize(s.stretchedTuning)); for (StateListener* listener : _stateListeners) listener->onStateChanged(); diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 5863cdc5..163034cc 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -6,18 +6,18 @@ #include "SfizzVstEditor.h" #include "SfizzVstState.h" -#include "GUIComponents.h" +#include "editor/Editor.h" +#include "editor/EditIds.h" #if !defined(__APPLE__) && !defined(_WIN32) #include "X11RunLoop.h" #endif using namespace VSTGUI; -static ViewRect sfizzUiViewRect {0, 0, 482, 225}; +static ViewRect sfizzUiViewRect { 0, 0, Editor::viewWidth, Editor::viewHeight }; SfizzVstEditor::SfizzVstEditor(void *controller) - : VSTGUIEditor(controller, &sfizzUiViewRect), - _logo("logo.png") + : VSTGUIEditor(controller, &sfizzUiViewRect) { getController()->addSfizzStateListener(this); } @@ -45,7 +45,11 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p config = &x11config; #endif - createFrameContents(); + Editor* editor = editor_.get(); + if (!editor) { + editor = new Editor(*this); + editor_.reset(editor); + } updateStateDisplay(); if (!frame->open(parent, platformType, config)) { @@ -53,6 +57,8 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p return false; } + editor->open(*frame); + return true; } @@ -60,121 +66,16 @@ void PLUGIN_API SfizzVstEditor::close() { CFrame *frame = this->frame; if (frame) { - frame->removeAll(); + if (editor_) + editor_->close(); if (frame->getNbReference() != 1) - frame->forget (); - else { + frame->forget(); + else frame->close(); - this->frame = nullptr; - } } } /// -void SfizzVstEditor::valueChanged(CControl* ctl) -{ - int32_t tag = ctl->getTag(); - float value = ctl->getValue(); - float valueNorm = ctl->getValueNormalized(); - SfizzVstController* controller = getController(); - - switch (tag) { - case kTagLoadSfzFile: - if (value != 1) - break; - - Call::later([this]() { chooseSfzFile(); }); - break; - - case kTagLoadScalaFile: - if (value != 1) - break; - - Call::later([this]() { chooseScalaFile(); }); - break; - - case kTagSetVolume: - controller->setParamNormalized(kPidVolume, valueNorm); - controller->performEdit(kPidVolume, valueNorm); - updateVolumeLabel(value); - break; - - case kTagSetNumVoices: - controller->setParamNormalized(kPidNumVoices, valueNorm); - controller->performEdit(kPidNumVoices, valueNorm); - updateNumVoicesLabel(static_cast(value)); - break; - - case kTagSetOversampling: - controller->setParamNormalized(kPidOversampling, valueNorm); - controller->performEdit(kPidOversampling, valueNorm); - updateOversamplingLabel(static_cast(value)); - break; - - case kTagSetPreloadSize: - controller->setParamNormalized(kPidPreloadSize, valueNorm); - controller->performEdit(kPidPreloadSize, valueNorm); - updatePreloadSizeLabel(static_cast(value)); - break; - - case kTagSetScalaRootKey: - controller->setParamNormalized(kPidScalaRootKey, valueNorm); - controller->performEdit(kPidScalaRootKey, valueNorm); - updateScalaRootKeyLabel(static_cast(value)); - break; - - case kTagSetTuningFrequency: - controller->setParamNormalized(kPidTuningFrequency, valueNorm); - controller->performEdit(kPidTuningFrequency, valueNorm); - updateTuningFrequencyLabel(value); - break; - - case kTagSetStretchedTuning: - controller->setParamNormalized(kPidStretchedTuning, valueNorm); - controller->performEdit(kPidStretchedTuning, valueNorm); - updateStretchedTuningLabel(value); - break; - - default: - if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) - setActivePanel(tag - kTagFirstChangePanel); - break; - } -} - -void SfizzVstEditor::enterOrLeaveEdit(CControl* ctl, bool enter) -{ - int32_t tag = ctl->getTag(); - Vst::ParamID id; - - switch (tag) { - case kTagSetVolume: id = kPidVolume; break; - case kTagSetNumVoices: id = kPidNumVoices; break; - case kTagSetOversampling: id = kPidOversampling; break; - case kTagSetPreloadSize: id = kPidPreloadSize; break; - case kTagSetScalaRootKey: id = kPidScalaRootKey; break; - case kTagSetTuningFrequency: id = kPidTuningFrequency; break; - case kTagSetStretchedTuning: id = kPidStretchedTuning; break; - default: return; - } - - SfizzVstController* controller = getController(); - if (enter) - controller->beginEdit(id); - else - controller->endEdit(id); -} - -void SfizzVstEditor::controlBeginEdit(CControl* ctl) -{ - enterOrLeaveEdit(ctl, true); -} - -void SfizzVstEditor::controlEndEdit(CControl* ctl) -{ - enterOrLeaveEdit(ctl, false); -} - CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message) { CMessageResult result = VSTGUIEditor::notify(sender, message); @@ -205,20 +106,83 @@ void SfizzVstEditor::onStateChanged() } /// -void SfizzVstEditor::chooseSfzFile() +void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) { - SharedPointer fs(CNewFileSelector::create(frame)); + if (id == EditId::SfzFile) + loadSfzFile(absl::get(v)); + else if (id == EditId::ScalaFile) + loadScalaFile(absl::get(v)); + else { + SfizzVstController* ctrl = getController(); - fs->setTitle("Load SFZ file"); - fs->setDefaultExtension(CFileExtension("SFZ", "sfz")); + auto normalizeAndSet = [ctrl](Vst::ParamID pid, const SfizzParameterRange& range, float value) { + float normValue = range.normalize(value); + ctrl->setParamNormalized(pid, normValue); + ctrl->performEdit(pid, normValue); + }; - if (fs->runModal()) { - UTF8StringPtr file = fs->getSelectedFile(0); - if (file) - loadSfzFile(file); + switch (id) { + case EditId::Volume: + normalizeAndSet(kPidVolume, kParamVolumeRange, absl::get(v)); + break; + case EditId::Polyphony: + normalizeAndSet(kPidNumVoices, kParamNumVoicesRange, absl::get(v)); + break; + case EditId::Oversampling: + { + const int32 value = static_cast(absl::get(v)); + + int32 log2Value = 0; + for (int32 f = value; f > 1; f /= 2) + ++log2Value; + + normalizeAndSet(kPidOversampling, kParamOversamplingRange, log2Value); + } + break; + case EditId::PreloadSize: + normalizeAndSet(kPidPreloadSize, kParamPreloadSizeRange, absl::get(v)); + break; + case EditId::ScalaRootKey: + normalizeAndSet(kPidScalaRootKey, kParamScalaRootKeyRange, absl::get(v)); + break; + case EditId::TuningFrequency: + normalizeAndSet(kPidTuningFrequency, kParamTuningFrequencyRange, absl::get(v)); + break; + case EditId::StretchTuning: + normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, absl::get(v)); + break; + + case EditId::UIActivePanel: + ctrl->getSfizzUiState().activePanel = static_cast(absl::get(v)); + break; + + default: + break; + } } } +void SfizzVstEditor::uiBeginSend(EditId id) +{ + Vst::ParamID pid = parameterOfEditId(id); + if (pid != -1) + getController()->beginEdit(pid); +} + +void SfizzVstEditor::uiEndSend(EditId id) +{ + Vst::ParamID pid = parameterOfEditId(id); + if (pid != -1) + getController()->endEdit(pid); +} + +void SfizzVstEditor::uiSendMIDI(const uint8_t* msg, uint32_t len) +{ + // TODO send MIDI... + +} + +/// void SfizzVstEditor::loadSfzFile(const std::string& filePath) { SfizzVstController* ctl = getController(); @@ -233,22 +197,6 @@ void SfizzVstEditor::loadSfzFile(const std::string& filePath) Vst::IAttributeList* attr = msg->getAttributes(); attr->setBinary("File", filePath.data(), filePath.size()); ctl->sendMessage(msg); - - updateSfzFileLabel(filePath); -} - -void SfizzVstEditor::chooseScalaFile() -{ - SharedPointer fs(CNewFileSelector::create(frame)); - - fs->setTitle("Load Scala file"); - fs->setDefaultExtension(CFileExtension("SCL", "scl")); - - if (fs->runModal()) { - UTF8StringPtr file = fs->getSelectedFile(0); - if (file) - loadScalaFile(file); - } } void SfizzVstEditor::loadScalaFile(const std::string& filePath) @@ -265,414 +213,6 @@ void SfizzVstEditor::loadScalaFile(const std::string& filePath) Vst::IAttributeList* attr = msg->getAttributes(); attr->setBinary("File", filePath.data(), filePath.size()); ctl->sendMessage(msg); - - updateScalaFileLabel(filePath); -} - -void SfizzVstEditor::createFrameContents() -{ - SfizzVstController* controller = getController(); - const SfizzUiState& uiState = controller->getSfizzUiState(); - - CFrame* frame = this->frame; - CRect bounds = frame->getViewSize(); - - frame->setBackgroundColor(CColor(0xff, 0xff, 0xff)); - - CRect bottomRow = bounds; - bottomRow.top = bottomRow.bottom - 30; - - CRect topRow = bounds; - topRow.bottom = topRow.top + 30; - - CViewContainer* panel; - _activePanel = std::max(0, std::min(kNumPanels - 1, static_cast(uiState.activePanel))); - - CRect topLeftLabelBox = topRow; - topLeftLabelBox.right -= 20 * kNumPanels; - - // general panel - { - panel = new CViewContainer(bounds); - frame->addView(panel); - panel->setTransparency(true); - - CKickButton* sfizzButton = new CKickButton(bounds, this, kTagLoadSfzFile, &_logo); - panel->addView(sfizzButton); - - CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "No file loaded"); - topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - panel->addView(topLeftLabel); - _sfzFileLabel = topLeftLabel; - - _subPanels[kPanelGeneral] = panel; - } - - // settings panel - { - panel = new CViewContainer(bounds); - frame->addView(panel); - panel->setTransparency(true); - - CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Settings"); - topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - panel->addView(topLeftLabel); - - CRect row = topRow; - row.top += 45.0; - row.bottom += 45.0; - row.left += 20.0; - row.right -= 20.0; - - static const CCoord interRow = 35.0; - static const CCoord interColumn = 20.0; - static const int numColumns = 3; - - auto nthColumn = [&row](int colIndex) -> CRect { - CRect div = row; - CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; - div.left = div.left + colIndex * (columnWidth + interColumn); - div.right = div.left + columnWidth; - return div; - }; - - CTextLabel* label; - SimpleSlider* slider; - - label = new CTextLabel(nthColumn(0), "Volume"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetVolume); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidVolume); - _volumeSlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _volumeLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Polyphony"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetNumVoices); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidNumVoices); - _numVoicesSlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _numVoicesLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Oversampling"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetOversampling); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidOversampling); - _oversamplingSlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _oversamplingLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Preload size"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetPreloadSize); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidPreloadSize); - _preloadSizeSlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _preloadSizeLabel = label; - panel->addView(label); - - _subPanels[kPanelSettings] = panel; - } - - // tuning panel - { - panel = new CViewContainer(bounds); - frame->addView(panel); - panel->setTransparency(true); - - CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Tuning"); - topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - panel->addView(topLeftLabel); - - CRect row = topRow; - row.top += 45.0; - row.bottom += 45.0; - row.left += 20.0; - row.right -= 20.0; - - static const CCoord interRow = 35.0; - static const CCoord interColumn = 20.0; - static const int numColumns = 3; - - auto nthColumn = [&row](int colIndex) -> CRect { - CRect div = row; - CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; - div.left = div.left + colIndex * (columnWidth + interColumn); - div.right = div.left + columnWidth; - return div; - }; - - CTextLabel* label; - SimpleSlider* slider; - CTextButton* textbutton; - - label = new CTextLabel(nthColumn(0), "Scala file"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - textbutton = new CTextButton(nthColumn(1), this, kTagLoadScalaFile, "Choose"); - panel->addView(textbutton); - label = new CTextLabel(nthColumn(2), ""); - _scalaFileLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Scala root key"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetScalaRootKey); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidScalaRootKey); - _scalaRootKeySlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _scalaRootKeyLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Tuning frequency"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetTuningFrequency); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidTuningFrequency); - _tuningFrequencySlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _tuningFrequencyLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Stretched tuning"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - slider = new SimpleSlider(nthColumn(1), this, kTagSetStretchedTuning); - panel->addView(slider); - adjustMinMaxToRangeParam(slider, kPidStretchedTuning); - _stretchedTuningSlider = slider; - label = new CTextLabel(nthColumn(2), ""); - _stretchedTuningLabel = label; - panel->addView(label); - - _subPanels[kPanelTuning] = panel; - } - - // info panel - { - panel = new CViewContainer(bounds); - frame->addView(panel); - panel->setTransparency(true); - - CTextLabel* topLeftLabel = new CTextLabel(topLeftLabelBox, "Information"); - topLeftLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - topLeftLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - panel->addView(topLeftLabel); - - CRect row = topRow; - row.top += 45.0; - row.bottom += 45.0; - row.left += 20.0; - row.right -= 20.0; - - static const CCoord interRow = 20.0; - static const CCoord interColumn = 20.0; - static const int numColumns = 3; - - auto nthColumn = [&row](int colIndex) -> CRect { - CRect div = row; - CCoord columnWidth = (div.right - div.left + interColumn) / numColumns - interColumn; - div.left = div.left + colIndex * (columnWidth + interColumn); - div.right = div.left + columnWidth; - return div; - }; - - CTextLabel* label; - - label = new CTextLabel(nthColumn(0), "Curves"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoCurvesLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Masters"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoMastersLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Groups"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoGroupsLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Regions"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoRegionsLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Samples"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoSamplesLabel = label; - panel->addView(label); - - row.top += interRow; - row.bottom += interRow; - - label = new CTextLabel(nthColumn(0), "Voices"); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - panel->addView(label); - label = new CTextLabel(nthColumn(1), ""); - label->setFontColor(CColor(0x00, 0x00, 0x00)); - label->setFrameColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - label->setHoriAlign(kLeftText); - _infoVoicesLabel = label; - panel->addView(label); - - _subPanels[kPanelInfo] = panel; - } - - // all panels - for (unsigned currentPanel = 0; currentPanel < kNumPanels; ++currentPanel) { - panel = _subPanels[currentPanel]; - - CTextLabel* descLabel = new CTextLabel( - bottomRow, "Paul Ferrand and the SFZ Tools work group"); - descLabel->setFontColor(CColor(0x00, 0x00, 0x00)); - descLabel->setBackColor(CColor(0x00, 0x00, 0x00, 0x00)); - panel->addView(descLabel); - - for (unsigned i = 0; i < kNumPanels; ++i) { - CRect btnRect = topRow; - btnRect.left = topRow.right - (kNumPanels - i) * 50; - btnRect.right = btnRect.left + 50; - - const char *text; - switch (i) { - case kPanelGeneral: text = "File"; break; - case kPanelSettings: text = "Setup"; break; - case kPanelTuning: text = "Tuning"; break; - case kPanelInfo: text = "Info"; break; - default: text = "?"; break; - } - - CTextButton* changePanelButton = new CTextButton(btnRect, this, kTagFirstChangePanel + i, text); - panel->addView(changePanelButton); - - changePanelButton->setRoundRadius(0.0); - } - - panel->setVisible(currentPanel == _activePanel); - } } void SfizzVstEditor::updateStateDisplay() @@ -686,196 +226,38 @@ void SfizzVstEditor::updateStateDisplay() const SfizzPlayState& playState = controller->getSfizzPlayState(); /// - updateSfzFileLabel(state.sfzFile); - if (_volumeSlider) - _volumeSlider->setValue(state.volume); - updateVolumeLabel(state.volume); - if (_numVoicesSlider) - _numVoicesSlider->setValue(state.numVoices); - updateNumVoicesLabel(state.numVoices); - if (_oversamplingSlider) - _oversamplingSlider->setValue(state.oversamplingLog2); - updateOversamplingLabel(state.oversamplingLog2); - if (_preloadSizeSlider) - _preloadSizeSlider->setValue(state.preloadSize); - updatePreloadSizeLabel(state.preloadSize); - updateScalaFileLabel(state.scalaFile); - if (_scalaRootKeySlider) - _scalaRootKeySlider->setValue(state.scalaRootKey); - updateScalaRootKeyLabel(state.scalaRootKey); - if (_tuningFrequencySlider) - _tuningFrequencySlider->setValue(state.tuningFrequency); - updateTuningFrequencyLabel(state.tuningFrequency); - if (_stretchedTuningSlider) - _stretchedTuningSlider->setValue(state.stretchedTuning); - updateStretchedTuningLabel(state.stretchedTuning); + uiReceiveValue(EditId::SfzFile, state.sfzFile); + uiReceiveValue(EditId::Volume, state.volume); + uiReceiveValue(EditId::Polyphony, state.numVoices); + uiReceiveValue(EditId::Oversampling, 1u << state.oversamplingLog2); + uiReceiveValue(EditId::PreloadSize, state.preloadSize); + uiReceiveValue(EditId::ScalaFile, state.scalaFile); + uiReceiveValue(EditId::ScalaRootKey, state.scalaRootKey); + uiReceiveValue(EditId::TuningFrequency, state.tuningFrequency); + uiReceiveValue(EditId::StretchTuning, state.stretchedTuning); /// - struct InfoLabel { const uint32* src; CTextLabel* dst; }; - for (const auto& item : { - InfoLabel{&playState.curves, _infoCurvesLabel}, - InfoLabel{&playState.masters, _infoMastersLabel}, - InfoLabel{&playState.groups, _infoGroupsLabel}, - InfoLabel{&playState.regions, _infoRegionsLabel}, - InfoLabel{&playState.preloadedSamples, _infoSamplesLabel}, - InfoLabel{&playState.activeVoices, _infoVoicesLabel} }) - { - if (item.dst) { - char text[64]; - sprintf(text, "%u", *item.src); - text[sizeof(text) - 1] = '\0'; - item.dst->setText(text); - } - } + uiReceiveValue(EditId::UINumCurves, playState.curves); + uiReceiveValue(EditId::UINumMasters, playState.masters); + uiReceiveValue(EditId::UINumGroups, playState.groups); + uiReceiveValue(EditId::UINumRegions, playState.regions); + uiReceiveValue(EditId::UINumPreloadedSamples, playState.preloadedSamples); + uiReceiveValue(EditId::UINumActiveVoices, playState.activeVoices); /// - setActivePanel(uiState.activePanel); + uiReceiveValue(EditId::UIActivePanel, uiState.activePanel); } -void SfizzVstEditor::updateSfzFileLabel(const std::string& filePath) +Vst::ParamID SfizzVstEditor::parameterOfEditId(EditId id) { - updateLabelWithFileName(_sfzFileLabel, filePath); -} - -void SfizzVstEditor::updateScalaFileLabel(const std::string& filePath) -{ - updateLabelWithFileName(_scalaFileLabel, filePath); -} - -void SfizzVstEditor::updateLabelWithFileName(CTextLabel* label, const std::string& filePath) -{ - if (!label) - return; - - std::string fileName; - if (filePath.empty()) - fileName = ""; - else { -#if defined (_WIN32) - size_t pos = filePath.find_last_of("/\\"); -#else - size_t pos = filePath.rfind('/'); -#endif - fileName = (pos != filePath.npos) ? - filePath.substr(pos + 1) : filePath; - } - label->setText(fileName.c_str()); -} - -void SfizzVstEditor::updateVolumeLabel(float volume) -{ - CTextLabel* label = _volumeLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%.1f dB", volume); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - -void SfizzVstEditor::updateNumVoicesLabel(int numVoices) -{ - CTextLabel* label = _numVoicesLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%d", numVoices); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - -void SfizzVstEditor::updateOversamplingLabel(int oversamplingLog2) -{ - CTextLabel* label = _oversamplingLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%dx", 1 << oversamplingLog2); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - -void SfizzVstEditor::updatePreloadSizeLabel(int preloadSize) -{ - CTextLabel* label = _preloadSizeLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%.1f kB", preloadSize * (1.0 / 1024)); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - -void SfizzVstEditor::updateScalaRootKeyLabel(int rootKey) -{ - CTextLabel* label = _scalaRootKeyLabel; - if (!label) - return; - - static const char *octNoteNames[12] = { - "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", - }; - - auto noteName = [](int key) -> std::string - { - int octNum; - int octNoteNum; - if (key >= 0) { - octNum = key / 12 - 1; - octNoteNum = key % 12; - } - else { - octNum = -2 - (key + 1) / -12; - octNoteNum = (key % 12 + 12) % 12; - } - return std::string(octNoteNames[octNoteNum]) + std::to_string(octNum); - }; - - label->setText(noteName(rootKey)); -} - -void SfizzVstEditor::updateTuningFrequencyLabel(float tuningFrequency) -{ - CTextLabel* label = _tuningFrequencyLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%.1f", tuningFrequency); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - -void SfizzVstEditor::updateStretchedTuningLabel(float stretchedTuning) -{ - CTextLabel* label = _stretchedTuningLabel; - if (!label) - return; - - char text[64]; - sprintf(text, "%.3f", stretchedTuning); - text[sizeof(text) - 1] = '\0'; - label->setText(text); -} - - -void SfizzVstEditor::setActivePanel(unsigned panelId) -{ - panelId = std::max(0, std::min(kNumPanels - 1, static_cast(panelId))); - - getController()->getSfizzUiState().activePanel = panelId; - - if (_activePanel != panelId) { - if (frame) - _subPanels[_activePanel]->setVisible(false); - - _activePanel = panelId; - - if (frame) - _subPanels[panelId]->setVisible(true); + switch (id) { + case EditId::Volume: return kPidVolume; + case EditId::Polyphony: return kPidNumVoices; + case EditId::Oversampling: return kPidOversampling; + case EditId::PreloadSize: return kPidPreloadSize; + case EditId::ScalaRootKey: return kPidScalaRootKey; + case EditId::TuningFrequency: return kPidTuningFrequency; + case EditId::StretchTuning: return kPidStretchedTuning; + default: return -1; } } diff --git a/vst/SfizzVstEditor.h b/vst/SfizzVstEditor.h index 21cf8a87..9c918765 100644 --- a/vst/SfizzVstEditor.h +++ b/vst/SfizzVstEditor.h @@ -6,7 +6,9 @@ #pragma once #include "SfizzVstController.h" +#include "editor/EditorController.h" #include "public.sdk/source/vst/vstguieditor.h" +class Editor; #if !defined(__APPLE__) && !defined(_WIN32) namespace VSTGUI { class RunLoop; } #endif @@ -14,7 +16,7 @@ namespace VSTGUI { class RunLoop; } using namespace Steinberg; using namespace VSTGUI; -class SfizzVstEditor : public Vst::VSTGUIEditor, public IControlListener, public SfizzVstController::StateListener { +class SfizzVstEditor : public Vst::VSTGUIEditor, public SfizzVstController::StateListener, public EditorController { public: explicit SfizzVstEditor(void *controller); ~SfizzVstEditor(); @@ -27,98 +29,28 @@ public: return static_cast(Vst::VSTGUIEditor::getController()); } - // IControlListener - void valueChanged(CControl* ctl) override; - void enterOrLeaveEdit(CControl* ctl, bool enter); - void controlBeginEdit(CControl* ctl) override; - void controlEndEdit(CControl* ctl) override; - // VSTGUIEditor CMessageResult notify(CBaseObject* sender, const char* message) override; // SfizzVstController::StateListener void onStateChanged() override; -private: - void chooseSfzFile(); - void loadSfzFile(const std::string& filePath); +protected: + // EditorController + void uiSendValue(EditId id, const EditValue& v) override; + void uiBeginSend(EditId id) override; + void uiEndSend(EditId id) override; + void uiSendMIDI(const uint8_t* msg, uint32_t len) override; - void chooseScalaFile(); +private: + void loadSfzFile(const std::string& filePath); void loadScalaFile(const std::string& filePath); - void createFrameContents(); void updateStateDisplay(); - void updateSfzFileLabel(const std::string& filePath); - void updateScalaFileLabel(const std::string& filePath); - static void updateLabelWithFileName(CTextLabel* label, const std::string& filePath); - void updateVolumeLabel(float volume); - void updateNumVoicesLabel(int numVoices); - void updateOversamplingLabel(int oversamplingLog2); - void updatePreloadSizeLabel(int preloadSize); - void updateScalaRootKeyLabel(int rootKey); - void updateTuningFrequencyLabel(float tuningFrequency); - void updateStretchedTuningLabel(float stretchedTuning); - void setActivePanel(unsigned panelId); - template - void adjustMinMaxToRangeParam(Control* c, Vst::ParamID id) - { - auto* p = static_cast(getController()->getParameterObject(id)); - c->setMin(p->getMin()); - c->setMax(p->getMax()); - c->setDefaultValue(p->toPlain(p->getInfo().defaultNormalizedValue)); - } + Vst::ParamID parameterOfEditId(EditId id); - enum { - kPanelGeneral, - // kPanelControls, - kPanelSettings, - kPanelTuning, - kPanelInfo, - kNumPanels, - }; - - unsigned _activePanel = 0; - CViewContainer* _subPanels[kNumPanels] = {}; - - enum { - kTagLoadSfzFile, - kTagSetVolume, - kTagSetNumVoices, - kTagSetOversampling, - kTagSetPreloadSize, - kTagLoadScalaFile, - kTagSetScalaRootKey, - kTagSetTuningFrequency, - kTagSetStretchedTuning, - kTagFirstChangePanel, - kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, - }; - - CBitmap _logo; - CTextLabel* _sfzFileLabel = nullptr; - CTextLabel* _scalaFileLabel = nullptr; - CSliderBase *_volumeSlider = nullptr; - CTextLabel* _volumeLabel = nullptr; - CSliderBase *_numVoicesSlider = nullptr; - CTextLabel* _numVoicesLabel = nullptr; - CSliderBase *_oversamplingSlider = nullptr; - CTextLabel* _oversamplingLabel = nullptr; - CSliderBase *_preloadSizeSlider = nullptr; - CTextLabel* _preloadSizeLabel = nullptr; - CSliderBase *_scalaRootKeySlider = nullptr; - CTextLabel* _scalaRootKeyLabel = nullptr; - CSliderBase *_tuningFrequencySlider = nullptr; - CTextLabel* _tuningFrequencyLabel = nullptr; - CSliderBase *_stretchedTuningSlider = nullptr; - CTextLabel* _stretchedTuningLabel = nullptr; - - CTextLabel* _infoCurvesLabel = nullptr; - CTextLabel* _infoMastersLabel = nullptr; - CTextLabel* _infoGroupsLabel = nullptr; - CTextLabel* _infoRegionsLabel = nullptr; - CTextLabel* _infoSamplesLabel = nullptr; - CTextLabel* _infoVoicesLabel = nullptr; + std::unique_ptr editor_; #if !defined(__APPLE__) && !defined(_WIN32) SharedPointer _runLoop; diff --git a/vst/SfizzVstProcessor.cpp b/vst/SfizzVstProcessor.cpp index bedde084..441fd9df 100644 --- a/vst/SfizzVstProcessor.cpp +++ b/vst/SfizzVstProcessor.cpp @@ -289,15 +289,15 @@ void SfizzVstProcessor::processParameterChanges(Vst::IParameterChanges& pc) break; case kPidScalaRootKey: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.scalaRootKey = static_cast(kParamScalaRootKey.denormalize(value)); + _state.scalaRootKey = static_cast(kParamScalaRootKeyRange.denormalize(value)); break; case kPidTuningFrequency: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.tuningFrequency = kParamTuningFrequency.denormalize(value); + _state.tuningFrequency = kParamTuningFrequencyRange.denormalize(value); break; case kPidStretchedTuning: if (pointCount > 0 && vq->getPoint(pointCount - 1, sampleOffset, value) == kResultTrue) - _state.stretchedTuning = kParamStretchedTuning.denormalize(value); + _state.stretchedTuning = kParamStretchedTuningRange.denormalize(value); break; } } diff --git a/vst/SfizzVstState.h b/vst/SfizzVstState.h index f356d04e..531e2dac 100644 --- a/vst/SfizzVstState.h +++ b/vst/SfizzVstState.h @@ -99,6 +99,6 @@ static constexpr SfizzParameterRange kParamVolumeRange(0.0, -60.0, +6.0); static constexpr SfizzParameterRange kParamNumVoicesRange(64.0, 1.0, 256.0); static constexpr SfizzParameterRange kParamOversamplingRange(0.0, 0.0, 3.0); static constexpr SfizzParameterRange kParamPreloadSizeRange(8192.0, 1024.0, 65536.0); -static constexpr SfizzParameterRange kParamScalaRootKey(60.0, 0.0, 127.0); -static constexpr SfizzParameterRange kParamTuningFrequency(440.0, 300.0, 500.0); -static constexpr SfizzParameterRange kParamStretchedTuning(0.0, 0.0, 1.0); +static constexpr SfizzParameterRange kParamScalaRootKeyRange(60.0, 0.0, 127.0); +static constexpr SfizzParameterRange kParamTuningFrequencyRange(440.0, 300.0, 500.0); +static constexpr SfizzParameterRange kParamStretchedTuningRange(0.0, 0.0, 1.0); diff --git a/vst/cmake/Vst3.cmake b/vst/cmake/Vst3.cmake index 68118f73..259f62a2 100644 --- a/vst/cmake/Vst3.cmake +++ b/vst/cmake/Vst3.cmake @@ -63,222 +63,7 @@ endfunction() # --- VSTGUI --- function(plugin_add_vstgui NAME) - target_sources("${NAME}" PRIVATE - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/animations.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/animator.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/animation/timingfunctions.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cbitmap.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cbitmapfilter.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ccolor.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdatabrowser.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdrawcontext.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdrawmethods.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cdropsource.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cfileselector.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cfont.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cframe.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cgradientview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cgraphicspath.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/clayeredviewcontainer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/clinestyle.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/coffscreencontext.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cautoanimation.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cbuttons.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ccolorchooser.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ccontrol.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cfontchooser.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cknob.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/clistcontrol.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cmoviebitmap.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cmoviebutton.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/coptionmenu.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cparamdisplay.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cscrollbar.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csearchtextedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csegmentbutton.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cslider.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cspecialdigit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/csplashscreen.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cstringlist.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cswitch.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ctextedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/ctextlabel.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cvumeter.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/controls/cxypad.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/copenglview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cpoint.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/crect.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/crowcolumnview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cscrollview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cshadowviewcontainer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/csplitview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cstring.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ctabview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/ctooltipsupport.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cviewcontainer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/cvstguitimer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/genericstringlistdatabrowsersource.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/genericoptionmenu.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/vstguidebug.cpp") - - if(WIN32) - target_sources("${NAME}" PRIVATE - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dbitmap.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2ddrawcontext.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dfont.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/direct2d/d2dgraphicspath.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32datapackage.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32dragging.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32frame.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32openglview.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32optionmenu.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32support.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/win32textedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/winfileselector.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/winstring.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/win32/wintimer.cpp") - elseif(APPLE) - target_sources("${NAME}" PRIVATE - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/genericoptionmenu.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/generictextedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewframe.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewoptionmenu.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/carbon/hiviewtextedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/caviewlayer.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cfontmac.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cgbitmap.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cgdrawcontext.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/autoreleasepool.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoahelpers.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoaopenglview.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/cocoatextedit.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewdraggingsession.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewframe.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/cocoa/nsviewoptionmenu.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macclipboard.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macfileselector.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macglobals.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/macstring.mm" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/mactimer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/mac/quartzgraphicspath.cpp") - else() - target_sources("${NAME}" PRIVATE - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/fileresourceinputstream.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/common/generictextedit.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairobitmap.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairocontext.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairofont.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairogradient.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/cairopath.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/linuxstring.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11fileselector.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11frame.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11platform.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11timer.cpp" - "${VST3SDK_BASEDIR}/vstgui4/vstgui/lib/platform/linux/x11utils.cpp") - endif() - - target_include_directories("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/vstgui4") - - if(WIN32) - target_compile_definitions("${NAME}" PRIVATE "NOMINMAX=1") - if (NOT MSVC) - # autolinked on MSVC with pragmas - find_library(OPENGL32_LIBRARY "opengl32") - find_library(D2D1_LIBRARY "d2d1") - find_library(DWRITE_LIBRARY "dwrite") - find_library(DWMAPI_LIBRARY "dwmapi") - find_library(WINDOWSCODECS_LIBRARY "windowscodecs") - find_library(SHLWAPI_LIBRARY "shlwapi") - target_link_libraries("${NAME}" PRIVATE - "${OPENGL32_LIBRARY}" - "${D2D1_LIBRARY}" - "${DWRITE_LIBRARY}" - "${DWMAPI_LIBRARY}" - "${WINDOWSCODECS_LIBRARY}" - "${SHLWAPI_LIBRARY}") - endif() - elseif(APPLE) - find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation") - find_library(APPLE_FOUNDATION_LIBRARY "Foundation") - find_library(APPLE_COCOA_LIBRARY "Cocoa") - find_library(APPLE_OPENGL_LIBRARY "OpenGL") - find_library(APPLE_ACCELERATE_LIBRARY "Accelerate") - find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore") - find_library(APPLE_CARBON_LIBRARY "Carbon") - find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox") - find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio") - find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI") - target_link_libraries("${NAME}" PRIVATE - "${APPLE_COREFOUNDATION_LIBRARY}" - "${APPLE_FOUNDATION_LIBRARY}" - "${APPLE_COCOA_LIBRARY}" - "${APPLE_OPENGL_LIBRARY}" - "${APPLE_ACCELERATE_LIBRARY}" - "${APPLE_QUARTZCORE_LIBRARY}" - "${APPLE_CARBON_LIBRARY}" - "${APPLE_AUDIOTOOLBOX_LIBRARY}" - "${APPLE_COREAUDIO_LIBRARY}" - "${APPLE_COREMIDI_LIBRARY}") - else() - find_package(X11 REQUIRED) - find_package(Freetype REQUIRED) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBXCB REQUIRED xcb) - pkg_check_modules(LIBXCB_UTIL REQUIRED xcb-util) - pkg_check_modules(LIBXCB_CURSOR REQUIRED xcb-cursor) - pkg_check_modules(LIBXCB_KEYSYMS REQUIRED xcb-keysyms) - pkg_check_modules(LIBXCB_XKB REQUIRED xcb-xkb) - pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) - pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) - pkg_check_modules(CAIRO REQUIRED cairo) - pkg_check_modules(FONTCONFIG REQUIRED fontconfig) - target_include_directories("${NAME}" PRIVATE - ${X11_INCLUDE_DIRS} - ${FREETYPE_INCLUDE_DIRS} - ${LIBXCB_INCLUDE_DIRS} - ${LIBXCB_UTIL_INCLUDE_DIRS} - ${LIBXCB_CURSOR_INCLUDE_DIRS} - ${LIBXCB_KEYSYMS_INCLUDE_DIRS} - ${LIBXCB_XKB_INCLUDE_DIRS} - ${LIBXKB_COMMON_INCLUDE_DIRS} - ${LIBXKB_COMMON_X11_INCLUDE_DIRS} - ${CAIRO_INCLUDE_DIRS} - ${FONTCONFIG_INCLUDE_DIRS}) - target_link_libraries("${NAME}" PRIVATE - ${X11_LIBRARIES} - ${FREETYPE_LIBRARIES} - ${LIBXCB_LIBRARIES} - ${LIBXCB_UTIL_LIBRARIES} - ${LIBXCB_CURSOR_LIBRARIES} - ${LIBXCB_KEYSYMS_LIBRARIES} - ${LIBXCB_XKB_LIBRARIES} - ${LIBXKB_COMMON_LIBRARIES} - ${LIBXKB_COMMON_X11_LIBRARIES} - ${CAIRO_LIBRARIES} - ${FONTCONFIG_LIBRARIES}) - find_library(DL_LIBRARY "dl") - if(DL_LIBRARY) - target_link_libraries("${NAME}" PRIVATE "${DL_LIBRARY}") - endif() - endif() - - target_sources("${NAME}" PRIVATE - "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstguieditor.cpp") - - target_include_directories("${NAME}" PRIVATE - external/steinberg/src) - + target_link_libraries("${NAME}" PRIVATE sfizz-vstgui) + target_sources("${NAME}" PRIVATE "${VST3SDK_BASEDIR}/public.sdk/source/vst/vstguieditor.cpp") target_compile_definitions("${NAME}" PRIVATE "SMTG_MODULE_IS_BUNDLE=1") - - if(${CMAKE_BUILD_TYPE} MATCHES "Debug") - target_compile_definitions("${NAME}" PRIVATE "DEVELOPMENT") - endif() - - if(${CMAKE_BUILD_TYPE} MATCHES "Release") - target_compile_definitions("${NAME}" PRIVATE "RELEASE") - endif() endfunction() From b92209de7468e5cddf70fe9b986087293f852170 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 05:47:37 +0200 Subject: [PATCH 02/24] Support UI in LV2 --- .travis/prepare_osx.sh | 3 +- editor/CMakeLists.txt | 7 +- editor/cmake/Vstgui.cmake | 11 + {vst => editor}/resources/logo.png | Bin {vst => editor}/resources/logo.svg | 0 editor/src/editor/Editor.cpp | 2 +- lv2/CMakeLists.txt | 50 ++- lv2/lv2ui.version | 4 + lv2/manifest.ttl.in | 8 +- lv2/sfizz.c | 61 ++-- lv2/sfizz.ttl.in | 69 ++++ lv2/sfizz_lv2.h | 43 +++ lv2/sfizz_ui.cpp | 492 +++++++++++++++++++++++++++++ lv2/sfizz_ui.ttl.in | 14 + lv2/vstgui_helpers.cpp | 170 ++++++++++ lv2/vstgui_helpers.h | 68 ++++ vst/CMakeLists.txt | 7 +- 17 files changed, 966 insertions(+), 43 deletions(-) rename {vst => editor}/resources/logo.png (100%) rename {vst => editor}/resources/logo.svg (100%) create mode 100644 lv2/lv2ui.version create mode 100644 lv2/sfizz_lv2.h create mode 100644 lv2/sfizz_ui.cpp create mode 100644 lv2/sfizz_ui.ttl.in create mode 100644 lv2/vstgui_helpers.cpp create mode 100644 lv2/vstgui_helpers.h diff --git a/.travis/prepare_osx.sh b/.travis/prepare_osx.sh index 8fc891c9..8de6d08e 100755 --- a/.travis/prepare_osx.sh +++ b/.travis/prepare_osx.sh @@ -15,7 +15,8 @@ buildenv make DESTDIR=${PWD}/${INSTALL_DIR} install # Bundle LV2 dependencies cd "${INSTALL_DIR}"/Library/Audio/Plug-Ins/LV2 -dylibbundler -od -b -x sfizz.lv2/sfizz.so -d sfizz.lv2/libs/ -p @loader_path/libs/ +dylibbundler -od -b -x sfizz.lv2/Contents/Binary/sfizz.so -d sfizz.lv2/Contents/libs/ -p @loader_path/../libs/ +dylibbundler -od -b -x sfizz.lv2/Contents/Binary/sfizz_ui.so -d sfizz.lv2/Contents/libs/ -p @loader_path/../libs/ cd "${TRAVIS_BUILD_DIR}/build" # Bundle VST3 dependencies diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 977f36a4..777939d4 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -1,6 +1,10 @@ set(VSTGUI_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/vstgui4") include("cmake/Vstgui.cmake") +set(EDITOR_RESOURCES + logo.png + PARENT_SCOPE) + # editor add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/EditIds.h @@ -13,4 +17,5 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_after.h src/editor/utility/vstgui_before.h) target_include_directories(sfizz_editor PUBLIC "src") -target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui absl::strings) +target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui) +target_link_libraries(sfizz_editor PUBLIC absl::strings absl::variant) diff --git a/editor/cmake/Vstgui.cmake b/editor/cmake/Vstgui.cmake index 92f85f03..e853b091 100644 --- a/editor/cmake/Vstgui.cmake +++ b/editor/cmake/Vstgui.cmake @@ -207,3 +207,14 @@ endif() if(${CMAKE_BUILD_TYPE} MATCHES "Release") target_compile_definitions(sfizz-vstgui PRIVATE "RELEASE") endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(sfizz-vstgui PRIVATE + "-Wno-deprecated-copy" + "-Wno-ignored-qualifiers" + "-Wno-reorder" + "-Wno-sign-compare" + "-Wno-unused-function" + "-Wno-unused-parameter" + "-Wno-unused-variable") +endif() diff --git a/vst/resources/logo.png b/editor/resources/logo.png similarity index 100% rename from vst/resources/logo.png rename to editor/resources/logo.png diff --git a/vst/resources/logo.svg b/editor/resources/logo.svg similarity index 100% rename from vst/resources/logo.svg rename to editor/resources/logo.svg diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index c4d247c8..1024c27d 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -288,7 +288,7 @@ void Editor::Impl::createFrameContents() view->setBackgroundColor(CColor(0xff, 0xff, 0xff)); - SharedPointer logo = new CBitmap("logo.png"); + SharedPointer logo { new CBitmap("logo.png") }; CRect bottomRow = bounds; bottomRow.top = bottomRow.bottom - 30; diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index 4104eb25..c45f964f 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -11,6 +11,10 @@ set (LV2PLUGIN_TTL_SRC_FILES manifest.ttl.in ${PROJECT_NAME}.ttl.in ) +if (SFIZZ_LV2_UI) + list(APPEND LV2PLUGIN_TTL_SRC_FILES + ${PROJECT_NAME}_ui.ttl.in) +endif() source_group("Turtle Files" FILES ${LV2PLUGIN_TTL_SRC_FILES} ) @@ -19,31 +23,61 @@ add_library (${LV2PLUGIN_PRJ_NAME} MODULE atomic_compat.h ${LV2PLUGIN_TTL_SRC_FILES}) target_link_libraries (${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME}) + +if (SFIZZ_LV2_UI) + add_library (${LV2PLUGIN_PRJ_NAME}_ui MODULE + ${PROJECT_NAME}_ui.cpp + vstgui_helpers.h + vstgui_helpers.cpp) + target_link_libraries (${LV2PLUGIN_PRJ_NAME}_ui sfizz_editor sfizz-vstgui) +endif() + # Explicitely strip all symbols on Linux but lv2_descriptor() # MacOS linker does not support this apparently https://bugs.webkit.org/show_bug.cgi?id=144555 if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") file(COPY lv2.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,--version-script=lv2.version") # target_link_libraries(${LV2PLUGIN_PRJ_NAME} "-Wl,-u,lv2_descriptor") + if (SFIZZ_LV2_UI) + file(COPY lv2ui.version DESTINATION ${CMAKE_BINARY_DIR}/lv2) + target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,--version-script=lv2ui.version") + # target_link_libraries(${LV2PLUGIN_PRJ_NAME}_ui "-Wl,-u,lv2ui_descriptor") + endif() endif() target_include_directories(${LV2PLUGIN_PRJ_NAME} PRIVATE . external/ardour) sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME}) if (MINGW) set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LINK_FLAGS "-static") endif() +if (SFIZZ_LV2_UI) + target_include_directories(${LV2PLUGIN_PRJ_NAME}_ui PRIVATE . external/ardour) + sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME}_ui) + if (MINGW) + set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LINK_FLAGS "-static") + endif() +endif() # Remove the "lib" prefix, rename the target name and build it in the .lv build dir # /lv2/_lv2. to # /lv2/.lv2/. set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES PREFIX "") set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") -set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") +set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary") + +if (SFIZZ_LV2_UI) + set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES PREFIX "") + set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_ui") + set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary") +endif() # Generate *.ttl files from *.in sources, # create the destination directory if it doesn't exists and copy needed files file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR}) configure_file (manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl) configure_file (${PROJECT_NAME}.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ttl) +if (SFIZZ_LV2_UI) + configure_file (${PROJECT_NAME}_ui.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}_ui.ttl) +endif() configure_file (LICENSE.md.in ${PROJECT_BINARY_DIR}/LICENSE.md) if (SFIZZ_USE_VCPKG OR SFIZZ_STATIC_DEPENDENCIES OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC") file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR}) @@ -54,12 +88,22 @@ set(LV2_RESOURCES DefaultInstrument.sfz DefaultScale.scl) execute_process( - COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Resources") + COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Contents/Resources") foreach(res ${LV2_RESOURCES}) file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${res}" - DESTINATION "${PROJECT_BINARY_DIR}/Resources") + DESTINATION "${PROJECT_BINARY_DIR}/Contents/Resources") endforeach() +# Copy editor resources +if (SFIZZ_LV2_UI) + execute_process ( + COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Contents/Resources") + foreach(res ${EDITOR_RESOURCES}) + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources/${res}" + DESTINATION "${PROJECT_BINARY_DIR}/Contents/Resources") + endforeach() +endif() + # Installation if (NOT MSVC) install (DIRECTORY ${PROJECT_BINARY_DIR} DESTINATION ${LV2PLUGIN_INSTALL_DIR} diff --git a/lv2/lv2ui.version b/lv2/lv2ui.version new file mode 100644 index 00000000..95c55e1b --- /dev/null +++ b/lv2/lv2ui.version @@ -0,0 +1,4 @@ +LV2UIABI_1.0 { + global: *lv2ui_descriptor*; + local: *; +}; diff --git a/lv2/manifest.ttl.in b/lv2/manifest.ttl.in index 3ea4e883..ab407d33 100644 --- a/lv2/manifest.ttl.in +++ b/lv2/manifest.ttl.in @@ -1,7 +1,13 @@ @prefix lv2: . @prefix rdfs: . +@prefix ui: . <@LV2PLUGIN_URI@> a lv2:Plugin ; - lv2:binary <@PROJECT_NAME@@CMAKE_SHARED_MODULE_SUFFIX@> ; + lv2:binary ; rdfs:seeAlso <@PROJECT_NAME@.ttl> . + +@LV2PLUGIN_IF_ENABLE_UI@<@LV2PLUGIN_URI@#ui> +@LV2PLUGIN_IF_ENABLE_UI@ a ui:@LV2_UI_TYPE@ ; +@LV2PLUGIN_IF_ENABLE_UI@ ui:binary ; +@LV2PLUGIN_IF_ENABLE_UI@ rdfs:seeAlso <@PROJECT_NAME@_ui.ttl> . diff --git a/lv2/sfizz.c b/lv2/sfizz.c index ef07343e..b68c527f 100644 --- a/lv2/sfizz.c +++ b/lv2/sfizz.c @@ -32,6 +32,9 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "sfizz_lv2.h" + +#include #include #include #include @@ -58,23 +61,11 @@ #include "atomic_compat.h" -#define SFIZZ_URI "http://sfztools.github.io/sfizz" -#define SFIZZ_PREFIX SFIZZ_URI "#" -#define SFIZZ__sfzFile SFIZZ_URI ":" "sfzfile" -#define SFIZZ__tuningfile SFIZZ_URI ":" "tuningfile" -#define SFIZZ__numVoices SFIZZ_URI ":" "numvoices" -#define SFIZZ__preloadSize SFIZZ_URI ":" "preload_size" -#define SFIZZ__oversampling SFIZZ_URI ":" "oversampling" -// These ones are just for the worker -#define SFIZZ__logStatus SFIZZ_URI ":" "log_status" -#define SFIZZ__checkModification SFIZZ_URI ":" "check_modification" - #define CHANNEL_MASK 0x0F #define MIDI_CHANNEL(byte) (byte & CHANNEL_MASK) #define MIDI_STATUS(byte) (byte & ~CHANNEL_MASK) #define PITCH_BUILD_AND_CENTER(first_byte, last_byte) (int)(((unsigned int)last_byte << 7) + (unsigned int)first_byte) - 8192 #define MAX_BLOCK_SIZE 8192 -#define MAX_PATH_SIZE 1024 #define MAX_VOICES 256 #define DEFAULT_VOICES 64 #define DEFAULT_OVERSAMPLING SFIZZ_OVERSAMPLING_X1 @@ -82,8 +73,8 @@ #define LOG_SAMPLE_COUNT 48000 #define UNUSED(x) (void)(x) -#define DEFAULT_SCALA_FILE "Resources/DefaultScale.scl" -#define DEFAULT_SFZ_FILE "Resources/DefaultInstrument.sfz" +#define DEFAULT_SCALA_FILE "Contents/Resources/DefaultScale.scl" +#define DEFAULT_SFZ_FILE "Contents/Resources/DefaultInstrument.sfz" // This assumes that the longest path is the default sfz file; if not, change it #define MAX_BUNDLE_PATH_SIZE (MAX_PATH_SIZE - sizeof(DEFAULT_SFZ_FILE)) @@ -115,6 +106,11 @@ typedef struct const float *tuning_frequency_port; const float *stretch_tuning_port; float *active_voices_port; + float *num_curves_port; + float *num_masters_port; + float *num_groups_port; + float *num_regions_port; + float *num_samples_port; // Atom forge LV2_Atom_Forge forge; ///< Forge for writing atoms in run thread @@ -187,23 +183,6 @@ typedef struct char bundle_path[MAX_BUNDLE_PATH_SIZE]; } sfizz_plugin_t; -enum -{ - SFIZZ_CONTROL = 0, - SFIZZ_NOTIFY = 1, - SFIZZ_LEFT = 2, - SFIZZ_RIGHT = 3, - SFIZZ_VOLUME = 4, - SFIZZ_POLYPHONY = 5, - SFIZZ_OVERSAMPLING = 6, - SFIZZ_PRELOAD = 7, - SFIZZ_FREEWHEELING = 8, - SFIZZ_SCALA_ROOT_KEY = 9, - SFIZZ_TUNING_FREQUENCY = 10, - SFIZZ_STRETCH_TUNING = 11, - SFIZZ_ACTIVE_VOICES = 12, -}; - enum { SFIZZ_TIMEINFO_POSITION = 1 << 0, @@ -369,6 +348,21 @@ connect_port(LV2_Handle instance, case SFIZZ_ACTIVE_VOICES: self->active_voices_port = (float *)data; break; + case SFIZZ_NUM_CURVES: + self->num_curves_port = (float *)data; + break; + case SFIZZ_NUM_MASTERS: + self->num_masters_port = (float *)data; + break; + case SFIZZ_NUM_GROUPS: + self->num_groups_port = (float *)data; + break; + case SFIZZ_NUM_REGIONS: + self->num_regions_port = (float *)data; + break; + case SFIZZ_NUM_SAMPLES: + self->num_samples_port = (float *)data; + break; default: break; } @@ -977,6 +971,11 @@ run(LV2_Handle instance, uint32_t sample_count) sfizz_lv2_check_oversampling(self); sfizz_lv2_check_num_voices(self); *(self->active_voices_port) = sfizz_get_num_active_voices(self->synth); + *(self->num_curves_port) = sfizz_get_num_curves(self->synth); + *(self->num_masters_port) = sfizz_get_num_masters(self->synth); + *(self->num_groups_port) = sfizz_get_num_groups(self->synth); + *(self->num_regions_port) = sfizz_get_num_regions(self->synth); + *(self->num_samples_port) = sfizz_get_num_preloaded_samples(self->synth); // Log the buffer usage self->sample_counter += (int)sample_count; diff --git a/lv2/sfizz.ttl.in b/lv2/sfizz.ttl.in index b0934ca6..f4090158 100644 --- a/lv2/sfizz.ttl.in +++ b/lv2/sfizz.ttl.in @@ -13,6 +13,7 @@ @prefix rdfs: . @prefix state: . @prefix time: . +@prefix ui: . @prefix units: . @prefix urid: . @prefix work: . @@ -83,6 +84,8 @@ midnam:update a lv2:Feature . opts:supportedOption param:sampleRate ; opts:supportedOption bufsize:maxBlockLength, bufsize:nominalBlockLength ; + @LV2PLUGIN_IF_ENABLE_UI@ui:ui <@LV2PLUGIN_URI@#ui> ; + patch:writable <@LV2PLUGIN_URI@:sfzfile> , <@LV2PLUGIN_URI@:tuningfile> ; @@ -310,4 +313,70 @@ midnam:update a lv2:Feature . lv2:default 0 ; lv2:minimum 0 ; lv2:maximum 256 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 12 ; + lv2:symbol "active_voices" ; + lv2:name "Active voices", + "Voix utilisées"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 256 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 13 ; + lv2:symbol "num_curves" ; + lv2:name "Number of curves", + "Nombre de courbes"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 65535 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 14 ; + lv2:symbol "num_masters" ; + lv2:name "Number of masters", + "Nombre de maîtres"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 65535 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 15 ; + lv2:symbol "num_groups" ; + lv2:name "Number of groups", + "Nombre de groupes"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 65535 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 16 ; + lv2:symbol "num_regions" ; + lv2:name "Number of regions", + "Nombre de regions"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 65535 ; + ] , [ + a lv2:OutputPort, lv2:ControlPort ; + lv2:index 17 ; + lv2:symbol "num_samples" ; + lv2:name "Number of samples", + "Nombre d'échantillons"@fr ; + pg:group <@LV2PLUGIN_URI@#status> ; + lv2:portProperty lv2:integer ; + lv2:default 0 ; + lv2:minimum 0 ; + lv2:maximum 65535 ; ] . diff --git a/lv2/sfizz_lv2.h b/lv2/sfizz_lv2.h new file mode 100644 index 00000000..b0eafe00 --- /dev/null +++ b/lv2/sfizz_lv2.h @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once + +#define MAX_PATH_SIZE 1024 + +#define SFIZZ_URI "http://sfztools.github.io/sfizz" +#define SFIZZ_UI_URI "http://sfztools.github.io/sfizz#ui" +#define SFIZZ_PREFIX SFIZZ_URI "#" +#define SFIZZ__sfzFile SFIZZ_URI ":" "sfzfile" +#define SFIZZ__tuningfile SFIZZ_URI ":" "tuningfile" +#define SFIZZ__numVoices SFIZZ_URI ":" "numvoices" +#define SFIZZ__preloadSize SFIZZ_URI ":" "preload_size" +#define SFIZZ__oversampling SFIZZ_URI ":" "oversampling" +// These ones are just for the worker +#define SFIZZ__logStatus SFIZZ_URI ":" "log_status" +#define SFIZZ__checkModification SFIZZ_URI ":" "check_modification" + +enum +{ + SFIZZ_CONTROL = 0, + SFIZZ_NOTIFY = 1, + SFIZZ_LEFT = 2, + SFIZZ_RIGHT = 3, + SFIZZ_VOLUME = 4, + SFIZZ_POLYPHONY = 5, + SFIZZ_OVERSAMPLING = 6, + SFIZZ_PRELOAD = 7, + SFIZZ_FREEWHEELING = 8, + SFIZZ_SCALA_ROOT_KEY = 9, + SFIZZ_TUNING_FREQUENCY = 10, + SFIZZ_STRETCH_TUNING = 11, + SFIZZ_ACTIVE_VOICES = 12, + SFIZZ_NUM_CURVES = 13, + SFIZZ_NUM_MASTERS = 14, + SFIZZ_NUM_GROUPS = 15, + SFIZZ_NUM_REGIONS = 16, + SFIZZ_NUM_SAMPLES = 17, +}; diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp new file mode 100644 index 00000000..1cbb49a2 --- /dev/null +++ b/lv2/sfizz_ui.cpp @@ -0,0 +1,492 @@ +/* + SPDX-License-Identifier: ISC + + Sfizz LV2 plugin + + Copyright 2019-2020, Paul Ferrand + + This file was based on skeleton and example code from the LV2 plugin + distribution available at http://lv2plug.in/ + + The LV2 sample plugins have the following copyright and notice, which are + extended to the current work: + Copyright 2011-2016 David Robillard + Copyright 2011 Gabriel M. Beddingfield + Copyright 2011 James Morris + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + Compiling this plugin statically against libsndfile implies distributing it + under the terms of the LGPL v3 license. See the LICENSE.md file for more + information. If you did not receive a LICENSE.md file, inform the current + maintainer. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "sfizz_lv2.h" + +#include "editor/Editor.h" +#include "editor/EditorController.h" +#include "editor/EditIds.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vstgui_helpers.h" + +#include "editor/utility/vstgui_before.h" +#include "vstgui/lib/cframe.h" +#include "vstgui/lib/platform/iplatformframe.h" +#include "editor/utility/vstgui_after.h" +using namespace VSTGUI; + +/// +struct FrameHolderDeleter { + void operator()(CFrame* frame) const + { + if (frame->getNbReference() != 1) + frame->forget(); + else + frame->close(); + } +}; +typedef std::unique_ptr FrameHolder; + +/// +struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { + LV2UI_Write_Function write = nullptr; + LV2UI_Controller con = nullptr; + LV2_URID_Map *map = nullptr; + LV2_URID_Unmap *unmap = nullptr; + LV2UI_Resize *resize = nullptr; + LV2UI_Touch *touch = nullptr; + std::unique_ptr editor; + FrameHolder uiFrame; +#if LINUX + SharedPointer runLoop; +#endif + + /// VSTGUIEditorInterface + CFrame* getFrame() const override { return uiFrame.get(); } + + LV2_Atom_Forge atom_forge; + LV2_URID atom_event_transfer_uri; + LV2_URID atom_object_uri; + LV2_URID atom_path_uri; + LV2_URID atom_urid_uri; + LV2_URID midi_event_uri; + LV2_URID patch_get_uri; + LV2_URID patch_set_uri; + LV2_URID patch_property_uri; + LV2_URID patch_value_uri; + LV2_URID sfizz_sfz_file_uri; + LV2_URID sfizz_scala_file_uri; + +protected: + void uiSendValue(EditId id, const EditValue& v) override; + void uiBeginSend(EditId id) override; + void uiEndSend(EditId id) override; + void uiSendMIDI(const uint8_t* msg, uint32_t len) override; + +private: + void uiTouch(EditId id, bool t); +}; + +static LV2UI_Handle +instantiate(const LV2UI_Descriptor *descriptor, + const char *plugin_uri, + const char *bundle_path, + LV2UI_Write_Function write_function, + LV2UI_Controller controller, + LV2UI_Widget *widget, + const LV2_Feature * const *features) +{ + std::unique_ptr self { new sfizz_ui_t }; + + (void)descriptor; + (void)plugin_uri; + (void)bundle_path; + + self->write = write_function; + self->con = controller; + + void *parentWindowId = nullptr; + + LV2_URID_Map *map = nullptr; + LV2_URID_Unmap *unmap = nullptr; + + for (const LV2_Feature *const *f = features; *f; f++) + { + if (!strcmp((**f).URI, LV2_URID__map)) + self->map = map = (LV2_URID_Map *)(**f).data; + else if (!strcmp((**f).URI, LV2_URID__unmap)) + self->unmap = unmap = (LV2_URID_Unmap *)(**f).data; + else if (!strcmp((**f).URI, LV2_UI__resize)) + self->resize = (LV2UI_Resize *)(**f).data; + else if (!strcmp((**f).URI, LV2_UI__touch)) + self->touch = (LV2UI_Touch*)(**f).data; + else if (!strcmp((**f).URI, LV2_UI__parent)) + parentWindowId = (**f).data; + } + + // The map feature is required + if (!map || !unmap) + return nullptr; + + LV2_Atom_Forge *forge = &self->atom_forge; + lv2_atom_forge_init(forge, map); + self->atom_event_transfer_uri = map->map(map->handle, LV2_ATOM__eventTransfer); + self->atom_object_uri = map->map(map->handle, LV2_ATOM__Object); + self->atom_path_uri = map->map(map->handle, LV2_ATOM__Path); + self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID); + self->midi_event_uri = map->map(map->handle, LV2_MIDI__MidiEvent); + self->patch_get_uri = map->map(map->handle, LV2_PATCH__Get); + self->patch_set_uri = map->map(map->handle, LV2_PATCH__Set); + self->patch_property_uri = map->map(map->handle, LV2_PATCH__property); + self->patch_value_uri = map->map(map->handle, LV2_PATCH__value); + self->sfizz_sfz_file_uri = map->map(map->handle, SFIZZ__sfzFile); + self->sfizz_scala_file_uri = map->map(map->handle, SFIZZ__tuningfile); + + // set up the resource path + // * on Linux, this is determined by going 2 folders back from the SO path + // name, and appending "Contents/Resources" (not overridable) + // * on Windows, the folder is set programmatically + // * on macOS, resource files are looked up using CFBundle APIs +#if _WIN32 + IWin32PlatformFrame::setResourceBasePath((std::string(bundle_path) + "\\Contents\\Resources\\").c_str()); +#elif __APPLE__ + #pragma message("TODO: make resources work on macOS using bundles") +#endif + + // makes labels refresh correctly + CView::kDirtyCallAlwaysOnMainThread = true; + + const CRect uiBounds(0, 0, Editor::viewWidth, Editor::viewHeight); + CFrame* uiFrame = new CFrame(uiBounds, self.get()); + self->uiFrame.reset(uiFrame); + + IPlatformFrameConfig* config = nullptr; +#if LINUX + SharedPointer runLoop = new Lv2IdleRunLoop; + self->runLoop = runLoop; + VSTGUI::X11::FrameConfig x11Config; + x11Config.runLoop = runLoop; + config = &x11Config; +#endif + + if (!uiFrame->open(parentWindowId, kDefaultNative, config)) + return nullptr; + + Editor *editor = new Editor(*self); + self->editor.reset(editor); + editor->open(*uiFrame); + + *widget = reinterpret_cast(uiFrame->getPlatformFrame()->getPlatformRepresentation()); + + if (self->resize) + self->resize->ui_resize(self->resize->handle, Editor::viewWidth, Editor::viewHeight); + + // send a request to receive all parameters + uint8_t buffer[256]; + lv2_atom_forge_set_buffer(forge, buffer, sizeof(buffer)); + LV2_Atom_Forge_Frame frame; + LV2_Atom *msg = (LV2_Atom *)lv2_atom_forge_object(forge, &frame, 0, self->patch_get_uri); + lv2_atom_forge_pop(forge, &frame); + write_function(controller, 0, lv2_atom_total_size(msg), self->atom_event_transfer_uri, msg); + + return self.release(); +} + +static void +cleanup(LV2UI_Handle ui) +{ + sfizz_ui_t *self = (sfizz_ui_t *)ui; + delete self; +} + +static void +port_event(LV2UI_Handle ui, + uint32_t port_index, + uint32_t buffer_size, + uint32_t format, + const void *buffer) +{ + sfizz_ui_t *self = (sfizz_ui_t *)ui; + + if (format == 0) { + const float v = *reinterpret_cast(buffer); + + switch (port_index) { + case SFIZZ_VOLUME: + self->uiReceiveValue(EditId::Volume, v); + break; + case SFIZZ_POLYPHONY: + self->uiReceiveValue(EditId::Polyphony, v); + break; + case SFIZZ_OVERSAMPLING: + self->uiReceiveValue(EditId::Oversampling, v); + break; + case SFIZZ_PRELOAD: + self->uiReceiveValue(EditId::PreloadSize, v); + break; + case SFIZZ_SCALA_ROOT_KEY: + self->uiReceiveValue(EditId::ScalaRootKey, v); + break; + case SFIZZ_TUNING_FREQUENCY: + self->uiReceiveValue(EditId::TuningFrequency, v); + break; + case SFIZZ_STRETCH_TUNING: + self->uiReceiveValue(EditId::StretchTuning, v); + break; + case SFIZZ_ACTIVE_VOICES: + self->uiReceiveValue(EditId::UINumActiveVoices, v); + break; + case SFIZZ_NUM_CURVES: + self->uiReceiveValue(EditId::UINumCurves, v); + break; + case SFIZZ_NUM_MASTERS: + self->uiReceiveValue(EditId::UINumMasters, v); + break; + case SFIZZ_NUM_GROUPS: + self->uiReceiveValue(EditId::UINumGroups, v); + break; + case SFIZZ_NUM_REGIONS: + self->uiReceiveValue(EditId::UINumRegions, v); + break; + case SFIZZ_NUM_SAMPLES: + self->uiReceiveValue(EditId::UINumPreloadedSamples, v); + break; + } + } + else if (format == self->atom_event_transfer_uri) { + auto *atom = reinterpret_cast(buffer); + + if (atom->type == self->atom_object_uri) { + const LV2_Atom *prop = nullptr; + const LV2_Atom *value = nullptr; + + lv2_atom_object_get( + reinterpret_cast(atom), + self->patch_property_uri, &prop, self->patch_value_uri, &value, 0); + + if (prop && value && prop->type == self->atom_urid_uri) { + const LV2_URID prop_uri = reinterpret_cast(prop)->body; + auto *value_body = reinterpret_cast(LV2_ATOM_BODY_CONST(value)); + + if (prop_uri == self->sfizz_sfz_file_uri && value->type == self->atom_path_uri) { + std::string path(value_body, strnlen(value_body, value->size)); + self->uiReceiveValue(EditId::SfzFile, path); + } + else if (prop_uri == self->sfizz_scala_file_uri && value->type == self->atom_path_uri) { + std::string path(value_body, strnlen(value_body, value->size)); + self->uiReceiveValue(EditId::ScalaFile, path); + } + } + } + } + + (void)buffer_size; +} + +static int +idle(LV2UI_Handle ui) +{ + sfizz_ui_t *self = (sfizz_ui_t *)ui; + +#if LINUX + self->runLoop->execIdle(); +#endif + + return 0; +} + +static const LV2UI_Idle_Interface idle_interface = { + &idle, +}; + +static int +show(LV2UI_Handle ui) +{ + sfizz_ui_t *self = (sfizz_ui_t *)ui; + self->uiFrame->setVisible(true); + return 0; +} + +static int +hide(LV2UI_Handle ui) +{ + sfizz_ui_t *self = (sfizz_ui_t *)ui; + self->uiFrame->setVisible(false); + return 0; +} + +static const LV2UI_Show_Interface show_interface = { + &show, + &hide, +}; + +const void * +extension_data(const char *uri) +{ + if (!strcmp(uri, LV2_UI__idleInterface)) + return &idle_interface; + + if (!strcmp(uri, LV2_UI__showInterface)) + return &show_interface; + + return nullptr; +} + +static const LV2UI_Descriptor descriptor = { + SFIZZ_UI_URI, + instantiate, + cleanup, + port_event, + extension_data, +}; + +LV2_SYMBOL_EXPORT +const LV2UI_Descriptor * +lv2ui_descriptor(uint32_t index) +{ +#if LINUX + VSTGUI::initializeSoHandle(); +#endif + + switch (index) + { + case 0: + return &descriptor; + default: + return nullptr; + } +} + +/// +void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) +{ + auto sendFloat = [this](int port, float value) { + write(con, port, sizeof(float), 0, &value); + }; + + auto sendPath = [this](LV2_URID property, const std::string& value) { + LV2_Atom_Forge *forge = &atom_forge; + LV2_Atom_Forge_Frame frame; + alignas(LV2_Atom) uint8_t buffer[MAX_PATH_SIZE + 512]; + auto *atom = reinterpret_cast(buffer); + lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); + if (lv2_atom_forge_object(forge, &frame, 0, patch_set_uri) && + lv2_atom_forge_key(forge, patch_property_uri) && + lv2_atom_forge_urid(forge, property) && + lv2_atom_forge_key(forge, patch_value_uri) && + lv2_atom_forge_path(forge, value.data(), value.size())) + { + lv2_atom_forge_pop(forge, &frame); + write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom); + } + }; + + switch (id) { + case EditId::Volume: + sendFloat(SFIZZ_VOLUME, absl::get(v)); + break; + case EditId::Polyphony: + sendFloat(SFIZZ_POLYPHONY, absl::get(v)); + break; + case EditId::Oversampling: + sendFloat(SFIZZ_OVERSAMPLING, absl::get(v)); + break; + case EditId::PreloadSize: + sendFloat(SFIZZ_PRELOAD, absl::get(v)); + break; + case EditId::ScalaRootKey: + sendFloat(SFIZZ_SCALA_ROOT_KEY, absl::get(v)); + break; + case EditId::TuningFrequency: + sendFloat(SFIZZ_TUNING_FREQUENCY, absl::get(v)); + break; + case EditId::StretchTuning: + sendFloat(SFIZZ_STRETCH_TUNING, absl::get(v)); + break; + case EditId::SfzFile: + sendPath(sfizz_sfz_file_uri, absl::get(v)); + break; + case EditId::ScalaFile: + sendPath(sfizz_scala_file_uri, absl::get(v)); + break; + default: + break; + } +} + +void sfizz_ui_t::uiBeginSend(EditId id) +{ + uiTouch(id, true); +} + +void sfizz_ui_t::uiEndSend(EditId id) +{ + uiTouch(id, false); +} + +void sfizz_ui_t::uiTouch(EditId id, bool t) +{ + if (!touch) + return; + + switch (id) { + case EditId::Volume: + touch->touch(touch->handle, SFIZZ_VOLUME, t); + break; + case EditId::Polyphony: + touch->touch(touch->handle, SFIZZ_POLYPHONY, t); + break; + case EditId::Oversampling: + touch->touch(touch->handle, SFIZZ_OVERSAMPLING, t); + break; + case EditId::PreloadSize: + touch->touch(touch->handle, SFIZZ_PRELOAD, t); + break; + case EditId::ScalaRootKey: + touch->touch(touch->handle, SFIZZ_SCALA_ROOT_KEY, t); + break; + case EditId::TuningFrequency: + touch->touch(touch->handle, SFIZZ_TUNING_FREQUENCY, t); + break; + case EditId::StretchTuning: + touch->touch(touch->handle, SFIZZ_STRETCH_TUNING, t); + break; + default: + break; + } +} + +void sfizz_ui_t::uiSendMIDI(const uint8_t* msg, uint32_t len) +{ + LV2_Atom_Forge *forge = &atom_forge; + alignas(LV2_Atom) uint8_t buffer[512]; + auto *atom = reinterpret_cast(buffer); + lv2_atom_forge_set_buffer(forge, (uint8_t *)&buffer, sizeof(buffer)); + if (lv2_atom_forge_atom(forge, len, midi_event_uri) && + lv2_atom_forge_write(forge, msg, len)) + { + write(con, SFIZZ_CONTROL, lv2_atom_total_size(atom), atom_event_transfer_uri, atom); + } +} diff --git a/lv2/sfizz_ui.ttl.in b/lv2/sfizz_ui.ttl.in new file mode 100644 index 00000000..b5fb3470 --- /dev/null +++ b/lv2/sfizz_ui.ttl.in @@ -0,0 +1,14 @@ +@prefix lv2: . +@prefix ui: . +@prefix urid: . + +<@LV2PLUGIN_URI@#ui> + lv2:extensionData ui:idleInterface ; + lv2:extensionData ui:showInterface ; + lv2:requiredFeature ui:idleInterface ; + lv2:optionalFeature ui:noUserResize ; + lv2:optionalFeature ui:resize ; + lv2:optionalFeature ui:parent ; + lv2:optionalFeature ui:touch ; + lv2:requiredFeature urid:map ; + lv2:requiredFeature urid:unmap . diff --git a/lv2/vstgui_helpers.cpp b/lv2/vstgui_helpers.cpp new file mode 100644 index 00000000..4e8969f6 --- /dev/null +++ b/lv2/vstgui_helpers.cpp @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +// Note(jpc) same code as used in Surge LV2, I am the original author + +#include "vstgui_helpers.h" +#include +#include +#include +#include +#if LINUX +#include +#include +#endif + +#if LINUX +void Lv2IdleRunLoop::execIdle() +{ + std::chrono::steady_clock::time_point tick = std::chrono::steady_clock::now(); + + for (Event& ev : _events) + { + if (!ev.alive) + continue; + +// TODO LV2: fix me, XCB descriptor polling not working at this point +#if 0 + pollfd pfd = {}; + pfd.fd = ev.fd; + pfd.events = POLLIN|POLLERR|POLLHUP; + if (poll(&pfd, 1, 0) > 0) +#endif + { + ev.handler->onEvent(); + } + } + + for (Timer& tm : _timers) + { + if (!tm.alive) + continue; + + if (tm.lastTickValid) + { + std::chrono::steady_clock::duration duration = tick - tm.lastTick; + tm.counter += std::chrono::duration_cast(duration); + if (tm.counter >= tm.interval) + { + tm.handler->onTimer(); + tm.counter = std::min(tm.counter - tm.interval, tm.interval); + } + } + tm.lastTick = tick; + tm.lastTickValid = true; + } + + garbageCollectDeadHandlers(_events); + garbageCollectDeadHandlers(_timers); +} + +bool Lv2IdleRunLoop::registerEventHandler(int fd, VSTGUI::X11::IEventHandler* handler) +{ + // fprintf(stderr, "registerEventHandler %d %p\n", fd, handler); + + Event ev; + ev.fd = fd; + ev.handler = handler; + ev.alive = true; + _events.push_back(ev); + + return true; +} + +bool Lv2IdleRunLoop::unregisterEventHandler(VSTGUI::X11::IEventHandler* handler) +{ + // fprintf(stderr, "unregisterEventHandler %p\n", handler); + + auto it = std::find_if(_events.begin(), _events.end(), [handler](const Event& ev) -> bool { + return ev.handler == handler && ev.alive; + }); + + if (it != _events.end()) + it->alive = false; + + return true; +} + +bool Lv2IdleRunLoop::registerTimer(uint64_t interval, VSTGUI::X11::ITimerHandler* handler) +{ + // fprintf(stderr, "registerTimer %lu %p\n", interval, handler); + + Timer tm; + tm.interval = std::chrono::milliseconds(interval); + tm.counter = std::chrono::microseconds(0); + tm.lastTickValid = false; + tm.handler = handler; + tm.alive = true; + _timers.push_back(tm); + + return true; +} + +bool Lv2IdleRunLoop::unregisterTimer(VSTGUI::X11::ITimerHandler* handler) +{ + // fprintf(stderr, "unregisterTimer %p\n", handler); + + auto it = std::find_if(_timers.begin(), _timers.end(), [handler](const Timer& tm) -> bool { + return tm.handler == handler && tm.alive; + }); + + if (it != _timers.end()) + it->alive = false; + + return true; +} + +template void Lv2IdleRunLoop::garbageCollectDeadHandlers(std::list& handlers) +{ + auto pos = handlers.begin(); + auto end = handlers.end(); + + while (pos != end) + { + auto curPos = pos++; + if (!curPos->alive) + handlers.erase(curPos); + } +} +#endif + +/// +#if LINUX +namespace VSTGUI +{ +void* soHandle = nullptr; + +static volatile bool soHandleInitialized = false; +static std::mutex soHandleMutex; + +struct Dl_handle_deleter +{ + void operator()(void* x) const noexcept + { + dlclose(x); + } +}; +static std::unique_ptr soHandlePointer; +} // namespace VSTGUI + +void VSTGUI::initializeSoHandle() +{ + if (VSTGUI::soHandleInitialized) + return; + + std::lock_guard lock(VSTGUI::soHandleMutex); + if (VSTGUI::soHandleInitialized) + return; + + Dl_info info; + if (dladdr((void*)&lv2ui_descriptor, &info)) + { + VSTGUI::soHandle = dlopen(info.dli_fname, RTLD_LAZY); + VSTGUI::soHandlePointer.reset(VSTGUI::soHandle); + } + VSTGUI::soHandleInitialized = true; +} +#endif diff --git a/lv2/vstgui_helpers.h b/lv2/vstgui_helpers.h new file mode 100644 index 00000000..bb48936e --- /dev/null +++ b/lv2/vstgui_helpers.h @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +// Note(jpc) same code as used in Surge LV2, I am the original author + +#pragma once +#include +#include + +#include "editor/utility/vstgui_before.h" +#include "vstgui/lib/vstguibase.h" +#if LINUX +#include "vstgui/lib/platform/platform_x11.h" +#include "vstgui/lib/platform/linux/x11platform.h" +#endif +#include "editor/utility/vstgui_after.h" + +#if LINUX +class Lv2IdleRunLoop : public VSTGUI::X11::IRunLoop +{ +public: + void execIdle(); + + bool registerEventHandler(int fd, VSTGUI::X11::IEventHandler* handler) override; + bool unregisterEventHandler(VSTGUI::X11::IEventHandler* handler) override; + bool registerTimer(uint64_t interval, VSTGUI::X11::ITimerHandler* handler) override; + bool unregisterTimer(VSTGUI::X11::ITimerHandler* handler) override; + + void forget() override + {} + void remember() override + {} + +private: + struct Event + { + int fd; + VSTGUI::X11::IEventHandler* handler; + bool alive; + }; + struct Timer + { + std::chrono::microseconds interval; + std::chrono::microseconds counter; + bool lastTickValid; + std::chrono::steady_clock::time_point lastTick; + VSTGUI::X11::ITimerHandler* handler; + bool alive; + }; + +private: + template static void garbageCollectDeadHandlers(std::list& handlers); + +private: + std::list _events; + std::list _timers; +}; +#endif + +#if LINUX +namespace VSTGUI +{ +void initializeSoHandle(); +} +#endif diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index 5d0301e6..f96abd80 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -27,9 +27,6 @@ set(VSTPLUGIN_HEADERS SfizzVstState.h X11RunLoop.h) -set(VSTPLUGIN_RESOURCES - logo.png) - add_library(${VSTPLUGIN_PRJ_NAME} MODULE ${VSTPLUGIN_HEADERS} ${VSTPLUGIN_SOURCES}) @@ -71,8 +68,8 @@ endif() # Create the bundle (see "VST 3 Locations / Format") execute_process ( COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") -foreach(res ${VSTPLUGIN_RESOURCES}) - file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/resources/${res}" +foreach(res ${EDITOR_RESOURCES}) + file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources/${res}" DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") endforeach() if(WIN32) From ecde6a4baf7d03cb53c4fae1db1e88ee366c8ffe Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 09:37:39 +0200 Subject: [PATCH 03/24] Allow clang-tidy to find new headers --- scripts/run_clang_tidy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/run_clang_tidy.sh b/scripts/run_clang_tidy.sh index a25f69f9..0f3ff24b 100755 --- a/scripts/run_clang_tidy.sh +++ b/scripts/run_clang_tidy.sh @@ -33,4 +33,5 @@ clang-tidy \ -- -Iexternal/abseil-cpp -Isrc/external -Isrc/external/pugixml/src \ -Isrc/sfizz -Isrc -Isrc/external/spline -Isrc/external/cpuid/src \ -Ivst -Ivst/external/VST_SDK/VST3_SDK -Ivst/external/VST_SDK/VST3_SDK/vstgui4 -Ivst/external/ring_buffer \ + -Ieditor/src \ -DNDEBUG -std=c++17 From 4c9249f713dceea38458a68e4e6cac29cc47d2cd Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 09:42:04 +0200 Subject: [PATCH 04/24] Fix a narrowing conversion failing in MSVC --- editor/src/editor/Editor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index 1024c27d..ea2c8e57 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -282,7 +282,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) void Editor::Impl::createFrameContents() { - const CRect bounds { 0.0, 0.0, viewWidth, viewHeight }; + const CRect bounds { 0.0, 0.0, static_cast(viewWidth), static_cast(viewHeight) }; CViewContainer* view = new CViewContainer(bounds); view_ = view; From f5c735f0f1757edaf131ec75f00b5c42f46078c2 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 09:44:43 +0200 Subject: [PATCH 05/24] appveyor: also copy lv2_ui --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index f1110ee1..d5e329a7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,6 +29,7 @@ build_script: after_build: - cmd: cp sfizz.lv2/Release/sfizz.dll sfizz.lv2/ +- cmd: cp sfizz.lv2/Release/sfizz_ui.dll sfizz.lv2/ - cmd: rm -rf sfizz.lv2/Release - cmd: if %platform%==Win32 set RELEASE_ARCH=x86 - cmd: if %platform%==x64 set RELEASE_ARCH=x64 From 1d58dafa2cd7cd35b98bef520b544289020b8852 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 10:02:41 +0200 Subject: [PATCH 06/24] Fix a problem with variant under minGW --- editor/src/editor/Editor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index ea2c8e57..edad917d 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -909,7 +909,7 @@ void Editor::Impl::valueChanged(CControl* ctl) break; case kTagSetOversampling: - ctrl.uiSendValue(EditId::Oversampling, 1 << static_cast(value)); + ctrl.uiSendValue(EditId::Oversampling, static_cast(1 << static_cast(value))); updateOversamplingLabel(static_cast(value)); break; @@ -936,7 +936,7 @@ void Editor::Impl::valueChanged(CControl* ctl) default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) { int panelId = tag - kTagFirstChangePanel; - ctrl.uiSendValue(EditId::UIActivePanel, panelId); + ctrl.uiSendValue(EditId::UIActivePanel, static_cast(panelId)); setActivePanel(panelId); } break; From 0c0a99c421805d49e3606404665af9261f3d88f6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 10:43:26 +0200 Subject: [PATCH 07/24] Fixes for MinGW --- editor/cmake/Vstgui.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/editor/cmake/Vstgui.cmake b/editor/cmake/Vstgui.cmake index e853b091..2cac1f17 100644 --- a/editor/cmake/Vstgui.cmake +++ b/editor/cmake/Vstgui.cmake @@ -208,12 +208,21 @@ if(${CMAKE_BUILD_TYPE} MATCHES "Release") target_compile_definitions(sfizz-vstgui PRIVATE "RELEASE") endif() +if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # higher C++ requirement on Windows + set_property(TARGET sfizz-vstgui PROPERTY CXX_STANDARD 14) +endif() + if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") target_compile_options(sfizz-vstgui PRIVATE "-Wno-deprecated-copy" + "-Wno-deprecated-declarations" + "-Wno-extra" "-Wno-ignored-qualifiers" + "-Wno-multichar" "-Wno-reorder" "-Wno-sign-compare" + "-Wno-unknown-pragmas" "-Wno-unused-function" "-Wno-unused-parameter" "-Wno-unused-variable") From cf009e61b157bd1538673fca91a5542afb8b1dad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 11:12:29 +0200 Subject: [PATCH 08/24] More changes for MinGW --- editor/src/editor/utility/vstgui_before.h | 2 ++ lv2/sfizz_ui.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/editor/src/editor/utility/vstgui_before.h b/editor/src/editor/utility/vstgui_before.h index bb01d0c3..8293e82b 100644 --- a/editor/src/editor/utility/vstgui_before.h +++ b/editor/src/editor/utility/vstgui_before.h @@ -9,4 +9,6 @@ #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wdeprecated-copy" +#pragma GCC diagnostic ignored "-Wmultichar" +#pragma GCC diagnostic ignored "-Wextra" #endif diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 1cbb49a2..69156dea 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -54,6 +54,9 @@ #include "editor/utility/vstgui_before.h" #include "vstgui/lib/cframe.h" #include "vstgui/lib/platform/iplatformframe.h" +#if defined(_WIN32) +#include "vstgui/lib/platform/platform_win32.h" +#endif #include "editor/utility/vstgui_after.h" using namespace VSTGUI; From 15b198d18649aa6987e2ab69df5f757383d538d0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 11:13:00 +0200 Subject: [PATCH 09/24] Eliminate a warning --- lv2/sfizz_ui.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 69156dea..4c4d49ed 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -315,6 +315,8 @@ idle(LV2UI_Handle ui) #if LINUX self->runLoop->execIdle(); +#else + (void)self; #endif return 0; From 66826ef8795b49658fc154a09ad5d763f0593877 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 11:21:26 +0200 Subject: [PATCH 10/24] Rewrite some preprocessor conditionals --- lv2/sfizz_ui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 4c4d49ed..6baf4021 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -172,9 +172,9 @@ instantiate(const LV2UI_Descriptor *descriptor, // name, and appending "Contents/Resources" (not overridable) // * on Windows, the folder is set programmatically // * on macOS, resource files are looked up using CFBundle APIs -#if _WIN32 +#if defined(_WIN32) IWin32PlatformFrame::setResourceBasePath((std::string(bundle_path) + "\\Contents\\Resources\\").c_str()); -#elif __APPLE__ +#elif defined(__APPLE__) #pragma message("TODO: make resources work on macOS using bundles") #endif From 58fe6fb1156ffddc377f965ee4360aca6a3034d0 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 11:38:23 +0200 Subject: [PATCH 11/24] Define DllMain for VSTGUI --- lv2/vstgui_helpers.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lv2/vstgui_helpers.cpp b/lv2/vstgui_helpers.cpp index 4e8969f6..43ff0901 100644 --- a/lv2/vstgui_helpers.cpp +++ b/lv2/vstgui_helpers.cpp @@ -15,6 +15,9 @@ #include #include #endif +#if WINDOWS +#include +#endif #if LINUX void Lv2IdleRunLoop::execIdle() @@ -168,3 +171,16 @@ void VSTGUI::initializeSoHandle() VSTGUI::soHandleInitialized = true; } #endif + +/// +#if WINDOWS +void* hInstance = nullptr; + +__declspec(dllexport) +BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID) +{ + if (reason == DLL_PROCESS_ATTACH) + hInstance = dllInstance; + return TRUE; +} +#endif From 1904aec674e9443737ce2f16d11135b9f066b31e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 12:52:23 +0200 Subject: [PATCH 12/24] Replace absl::variant --- editor/CMakeLists.txt | 2 +- editor/src/editor/EditValue.h | 67 ++++++++++++++++++++++++++++ editor/src/editor/Editor.cpp | 32 ++++++------- editor/src/editor/EditorController.h | 4 +- lv2/sfizz_ui.cpp | 18 ++++---- vst/SfizzVstEditor.cpp | 20 ++++----- 6 files changed, 105 insertions(+), 38 deletions(-) create mode 100644 editor/src/editor/EditValue.h diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 777939d4..65cdb6d9 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -18,4 +18,4 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL src/editor/utility/vstgui_before.h) target_include_directories(sfizz_editor PUBLIC "src") target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui) -target_link_libraries(sfizz_editor PUBLIC absl::strings absl::variant) +target_link_libraries(sfizz_editor PUBLIC absl::strings) diff --git a/editor/src/editor/EditValue.h b/editor/src/editor/EditValue.h new file mode 100644 index 00000000..b8d911dd --- /dev/null +++ b/editor/src/editor/EditValue.h @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: BSD-2-Clause + +// This code is part of the sfizz library and is licensed under a BSD 2-clause +// license. You should have receive a LICENSE.md file along with the code. +// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz + +#pragma once +#include +#include +#include + +class EditValue { +public: + constexpr EditValue() : tag(Nil) {} + EditValue(float value) { reset(value); } + EditValue(std::string value) { reset(value); } + ~EditValue() { reset(); } + + void reset() noexcept + { + if (tag == String) + destruct(u.s); + tag = Nil; + } + + void reset(float value) noexcept + { + reset(); + u.f = value; + tag = Float; + } + + void reset(std::string value) noexcept + { + reset(); + new (&u.s) std::string(std::move(value)); + tag = String; + } + + float to_float() const + { + if (tag != Float) + throw std::runtime_error("the tagged union does not contain `float`"); + return u.f; + } + + const std::string& to_string() const + { + if (tag != String) + throw std::runtime_error("the tagged union does not contain `string`"); + return u.s; + } + +private: + template static void destruct(T& obj) { obj.~T(); } + +private: + enum TypeTag { Nil, Float, String }; + union Union { + constexpr explicit Union(float f = 0.0f) noexcept : f(f) {} + ~Union() noexcept {} + float f; + std::string s; + }; + TypeTag tag { Nil }; + Union u; +}; diff --git a/editor/src/editor/Editor.cpp b/editor/src/editor/Editor.cpp index edad917d..dccae14c 100644 --- a/editor/src/editor/Editor.cpp +++ b/editor/src/editor/Editor.cpp @@ -158,13 +158,13 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) switch (id) { case EditId::SfzFile: { - const std::string& value = absl::get(v); + const std::string& value = v.to_string(); updateSfzFileLabel(value); } break; case EditId::Volume: { - const float value = absl::get(v); + const float value = v.to_float(); if (volumeSlider_) volumeSlider_->setValue(value); updateVolumeLabel(value); @@ -172,7 +172,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::Polyphony: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (numVoicesSlider_) numVoicesSlider_->setValue(value); updateNumVoicesLabel(value); @@ -180,7 +180,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::Oversampling: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); int log2Value = 0; for (int f = value; f > 1; f /= 2) @@ -193,7 +193,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::PreloadSize: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (preloadSizeSlider_) preloadSizeSlider_->setValue(value); updatePreloadSizeLabel(value); @@ -201,13 +201,13 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::ScalaFile: { - const std::string& value = absl::get(v); + const std::string& value = v.to_string(); updateScalaFileLabel(value); } break; case EditId::ScalaRootKey: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (scalaRootKeySlider_) scalaRootKeySlider_->setValue(value); updateScalaRootKeyLabel(value); @@ -215,7 +215,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::TuningFrequency: { - const float value = absl::get(v); + const float value = v.to_float(); if (tuningFrequencySlider_) tuningFrequencySlider_->setValue(value); updateTuningFrequencyLabel(value); @@ -223,7 +223,7 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::StretchTuning: { - const float value = absl::get(v); + const float value = v.to_float(); if (stretchedTuningSlider_) stretchedTuningSlider_->setValue(value); updateStretchedTuningLabel(value); @@ -231,49 +231,49 @@ void Editor::Impl::uiReceiveValue(EditId id, const EditValue& v) break; case EditId::UINumCurves: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoCurvesLabel_) formatLabel(label, "%u", value); } break; case EditId::UINumMasters: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoMastersLabel_) formatLabel(label, "%u", value); } break; case EditId::UINumGroups: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoGroupsLabel_) formatLabel(label, "%u", value); } break; case EditId::UINumRegions: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoRegionsLabel_) formatLabel(label, "%u", value); } break; case EditId::UINumPreloadedSamples: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoSamplesLabel_) formatLabel(label, "%u", value); } break; case EditId::UINumActiveVoices: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); if (CTextLabel* label = infoVoicesLabel_) formatLabel(label, "%u", value); } break; case EditId::UIActivePanel: { - const int value = static_cast(absl::get(v)); + const int value = static_cast(v.to_float()); setActivePanel(value); } break; diff --git a/editor/src/editor/EditorController.h b/editor/src/editor/EditorController.h index 6b6988c1..4d3db4c9 100644 --- a/editor/src/editor/EditorController.h +++ b/editor/src/editor/EditorController.h @@ -5,11 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "EditValue.h" #include -#include +#include #include enum class EditId : int; -typedef absl::variant EditValue; class EditorController { public: diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 6baf4021..069d4942 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -410,31 +410,31 @@ void sfizz_ui_t::uiSendValue(EditId id, const EditValue& v) switch (id) { case EditId::Volume: - sendFloat(SFIZZ_VOLUME, absl::get(v)); + sendFloat(SFIZZ_VOLUME, v.to_float()); break; case EditId::Polyphony: - sendFloat(SFIZZ_POLYPHONY, absl::get(v)); + sendFloat(SFIZZ_POLYPHONY, v.to_float()); break; case EditId::Oversampling: - sendFloat(SFIZZ_OVERSAMPLING, absl::get(v)); + sendFloat(SFIZZ_OVERSAMPLING, v.to_float()); break; case EditId::PreloadSize: - sendFloat(SFIZZ_PRELOAD, absl::get(v)); + sendFloat(SFIZZ_PRELOAD, v.to_float()); break; case EditId::ScalaRootKey: - sendFloat(SFIZZ_SCALA_ROOT_KEY, absl::get(v)); + sendFloat(SFIZZ_SCALA_ROOT_KEY, v.to_float()); break; case EditId::TuningFrequency: - sendFloat(SFIZZ_TUNING_FREQUENCY, absl::get(v)); + sendFloat(SFIZZ_TUNING_FREQUENCY, v.to_float()); break; case EditId::StretchTuning: - sendFloat(SFIZZ_STRETCH_TUNING, absl::get(v)); + sendFloat(SFIZZ_STRETCH_TUNING, v.to_float()); break; case EditId::SfzFile: - sendPath(sfizz_sfz_file_uri, absl::get(v)); + sendPath(sfizz_sfz_file_uri, v.to_string()); break; case EditId::ScalaFile: - sendPath(sfizz_scala_file_uri, absl::get(v)); + sendPath(sfizz_scala_file_uri, v.to_string()); break; default: break; diff --git a/vst/SfizzVstEditor.cpp b/vst/SfizzVstEditor.cpp index 163034cc..1d0a127f 100644 --- a/vst/SfizzVstEditor.cpp +++ b/vst/SfizzVstEditor.cpp @@ -109,9 +109,9 @@ void SfizzVstEditor::onStateChanged() void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) { if (id == EditId::SfzFile) - loadSfzFile(absl::get(v)); + loadSfzFile(v.to_string()); else if (id == EditId::ScalaFile) - loadScalaFile(absl::get(v)); + loadScalaFile(v.to_string()); else { SfizzVstController* ctrl = getController(); @@ -123,14 +123,14 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) switch (id) { case EditId::Volume: - normalizeAndSet(kPidVolume, kParamVolumeRange, absl::get(v)); + normalizeAndSet(kPidVolume, kParamVolumeRange, v.to_float()); break; case EditId::Polyphony: - normalizeAndSet(kPidNumVoices, kParamNumVoicesRange, absl::get(v)); + normalizeAndSet(kPidNumVoices, kParamNumVoicesRange, v.to_float()); break; case EditId::Oversampling: { - const int32 value = static_cast(absl::get(v)); + const int32 value = static_cast(v.to_float()); int32 log2Value = 0; for (int32 f = value; f > 1; f /= 2) @@ -140,20 +140,20 @@ void SfizzVstEditor::uiSendValue(EditId id, const EditValue& v) } break; case EditId::PreloadSize: - normalizeAndSet(kPidPreloadSize, kParamPreloadSizeRange, absl::get(v)); + normalizeAndSet(kPidPreloadSize, kParamPreloadSizeRange, v.to_float()); break; case EditId::ScalaRootKey: - normalizeAndSet(kPidScalaRootKey, kParamScalaRootKeyRange, absl::get(v)); + normalizeAndSet(kPidScalaRootKey, kParamScalaRootKeyRange, v.to_float()); break; case EditId::TuningFrequency: - normalizeAndSet(kPidTuningFrequency, kParamTuningFrequencyRange, absl::get(v)); + normalizeAndSet(kPidTuningFrequency, kParamTuningFrequencyRange, v.to_float()); break; case EditId::StretchTuning: - normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, absl::get(v)); + normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, v.to_float()); break; case EditId::UIActivePanel: - ctrl->getSfizzUiState().activePanel = static_cast(absl::get(v)); + ctrl->getSfizzUiState().activePanel = static_cast(v.to_float()); break; default: From 1fd771049354cb747fea657596cf209599a0d540 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 13:09:07 +0200 Subject: [PATCH 13/24] Try cmake hack which disables Release/ output dir in MSVC --- appveyor.yml | 3 --- lv2/CMakeLists.txt | 4 ++-- vst/CMakeLists.txt | 13 ++++--------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index d5e329a7..ebc8dc20 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,9 +28,6 @@ build_script: - cmd: cmake --build . --config Release -j after_build: -- cmd: cp sfizz.lv2/Release/sfizz.dll sfizz.lv2/ -- cmd: cp sfizz.lv2/Release/sfizz_ui.dll sfizz.lv2/ -- cmd: rm -rf sfizz.lv2/Release - cmd: if %platform%==Win32 set RELEASE_ARCH=x86 - cmd: if %platform%==x64 set RELEASE_ARCH=x64 - cmd: 7z a sfizz-lv2-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.lv2 diff --git a/lv2/CMakeLists.txt b/lv2/CMakeLists.txt index c45f964f..3322d3d1 100644 --- a/lv2/CMakeLists.txt +++ b/lv2/CMakeLists.txt @@ -62,12 +62,12 @@ endif() # /lv2/.lv2/. set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES PREFIX "") set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}") -set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary") +set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") if (SFIZZ_LV2_UI) set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES PREFIX "") set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES OUTPUT_NAME "${PROJECT_NAME}_ui") - set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary") + set_target_properties (${LV2PLUGIN_PRJ_NAME}_ui PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/Contents/Binary/$<0:>") endif() # Generate *.ttl files from *.in sources, diff --git a/vst/CMakeLists.txt b/vst/CMakeLists.txt index f96abd80..c4b3538e 100644 --- a/vst/CMakeLists.txt +++ b/vst/CMakeLists.txt @@ -75,19 +75,14 @@ endforeach() if(WIN32) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES SUFFIX ".vst3" - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") - foreach(config ${CMAKE_CONFIGURATION_TYPES}) - string(TOUPPER "${config}" config) - set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES - "LIBRARY_OUTPUT_DIRECTORY_${config}" "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win") - endforeach() + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-win/$<0:>") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/win/Plugin.ico" "${CMAKE_CURRENT_SOURCE_DIR}/win/desktop.ini" DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}") elseif(APPLE) set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES SUFFIX "" - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/MacOS/$<0:>") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo" DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents") set(SFIZZ_VST3_BUNDLE_EXECUTABLE "${PROJECT_NAME}") @@ -98,7 +93,7 @@ elseif(APPLE) DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources") else() set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/${VST3_PACKAGE_ARCHITECTURE}-linux/$<0:>") endif() file(COPY "gpl-3.0.txt" @@ -233,7 +228,7 @@ elseif(SFIZZ_AU) COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/Resources") set_target_properties(${AUPLUGIN_PRJ_NAME} PROPERTIES SUFFIX "" - LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/MacOS") + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents/MacOS/$<0:>") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo" DESTINATION "${PROJECT_BINARY_DIR}/${AUPLUGIN_BUNDLE_NAME}/Contents") set(SFIZZ_AU_BUNDLE_EXECUTABLE "${PROJECT_NAME}") From eed54ec8414850143e40195863a71b315e7c02c5 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 20:07:46 +0200 Subject: [PATCH 14/24] Correct a mistake in french text --- lv2/sfizz.ttl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lv2/sfizz.ttl.in b/lv2/sfizz.ttl.in index f4090158..cddda959 100644 --- a/lv2/sfizz.ttl.in +++ b/lv2/sfizz.ttl.in @@ -362,7 +362,7 @@ midnam:update a lv2:Feature . lv2:index 16 ; lv2:symbol "num_regions" ; lv2:name "Number of regions", - "Nombre de regions"@fr ; + "Nombre de régions"@fr ; pg:group <@LV2PLUGIN_URI@#status> ; lv2:portProperty lv2:integer ; lv2:default 0 ; From 166be3c84398e596d0f6fd4f153ebe4d8b4429dc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 20:16:48 +0200 Subject: [PATCH 15/24] Update innosetup --- scripts/innosetup.iss.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index d97d3f2b..0b4aa85a 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -49,6 +49,7 @@ Name: "vst3"; Description: "VST3 plugin"; Types: full custom; [Files] Source: "sfizz.lv2\sfizz.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"; Flags: ignoreversion +Source: "sfizz.lv2\sfizz_ui.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"; Flags: ignoreversion Source: "sfizz.lv2\manifest.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" Source: "sfizz.lv2\sfizz.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" Source: "sfizz.lv2\lgpl-3.0.txt"; Components: main; DestDir: "{app}" From 7417cd23ab2a35249d3646b436f0f219227ea29b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 20:32:58 +0200 Subject: [PATCH 16/24] Attempt to fix LV2 Vstgui on macOS --- lv2/sfizz_ui.cpp | 3 +++ lv2/vstgui_helpers.cpp | 38 ++++++++++++++++++++++++++++++++++++++ lv2/vstgui_helpers.h | 7 +++++++ 3 files changed, 48 insertions(+) diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 069d4942..b7fe308b 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -374,6 +374,9 @@ lv2ui_descriptor(uint32_t index) #if LINUX VSTGUI::initializeSoHandle(); #endif +#if MAC + VSTGUI::initializeBundleRef(); +#endif switch (index) { diff --git a/lv2/vstgui_helpers.cpp b/lv2/vstgui_helpers.cpp index 43ff0901..d1ad3187 100644 --- a/lv2/vstgui_helpers.cpp +++ b/lv2/vstgui_helpers.cpp @@ -18,6 +18,9 @@ #if WINDOWS #include #endif +#if MAC +#include "vstgui/plugin-bindings/getpluginbundle.h" +#endif #if LINUX void Lv2IdleRunLoop::execIdle() @@ -184,3 +187,38 @@ BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID) return TRUE; } #endif + +/// +#if MAC +namespace VSTGUI +{ +void* gBundleRef = nullptr; + +static volatile bool gBundleRefInitialized = false; +static std::mutex gBundleRefMutex; + +struct CFBundle_deleter { + void operator()(CFBundleRef x) const noexcept + { + CFRelease(x); + } +}; +static std::unique_ptr<__CFBundle, CFBundle_deleter> gBundleRefPointer; +} // namespace VSTGUI + +void VSTGUI::initializeBundleRef() +{ + if (VSTGUI::gBundleRefInitialized) + return; + + std::lock_guard lock(VSTGUI::gBundleRefMutex); + if (VSTGUI::gBundleRefInitialized) + return; + + CFBundleRef bundleRef = GetPluginBundle(); + VSTGUI::gBundleRef = bundleRef; + VSTGUI::gBundleRefPointer.reset(bundleRef); + + VSTGUI::gBundleRefInitialized = true; +} +#endif diff --git a/lv2/vstgui_helpers.h b/lv2/vstgui_helpers.h index bb48936e..8367a2c4 100644 --- a/lv2/vstgui_helpers.h +++ b/lv2/vstgui_helpers.h @@ -66,3 +66,10 @@ namespace VSTGUI void initializeSoHandle(); } #endif + +#if MAC +namespace VSTGUI +{ +void initializeBundleRef(); +} +#endif From 833606aef9f2e75a50d56a728738c9a17261a958 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 20:38:56 +0200 Subject: [PATCH 17/24] Update innosetup --- scripts/innosetup.iss.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/innosetup.iss.in b/scripts/innosetup.iss.in index 0b4aa85a..b287de6a 100644 --- a/scripts/innosetup.iss.in +++ b/scripts/innosetup.iss.in @@ -48,10 +48,14 @@ Name: "lv2"; Description: "LV2 plugin"; Types: full custom; Name: "vst3"; Description: "VST3 plugin"; Types: full custom; [Files] -Source: "sfizz.lv2\sfizz.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"; Flags: ignoreversion -Source: "sfizz.lv2\sfizz_ui.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"; Flags: ignoreversion +Source: "sfizz.lv2\Contents\Binary\sfizz.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Binary"; Flags: ignoreversion +Source: "sfizz.lv2\Contents\Binary\sfizz_ui.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Binary"; Flags: ignoreversion +Source: "sfizz.lv2\Contents\Resources\DefaultInstrument.sfz"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources" +Source: "sfizz.lv2\Contents\Resources\DefaultScale.scl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources" +Source: "sfizz.lv2\Contents\Resources\logo.png"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources" Source: "sfizz.lv2\manifest.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" Source: "sfizz.lv2\sfizz.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" +Source: "sfizz.lv2\sfizz_ui.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2" Source: "sfizz.lv2\lgpl-3.0.txt"; Components: main; DestDir: "{app}" Source: "sfizz.lv2\LICENSE.md"; Components: main; DestDir: "{app}" Source: "sfizz.vst3\desktop.ini"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3" From d008fb3bc8677188b9a60344b7020e7f462d77db Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Mon, 31 Aug 2020 23:15:54 +0200 Subject: [PATCH 18/24] Bundle checked to work on macOS, remove message [ci skip] --- lv2/sfizz_ui.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index b7fe308b..020f5989 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -174,8 +174,6 @@ instantiate(const LV2UI_Descriptor *descriptor, // * on macOS, resource files are looked up using CFBundle APIs #if defined(_WIN32) IWin32PlatformFrame::setResourceBasePath((std::string(bundle_path) + "\\Contents\\Resources\\").c_str()); -#elif defined(__APPLE__) - #pragma message("TODO: make resources work on macOS using bundles") #endif // makes labels refresh correctly From c27b3cb192406d5d26507c875a5da046190a089f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 2 Sep 2020 10:22:49 +0200 Subject: [PATCH 19/24] Set draw mode in the slider painter --- editor/src/editor/GUIComponents.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/editor/src/editor/GUIComponents.cpp b/editor/src/editor/GUIComponents.cpp index 56fb6f8e..a85bf64b 100644 --- a/editor/src/editor/GUIComponents.cpp +++ b/editor/src/editor/GUIComponents.cpp @@ -28,6 +28,8 @@ void SimpleSlider::draw(CDrawContext* dc) CRect bounds = getViewSize(); CRect handle = calculateHandleRect(getValueNormalized()); + dc->setDrawMode(kAntiAliasing); + dc->setFrameColor(_frame); dc->drawRect(bounds, kDrawStroked); From 1ef7631cc8c51ccee5e73f75e9f7a169e33414b6 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 2 Sep 2020 11:23:50 +0200 Subject: [PATCH 20/24] Update to custom Vstgui which fixes drawing issues --- editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/external/vstgui4 b/editor/external/vstgui4 index c6a7f607..ecb6892f 160000 --- a/editor/external/vstgui4 +++ b/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit c6a7f607c21a7353e922a6d45e54d6c56d5a6745 +Subproject commit ecb6892fea8a1aa7671376b6306724f8fababc1a From 239195ae74abad0689b902b26f7753591b06b95b Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Wed, 2 Sep 2020 14:06:25 +0200 Subject: [PATCH 21/24] Update of vstgui to resolve a coordinate problem --- editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/external/vstgui4 b/editor/external/vstgui4 index ecb6892f..8390d355 160000 --- a/editor/external/vstgui4 +++ b/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit ecb6892fea8a1aa7671376b6306724f8fababc1a +Subproject commit 8390d355fb65c6426d22a97de16a39a1be673481 From 026875ae98e50d2ab898c6053062992135c3b845 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 4 Sep 2020 07:57:14 +0200 Subject: [PATCH 22/24] Update vstgui to fix cairo font matching --- editor/external/vstgui4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/external/vstgui4 b/editor/external/vstgui4 index 8390d355..7316f9fb 160000 --- a/editor/external/vstgui4 +++ b/editor/external/vstgui4 @@ -1 +1 @@ -Subproject commit 8390d355fb65c6426d22a97de16a39a1be673481 +Subproject commit 7316f9fb2891b9f0e2a408cfbf4ec35aeec268bd From 174194ebd2df2795b516bee906b04efe0c5f59bc Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 4 Sep 2020 10:30:03 +0200 Subject: [PATCH 23/24] Fix a plugin crash on closing UI --- lv2/sfizz_ui.cpp | 13 +++--- lv2/vstgui_helpers.cpp | 90 +++++++++++++++++++----------------------- lv2/vstgui_helpers.h | 18 ++++++++- 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/lv2/sfizz_ui.cpp b/lv2/sfizz_ui.cpp index 020f5989..10ed2cbe 100644 --- a/lv2/sfizz_ui.cpp +++ b/lv2/sfizz_ui.cpp @@ -74,6 +74,12 @@ typedef std::unique_ptr FrameHolder; /// struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { +#if LINUX + SoHandleInitializer soHandleInitializer; +#endif +#if MAC + BundleRefInitializer bundleRefInitializer; +#endif LV2UI_Write_Function write = nullptr; LV2UI_Controller con = nullptr; LV2_URID_Map *map = nullptr; @@ -369,13 +375,6 @@ LV2_SYMBOL_EXPORT const LV2UI_Descriptor * lv2ui_descriptor(uint32_t index) { -#if LINUX - VSTGUI::initializeSoHandle(); -#endif -#if MAC - VSTGUI::initializeBundleRef(); -#endif - switch (index) { case 0: diff --git a/lv2/vstgui_helpers.cpp b/lv2/vstgui_helpers.cpp index d1ad3187..0a402a20 100644 --- a/lv2/vstgui_helpers.cpp +++ b/lv2/vstgui_helpers.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #if LINUX #include #include @@ -143,36 +144,31 @@ namespace VSTGUI { void* soHandle = nullptr; -static volatile bool soHandleInitialized = false; +static volatile size_t soHandleCount = 0; static std::mutex soHandleMutex; -struct Dl_handle_deleter +SoHandleInitializer::SoHandleInitializer() { - void operator()(void* x) const noexcept - { - dlclose(x); - } -}; -static std::unique_ptr soHandlePointer; -} // namespace VSTGUI - -void VSTGUI::initializeSoHandle() -{ - if (VSTGUI::soHandleInitialized) - return; - - std::lock_guard lock(VSTGUI::soHandleMutex); - if (VSTGUI::soHandleInitialized) - return; - - Dl_info info; - if (dladdr((void*)&lv2ui_descriptor, &info)) - { - VSTGUI::soHandle = dlopen(info.dli_fname, RTLD_LAZY); - VSTGUI::soHandlePointer.reset(VSTGUI::soHandle); - } - VSTGUI::soHandleInitialized = true; + std::lock_guard lock(soHandleMutex); + if (soHandleCount++ == 0) { + Dl_info info; + if (dladdr((void*)&lv2ui_descriptor, &info)) + soHandle = dlopen(info.dli_fname, RTLD_LAZY); + if (!soHandle) + throw std::runtime_error("SoHandleInitializer"); + } } + +SoHandleInitializer::~SoHandleInitializer() +{ + std::lock_guard lock(soHandleMutex); + if (--soHandleCount == 0) { + dlclose(soHandle); + soHandle = nullptr; + } +} + +} // namespace VSTGUI #endif /// @@ -194,31 +190,27 @@ namespace VSTGUI { void* gBundleRef = nullptr; -static volatile bool gBundleRefInitialized = false; +static volatile size_t gBundleRefCount = 0; static std::mutex gBundleRefMutex; -struct CFBundle_deleter { - void operator()(CFBundleRef x) const noexcept - { - CFRelease(x); - } -}; -static std::unique_ptr<__CFBundle, CFBundle_deleter> gBundleRefPointer; -} // namespace VSTGUI - -void VSTGUI::initializeBundleRef() +BundleRefInitializer::BundleRefInitializer() { - if (VSTGUI::gBundleRefInitialized) - return; - - std::lock_guard lock(VSTGUI::gBundleRefMutex); - if (VSTGUI::gBundleRefInitialized) - return; - - CFBundleRef bundleRef = GetPluginBundle(); - VSTGUI::gBundleRef = bundleRef; - VSTGUI::gBundleRefPointer.reset(bundleRef); - - VSTGUI::gBundleRefInitialized = true; + std::lock_guard lock(gBundleRefMutex); + if (bundleRefCount++ == 0) { + gBundleRef = GetPluginBundle(); + if (!gBundleRef) + throw std::runtime_error("BundleRefInitializer"); + } } + +BundleRefInitializer::~BundleRefInitializer() +{ + std::lock_guard lock(gBundleRefMutex); + if (--bundleRefCount == 0) { + CFRelease((CFBundleRef)gBundleRef); + gBundleRef = nullptr; + } +} + +} // namespace VSTGUI #endif diff --git a/lv2/vstgui_helpers.h b/lv2/vstgui_helpers.h index 8367a2c4..2fbcd841 100644 --- a/lv2/vstgui_helpers.h +++ b/lv2/vstgui_helpers.h @@ -63,13 +63,27 @@ private: #if LINUX namespace VSTGUI { -void initializeSoHandle(); +class SoHandleInitializer { +public: + SoHandleInitializer(); + ~SoHandleInitializer(); +private: + SoHandleInitializer(const SoHandleInitializer&) = delete; + SoHandleInitializer& operator=(const SoHandleInitializer&) = delete; +}; } #endif #if MAC namespace VSTGUI { -void initializeBundleRef(); +class BundleRefInitializer { +public: + BundleRefInitializer(); + ~BundleRefInitializer(); +private: + BundleRefInitializer(const BundleRefInitializer&) = delete; + BundleRefInitializer& operator=(const BundleRefInitializer&) = delete; +}; } #endif From 2512d8047fe1f498aec0b518bbc0d5cf5e60d23f Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Fri, 4 Sep 2020 11:04:04 +0200 Subject: [PATCH 24/24] Try to repair the macOS build --- lv2/vstgui_helpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lv2/vstgui_helpers.cpp b/lv2/vstgui_helpers.cpp index 0a402a20..31637bb0 100644 --- a/lv2/vstgui_helpers.cpp +++ b/lv2/vstgui_helpers.cpp @@ -196,7 +196,7 @@ static std::mutex gBundleRefMutex; BundleRefInitializer::BundleRefInitializer() { std::lock_guard lock(gBundleRefMutex); - if (bundleRefCount++ == 0) { + if (gBundleRefCount++ == 0) { gBundleRef = GetPluginBundle(); if (!gBundleRef) throw std::runtime_error("BundleRefInitializer"); @@ -206,7 +206,7 @@ BundleRefInitializer::BundleRefInitializer() BundleRefInitializer::~BundleRefInitializer() { std::lock_guard lock(gBundleRefMutex); - if (--bundleRefCount == 0) { + if (--gBundleRefCount == 0) { CFRelease((CFBundleRef)gBundleRef); gBundleRef = nullptr; }