New repository, for git history check the original

This commit is contained in:
redtide 2023-05-08 14:43:33 +02:00
commit d6ab7584cb
No known key found for this signature in database
237 changed files with 52150 additions and 0 deletions

5
.clang-format Normal file
View file

@ -0,0 +1,5 @@
---
BasedOnStyle: WebKit
SortIncludes: false
...

37
.clang-tidy Normal file
View file

@ -0,0 +1,37 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,abseil-*,bugprone-*,performance-*,-abseil-no-internal-dependencies'
WarningsAsErrors: 'clang-diagnostic-*,clang-analyzer-*,abseil-*,bugprone-*,performance-*'
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: file
User: paul
CheckOptions:
- key: cert-dcl16-c.NewSuffixes
value: 'L;LL;LU;LLU'
- key: cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField
value: '0'
- key: cppcoreguidelines-explicit-virtual-functions.IgnoreDestructors
value: '1'
- key: cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: '1'
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
...

18
.editorconfig Normal file
View file

@ -0,0 +1,18 @@
# EditorConfig configuration
# http://editorconfig.org
# Top-most EditorConfig file
root = true
# UTF-8 charset, set indent to spaces with width of four,
# with no trailing whitespaces and a newline ending every file.
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.{fl,in,sh,ttl,yml}]
indent_size = 2
indent_style = space

32
.gitattributes vendored Normal file
View file

@ -0,0 +1,32 @@
.* export-ignore
.*/** export-ignore
appveyor.yml export-ignore
/scripts/appveyor/** export-ignore
/vst/external/VST_SDK/VST3_SDK/**/CMakeLists.txt export-ignore
/vst/external/VST_SDK/VST3_SDK/public.sdk/samples export-ignore
/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/*wrapper/** export-ignore
/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/interappaudio/** export-ignore
/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/testsuite/** export-ignore
/vst/external/VST_SDK/VST3_SDK/public.sdk/source/vst/utility/test/** export-ignore
/editor/external/vstgui4/**/CMakeLists.txt export-ignore
/editor/external/vstgui4/vstgui/Documentation/** export-ignore
/editor/external/vstgui4/vstgui/doxygen/** export-ignore
/editor/external/vstgui4/vstgui/standalone/** export-ignore
/editor/external/vstgui4/vstgui/tests/** export-ignore
/editor/external/vstgui4/vstgui/tools/** export-ignore
/editor/external/vstgui4/vstgui/uidescription/** export-ignore
/editor/external/vstgui4/vstgui/uidescription/icontroller.h -export-ignore
/editor/external/vstgui4/vstgui/vstgui_standalone* export-ignore
/editor/external/vstgui4/vstgui/vstgui_uidescription* export-ignore
/external/st_audiofile/thirdparty/dr_libs/old/** export-ignore
/external/st_audiofile/thirdparty/dr_libs/tests/** export-ignore
/external/filesystem/test/** export-ignore
/external/abseil-cpp/conanfile.py export-ignore
/external/abseil-cpp/**/BUILD.bazel export-ignore
/external/abseil-cpp/ci/** export-ignore
/external/simde/docker/** export-ignore
/external/simde/test/** export-ignore
/external/simde/meson* export-ignore
/external/simde/*.py export-ignore
/external/simde/*.yml export-ignore
/external/simde/*.toml export-ignore

482
.github/workflows/build.yml vendored Normal file
View file

@ -0,0 +1,482 @@
name: build
on:
push:
branches:
- 'develop'
- 'master'
tags:
- '[0-9]*'
- 'v[0-9]*'
pull_request:
branches:
- '*'
workflow_dispatch:
env:
BUILD_TYPE: Release
jobs:
clang_tidy:
# if: ${{ false }}
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
clang-tidy \
libsndfile1-dev
- name: Clang Tidy
working-directory: ${{runner.workspace}}
run: cd "$GITHUB_WORKSPACE" && scripts/run_clang_tidy.sh
build_for_linux:
# if: ${{ false }}
runs-on: ubuntu-20.04
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-linux" >> "$GITHUB_ENV"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
ninja-build \
libjack-jackd2-dev \
libsndfile1-dev \
libcairo2-dev \
libpango1.0-dev \
libfontconfig1-dev \
libx11-xcb-dev \
libxcb-util-dev \
libxcb-cursor-dev \
libxcb-xkb-dev \
libxkbcommon-dev \
libxkbcommon-x11-dev \
libxcb-keysyms1-dev
- name: Create Build Environment
shell: bash
working-directory: ${{runner.workspace}}
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake "$GITHUB_WORKSPACE" -G Ninja \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DSFIZZ_JACK=ON \
-DSFIZZ_VST=ON \
-DSFIZZ_LV2_UI=ON \
-DSFIZZ_PUREDATA=ON \
-DSFIZZ_TESTS=ON \
-DSFIZZ_SHARED=OFF \
-DSFIZZ_STATIC_DEPENDENCIES=OFF \
-DSFIZZ_LV2=ON \
-DCMAKE_CXX_STANDARD=17
- name: Build tests
if: ${{ false }} # DISABLED: Do this in library repo
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "$BUILD_TYPE" -j 2 --target sfizz_tests
- name: Run tests
if: ${{ false }} # DISABLED: Do this in library repo
shell: bash
run: ${{runner.workspace}}/build/tests/sfizz_tests
# Reenable with newer cmakes
# working-directory: ${{runner.workspace}}/build
# run: ctest -j 2 -C "$BUILD_TYPE" --output-on-failure
- name: Build all
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "$BUILD_TYPE" -j 2
- name: Install
working-directory: ${{runner.workspace}}/build
shell: bash
run: |
DESTDIR="$(pwd)/$install_name" cmake --build . --config "$BUILD_TYPE" --target install
tar czvf "$install_name".tar.gz "$install_name"
- uses: actions/upload-artifact@v3
with:
name: Linux tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_with_libsndfile:
if: ${{ false }} # DISABLED: Do this in library repo
runs-on: ubuntu-20.04
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-linux" >> "$GITHUB_ENV"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
ninja-build \
libsndfile1-dev
- name: Create Build Environment
shell: bash
working-directory: ${{runner.workspace}}
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake "$GITHUB_WORKSPACE" -G Ninja \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=OFF \
-DSFIZZ_LV2_UI=OFF \
-DSFIZZ_PUREDATA=OFF \
-DSFIZZ_USE_SNDFILE=ON \
-DSFIZZ_TESTS=ON \
-DSFIZZ_SHARED=OFF \
-DSFIZZ_STATIC_DEPENDENCIES=OFF \
-DSFIZZ_LV2=OFF
- name: Build tests
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "$BUILD_TYPE" -j 2 --target sfizz_tests
- name: Run tests
shell: bash
run: ${{runner.workspace}}/build/tests/sfizz_tests
build_for_macos:
# if: ${{ false }}
runs-on: macos-11
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-macos" >> "$GITHUB_ENV"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Create Build Environment
shell: bash
working-directory: ${{runner.workspace}}
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake "$GITHUB_WORKSPACE" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DSFIZZ_AU=ON \
-DSFIZZ_LV2=ON \
-DSFIZZ_LV2_UI=ON \
-DSFIZZ_VST=ON \
-DSFIZZ_JACK=OFF \
-DSFIZZ_TESTS=ON \
-DSFIZZ_SHARED=OFF \
-DSFIZZ_STATIC_DEPENDENCIES=OFF \
-DCMAKE_CXX_STANDARD=17
- name: Build tests
if: ${{ false }} # DISABLED: Do this in library repo
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
cmake --build . --config "$BUILD_TYPE" -j 2 --target sfizz_tests
- name: Run tests
if: ${{ false }} # DISABLED: Do this in library repo
shell: bash
run: ${{runner.workspace}}/build/tests/sfizz_tests
# Reenable with newer cmakes
# working-directory: ${{runner.workspace}}/build
# run: ctest -j 2 -C "$BUILD_TYPE" --output-on-failure
- name: Build plugins
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "$BUILD_TYPE" -j 2
- name: Package OSX bundles
shell: bash
working-directory: ${{runner.workspace}}
run: $GITHUB_WORKSPACE/scripts/package-osx-bundles.sh
- name: Create OSX installer
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
productbuild \
--distribution $GITHUB_WORKSPACE/scripts/plugin.pkg/package.xml \
--identifier "sfz.tools.sfizz" \
--package-path "${{runner.workspace}}/build" \
--version 0 \
${{env.install_name}}.pkg
- uses: actions/upload-artifact@v3
with:
name: macOS installer
path: |
${{runner.workspace}}/build/${{env.install_name}}.pkg
build_for_mod:
if: ${{ false }} # DISABLED: Old image which doesn't work with CMake > 3.5
runs-on: ubuntu-20.04
container:
image: jpcima/mod-plugin-builder
options: --user 0
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-moddevices" >> "$GITHUB_ENV"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Fix up MOD environment
shell: bash
run: ln -sf /home/builder/mod-workdir ~/mod-workdir
- name: Create Build Environment
shell: bash
working-directory: ${{runner.workspace}}
run: mod-plugin-builder /usr/local/bin/cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
mod-plugin-builder /usr/local/bin/cmake "$GITHUB_WORKSPACE" \
-DPROJECT_SYSTEM_PROCESSOR=armv7-a \
-DCMAKE_BUILD_TYPE=Release \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=OFF \
-DSFIZZ_LV2_UI=OFF
- name: Build
shell: bash
working-directory: ${{runner.workspace}}/build
run: mod-plugin-builder /usr/local/bin/cmake --build . --config "$BUILD_TYPE" -- -j 2
- name: Install
working-directory: ${{runner.workspace}}/build
shell: bash
run: |
DESTDIR="$(pwd)/$install_name" mod-plugin-builder /usr/local/bin/cmake --build . --config "$BUILD_TYPE" --target install
tar czvf "$install_name".tar.gz "$install_name"
- uses: actions/upload-artifact@v3
with:
name: MOD devices tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_for_windows:
# if: ${{ false }}
runs-on: windows-2019
strategy:
matrix:
include:
- platform: x86
pkg_platform: Win32
release_arch: Win32
bits: 32
- platform: x64
pkg_platform: Win64
release_arch: x64
bits: 64
steps:
- name: Set install name
run: |
echo "install_ref=$(${Env:GITHUB_REF}.split('/')[-1])" >> "${Env:GITHUB_ENV}"
echo "install_name=sfizz-$(${Env:GITHUB_REF}.split('/')[-1])-win${{matrix.bits}}" >> "${Env:GITHUB_ENV}"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Create Build Environment
working-directory: ${{runner.workspace}}
run: cmake -E make_directory build
- name: Configure CMake
working-directory: ${{runner.workspace}}/build
run: |
cmake "${Env:GITHUB_WORKSPACE}" -G"Visual Studio 16 2019" -A"${{matrix.release_arch}}" -DCMAKE_BUILD_TYPE="${Env:BUILD_TYPE}" -DCMAKE_CXX_STANDARD=17 -DSFIZZ_TESTS=ON -DSFIZZ_VST=ON -DSFIZZ_LV2=ON -DSFIZZ_PUREDATA=ON
- name: Build tests
if: ${{ false }} # DISABLED: Do this in library repo
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2 --target sfizz_tests
- name: Test
if: ${{ false }} # DISABLED: Do this in library repo
run: ${{runner.workspace}}/build/tests/Release/sfizz_tests
- name: Build all
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2
- name: Install pluginval
if: ${{ matrix.platform == 'x64' }}
run: |
Invoke-WebRequest https://github.com/Tracktion/pluginval/releases/download/latest_release/pluginval_Windows.zip -OutFile pluginval.zip
Expand-Archive pluginval.zip -DestinationPath pluginval
echo "$(Get-Location)\pluginval" | Out-File -FilePath ${Env:GITHUB_PATH} -Encoding utf8 -Append
pluginval\pluginval --version
- name: Validate VST3
if: ${{ matrix.platform == 'x64' }}
working-directory: ${{runner.workspace}}/build
run: pluginval --validate-in-process --validate sfizz.vst3
- name: Create installer
working-directory: ${{runner.workspace}}/build
run: iscc /O"." /F"${Env:install_name}" /dARCH="${{matrix.platform}}" innosetup.iss
- uses: actions/upload-artifact@v3
with:
name: ${{matrix.pkg_platform}} installer
path: ${{runner.workspace}}/build/${{env.install_name}}.exe
build_for_mingw:
if: ${{ false }} # DISABLED TEMPORARILY
runs-on: ubuntu-20.04
strategy:
matrix:
include:
- platform: i686
pkg_platform: Win32
bits: 32
- platform: x86_64
pkg_platform: Win64
bits: 64
container:
image: archlinux
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-mingw${{matrix.bits}}" >> "$GITHUB_ENV"
- name: Configure pacman repositories
shell: bash
run: |
cat >>/etc/pacman.conf <<EOF
[multilib]
Include = /etc/pacman.d/mirrorlist
[mingw-w64]
SigLevel = Optional TrustAll
Server = https://github.com/jpcima/arch-mingw-w64/releases/download/repo.\$arch/
EOF
- name: Set up dependencies
shell: bash
run: |
pacman -Sqyu --noconfirm
pacman -Sq --needed --noconfirm base-devel git wget ninja mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Fix MinGW headers
shell: bash
run: |
cp -vf "$GITHUB_WORKSPACE"/scripts/mingw_dwrite_3.h \
/usr/${{matrix.platform}}-w64-mingw32/include/dwrite_3.h
- name: Create Build Environment
shell: bash
working-directory: ${{runner.workspace}}
run: cmake -E make_directory build
- name: Configure CMake
shell: bash
working-directory: ${{runner.workspace}}/build
run: |
${{matrix.platform}}-w64-mingw32-cmake "$GITHUB_WORKSPACE" -G Ninja \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_LTO=OFF \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=ON \
-DSFIZZ_PUREDATA=ON \
-DSFIZZ_STATIC_DEPENDENCIES=ON \
-DCMAKE_CXX_STANDARD=17
- name: Build
shell: bash
working-directory: ${{runner.workspace}}/build
run: ${{matrix.platform}}-w64-mingw32-cmake --build . --config "$BUILD_TYPE" -j 2
- name: Install
working-directory: ${{runner.workspace}}/build
shell: bash
run: |
DESTDIR="$(pwd)/$install_name" ${{matrix.platform}}-w64-mingw32-cmake --build . --config "$BUILD_TYPE" --target install
tar czvf "$install_name".tar.gz "$install_name"
- uses: actions/upload-artifact@v3
with:
name: ${{matrix.pkg_platform}} MinGW tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
# build_with_makefile: MOVED in library repo
archive_source_code:
runs-on: ubuntu-20.04
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}" >> "$GITHUB_ENV"
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
python3-pip
sudo pip install git-archive-all
- name: Archive source code
shell: bash
run: |
cd "$GITHUB_WORKSPACE" && \
git-archive-all --prefix="${install_name}/" -9 "${{runner.workspace}}/${install_name}.tar.gz"
- uses: actions/upload-artifact@v3
with:
name: Source code tarball
path: ${{runner.workspace}}/${{env.install_name}}.tar.gz
deploy:
runs-on: ubuntu-20.04
if: startsWith(github.ref, 'refs/tags/')
needs:
# - build_for_linux
# - build_for_mod
# - build_for_mingw
- build_for_macos
- build_for_windows
- archive_source_code
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
- uses: actions/download-artifact@v3
if: ${{ false }} # DISABLED: Use distro packages
with:
name: Linux tarball
- uses: actions/download-artifact@v3
with:
name: macOS installer
- uses: actions/download-artifact@v3
if: ${{ false }} # DISABLED: See comment above
with:
name: MOD devices tarball
- uses: actions/download-artifact@v3
if: ${{ false }} # DISABLED: MinGW 32 build temporarily disabled
with:
name: Win32 MinGW tarball
- uses: actions/download-artifact@v3
if: ${{ false }} # DISABLED: MinGW 64 build temporarily disabled
with:
name: Win64 MinGW tarball
- uses: actions/download-artifact@v3
with:
name: Win32 installer
- uses: actions/download-artifact@v3
with:
name: Win64 installer
- uses: actions/download-artifact@v3
with:
name: Source code tarball
- name: Display file information
shell: bash
run: ls -lR
- uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
with:
tag_name: ${{env.install_ref}}
name: Release ${{env.install_ref}}
draft: false
prerelease: false
files: |
sfizz-${{env.install_ref}}-*
sfizz-${{env.install_ref}}.*

34
.gitignore vendored Normal file
View file

@ -0,0 +1,34 @@
build*/*
docs
.vscode
perf.data
perf.data.old
CMakeBuild/
Makefile
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
compile_commands.json
*.a
*.user*
*.autosave
*.diff
/Doxyfile
.DS_Store
.cache/
.cmake/
clients/sfizz_jack
clients/sfzprint
/plugins/vst/download/
/plugins/vst/external/vstsdk2.4/
/plugins/vst/external/CoreAudioUtilityClasses/
/plugins/editor/external/fluentui-system-icons/
*.sublime-*
*.code-*
.kak.tags.namecache
.clangd

18
.gitmodules vendored Normal file
View file

@ -0,0 +1,18 @@
[submodule "plugins/vst/external/VST_SDK/VST3_SDK/base"]
path = plugins/vst/external/VST_SDK/VST3_SDK/base
url = https://github.com/steinbergmedia/vst3_base.git
[submodule "plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces"]
path = plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces
url = https://github.com/steinbergmedia/vst3_pluginterfaces.git
[submodule "plugins/vst/external/VST_SDK/VST3_SDK/public.sdk"]
path = plugins/vst/external/VST_SDK/VST3_SDK/public.sdk
url = https://github.com/steinbergmedia/vst3_public_sdk.git
[submodule "plugins/editor/external/vstgui4"]
path = plugins/editor/external/vstgui4
url = https://github.com/sfztools/vstgui.git
[submodule "plugins/vst/external/sfzt_auwrapper"]
path = plugins/vst/external/sfzt_auwrapper
url = https://github.com/sfztools/sfzt_auwrapper.git
[submodule "library"]
path = library
url = https://github.com/sfztools/sfizz.git

13
AUTHORS.md Normal file
View file

@ -0,0 +1,13 @@
# Author and contributors
Contributors to `sfizz`, in chronologic order:
- Paul Ferrand (2019-2020) (maintainer)
- Andrea Zanellato (2019-2020) (devops, documentation and distribution)
- Alexander Mitchell (2020)
- Michael Willis (2020)
- Jean-Pierre Cimalando (2020)
- Tobiasz "unfa" Karoń (2020)
- Kinwie (2020)
- Atsushi Eno (2020)
- Dominique Würtz (2021)

774
CHANGELOG.md Normal file
View file

@ -0,0 +1,774 @@
# Changelog
The format is based on [Keep a Changelog][1].
This project tries to adhere to [Semantic Versioning][2].
## [Unreleased]
## [1.2.1] - 2023-04-15
### Globally
#### Added
- Mac OS Installer (#93 #1087)
- This file from Release-Notes.md in wiki.
#### Changed
- Updated bundled dependencies and added more options to use those
preinstalled in system (#1104 #1117 #1143 #1145 #1149)
- CI: Various updates and fixes for GitHub Actions; removed Travis and Appveyor
### Library
#### Added
- Add LFO frequency as an EG target (#1103)
- New `image_controls` opcode to add a background image on UI' Controls tab (#1156)
#### Fixed
- Disabled temporarily the embedded sample test
- Parse 0-valued note ons as note offs (#1072 #1073)
- Correct a bug with dynamic updates on offed EGs (#2 #1088)
- jack: Wait for CLI thread to finish on quit (#1097)
- Fix libsndfile build and add CI (#1112 #1090)
- Last keyswitches don't change the midi state (#1113 #1074)
- Add section suffix to man pages (#1124)
### UI
#### Added
- HiDPI: Added a Zoom menu in Settings to apply an user' zoom ratio preference
(#1123 #1153)
#### Changed
- Colored logo button on mouse hover (#1151)
- Centered, full-size background images container (#1152)
- XP style tooltips (#1156)
- Window size has been changed to be compatible with ARIA banks
(775x335 for image backgrounds) (#1140 #1156)
- The CC knobs rotator and title label have a white color
on a semi-transparent background in the controls tab (#1156)
- The info tab becomes a dark and semi-transparent overlay dialog above the
Home tab; both will display the same background image when available (#1156)
### Plugins
#### Added
- Handle LV2 scaleFactor supportedOption (#1153)
#### Fixed
- Added suffix "-multi" to LV2 and VST3. (#1084)
- Fix LV2 manifest when using PSA (#1114)
- Fix 2 bugs in LV2 and VST3 for loads and stores (#1115 #1098)
## [1.2.0] - 2022-02-15
### Major improvements
- The sfizz engine now handles multiple stereo outputs,
through the `output` opcode. The VST3 and LV2 plugins both have
a 16-out version (as 8 stereo outs) (#1002)
- The `emscripten` branch allows to run sfizz through WASM
for your web-oriented needs. An example with WebMidi
is available at https://sfz.tools/sfizz-webaudio/
(requires a Chromium-based browser),
with source code at https://github.com/sfztools/sfizz-webaudio.
- sfizz can now parse embedded samples in base64 data (#1041)
### Library
#### Added
- Added `sfizz_send_program_change` and its C++ counterpart.
- Added `sfizz_set_sustain_cancels_release` and its C++ counterpart.
- Support extended CCs 140 and 141 for "keydelta" (#1003)
- Added better support for files that are fully loaded in memory
and not simply preloaded (#1031)
- Added support for `loprog/hiprog` (#1058)
#### Changed
- The internal midi state is not reset when loading/reloading.
This means in particular that controls changed on an instrument
will be kept if you edit the underlying SFZ file (#1002)
- Updated dependent libraries (#1018)
- Negative values for lokey will not disable the region anymore (#1019)
- Choke groups now act through CC switches (#1024)
- `sw_last` is now properly affected by `octave_offset` and `note_offset` (#1039)
- sfizz is now clamping flex EG levels (#1037)
#### Fixed
- Corrected a bug when reloading some files (#1028)
- Corrected mistakes in the shelving filters (#1027)
- Properly read exponential notation in floats (#1036)
- Corrected a bug where long-tailed effects would be cut off (#1050)
- Corrected a bug in the band rejection filters (#1052).
The `apf_1p` filter still misbehaves and is disabled for now.
#### Deprecated
- `sfizz_enable_logging` and `sfizz_disable_logging`
(and their C++ counterparts) are deprecated,
replaced by `sfizz_get_callback_breakdown` which needs to be called
at the end of a callback by the host (#1034).
All file writing is handled by the host for logging.
### UI
#### Added
- Added support in the plugin GUI/parameters for the "sustain cancels release"
behavior of LinuxSampler.
#### Changed
- Updated the GUI option panel for the plugins (#1022)
and some hints on the tab buttons (#1057)
#### Fixed
- Numpad input is now properly handled (#1053)
### Plugins
#### Added
- In the LV2 plugin, plugin-side automation is now enabled by default
(which means all SFZ control changes are naturally bound
to incoming MIDI control changes and not controlled by a plugin parameter).
You can disable this at build time and show the relevant parameters
using `SFIZZ_LV2_PSA`. Too many hosts expect their plugins to respond
to midi messages for things like pedal and volume. (#1054)
- The LV2 plugin now has a string output parameter
with the CC used by the instrument (#1060)
#### Fixed
- Corrected a crash in some VST3 hosts (#1035)
## [1.1.1] - 2021-11-08 [YANKED]
### Fixed
- Roll back VSTGUI to 4.10.2 to avoid corruption of the UI in some scenarios
## [1.1.0] - 2021-10-23
### Library
#### Added
- Added support for `hint_sustain_cancels_release`, which when activated
reproduces a LinuxSampler behavior by sustaining already released notes (#898).
A GUI option should come later.
- Added support for `amp_veltrack_oncc`, `pitch_veltrack_oncc`,
and `fil_veltrack_oncc` (#938)
- Dynamic EGs are supported for flex EGs (#933 #932 #930)
- Support `_curvecc` for extended CCs (#993)
- Support `lorand` and `hirand` on CC-triggered regions (#997)
- The engine now parses `oscillator=auto` and only enables oscillators
on short samples with wavetable tags in the WAV metadata (#954)
- Added a polyphony option to `sfizz_render` (#992)
- Added a text interface to `sfizz_jack` (#973)
#### Changed
- Filter resonance can now be negative (#919)
- The JACK and PureData clients can use custom importers (#926)
- Polyphony groups can have negative indices (#934)
- Parse `lokey=-1` as `hikey=-1` (#941)
- Since the default build of the LV2 plugin is not statically linked against
libsndfile, the distribution license is changed to the ISC license (#943)
#### Fixed
- Fixed a bug which could prevent parameters to be automated in Ardour (#893)
- Fixed a bug where high definition CC,
crossfade or aftertouch events could be ignored (#855 #896)
- Resetting all controllers will now reset them to their default,
instead of 0 (#905)
- Fix `off_by` behavior with long-releasing notes (#972)
- Improved the preloading for monolithic wave files (#935)
- The DecentSampler importer now better translates the loop modes (#981)
- CC-triggered voices can be cut off by polyphony groups (#917)
- Allow building on MacOS 10.9 (#990)
- Corrected a bug where octave and note offset
were not reset upon loading a new file (#994)
- Corrected a bug where CC-triggered voices could generate note-offs
when cut by a polyphony group (#998)
- Added man pages for `sfizz_render` and `sfizz_jack`, plus jack client fix (#999)
- Various build system improvements for different platforms
(#957 #958 #964 #967 #968 #989 #978 #942 #921 #920 #902 #849 #850 #856 #1001)
### UI
#### Added
- Added a GUI volume meter (#859)
- It is now possible to enter values for CCs on the plugin GUI
by double clicking on the CC knob (#945).
A high-resolution input option is also available on a right click.
#### Fixed
- Respect the editor set for sfz files on MacOS (#925)
### Plugins
#### Added
- Added a Puredata plugin (#869 #873 #874)
- Implement support for VST3 keyswitch and midi note names (#877 #876)
#### Fixed
- Corrected a bug for the LV2 plugin when used in the Ardour DAW (#924)
- Even when plugin-side automation is disabled (through `SFIZZ_LV2_PSA`),
sustain and sostenuto CC events will still go through to the plugin to improve
the user experience on hosts that do not support automatic mapping of control
ports to midi events through the LV2 `midi:binding` extension (#963).
- Fixed a bug that could hang the background thread in the VST plugin
(#984 #865 #864)
- The current keyswitch is properly saved and restored with the plugin state (#961)
- Improved the X11 runloop (#986)
- Corrected a bug which prevented VST3 or LV2 plugins
to be loaded by the Ardour DAW (#995)
## [1.0.0] - 2021-04-16
- SFZ v1 is virtually supported except for a handful of opcodes.
Please check https://sfz.tools/sfizz/development/status/
for the up-to-date status of opcode support.
- It is now possible to build sfizz without relying on libsndfile,
using a set of libraries. This is now the default build mode.
Building with libsndfile can be enabled at configure time.
- The library and plugins can now load DecentSampler files,
and could accomodate other formats.
- CCs, keyswitch range, key ranges and active keyswitch
are now displayed in the editor for all plugins.
There has been a lot of UI work to make it more practical to use.
- There is an OSC interface in the library, which allows to have introspection
into the currently loaded file, the state of CCs/keyswitches,
and also set some parameters for loaded regions.
### Library
#### Added
- Added documentation in the API calls to make clear
that sample-accurate triggering of voice requires
messages to be sent in order. The VST plugin in particular
did not respect this and has been updated.
- There are new HD (float) versions of API calls for note and CC events.
- Added an info panel in the plugin UI
(#793 #792 #791 #789 #788 #787 #782 #779 #773)
- Support DecentSampler and a generic importer for other formats (#725 #715 #680)
- Add high-definition versions of the API calls (#820)
- Support polyphonic aftertouch events, triggers and targets (#809 #764)
- Support monophonic aftertouch events, triggers and targets (#765 #630 )
- It is now possible to change some parameters of the regions
after loading the file through the OSC interface (#761)
- Added modulation targets for amplitude, pan, width, position, pitch and volume (#760)
- Support CC modifiers for `end`, `loop_start` and `loop_end` (#752)
- Support CC modifiers for LFO targets (#753)
- Support SFZ v1 extended CCs (#747)
- Implement the sostenuto logic (#739)
- Added CC modulation for `depth` targets (#730)
- Implement v1 LFOs (#693)
- Support `count` and `loop_count` (#654)
- Support `delay_oncc` (#653)
- Support `sw_vel` (#650)
- Added windowed sinc interpolation for `sample_quality` from 3 to 10 (#609)
- Support `lfoN_beats` (#553)
- Add region and voice introspection to the OSC interface (#555)
- Add an alternative to libsndfile (#482 #534 #535 #536)
- Support disjoint keyswitch ranges, as well as `sw_lolast` and `sw_hilast` (#526)
#### Changed
- The ABI is broken, leading to a major version change.
- Thread-safety now has to be handled externally.
The API has been updated to provide a concurrency spec.
- The current version of the internal oversampling factor was too unstable
and has been disabled for the time being. The API and plugin parameters
are staying for compatibility. A more robust implementation should come soon.
- A new `bpmTempo` method has been added to pass tempo as beats-per-minute
rather than seconds per beat.
The previous version is deprecated.
- `aftertouch` is renamed as `channel_aftertouch` (for C)
and `channelAftertouch` (for C++) throughout the API
to be more consistent with `polyAftertouch`.
- The C++ standard is set to 14 if you build the UI on LV2,
or if you build the VST version. This will likely increase to 17 shortly
due to the dependency on VSTGUI. The ui-less LV2 plugin and the library
remain C++11 compatible.
Note that windows builds already use C++17 on all targets. (#795)
- The library uses an Hermite interpolation by default (#828 #829)
- Corrected a bug where regions with long release envelopes
would not stop on sample ending (#811)
- Update abseil and ghc::filesystem (#780), the tunings library from Surge
(#785), catch2 (#711)
- Improve the choking logic to match the spec and other implementations (#778)
- Refactored opcode reading and storing (#748 #727 #721 #722 #720 #700 #559)
- Filter/EQ parameters are clamped even with modulation (#701 #699)
- Delay envelope start by the voice delay (#655 #432)
- Allow parsing of some badly formed files files (#600)
- Match ARIA's LFOs (#613)
- Improve the Hermite interpolation (#597)
- Enable fast-math on MSVC (#567)
#### Fixed
- Fix an error where sample indices could wrap for massive pitch modulations
(#825 #751)
- Small files with only zeroes are considered as `*silence` (#831)
- Corrected a regression where sfizz would stop loading the SFZ file
if some sample files cannot be loaded (#806)
- Fix the parser to support sharp (#) symbols in file names (#746)
- Improved the ADSR transitions from decay to sustain, and from release to 0 (#734 #373)
- Reset the smoothers if the playhead moved (#731 #710 #382)
- Corrected a bug where the first sample was ignored on playback (#732 #394)
- If the sustain level is low enough the envelope is set to free-run (#723, #676)
- Fix loop crossfades when the loop starts early in the sample (#718)
- Fix random generators to match ARIA's behavior (#719)
- Fix corruption appearing in some sample libraries (#717 #695)
- Smoothers are now linear (#713 #714 #703)
- Fix a bug where the sample rate was not propagated properly to the flex EGs (#683)
- Fix `note_polyphony` choking (#634 #529)
- Respect the `end` opcode (#618)
- Fix allocations that may happen on the RT thread (#621)
- Fix the polyphony manager when the engine polyphony is changed
after a file is loaded (#619)
- Avoid reloading invalid files (#614)
- Update AtomicQueue to correct a bug (#583)
- Fix crashes when building with libsndfile (#542 #543)
- Properly pad and align the wav files upon reading (#538)
- Handle gracefully having a different `sw_default` in a region (#531)
### UI
#### Added
- UI improvements and tweaks, adding themability in particular (#826 #824 #822
#821 #819 #818 #816 #812 #799 #743 #691 #674 #673 #672 #670 #662 #661 #656)
- Show the current keyswitch on the editor and the virtual keybnoard (#665 #657)
- Added a button to reset the scala file to default (#660)
- The plugins now display an image through the `image` opcode (#770)
#### Changed
- Improve font handling (#669 #622)
- Improve file handling in the UI (#645 #659 #658)
and enable the use of a "default user directory" or environment variable.
This also allows the plugin to "find" missing sfz files
in a different environment (#644 #581 #572 #532)
- Update VST to 3.7.2 (#798)
### Plugins
#### Added
- Added the option to build a VST2 version of sfizz
if you have the SDK available (#708)
#### Changed
- Order VST events (#810 #803)
#### Fixed
- Fix corruptions and crashes that happened in the LV2 plugin (#794 #668 #557)
- The internal controllers of sfizz are now presented as parameters
in the LV2 plugin. Experimental midi binding is also active on them. By default
the "direct" midi input is disabled and you need to map to the parameters.
A compile-time option is available to re-enable the midi input. (#776)
- Fix crashes in the VST plugin (#709 #702 #681 #625)
- Enable checking if file changed even when the transport is not running (#712 #689)
- The Mac builds are now signed (#550 #552)
#### Removed
- Remove automation from un-automatable parameters in the VST plugin (#814)
## [0.5.1] - 2020-10-25 [YANKED]
### Fixed
- Corrected race conditions that appeared with the new thread and file pools
(#507 #508 #514 #521)
- Take the internal oversampling factor into account for loop points,
and solve an issue where loop points specified in sfz files
were not taken into account (#506)
- Fix an implementation error for the internal hash function
when applied on a single byte (#512)
- Knobs are linear in the AU plugin (#517)
- Fix a crash in VSTGUI (#520)
- Fix the resource path in the LV2 plugin under windows (#524)
- Add MacOS make install rules (#525)
## [0.5.0] - 2020-10-15
### Major improvements
#### Added
- Added basic support for Flex EGs (#388) as modulation sources (targets to come)
- Added basic support for LFOs (#338) as modulation sources (targets to come)
- EGs and LFOs can now target EQs and filters (#424)
- A new GUI has been added and is common to the LV2 and VST plugin
(#397 #404 #419 #489 #492 #495 #496 #497)
still mostly work in progress, more to come!
- Provided build systems to use sfizz with the VCV-Rack SDK
and the DISTRHO Plugin Framework
### Library
#### Added
- Added API support for setting the playback state,
time position and signature (#354)
- The API documentation on the sfizz's website has been streamlined alot !
- Added support for `sustain_lo` (#327)
- Audio files are now read incrementally, improving the availability under load (#294)
- Added support for effect types `reverb`, `disto`, `gate` and `comp`
- Added support for `off_time` and complete support for `off_mode`.
The voice stealing logic was improved to take into account `polyphony`,
`note_polyphony` and `group_polyphony` properly (#349 #352 #393 #413 #414 #467).
Note that this support is also available for the engine polyphony.
In this case, some additional voice will take over for the release duration (#477).
- Support for `offset_cc` (#385)
- `sfizz_render` now supports a `--quality` switch,
which acts like the `sample_quality` opcode (#408)
- `pitch_keycenter=sample` is now taken into account (#362)
- Support `oscillator_detunecc` (#434)
- Support basic FM synthesis for oscillator regions (#436)
- Support `hint_ram_loading` for loading the whole samples in RAM (#353)
- Support for `loop_crossfade` (#464)
- Improve the filter shortcut path (#336)
#### Changed
- The voice stealing is now configurable using `hint_stealing`,
with possible values as `first`, `oldest` (default), and `envelope_and_age`.
The latter is the more CPU-consuming version which requires to follow
the envelope of each voice to kill low-volume ones preferably.
Note that the voice stealing continue to kill all voices
started on the same event by default (i.e. all layers of the same note). (#344 #384 #353)
- `sfizz` now internally uses a modulation matrix to link
all modulation sources (CC, LFOs, and EGs) and targets (#335 #351 #386)
- The wavetable quality has been improved (#347)
- Loading probable wavetable files, or wav files containing wavetable metadata
now sets `oscillator=on` on the region (#431)
- The default `sample_quality` was put back to 1 for live playing and 2 for freewheeling (#405)
- Improve the file loading logic to keep files in memory
for a short while in case they get reused (#425)
- Improved the release logic in many cases (#324 #414 #413)
- Set the level of the `*noise` generator to match ARIA's (#429)
#### Fixed
- CC 7, 10 and 11 are now linked by default to pan, volume and expression (#475)
- All phase-related opcodes in sfizz now use the 0->1 convention,
as does ARIA/Sforzando, instead of the 0->360 convention (#499)
- Fix an unwanted copy in the realtime thread (#334)
- Fix the default `ampeg_attack` and `ampeg_release` to avoid clicks (#437)
- Corrected a race condition in freewheeling mode (#500)
- Fixed a potential non-realtime operation in the realtime thread (#498)
- Fix a bug when using a larger internal oversampling for regions
with an `offset` value (#469)
- Fix an issue when loops occured more than once in a block (#462)
- Increase the range of the clamping on amplitude (#468) and pitch (#474)
- Fix CC modulations with their source depth set to 0 (#475)
- Fix an overshoot for crazily large cutoff values (#478); cutoffs are now clamped
- Fix the MIDNAM output for the case where extended CCs are used (#420)
- Fixed a bug where release voices where not ignored on self-mask search (#348)
- Fixed `amp_veltrack` behavior (#371)
- Fix the ADSRH envelope release rate (#376)
- Fixed an error for files where the loop spans the entire file (#378)
- Fixed `sustain_cc` behavior (#377)
- Match the default volumes with ARIA (#381)
- Properly set the `loop_mode` for release regions (#379)
- Regions with `end=0` are now properly disabled (#380)
- Fix `fil_random` to be bipolar (#452)
- The `sequence` order now properly starts at 1 (#451)
- Fix an issue on Flush to Zero on some ARM platforms (#455)
- Fix `pitch_veltrack` (#461)
- Opcode values now properly stop at the `<` character (#439)
- Fix various build errors and issues on all platforms
(#345 #401 #400 #399 #417 #447 #449 #443 #453 #456 #459 #471 #484 #487 #488 #491)
- Existing and known CC values are now correctly taken into account for modulations (#421)
- Fix various performance regressions and improved performance
especially on ARM builds (#410 #412 #415 #426)
### UI
#### Added
- The file dialog initial directory is now the root of the current loaded file (#428)
### Plugins
#### Added
- A new output port for active voices has been added in the LV2 plugin (#321)
#### Fixed
- Support for `atom:Blank` atoms in the LV2 plugin (#363)
## [0.4.0] - 2020-07-24
### Major improvements
#### Added
- Added support for polynomial resamples and `sample_quality` opcodes (#238 #267).
The engine now defaults to a value of `2` for this opcode,
which is more intensive than the original linear interpolation resampler
but provides a better quality. Added support for better resampling algorithms
also in the wavetables via `oscillator_quality` (#287).
- Support `_curvecc` and `_stepcc` opcodes (#166 #155 #77)
as well as `_smoothcc` opcodes (#181 #48 #22 #153 #297 #285)
- Added support and API for Scala tuning files in the engine and the plugins
(#253 #268 #282)
### Library
#### Added
- Added API calls to set `$variable` define values prior to loading an SFZ file
(#168 #119 #130)
- Added API calls to get key labels and cc labels
defined by `label_key` and `label_cc` (#174)
- Added an API call to load an sfz file as an `std::string` or `const char*` (#217)
- Added API calls for Scala files and tunings (#253)
- Added high-definition floating point CC API calls (#244)
- Added API calls to change the default resampling quality (#267 #238)
- Added support for unison oscillators (#161)
- Support for the `polyphony` opcode at all levels (#171 #275),
as well as `note_polyphony`. The `group=` polyphony is also more flexible
and can be defined anywhere.
- Added support for `offset_cc` (#170 #159)
- Added support for `direction=reverse` (#185 #179)
- Added support to label the keys using a `label_key` opcode.
This is not really standard yet, but it is now integrated in the LV2 plugin
to advertise the names in the MIDNAM file and possibly change their labels
in hosts that support it. (#174 #154)
- Added support for block comments `/* */` in the parser (#196 #195)
- Added a `sfizz_render` client in tree; you can build it with the make target
`sfizz_render` if the `SFIZZ_RENDER` CMake variable is set to `ON`. (#200 #201 #206)
- Add support to integrate sfizz in DPF plugins (#216)
- Added support for the `set_hdcc` opcodes and overall added the ability
to support floating-point CCs from the API (#233 #232 #244)
- Added support for FLAC loops (#242 #229)
- Add headers and group sources in the CMake project for integration with e.g. Qt (#312)
- Support flat notes parsed as string values (#291 #289)
#### Fixed
- Solved some issues with DSmolken's drumkits related to the ampeg envelope (#172)
- An exception problem was thrown if an sfz file was deleted (#182 #184)
- Improved the filter stability (#198 #199 #210)
- Handle `USE_LIBCPP` properly on configure (#203)
- Fix the handling of loop markers if sample `end=` is present (#202 #204)
- Handle note on with 0 velocity as note offs in the jack client (#208 #211)
- Solved an issue with super short files (#215)
- Fixed some parsing issues with `$variables` (#230)
- Process `$` expansions in `#include` (#247)
- Change the default build type to `RelWithDebInfo` (#249)
- Improve the note stealing algorithm (#214);
note that this is still very much a work in progress since many heuristics
are in play here. Feel free to report misbehavior
regarding note stealing as we improve this regularly.
- Corrected a bug with SFZ v1 `velcurve` (#263)
- Properly support the `off_by=-1` opcode to correctly reset the value. (#235)
- Ignore garbage values following e.g. a key number in opcode values
(as in `key=64Garbage` -> `key=64`) (#263)
- `ampeg_****_onccXX` modifiers now properly consider multiple CC modifiers
(#300 #167)
- Trigger on CC does not require disabling the key triggering through e.g. `key=-1` (#315)
- Improved handling of `release_key` (#298); still not perfect, if the region
spans multiple key and multiple notes happened with the pedal down,
only a single voice will start.
- Corrected a parsing issue when `$variables` were part of an opcode name (#328)
- Various other plumbing changes
### Plugins
#### Added
- Added an AudioUnit target (#224)
- Support the `mapPath` feature of the LV2 specifications,
for tentatively better portability in plugin states (#303)
- New instances of the sfizz LV2 plugin will now load a default
`*sine` instrument (#283)
#### Fixed
- Properly bundle the `dylib` for macOS (#188)
- Corrected a stack smashing bug in the LV2 plugin (#226)
- Properly advertise the VST plugin parameters (#241)
- Corrected some errors with null-terminated atoms in the LV2 plugin (#269)
- Properly read the LV2 option list until the end (#323, by @atsushieno)
## [0.3.2] - 2020-04-03
### Added
- Added an experimental support for `make uninstall` (#118, #120)
- Add the autopan (#105), width, rectifier, gain, limiter (#131),
and string resonator (#143) effects
- Curves are now registered within the synth but cannot be referenced yet (#96)
- Added a "panic button" API that kills voices (#122)
- Added support for more generators using wavetables (#61)
- Added support for the `oscillator` opcode, to create generators from files (#128)
- Added support for `note_polyphony`, `polyphony`, and `note_selfmask` (#142)
- Added support for `pitch_cc` and `tune_cc` modifiers (#142)
### Changed
- sfizz now builds down to gcc-4.9 with stricter C++11 compliance.
The main release builds use C++17 mode on newer compilers (#111, #110)
- Upstream libraries updates (abseil, filesystem and atomic_queue) (#121)
- The logging API can be used to set a log filename (a6cbb48)
- Reworked the parser; the new one is more efficient,
and can indicate error/warning ranges (#130)
- The VST plugin now reloads the file automatically, like the LV2 plugin (#139)
- The max number of CCs was increased to 512,
to accomodate some libraries that use cc300 modifiers.
- The engine uses floating point values internally for midi events (#137);
this prepares it for high-resolution midi down the line.
- The modifier support was overhauled;
all regions can now have multiple CCs modifying the same target (#142).
- Improved performance of the amplitude stage gain of the rendering process (#145)
- The VST3 are now a submodule; more architecture targets have been added
(#158, #147, patch proposed by @hexdump0815)
### Fixed
- Corrected a bug where the VST plugin got recreated needlessly in some hosts (#122)
- Corrected a potential overflow for CC names (930bfdf)
- Generators using wavetables are now correctly tuned (#126)
- The stereo panning stage of the process was corrected;
width is now set to 100% by default as it should,
and panning is properly applied (1faa7f, b55171, #133)
- Corrected errors in the performance report script related to display values
(file names and histogram range)
- Fixes some realtime synchronization issues in the VST (#140)
- Corrected bugs and differences with Cakewalk/ARIA in the ADSR envelope (#136, #129)
## [0.3.1] - 2020-03-14
### Added
- Added a VST3 plug-in front-end to the library. It is still quite experimental
and suffers from problems that stem from the VST3 SDK itself. (#99)
- Added effect buses and processing. There is a "lofi" effect available for now,
as well as the same filters and EQs you can apply on the regions.
More will come soon! (#84)
- Added a script to parse and render the timings.
This can help tracking performance issues and regressions. (#89)
### Fixed
- Various fixups, performance improvements, and CI updates.
## [0.3.0] - 2020-02-29
### Added
- Added filter and EQ handling (the `filN_...` and `eqN_...` opcodes).
There are also no limits to the amount of filters and EQs you can slap
on each region beyond your CPU. Most if not all of the relevant filter types
from the SFZ v2 spec are supported.
- Added a new command-line option for the JACK client
to set the client's name (#75, #76).
- Added initial MIDNAM support (#79).
The MIDNAM shows the named CCs in the SFZ file for now.
- Added fine timings within the callbacks for performance improvements
and regression testing (#65).
- Added a crude `*noise` generator. This generator is a bit expensive
for what it does but it's mostly useful to test the filters.
### Changed
- Reworked the parsing code for faster dispatching and better handling
of complex opcodes with multiple parameters in their opcode name (#40).
- Reworked the panning and stereo image process.
The new process uses tabulated functions and avoid expensive calls
to compute sine and cosine functions (#47, #56).
### Fixed
- Corrected a bug with Ardour where saving a session with no file loaded
would crash on reopening.
- Corrected a bug where voices triggered on key off would never end
and fill up the polyphony (#63).
- Improved and completed CI on all platforms.
## [v0.2.0] - 2020-01-30
First version not depending on SFZero / JUCE,
becoming a library to be used in other projects, plus a LV2 plugin.
### Added
- Added an LV2 plugin version.
- Added support for pitch bends (#6)
as well as pitch-bend activation for regions (`lobend` and `hibend` opcodes).
- Added dynamic updates for the current modifiers
(panning, stereo image, volume and amplitude mainly) (#19, #28)
- Added timing for callbacks and file loading times.
- Added a windows build process for both the shared library and the LV2.
`sfizz` now builds on all major platforms.
### Changed
- The parser now falls back to case-insensitive search if it doesn't find
the sample file in its current path (#28),
so that the behavior of SFZ libraries on case-sensitive filesystems
will match Windows and macOS default case-insensitive filesystems.
- The file now reload automatically on file change,
and you can force a reload if necessary (#17).
### Fixed
- Corrected a bug where memory would be read past the end of the file in memory,
generating artifacts.
- Corrected a bug where the real-time queue handling background loading
of the voices would fail spuriously.
- Corrected a bug where in the LV2 plugin the unknown opcode list was truncated (#18).
- The JACK client will warn you instead of crashing
if you do not give it a file to load (#27).
## [v0.1.0] - 2019-05-30
- Initial release, based on SFZero and JUCE.
[1]: https://keepachangelog.com/en/1.0.0/
[2]: https://semver.org/spec/v2.0.0.html
[Unreleased]: https://github.com/sfztools/sfizz/compare/1.2.1...HEAD
[1.2.1]: https://github.com/sfztools/sfizz/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/sfztools/sfizz/compare/1.1.1...1.2.0
[1.1.1]: https://github.com/sfztools/sfizz/compare/1.1.0...1.1.1
[1.1.0]: https://github.com/sfztools/sfizz/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/sfztools/sfizz/compare/0.5.1...1.0.0
[0.5.1]: https://github.com/sfztools/sfizz/compare/0.5.0...0.5.1
[0.5.0]: https://github.com/sfztools/sfizz/compare/0.4.0...0.5.0
[0.4.0]: https://github.com/sfztools/sfizz/compare/0.3.2...0.4.0
[0.3.2]: https://github.com/sfztools/sfizz/compare/0.3.1...0.3.2
[0.3.1]: https://github.com/sfztools/sfizz/compare/0.3.0...0.3.1
[0.3.0]: https://github.com/sfztools/sfizz/compare/v0.2.0...0.3.0
[v0.2.0]: https://github.com/sfztools/sfizz/commits/v0.2.0
[v0.1.0]: https://github.com/sfztools/sfizz-juce/releases/tag/v0.1.0-beta.2

53
CMakeLists.txt Normal file
View file

@ -0,0 +1,53 @@
if (WIN32)
cmake_minimum_required (VERSION 3.15)
cmake_policy(SET CMP0091 NEW)
else()
# FIXME: The old JPC fork of mod-plugin-builder image used in CI requires 3.5.
# The current upstream one needs a different configuration.
# Minimum required to use SFIZZ_USE_SYSTEM_ABSEIL is 3.11,
# see library/cmake/SfizzDeps.cmake at line 70.
cmake_minimum_required(VERSION 3.11)
endif()
project (sfizz VERSION 1.2.2 LANGUAGES CXX C)
set (PROJECT_DESCRIPTION
"SFZ based sampler, providing AU, LV2, PureData and VST plugins."
)
# External configuration CMake scripts
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};"
"${CMAKE_CURRENT_SOURCE_DIR}/library/cmake;"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
)
include(BuildType)
include(OptionEx)
option_ex(SFIZZ_AU "Enable AU plug-in build" APPLE)
option_ex(SFIZZ_LV2 "Enable LV2 plug-in build" ON)
option_ex(SFIZZ_LV2_UI "Enable LV2 plug-in user interface" ON)
option_ex(SFIZZ_PUREDATA "Enable Puredata plug-in build" OFF)
option_ex(SFIZZ_USE_SYSTEM_LV2 "Use LV2 headers preinstalled on system" OFF)
option_ex(SFIZZ_USE_SYSTEM_VST3SDK "Use VST3SDK source files preinstalled on system" OFF)
option_ex(SFIZZ_VST2 "Enable VST2 plug-in build (unsupported)" OFF)
option_ex(SFIZZ_VST "Enable VST plug-in build" ON)
set(MIDI_CC_MAX 512 CACHE STRING "Maximum amount of Control Change Messages")
include(SfizzConfig) # Re-used for this project
include(BundleDylibs)
add_subdirectory(library)
add_subdirectory(plugins)
# Windows installer
if(WIN32)
include(VSTConfig)
configure_file(${PROJECT_SOURCE_DIR}/scripts/innosetup.iss.in
${PROJECT_BINARY_DIR}/innosetup.iss @ONLY)
endif()
# Put it at the end so that the vst/lv2 directories are registered
if (NOT MSVC)
include(PluginsUninstall)
endif()
show_build_info_if_needed()

223
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,223 @@
# Contributing to sfizz
Thanks for considering contributing!
There is actually many things anyone can do, programming-related or music-related.
## Using the software for your projects
One of the best and probably simplest thing to do is simply to use sfizz in a number of situations.
There is only so much we can test as far as sfz libraries go, or differents hosts for the plugin versions.
If during the course of your usage you find out that sfizz does not behave as it should with respect to what the SFZ spec dictates, or what other players do, please file in a bug reports.
If there is some feature that would be fantastic for you, feel free to post a feature requests in the issues.
This will help us track and remember everything.
Refer to (#filing-bugs-and-feature-requests) for more precision.
### Filing bugs and feature requests
When filing a bug, try to be as precise as possible.
Obviously bugs that are easily reproducible are easier to solve.
- If sfizz fails to play a library correctly, please give us a link to the library and ideally an example of what you except. It helps **tremendously** if you can provide a *minimal* example in the form of a simple custom sfz library that pinpoints the problem exactly, along with instruction or midi files to render.
- If the plugins crashes, please try to reproduce and detail everything you did up to the crash, as well as the host and sfz library. It can be really helpful to provide session files, again with a minimal example.
- If the behavior of sfizz is clumsy and annoying, and the user experience feels subpar, please tell us and try to propose some solutions on how it could be improved. As developers, we are viewing and using sfizz in specific ways which may actually be quite far from what users would like, but we're all ears :)
For feature requests, provide details about the expected behavior and possibly example sfz files that will benefit from the new feature.
Note that we aim at implementing the sfz spec as a whole, and possibly some extensions by e.g. ARIA so normally all sfz features should come at some point.
### Using the C or C++ library
Sfizz is liberally licensed and you can freely use it in any project under the term of its license and its dependencies.
We provide a somewhat simple C and C++ API that covers our use cases within plugins mostly, and should be useful.
The API is documented over at the [api] page.
You can find example of using the C API in the `lv2` directory which contains sfizz's LV2 plugin.
You can find example of using the C++ API in the `vst3` directory which contains sfizz's VST3 plugin.
In both cases sfizz is built in the plugins as a static library.
The project [sfizz-render] illustrates how one might use sfizz as a shared library through a `make`- and `pkg-config`-based process.
Other projects that bundle or use sfizz are:
- (https://github.com/sfztools/beatbox): a live drum machine
If you use the library, maybe you will have specific needs and requests that could be useful to you.
Be sure to post an issue for this so we can improve the API, especially because we have to queue API changes so it stays a bit stable over time.
## Developing for sfizz
We welcome all code contributions to sfizz, whatever your coding level.
If there is a specific feature you would like, and you are willing to put in the time (and have some form of initial background in modern C++ code), we can mentor you and provide breadcrumbs through the codebase.
Sfizz is still very much alpha, and we're refactoring large parts of the code on a regular basis.
We try to keep the public API documented, and most of the internal APIs are also documented, but this can be in flux from time to time.
If you want to add things we encourage you to ask around through an issue, on Discord, IRC, or by email, so that we may be able to guide you and discuss about how and what to implement.
### Handling the repository and its submodules
Sfizz uses a number of submodules, namely abseil and the VST sdk.
These submodules are purely consumed by sfizz, and the maintainers will manage updating them when needed.
As such, they should *not* pose too much issues.
They are all pinned to specific branches or commits in their original repository.
To clone the sfizz repository, the recommended way is to do
```bash
git clone https://github.com/sfztools/sfizz.git --recursive
# Other possibility
git clone https://github.com/sfztools/sfizz.git
cd sfizz
git submodule update --init
```
If after some time you happen to see something like this:
```
git status
On branch develop
Your branch is up to date with 'origin/develop'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: external/abseil-cpp (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
```
Then it means that the abseil submodule *on your disk* differs from the one expected by sfizz.
This usually happens if i) you modified one of abseil's files, in which case the repository will be dirty, or ii) sfizz updated abseil's and pinned it to another commit.
Assuming you were not adding relevant changes to abseil in order to push them upstream, you can usually resolve this issue through
```bash
git submodule update
```
**All changes in the submodule will be lost**.
If you were in fact modifying abseil for some reason, then consider either pushing your changes upstream or find an alternative.
Same goes for the VST SDK.
### Building sfizz from source
For details on the dependencies and platform-specific information for building sfizz, please refer to the [build] page.
Note that for development you will probably want all dependencies, which means using debian's lingo:
- `cmake`
- `g++` or `clang++`
- `clang-format`
- `libjack-jackd2-dev`
- `libsndfile-dev`
We also recommend building [benchmark] from source and installing it as a static library.
You will also want to configure using the `-DSFIZZ_TESTS=ON` flag and `-DSFIZZ_BENCHMARKS=ON` flag to be able to run the tests and possibly the micro-benchmarks.
### Forking and creating pull requests
We do development on the git `develop` branch, and distribute using the `master` branch.
We mostly avoid directly committing to the `develop` branch and go through pull requests and issues for development-related discussion and choices.
Try to have public and private discussion about development, and if such discussion happen on IRC or Discord, try to sum them up in a pull request or an issue that we can then refer to.
Obviously, light technical questions can be asked freely in private, but the goal is to open the discussion for everyone to see.
To start contributing, we encourage you to fork the main sfizz repository on your personal account and clone it locally on your machine
In the clone of your fork, and add the `sfztools` repository as a remote as follows
```bash
# Clone your own fork in a specific directory
git clone https://github.com/MY_GITHUB_NAME/sfizz.git sfizz-fork
cd sfizz-fork
# Add the upstream sfztools remote
git remote add upstream https://github.com/sfztools/sfizz.git
```
Once done, the contribution process is as follows:
1. Fetch the latest changes from the `upstream` remote, in particular the `develop` branch.
2. Checkout the `upstream/develop` branch, and immediately checkout to a new local branch to start adding changes
3. Add commits to your local branch
4. Push the local branch to your own fork
5. Go back to Github web interface and create a pull request
In command language, this translates to
```bash
# Fetch the latest status from upstrea
git fetch upstream
# Checkout the upstream develop branch
git checkout upstream/develop
# Create a new local branch
git checkout -b my-new-contribution
# Do things as usual for git: git add, git commit
# ...
# Once ready, push the branch to your fork. Github will tell you where to go for a pull request from there.
git push --set-upstream origin my-new-contribution
```
### Adding files to the build system
We use CMake for the build system.
For the main sfizz library, the main file is `src/CMakeLists.txt`.
In particular if you add a new `.cpp` file to sfizz, you should add it to the `SFIZZ_SOURCES` list in this file so it gets compiled and linked with the rest of the library.
### Coding style and guidelines
We have continuous integration targets down to gcc 4.9, so the code has to be fully C++11 compliant.
Sadly this means some bonuses from C++14 are not available, although `absl` compensates many things from a standard library point of view.
All modern C++ guidelines apply, as well as rules related to audio programming:
- Raw pointers are non-owning observers; use `unique_ptr` and `shared_ptr` for owning references, and `absl::optional` for nullable/optional/maybe values returned from functions.
- Use move semantics when appropriate.
- Try to use [RAII] wrappers and write them if necessary.
- Avoid allocating memory, calling functions that throw, using system calls, or any launching any blocking operation in the audio thread; for sfizz, that means anything that is called at some point from `Synth::renderBlock` and `Synth::noteOn`, `noteOff`, ... and all midi events.
- We have a helper class that helps us to track allocation in the form of the `sfz::Buffer` class and the `sfz::AudioBuffer` class, so use it for heap memory in lieu of naked `new` or `unique_ptr<T[]>` when relevant.
- Most things in the [CppCoreGuidelines] are good to take, although be careful as many proposed things may break the *no allocation* rule.
We also have a `clang-tidy` CI step that may annoy you from time to time.
We have a `clang-format` coding style in that is loosely based on the WebKit style.
We encourage you to use it, as well as `git-clang-format` to format your PR.
If possible, find a plugin for your text editor than handles `.editorconfig` files. Most editors have one.
Some notes :
- Class and type names start by a capital letter and follow the `PascalCase`, function names and variables in the C++ part follow the `camelCase`, and function names and variables in the C part follows a `snake_case` to blend with the surroundings.
- Try to keep names meaningful, and code clear if possible.
- Comment your classes APIs, in a terse and clear way. Comments inside the code are usually not needed *if the code is written clearly with meaningful names*, but if you feel that it's needed please do.
- You can use `_` in front of private variables, but we do not have a consistent naming for these yet.
All these rules are subject to change upon discussion and integration.
### Testing your changes
To build and run the tests, you need to have configured sfizz with the `-DSFIZZ_TESTS=ON` flag.
You can then use the `make sfizz_tests` command from your build directory.
The tests are located in `tests/sfizz_tests` from the same build directory.
Note that these tests mostly cover the parsing and observable invariants of sfizz, as well as all helper methods as much as possible.
The processing and rendering is usually harder to test as it produces alot of data.
We are in the process of making a testing platform using rendered wave files, but it is not yet here.
If you write anything testable however, we encourage you to write the tests.
We use the [Catch] library for testing, and you can check out the files in `tests/` for examples on how to add some.
To actually try your changes, you can use the `clients/sfizz_jack` client to instantiate a JACK application, or use `jalv` for a similar purpose by launching from your build directory
```bash
env LV2_PATH=$PWD jalv.gtk3 http://sfztools.github.io/sfizz
```
Similarly, you can launch e.g. Ardour with suitable reference to your version of the sfizz LV2 plugin with
```bash
env LV2_PATH=$PWD Ardour6
```
### Running micro-benchmarks
For micro-optimization purposes we have a number of benchmarks written in `benchmarks/`, build against the [benchmark] library.
If you wonder about the performance of something, feel free to write some too and add them to the build system.
We tend to name the benchmarks with the `bm_` prefix.
It can be as simple as adding a line
```cmake
sfizz_add_benchmark(bm_wavfile BM_wavfile.cpp)
```
to the `benchmarks/CMakeLists.txt` file but you might need to link to other libraries depending on what you are benchmarking.
The `CMakeLists.txt` file contains example that you can copy and try.
### Running in-use benchmarks
We have logging facilities for the processing inside of sfizz, that we use to track how the additions impact the rendering speed.
For now the usage is a bit hand-made, as it requires the [sfizz-render] program and manually pre-loading the development `.so` library.
The logger outputs CSV files for the rendering and file-loading processes.
The file `scripts/performance_report.py` is made to process and produce a nice interactive report from this data.
[build]: https://sfz.tools/sfizz/development/build/
[benchmark]: https://github.com/google/benchmark
[sfizz-render]: https://github.com/sfztools/sfizz-render
[GOVERNANCE]: GOVERNANCE.md
[api]: https://sfz.tools/sfizz/api/
[RAII]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-resource
[CppCoreGuidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
[Catch]: https://github.com/catchorg/Catch2

1
FUNDING.yml Normal file
View file

@ -0,0 +1 @@
open_collective: sfztools

56
GOVERNANCE.md Normal file
View file

@ -0,0 +1,56 @@
## Leadership
The current maintainers of sfizz and the sfz tools organization are :
- Paul "@paulfd" Ferrand
- Jean-Pierre "@jpcima" Cimalando
- Andrea "@redtide" Zanellato
1. Sfizz does not follow a so-called "Benevolent Dictatorship for Life" model.
Given the current size of the project, we believe an horizontal organization model to be the most relevant.
2. Decisions regarding the technical part or the organizational part of the project are taken unanimously between the maintainers, where anyone can obviously abstain on any decision.
3. We use Git as a global supporting platform for all decisions regarding the project, in the form of either pull requests or issues.
This guarantees that a trace is kept for any contribution or change, and that users may interject and discuss on the subject at hand.
## Donations and financial contributions
In most jurisdictions, handling money requires bank accounts and identification as a physical person, or be incorporated as a non-profit or for-profit organization.
We wish to:
- keep things simple;
- support the horizontal governance model we chose;
- facilitate a transparent handling of the finances of the project from the maintainers;
- abide by international laws for the transfer and handling of money in support of a project.
Considering these constraints, we chose to host the SFZ tools organization within the [SFZTools Open Collective].
The Open Collective fiscal host holds the money of unincorporated partnerships such as SFZ tools, providing legal channels and accounting, as well as tools to support a transparent budget management by members of the collective.
We apply the following ruleset to handle the project's financial resources:
1. As everything in SFZ tools, usage of the project's financial resources is subject to unanimous approval by all maintainers.
2. The money is primarily directed towards expenses to support hosting the project---namely the website, and continuous testing and integration platforms.
3. At any time, a maintainer may submit an expense request regarding the development of sfizz, for example but not limited to software resources, commercial SFZ libraries, or hardware devices.
4. Every 3 months, during the months of March, June, September and December, the maintainers will gather in a budget meeting. The goal of the budget meeting decide in goodwill how to handle the money left over between contributors to the project.
5. The partition should take into account individual technical and organizational contributions.
The partition may also include other project that sfizz uses or wish to support.
6. Any contributor may waive its own share to benefit either the project---pooling back resources for the next round---or the other contributors.
7. Failure to reach a unanimous agreement will see the donations pooled back until the next budget meeting.
8. The budget and expenses are kept public so all donators can keep track of how their donations are used.
Note that the Open Collective platform charges a 10% administrative fee on all donations; subsequent fees may be charged by credit card or banks as the money is moved from the collective to individual accounts.
## Changes to the governance model
1. This document is subject to changes and version control.
It is the role of maintainers to best adapt the governance model to the evolution of the project.
2. Change to the governance model are mapped to changes to this document through the same decision process, e.g. a pull request with approval from all maintainers.
3. Maintainers can be invited from regular contributors at any point in time; maintainers wishing to leave the governance of the project may inform the other maintainers.
In both cases, updates to this document reflect the evolution of the governance team and rules.
## License for the GOVERNANCE.md file
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided that this notice
is preserved. This file is offered as-is, without any warranty.
[Open-source Open Collective]: https://opencollective.com/sfztools

25
LICENSE Normal file
View file

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2021-2023, sfizz contributors (detailed in AUTHORS.md)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

110
README.md Normal file
View file

@ -0,0 +1,110 @@
# sfizz
![build](https://github.com/sfztools/sfizz/actions/workflows/build.yml/badge.svg)
[![Discord Badge Image]](https://discord.gg/3ArE9Mw)
[![SFZv1 Status Image]](https://sfz.tools/sfizz/development/status/opcodes/?v=1)
[![SFZv2 Status Image]](https://sfz.tools/sfizz/development/status/opcodes/?v=2)
[![ARIA Status Image]](https://sfz.tools/sfizz/development/status/opcodes/?v=aria)
[![Cakewalk Status Image]](https://sfz.tools/sfizz/development/status/opcodes/?v=cakewalk)
SFZ parser and synth c++ library, providing AU / LV2 / VST3 plugins
and JACK standalone client, please check [our website] for more details.
![Screenshot](screenshot.png)
## Using sfizz
Sfizz can be used most easily within an LV2 host such as [Carla] or [Ardour].
It can also be integrated as a library within your own program; check out our [API] bindings for C and C++.
Our [releases] are an immediate way to get a working library or LV2/VST plugin for Windows and Mac.
Linux builds are available over at [OBS].
On any operating system, you might prefer to [build from source]!
## Contributing to sfizz
There is actually many things anyone can do, programming-related or music-related.
Please check out the [CONTRIBUTING](CONTRIBUTING.md) document for information about filing bug reports or feature requests, and helping the development of sfizz
## Donating to sfizz
Sfizz and the work in the SFZ tools organization is purely driven by hobbyists who choose to use their free time to benefit this project.
We firmly believe in the honesty and goodwill of users as a whole, and we want to promote a healthy relationship to software and to the cost of producing quality software.
No financial returns is explicitely required from using sfizz in any shape.
However, if you feel that sfizz produces value for you or your products, and if you find that your financial situation allows for it, we put together ways to donate to the project.
You are never compelled to do so, the [CONTRIBUTING](CONTRIBUTING.md) file contains different ways to contribute.
In all of sfizz's governance model, we strive to live in the open.
Finances are no different, and we put in place a process so that the use of donations is as transparent as possible through our [Open Collective].
We invite you to check out the [GOVERNANCE](GOVERNANCE.md) file to see how the organization is governed and how are donations handled.
## Dependencies and licenses
The sfizz library has the option to be compiled against either the `dr_libs`
audio libraries, which is now the default option, or `libsndfile`.
- [dr_libs] is licensed under the MIT No Attribution license
- [libsndfile] is licensed under the GNU Lesser General Public License v2.1
The sfizz library makes primary use of:
- [Abseil], licensed under the Apache License 2.0
- [atomic_queue] by Maxim Egorushkin, licensed under the MIT license
- [filesystem] by Steffen Schümann, licensed under the BSD 3-Clause license
- [hiir] by Laurent de Soras, licensed under the WTFPL v2 license
- [KISS FFT] by Mark Borgerding, licensed under the BSD 3-Clause license
- [Surge tuning] by Paul Walker, licensed under the MIT license
- [pugixml] by Arseny Kapoulkine, licensed under the MIT license
- [cephes] by Stephen Moshier, licensed under the BSD 3-Clause license
- [cpuid] by Steinwurf ApS, licensed under the BSD 3-Clause license
- [faust-libraries] by GRAME, Julius O. Smith III and Eric Tarr, licensed under the STK-4.3 license and a permissive variant of the LGPL license
The sfizz library also uses in some subprojects:
- [Catch2], licensed under the Boost Software License 1.0
- [benchmark], licensed under the Apache License 2.0
- [LV2], licensed under the ISC license
- [JACK], licensed under the GNU Lesser General Public License v2.1
- [cxxopts] by Jarryd Beck, licensed under the MIT license
- [fmidi] by Jean Pierre Cimalando, licensed under the Boost Software License 1.0
- [libsamplerate], licensed under the BSD 2-Clause license
- [GLSL-Color-Spaces] by tobspr, licensed under the MIT license
- [stb_image] by Sean Barrett, licensed as public domain or MIT license
[Abseil]: https://abseil.io/
[atomic_queue]: https://github.com/max0x7ba/atomic_queue
[benchmark]: https://github.com/google/benchmark
[Catch2]: https://github.com/catchorg/Catch2
[filesystem]: https://github.com/gulrak/filesystem
[Surge tuning]: https://surge-synth-team.org/tuning-library/
[pugixml]: https://pugixml.org/
[cephes]: https://www.netlib.org/cephes/
[cpuid]: https://github.com/steinwurf/cpuid
[dr_libs]: https://github.com/mackron/dr_libs
[faust-libraries]: https://github.com/grame-cncm/faustlibraries
[hiir]: http://ldesoras.free.fr/prod.html#src_hiir
[KISS FFT]: http://kissfft.sourceforge.net/
[JACK]: https://github.com/jackaudio/jack2
[cxxopts]: https://github.com/jarro2783/cxxopts
[fmidi]: https://github.com/jpcima/fmidi
[libsamplerate]: http://www.mega-nerd.com/SRC/
[libsndfile]: http://www.mega-nerd.com/libsndfile/
[LV2]: https://lv2plug.in/
[GLSL-Color-Spaces]: https://github.com/tobspr/GLSL-Color-Spaces
[stb_image]: https://github.com/nothings/stb
[our website]: https://sfz.tools/sfizz
[releases]: https://github.com/sfztools/sfizz/releases
[Carla]: https://kx.studio/Applications:Carla
[Ardour]: https://ardour.org/
[API]: https://sfz.tools/sfizz/api/
[Open Collective]: https://opencollective.com/sfztools
[build from source]: https://sfz.tools/sfizz/development/build/
[AppVeyor Build Status]: https://img.shields.io/appveyor/ci/sfztools/sfizz.svg?label=Windows&style=popout&logo=appveyor
[Travis Build Status]: https://img.shields.io/travis/com/sfztools/sfizz.svg?label=Linux&style=popout&logo=travis
[Discord Badge Image]: https://img.shields.io/discord/587748534321807416?label=discord&logo=discord
[OBS]: https://software.opensuse.org//download.html?project=home%3Asfztools%3Asfizz&package=sfizz
[SFZv1 Status Image]: https://sfz.tools/assets/img/sfizz/badge_sfz1.svg
[SFZv2 Status Image]: https://sfz.tools/assets/img/sfizz/badge_sfz2.svg
[ARIA Status Image]: https://sfz.tools/assets/img/sfizz/badge_aria.svg
[Cakewalk Status Image]: https://sfz.tools/assets/img/sfizz/badge_cakewalk.svg

32
cmake/BundleDylibs.cmake Normal file
View file

@ -0,0 +1,32 @@
# Dylib bundler for macOS
# Requires the external program "dylibbundler"
if(APPLE)
find_program(DYLIBBUNDLER_PROGRAM "dylibbundler")
if(NOT DYLIBBUNDLER_PROGRAM)
message(WARNING "The installation helper \"dylibbundler\" is not available.")
endif()
endif()
function(bundle_dylibs NAME PATH)
if(NOT APPLE OR NOT DYLIBBUNDLER_PROGRAM)
return()
endif()
set(_relative_libdir "../Frameworks")
get_filename_component(_dir "${PATH}" DIRECTORY)
set(_dir "${_dir}/${_relative_libdir}")
set(_script "${CMAKE_CURRENT_BINARY_DIR}/_bundle-dylibs.${NAME}.cmake")
file(WRITE "${_script}"
"execute_process(COMMAND \"${DYLIBBUNDLER_PROGRAM}\"
\"-cd\" \"-of\" \"-b\"
\"-x\" \"\$ENV{DESTDIR}${PATH}\"
\"-d\" \"\$ENV{DESTDIR}${_dir}\"
\"-p\" \"@loader_path/${_relative_libdir}/\")
")
install(SCRIPT "${_script}" ${ARGN})
endfunction()

126
cmake/LV2Config.cmake Normal file
View file

@ -0,0 +1,126 @@
# This option is for MIDI CC support in absence of host midi:binding support
option(SFIZZ_LV2_PSA "Enable plugin-side MIDI automations" ON)
# Configuration for this plugin
# TODO: generate version from git
set(LV2PLUGIN_VERSION_MINOR 10)
set(LV2PLUGIN_VERSION_MICRO 3)
set(LV2PLUGIN_NAME "sfizz")
set(LV2PLUGIN_COMMENT "SFZ sampler")
set(LV2PLUGIN_URI "http://sfztools.github.io/sfizz")
set(LV2PLUGIN_REPOSITORY SFIZZ_REPOSITORY)
set(LV2PLUGIN_AUTHOR "SFZTools")
set(LV2PLUGIN_EMAIL "paul@ferrand.cc")
if(SFIZZ_USE_VCPKG)
set(LV2PLUGIN_SPDX_LICENSE_ID "LGPL-3.0-only")
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(APPLE)
set(LV2PLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/LV2" CACHE STRING
"Install destination for LV2 bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/LV2]")
elseif(MSVC)
set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lv2" CACHE STRING
"Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lv2]")
else()
set(LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING
"Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/lv2]")
endif()
include(StringUtility)
function(sfizz_lv2_generate_controllers_ttl FILE)
file(WRITE "${FILE}" "# LV2 parameters for SFZ controllers
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix midi: <http://lv2plug.in/ns/ext/midi#> .
@prefix patch: <http://lv2plug.in/ns/ext/patch#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sfizz: <${LV2PLUGIN_URI}#> .
")
math(EXPR _j "${MIDI_CC_MAX}-1")
foreach(_i RANGE "${_j}")
if(_i LESS 128 AND SFIZZ_LV2_PSA)
continue() # Don't generate automation parameters for CCs with plugin-side automation
endif()
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" "
sfizz:cc${_i}
a lv2:Parameter ;
rdfs:label \"Controller ${_i}\" ;
rdfs:range atom:Float ;
lv2:minimum 0.0 ;
lv2:maximum 1.0")
if(_i LESS 128 AND NOT SFIZZ_LV2_PSA)
math(EXPR _digit1 "${_i}>>4")
math(EXPR _digit2 "${_i}&15")
string(SUBSTRING "0123456789ABCDEF" "${_digit1}" 1 _digit1)
string(SUBSTRING "0123456789ABCDEF" "${_digit2}" 1 _digit2)
file(APPEND "${FILE}" " ;
midi:binding \"B0${_digit1}${_digit2}00\"^^midi:MidiEvent .
")
else()
file(APPEND "${FILE}" " .
")
endif()
endforeach()
file(APPEND "${FILE}" "
<${LV2PLUGIN_URI}>
a lv2:Plugin ;
")
file(APPEND "${FILE}" " patch:readable")
if(NOT SFIZZ_LV2_PSA)
file(APPEND "${FILE}" " sfizz:cc000")
foreach(_i RANGE 1 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
else()
file(APPEND "${FILE}" " sfizz:cc128")
foreach(_i RANGE 129 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
endif()
file(APPEND "${FILE}" " ;
")
file(APPEND "${FILE}" " patch:writable")
if(NOT SFIZZ_LV2_PSA)
file(APPEND "${FILE}" " sfizz:cc000")
foreach(_i RANGE 1 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
else()
file(APPEND "${FILE}" " sfizz:cc128")
foreach(_i RANGE 129 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
endif()
file(APPEND "${FILE}" " .
")
endfunction()

View file

@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif()
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif()
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif()
endforeach()

View file

@ -0,0 +1,19 @@
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/MakeUninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/MakeUninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/MakeUninstall.cmake)
if(SFIZZ_LV2 AND LV2PLUGIN_INSTALL_DIR)
add_custom_command(TARGET uninstall
COMMAND rm -rv "${LV2PLUGIN_INSTALL_DIR}/${PROJECT_NAME}.lv2")
endif()
if(SFIZZ_VST AND VSTPLUGIN_INSTALL_DIR)
add_custom_command(TARGET uninstall
COMMAND rm -rv "${VSTPLUGIN_INSTALL_DIR}/${PROJECT_NAME}.vst3")
endif()
endif()

View file

@ -0,0 +1,70 @@
find_path(PD_INCLUDE_BASEDIR "m_pd.h" PATH_SUFFIXES "pd")
set(PD_IMP_DEF "${PROJECT_SOURCE_DIR}/plugins/puredata/external/pd/bin/pd.def")
if(PD_INCLUDE_BASEDIR)
message(STATUS "Puredata headers: ${PUREDATA_INCLUDE_DIR}")
else()
message(STATUS "Puredata headers not found, using our own")
set(PD_INCLUDE_BASEDIR "${PROJECT_SOURCE_DIR}/plugins/puredata/external/pd/include")
endif()
if(WIN32)
set(PUREDATA_SUFFIX ".dll")
elseif(APPLE)
set(PUREDATA_SUFFIX ".pd_darwin")
else()
set(PUREDATA_SUFFIX ".pd_linux")
endif()
if(APPLE)
set(PDPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Pd" CACHE STRING
"Install destination for Puredata bundle [default: $ENV{HOME}/Library/Pd]")
elseif(MSVC)
set(PDPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/Pd/extra" CACHE STRING
"Install destination for Puredata bundle [default: ${CMAKE_INSTALL_PREFIX}/Pd/extra]")
else()
set(PDPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/pd/extra" CACHE STRING
"Install destination for Puredata bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/pd/extra]")
endif()
if(WIN32)
add_library(pdex-implib STATIC IMPORTED)
if(MSVC)
add_custom_command(
OUTPUT "pd.lib"
COMMAND "lib" "/out:pd.lib" "/def:${PD_IMP_DEF}" "/machine:${MSVC_C_ARCHITECTURE_ID}"
DEPENDS "${PD_IMP_DEF}")
add_custom_target(pdex-implib-generated
DEPENDS "pd.lib")
set_target_properties(pdex-implib PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/pd.lib")
else()
find_program(PD_DLLTOOL_PROGRAM "dlltool")
if(NOT PD_DLLTOOL_PROGRAM)
message(FATAL_ERROR "Cannot find dlltool")
endif()
add_custom_command(
OUTPUT "libpd.dll.a"
COMMAND "${PD_DLLTOOL_PROGRAM}" "-l" "libpd.dll.a" "-d" "${PD_IMP_DEF}"
DEPENDS "${PD_IMP_DEF}")
add_custom_target(pdex-implib-generated
DEPENDS "libpd.dll.a")
set_target_properties(pdex-implib PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/libpd.dll.a")
endif()
add_dependencies(pdex-implib pdex-implib-generated)
endif()
function(add_pd_external TARGET)
add_library("${TARGET}" MODULE ${ARGN})
target_include_directories("${TARGET}" PRIVATE "${PD_INCLUDE_BASEDIR}")
set_target_properties("${TARGET}" PROPERTIES
PREFIX ""
SUFFIX "${PUREDATA_SUFFIX}")
if(APPLE)
set_property(TARGET "${TARGET}" APPEND_STRING
PROPERTY LINK_FLAGS " -Wl,-undefined,suppress,-flat_namespace")
elseif(WIN32)
target_link_libraries("${TARGET}" PRIVATE pdex-implib)
endif()
endfunction()

11
cmake/StringUtility.cmake Normal file
View file

@ -0,0 +1,11 @@
# SPDX-License-Identifier: BSD-2-Clause
function(string_left_pad VAR INPUT LENGTH FILLCHAR)
set(_output "${INPUT}")
string(LENGTH "${_output}" _length)
while(_length LESS "${LENGTH}")
set(_output "${FILLCHAR}${_output}")
string(LENGTH "${_output}" _length)
endwhile()
set("${VAR}" "${_output}" PARENT_SCOPE)
endfunction()

48
cmake/VSTConfig.cmake Normal file
View file

@ -0,0 +1,48 @@
set(VSTPLUGIN_NAME "sfizz")
set(VSTPLUGIN_VENDOR "SFZTools")
set(VSTPLUGIN_URL "http://sfztools.github.io/sfizz")
set(VSTPLUGIN_EMAIL "paul@ferrand.cc")
if(APPLE)
set(VSTPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/VST3" CACHE STRING
"Install destination for VST bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/VST3]")
set(AUPLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/Components" CACHE STRING
"Install destination for AudioUnit bundle [default: $ENV{HOME}/Library/Audio/Plug-Ins/Components]")
elseif(MSVC)
set(VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/vst3" CACHE STRING
"Install destination for VST bundle [default: ${CMAKE_INSTALL_PREFIX}/vst3]")
else()
set(VSTPLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/vst3" CACHE STRING
"Install destination for VST bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/vst3]")
endif()
if(NOT VST3_SYSTEM_PROCESSOR)
set(VST3_SYSTEM_PROCESSOR "${PROJECT_SYSTEM_PROCESSOR}")
endif()
message(STATUS "The system architecture is: ${VST3_SYSTEM_PROCESSOR}")
# --- VST3 Bundle architecture ---
if(NOT VST3_PACKAGE_ARCHITECTURE)
if(APPLE)
# VST3 packages are universal on Apple, architecture string not needed
else()
if(VST3_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64)$")
set(VST3_PACKAGE_ARCHITECTURE "x86_64")
elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(i.86|x86|X86)$")
if(WIN32)
set(VST3_PACKAGE_ARCHITECTURE "x86")
else()
set(VST3_PACKAGE_ARCHITECTURE "i386")
endif()
elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(armv[3-8][a-z]*)$")
set(VST3_PACKAGE_ARCHITECTURE "${VST3_SYSTEM_PROCESSOR}")
elseif(VST3_SYSTEM_PROCESSOR MATCHES "^(aarch64)$")
set(VST3_PACKAGE_ARCHITECTURE "aarch64")
else()
message(FATAL_ERROR "We don't know this architecture for VST3: ${VST3_SYSTEM_PROCESSOR}.")
endif()
endif()
endif()
message(STATUS "The VST3 architecture is deduced as: ${VST3_PACKAGE_ARCHITECTURE}")

1
library Submodule

@ -0,0 +1 @@
Subproject commit 37bf8fe7baf38e24fd9b16686a1030a5230f20f9

BIN
mac/dmg-back.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

251
mac/dmg-back.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

BIN
mac/dmg-back@2x.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

60
plugins/CMakeLists.txt Normal file
View file

@ -0,0 +1,60 @@
add_library(plugins-common STATIC EXCLUDE_FROM_ALL
"common/plugin/RMSFollower.h"
"common/plugin/MessageUtils.h"
"common/plugin/MessageUtils.cpp"
"common/plugin/InstrumentDescription.h"
"common/plugin/InstrumentDescription.cpp"
"common/plugin/NativeHelpers.h"
"common/plugin/NativeHelpers.cpp"
"common/plugin/SfizzFileScan.h"
"common/plugin/SfizzFileScan.cpp"
"common/plugin/FileTrie.h"
"common/plugin/FileTrie.cpp"
"common/plugin/SfizzForeignPaths.h"
"common/plugin/SfizzForeignPaths.cpp"
"common/plugin/SfizzSettings.h"
"common/plugin/SfizzSettings.cpp")
if(APPLE)
target_sources(plugins-common PRIVATE
"common/plugin/SfizzForeignPaths.mm"
"common/plugin/SfizzSettings.mm"
"common/plugin/NativeHelpers.mm")
set_property(
SOURCE "common/plugin/SfizzForeignPaths.mm"
"common/plugin/SfizzSettings.mm"
"common/plugin/NativeHelpers.mm"
APPEND_STRING
PROPERTY COMPILE_FLAGS " -fobjc-arc")
endif()
target_include_directories(plugins-common PUBLIC "common")
target_link_libraries(plugins-common
PUBLIC sfizz::spin_mutex
PUBLIC sfizz::simde sfizz::filesystem absl::strings
PRIVATE sfizz::pugixml
PRIVATE sfizz::internal sfizz::sfizz)
add_library(sfizz::plugins-common ALIAS plugins-common)
# Link system dependencies
if(WIN32)
elseif(ANDROID)
elseif(APPLE)
target_link_libraries(plugins-common PRIVATE
"${APPLE_FOUNDATION_LIBRARY}")
else()
endif()
if((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2)
add_subdirectory(editor)
endif()
if(SFIZZ_LV2)
add_subdirectory(lv2)
endif()
if((SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2) AND NOT (PROJECT_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc).*"))
add_subdirectory(vst)
endif()
if(SFIZZ_PUREDATA)
add_subdirectory(puredata)
endif()

View file

@ -0,0 +1,108 @@
// 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 "FileTrie.h"
#include <iostream>
#include <stdexcept>
#include <cassert>
constexpr size_t FileTrie::npos;
fs::path FileTrie::at(size_t index) const
{
if (index >= entries_.size())
throw std::out_of_range("FileTrie::at");
return pathFromEntry(index);
}
fs::path FileTrie::operator[](size_t index) const
{
assert(index < entries_.size());
return pathFromEntry(index);
}
fs::path FileTrie::pathFromEntry(size_t index) const
{
const Entry* currentEntry = &entries_[index];
fs::path path = fs::u8path(currentEntry->name);
size_t currentIndex;
while ((currentIndex = currentEntry->parent) != npos) {
currentEntry = &entries_[currentIndex];
path = fs::u8path(currentEntry->name) / path;
}
return path;
}
std::ostream& operator<<(std::ostream& os, const FileTrie& trie)
{
os << '{' << '\n';
for (size_t i = 0, n = trie.size(); i < n; ++i)
os << '\t' << i << ':' << ' ' << trie[i] << ',' << '\n';
os << '}';
return os;
}
//------------------------------------------------------------------------------
FileTrieBuilder::FileTrieBuilder(size_t initialCapacity)
{
FileTrie& trie = trie_;
trie.entries_.reserve(initialCapacity);
}
FileTrie&& FileTrieBuilder::build()
{
FileTrie& trie = trie_;
trie.entries_.shrink_to_fit();
return std::move(trie);
}
size_t FileTrieBuilder::addFile(const fs::path& path)
{
if (path.empty())
return FileTrie::npos;
size_t dirIndex = ensureDirectory(path.parent_path());
FileTrie& trie = trie_;
FileTrie::Entry ent;
ent.parent = dirIndex;
ent.name = (--path.end())->u8string();
size_t fileIndex = trie.entries_.size();
trie.entries_.push_back(std::move(ent));
return fileIndex;
}
size_t FileTrieBuilder::ensureDirectory(const fs::path& dirPath)
{
if (dirPath.empty())
return FileTrie::npos;
const fs::path::string_type& dirNat = dirPath.native();
auto it = directories_.find(dirNat);
if (it != directories_.end())
return it->second;
FileTrie& trie = trie_;
FileTrie::Entry ent;
ent.parent = FileTrie::npos;
ent.name = (--dirPath.end())->u8string();
if (dirPath.has_parent_path()) {
fs::path parentPath = dirPath.parent_path();
if (parentPath != dirPath)
ent.parent = ensureDirectory(parentPath);
}
size_t dirIndex = trie.entries_.size();
trie.entries_.push_back(std::move(ent));
directories_[dirNat] = dirIndex;
return dirIndex;
}

View file

@ -0,0 +1,52 @@
// 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 <ghc/fs_std.hpp>
#include <string>
#include <vector>
#include <unordered_map>
#include <iosfwd>
#include <cstddef>
class FileTrie {
public:
static constexpr size_t npos = ~size_t(0);
size_t size() const noexcept { return entries_.size(); }
fs::path at(size_t index) const;
fs::path operator[](size_t index) const;
void clear() noexcept { entries_.clear(); }
private:
fs::path pathFromEntry(size_t index) const;
private:
struct Entry {
size_t parent = npos;
std::string name;
};
std::vector<Entry> entries_;
friend class FileTrieBuilder;
};
std::ostream& operator<<(std::ostream& os, const FileTrie& trie);
//------------------------------------------------------------------------------
class FileTrieBuilder {
public:
explicit FileTrieBuilder(size_t initialCapacity = 8192);
FileTrie&& build();
size_t addFile(const fs::path& path);
private:
size_t ensureDirectory(const fs::path& dirPath);
private:
FileTrie trie_;
std::unordered_map<fs::path::string_type, size_t> directories_;
};

View file

@ -0,0 +1,224 @@
// 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 "InstrumentDescription.h"
#include "MessageUtils.h"
#include "sfizz.hpp"
#include <absl/strings/str_cat.h>
#include <algorithm>
#include <memory>
#include <iostream>
#include <cstring>
#include <cstdint>
template <class... Args>
static void bufferedStrCat(std::string* buffer, const Args&... args)
{
buffer->clear();
absl::StrAppend(buffer, args...);
}
std::string getDescriptionBlob(sfizz_synth_t* handle)
{
std::string blob;
blob.reserve(128 * 1024);
std::vector<char> msgbuf;
msgbuf.resize(1024);
std::string pathbuf;
pathbuf.reserve(256);
struct ClientData {
sfz::Sfizz* synth = nullptr;
sfz::Client* client = nullptr;
std::string* blob = nullptr;
std::vector<char>* msgbuf = nullptr;
std::string* pathbuf = nullptr;
};
sfz::Sfizz synth(handle);
ClientData cdata;
sfz::ClientPtr client = synth.createClient(&cdata);
cdata.synth = &synth;
cdata.client = client.get();
cdata.blob = &blob;
cdata.msgbuf = &msgbuf;
cdata.pathbuf = &pathbuf;
synth.setReceiveCallback(*client, [](void* data, int, const char* path, const char* sig, const sfizz_arg_t* args) {
ClientData& cdata = *reinterpret_cast<ClientData*>(data);
unsigned indices[8];
///
uint32_t msglen = sfizz_prepare_message(cdata.msgbuf->data(), cdata.msgbuf->size(), path, sig, args);
if (msglen > cdata.msgbuf->size()) {
cdata.msgbuf->resize(msglen);
sfizz_prepare_message(cdata.msgbuf->data(), cdata.msgbuf->size(), path, sig, args);
}
cdata.blob->append(cdata.msgbuf->data(), msglen);
///
if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b")) {
ConstBitSpan bits(args[0].b->data, 8 * args[0].b->size);
for (unsigned key = 0; key < 128 && key < bits.bit_size(); ++key) {
if (bits.test(key)) {
bufferedStrCat(cdata.pathbuf, "/key", key, "/label");
cdata.synth->sendMessage(*cdata.client, 0, cdata.pathbuf->c_str(), "", nullptr);
}
}
}
else if (Messages::matchOSC("/sw/last/slots", path, indices) && !strcmp(sig, "b")) {
ConstBitSpan bits(args[0].b->data, 8 * args[0].b->size);
for (unsigned key = 0; key < 128 && key < bits.bit_size(); ++key) {
if (bits.test(key)) {
bufferedStrCat(cdata.pathbuf, "/sw/last/", key, "/label");
cdata.synth->sendMessage(*cdata.client, 0, cdata.pathbuf->c_str(), "", nullptr);
}
}
}
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b")) {
ConstBitSpan bits(args[0].b->data, 8 * args[0].b->size);
for (unsigned cc = 0; cc < sfz::config::numCCs && cc < bits.bit_size(); ++cc) {
if (bits.test(cc)) {
bufferedStrCat(cdata.pathbuf, "/cc", cc, "/label");
cdata.synth->sendMessage(*cdata.client, 0, cdata.pathbuf->c_str(), "", nullptr);
bufferedStrCat(cdata.pathbuf, "/cc", cc, "/default");
cdata.synth->sendMessage(*cdata.client, 0, cdata.pathbuf->c_str(), "", nullptr);
bufferedStrCat(cdata.pathbuf, "/cc", cc, "/value");
cdata.synth->sendMessage(*cdata.client, 0, cdata.pathbuf->c_str(), "", nullptr);
}
}
}
});
synth.sendMessage(*client, 0, "/num_regions", "", nullptr);
synth.sendMessage(*client, 0, "/num_groups", "", nullptr);
synth.sendMessage(*client, 0, "/num_masters", "", nullptr);
synth.sendMessage(*client, 0, "/num_curves", "", nullptr);
synth.sendMessage(*client, 0, "/num_samples", "", nullptr);
synth.sendMessage(*client, 0, "/root_path", "", nullptr);
synth.sendMessage(*client, 0, "/image", "", nullptr);
synth.sendMessage(*client, 0, "/image_controls", "", nullptr);
synth.sendMessage(*client, 0, "/key/slots", "", nullptr);
synth.sendMessage(*client, 0, "/sw/last/slots", "", nullptr);
synth.sendMessage(*client, 0, "/cc/slots", "", nullptr);
synth.sendMessage(*client, 0, "/sustain_or_sostenuto/slots", "", nullptr);
blob.shrink_to_fit();
return blob;
}
InstrumentDescription parseDescriptionBlob(absl::string_view blob)
{
InstrumentDescription desc;
const uint8_t* src = reinterpret_cast<const uint8_t*>(blob.data());
uint32_t srcSize = blob.size();
char buffer[1024];
const char* path;
const char* sig;
const sfizz_arg_t* args;
int32_t byteCount;
while ((byteCount = sfizz_extract_message(src, srcSize, buffer, sizeof(buffer), &path, &sig, &args)) > 0) {
unsigned indices[8];
///
auto copyArgToBitSpan = [](const sfizz_arg_t& arg, BitSpan bits)
{
size_t size = std::min<size_t>(bits.byte_size(), arg.b->size);
memcpy(bits.data(), arg.b->data, size);
};
//
if (Messages::matchOSC("/num_regions", path, indices) && !strcmp(sig, "i"))
desc.numRegions = uint32_t(args[0].i);
else if (Messages::matchOSC("/num_groups", path, indices) && !strcmp(sig, "i"))
desc.numGroups = uint32_t(args[0].i);
else if (Messages::matchOSC("/num_masters", path, indices) && !strcmp(sig, "i"))
desc.numMasters = uint32_t(args[0].i);
else if (Messages::matchOSC("/num_curves", path, indices) && !strcmp(sig, "i"))
desc.numCurves = uint32_t(args[0].i);
else if (Messages::matchOSC("/num_samples", path, indices) && !strcmp(sig, "i"))
desc.numSamples = uint32_t(args[0].i);
else if (Messages::matchOSC("/root_path", path, indices) && !strcmp(sig, "s"))
desc.rootPath = args[0].s;
else if (Messages::matchOSC("/image", path, indices) && !strcmp(sig, "s"))
desc.image = args[0].s;
else if (Messages::matchOSC("/image_controls", path, indices) && !strcmp(sig, "s"))
desc.image_controls = args[0].s;
else if (Messages::matchOSC("/key/slots", path, indices) && !strcmp(sig, "b"))
copyArgToBitSpan(args[0], desc.keyUsed.span());
else if (Messages::matchOSC("/sw/last/slots", path, indices) && !strcmp(sig, "b"))
copyArgToBitSpan(args[0], desc.keyswitchUsed.span());
else if (Messages::matchOSC("/cc/slots", path, indices) && !strcmp(sig, "b"))
copyArgToBitSpan(args[0], desc.ccUsed.span());
else if (Messages::matchOSC("/sustain_or_sostenuto/slots", path, indices) && !strcmp(sig, "b"))
copyArgToBitSpan(args[0], desc.sustainOrSostenuto.span());
else if (Messages::matchOSC("/key&/label", path, indices) && !strcmp(sig, "s"))
desc.keyLabel[indices[0]] = args[0].s;
else if (Messages::matchOSC("/sw/last/&/label", path, indices) && !strcmp(sig, "s"))
desc.keyswitchLabel[indices[0]] = args[0].s;
else if (Messages::matchOSC("/cc&/label", path, indices) && !strcmp(sig, "s"))
desc.ccLabel[indices[0]] = args[0].s;
else if (Messages::matchOSC("/cc&/default", path, indices) && !strcmp(sig, "f"))
desc.ccDefault[indices[0]] = args[0].f;
else if (Messages::matchOSC("/cc&/value", path, indices) && !strcmp(sig, "f"))
desc.ccValue[indices[0]] = args[0].f;
src += byteCount;
srcSize -= byteCount;
}
return desc;
}
std::ostream& operator<<(std::ostream& os, const InstrumentDescription& desc)
{
os << "instrument:\n";
os << " regions: " << desc.numRegions << "\n";
os << " groups: " << desc.numGroups << "\n";
os << " masters: " << desc.numMasters << "\n";
os << " curves: " << desc.numCurves << "\n";
os << " samples: " << desc.numSamples << "\n";
os << " root_path: " << desc.rootPath << "\n";
os << " image: " << desc.image << "\n";
os << " image_controls: " << desc.image_controls << "\n";
os << " keys:\n";
for (unsigned i = 0; i < 128; ++i) {
if (desc.keyUsed.test(i)) {
os << " - number: " << i << "\n";
if (!desc.keyLabel[i].empty())
os << " label: " << desc.keyLabel[i].c_str() << "\n";
}
}
os << " keyswitches:\n";
for (unsigned i = 0; i < 128; ++i) {
if (desc.keyswitchUsed.test(i)) {
os << " - number: " << i << "\n";
if (!desc.keyswitchLabel[i].empty())
os << " label: " << desc.keyswitchLabel[i].c_str() << "\n";
}
}
os << " cc:\n";
for (unsigned i = 0; i < sfz::config::numCCs; ++i) {
if (desc.ccUsed.test(i)) {
os << " - number: " << i << "\n";
os << " default: " << desc.ccDefault[i] << "\n";
if (!desc.ccLabel[i].empty())
os << " label: " << desc.ccLabel[i].c_str() << "\n";
}
}
return os;
}

View file

@ -0,0 +1,56 @@
// 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 "sfizz/Config.h"
#include "sfizz/utility/bit_array/BitArray.h"
#include <absl/strings/string_view.h>
#include <string>
#include <array>
#include <iosfwd>
struct sfizz_synth_t;
/**
* @brief Description of user-interactible elements of the SFZ instrument
*/
struct InstrumentDescription {
uint32_t numRegions {};
uint32_t numGroups {};
uint32_t numMasters {};
uint32_t numCurves {};
uint32_t numSamples {};
std::string rootPath;
std::string image;
std::string image_controls;
BitArray<128> keyUsed {};
BitArray<128> keyswitchUsed {};
BitArray<128> sustainOrSostenuto {};
BitArray<sfz::config::numCCs> ccUsed {};
std::array<std::string, 128> keyLabel {};
std::array<std::string, 128> keyswitchLabel {};
std::array<std::string, sfz::config::numCCs> ccLabel {};
std::array<float, sfz::config::numCCs> ccDefault {};
std::array<float, sfz::config::numCCs> ccValue {};
};
/**
* @brief Produce a description of the currently loaded instrument in the synth,
* in the form of a concatenation of OSC messages.
*
* This form is a message transmissible over binary channels.
*/
std::string getDescriptionBlob(sfizz_synth_t* handle);
/**
* @brief Extract the information from the OSC blob and rearrange it in a
* structured form.
*/
InstrumentDescription parseDescriptionBlob(absl::string_view blob);
/**
* @brief Display the description in human-readable format.
*/
std::ostream& operator<<(std::ostream& os, const InstrumentDescription& desc);

View file

@ -0,0 +1,39 @@
// 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 "MessageUtils.h"
#include <absl/strings/ascii.h>
#include <absl/strings/numbers.h>
#include <cstring>
namespace Messages {
bool matchOSC(const char* pattern, const char* path, unsigned* indices)
{
unsigned nthIndex = 0;
while (const char *endp = std::strchr(pattern, '&')) {
size_t length = endp - pattern;
if (std::strncmp(pattern, path, length))
return false;
pattern += length;
path += length;
length = 0;
while (absl::ascii_isdigit(path[length]))
++length;
if (!absl::SimpleAtoi(absl::string_view(path, length), &indices[nthIndex++]))
return false;
pattern += 1;
path += length;
}
return !std::strcmp(path, pattern);
}
} // namespace Messages

View file

@ -0,0 +1,19 @@
// 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
namespace Messages {
/**
* Simple matcher for message handling in O(N)
* @param[in] pattern Pattern to match, where '&' characters match positive integer numbers
* @param[in] path Path to match against the pattern
* @param[out] indices Table which received the indices, with size >= the number of '&' in the pattern
*/
bool matchOSC(const char* pattern, const char* path, unsigned* indices);
} // namespace Messages

View file

@ -0,0 +1,144 @@
// 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 "NativeHelpers.h"
#include <absl/strings/match.h>
#include <absl/strings/strip.h>
#include <absl/strings/string_view.h>
#include <stdexcept>
#include <cstdlib>
#include <fstream>
#if defined(_WIN32)
#include <windows.h>
#include <shlobj.h>
const fs::path& getUserDocumentsDirectory()
{
static const fs::path directory = []() -> fs::path {
std::unique_ptr<WCHAR[]> path(new WCHAR[32768]);
if (SHGetFolderPathW(nullptr, CSIDL_PERSONAL|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, path.get()) != S_OK)
throw std::runtime_error("Cannot get the document directory.");
return fs::path(path.get());
}();
return directory;
}
wchar_t *stringToWideChar(const char *str, int strCch)
{
unsigned strSize = MultiByteToWideChar(CP_UTF8, 0, str, strCch, nullptr, 0);
if (strSize == 0)
return {};
std::unique_ptr<wchar_t[]> strW(new wchar_t[strSize]);
if (MultiByteToWideChar(CP_UTF8, 0, str, strCch, strW.get(), strSize) == 0)
return {};
return strW.release();
}
char* stringToUTF8(const wchar_t *strW, int strWCch)
{
unsigned strSize = WideCharToMultiByte(CP_UTF8, 0, strW, strWCch, nullptr, 0, nullptr, nullptr);
if (strSize == 0)
return {};
std::unique_ptr<char[]> str(new char[strSize]);
if (WideCharToMultiByte(CP_UTF8, 0, strW, strWCch, str.get(), strSize, nullptr, nullptr) == 0)
return {};
return str.release();
}
#elif defined(__APPLE__)
// implemented in NativeHelpers.mm
#else
const fs::path& getUserDocumentsDirectory()
{
static const fs::path directory = []() -> fs::path {
for (const XdgUserDirsEntry& ent :
parseXdgUserDirs(getXdgConfigHome() / "user-dirs.dirs")) {
if (ent.name == "XDG_DOCUMENTS_DIR")
return ent.value;
}
return getUserHomeDirectory() / "Documents";
}();
return directory;
}
const fs::path& getUserHomeDirectory()
{
static const fs::path directory = []() -> fs::path {
const char* home = getenv("HOME");
if (home && home[0] == '/')
return fs::u8path(home);
else
throw std::runtime_error("Cannot get the home directory.");
}();
return directory;
}
const fs::path& getXdgConfigHome()
{
static const fs::path directory = []() -> fs::path {
const char* config = getenv("XDG_CONFIG_HOME");
if (config && config[0] == '/')
return fs::u8path(config);
else
return getUserHomeDirectory() / ".config";
}();
return directory;
}
std::vector<XdgUserDirsEntry> parseXdgUserDirs(const fs::path& userDirsPath)
{
// from user-dirs.dirs(5)
// This file contains lines of the form `XDG_NAME_DIR=VALUE`
// VALUE must be of the form "$HOME/Path" or "/Path".
// Lines beginning with a # character are ignored.
std::vector<XdgUserDirsEntry> ents;
const fs::path& home = getUserHomeDirectory();
fs::ifstream in(userDirsPath);
std::string lineBuf;
lineBuf.reserve(256);
while (std::getline(in, lineBuf)) {
absl::string_view line(lineBuf);
line = absl::StripLeadingAsciiWhitespace(line);
if (line.empty() || line.front() == '#')
continue;
size_t pos = line.find('=');
if (pos == line.npos)
continue;
XdgUserDirsEntry ent;
ent.name = std::string(line.substr(0, pos));
absl::string_view rawValue = line.substr(pos + 1);
rawValue = absl::StripTrailingAsciiWhitespace(rawValue);
if (rawValue.size() < 2 || rawValue.front() != '"' || rawValue.back() != '"')
continue;
rawValue.remove_prefix(1);
rawValue.remove_suffix(1);
if (!rawValue.empty() && rawValue.front() == '/')
ent.value = fs::u8path(rawValue.begin(), rawValue.end());
else if (absl::StartsWith(rawValue, "$HOME")) {
absl::string_view part = rawValue.substr(5);
ent.value = home / fs::u8path(part.begin(), part.end()).relative_path();
}
else
continue;
ents.push_back(std::move(ent));
}
return ents;
}
#endif

View file

@ -0,0 +1,26 @@
// 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 <ghc/fs_std.hpp>
#include <vector>
#if defined(_WIN32)
#include <cwchar>
#endif
const fs::path& getUserDocumentsDirectory();
#if !defined(_WIN32) && !defined(__APPLE__)
const fs::path& getUserHomeDirectory();
const fs::path& getXdgConfigHome();
struct XdgUserDirsEntry { std::string name; fs::path value; };
std::vector<XdgUserDirsEntry> parseXdgUserDirs(const fs::path& userDirsPath);
#endif
#if defined(_WIN32)
wchar_t *stringToWideChar(const char *str, int strCch = -1);
char* stringToUTF8(const wchar_t *strW, int strWCch = -1);
#endif

View file

@ -0,0 +1,27 @@
// 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 "NativeHelpers.h"
#import <Foundation/Foundation.h>
#include <stdexcept>
#if !__has_feature(objc_arc)
#error This source file requires ARC
#endif
const fs::path& getUserDocumentsDirectory()
{
static const fs::path directory = []() -> fs::path {
NSFileManager* fm = [NSFileManager defaultManager];
NSArray<NSURL*>* urls = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
for (NSUInteger i = 0, n = [urls count]; i < n; ++i) {
NSURL *url = [urls objectAtIndex:i];
if ([url isFileURL])
return fs::path([url path].UTF8String);
}
throw std::runtime_error("Cannot get the document directory.");
}();
return directory;
}

View file

@ -0,0 +1,188 @@
// 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 <simde/x86/sse.h>
#include <cstddef>
#include <cmath>
#ifdef _WIN32
#include <malloc.h>
#endif
class RMSFollower {
public:
RMSFollower()
{
setNumOutputs(numOutputs_);
updatePole();
}
~RMSFollower()
{
freeAlignedMemory();
}
void clear()
{
for (int c = 0; c < numOutputs_; c += 4) {
simde__m128* mem = (simde__m128*) (mem_ + c);
*mem = simde_mm_setzero_ps();
}
}
void setNumOutputs(int numOutputs)
{
freeAlignedMemory();
numOutputs_ = numOutputs;
memSize_ = numOutputs % 4 == 0 ? numOutputs * sizeof(float) : (numOutputs / 4 + 1) * 4 * sizeof(float);
#ifdef _WIN32
mem_ = (float *)_aligned_malloc(memSize_, 4 * sizeof(float));
#elif __APPLE__
mem_ = (float *)malloc(memSize_); // Should be 16 aligned
#else
mem_ = (float *)aligned_alloc(4 * sizeof(float), memSize_);
#endif
clear();
}
void init(float sampleRate)
{
sampleRate_ = sampleRate;
updatePole();
}
void setT60(float t60)
{
t60_ = t60;
updatePole();
}
void process(const float** blocks, size_t numFrames, size_t numChannels)
{
assert(numChannels <= static_cast<size_t>(numOutputs_));
const auto numSafeChannels = (numChannels / 4) * 4;
for (size_t c = 0; c < numSafeChannels; c += 4) {
simde__m128* mem = (simde__m128*) (mem_ + c);
process4(mem, &blocks[c], numFrames);
}
simde__m128* mem = (simde__m128*) (mem_ + numSafeChannels);
const auto remainingChannels = numChannels - numSafeChannels;
if (remainingChannels >= 4)
process4(mem, &blocks[numSafeChannels], numFrames);
else if (remainingChannels == 3)
process3(mem, &blocks[numSafeChannels], numFrames);
else if (remainingChannels == 2)
process2(mem, &blocks[numSafeChannels], numFrames);
else if (remainingChannels == 1)
process1(mem, &blocks[numSafeChannels], numFrames);
}
void getMS(float* ms, size_t numChannels) const
{
assert(numChannels <= static_cast<size_t>(numOutputs_));
const auto numSafeChannels = (numChannels / 4) * 4;
for (size_t c = 0; c < numSafeChannels; c += 4) {
simde__m128* mem = (simde__m128*) (mem_ + c);
simde_mm_store_ps(ms + c, *mem);
}
simde__m128* mem = (simde__m128*) (mem_ + numSafeChannels);
float* temp = (float*)&temp;
simde_mm_store_ps(temp, *mem);
for (size_t c = numSafeChannels, t = 0; c < numChannels; c++, t++)
ms[c] = temp[t];
}
void getRMS(float* rms, size_t numChannels) const
{
assert(numChannels <= static_cast<size_t>(numOutputs_));
const auto numSafeChannels = (numChannels / 4) * 4;
for (size_t c = 0; c < numSafeChannels; c += 4) {
simde__m128* mem = (simde__m128*) (mem_ + c);
simde_mm_store_ps(rms + c, simde_mm_sqrt_ps(*mem));
}
simde__m128* mem = (simde__m128*) (mem_ + numSafeChannels);
float* temp = (float*)&temp_;
simde_mm_store_ps(temp, simde_mm_sqrt_ps(*mem));
for (size_t c = numSafeChannels, t = 0; c < numChannels; c++, t++)
rms[c] = temp[t];
}
private:
void freeAlignedMemory()
{
if (mem_)
#ifdef _WIN32
_aligned_free(mem_);
#else
free(mem_);
#endif
}
void updatePole()
{
pole_ = std::exp(float(-2.0 * M_PI) / (t60_ * sampleRate_));
}
void process1(simde__m128* mem, const float** blocks, size_t numFrames)
{
simde__m128 input;
const simde__m128 pole = simde_mm_load1_ps(&pole_);
for (size_t i = 0; i < numFrames; ++i) {
input = simde_mm_setr_ps(
blocks[0][i], 0.0f, 0.0f, 0.0f);
input = simde_mm_mul_ps(input, input);
*mem = simde_mm_add_ps(input, simde_mm_mul_ps(pole, simde_mm_sub_ps(*mem, input)));
}
}
void process2(simde__m128* mem, const float** blocks, size_t numFrames)
{
simde__m128 input;
const simde__m128 pole = simde_mm_load1_ps(&pole_);
for (size_t i = 0; i < numFrames; ++i) {
input = simde_mm_setr_ps(
blocks[0][i], blocks[1][i], 0.0f, 0.0f);
input = simde_mm_mul_ps(input, input);
*mem = simde_mm_add_ps(input, simde_mm_mul_ps(pole, simde_mm_sub_ps(*mem, input)));
}
}
void process3(simde__m128* mem, const float** blocks, size_t numFrames)
{
simde__m128 input;
const simde__m128 pole = simde_mm_load1_ps(&pole_);
for (size_t i = 0; i < numFrames; ++i) {
input = simde_mm_setr_ps(
blocks[0][i], blocks[1][i], blocks[2][i], 0.0f);
input = simde_mm_mul_ps(input, input);
*mem = simde_mm_add_ps(input, simde_mm_mul_ps(pole, simde_mm_sub_ps(*mem, input)));
}
}
void process4(simde__m128* mem, const float** blocks, size_t numFrames)
{
simde__m128 input;
const simde__m128 pole = simde_mm_load1_ps(&pole_);
for (size_t i = 0; i < numFrames; ++i) {
input = simde_mm_setr_ps(
blocks[0][i], blocks[1][i], blocks[2][i], blocks[3][i]);
input = simde_mm_mul_ps(input, input);
*mem = simde_mm_add_ps(input, simde_mm_mul_ps(pole, simde_mm_sub_ps(*mem, input)));
}
}
private:
float* mem_ { nullptr };
simde__m128 temp_;
float pole_ {};
float t60_ = 300e-3;
float sampleRate_ = 44100;
int numOutputs_ = 2;
int memSize_ = 4;
};

View file

@ -0,0 +1,286 @@
// 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 "SfizzFileScan.h"
#include "SfizzForeignPaths.h"
#include "SfizzSettings.h"
#include "NativeHelpers.h"
#include <absl/strings/ascii.h>
#include <absl/algorithm/container.h>
#include <memory>
#if defined(_WIN32)
#include <windows.h>
#endif
// wait at least this much before refreshing the file rescan
// it permits to not repeat the operation many times if many searches are
// requested at once, eg. on session loading with multiple plugin instances
static const std::chrono::seconds expiration_time { 10 };
SfzFileScan& SfzFileScan::getInstance()
{
static SfzFileScan instance;
return instance;
}
bool SfzFileScan::locateRealFile(const fs::path& pathOrig, fs::path& pathFound)
{
if (pathOrig.empty())
return false;
std::unique_lock<std::mutex> lock { mutex };
refreshScan();
auto it = file_index_.find(keyOf(pathOrig.filename()));
if (it == file_index_.end())
return false;
const std::list<size_t>& candidateIndices = it->second;
std::vector<fs::path> candidates;
candidates.reserve(candidateIndices.size());
for (const size_t index : candidateIndices)
candidates.push_back(file_trie_[index]);
lock.unlock();
pathFound = electBestMatch(pathOrig, candidates);
return true;
}
bool SfzFileScan::isExpired() const
{
return !completion_time_ ||
(clock::now() - *completion_time_) > expiration_time;
}
void SfzFileScan::refreshScan(bool force)
{
if (!force && !isExpired())
return;
file_trie_.clear();
file_index_.clear();
FileTrieBuilder builder;
for (const fs::path& dirPath : SfizzPaths::getSfzSearchPaths()) {
std::error_code ec;
const fs::directory_options dirOpts =
fs::directory_options::skip_permission_denied;
for (fs::recursive_directory_iterator it(dirPath, dirOpts, ec);
!ec && it != fs::recursive_directory_iterator();
it.increment(ec))
{
const fs::directory_entry& ent = *it;
const fs::path& filePath = ent.path();
std::error_code ec;
if (ent.is_regular_file(ec) /*&& pathIsSfz(filePath)*/) {
size_t fileIndex = builder.addFile(filePath);
file_index_[keyOf(filePath.filename())].push_back(fileIndex);
}
}
}
file_trie_ = builder.build();
completion_time_ = clock::now();
}
std::string SfzFileScan::keyOf(const fs::path& path)
{
std::string key = path.u8string();
absl::AsciiStrToLower(&key);
return key;
}
namespace SfzFileScanImpl {
template <class T>
bool asciiCaseEqual(const std::basic_string<T>& a, const std::basic_string<T>& b)
{
const size_t n = a.size();
if (n != b.size())
return false;
auto lower = [](T c) -> T {
return (c >= T('A') && c <= T('Z')) ? (c - T('A') + T('a')) : c;
};
for (size_t i = 0; i < n; ++i)
if (lower(a[i]) != lower(b[i]))
return false;
return true;
}
} // namespace SfzFileScanImpl
bool SfzFileScan::pathIsSfz(const fs::path& path)
{
const fs::path::string_type& str = path.native();
using char_type = fs::path::value_type;
const size_t n = str.size();
return n > 4 &&
str[n - 4] == char_type('.') &&
(str[n - 3] == char_type('s') || str[n - 3] == char_type('S')) &&
(str[n - 2] == char_type('f') || str[n - 2] == char_type('F')) &&
(str[n - 1] == char_type('z') || str[n - 1] == char_type('Z'));
}
const fs::path& SfzFileScan::electBestMatch(const fs::path& path, absl::Span<const fs::path> candidates)
{
if (candidates.empty())
return path;
if (candidates.size() == 1)
return candidates.front();
struct Score {
size_t components = 0;
size_t exact = 0;
bool operator<(const Score& other) const noexcept
{
return (components != other.components) ?
(components < other.components) : (exact < other.exact);
}
};
std::vector<Score> scores;
scores.reserve(candidates.size());
for (size_t i = 0, n = candidates.size(); i < n; ++i) {
scores.emplace_back();
Score& score = scores.back();
const fs::path& p1 = path;
const fs::path& p2 = candidates[i];
auto it1 = p1.end();
auto it2 = p2.end();
bool matching = true;
while (matching && it1-- != p1.begin() && it2-- != p2.begin()) {
const fs::path& c1 = *it1;
const fs::path& c2 = *it2;
if (c1 == c2) {
score.components += 1;
score.exact += 1;
}
else if (SfzFileScanImpl::asciiCaseEqual(c1.native(), c2.native()))
score.components += 1;
else
matching = false;
}
}
size_t best = 0;
for (size_t i = 1, n = scores.size(); i < n; ++i) {
if (scores[best] < scores[i])
best = i;
}
return candidates[best];
}
//------------------------------------------------------------------------------
namespace SfizzPaths {
std::vector<fs::path> getSfzSearchPaths()
{
std::vector<fs::path> paths;
paths.reserve(8);
auto addPath = [&paths](const fs::path& newPath) {
if (absl::c_find(paths, newPath) == paths.end())
paths.push_back(newPath);
};
absl::optional<fs::path> configDefaultPath = getSfzConfigDefaultPath();
fs::path fallbackDefaultPath = getSfzFallbackDefaultPath();
if (configDefaultPath)
addPath(*configDefaultPath);
addPath(fallbackDefaultPath);
for (const fs::path& path : getEnvironmentSfzPaths())
addPath(path);
for (const fs::path& foreign : {
getAriaPathSetting("user_files_dir"),
getAriaPathSetting("Converted_path") })
if (!foreign.empty() && foreign.is_absolute())
addPath(foreign);
paths.shrink_to_fit();
return paths;
}
absl::optional<fs::path> getSfzConfigDefaultPath()
{
SfizzSettings settings;
fs::path path = fs::u8path(settings.load_or("user_files_dir", {}));
if (path.empty() || !path.is_absolute())
return {};
return path;
}
void setSfzConfigDefaultPath(const fs::path& path)
{
if (path.empty() || !path.is_absolute())
return;
SfizzSettings settings;
settings.store("user_files_dir", path.u8string());
}
fs::path getSfzFallbackDefaultPath()
{
return getUserDocumentsDirectory() / "SFZ instruments";
}
std::vector<fs::path> getEnvironmentSfzPaths()
{
std::vector<fs::path> paths;
#if defined(_WIN32)
std::unique_ptr<WCHAR[]> buf;
DWORD bufsize = GetEnvironmentVariableW(L"SFZ_PATH", nullptr, 0);
if (bufsize == 0)
return {};
buf.reset(new WCHAR[bufsize]);
if (GetEnvironmentVariableW(L"SFZ_PATH", buf.get(), bufsize) != bufsize - 1)
return {};
paths.reserve(8);
const WCHAR* env = buf.get();
while (*env) {
const WCHAR* endp;
for (endp = env; *endp && *endp != L';'; ++endp);
fs::path path = fs::path(env, endp);
if (!path.empty() && path.is_absolute())
paths.push_back(std::move(path));
env = *endp ? (endp + 1) : endp;
}
#else
const char* env = getenv("SFZ_PATH");
if (!env)
return {};
paths.reserve(8);
while (*env) {
const char* endp;
for (endp = env; *endp != ':' && *endp != '\0'; ++endp);
fs::path path = fs::u8path(env, endp);
if (!path.empty() && path.is_absolute())
paths.push_back(std::move(path));
env = *endp ? (endp + 1) : endp;
}
#endif
return paths;
}
} // namespace SfizzPaths

View file

@ -0,0 +1,44 @@
// 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 "FileTrie.h"
#include <absl/types/span.h>
#include <absl/types/optional.h>
#include <ghc/fs_std.hpp>
#include <string>
#include <vector>
#include <list>
#include <unordered_map>
#include <mutex>
#include <chrono>
class SfzFileScan {
public:
static SfzFileScan& getInstance();
bool locateRealFile(const fs::path& pathOrig, fs::path& pathFound);
private:
typedef std::chrono::steady_clock clock;
std::mutex mutex;
absl::optional<clock::time_point> completion_time_;
FileTrie file_trie_;
std::unordered_map<std::string, std::list<size_t>> file_index_;
bool isExpired() const;
void refreshScan(bool force = false);
static std::string keyOf(const fs::path& path);
static bool pathIsSfz(const fs::path& path);
static const fs::path& electBestMatch(const fs::path& path, absl::Span<const fs::path> candidates);
};
namespace SfizzPaths {
std::vector<fs::path> getSfzSearchPaths();
absl::optional<fs::path> getSfzConfigDefaultPath();
void setSfzConfigDefaultPath(const fs::path& path);
fs::path getSfzFallbackDefaultPath();
std::vector<fs::path> getEnvironmentSfzPaths();
} // namespace SfizzPaths

View file

@ -0,0 +1,53 @@
// 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 "SfizzForeignPaths.h"
namespace SfizzPaths {
#if defined(_WIN32)
#include <windows.h>
fs::path getAriaPathSetting(const char* name)
{
std::unique_ptr<WCHAR[]> nameW;
unsigned nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
if (nameSize == 0)
return {};
nameW.reset(new WCHAR[nameSize]);
if (MultiByteToWideChar(CP_UTF8, 0, name, -1, nameW.get(), nameSize) == 0)
return {};
const WCHAR ariaKeyPath[] = L"Software\\Plogue Art et Technologie, Inc\\Aria";
HKEY key = nullptr;
LSTATUS status = RegOpenKeyExW(HKEY_CURRENT_USER, ariaKeyPath, 0, KEY_QUERY_VALUE, &key);
if (status != ERROR_SUCCESS)
return {};
DWORD valueSize = 32768 * sizeof(WCHAR);
std::unique_ptr<WCHAR[]> valueW(new WCHAR[(valueSize / sizeof(WCHAR)) + 1]());
DWORD valueType;
status = RegQueryValueExW(
key, nameW.get(), nullptr,
&valueType, reinterpret_cast<LPBYTE>(valueW.get()), &valueSize);
RegCloseKey(key);
if (status != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ))
return {};
return fs::path(valueW.get());
}
#elif defined(__APPLE__)
// implementation in SfizzForeignPaths.mm
#else
fs::path getAriaPathSetting(const char* name)
{
(void)name;
return {};
}
#endif
} // namespace SfizzPaths

View file

@ -0,0 +1,12 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include <ghc/fs_std.hpp>
namespace SfizzPaths {
fs::path getAriaPathSetting(const char* name);
} // namespace SfizzPaths

View file

@ -0,0 +1,27 @@
// 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 "SfizzForeignPaths.h"
#if defined(__APPLE__)
#import <Foundation/Foundation.h>
#if !__has_feature(objc_arc)
#error This source file requires ARC
#endif
namespace SfizzPaths {
fs::path getAriaPathSetting(const char* name)
{
NSUserDefaults* ud = [[NSUserDefaults alloc] initWithSuiteName:@"com.plogue.aria"];
NSString* value = [ud stringForKey:[NSString stringWithUTF8String:name]];
if (!value)
return {};
return fs::path(value.UTF8String);
}
} // namespace SfizzPaths
#endif

View file

@ -0,0 +1,145 @@
// 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 "SfizzSettings.h"
#include "NativeHelpers.h"
#include <memory>
#include <cstdlib>
std::string SfizzSettings::load_or(const char* key, absl::string_view defaultValue)
{
absl::optional<std::string> optValue = load(key);
return optValue ? *optValue : std::string(defaultValue);
}
#if defined(_WIN32)
#include <windows.h>
static HKEY openRegistryKey()
{
LSTATUS status;
HKEY root = HKEY_CURRENT_USER;
HKEY parent = root;
HKEY key = nullptr;
for (const WCHAR* component : {L"Software", L"SFZTools", L"sfizz"}) {
status = RegCreateKeyExW(
parent, component, 0, nullptr,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &key, nullptr);
if (parent != root)
RegCloseKey(parent);
if (status != ERROR_SUCCESS)
return nullptr;
parent = key;
}
return key;
}
absl::optional<std::string> SfizzSettings::load(const char* name)
{
std::unique_ptr<WCHAR[]> nameW { stringToWideChar(name) };
if (!nameW)
return {};
HKEY key = openRegistryKey();
if (!key)
return {};
WCHAR valueW[32768];
DWORD valueSize = sizeof(valueW);
DWORD valueType;
LSTATUS status = RegQueryValueExW(
key, nameW.get(), nullptr,
&valueType, reinterpret_cast<BYTE*>(valueW), &valueSize);
RegCloseKey(key);
if (status != ERROR_SUCCESS || (valueType != REG_SZ && valueType != REG_EXPAND_SZ))
return {};
std::unique_ptr<char[]> value { stringToUTF8(valueW) };
if (!value)
return {};
return std::string(value.get());
}
bool SfizzSettings::store(const char* name, absl::string_view value)
{
std::unique_ptr<WCHAR[]> nameW { stringToWideChar(name) };
std::unique_ptr<WCHAR[]> valueW { stringToWideChar(std::string(value).c_str()) };
if (!nameW || !valueW)
return false;
HKEY key = openRegistryKey();
if (!key)
return {};
LSTATUS status = RegSetValueExW(
key, nameW.get(), 0, RRF_RT_REG_SZ,
reinterpret_cast<const BYTE*>(valueW.get()),
(wcslen(valueW.get()) + 1) * sizeof(WCHAR));
RegCloseKey(key);
return status == ERROR_SUCCESS;
}
#elif defined(__APPLE__)
// implementation in SfizzSettings.mm
#else
#include <pugixml.hpp>
#include <ghc/fs_std.hpp>
static const fs::path getSettingsPath()
{
const fs::path dirPath = getXdgConfigHome() / "SFZTools" / "sfizz";
std::error_code ec;
fs::create_directories(dirPath, ec);
if (ec)
return {};
return dirPath / "settings.xml";
}
absl::optional<std::string> SfizzSettings::load(const char* key)
{
const fs::path path = getSettingsPath();
if (path.empty())
return {};
pugi::xml_document doc;
if (!doc.load_file(path.c_str()))
return {};
pugi::xml_node root = doc.child("properties");
if (!root)
return {};
pugi::xml_node entry = root.find_child_by_attribute("entry", "key", key);
if (!entry)
return {};
return std::string(entry.text().get());
}
bool SfizzSettings::store(const char* key, absl::string_view value)
{
const fs::path path = getSettingsPath();
if (path.empty())
return false;
pugi::xml_document doc;
doc.load_file(path.c_str());
pugi::xml_node root = doc.child("properties");
if (!root)
root = doc.append_child("properties");
pugi::xml_node entry = root.find_child_by_attribute("entry", "key", key);
if (!entry) {
entry = root.append_child("entry");
entry.append_attribute("key").set_value(key);
}
entry.text().set(std::string(value).c_str());
return doc.save_file(path.c_str());
}
#endif

View file

@ -0,0 +1,16 @@
// 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 <absl/strings/string_view.h>
#include <absl/types/optional.h>
class SfizzSettings {
public:
absl::optional<std::string> load(const char* key);
std::string load_or(const char* key, absl::string_view defaultValue);
bool store(const char* key, absl::string_view value);
};

View file

@ -0,0 +1,38 @@
// 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 "SfizzSettings.h"
#if defined(__APPLE__)
#import <Foundation/Foundation.h>
#if !__has_feature(objc_arc)
#error This source file requires ARC
#endif
static NSUserDefaults* getUserDefaults()
{
return [[NSUserDefaults alloc] initWithSuiteName:@"tools.sfz.sfizz"];;
}
absl::optional<std::string> SfizzSettings::load(const char* key)
{
NSUserDefaults* ud = getUserDefaults();
NSString* value = [ud stringForKey:[NSString stringWithUTF8String:key]];
if (!value)
return {};
return std::string(value.UTF8String);
}
bool SfizzSettings::store(const char* key, absl::string_view value)
{
NSUserDefaults* ud = getUserDefaults();
NSString* object =
[[NSString alloc] initWithBytes:value.data()
length:(NSUInteger)value.size() encoding:NSUTF8StringEncoding];
[ud setObject:object forKey:[NSString stringWithUTF8String:key]];
return true;
}
#endif

View file

@ -0,0 +1,158 @@
if(SFIZZ_USE_SYSTEM_VST3SDK)
find_package(PkgConfig REQUIRED)
pkg_check_modules(VST3SDK "vst3sdk" REQUIRED)
set(VSTGUI_BASEDIR "${VST3SDK_INCLUDE_DIRS}/vstgui4")
else()
set(VSTGUI_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/vstgui4")
endif()
include("cmake/Vstgui.cmake")
set(EDITOR_RESOURCES
logo.png
logo_orange.png
logo_text.png
logo_text_white.png
logo_text_shaded.png
logo_text@2x.png
logo_text_white@2x.png
logo_text_shaded@2x.png
background.png
background@2x.png
background_button_about.png
background_button_about@2x.png
icon_white.png
icon_white@2x.png
knob48.png
knob48@2x.png
Fonts/sfizz-fluentui-system-r20.ttf
Fonts/sfizz-fluentui-system-f20.ttf
Fonts/sfizz-misc-icons.ttf
Fonts/Roboto-Regular.ttf
Themes/Default/theme.xml
Themes/Dark/theme.xml
PARENT_SCOPE
)
set(UI_RESOURCES
resources/Themes/Default/theme.xml
resources/Themes/Dark/theme.xml
)
function(copy_editor_resources TARGET SOURCE_DIR DESTINATION_DIR)
set(_deps)
foreach(res ${EDITOR_RESOURCES})
get_filename_component(_dir "${res}" DIRECTORY)
file(MAKE_DIRECTORY "${DESTINATION_DIR}/${_dir}")
add_custom_command(
OUTPUT "${DESTINATION_DIR}/${res}"
COMMAND "${CMAKE_COMMAND}" "-E" "copy"
"${SOURCE_DIR}/${res}" "${DESTINATION_DIR}/${res}"
DEPENDS "${SOURCE_DIR}/${res}")
list(APPEND _deps "${DESTINATION_DIR}/${res}")
endforeach()
add_custom_target("${TARGET}_editor_resources" DEPENDS ${_deps})
add_dependencies("${TARGET}" "${TARGET}_editor_resources")
endfunction()
set(UI_FILES layout/main.fl layout/about.fl)
source_group("Editor UI" FILES ${UI_FILES})
source_group("Editor Resources" FILES ${UI_RESOURCES})
# 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/EditorLibs.h
src/editor/EditorLibs.cpp
src/editor/EditorController.h
src/editor/GUIComponents.h
src/editor/GUIComponents.cpp
src/editor/GUIDefs.h
src/editor/GUIDefs.cpp
src/editor/GUIHelpers.h
src/editor/GUIHelpers.cpp
src/editor/GUIPiano.h
src/editor/GUIPiano.cpp
src/editor/DlgAbout.h
src/editor/DlgAbout.cpp
src/editor/Theme.h
src/editor/Theme.cpp
src/editor/ColorHelpers.h
src/editor/ColorHelpers.cpp
src/editor/ImageHelpers.h
src/editor/ImageHelpers.cpp
src/editor/NativeHelpers.h
src/editor/NativeHelpers.cpp
src/editor/VSTGUIHelpers.h
src/editor/VSTGUIHelpers.cpp
src/editor/layout/main.hpp
src/editor/layout/about.hpp
src/editor/utility/vstgui_after.h
src/editor/utility/vstgui_before.h
${UI_FILES}
${UI_RESOURCES}
)
add_library(sfizz::editor ALIAS sfizz_editor)
target_include_directories(sfizz_editor PUBLIC "src")
target_link_libraries(sfizz_editor PUBLIC sfizz::messaging sfizz::plugins-common)
target_link_libraries(sfizz_editor PRIVATE sfizz::vstgui)
target_compile_definitions(sfizz_editor PRIVATE
"SFIZZ_VERSION=\"${CMAKE_PROJECT_VERSION}\"")
if(APPLE)
find_library(APPLE_APPKIT_LIBRARY "AppKit")
find_library(APPLE_CORESERVICES_LIBRARY "CoreServices")
find_library(APPLE_FOUNDATION_LIBRARY "Foundation")
target_sources(sfizz_editor PRIVATE
src/editor/NativeHelpers.mm
src/editor/VSTGUIHelpers.mm)
target_link_libraries(sfizz_editor PRIVATE
"${APPLE_APPKIT_LIBRARY}"
"${APPLE_CORESERVICES_LIBRARY}"
"${APPLE_FOUNDATION_LIBRARY}")
target_compile_options(sfizz_editor PRIVATE "-fobjc-arc")
endif()
# dependencies
add_library(sfizz_colorspaces INTERFACE)
add_library(sfizz::colorspaces ALIAS sfizz_colorspaces)
target_include_directories(sfizz_colorspaces INTERFACE "external/color-spaces")
add_library(sfizz_stb_image INTERFACE)
add_library(sfizz::stb_image ALIAS sfizz_stb_image)
target_include_directories(sfizz_stb_image INTERFACE "external/stb_image")
if(WIN32)
#
elseif(APPLE)
#
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(sfizz-gio "gio-2.0" REQUIRED)
target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS})
target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES})
endif()
target_link_libraries(sfizz_editor PRIVATE sfizz::colorspaces sfizz::stb_image
sfizz::bit_array sfizz::filesystem sfizz::pugixml)
# layout tool
if(NOT CMAKE_CROSSCOMPILING)
add_executable(layout-maker
"tools/layout-maker/sources/layout.h"
"tools/layout-maker/sources/reader.cpp"
"tools/layout-maker/sources/reader.h"
"tools/layout-maker/sources/main.cpp")
target_link_libraries(layout-maker PRIVATE absl::strings)
foreach(_layout main about)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/${_layout}.hpp"
COMMAND "$<TARGET_FILE:layout-maker>"
"${CMAKE_CURRENT_SOURCE_DIR}/layout/${_layout}.fl"
> "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/${_layout}.hpp"
DEPENDS layout-maker "${CMAKE_CURRENT_SOURCE_DIR}/layout/${_layout}.fl")
endforeach()
endif()
# Git build identifier
target_link_libraries(sfizz_editor PRIVATE sfizz-git-build-id)

View file

@ -0,0 +1,261 @@
# Find vstgui version
FILE(READ ${VSTGUI_BASEDIR}/vstgui/lib/vstguibase.h VSTGUIBASE_HEADER)
string(REGEX MATCH "\#define VSTGUI_VERSION_MAJOR ([0-9]*)" _ ${VSTGUIBASE_HEADER})
set(VSTGUI_VERSION_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "\#define VSTGUI_VERSION_MINOR ([0-9]*)" _ ${VSTGUIBASE_HEADER})
set(VSTGUI_VERSION_MINOR ${CMAKE_MATCH_1})
set(VSTGUI_VERSION "${VSTGUI_VERSION_MAJOR}.${VSTGUI_VERSION_MINOR}")
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/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/platform/platformfactory.cpp"
"${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/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/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/pixelbuffer.cpp"
"${VSTGUI_BASEDIR}/vstgui/lib/vstguidebug.cpp"
"${VSTGUI_BASEDIR}/vstgui/lib/vstguiinit.cpp")
if(${VSTGUI_VERSION} VERSION_GREATER "4.10")
target_sources(sfizz_vstgui PRIVATE
${VSTGUI_BASEDIR}/vstgui/lib/cgradient.cpp
${VSTGUI_BASEDIR}/vstgui/lib/events.cpp)
endif()
add_library(sfizz::vstgui ALIAS sfizz_vstgui)
if(WIN32)
target_sources(sfizz_vstgui PRIVATE
"${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/win32factory.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/win32resourcestream.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")
if(${VSTGUI_VERSION} VERSION_GREATER "4.10")
target_sources(sfizz_vstgui PRIVATE
${VSTGUI_BASEDIR}/vstgui/lib/platform/win32/direct2d/d2dgradient.cpp)
endif()
elseif(APPLE)
target_sources(sfizz_vstgui PRIVATE
"${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/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/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/macclipboard.mm"
"${VSTGUI_BASEDIR}/vstgui/lib/platform/mac/macfactory.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/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/linuxfactory.cpp"
"${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/linuxstring.cpp"
"${VSTGUI_BASEDIR}/vstgui/lib/platform/linux/x11dragging.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
target_link_libraries(sfizz_vstgui PRIVATE
"opengl32"
"d2d1"
"dwrite"
"dwmapi"
"windowscodecs"
"shlwapi")
endif()
elseif(APPLE)
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(PANGO REQUIRED pangocairo pangoft2)
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
pkg_check_modules(GLIB REQUIRED glib-2.0)
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}
${PANGO_INCLUDE_DIRS}
${FONTCONFIG_INCLUDE_DIRS}
${GLIB_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}
${PANGO_LIBRARIES}
${FONTCONFIG_LIBRARIES}
${GLIB_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 PUBLIC "DEVELOPMENT")
endif()
if(${CMAKE_BUILD_TYPE} MATCHES "Release")
target_compile_definitions(sfizz_vstgui PUBLIC "RELEASE")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
# Windows 10 RS2 DDI for custom fonts
target_compile_definitions(sfizz_vstgui PRIVATE "NTDDI_VERSION=0x0A000003")
# disable custom fonts if dwrite3 API is unavailable in MinGW
if(MINGW)
check_cxx_source_compiles("
#include <windows.h>
#include <dwrite_3.h>
HRESULT FeatureCheck(IDWriteFontSet* self, const WCHAR* name, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFontSet** fontset)
{
return self->GetMatchingFonts(name, weight, stretch, style, fontset);
}
int main()
{
return 0;
}" SFIZZ_MINGW_SUPPORTS_DWRITE3)
if(NOT SFIZZ_MINGW_SUPPORTS_DWRITE3)
message(WARNING "This version of MinGW does not support DirectWrite 3. Custom font support is disabled.")
target_compile_definitions(sfizz_vstgui PRIVATE "VSTGUI_WIN32_CUSTOMFONT_SUPPORT=0")
endif()
endif()
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
gw_target_warn(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()

View file

@ -0,0 +1,129 @@
// SPDX-License-Identifier: MIT
/*
GLSL Color Space Utility Functions
(c) 2015 tobspr
Porting a subset to C++
(c) 2020 Jean Pierre Cimalando
-------------------------------------------------------------------------------
The MIT License (MIT)
Copyright (c) 2015
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-------------------------------------------------------------------------------
Most formulars / matrices are from:
https://en.wikipedia.org/wiki/SRGB
Some are from:
http://www.chilliant.com/rgb2hsv.html
https://www.fourcc.org/fccyvrgb.php
*/
#pragma once
#include <array>
#include <algorithm>
#include <cmath>
namespace ColorSpaces {
template <std::size_t N> using vec = std::array<float, N>;
using vec3 = vec<3>;
using vec4 = vec<4>;
template <class T>
T clamp(T x, T lo, T hi)
{
return std::max(lo, std::min(hi, x));
}
template <std::size_t N>
vec<N> saturate(vec<N> x)
{
for (std::size_t i = 0; i < N; ++i)
x[i] = clamp(x[i], 0.0f, 1.0f);
return x;
}
float dot(vec3 a, vec3 b)
{
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
// Constants
static constexpr float HCV_EPSILON = 1e-10;
static constexpr float HCY_EPSILON = 1e-10;
// Converts a value from linear RGB to HCV (Hue, Chroma, Value)
vec3 rgb_to_hcv(vec3 rgb)
{
// Based on work by Sam Hocevar and Emil Persson
vec4 P = (rgb[1] < rgb[2]) ? vec4{{rgb[2], rgb[1], -1.0, 2.0/3.0}} : vec4{{rgb[1], rgb[2], 0.0, -1.0/3.0}};
vec4 Q = (rgb[0] < P[0]) ? vec4{{P[0], P[1], P[3], rgb[0]}} : vec4{{rgb[0], P[1], P[2], P[0]}};
float C = Q[0] - std::min(Q[3], Q[1]);
float H = std::abs((Q[3] - Q[1]) / (6 * C + HCV_EPSILON) + Q[2]);
return vec3{{H, C, Q[0]}};
}
// Converts from pure Hue to linear RGB
vec3 hue_to_rgb(float hue)
{
float R = std::fabs(hue * 6 - 3) - 1;
float G = 2 - std::fabs(hue * 6 - 2);
float B = 2 - std::fabs(hue * 6 - 4);
return saturate(vec3{{R,G,B}});
}
// Converts from HCY to linear RGB
vec3 hcy_to_rgb(vec3 hcy)
{
const vec3 HCYwts{{0.299, 0.587, 0.114}};
vec3 RGB = hue_to_rgb(hcy[0]);
float Z = dot(RGB, HCYwts);
if (hcy[2] < Z) {
hcy[1] *= hcy[2] / Z;
} else if (Z < 1) {
hcy[1] *= (1 - hcy[2]) / (1 - Z);
}
return vec3{{(RGB[0] - Z) * hcy[1] + hcy[2],
(RGB[1] - Z) * hcy[1] + hcy[2],
(RGB[2] - Z) * hcy[1] + hcy[2]}};
}
// Converts from rgb to hcy (Hue, Chroma, Luminance)
vec3 rgb_to_hcy(vec3 rgb)
{
const vec3 HCYwts = vec3{{0.299, 0.587, 0.114}};
// Corrected by David Schaeffer
vec3 HCV = rgb_to_hcv(rgb);
float Y = dot(rgb, HCYwts);
float Z = dot(hue_to_rgb(HCV[0]), HCYwts);
if (Y < Z) {
HCV[1] *= Z / (HCY_EPSILON + Y);
} else {
HCV[1] *= (1 - Z) / (HCY_EPSILON + 1 - Y);
}
return vec3{{HCV[0], HCV[1], Y}};
}
} // namespace ColorSpaces

View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,37 @@
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load diff

1
plugins/editor/external/vstgui4 vendored Submodule

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

View file

@ -0,0 +1,68 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0305
header_name {.h}
code_name {.cxx}
widget_class aboutView {
label {About sfizz} open
xywh {527 165 800 475} type Double visible
} {
Fl_Box {} {
image {../resources/logo_orange.png} xywh {200 0 400 180}
class Logo
}
Fl_Box {} {
xywh {260 180 280 80}
class InfoBox
}
Fl_Box {} {
xywh {200 260 400 100}
class DescriptionBox
}
Fl_Box lblHover_ {
xywh {460 435 315 25} labelsize 12 hide
class HoverBox
}
Fl_Button {} {
comment {tag=kTagButtonSfztools}
xywh {460 405 40 40} labelsize 30
class ButtonSfztools
}
Fl_Button {} {
comment {tag=kTagButtonGithub}
xywh {530 405 40 40} labelsize 30
class ButtonGithub
}
Fl_Button {} {
comment {tag=kTagButtonDiscord}
xywh {600 405 40 40} labelsize 30
class ButtonDiscord
}
Fl_Button {} {
comment {tag=kTagButtonOpencollective}
xywh {670 405 40 40} labelsize 30
class ButtonOpencollective
}
Fl_Button {} {
comment {tag=kTagButtonSfzformat}
xywh {740 405 40 40} labelsize 30
class ButtonSfzformat
}
Fl_Box {} {
label {Format
Host
Processor
Address
System}
xywh {15 375 90 90} align 20
class SysInfoKeyBox
}
Fl_Box lblSysInfoValue_ {
label {%PluginFormat%
%HostProgram%
%HostCPU%
%HostBits% bits
%HostOS%} selected
xywh {105 375 345 90} align 20
class SysInfoValueBox
}
}

View file

@ -0,0 +1,464 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0304
header_name {.h}
code_name {.cxx}
widget_class mainView {open
xywh {624 564 775 515} type Double
class LogicalGroup visible
} {
Fl_Box imageContainer_ {
image {../resources/background.png} xywh {0 110 775 335}
class Background
}
Fl_Group {} {
comment {palette=invertedPalette} open
xywh {0 0 775 110}
class LogicalGroup
} {
Fl_Group {} {
xywh {5 4 175 101} box ROUNDED_BOX align 0
class RoundedGroup
} {
Fl_Box {} {
comment {tag=kTagAbout}
image {../resources/logo_text_shaded.png} xywh {32 9 120 60}
class AboutButton
}
Fl_Button {panelButtons_[kPanelInfo]} {
comment {tag=kTagFirstChangePanel+kPanelInfo}
xywh {56 73 32 32} labelsize 30
class InfoButton
}
Fl_Button {panelButtons_[kPanelControls]} {
comment {tag=kTagFirstChangePanel+kPanelControls}
xywh {97 73 32 32} labelsize 30
class CCButton
}
Fl_Button {panelButtons_[kPanelSettings]} {
comment {tag=kTagFirstChangePanel+kPanelSettings}
xywh {137 73 32 32} labelsize 30
class SettingsButton
}
Fl_Button {panelButtons_[kPanelGeneral]} {
comment {tag=kTagFirstChangePanel+kPanelGeneral}
xywh {16 73 32 32} labelsize 30
class HomeButton
}
}
Fl_Group {} {open
xywh {185 5 365 100} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Box {} {
label {Separator 1}
xywh {195 40 345 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box {} {
label {Separator 2}
xywh {195 75 345 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box sfzFileLabel_ {
label {DefaultInstrument.sfz}
comment {tag=kTagLoadSfzFile}
xywh {195 10 270 30} labelsize 20 align 20
class ClickableLabel
}
Fl_Box keyswitchLabel_ {
xywh {255 45 285 30} labelsize 20 align 20
class Label
}
Fl_Box keyswitchBadge_ {
xywh {195 47 60 26} box THIN_UP_BOX labelsize 20
class Badge
}
Fl_Box keyswitchInactiveLabel_ {
label {No key switch}
xywh {195 45 345 30} labelsize 20 align 20 hide
class InactiveLabel
}
Fl_Box {} {
label {Voices:}
xywh {195 78 60 25} align 24
class Label
}
Fl_Button {} {
comment {tag=kTagPreviousSfzFile}
xywh {465 15 25 25} labelsize 24
class PreviousFileButton
}
Fl_Button {} {
comment {tag=kTagNextSfzFile}
xywh {490 15 25 25} labelsize 24
class NextFileButton
}
Fl_Button fileOperationsMenu_ {
comment {tag=kTagFileOperations}
xywh {515 15 25 25} labelsize 24
class ChevronDropDown
}
Fl_Box infoVoicesLabel_ {
xywh {255 78 40 25} align 16
class Label
}
Fl_Box {} {
label {Max:}
xywh {315 78 40 25} align 24
class Label
}
Fl_Box numVoicesLabel_ {
xywh {355 78 35 25} align 16
class Label
}
Fl_Box {} {
label {Memory:}
xywh {430 78 60 25} align 24
class Label
}
Fl_Box memoryLabel_ {
xywh {490 78 50 25} align 16
class Label
}
Fl_Button numVoicesSlider_ {
comment {tag=kTagSetNumVoices}
xywh {390 82 20 20} labelsize 16
class ChevronValueDropDown
}
}
Fl_Group {} {
xywh {555 5 215 100} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Dial {} {
xywh {587 20 48 48} value 0.5 hide
class Knob48
}
Fl_Box {} {
label Center
xywh {582 70 60 5} hide
class ValueLabel
}
Fl_Box volumeCCKnob_ {
label Volume
comment {tag=kTagSetCCVolume}
xywh {560 10 70 90} box BORDER_BOX align 17
class KnobCCBox
}
Fl_Box panCCKnob_ {
label Pan
comment {tag=kTagSetCCPan}
xywh {635 10 70 90} box BORDER_BOX align 17
class KnobCCBox
}
Fl_Box {meters_[0]} {
xywh {710 10 23 90} box BORDER_BOX
class VMeter
}
Fl_Box {meters_[1]} {
xywh {740 10 23 90} box BORDER_BOX
class VMeter
}
}
}
Fl_Group {subPanels_[kPanelInfo]} {
xywh {0 110 775 335} hide
class LogicalGroup
} {
Fl_Group {} {
xywh {0 110 775 335} box BORDER_BOX
class SquaredTransparentGroup
} {
Fl_Box {} {
label {Curves:}
xywh {20 120 60 25} align 20
class InfoLabel
}
Fl_Box {} {
label {Masters:}
xywh {20 145 60 25} align 20
class InfoLabel
}
Fl_Box {} {
label {Groups:}
xywh {20 170 60 25} align 20
class InfoLabel
}
Fl_Box {} {
label {Regions:}
xywh {20 195 60 25} align 20
class InfoLabel
}
Fl_Box {} {
label {Samples:}
xywh {20 220 60 25} align 20
class InfoLabel
}
Fl_Box infoCurvesLabel_ {
label 0
xywh {120 120 40 25} align 16
class InfoLabel
}
Fl_Box infoMastersLabel_ {
label 0
xywh {120 145 40 25} align 16
class InfoLabel
}
Fl_Box infoGroupsLabel_ {
label 0
xywh {120 170 40 25} align 16
class InfoLabel
}
Fl_Box infoRegionsLabel_ {
label 0
xywh {120 195 40 25} align 16
class InfoLabel
}
Fl_Box infoSamplesLabel_ {
label 0
xywh {120 220 40 25} align 16
class InfoLabel
}
}
}
Fl_Group {subPanels_[kPanelControls]} {
xywh {0 110 775 335} hide
class LogicalGroup
} {
Fl_Group controlsPanel_ {
xywh {0 110 775 335} box BORDER_BOX
class ControlsPanel
} {}
}
Fl_Group {subPanels_[kPanelSettings]} {
xywh {0 110 775 335}
class LogicalGroup
} {
Fl_Group {} {open
xywh {0 110 775 335} box BORDER_BOX
class SquaredGroup
} {
Fl_Spinner oversamplingSlider_ {
comment {tag=kTagSetOversampling}
xywh {180 195 70 25}
class ValueMenu
}
Fl_Box {} {
label Oversampling
xywh {10 195 85 25} align 20
class Label
}
Fl_Box {} {
label {Preload size}
xywh {10 170 75 25} align 20
class Label
}
Fl_Spinner preloadSizeSlider_ {
comment {tag=kTagSetPreloadSize}
xywh {180 170 70 25}
class ValueMenu
}
Fl_Spinner sampleQualitySlider_ {
comment {tag=kTagSetSampleQuality}
xywh {430 145 80 25}
class ValueMenu
}
Fl_Box {} {
label Sample
xywh {270 145 50 25} align 20
class Label
}
Fl_Box {} {
label Oscillator
xywh {270 195 60 25} align 20
class Label
}
Fl_Spinner oscillatorQualitySlider_ {
comment {tag=kTagSetOscillatorQuality}
xywh {430 195 80 25}
class ValueMenu
}
Fl_Spinner themeMenu_ {
comment {tag=kTagThemeMenu}
xywh {665 145 100 25}
class OptionMenu
}
Fl_Box {} {
label Theme
xywh {525 145 45 25} align 20
class Label
}
Fl_Box {} {
label {User SFZ folder}
xywh {525 170 95 25} align 20
class Label
}
Fl_Button userFilesDirButton_ {
label DefaultPath
comment {tag=kTagChooseUserFilesDir}
xywh {665 170 100 25}
class ValueButton
}
Fl_Box {} {
label {Root key}
xywh {525 310 60 25} align 20
class Label
}
Fl_Box {} {
label Frequency
xywh {525 335 70 25} align 20
class Label
}
Fl_Dial stretchedTuningSlider_ {
comment {tag=kTagSetStretchedTuning}
xywh {700 360 48 48} value 0.5
class StyledKnob
}
Fl_Box {} {
label Stretch
xywh {525 370 50 25} align 20
class Label
}
Fl_Box {} {
label {Scala file}
xywh {525 285 60 25} align 20
class Label
}
Fl_Button scalaFileButton_ {
label DefaultScale
comment {tag=kTagLoadScalaFile}
xywh {624 285 100 25}
class ValueButton
}
Fl_Spinner scalaRootKeySlider_ {
comment {tag=kTagSetScalaRootKey}
xywh {685 310 35 25}
class ValueMenu
}
Fl_Spinner scalaRootOctaveSlider_ {
comment {tag=kTagSetScalaRootKey}
xywh {720 310 30 25}
class ValueMenu
}
Fl_Button scalaResetButton_ {
comment {tag=kTagResetScalaFile}
xywh {725 285 25 25}
class ResetSomethingButton
}
Fl_Box {} {
label {when freewheeling}
xywh {270 170 145 25} align 20
class Label
}
Fl_Spinner freewheelingSampleQualitySlider_ {
comment {tag=kTagSetFreewheelingSampleQuality}
xywh {430 170 80 25}
class ValueMenu
}
Fl_Box {} {
label {Sustain cancels release}
xywh {10 220 145 25} align 20
class Label
}
Fl_Check_Button sustainCancelsReleaseCheckbox_ {
comment {tag=kTagSetSustainCancelsRelease}
xywh {180 220 25 25} down_box DOWN_BOX
class Checkbox
}
Fl_Box sfizzVersionLabel_ {
label SFIZZ_VERSION
xywh {10 145 225 20}
class Label
}
Fl_Box {} {
label {Rendering quality}
xywh {270 115 110 25} align 20
class Label
}
Fl_Box {} {
label {Separator 2}
xywh {10 135 240 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box {} {
label {Engine options}
xywh {10 115 95 25} align 20
class Label
}
Fl_Box {} {
label Other
xywh {525 115 40 25} align 20
class Label
}
Fl_Box {} {
label Tuning
xywh {525 255 225 25} align 20
class Label
}
Fl_Box {} {
label {Separator Rendering}
xywh {270 135 239 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box {} {
label {Separator Other}
xywh {525 135 240 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box {} {
label {Separator Tuning}
xywh {525 275 225 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Button tuningFrequencyDropdown_ {
comment {tag=kTagSetTuningFrequency}
xywh {725 335 25 25} labelsize 24
class ChevronValueDropDown
}
Fl_Text_Editor tuningFrequencyEdit_ {
comment {tag=kTagSetTuningFrequency}
xywh {665 335 60 25}
class TextEdit
}
Fl_Box {} {
label {when freewheeling}
xywh {270 220 145 25} align 20
class Label
}
Fl_Spinner freewheelingOscillatorQualitySlider_ {
comment {tag=kTagSetFreewheelingOscillatorQuality}
xywh {430 220 80 25}
class ValueMenu
}
Fl_Box {} {
label Zoom
xywh {525 195 95 25} align 20
class Label
}
Fl_Spinner zoomMenu_ {
comment {tag=kTagZoomMenu}
xywh {665 195 100 25}
class OptionMenu
}
Fl_Button defaultZoomButton_ {
label {Set Default}
comment {tag=kTagSetDefaultZoom}
xywh {665 220 100 25}
class ValueButton
}
}
}
Fl_Box piano_ {
xywh {0 445 775 70} labelsize 16
class Piano
}
Fl_Group {subPanels_[kPanelGeneral]} {
xywh {0 110 775 335} hide
class LogicalGroup
} {}
Fl_Box lblHover_ {
comment {palette=invertedPalette}
xywh {5 105 170 25} hide
class HoverBox
}
}

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,40 @@
<?xml version="1.0"?>
<sfizz-theme author="Andrea Zanellato" version="1.0.0">
<color name="frameBackground">#121212</color>
<palette name="normal">
<color name="boxBackground">#1d1d1d</color>
<color name="text">#e3e3e3</color>
<color name="inactiveText">#a2a2a2</color>
<color name="highlightedText">#e9e9e9</color>
<color name="titleBoxText">#e3e3e3</color>
<color name="titleBoxBackground">#2d2d2d</color>
<color name="valueText">#e3e3e3</color>
<color name="valueBackground">#121212</color>
<color name="icon">#e3e3e3</color>
<color name="iconHighlight">#ff6000</color>
<color name="knobActiveTrack">#006b0b</color>
<color name="knobInactiveTrack">#6f6f6f</color>
<color name="knobLineIndicator">#ffffff</color>
<color name="knobText">#ffffff</color>
<color name="knobLabelText">#ffffff</color>
<color name="knobLabelBackground">#006b0b</color>
</palette>
<palette name="inverted">
<color name="boxBackground">#2d2d2d</color>
<color name="text">#9e9e9e</color>
<color name="inactiveText">#a2a2a2</color>
<color name="highlightedText">#e9e9e9</color>
<color name="titleBoxText">#9e9e9e</color>
<color name="titleBoxBackground">#2d2d2d</color>
<color name="valueText">#9e9e9e</color>
<color name="valueBackground">#121212</color>
<color name="icon">#9e9e9e</color>
<color name="iconHighlight">#ff6000</color>
<color name="knobActiveTrack">#006b0b</color>
<color name="knobInactiveTrack">#6f6f6f</color>
<color name="knobLineIndicator">#ffffff</color>
<color name="knobText">#ffffff</color>
<color name="knobLabelText">#ffffff</color>
<color name="knobLabelBackground">#006b0b</color>
</palette>
</sfizz-theme>

View file

@ -0,0 +1,40 @@
<?xml version="1.0"?>
<sfizz-theme>
<color name="frameBackground">#d3d7cf</color>
<palette name="normal">
<color name="boxBackground">#babdb6</color>
<color name="text">#000000</color>
<color name="inactiveText">#b2b2b2</color>
<color name="highlightedText">#fd9800</color>
<color name="titleBoxText">#ffffff</color>
<color name="titleBoxBackground">#2e3436</color>
<color name="valueText">#ffffff</color>
<color name="valueBackground">#2e3436</color>
<color name="icon">#000000</color>
<color name="iconHighlight">#fd9800</color>
<color name="knobActiveTrack">#00aa11</color>
<color name="knobInactiveTrack">#303030</color>
<color name="knobLineIndicator">#000000</color>
<color name="knobText">#000000</color>
<color name="knobLabelText">#ffffff</color>
<color name="knobLabelBackground">#006b0b</color>
</palette>
<palette name="inverted">
<color name="boxBackground">#2e3436</color>
<color name="text">#ffffff</color>
<color name="inactiveText">#b2b2b2</color>
<color name="highlightedText">#fd9800</color>
<color name="titleBoxText">#000000</color>
<color name="titleBoxBackground">#babdb6</color>
<color name="valueText">#000000</color>
<color name="valueBackground">#9a9a9a</color>
<color name="icon">#b2b2b2</color>
<color name="iconHighlight">#fd9800</color>
<color name="knobActiveTrack">#00aa11</color>
<color name="knobInactiveTrack">#606060</color>
<color name="knobLineIndicator">#ffffff</color>
<color name="knobText">#ffffff</color>
<color name="knobLabelText">#ffffff</color>
<color name="knobLabelBackground">#006b0b</color>
</palette>
</sfizz-theme>

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,252 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="192"
inkscape:export-xdpi="192"
inkscape:export-filename="/home/jpc/documents/projects/sfizz/editor/resources/logo_text@2x.png"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="logo_text.svg"
id="svg8"
version="1.1"
viewBox="0 0 105.83333 66.145836"
height="250"
width="400">
<title
id="title1469">sfizz logo</title>
<defs
id="defs2">
<linearGradient
id="linearGradient1445"
inkscape:collect="always">
<stop
id="stop1441"
offset="0"
style="stop-color:#646464;stop-opacity:1" />
<stop
id="stop1443"
offset="1"
style="stop-color:#000000;stop-opacity:1" />
</linearGradient>
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect1150"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
unit="mm"
method="auto"
mode="C"
radius="1"
chamfer_steps="2"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect1136"
effect="fillet_chamfer" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect968"
effect="fillet_chamfer" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect921"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
unit="mm"
method="auto"
mode="C"
radius="1"
chamfer_steps="2"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect1183"
effect="fillet_chamfer" />
<inkscape:path-effect
end_linecap_type="zerowidth"
scale_width="1"
miter_limit="4"
linejoin_type="round"
start_linecap_type="zerowidth"
interpolator_beta="0.2"
interpolator_type="CubicBezierFit"
sort_points="true"
offset_points="0.19099662,0.36320029 | 0.41721681,0.40988822 | 0.9095762,0.070646707"
lpeversion="1"
is_visible="true"
id="path-effect1172"
effect="powerstroke" />
<clipPath
id="clipPath917"
clipPathUnits="userSpaceOnUse">
<rect
y="68.872978"
x="24.792475"
height="25.252825"
width="39.659527"
id="rect919"
style="fill:#ffffff;stroke:none;stroke-width:2;stroke-linecap:round;paint-order:markers stroke fill" />
</clipPath>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="231.60674"
x2="539.22601"
y1="190.42654"
x1="539.22601"
id="linearGradient1447"
xlink:href="#linearGradient1445"
inkscape:collect="always"
gradientTransform="translate(34.589224,10.333824)" />
</defs>
<sodipodi:namedview
fit-margin-bottom="10"
fit-margin-right="10"
fit-margin-left="10"
fit-margin-top="10"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-center="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox="true"
inkscape:guide-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="27"
inkscape:window-x="0"
inkscape:window-height="1008"
inkscape:window-width="1920"
showguides="false"
inkscape:snap-global="false"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="53.822531"
inkscape:cx="17.632385"
inkscape:zoom="1"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
units="px">
<sodipodi:guide
id="guide899"
orientation="1,0"
position="-452.4563,176.31198" />
<sodipodi:guide
id="guide901"
orientation="0,-1"
position="-351.71366,154.32488" />
<sodipodi:guide
id="guide1008"
orientation="1,0"
position="-536.98274,156.82863" />
<sodipodi:guide
id="guide1185"
orientation="1,0"
position="-351.75629,154.33106" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>sfizz logo</dc:title>
<dc:date>2020-05-16</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Tobiasz 'unfa' Karoń</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>CC-0</dc:title>
</cc:Agent>
</dc:rights>
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
transform="translate(-495.92008,-191.91875)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
id="path1439"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.8154px;line-height:1.25;font-family:ABeeZee;-inkscape-font-specification:ABeeZee;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient1447);fill-opacity:1;stroke:none;stroke-width:0.264584"
d="m 569.95053,215.93967 h 13.61282 v 2.40226 l -9.9572,12.91651 h 10.13128 v 2.78523 h -13.99579 v -2.47189 l 9.99202,-12.91651 h -9.78313 z m -16.4328,0 h 13.61282 v 2.40226 l -9.9572,12.91651 h 10.13128 v 2.78523 h -13.99579 v -2.47189 l 9.99202,-12.91651 h -9.78313 z m -6.38378,18.104 h -3.13338 l 3.1682,-18.104 h 3.13339 z m 2.33264,-21.20257 c -0.64989,0 -1.14891,-0.18568 -1.49707,-0.55705 -0.32494,-0.39457 -0.48741,-0.84717 -0.48741,-1.3578 0,-0.74273 0.2321,-1.33459 0.69631,-1.77559 0.4642,-0.46421 1.04446,-0.69631 1.74077,-0.69631 0.64989,0 1.1373,0.19729 1.46224,0.59187 0.34815,0.37136 0.52223,0.81235 0.52223,1.32298 0,0.74273 -0.2321,1.34619 -0.6963,1.8104 -0.46421,0.441 -1.04446,0.6615 -1.74077,0.6615 z m -12.24537,3.76006 h 5.36157 l -0.48741,2.7156 h -5.36157 l -3.06376,17.23362 c -0.18568,1.02125 -0.4526,1.88003 -0.80075,2.57634 -0.34815,0.71952 -0.76594,1.29978 -1.25336,1.74077 -0.48741,0.44099 -1.04446,0.75433 -1.67114,0.94002 -0.62667,0.20889 -1.29977,0.31334 -2.01929,0.31334 -0.76594,0 -1.46225,-0.10445 -2.08892,-0.31334 -0.64989,-0.20889 -1.21854,-0.49902 -1.70596,-0.87039 l 1.25336,-2.57634 c 0.32494,0.32495 0.70791,0.58026 1.1489,0.76594 0.41779,0.18568 0.8936,0.27852 1.42744,0.27852 0.62667,0 1.16051,-0.2205 1.6015,-0.66149 0.46421,-0.44099 0.78915,-1.14891 0.97484,-2.12374 l 3.06375,-17.30325 h -2.78523 l 0.48741,-2.7156 h 2.78524 l 0.52223,-2.78523 c 0.39457,-2.13535 1.14891,-3.65562 2.263,-4.56082 1.11409,-0.92841 2.54152,-1.39262 4.28229,-1.39262 0.95162,0 1.83361,0.12766 2.64597,0.38297 0.81236,0.23211 1.54348,0.52224 2.19337,0.87039 l -1.21854,2.64597 c -0.53383,-0.27853 -1.09088,-0.53384 -1.67114,-0.76594 -0.55704,-0.23211 -1.21853,-0.34816 -1.98447,-0.34816 -0.85878,0 -1.5899,0.25531 -2.19337,0.76594 -0.60347,0.48742 -0.99804,1.25336 -1.18373,2.29782 z m -21.96217,13.36911 c 0.60347,0.53384 1.3578,0.96323 2.263,1.28817 0.92841,0.32495 1.91485,0.48742 2.95931,0.48742 1.29977,0 2.2746,-0.20889 2.92449,-0.62668 0.6731,-0.44099 1.00965,-0.99804 1.00965,-1.67114 0,-0.34815 -0.0696,-0.6731 -0.20889,-0.97483 -0.11605,-0.30173 -0.34816,-0.59186 -0.69631,-0.87039 -0.32495,-0.27852 -0.77755,-0.54544 -1.3578,-0.80075 -0.58026,-0.27852 -1.33459,-0.58025 -2.263,-0.9052 -1.71756,-0.58026 -2.99413,-1.26496 -3.8297,-2.05411 -0.83557,-0.81236 -1.25335,-1.92645 -1.25335,-3.34228 0,-0.69631 0.15087,-1.34619 0.4526,-1.94966 0.32495,-0.60347 0.77755,-1.1257 1.3578,-1.56669 0.60347,-0.46421 1.32299,-0.82397 2.15856,-1.07928 0.85878,-0.25531 1.83361,-0.38297 2.92449,-0.38297 1.18372,0 2.21658,0.12766 3.09857,0.38297 0.9052,0.2321 1.71756,0.53383 2.43708,0.9052 l -0.87039,2.57634 c -0.62667,-0.37137 -1.34619,-0.6731 -2.15855,-0.9052 -0.78915,-0.2321 -1.67114,-0.34815 -2.64597,-0.34815 -1.20693,0 -2.12374,0.24371 -2.75042,0.73112 -0.62668,0.48741 -0.94002,1.02125 -0.94002,1.60151 0,0.27852 0.0464,0.53383 0.13927,0.76594 0.11605,0.2321 0.31333,0.4526 0.59186,0.66149 0.27852,0.20889 0.64988,0.41779 1.11409,0.62668 0.46421,0.20889 1.04446,0.42938 1.74077,0.66149 1.13731,0.39457 2.10053,0.80075 2.88968,1.21854 0.78915,0.39457 1.42743,0.83557 1.91485,1.32298 0.48741,0.48742 0.83557,1.02126 1.04446,1.60151 0.20889,0.55705 0.31334,1.18372 0.31334,1.88003 0,0.81236 -0.17408,1.54348 -0.52223,2.19337 -0.34816,0.64989 -0.83558,1.20693 -1.46225,1.67114 -0.62668,0.44099 -1.39262,0.77754 -2.29782,1.00965 -0.88199,0.25531 -1.86842,0.38297 -2.95931,0.38297 -1.39261,0 -2.63436,-0.17408 -3.72524,-0.52223 -1.09089,-0.34815 -1.99609,-0.80075 -2.71561,-1.3578 z"
sodipodi:nodetypes="cccccccccccccccccccccccccccscscscscsccccccscsccccsccccccccsccccscccccscscccccscccsccccssscssccccssccsscc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -0,0 +1,81 @@
// 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 "ColorHelpers.h"
#include <ColorSpaces.h>
SColorRGB::SColorRGB(const CColor &cc)
{
r = cc.normRed<float>();
g = cc.normGreen<float>();
b = cc.normBlue<float>();
a = cc.normAlpha<float>();
}
SColorRGB::SColorRGB(const SColorHCY &hcy)
{
ColorSpaces::vec3 vhcy{{hcy.h, hcy.c, hcy.y}};
ColorSpaces::vec3 vrgb = ColorSpaces::hcy_to_rgb(vhcy);
r = vrgb[0];
g = vrgb[1];
b = vrgb[2];
a = hcy.a;
}
CColor SColorRGB::toColor() const
{
CColor cc;
cc.setNormRed(r);
cc.setNormGreen(g);
cc.setNormBlue(b);
cc.setNormAlpha(a);
return cc;
}
SColorHCY::SColorHCY(const SColorRGB &rgb)
{
ColorSpaces::vec3 vrgb{{rgb.r, rgb.g, rgb.b}};
ColorSpaces::vec3 vhcy = ColorSpaces::rgb_to_hcy(vrgb);
h = vhcy[0];
c = vhcy[1];
y = vhcy[2];
a = rgb.a;
}
static int hexDigitFromChar(char c)
{
return (c >= '0' && c <= '9') ? (c - '0') :
(c >= 'a' && c <= 'z') ? (c - 'a' + 10) :
(c >= 'A' && c <= 'Z') ? (c - 'A' + 10) : -1;
}
bool colorFromHex(absl::string_view hex, CColor& color)
{
if (hex.empty() || hex[0] != '#')
return false;
hex = hex.substr(1, hex.size());
size_t length = hex.size();
uint32_t rgba = 0;
if (length == 6 || length == 8) {
for (size_t i = 0; i < length; ++i) {
int d = hexDigitFromChar(hex[i]);
if (d == -1)
return false;
rgba = (rgba << 4) | d;
}
}
if (length == 6)
rgba = (rgba << 8) | 0xff;
color.red = rgba >> 24;
color.green = (rgba >> 16) & 0xff;
color.blue = (rgba >> 8) & 0xff;
color.alpha = rgba & 0xff;
return true;
}

View file

@ -0,0 +1,38 @@
// 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 "utility/vstgui_before.h"
#include "vstgui/lib/ccolor.h"
#include "utility/vstgui_after.h"
#include <absl/strings/string_view.h>
using namespace VSTGUI;
struct SColorRGB;
struct SColorHCY;
struct SColorRGB {
SColorRGB() = default;
explicit SColorRGB(const CColor &cc);
explicit SColorRGB(const SColorHCY &hcy);
SColorRGB(float r, float g, float b, float a = 1.0) : r(r), g(g), b(b), a(a) {}
CColor toColor() const;
float r {}, g {}, b {}, a { 1.0 };
};
struct SColorHCY {
SColorHCY() = default;
explicit SColorHCY(const CColor &cc) : SColorHCY(SColorRGB(cc)) {}
explicit SColorHCY(const SColorRGB &rgb);
SColorHCY(float h, float c, float y, float a = 1.0) : h(h), c(c), y(y), a(a) {}
CColor toColor() const { return SColorRGB(*this).toColor(); }
float h {}, c {}, y {}, a { 1.0 };
};
bool colorFromHex(absl::string_view hex, CColor& color);

View file

@ -0,0 +1,323 @@
// 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 "DlgAbout.h"
#include "GUIComponents.h"
#include "GUIDefs.h"
#include "GitBuildId.h"
#include "NativeHelpers.h"
#include "utility/vstgui_before.h"
#include "vstgui/vstgui.h"
#include "utility/vstgui_after.h"
#include <absl/strings/str_cat.h>
#if 0
#include <absl/time/clock.h>
#include <absl/time/time.h>
#endif
using namespace gui;
SAboutDialog::SAboutDialog(const CRect& bounds)
: CViewContainer(bounds)
{
SharedPointer<CBitmap> logo = owned(new CBitmap("logo_orange.png"));
setBackgroundColor(kColorControlsScrollerTransparency);
CView* aboutView = nullptr;
{
auto createaboutView = [](const CRect& bounds, int, const char*, CHoriTxtAlign, int) {
CViewContainer* container = new CViewContainer(bounds);
container->setBackgroundColor(kColorTransparent);
return container;
};
auto createLogo = [&logo](const CRect& bounds, int, const char*, CHoriTxtAlign, int) {
CViewContainer* container = new CViewContainer(bounds);
container->setBackgroundColor(kColorTransparent);
container->setBackground(logo);
return container;
};
auto createInfoBox = [](const CRect& bounds, int, const char*, CHoriTxtAlign align, int fontsize) {
CMultiLineTextLabel* lbl = new CMultiLineTextLabel(bounds);
auto font = makeOwned<CFontDesc>("Roboto", fontsize);
lbl->setFont(font);
lbl->setFontColor(kWhiteCColor);
lbl->setFrameColor(kColorTransparent);
lbl->setBackColor(kColorTransparent);
lbl->setHoriAlign(align);
const char* version = SFIZZ_VERSION;
std::string versionBuf;
if (GitBuildId[0]) {
versionBuf = absl::StrCat(SFIZZ_VERSION ".", GitBuildId);
version = versionBuf.c_str();
}
#if 0
absl::TimeZone utc = absl::UTCTimeZone();
absl::Time time = absl::Now();
absl::CivilYear date = absl::ToCivilYear(time, utc);
// u8"Copyright 2019-", date.year(), u8" by SFZTools Team,\n"
#endif
lbl->setText(absl::StrCat(
u8"Version ", version, u8"\n"
u8"Copyright 2019-2023 by SFZTools Team,\n"
u8"licensed under BSD 2-clause license."));
return lbl;
};
auto createDescriptionBox = [](const CRect& bounds, int, const char*, CHoriTxtAlign align, int fontsize) {
CMultiLineTextLabel* lbl = new CMultiLineTextLabel(bounds);
auto font = makeOwned<CFontDesc>("Roboto", fontsize);
lbl->setFont(font);
lbl->setFontColor(kWhiteCColor);
lbl->setFrameColor(kColorTransparent);
lbl->setBackColor(kColorTransparent);
lbl->setHoriAlign(align);
lbl->setText(absl::StrCat(
u8"Maintainers: Paul Ferrand, Jean-Pierre Cimalando\n"
u8"Contributors: Andrea Zanellato, Alexander Mitchell, Michael Willis,\n"
u8"Tobiasz \"unfa\" Karoń, Kinwie, Atsushi Eno, Dominique Würtz,\n"
u8"Even Brenden et al."));
return lbl;
};
auto createHoverBox = [](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) {
CTextLabel* lbl = new CTextLabel(bounds, label);
auto font = makeOwned<CFontDesc>("Roboto", fontsize);
lbl->setFontColor(kColorOrange);
lbl->setFrameColor(kColorTransparent);
lbl->setBackColor(kColorTransparent);
lbl->setHoriAlign(align);
lbl->setFont(font);
return lbl;
};
auto createSysInfoKeyBox = [](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) {
CMultiLineTextLabel* lbl = new CMultiLineTextLabel(bounds);
auto font = makeOwned<CFontDesc>("Roboto", fontsize, kBoldFace);
lbl->setFont(font);
lbl->setFontColor(kColorOrange);
lbl->setFrameColor(kColorTransparent);
lbl->setBackColor(kColorTransparent);
lbl->setHoriAlign(align);
lbl->setText(label);
return lbl;
};
auto createSysInfoValueBox = [](const CRect& bounds, int, const char* label, CHoriTxtAlign align, int fontsize) {
CMultiLineTextLabel* lbl = new CMultiLineTextLabel(bounds);
auto font = makeOwned<CFontDesc>("Roboto", fontsize);
lbl->setFont(font);
lbl->setFontColor(kWhiteCColor);
lbl->setFrameColor(kColorTransparent);
lbl->setBackColor(kColorTransparent);
lbl->setHoriAlign(align);
lbl->setText(label);
return lbl;
};
auto createGlyphButton = [this](UTF8StringPtr glyph, const CRect& bounds, int tag, int fontsize) {
STextButton* btn = new STextButton(bounds, this, tag, glyph);
btn->setFont(makeOwned<CFontDesc>("Sfizz Misc Icons", fontsize));
btn->setTextColor(kWhiteCColor);
btn->setHighlightColor(kColorOrange);
btn->setFrameColor(kColorTransparent);
btn->setFrameColorHighlighted(kColorTransparent);
btn->setGradient(nullptr);
btn->setGradientHighlighted(nullptr);
return btn;
};
auto createButtonSfztools = [this, &createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
STextButton* btn = createGlyphButton(u8"\ue000", bounds, tag, fontsize);
btn->OnHoverEnter = [this, btn]() { buttonHoverEnter(btn, "SFZ Tools"); };
btn->OnHoverLeave = [this, btn]() { buttonHoverLeave(btn); };
return btn;
};
auto createButtonGithub = [this, &createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
STextButton* btn = createGlyphButton(u8"\ue001", bounds, tag, fontsize);
btn->OnHoverEnter = [this, btn]() { buttonHoverEnter(btn, "Source code"); };
btn->OnHoverLeave = [this, btn]() { buttonHoverLeave(btn); };
return btn;
};
auto createButtonDiscord = [this, &createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
STextButton* btn = createGlyphButton(u8"\ue002", bounds, tag, fontsize);
btn->OnHoverEnter = [this, btn]() { buttonHoverEnter(btn, "Community chat"); };
btn->OnHoverLeave = [this, btn]() { buttonHoverLeave(btn); };
return btn;
};
auto createButtonOpencollective = [this, &createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
STextButton* btn = createGlyphButton(u8"\ue003", bounds, tag, fontsize);
btn->OnHoverEnter = [this, btn]() { buttonHoverEnter(btn, "Support us"); };
btn->OnHoverLeave = [this, btn]() { buttonHoverLeave(btn); };
return btn;
};
auto createButtonSfzformat = [this, &createGlyphButton](const CRect& bounds, int tag, const char*, CHoriTxtAlign, int fontsize) {
STextButton* btn = createGlyphButton(u8"\ue004", bounds, tag, fontsize);
btn->OnHoverEnter = [this, btn]() { buttonHoverEnter(btn, "SFZ Format"); };
btn->OnHoverLeave = [this, btn]() { buttonHoverLeave(btn); };
return btn;
};
#include "layout/about.hpp"
}
addView(aboutView);
CRect aboutBounds = aboutView->getViewSize();
aboutBounds.centerInside(CRect(bounds).originize());
aboutView->setViewSize(aboutBounds);
///
sysInfoTemplate_ = lblSysInfoValue_->getText();
sysInfoVariables_["%Pluginformat%"] = {};
sysInfoVariables_["%HostOS%"] = getOperatingSystemName();
sysInfoVariables_["%HostCPU%"] = getProcessorName();
sysInfoVariables_["%HostBits%"] = std::to_string(8 * sizeof(void*));
sysInfoVariables_["%HostProgram%"] = getCurrentProcessName();
updateSysInfo();
}
void SAboutDialog::setPluginFormat(const std::string& pluginFormat)
{
sysInfoVariables_["%PluginFormat%"] = pluginFormat;
updateSysInfo();
}
void SAboutDialog::setPluginHost(const std::string& pluginHost)
{
sysInfoVariables_["%HostProgram%"] = pluginHost;
updateSysInfo();
}
void SAboutDialog::updateSysInfo()
{
std::string text = sysInfoTemplate_;
for (const auto& infoKeyValue : sysInfoVariables_) {
size_t pos = text.find(infoKeyValue.first);
if (pos != text.npos)
text.replace(pos, infoKeyValue.first.size(), infoKeyValue.second);
}
lblSysInfoValue_->setText(UTF8String(text));
}
void SAboutDialog::buttonHoverEnter(CControl* btn, const char* text)
{
CRect rect = lblHover_->getViewSize();
CRect btnRect = btn->getViewSize();
rect.left = btnRect.left - 100;
rect.right = btnRect.right + 100;
lblHover_->setViewSize(rect);
lblHover_->setText(text);
lblHover_->setVisible(true);
lblHover_->invalid();
}
void SAboutDialog::buttonHoverLeave(CControl* btn)
{
(void)btn;
lblHover_->setVisible(false);
}
CMouseEventResult SAboutDialog::onMouseDown(CPoint& where, const CButtonState& buttons)
{
CMouseEventResult result = CViewContainer::onMouseDown(where, buttons);
if (result != kMouseEventHandled) {
setVisible(false);
result = kMouseEventHandled;
}
return result;
}
#if VSTGUI_MORE_THAN_4_10
void SAboutDialog::onKeyboardEvent (KeyboardEvent& event, CFrame* frame)
{
auto vstKeyCode = toVstKeyCode (event);
if (event.type == EventType::KeyDown && vstKeyCode.virt == VKEY_ESCAPE)
{
setVisible(false);
frame->unregisterKeyboardHook(this);
event.consumed = true;
}
}
#else
int32_t SAboutDialog::onKeyDown (const VstKeyCode& keyCode, CFrame* frame)
{
if (keyCode.virt == VKEY_ESCAPE) {
setVisible(false);
frame->unregisterKeyboardHook(this);
return 1;
}
return -1;
}
int32_t SAboutDialog::onKeyUp (const VstKeyCode& keyCode, CFrame* frame)
{
(void)keyCode;
(void)frame;
return -1;
}
#endif
void SAboutDialog::valueChanged(CControl *ctl)
{
int32_t tag = ctl->getTag();
float value = ctl->getValue();
switch (tag) {
case kTagButtonSfztools:
if (value != 1)
break;
Call::later([]() {
openURLWithExternalProgram("https://sfz.tools/sfizz/");
});
break;
case kTagButtonGithub:
if (value != 1)
break;
Call::later([]() {
openURLWithExternalProgram("https://github.com/sfztools/sfizz");
});
break;
case kTagButtonDiscord:
if (value != 1)
break;
Call::later([]() {
openURLWithExternalProgram("https://discord.gg/3ArE9Mw");
});
break;
case kTagButtonOpencollective:
if (value != 1)
break;
Call::later([]() {
openURLWithExternalProgram("https://opencollective.com/sfztools");
});
break;
case kTagButtonSfzformat:
if (value != 1)
break;
Call::later([]() {
openURLWithExternalProgram("https://sfzformat.com/");
});
break;
default:
break;
}
}

View file

@ -0,0 +1,58 @@
// 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 "utility/vstgui_before.h"
#include "vstgui/lib/cviewcontainer.h"
#include "vstgui/vstgui.h"
#include "utility/vstgui_after.h"
#include <string>
#define VSTGUI_MORE_THAN_4_10 ((VSTGUI_VERSION_MAJOR > 4) \
|| (VSTGUI_VERSION_MAJOR == 4 && VSTGUI_VERSION_MINOR > 10))
using namespace VSTGUI;
class SAboutDialog : public CViewContainer, public IControlListener, public IKeyboardHook {
enum {
kTagButtonSfztools,
kTagButtonGithub,
kTagButtonDiscord,
kTagButtonOpencollective,
kTagButtonSfzformat
};
public:
explicit SAboutDialog(const CRect& bounds);
void setPluginFormat(const std::string& pluginFormat);
void setPluginHost(const std::string& pluginHost);
#if VSTGUI_MORE_THAN_4_10
void onKeyboardEvent (KeyboardEvent& event, CFrame* frame) override;
#else
int32_t onKeyDown(const VstKeyCode& code, CFrame* frame) override;
int32_t onKeyUp(const VstKeyCode& code, CFrame* frame) override;
#endif
protected:
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override;
// IControlListener
void valueChanged(CControl* ctl) override;
private:
void updateSysInfo();
void buttonHoverEnter(CControl* btn, const char* text);
void buttonHoverLeave(CControl* btn);
CTextLabel* lblHover_ = {};
CTextLabel* lblSysInfoValue_ = {};
std::string sysInfoTemplate_;
std::map<std::string, std::string> sysInfoVariables_;
};

View file

@ -0,0 +1,44 @@
// 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::SampleQuality:
return { 2, 0, 10 };
case EditId::OscillatorQuality:
return { 1, 0, 3 };
case EditId::FreewheelingSampleQuality:
return { 10, 0, 10 };
case EditId::FreewheelingOscillatorQuality:
return { 3, 0, 3 };
case EditId::SustainCancelsRelease:
return { 0, 0, 1 };
case EditId::UIActivePanel:
return { 0, 0, 255 };
case EditId::UIZoom:
return { 100, 100, 300 };
}
}

View file

@ -0,0 +1,109 @@
// 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 "sfizz/Config.h"
#include <cassert>
enum class EditId : int {
SfzFile,
Volume,
Polyphony,
Oversampling,
PreloadSize,
ScalaFile,
ScalaRootKey,
TuningFrequency,
StretchTuning,
SampleQuality,
OscillatorQuality,
FreewheelingSampleQuality,
FreewheelingOscillatorQuality,
SustainCancelsRelease,
CanEditUserFilesDir,
UserFilesDir,
FallbackFilesDir,
//
#define KEY_RANGE(Name) Name##0, Name##Last = Name##0 + 128 - 1
#define CC_RANGE(Name) Name##0, Name##Last = Name##0 + sfz::config::numCCs - 1
#define METER_RANGE(Name) Name##0, Name##Last = Name##0 + 16 - 1
//
KEY_RANGE(Key),
CC_RANGE(Controller),
//
KEY_RANGE(KeyUsed),
KEY_RANGE(KeyLabel),
KEY_RANGE(KeyswitchUsed),
KEY_RANGE(KeyswitchLabel),
CC_RANGE(ControllerUsed),
CC_RANGE(ControllerDefault),
CC_RANGE(ControllerLabel),
//
METER_RANGE(Level),
//
UINumCurves,
UINumMasters,
UINumGroups,
UINumRegions,
UINumPreloadedSamples,
UINumActiveVoices,
UIActivePanel,
UIZoom,
//
BackgroundImage,
ControlsImage,
//
PluginFormat,
PluginHost,
PluginOutputs,
//
#undef KEY_RANGE
#undef CC_RANGE
#undef METER_RANGE
};
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) {}
float extent() const noexcept { return max - min; }
static EditRange get(EditId id);
};
#define DEFINE_EDIT_ID_RANGE_HELPERS(type, Type, IdPrefix) \
inline bool editIdIs##Type(EditId id) \
{ \
return int(id) >= int(EditId::IdPrefix##0) && \
int(id) <= int(EditId::IdPrefix##Last); \
} \
inline EditId editIdFor##Type(int value) \
{ \
EditId id = EditId(int(EditId::IdPrefix##0) + value); \
assert(editIdIs##Type(id)); \
return id; \
} \
inline int type##ForEditId(EditId id) \
{ \
assert(editIdIs##Type(id)); \
return int(id) - int(EditId::IdPrefix##0); \
}
// defines editIdForCC, ccForEditId, editIdIsCC, etc..
DEFINE_EDIT_ID_RANGE_HELPERS(cc, CC, Controller)
DEFINE_EDIT_ID_RANGE_HELPERS(level, Level, Level)
DEFINE_EDIT_ID_RANGE_HELPERS(key, Key, Key)
DEFINE_EDIT_ID_RANGE_HELPERS(keyUsed, KeyUsed, KeyUsed)
DEFINE_EDIT_ID_RANGE_HELPERS(keyLabel, KeyLabel, KeyLabel)
DEFINE_EDIT_ID_RANGE_HELPERS(keyswitchUsed, KeyswitchUsed, KeyswitchUsed)
DEFINE_EDIT_ID_RANGE_HELPERS(keyswitchLabel, KeyswitchLabel, KeyswitchLabel)
DEFINE_EDIT_ID_RANGE_HELPERS(ccUsed, CCUsed, ControllerUsed)
DEFINE_EDIT_ID_RANGE_HELPERS(ccDefault, CCDefault, ControllerDefault)
DEFINE_EDIT_ID_RANGE_HELPERS(ccLabel, CCLabel, ControllerLabel)
#undef DEFINE_EDIT_ID_RANGE_HELPERS

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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
// 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 <sfizz_message.h>
#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,53 @@
// 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 <sfizz_message.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;
virtual void uiSendMessage(const char* path, const char* sig, const sfizz_arg_t* args) = 0;
class Receiver;
void decorate(Receiver* r) { r_ = r; }
class Receiver {
public:
virtual ~Receiver() {}
virtual void uiReceiveValue(EditId id, const EditValue& v) = 0;
virtual void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args) = 0;
};
// called by DSP
void uiReceiveValue(EditId id, const EditValue& v);
void uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args);
private:
Receiver* r_ = nullptr;
};
inline void EditorController::uiReceiveValue(EditId id, const EditValue& v)
{
if (r_)
r_->uiReceiveValue(id, v);
}
inline void EditorController::uiReceiveMessage(const char* path, const char* sig, const sfizz_arg_t* args)
{
if (r_)
r_->uiReceiveMessage(path, sig, args);
}

View file

@ -0,0 +1,8 @@
// 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
#define STB_IMAGE_IMPLEMENTATION
#include "EditorLibs.h"

View file

@ -0,0 +1,8 @@
// 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 <stb_image.h>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,521 @@
// 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 "GUIDefs.h"
#include <bitset>
#include <vector>
#include <memory>
#include <functional>
#include "utility/vstgui_before.h"
#include "vstgui/lib/controls/cslider.h"
#include "vstgui/lib/controls/cknob.h"
#include "vstgui/lib/controls/ctextlabel.h"
#include "vstgui/lib/controls/ctextedit.h"
#include "vstgui/lib/controls/cbuttons.h"
#include "vstgui/lib/controls/coptionmenu.h"
#include "vstgui/lib/controls/cscrollbar.h"
#include "vstgui/lib/controls/icontrollistener.h"
#include "vstgui/lib/cviewcontainer.h"
#include "vstgui/lib/cscrollview.h"
#include "vstgui/lib/ccolor.h"
#include "vstgui/lib/dragging.h"
#include "utility/vstgui_after.h"
using namespace VSTGUI;
///
class SBoxContainer : public CViewContainer {
public:
explicit SBoxContainer(const CRect& size);
virtual ~SBoxContainer() {}
void setCornerRadius(CCoord radius);
void setBackgroundColor(const CColor& color) override;
CColor getBackgroundColor() const override;
protected:
void drawRect(CDrawContext* dc, const CRect& updateRect) override;
protected:
CCoord cornerRadius_ = 0.0;
CColor backgroundColor_;
};
///
class STitleContainer : public SBoxContainer {
public:
explicit STitleContainer(const CRect& size, UTF8StringPtr text = nullptr);
~STitleContainer() {}
void setTitleFont(CFontRef font);
CFontRef getTitleFont() { return titleFont_; }
void setTitleFontColor(CColor color);
CColor getTitleFontColor() const { return titleFontColor_; }
void setTitleBackgroundColor(CColor color);
CColor getTitleBackgroundColor() const { return titleBackgroundColor_; }
protected:
void drawRect(CDrawContext* dc, const CRect& updateRect) override;
private:
std::string text_;
CColor titleFontColor_;
CColor titleBackgroundColor_;
SharedPointer<CFontDesc> titleFont_;
};
///
class SFileDropTarget : public IDropTarget,
public NonAtomicReferenceCounted {
public:
typedef std::function<void(const std::string&)> FileDropFunction;
void setFileDropFunction(FileDropFunction f);
protected:
DragOperation onDragEnter(DragEventData data) override;
DragOperation onDragMove(DragEventData data) override;
void onDragLeave(DragEventData data) override;
bool onDrop(DragEventData data) override;
private:
static bool isFileDrop(IDataPackage* package);
private:
DragOperation op_ = DragOperation::None;
FileDropFunction dropFunction_;
};
///
class SValueMenu : public CParamDisplay {
public:
explicit SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag);
CColor getHoverColor() const { return hoverColor_; }
void setHoverColor(const CColor& color);
CMenuItem* addEntry(CMenuItem* item, float value, int32_t index = -1);
CMenuItem* addEntry(const UTF8String& title, float value, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags);
CMenuItem* addSeparator(int32_t index = -1);
int32_t getNbEntries() const;
protected:
void draw(CDrawContext* dc) override;
CMouseEventResult onMouseEntered(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseExited(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override;
bool onWheel(const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override;
private:
CColor hoverColor_;
bool hovered_ = false;
//
class MenuListener;
//
void onItemClicked(int32_t index);
//
CMenuItemList menuItems_;
std::vector<float> menuItemValues_;
SharedPointer<MenuListener> menuListener_;
//
class MenuListener : public IControlListener, public NonAtomicReferenceCounted {
public:
explicit MenuListener(SValueMenu& menu) : menu_(menu) {}
void valueChanged(CControl* control) override
{
menu_.onItemClicked(static_cast<int32_t>(control->getValue()));
}
private:
SValueMenu& menu_;
};
};
///
class SActionMenu : public CParamDisplay {
public:
explicit SActionMenu(const CRect& bounds, IControlListener* listener);
std::string getTitle() const { return title_; }
void setTitle(std::string title);
CColor getHoverColor() const { return hoverColor_; }
void setHoverColor(const CColor& color);
CMenuItem* addEntry(CMenuItem* item, int32_t tag, int32_t index = -1);
CMenuItem* addEntry(const UTF8String& title, int32_t tag, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags);
CMenuItem* addSeparator(int32_t index = -1);
int32_t getNbEntries() const;
protected:
void draw(CDrawContext* dc) override;
CMouseEventResult onMouseEntered(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseExited(CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override;
private:
std::string title_;
CColor hoverColor_;
bool hovered_ = false;
class MenuListener;
//
void onItemClicked(int32_t index);
//
CMenuItemList menuItems_;
std::vector<int32_t> menuItemTags_;
SharedPointer<MenuListener> menuListener_;
//
class MenuListener : public IControlListener, public NonAtomicReferenceCounted {
public:
explicit MenuListener(SActionMenu& menu) : menu_(menu) {}
void valueChanged(CControl* control) override
{
menu_.onItemClicked(static_cast<int32_t>(control->getValue()));
}
private:
SActionMenu& menu_;
};
};
///
class SHoverButton : public CKickButton {
public:
SHoverButton(
const CRect& size,
IControlListener* listener,
int32_t tag,
CBitmap* background,
const CPoint& offset = CPoint (0, 0))
: CKickButton(size, listener, tag, background, offset)
{}
CMouseEventResult onMouseEntered(CPoint&, const CButtonState&) override;
CMouseEventResult onMouseExited(CPoint&, const CButtonState&) override;
void draw(CDrawContext*) override;
std::function<void()> OnHoverEnter;
std::function<void()> OnHoverLeave;
private:
bool hovered_ { false };
};
///
class STextButton: public CTextButton {
public:
STextButton(const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, UTF8StringPtr title = nullptr)
: CTextButton(size, listener, tag, title) {}
CColor getHighlightColor() const { return highlightColor_; }
void setHighlightColor(const CColor& color);
CColor getInactiveColor() const { return inactiveColor_; }
void setInactiveColor(const CColor& color);
bool isInactive() const { return inactive_; }
void setInactive(bool b);
bool isHighlighted() const { return highlighted_; }
void setHighlighted(bool b);
CMouseEventResult onMouseEntered (CPoint& where, const CButtonState& buttons) override;
CMouseEventResult onMouseExited (CPoint& where, const CButtonState& buttons) override;
void draw(CDrawContext* context) override;
std::function<void()> OnHoverEnter;
std::function<void()> OnHoverLeave;
private:
CColor highlightColor_;
bool hovered_ { false };
bool highlighted_ { false };
CColor inactiveColor_;
bool inactive_ { false };
};
///
class SStyledKnob : public CKnobBase {
public:
SStyledKnob(const CRect& size, IControlListener* listener, int32_t tag);
const CColor& getActiveTrackColor() const { return activeTrackColor_; }
void setActiveTrackColor(const CColor& color);
const CColor& getInactiveTrackColor() const { return inactiveTrackColor_; }
void setInactiveTrackColor(const CColor& color);
const CColor& getLineIndicatorColor() const { return lineIndicatorColor_; }
void setLineIndicatorColor(const CColor& color);
const CColor& getRotatorColor() const { return rotatorColor_; }
void setRotatorColor(const CColor& color);
void setFont(CFontRef font);
CFontRef getFont() const { return font_; }
void setFontColor(CColor fontColor);
CColor getFontColor() const { return fontColor_; }
using ValueToStringFunction = std::function<bool(float value, std::string& result)>;
void setValueToStringFunction(ValueToStringFunction func);
void setHideValue(bool hide) { hideValue_ = hide; invalid(); }
bool getHideValue() const { return hideValue_; }
CLASS_METHODS(SStyledKnob, CKnobBase)
protected:
void draw(CDrawContext* dc) override;
private:
CColor activeTrackColor_;
CColor inactiveTrackColor_;
CColor lineIndicatorColor_;
CColor rotatorColor_ { gui::kColorTransparent };
bool hideValue_ { false };
SharedPointer<CFontDesc> font_ = kNormalFont;
CColor fontColor_ { 0x00, 0x00, 0x00 };
ValueToStringFunction valueToStringFunction_;
};
class CFilledRect : public CView
{
public:
explicit CFilledRect(const CRect& size)
: CView(size) {}
void setRadius(CCoord radius) { radius_ = radius; invalid(); }
CCoord getRadius() const { return radius_; }
void setColor(CColor color){ color_ = color; invalid(); }
CColor getColor() { return color_; }
protected:
void draw(CDrawContext* dc) override;
private:
CCoord radius_ { 5.0 };
CColor color_ { 0, 0, 0, 70 };
};
///
class SKnobCCBox : public CViewContainer, ViewListenerAdapter {
public:
SKnobCCBox(const CRect& size, IControlListener* listener, int32_t tag);
~SKnobCCBox();
void setHue(float hue);
float getValue() const { return knob_->getValue(); }
float getDefaultValue() const { return knob_->getDefaultValue(); }
void setValue(float value);
void setDefaultValue(float value);
void setNameLabelText(const UTF8String& name) { label_->setText(name); label_->invalid(); }
void setCCLabelText(const UTF8String& name) { ccLabel_->setText(name); ccLabel_->invalid(); }
void setNameLabelFont(CFontRef font);
CFontRef getNameLabelFont() const { return label_->getFont(); }
void setNameLabelFontColor(CColor color) { label_->setFontColor(color); label_->invalid(); }
CColor getNameLabelFontColor() const { return label_->getFontColor(); }
void setNameLabelBackColor(CColor color) { label_->setBackColor(color); label_->invalid(); }
CColor getNameLabelBackColor() const { return label_->getBackColor(); }
void setValueEditFont(CFontRef font);
CFontRef getValueEditFont() const { return label_->getFont(); }
void setValueEditFontColor(CColor color) { valueEdit_->setFontColor(color); valueEdit_->invalid(); }
CColor getValueEditFontColor() const { return valueEdit_->getFontColor(); }
void setValueEditBackColor(CColor color) { valueEdit_->setBackColor(color); valueEdit_->invalid(); }
CColor getValueEditBackColor() const { return valueEdit_->getBackColor(); }
void setShadingRectangleColor(CColor color) { shadingRectangle_->setColor(color); shadingRectangle_->invalid(); }
CColor getShadingRectangleColor() const { return shadingRectangle_->getColor(); }
void setCCLabelFont(CFontRef font);
CFontRef getCCLabelFont() const { return ccLabel_->getFont(); }
void setCCLabelFontColor(CColor color) { ccLabel_->setFontColor(color); ccLabel_->invalid(); }
CColor getCCLabelFontColor() const { return ccLabel_->getFontColor(); }
void setCCLabelBackColor(CColor color) { ccLabel_->setBackColor(color); ccLabel_->invalid(); }
CColor getCCLabelBackColor() const { return ccLabel_->getBackColor(); }
void setKnobActiveTrackColor(CColor color) { knob_->setActiveTrackColor(color); knob_->invalid(); }
CColor getKnobActiveTrackColor() const { return knob_->getActiveTrackColor(); }
void setKnobInactiveTrackColor(CColor color) { knob_->setInactiveTrackColor(color); knob_->invalid(); }
CColor getKnobInactiveTrackColor() const { return knob_->getInactiveTrackColor(); }
void setKnobLineIndicatorColor(CColor color) { knob_->setLineIndicatorColor(color); knob_->invalid(); }
CColor getKnobLineIndicatorColor() const { return knob_->getLineIndicatorColor(); }
void setKnobRotatorColor(CColor color) { knob_->setRotatorColor(color); knob_->invalid(); }
CColor getKnobRotatorColor() const { return knob_->getRotatorColor(); }
void setKnobFont(CFontRef font) { knob_->setFont(font); knob_->invalid(); }
CFontRef getKnobFont() const { return knob_->getFont(); }
void setKnobFontColor(CColor color) { knob_->setFontColor(color); knob_->invalid(); }
CColor getKnobFontColor() const { return knob_->getFontColor(); }
// Edit box listener
void viewLostFocus (CView* view) override;
bool isHD() const noexcept { return hdMode_; }
void setHDMode(bool mode);
protected:
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons) override;
private:
void updateViewSizes();
void updateViewColors();
SharedPointer<CTextLabel> label_;
SharedPointer<CTextEdit> valueEdit_;
SharedPointer<SStyledKnob> knob_;
SharedPointer<CTextLabel> ccLabel_;
SharedPointer<CFilledRect> shadingRectangle_;
SharedPointer<CMenuItem> menuEntry_;
CRect nameLabelSize_;
CRect knobSize_;
CRect shadingRectangleSize_;
CRect ccLabelSize_;
CRect valueEditSize_;
CRect rectangleSize_;
float hue_ = 0.35;
class MenuListener : public IControlListener, public NonAtomicReferenceCounted {
public:
explicit MenuListener(SKnobCCBox& box) : box_(box) {}
void valueChanged(CControl*) override
{
box_.setHDMode(!box_.isHD());
}
private:
SKnobCCBox& box_;
};
SharedPointer<MenuListener> menuListener_;
bool hdMode_ { false };
};
///
class SControlsPanel : public CScrollView {
public:
explicit SControlsPanel(const CRect& size);
void setControlUsed(uint32_t index, bool used);
void setControlValue(uint32_t index, float value);
void setControlDefaultValue(uint32_t index, float value);
void setControlLabelText(uint32_t index, UTF8StringPtr text);
void setNameLabelFont(CFontRef font);
void setNameLabelFontColor(CColor color);
void setNameLabelBackColor(CColor color);
void setCCLabelFont(CFontRef font);
void setCCLabelBackColor(CColor color);
void setCCLabelFontColor(CColor color);
void setValueEditBackColor(CColor color);
void setValueEditFontColor(CColor color);
void setShadingRectangleColor(CColor color);
void setKnobActiveTrackColor(CColor color);
void setKnobInactiveTrackColor(CColor color);
void setKnobLineIndicatorColor(CColor color);
void setKnobRotatorColor(CColor color);
void setKnobFont(CFontRef font);
void setKnobFontColor(CColor color);
std::function<void(uint32_t, float)> ValueChangeFunction;
std::function<void(uint32_t)> BeginEditFunction;
std::function<void(uint32_t)> EndEditFunction;
protected:
void recalculateSubViews() override;
private:
void updateLayout();
void syncAllSlotStyles();
void syncSlotStyle(uint32_t index);
static std::string getDefaultLabelText(uint32_t index);
struct ControlSlot;
ControlSlot* getSlot(uint32_t index);
ControlSlot* getOrCreateSlot(uint32_t index);
private:
struct ControlSlot {
bool used = false;
SharedPointer<SKnobCCBox> box;
};
class ControlSlotListener : public IControlListener {
public:
explicit ControlSlotListener(SControlsPanel* panel) : panel_(panel) {}
void valueChanged(CControl* pControl) override;
void controlBeginEdit(CControl* pControl) override;
void controlEndEdit(CControl* pControl) override;
private:
SControlsPanel* panel_ = nullptr;
};
std::vector<std::unique_ptr<ControlSlot>> slots_;
std::unique_ptr<ControlSlotListener> listener_;
SharedPointer<CVSTGUITimer> relayoutTrigger_;
};
///
class SLevelMeter : public CView {
public:
explicit SLevelMeter(const CRect& size);
float getValue() const { return value_; }
void setValue(float value);
float getDangerThreshold() const { return dangerThreshold_; }
void setDangerThreshold(float thres) { dangerThreshold_ = thres; invalid(); }
CColor getFrameColor() const { return frameColor_; }
void setFrameColor(CColor color) { frameColor_ = color; invalid(); }
CColor getBackColor() const { return backColor_; }
void setBackColor(CColor color) { backColor_ = color; invalid(); }
CColor getNormalFillColor() const { return safeFillColor_; }
void setNormalFillColor(CColor color) { safeFillColor_ = color; invalid(); }
CColor getDangerFillColor() const { return dangerFillColor_; }
void setDangerFillColor(CColor color) { dangerFillColor_ = color; invalid(); }
CCoord getRoundRectRadius() const { return radius_; }
void setRoundRectRadius(CCoord radius) { radius_ = radius; invalid(); }
protected:
void draw(CDrawContext* dc) override;
private:
float value_ = 0;
float dangerThreshold_ = 0.5;
float dbMin_ = -40;
float dbMax_ = 0;
CColor frameColor_;
CColor safeFillColor_;
CColor dangerFillColor_;
CColor backColor_;
CCoord radius_ = 5.0;
SharedPointer<CVSTGUITimer> timer_;
bool timerArmed_ = false;
};
///
class SPlaceHolder : public CView {
public:
explicit SPlaceHolder(const CRect& size, const CColor& color = {0xff, 0x00, 0x00, 0xff});
protected:
void draw(CDrawContext* dc) override;
private:
CColor color_;
};

View file

@ -0,0 +1,26 @@
// 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 "GUIDefs.h"
#include "utility/vstgui_before.h"
#include "vstgui/lib/ccolor.h"
#include "utility/vstgui_after.h"
namespace gui {
const CColor kColorTransparent { CColor(0x00, 0x00, 0x00, 0x00) };
const CColor kColorTransparentDark { CColor(0x00, 0x00, 0x00, 0xc0) };
const CColor kColorOrange { CColor(0xfd, 0x98, 0x00, 0xff) };
const CColor kColorControlsScrollerTransparency { CColor(0x00, 0x00, 0x00, 0x80) };
const CColor kColorControlsTransparency { CColor(0x00, 0x00, 0x00, 0x80) };
const CColor kColorInfoTransparency { CColor(0x00, 0x00, 0x00, 0x99) };
const CColor kColorMeterDanger { CColor(0xaa, 0x00, 0x00) };
const CColor kColorMeterNormal { CColor(0x00, 0xaa, 0x11) };
const CColor kColorTooltipBackground { CColor(0xff, 0xff, 0xd2, 0xff) };
}

View file

@ -0,0 +1,28 @@
// 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 "utility/vstgui_before.h"
#include "vstgui/lib/vstguifwd.h"
#include "utility/vstgui_after.h"
using VSTGUI::CColor;
namespace gui {
extern const CColor kColorTransparent;
extern const CColor kColorTransparentDark;
extern const CColor kColorOrange;
extern const CColor kColorControlsScrollerTransparency;
extern const CColor kColorControlsTransparency;
extern const CColor kColorInfoTransparency;
extern const CColor kColorMeterDanger;
extern const CColor kColorMeterNormal;
extern const CColor kColorTooltipBackground;
}

View file

@ -0,0 +1,78 @@
// 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 "GUIHelpers.h"
#define VSTGUI_MORE_THAN_4_10 ((VSTGUI_VERSION_MAJOR > 4) || (VSTGUI_VERSION_MAJOR == 4 && VSTGUI_VERSION_MINOR > 10))
#if VSTGUI_MORE_THAN_4_10
#include "utility/vstgui_before.h"
#include <vstgui/lib/events.h>
#include "utility/vstgui_after.h"
#endif
class SFrameDisabler::KeyAndMouseHook : public CBaseObject,
public IKeyboardHook,
public IMouseObserver {
public:
void setEnabled(bool value) { enabled_ = value; }
protected:
void onMouseEntered(CView*, CFrame*) override {}
void onMouseExited(CView*, CFrame*) override {}
#if VSTGUI_MORE_THAN_4_10
void onKeyboardEvent(KeyboardEvent& event, CFrame* frame) override;
void onMouseEvent(MouseEvent& event, CFrame* frame) override;
#else
int32_t onKeyDown(const VstKeyCode&, CFrame*) override { return enabled_ ? -1 : 1; }
int32_t onKeyUp(const VstKeyCode&, CFrame*) override { return enabled_ ? -1 : 1; }
CMouseEventResult onMouseMoved(CFrame*, const CPoint&, const CButtonState&) override { return enabled_ ? kMouseEventNotHandled : kMouseEventHandled; }
CMouseEventResult onMouseDown(CFrame*, const CPoint&, const CButtonState&) override { return enabled_ ? kMouseEventNotHandled : kMouseEventHandled; }
#endif
private:
bool enabled_ = true;
};
SFrameDisabler::SFrameDisabler(CFrame* frame)
: frame_(frame), hook_(makeOwned<KeyAndMouseHook>())
{
frame->registerKeyboardHook(hook_);
frame->registerMouseObserver(hook_);
delayedEnabler_ = makeOwned<CVSTGUITimer>(
[this](CVSTGUITimer* t) { hook_->setEnabled(true); t->stop(); },
1, false);
}
SFrameDisabler::~SFrameDisabler()
{
frame_->unregisterKeyboardHook(hook_);
frame_->unregisterMouseObserver(hook_);
}
void SFrameDisabler::enable()
{
delayedEnabler_->start();
}
void SFrameDisabler::disable()
{
hook_->setEnabled(false);
delayedEnabler_->stop();
}
#if VSTGUI_MORE_THAN_4_10
void SFrameDisabler::KeyAndMouseHook::onKeyboardEvent(KeyboardEvent& event, CFrame*)
{
if (!enabled_)
event.consumed = true;
}
void SFrameDisabler::KeyAndMouseHook::onMouseEvent(MouseEvent& event, CFrame*)
{
if (!enabled_)
event.consumed = true;
}
#endif

Some files were not shown because too many files have changed in this diff Show more