Merge pull request #397 from jpcima/editor-vstgui-lv2

Editor vstgui lv2
This commit is contained in:
JP Cimalando 2020-09-04 11:35:18 +02:00 committed by GitHub
commit acce5d44f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 2685 additions and 1116 deletions

2
.gitmodules vendored
View file

@ -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

View file

@ -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:

View file

@ -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

View file

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

View file

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

View file

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

View file

@ -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 \
..

View file

@ -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()

View file

@ -28,8 +28,6 @@ build_script:
- cmd: cmake --build . --config Release -j
after_build:
- cmd: cp sfizz.lv2/Release/sfizz.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

View file

@ -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}]")

View file

@ -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}

21
editor/CMakeLists.txt Normal file
View file

@ -0,0 +1,21 @@
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
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)
target_link_libraries(sfizz_editor PUBLIC absl::strings)

229
editor/cmake/Vstgui.cmake Normal file
View file

@ -0,0 +1,229 @@
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()
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")
endif()

1
editor/external/vstgui4 vendored Submodule

@ -0,0 +1 @@
Subproject commit 7316f9fb2891b9f0e2a408cfbf4ec35aeec268bd

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -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 };
}
}

View file

@ -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 <cassert>
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);
};

View file

@ -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 <string>
#include <new>
#include <stdexcept>
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 <class T> 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;
};

View file

@ -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 <absl/strings/string_view.h>
#include <cstdarg>
#include <cstdio>
#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<CViewContainer> 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 <class Control>
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 = v.to_string();
updateSfzFileLabel(value);
}
break;
case EditId::Volume:
{
const float value = v.to_float();
if (volumeSlider_)
volumeSlider_->setValue(value);
updateVolumeLabel(value);
}
break;
case EditId::Polyphony:
{
const int value = static_cast<int>(v.to_float());
if (numVoicesSlider_)
numVoicesSlider_->setValue(value);
updateNumVoicesLabel(value);
}
break;
case EditId::Oversampling:
{
const int value = static_cast<int>(v.to_float());
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<int>(v.to_float());
if (preloadSizeSlider_)
preloadSizeSlider_->setValue(value);
updatePreloadSizeLabel(value);
}
break;
case EditId::ScalaFile:
{
const std::string& value = v.to_string();
updateScalaFileLabel(value);
}
break;
case EditId::ScalaRootKey:
{
const int value = static_cast<int>(v.to_float());
if (scalaRootKeySlider_)
scalaRootKeySlider_->setValue(value);
updateScalaRootKeyLabel(value);
}
break;
case EditId::TuningFrequency:
{
const float value = v.to_float();
if (tuningFrequencySlider_)
tuningFrequencySlider_->setValue(value);
updateTuningFrequencyLabel(value);
}
break;
case EditId::StretchTuning:
{
const float value = v.to_float();
if (stretchedTuningSlider_)
stretchedTuningSlider_->setValue(value);
updateStretchedTuningLabel(value);
}
break;
case EditId::UINumCurves:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoCurvesLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UINumMasters:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoMastersLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UINumGroups:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoGroupsLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UINumRegions:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoRegionsLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UINumPreloadedSamples:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoSamplesLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UINumActiveVoices:
{
const int value = static_cast<int>(v.to_float());
if (CTextLabel* label = infoVoicesLabel_)
formatLabel(label, "%u", value);
}
break;
case EditId::UIActivePanel:
{
const int value = static_cast<int>(v.to_float());
setActivePanel(value);
}
break;
}
}
void Editor::Impl::createFrameContents()
{
const CRect bounds { 0.0, 0.0, static_cast<CCoord>(viewWidth), static_cast<CCoord>(viewHeight) };
CViewContainer* view = new CViewContainer(bounds);
view_ = view;
view->setBackgroundColor(CColor(0xff, 0xff, 0xff));
SharedPointer<CBitmap> 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<CNewFileSelector> 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<CNewFileSelector> 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 = "<No file>";
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<int>(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<int>(value));
break;
case kTagSetOversampling:
ctrl.uiSendValue(EditId::Oversampling, static_cast<float>(1 << static_cast<int>(value)));
updateOversamplingLabel(static_cast<int>(value));
break;
case kTagSetPreloadSize:
ctrl.uiSendValue(EditId::PreloadSize, value);
updatePreloadSizeLabel(static_cast<int>(value));
break;
case kTagSetScalaRootKey:
ctrl.uiSendValue(EditId::ScalaRootKey, value);
updateScalaRootKeyLabel(static_cast<int>(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, static_cast<float>(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);
}

View file

@ -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 <memory>
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> impl_;
};

View file

@ -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 "EditValue.h"
#include <absl/strings/string_view.h>
#include <string>
#include <cstdint>
enum class EditId : int;
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);
}

View file

@ -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)
@ -25,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);

View file

@ -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;

View file

@ -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

View file

@ -0,0 +1,14 @@
// 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"
#pragma GCC diagnostic ignored "-Wmultichar"
#pragma GCC diagnostic ignored "-Wextra"
#endif

View file

@ -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,33 +23,63 @@ 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
# <build_dir>/lv2/<plugin_name>_lv2.<ext> to
# <build_dir>/lv2/<plugin_name>.lv2/<plugin_name>.<ext>
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/$<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/$<0:>")
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_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()
@ -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}

4
lv2/lv2ui.version Normal file
View file

@ -0,0 +1,4 @@
LV2UIABI_1.0 {
global: *lv2ui_descriptor*;
local: *;
};

View file

@ -1,7 +1,13 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
<@LV2PLUGIN_URI@>
a lv2:Plugin ;
lv2:binary <@PROJECT_NAME@@CMAKE_SHARED_MODULE_SUFFIX@> ;
lv2:binary <Contents/Binary/@PROJECT_NAME@@CMAKE_SHARED_MODULE_SUFFIX@> ;
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 <Contents/Binary/@PROJECT_NAME@_ui@CMAKE_SHARED_MODULE_SUFFIX@> ;
@LV2PLUGIN_IF_ENABLE_UI@ rdfs:seeAlso <@PROJECT_NAME@_ui.ttl> .

View file

@ -32,6 +32,9 @@
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "sfizz_lv2.h"
#include <lv2/atom/atom.h>
#include <lv2/atom/forge.h>
#include <lv2/atom/util.h>
#include <lv2/buf-size/buf-size.h>
@ -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;

View file

@ -13,6 +13,7 @@
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix state: <http://lv2plug.in/ns/ext/state#> .
@prefix time: <http://lv2plug.in/ns/ext/time#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@prefix work: <http://lv2plug.in/ns/ext/worker#> .
@ -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 régions"@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 ;
] .

43
lv2/sfizz_lv2.h Normal file
View file

@ -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,
};

497
lv2/sfizz_ui.cpp Normal file
View file

@ -0,0 +1,497 @@
/*
SPDX-License-Identifier: ISC
Sfizz LV2 plugin
Copyright 2019-2020, Paul Ferrand <paul@ferrand.cc>
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 <d@drobilla.net>
Copyright 2011 Gabriel M. Beddingfield <gabriel@teuton.org>
Copyright 2011 James Morris <jwm.art.net@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
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 <lv2/ui/ui.h>
#include <lv2/atom/atom.h>
#include <lv2/atom/forge.h>
#include <lv2/atom/util.h>
#include <lv2/midi/midi.h>
#include <lv2/patch/patch.h>
#include <lv2/urid/urid.h>
#include <string>
#include <memory>
#include <cstring>
#include <cstdio>
#include "vstgui_helpers.h"
#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;
///
struct FrameHolderDeleter {
void operator()(CFrame* frame) const
{
if (frame->getNbReference() != 1)
frame->forget();
else
frame->close();
}
};
typedef std::unique_ptr<CFrame, FrameHolderDeleter> 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;
LV2_URID_Unmap *unmap = nullptr;
LV2UI_Resize *resize = nullptr;
LV2UI_Touch *touch = nullptr;
std::unique_ptr<Editor> editor;
FrameHolder uiFrame;
#if LINUX
SharedPointer<Lv2IdleRunLoop> 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<sfizz_ui_t> 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 defined(_WIN32)
IWin32PlatformFrame::setResourceBasePath((std::string(bundle_path) + "\\Contents\\Resources\\").c_str());
#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<Lv2IdleRunLoop> 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<LV2UI_Widget>(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<const float*>(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<const LV2_Atom *>(buffer);
if (atom->type == self->atom_object_uri) {
const LV2_Atom *prop = nullptr;
const LV2_Atom *value = nullptr;
lv2_atom_object_get(
reinterpret_cast<const LV2_Atom_Object *>(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<const LV2_Atom_URID *>(prop)->body;
auto *value_body = reinterpret_cast<const char *>(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();
#else
(void)self;
#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)
{
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<const LV2_Atom *>(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, v.to_float());
break;
case EditId::Polyphony:
sendFloat(SFIZZ_POLYPHONY, v.to_float());
break;
case EditId::Oversampling:
sendFloat(SFIZZ_OVERSAMPLING, v.to_float());
break;
case EditId::PreloadSize:
sendFloat(SFIZZ_PRELOAD, v.to_float());
break;
case EditId::ScalaRootKey:
sendFloat(SFIZZ_SCALA_ROOT_KEY, v.to_float());
break;
case EditId::TuningFrequency:
sendFloat(SFIZZ_TUNING_FREQUENCY, v.to_float());
break;
case EditId::StretchTuning:
sendFloat(SFIZZ_STRETCH_TUNING, v.to_float());
break;
case EditId::SfzFile:
sendPath(sfizz_sfz_file_uri, v.to_string());
break;
case EditId::ScalaFile:
sendPath(sfizz_scala_file_uri, v.to_string());
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<const LV2_Atom *>(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);
}
}

14
lv2/sfizz_ui.ttl.in Normal file
View file

@ -0,0 +1,14 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix urid: <http://lv2plug.in/ns/ext/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 .

216
lv2/vstgui_helpers.cpp Normal file
View file

@ -0,0 +1,216 @@
// 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 <lv2/ui/ui.h>
#include <algorithm>
#include <memory>
#include <mutex>
#include <stdexcept>
#if LINUX
#include <dlfcn.h>
#include <poll.h>
#endif
#if WINDOWS
#include <windows.h>
#endif
#if MAC
#include "vstgui/plugin-bindings/getpluginbundle.h"
#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<std::chrono::microseconds>(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<Event>(_events);
garbageCollectDeadHandlers<Timer>(_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 <class T> void Lv2IdleRunLoop::garbageCollectDeadHandlers(std::list<T>& 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 size_t soHandleCount = 0;
static std::mutex soHandleMutex;
SoHandleInitializer::SoHandleInitializer()
{
std::lock_guard<std::mutex> 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<std::mutex> lock(soHandleMutex);
if (--soHandleCount == 0) {
dlclose(soHandle);
soHandle = nullptr;
}
}
} // namespace VSTGUI
#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
///
#if MAC
namespace VSTGUI
{
void* gBundleRef = nullptr;
static volatile size_t gBundleRefCount = 0;
static std::mutex gBundleRefMutex;
BundleRefInitializer::BundleRefInitializer()
{
std::lock_guard<std::mutex> lock(gBundleRefMutex);
if (gBundleRefCount++ == 0) {
gBundleRef = GetPluginBundle();
if (!gBundleRef)
throw std::runtime_error("BundleRefInitializer");
}
}
BundleRefInitializer::~BundleRefInitializer()
{
std::lock_guard<std::mutex> lock(gBundleRefMutex);
if (--gBundleRefCount == 0) {
CFRelease((CFBundleRef)gBundleRef);
gBundleRef = nullptr;
}
}
} // namespace VSTGUI
#endif

89
lv2/vstgui_helpers.h Normal file
View file

@ -0,0 +1,89 @@
// 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 <list>
#include <chrono>
#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 <class T> static void garbageCollectDeadHandlers(std::list<T>& handlers);
private:
std::list<Event> _events;
std::list<Timer> _timers;
};
#endif
#if LINUX
namespace VSTGUI
{
class SoHandleInitializer {
public:
SoHandleInitializer();
~SoHandleInitializer();
private:
SoHandleInitializer(const SoHandleInitializer&) = delete;
SoHandleInitializer& operator=(const SoHandleInitializer&) = delete;
};
}
#endif
#if MAC
namespace VSTGUI
{
class BundleRefInitializer {
public:
BundleRefInitializer();
~BundleRefInitializer();
private:
BundleRefInitializer(const BundleRefInitializer&) = delete;
BundleRefInitializer& operator=(const BundleRefInitializer&) = delete;
};
}
#endif

View file

@ -48,9 +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\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"

View file

@ -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

View file

@ -17,7 +17,6 @@ set(VSTPLUGIN_SOURCES
SfizzVstController.cpp
SfizzVstEditor.cpp
SfizzVstState.cpp
GUIComponents.cpp
VstPluginFactory.cpp
X11RunLoop.cpp)
@ -26,12 +25,8 @@ set(VSTPLUGIN_HEADERS
SfizzVstController.h
SfizzVstEditor.h
SfizzVstState.h
GUIComponents.h
X11RunLoop.h)
set(VSTPLUGIN_RESOURCES
logo.png)
add_library(${VSTPLUGIN_PRJ_NAME} MODULE
${VSTPLUGIN_HEADERS}
${VSTPLUGIN_SOURCES})
@ -40,7 +35,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
@ -72,26 +68,21 @@ 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)
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}")
@ -102,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"
@ -237,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}")

View file

@ -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();

View file

@ -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<int>(value));
break;
case kTagSetOversampling:
controller->setParamNormalized(kPidOversampling, valueNorm);
controller->performEdit(kPidOversampling, valueNorm);
updateOversamplingLabel(static_cast<int>(value));
break;
case kTagSetPreloadSize:
controller->setParamNormalized(kPidPreloadSize, valueNorm);
controller->performEdit(kPidPreloadSize, valueNorm);
updatePreloadSizeLabel(static_cast<int>(value));
break;
case kTagSetScalaRootKey:
controller->setParamNormalized(kPidScalaRootKey, valueNorm);
controller->performEdit(kPidScalaRootKey, valueNorm);
updateScalaRootKeyLabel(static_cast<int>(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<CNewFileSelector> fs(CNewFileSelector::create(frame));
if (id == EditId::SfzFile)
loadSfzFile(v.to_string());
else if (id == EditId::ScalaFile)
loadScalaFile(v.to_string());
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, v.to_float());
break;
case EditId::Polyphony:
normalizeAndSet(kPidNumVoices, kParamNumVoicesRange, v.to_float());
break;
case EditId::Oversampling:
{
const int32 value = static_cast<int32>(v.to_float());
int32 log2Value = 0;
for (int32 f = value; f > 1; f /= 2)
++log2Value;
normalizeAndSet(kPidOversampling, kParamOversamplingRange, log2Value);
}
break;
case EditId::PreloadSize:
normalizeAndSet(kPidPreloadSize, kParamPreloadSizeRange, v.to_float());
break;
case EditId::ScalaRootKey:
normalizeAndSet(kPidScalaRootKey, kParamScalaRootKeyRange, v.to_float());
break;
case EditId::TuningFrequency:
normalizeAndSet(kPidTuningFrequency, kParamTuningFrequencyRange, v.to_float());
break;
case EditId::StretchTuning:
normalizeAndSet(kPidStretchedTuning, kParamStretchedTuningRange, v.to_float());
break;
case EditId::UIActivePanel:
ctrl->getSfizzUiState().activePanel = static_cast<int32>(v.to_float());
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<CNewFileSelector> 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<int>(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 = "<No file>";
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<int>(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;
}
}

View file

@ -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<SfizzVstController*>(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 <class Control>
void adjustMinMaxToRangeParam(Control* c, Vst::ParamID id)
{
auto* p = static_cast<Vst::RangeParameter*>(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> editor_;
#if !defined(__APPLE__) && !defined(_WIN32)
SharedPointer<RunLoop> _runLoop;

View file

@ -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<int32>(kParamScalaRootKey.denormalize(value));
_state.scalaRootKey = static_cast<int32>(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;
}
}

View file

@ -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);

View file

@ -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()

@ -1 +0,0 @@
Subproject commit c6a7f607c21a7353e922a6d45e54d6c56d5a6745