Merge branch 'develop'

This commit is contained in:
Paul Fd 2021-04-16 17:24:15 +02:00
commit 3bda904fe6
741 changed files with 68872 additions and 31378 deletions

65
.appveyor.yml Normal file

File diff suppressed because one or more lines are too long

35
.gitattributes vendored
View file

@ -1,3 +1,38 @@
.* 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

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

@ -0,0 +1,458 @@
name: build
on:
push:
branches:
- '*'
tags:
- '[0-9]*'
- 'v[0-9]*'
pull_request:
branches:
- '*'
env:
BUILD_TYPE: Release
jobs:
clang_tidy:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
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:
runs-on: ubuntu-18.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@v2
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
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" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DSFIZZ_JACK=ON \
-DSFIZZ_VST=ON \
-DSFIZZ_LV2_UI=ON \
-DSFIZZ_TESTS=ON \
-DSFIZZ_SHARED=OFF \
-DSFIZZ_STATIC_DEPENDENCIES=OFF \
-DSFIZZ_LV2=ON \
-DCMAKE_CXX_STANDARD=17
- name: Build tests
shell: bash
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "$BUILD_TYPE" -j 2 --target sfizz_tests
- name: Test
shell: bash
run: ${{runner.workspace}}/build/tests/sfizz_tests
- 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@v2
with:
name: Linux tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_for_mod:
runs-on: ubuntu-18.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@v2
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" \
-DSFIZZ_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@v2
with:
name: MOD devices tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_for_win32:
runs-on: windows-2019
steps:
- name: Set install name
run: |
echo platform=x86 >> "${Env:GITHUB_ENV}"
echo release_arch=Win32 >> "${Env:GITHUB_ENV}"
echo "install_ref=$(${Env:GITHUB_REF}.split('/')[-1])" >> "${Env:GITHUB_ENV}"
echo "install_name=sfizz-$(${Env:GITHUB_REF}.split('/')[-1])-win32" >> "${Env:GITHUB_ENV}"
- uses: actions/checkout@v2
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"${Env:release_arch}" -DCMAKE_BUILD_TYPE="${Env:BUILD_TYPE}" -DCMAKE_CXX_STANDARD=17 -DSFIZZ_TESTS=ON -DSFIZZ_VST=ON -DSFIZZ_LV2=ON
- name: Build tests
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2 --target sfizz_tests
- name: Test
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: Create installer
working-directory: ${{runner.workspace}}/build
run: iscc /O"." /F"${Env:install_name}" /dARCH="${Env:platform}" innosetup.iss
- uses: actions/upload-artifact@v2
with:
name: Win32 installer
path: ${{runner.workspace}}/build/${{env.install_name}}.exe
build_for_win64:
runs-on: windows-2019
steps:
- name: Set install name
run: |
echo platform=x64 >> "${Env:GITHUB_ENV}"
echo release_arch=x64 >> "${Env:GITHUB_ENV}"
echo "install_ref=$(${Env:GITHUB_REF}.split('/')[-1])" >> "${Env:GITHUB_ENV}"
echo "install_name=sfizz-$(${Env:GITHUB_REF}.split('/')[-1])-win64" >> "${Env:GITHUB_ENV}"
- uses: actions/checkout@v2
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"${Env:release_arch}" -DCMAKE_BUILD_TYPE="${Env:BUILD_TYPE}" -DCMAKE_CXX_STANDARD=17 -DSFIZZ_TESTS=ON -DSFIZZ_VST=ON -DSFIZZ_LV2=ON
- name: Build tests
working-directory: ${{runner.workspace}}/build
run: cmake --build . --config "${Env:BUILD_TYPE}" -j 2 --target sfizz_tests
- name: Test
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
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
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="${Env:platform}" innosetup.iss
- uses: actions/upload-artifact@v2
with:
name: Win64 installer
path: ${{runner.workspace}}/build/${{env.install_name}}.exe
build_for_mingw32:
runs-on: ubuntu-18.04
container:
image: archlinux
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-mingw32" >> "$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 mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Fix MinGW headers
shell: bash
run: |
cp -vf "$GITHUB_WORKSPACE"/scripts/mingw_dwrite_3.h \
/usr/i686-w64-mingw32/include/dwrite_3.h
- name: Fix VST sources
shell: bash
# need to convert some includes to lower case (as of VST 3.7.1)
run: |
find "$GITHUB_WORKSPACE"/plugins/vst/external/VST_SDK -type d -name source -exec \
find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \
xargs -0 sed -i 's/<Windows.h>/<windows.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: |
i686-w64-mingw32-cmake "$GITHUB_WORKSPACE" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_LTO=OFF \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=ON \
-DSFIZZ_STATIC_DEPENDENCIES=ON \
-DCMAKE_CXX_STANDARD=17
- name: Build
shell: bash
working-directory: ${{runner.workspace}}/build
run: i686-w64-mingw32-cmake --build . --config "$BUILD_TYPE" -j 2
- name: Install
working-directory: ${{runner.workspace}}/build
shell: bash
run: |
DESTDIR="$(pwd)/$install_name" i686-w64-mingw32-cmake --build . --config "$BUILD_TYPE" --target install
tar czvf "$install_name".tar.gz "$install_name"
- uses: actions/upload-artifact@v2
with:
name: Win32 MinGW tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_for_mingw64:
runs-on: ubuntu-18.04
container:
image: archlinux
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
echo "install_name=sfizz-${GITHUB_REF##*/}-mingw64" >> "$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 mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Fix MinGW headers
shell: bash
run: |
cp -vf "$GITHUB_WORKSPACE"/scripts/mingw_dwrite_3.h \
/usr/x86_64-w64-mingw32/include/dwrite_3.h
- name: Fix VST sources
shell: bash
# need to convert some includes to lower case (as of VST 3.7.1)
run: |
find "$GITHUB_WORKSPACE"/plugins/vst/external/VST_SDK -type d -name source -exec \
find {} -type f -name '*.[hc]' -o -name '*.[hc]pp' -print0 \; | \
xargs -0 sed -i 's/<Windows.h>/<windows.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: |
x86_64-w64-mingw32-cmake "$GITHUB_WORKSPACE" \
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
-DENABLE_LTO=OFF \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=ON \
-DSFIZZ_STATIC_DEPENDENCIES=ON \
-DCMAKE_CXX_STANDARD=17
- name: Build
shell: bash
working-directory: ${{runner.workspace}}/build
run: x86_64-w64-mingw32-cmake --build . --config "$BUILD_TYPE" -j 2
- name: Install
working-directory: ${{runner.workspace}}/build
shell: bash
run: |
DESTDIR="$(pwd)/$install_name" x86_64-w64-mingw32-cmake --build . --config "$BUILD_TYPE" --target install
tar czvf "$install_name".tar.gz "$install_name"
- uses: actions/upload-artifact@v2
with:
name: Win64 MinGW tarball
path: ${{runner.workspace}}/build/${{env.install_name}}.tar.gz
build_with_makefile:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- name: Build with GNU make
shell: bash
run: make -C "$GITHUB_WORKSPACE" -f generic.mk -j2
- name: Compile a simple program
shell: bash
run: |
cat <<EOF > "$GITHUB_WORKSPACE"/simple.cpp
#include <sfizz.hpp>
int main() {
sfz::Sfizz synth;
synth.loadSfzString("", "");
return 0;
}
EOF
cat <<EOF > "$GITHUB_WORKSPACE"/simple.mk
all: simple
include generic.mk
simple.o: simple.cpp
\$(CXX) \$(CXXFLAGS) \$(SFIZZ_CXX_FLAGS) -c -o \$@ \$<
simple: simple.o \$(SFIZZ_TARGET)
\$(CXX) -o \$@ \$^ \$(SFIZZ_LINK_FLAGS) \$(LDFLAGS)
EOF
make -C "$GITHUB_WORKSPACE" -f simple.mk
archive_source_code:
runs-on: ubuntu-18.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@v2
with:
submodules: recursive
- name: Set up dependencies
run: |
sudo apt-get update && \
sudo apt-get install \
python-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@v2
with:
name: Source code tarball
path: ${{runner.workspace}}/${{env.install_name}}.tar.gz
deploy:
runs-on: ubuntu-18.04
if: startsWith(github.ref, 'refs/tags/')
needs:
- build_for_linux
- build_for_mod
- build_for_mingw32
- build_for_mingw64
- archive_source_code
steps:
- name: Set install name
run: |
echo "install_ref=${GITHUB_REF##*/}" >> "$GITHUB_ENV"
- uses: actions/download-artifact@v2
with:
name: Linux tarball
- uses: actions/download-artifact@v2
with:
name: MOD devices tarball
- uses: actions/download-artifact@v2
with:
name: Win32 MinGW tarball
- uses: actions/download-artifact@v2
with:
name: Win64 MinGW tarball
- uses: actions/download-artifact@v2
with:
name: Source code tarball
- name: Display file information
shell: bash
run: ls -lR
## Note: not using `actions/create-release@v1`
## because it cannot update an existing release
## see https://github.com/actions/create-release/issues/29
- 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}}.*

21
.gitignore vendored
View file

@ -1,4 +1,4 @@
build*
build*/*
docs
.vscode
perf.data
@ -11,7 +11,7 @@ CMakeFiles/
cmake_install.cmake
compile_commands.json
*.a
*.txt.user
*.user*
*.autosave
/Doxyfile
.DS_Store
@ -19,21 +19,12 @@ compile_commands.json
clients/sfizz_jack
clients/sfzprint
/vst/download/
/plugins/vst/download/
/plugins/vst/external/vstsdk2.4/
/plugins/vst/external/CoreAudioUtilityClasses/
/editor/external/fluentui-system-icons/
/plugins/editor/external/fluentui-system-icons/
# gh-pages unstaged files:
_api/
_site/
.bundle/
api/
assets/
node_modules/
.jekyll-cache
.jekyll-metadata
.sass-cache
*.lock
*.sublime-*
*.code-*
.kak.tags.namecache

35
.gitmodules vendored
View file

@ -4,18 +4,41 @@
branch = lts_2020_02_25
shallow = true
[submodule "vst/external/VST_SDK/VST3_SDK/base"]
path = vst/external/VST_SDK/VST3_SDK/base
path = plugins/vst/external/VST_SDK/VST3_SDK/base
url = https://github.com/steinbergmedia/vst3_base.git
shallow = true
[submodule "vst/external/VST_SDK/VST3_SDK/pluginterfaces"]
path = vst/external/VST_SDK/VST3_SDK/pluginterfaces
url = https://github.com/sfztools/vst3_pluginterfaces.git
path = plugins/vst/external/VST_SDK/VST3_SDK/pluginterfaces
url = https://github.com/steinbergmedia/vst3_pluginterfaces.git
shallow = true
[submodule "vst/external/VST_SDK/VST3_SDK/public.sdk"]
path = vst/external/VST_SDK/VST3_SDK/public.sdk
url = https://github.com/sfztools/vst3_public_sdk.git
path = plugins/vst/external/VST_SDK/VST3_SDK/public.sdk
url = https://github.com/steinbergmedia/vst3_public_sdk.git
shallow = true
[submodule "vst/external/VST_SDK/VST3_SDK/vstgui4"]
path = editor/external/vstgui4
path = plugins/editor/external/vstgui4
url = https://github.com/sfztools/vstgui.git
shallow = true
[submodule "external/st_audiofile/thirdparty/dr_libs"]
path = external/st_audiofile/thirdparty/dr_libs
url = https://github.com/mackron/dr_libs.git
shallow = true
[submodule "external/st_audiofile/thirdparty/stb_vorbis"]
path = external/st_audiofile/thirdparty/stb_vorbis
url = https://github.com/sfztools/stb_vorbis.git
shallow = true
[submodule "external/st_audiofile/thirdparty/libaiff"]
path = external/st_audiofile/thirdparty/libaiff
url = https://github.com/sfztools/libaiff.git
shallow = true
[submodule "vst/external/sfzt_auwrapper"]
path = plugins/vst/external/sfzt_auwrapper
url = https://github.com/sfztools/sfzt_auwrapper.git
shallow = true
[submodule "external/filesystem"]
path = external/filesystem
url = https://github.com/gulrak/filesystem.git
shallow = true
[submodule "external/simde"]
path = external/simde
url = https://github.com/simd-everywhere/simde.git

View file

@ -8,29 +8,7 @@ cache:
jobs:
include:
- name: "clang-tidy checks"
stage: "Tests"
addons:
apt:
packages:
- clang-tidy
- wget
- unzip
- libsndfile-dev
install: .travis/download_vst_sdk.sh
script: scripts/run_clang_tidy.sh
- name: "Linux amd64 tests"
arch: amd64
addons:
apt:
packages:
- libjack-jackd2-dev
- libsndfile1-dev
install: .travis/download_cmake.sh
script: .travis/script_test.sh
- name: "Linux arm64 tests"
- name: "Linux arm64 test and build"
arch: arm64-graviton2
group: edge
virt: lxd
@ -39,82 +17,17 @@ jobs:
packages:
- libjack-jackd2-dev
- libsndfile1-dev
- libcairo2-dev
- libfontconfig1-dev
- libx11-xcb-dev
- libxcb-util-dev
- libxcb-cursor-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libxcb-keysyms1-dev
install: .travis/download_cmake.sh
script: .travis/script_test.sh
- name: "macOS"
stage: "Build"
os: osx
osx_image: xcode11.3
addons:
homebrew:
packages:
- cmake
- libsndfile
- jack
- dylibbundler
env:
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
script: .travis/script_osx.sh
after_success: .travis/prepare_tarball.sh
- name: "MOD devices arm"
env:
- CONTAINER=jpcima/mod-plugin-builder
- CROSS_COMPILE=moddevices-arm
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-moddevices"
before_install: .travis/before_install_moddevices.sh
install: .travis/install_moddevices.sh
script: .travis/script_moddevices.sh
after_success: .travis/prepare_tarball.sh
- name: "Windows mingw32"
env:
- CROSS_COMPILE=mingw32
- CONTAINER=archlinux
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-mingw32"
before_install: .travis/before_install_mingw.sh
install: .travis/install_mingw.sh
script: .travis/script_mingw.sh
after_success: .travis/prepare_tarball.sh
- name: "Windows mingw64"
env:
- CROSS_COMPILE=mingw64
- CONTAINER=archlinux
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-mingw64"
before_install: .travis/before_install_mingw.sh
install: .travis/install_mingw.sh
script: .travis/script_mingw.sh
after_success: .travis/prepare_tarball.sh
- name: "Linux amd64 library"
arch: amd64
env:
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
addons:
apt:
packages:
- libjack-jackd2-dev
- libsndfile1-dev
install: .travis/download_cmake.sh
script: .travis/script_library.sh
after_success: .travis/prepare_tarball.sh
- name: "Linux arm64 library"
arch: arm64-graviton2
group: edge
virt: lxd
env:
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
addons:
apt:
packages:
- libjack-jackd2-dev
- libsndfile1-dev
install: .travis/download_cmake.sh
script: .travis/script_library.sh
after_success: .travis/prepare_tarball.sh
script: .travis/script_test_and_build.sh
- name: "Linux arm64 static plugins"
arch: arm64-graviton2
@ -135,43 +48,6 @@ jobs:
script: .travis/script_plugins.sh
after_success: .travis/prepare_tarball.sh
- name: "Linux amd64 static plugins"
env:
- INSTALL_DIR="sfizz-plugins-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
- ENABLE_VST_PLUGIN=ON
- ENABLE_LV2_UI=ON
addons:
apt:
packages:
- libjack-jackd2-dev
- libsndfile1-dev
- libcairo2-dev
- libfontconfig1-dev
- libx11-xcb-dev
- libxcb-util-dev
- libxcb-cursor-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libxcb-keysyms1-dev
install:
- .travis/download_cmake.sh
- .travis/download_static_libs.sh
script: .travis/script_plugins.sh
after_success: .travis/prepare_tarball.sh
- stage: "Deploy"
name: "Source packaging"
if: (tag =~ /^v?[0-9]/) AND (type = push)
env:
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-src"
addons:
apt:
packages:
- python-pip
install: sudo pip install git-archive-all
script: git-archive-all --prefix="sfizz-${TRAVIS_BRANCH}/" -9 "${INSTALL_DIR}.tar.gz"
- name: "Discord Webhook"
install: skip
script: bash ${TRAVIS_BUILD_DIR}/.travis/discord_webhook.sh success

View file

@ -1,17 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh
buildenv bash -c "echo Hello from container" # ensure to start the container
docker cp "$container":/etc/pacman.conf pacman.conf
cat >>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
docker cp pacman.conf "$container":/etc/pacman.conf
rm -f pacman.conf

View file

@ -1,6 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh
buildenv bash -c "echo Hello from container" # ensure to start the container

View file

@ -1,25 +0,0 @@
#!/bin/bash
if [ -z "$CONTAINER" ]; then
echo "The variable CONTAINER is not set."
exit 1
fi
buildenv() {
setup_container "$CONTAINER"
docker exec -w "$(pwd)" -u "$(id -u)" -i -t "$container" "$@"
}
buildenv_as_root() {
setup_container "$CONTAINER"
docker exec -w "$(pwd)" -u 0 -i -t "$container" "$@"
}
setup_container() {
if [ -f ${TRAVIS_BUILD_DIR}/docker-container-id ]; then
container=$(cat ${TRAVIS_BUILD_DIR}/docker-container-id)
else
container=$(docker run -d -i -t -v /home/travis:/home/travis "$1" /bin/bash)
echo "$container" > ${TRAVIS_BUILD_DIR}/docker-container-id
fi
}

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -ex
vst_download_prefix="vst/download"
vst_sdk_archive="vst-sdk_3.6.14_build-24_2019-11-29.zip"
mkdir -p ${vst_download_prefix}
if ! [[ -f "${vst_download_prefix}/${vst_sdk_archive}" ]]; then
wget -P ${vst_download_prefix} "https://download.steinberg.net/sdk_downloads/${vst_sdk_archive}"
fi
mkdir -p vst/external
unzip -ouq "${vst_download_prefix}/${vst_sdk_archive}" -d "vst/external"

View file

@ -1,8 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh
buildenv_as_root pacman -Sqyu --noconfirm
buildenv_as_root pacman -Sq --noconfirm base-devel wget mingw-w64-cmake mingw-w64-gcc mingw-w64-pkg-config mingw-w64-libsndfile
buildenv i686-w64-mingw32-gcc -v && buildenv i686-w64-mingw32-g++ -v && buildenv i686-w64-mingw32-cmake --version

View file

@ -1,4 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh

View file

@ -1,7 +0,0 @@
#!/bin/bash
set -ex
buildenv() {
"$@"
}

View file

@ -2,18 +2,12 @@
set -ex
if ! [ -z "$CONTAINER" ]; then
. .travis/docker_container.sh
else
. .travis/no_container.sh
fi
cd build
buildenv make DESTDIR=${PWD}/${INSTALL_DIR} install
make DESTDIR=${PWD}/${INSTALL_DIR} install
tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR}
# Only release a tarball if there is a tag
if [[ ${TRAVIS_TAG} != "" ]]; then
if [[ ${TRAVIS_TAG} != "" ]] && [[ ${DEPLOY_BUILD} ]]; then
mv "${INSTALL_DIR}.tar.gz" ${TRAVIS_BUILD_DIR}
fi

View file

@ -1,25 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh
mkdir -p build/${INSTALL_DIR} && cd build
if [[ ${CROSS_COMPILE} == "mingw32" ]]; then
buildenv i686-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=Release \
-DENABLE_LTO=OFF \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=ON \
-DSFIZZ_STATIC_DEPENDENCIES=ON \
-DCMAKE_CXX_STANDARD=17 \
..
buildenv make -j2
elif [[ ${CROSS_COMPILE} == "mingw64" ]]; then
buildenv x86_64-w64-mingw32-cmake -DCMAKE_BUILD_TYPE=Release \
-DENABLE_LTO=OFF \
-DSFIZZ_JACK=OFF \
-DSFIZZ_VST=ON \
-DSFIZZ_STATIC_DEPENDENCIES=ON \
-DCMAKE_CXX_STANDARD=17 \
..
buildenv make -j2
fi

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -ex
. .travis/docker_container.sh
mkdir -p build/${INSTALL_DIR} && cd build
buildenv mod-plugin-builder /usr/local/bin/cmake \
-DSFIZZ_SYSTEM_PROCESSOR=armv7-a \
-DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_LV2_UI=OFF ..
buildenv mod-plugin-builder make -j2

View file

@ -1,16 +0,0 @@
#!/bin/bash
set -ex
mkdir -p build/${INSTALL_DIR} && cd build
cmake -DCMAKE_BUILD_TYPE=Release \
-DSFIZZ_VST=ON \
-DSFIZZ_AU=ON \
-DSFIZZ_TESTS=OFF \
-DCMAKE_CXX_STANDARD=14 \
-DLV2PLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/LV2 \
-DVSTPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/VST3 \
-DAUPLUGIN_INSTALL_DIR=/Library/Audio/Plug-Ins/Components \
..
make -j$(sysctl -n hw.ncpu)
# Xcode not currently supported, see https://gitlab.kitware.com/cmake/cmake/issues/18088
# xcodebuild -project sfizz.xcodeproj -alltargets -configuration Debug build

View file

@ -3,12 +3,19 @@ set -ex
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release \
-DSFIZZ_JACK=OFF \
-DSFIZZ_JACK=ON \
-DSFIZZ_VST=ON \
-DSFIZZ_LV2_UI=ON \
-DSFIZZ_TESTS=ON \
-DSFIZZ_SHARED=OFF \
-DSFIZZ_STATIC_DEPENDENCIES=OFF \
-DSFIZZ_LV2=OFF \
-DSFIZZ_LV2=ON \
-DCMAKE_CXX_STANDARD=17 \
..
make -j2 sfizz_tests
tests/sfizz_tests
make -j2 sfizz_jack
make -j2 sfizz_render
make -j2 sfizz_lv2
make -j2 sfizz_lv2_ui
make -j2 sfizz_vst3

View file

@ -10,3 +10,4 @@ Contributors to `sfizz`, in chronologic order:
- Tobiasz "unfa" Karoń (2020)
- Kinwie (2020)
- Atsushi Eno (2020)
- Dominique Würtz (2021)

View file

@ -8,7 +8,7 @@ else()
endif()
endif()
project (sfizz VERSION 0.5.1 LANGUAGES CXX C)
project (sfizz VERSION 1.0.0 LANGUAGES CXX C)
set (PROJECT_DESCRIPTION "A library to load SFZ description files and use them to render music.")
# External configuration CMake scripts
@ -16,24 +16,36 @@ set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include (BuildType)
# Build Options
include (OptionEx)
set (BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests [default: OFF]")
option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON)
option (SFIZZ_JACK "Enable JACK stand-alone build [default: ON]" ON)
option (SFIZZ_RENDER "Enable renderer of SMF files [default: ON]" ON)
option (SFIZZ_LV2 "Enable LV2 plug-in build [default: ON]" ON)
option (SFIZZ_LV2_UI "Enable LV2 plug-in user interface [default: ON]" ON)
option (SFIZZ_VST "Enable VST plug-in build [default: OFF]" OFF)
option (SFIZZ_AU "Enable AU plug-in build [default: OFF]" OFF)
option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF)
option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF)
option (SFIZZ_DEVTOOLS "Enable developer tools build [default: OFF]" OFF)
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
option (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg [default: OFF]" OFF)
option (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically [default: OFF]" OFF)
option (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds [default: OFF]" OFF)
option_ex (ENABLE_LTO "Enable Link Time Optimization" ON)
option_ex (SFIZZ_JACK "Enable JACK stand-alone build" CMAKE_SYSTEM_NAME STREQUAL "Linux")
option_ex (SFIZZ_RENDER "Enable renderer of SMF files" ON)
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_VST "Enable VST plug-in build" ON)
option_ex (SFIZZ_AU "Enable AU plug-in build" APPLE)
option_ex (SFIZZ_VST2 "Enable VST2 plug-in build (unsupported)" OFF)
option_ex (SFIZZ_BENCHMARKS "Enable benchmarks build" OFF)
option_ex (SFIZZ_TESTS "Enable tests build" OFF)
option_ex (SFIZZ_DEMOS "Enable feature demos build" OFF)
option_ex (SFIZZ_DEVTOOLS "Enable developer tools build" OFF)
option_ex (SFIZZ_SHARED "Enable shared library build" ON)
option_ex (SFIZZ_USE_SNDFILE "Enable use of the sndfile library" OFF)
option_ex (SFIZZ_USE_VCPKG "Assume that sfizz is build using vcpkg" OFF)
option_ex (SFIZZ_USE_SYSTEM_ABSEIL "Use Abseil libraries preinstalled on system" OFF)
option_ex (SFIZZ_USE_SYSTEM_SIMDE "Use SIMDe libraries preinstalled on system" OFF)
option_ex (SFIZZ_STATIC_DEPENDENCIES "Link dependencies statically" OFF)
option_ex (SFIZZ_RELEASE_ASSERTS "Forced assertions in release builds" OFF)
# The fixed number of controller parameters
set(SFIZZ_NUM_CCS 512)
include (SfizzConfig)
include (SfizzDeps)
include (SfizzFaust)
# Don't use IPO in non Release builds
include (CheckIPO)
@ -41,39 +53,26 @@ include (CheckIPO)
# Dylib bunder for macOS
include (BundleDylibs)
# Add Abseil
add_subdirectory (external/abseil-cpp EXCLUDE_FROM_ALL)
# Add the static library targets and sources
add_subdirectory (src)
# Optional targets
add_subdirectory (clients)
if ((SFIZZ_LV2 AND SFIZZ_LV2_UI) OR SFIZZ_VST)
add_subdirectory (editor)
endif()
if (SFIZZ_LV2)
add_subdirectory (lv2)
endif()
if (SFIZZ_VST)
add_subdirectory (vst)
else()
if (SFIZZ_AU)
message(WARNING "Audio Unit requires VST to be enabled")
endif()
endif()
add_subdirectory (plugins)
if (SFIZZ_BENCHMARKS)
add_subdirectory (benchmarks)
endif()
if (SFIZZ_TESTS)
enable_testing ()
add_subdirectory (tests)
endif()
if (SFIZZ_DEMOS)
add_subdirectory (demos)
endif()
if (SFIZZ_DEVTOOLS)
add_subdirectory (devtools)
endif()

View file

@ -37,27 +37,51 @@ We invite you to check out the [GOVERNANCE](GOVERNANCE.md) file to see how the o
## Dependencies and licenses
The sfizz library makes primary use of:
- [libsndfile], licensed under the GNU Lesser General Public License v2.1
- [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://github.com/abseil/abseil-cpp
[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
[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
[libsndfile]: https://github.com/erikd/libsndfile/
[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

View file

@ -1,53 +0,0 @@
version: build-{build}
image: Visual Studio 2019
configuration: Release
platform:
- Win32
- x64
cache:
- c:\tools\vcpkg\installed\ -> appveyor.yml
install:
- cmd: choco install -y innosetup
- cmd: set PATH=C:\Program Files (x86)\Inno Setup 6;%PATH%
- cmd: if %platform%==Win32 set VCPKG_TRIPLET=x86-windows-static
- cmd: if %platform%==x64 set VCPKG_TRIPLET=x64-windows-static
# - cmd: cd c:\tools\vcpkg\
# - cmd: git pull
# - cmd: .\bootstrap-vcpkg.bat
# - cmd: cd %APPVEYOR_BUILD_FOLDER%
- cmd: vcpkg install libsndfile:%VCPKG_TRIPLET%
before_build:
- cmd: git submodule update --init --recursive
- cmd: mkdir CMakeBuild
- cmd: cd CMakeBuild
- cmd: cmake .. -G"Visual Studio 16 2019" -A"%platform%" -DSFIZZ_JACK=OFF -DSFIZZ_BENCHMARKS=OFF -DSFIZZ_TESTS=OFF -DSFIZZ_LV2=ON -DSFIZZ_VST=ON -DCMAKE_BUILD_TYPE=Release -DVCPKG_TARGET_TRIPLET=%VCPKG_TRIPLET% -DCMAKE_TOOLCHAIN_FILE=C:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake
build_script:
- cmd: cmake --build . --config Release -j
after_build:
- cmd: if %platform%==Win32 set RELEASE_ARCH=x86
- cmd: if %platform%==x64 set RELEASE_ARCH=x64
- cmd: 7z a sfizz-lv2-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.lv2
- cmd: 7z a sfizz-vst3-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip sfizz.vst3
- cmd: 7z a sfizz-lib-%APPVEYOR_REPO_TAG_NAME%-%RELEASE_ARCH%-msvc.zip src/Release/sfizz*
- cmd: iscc.exe /dARCH=%RELEASE_ARCH% innosetup.iss
artifacts:
- name: Packages
path: 'CMakeBuild/sfizz-*-msvc*'
# Deploy to GitHub Releases
# See https://www.appveyor.com/docs/deployment/github/
deploy:
- provider: GitHub
auth_token:
secure: xOugGAynvnZdc0DXaL3rlgMf4CICFLkdO8JxoRfLQMKJhkj/kZ4d8h7NCFneDzXG
artifact: Packages
draft: false
prerelease: false
force_update: true
on:
appveyor_repo_tag: true

View file

@ -35,24 +35,11 @@ public:
}
sfz::MidiState midiState;
sfz::Region region{0, midiState};
sfz::ADSREnvelope<float> envelope;
sfz::Region region{0};
sfz::ADSREnvelope envelope;
std::vector<float> output;
};
BENCHMARK_DEFINE_F(EnvelopeFixture, Scalar)(benchmark::State& state)
{
for (auto _ : state) {
envelope.reset(region.amplitudeEG, region, midiState, 0, 0, sampleRate);
envelope.startRelease(releaseTime);
for (int offset = 0; offset < envelopeSize; offset += static_cast<int>(state.range(0)))
for (auto& out: output)
out = envelope.getNextValue();
benchmark::DoNotOptimize(output);
}
state.counters["Blocks"] = benchmark::Counter(envelopeSize / static_cast<double>(state.range(0)), benchmark::Counter::kIsIterationInvariantRate);
}
BENCHMARK_DEFINE_F(EnvelopeFixture, Block)(benchmark::State& state)
{
for (auto _ : state) {
@ -66,6 +53,5 @@ BENCHMARK_DEFINE_F(EnvelopeFixture, Block)(benchmark::State& state)
state.counters["Blocks"] = benchmark::Counter(envelopeSize / static_cast<double>(state.range(0)), benchmark::Counter::kIsIterationInvariantRate);
}
BENCHMARK_REGISTER_F(EnvelopeFixture, Scalar)->RangeMultiplier(2)->Range((2 << 6), (2 << 11));
BENCHMARK_REGISTER_F(EnvelopeFixture, Block)->RangeMultiplier(2)->Range((2 << 6), (2 << 11));
BENCHMARK_MAIN();

View file

@ -5,13 +5,13 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "SIMDHelpers.h"
#include "Macros.h"
#include "utility/Macros.h"
#include <benchmark/benchmark.h>
#include <random>
#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
#include <cmath>
class AddArray : public benchmark::Fixture {
public:

View file

@ -5,13 +5,13 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "SIMDHelpers.h"
#include "Macros.h"
#include "utility/Macros.h"
#include <benchmark/benchmark.h>
#include <random>
#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
#include <cmath>
class WithinArray : public benchmark::Fixture {
public:

View file

@ -94,6 +94,7 @@ public:
static TemporaryFile fileWav;
static TemporaryFile fileFlac;
static TemporaryFile fileAiff;
static TemporaryFile fileOgg;
std::vector<float> workBuffer;
@ -101,6 +102,7 @@ public:
TemporaryFile AudioReaderFixture::fileWav = createAudioFile(SF_FORMAT_WAV|SF_FORMAT_PCM_16);
TemporaryFile AudioReaderFixture::fileFlac = createAudioFile(SF_FORMAT_FLAC|SF_FORMAT_PCM_16);
TemporaryFile AudioReaderFixture::fileAiff = createAudioFile(SF_FORMAT_AIFF|SF_FORMAT_PCM_16);
TemporaryFile AudioReaderFixture::fileOgg = createAudioFile(SF_FORMAT_OGG|SF_FORMAT_VORBIS);
TemporaryFile AudioReaderFixture::createAudioFile(int format)
@ -146,16 +148,12 @@ static void doReaderBenchmark(const fs::path& path, std::vector<float> &buffer,
static void doEntireRead(const fs::path& path)
{
#if !defined(_WIN32)
SndfileHandle handle(path.c_str());
#else
SndfileHandle handle(path.wstring().c_str());
#endif
if (handle.error())
throw std::runtime_error("cannot open sound file for reading");
sfz::AudioReaderPtr reader = sfz::createAudioReader(path, false);
if (!reader)
return;
std::vector<float> buffer(static_cast<size_t>(2 * handle.frames()));
handle.read(buffer.data(), buffer.size());
std::vector<float> buffer(static_cast<size_t>(2 * reader->frames()));
reader->readNextBlock(buffer.data(), buffer.size());
}
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireWav)(benchmark::State& state)
@ -200,6 +198,27 @@ BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseFlac)(benchmark::State& state)
}
}
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireAiff)(benchmark::State& state)
{
for (auto _ : state) {
doEntireRead(fileAiff.path());
}
}
BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardAiff)(benchmark::State& state)
{
for (auto _ : state) {
doReaderBenchmark(fileAiff.path(), workBuffer, sfz::AudioReaderType::Forward);
}
}
BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseAiff)(benchmark::State& state)
{
for (auto _ : state) {
doReaderBenchmark(fileAiff.path(), workBuffer, sfz::AudioReaderType::Reverse);
}
}
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireOgg)(benchmark::State& state)
{
for (auto _ : state) {
@ -214,12 +233,14 @@ BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardOgg)(benchmark::State& state)
}
}
//BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state)
//{
// for (auto _ : state) {
// doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse);
// }
//}
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state)
{
for (auto _ : state) {
doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse);
}
}
#endif
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseWav)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
@ -227,7 +248,12 @@ BENCHMARK_REGISTER_F(AudioReaderFixture, EntireWav)->Range(1, 1);
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseFlac)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, EntireFlac)->Range(1, 1);
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardAiff)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseAiff)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
BENCHMARK_REGISTER_F(AudioReaderFixture, EntireAiff)->Range(1, 1);
BENCHMARK_REGISTER_F(AudioReaderFixture, ForwardOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
//BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
#if !defined(ST_AUDIO_FILE_USE_SNDFILE)
BENCHMARK_REGISTER_F(AudioReaderFixture, ReverseOgg)->RangeMultiplier(2)->Range((1 << 6), (1 << 10));
#endif
BENCHMARK_REGISTER_F(AudioReaderFixture, EntireOgg)->Range(1, 1);
BENCHMARK_MAIN();

View file

@ -5,13 +5,13 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "SIMDHelpers.h"
#include "Macros.h"
#include "utility/Macros.h"
#include <benchmark/benchmark.h>
#include <random>
#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
#include <cmath>
class ClampArray : public benchmark::Fixture {
public:

View file

@ -13,6 +13,11 @@
class Interpolators : public benchmark::Fixture {
public:
Interpolators()
{
sfz::initializeInterpolators();
}
void SetUp(const ::benchmark::State& state)
{
std::random_device rd { };
@ -55,33 +60,27 @@ static void doInterpolation(absl::Span<const float> input, absl::Span<float> out
}
}
BENCHMARK_DEFINE_F(Interpolators, Linear)(benchmark::State& state)
{
ScopedFTZ ftz;
#define ADD_INTERPOLATOR_BENCHMARK(Type) \
BENCHMARK_DEFINE_F(Interpolators, Type)(benchmark::State& state) \
{ \
ScopedFTZ ftz; \
for (auto _ : state) { \
absl::Span<float> span = absl::MakeSpan(output); \
doInterpolation<sfz::kInterpolator##Type>(input, span); \
} \
} \
BENCHMARK_REGISTER_F(Interpolators, Type) \
->RangeMultiplier(4)->Range(1 << 4, 1 << 12);
for (auto _ : state) {
doInterpolation<sfz::kInterpolatorLinear>(input, absl::MakeSpan(output));
}
}
BENCHMARK_DEFINE_F(Interpolators, Hermite3)(benchmark::State& state)
{
ScopedFTZ ftz;
for (auto _ : state) {
doInterpolation<sfz::kInterpolatorHermite3>(input, absl::MakeSpan(output));
}
}
BENCHMARK_DEFINE_F(Interpolators, Bspline3)(benchmark::State& state)
{
ScopedFTZ ftz;
for (auto _ : state) {
doInterpolation<sfz::kInterpolatorBspline3>(input, absl::MakeSpan(output));
}
}
BENCHMARK_REGISTER_F(Interpolators, Linear)->RangeMultiplier(4)->Range(1 << 4, 1 << 12);
BENCHMARK_REGISTER_F(Interpolators, Hermite3)->RangeMultiplier(4)->Range(1 << 4, 1 << 12);
BENCHMARK_REGISTER_F(Interpolators, Bspline3)->RangeMultiplier(4)->Range(1 << 4, 1 << 12);
ADD_INTERPOLATOR_BENCHMARK(Nearest)
ADD_INTERPOLATOR_BENCHMARK(Linear)
ADD_INTERPOLATOR_BENCHMARK(Hermite3)
ADD_INTERPOLATOR_BENCHMARK(Bspline3)
ADD_INTERPOLATOR_BENCHMARK(Sinc8)
ADD_INTERPOLATOR_BENCHMARK(Sinc12)
ADD_INTERPOLATOR_BENCHMARK(Sinc16)
ADD_INTERPOLATOR_BENCHMARK(Sinc24)
ADD_INTERPOLATOR_BENCHMARK(Sinc36)
ADD_INTERPOLATOR_BENCHMARK(Sinc48)
ADD_INTERPOLATOR_BENCHMARK(Sinc60)
ADD_INTERPOLATOR_BENCHMARK(Sinc72)

View file

@ -1,191 +0,0 @@
// 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 "Buffer.h"
#include "SIMDHelpers.h"
#include <benchmark/benchmark.h>
#include <sndfile.hh>
#include "ghc/filesystem.hpp"
#include "Oversampler.h"
#include "AudioBuffer.h"
#include "absl/memory/memory.h"
#include <iostream>
constexpr std::array<double, 12> coeffsStage2x {
0.036681502163648017,
0.13654762463195771,
0.27463175937945411,
0.42313861743656667,
0.56109869787919475,
0.67754004997416162,
0.76974183386322659,
0.83988962484963803,
0.89226081800387891,
0.9315419599631839,
0.96209454837808395,
0.98781637073289708
};
constexpr std::array<double, 4> coeffsStage4x {
0.042448989488488006,
0.17072114107630679,
0.39329183835224008,
0.74569514831986694
};
constexpr std::array<double, 3> coeffsStage8x {
0.055748680811302048,
0.24305119574153092,
0.6466991311926823
};
#if defined(__x86_64__) || defined(__i386__)
#include "hiir/Upsampler2xSse.h"
using Upsampler2x = hiir::Upsampler2xSse<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xSse<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xSse<coeffsStage8x.size()>;
#elif defined(__arm__) || defined(__aarch64__)
#include "hiir/Upsampler2xNeon.h"
using Upsampler2x = hiir::Upsampler2xNeon<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xNeon<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xNeon<coeffsStage8x.size()>;
#else
#include "hiir/Upsampler2xFpu.h"
using Upsampler2x = hiir::Upsampler2xFpu<coeffsStage2x.size()>;
using Upsampler4x = hiir::Upsampler2xFpu<coeffsStage4x.size()>;
using Upsampler8x = hiir::Upsampler2xFpu<coeffsStage8x.size()>;
#endif
class FileFixture : public benchmark::Fixture {
public:
void SetUp(const ::benchmark::State& /* state */) {
rootPath = getPath() / "sample1.flac";
if (!ghc::filesystem::exists(rootPath)) {
#ifndef NDEBUG
std::cerr << "Can't find path" << '\n';
#endif
std::terminate();
}
sndfile = SndfileHandle(rootPath.c_str());
numFrames = static_cast<size_t>(sndfile.frames());
output = absl::make_unique<sfz::AudioBuffer<float>>(sndfile.channels(), numFrames * 4);
}
void TearDown(const ::benchmark::State& /* state */) {
}
ghc::filesystem::path getPath()
{
#ifdef __linux__
char buf[PATH_MAX + 1];
if (readlink("/proc/self/exe", buf, sizeof(buf) - 1) == -1)
return {};
std::string str { buf };
return str.substr(0, str.rfind('/'));
#elif _WIN32
return ghc::filesystem::current_path();
#endif
}
std::unique_ptr<sfz::AudioBuffer<float>> output;
SndfileHandle sndfile;
ghc::filesystem::path rootPath;
size_t numFrames { 0 };
};
BENCHMARK_DEFINE_F(FileFixture, NoResampling)(benchmark::State& state) {
for (auto _ : state)
{
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
sndfile.readf(buffer.data(), sndfile.frames());
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
}
}
BENCHMARK_DEFINE_F(FileFixture, ResampleAtOnce)(benchmark::State& state) {
for (auto _ : state)
{
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
sfz::Buffer<float> temp { numFrames * 4 };
Upsampler2x upsampler2x;
Upsampler4x upsampler4x;
upsampler2x.set_coefs(coeffsStage2x.data());
upsampler4x.set_coefs(coeffsStage4x.data());
sndfile.readf(buffer.data(), numFrames);
sfz::readInterleaved(buffer, output->getSpan(0), output->getSpan(1));
upsampler2x.process_block(temp.data(), output->channelReader(0), static_cast<long>(numFrames));
upsampler4x.process_block(output->channelWriter(0), temp.data(), static_cast<long>(numFrames * 2));
upsampler2x.clear_buffers();
upsampler4x.clear_buffers();
upsampler2x.process_block(temp.data(), output->channelReader(1), static_cast<long>(numFrames));
upsampler4x.process_block(output->channelWriter(1), temp.data(), static_cast<long>(numFrames * 2));
}
}
BENCHMARK_DEFINE_F(FileFixture, ResampleInChunks)(benchmark::State& state) {
for (auto _ : state)
{
auto chunkSize = static_cast<size_t>(state.range(0));
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
sfz::Buffer<float> leftInput { chunkSize };
sfz::Buffer<float> rightInput { chunkSize };
sfz::Buffer<float> chunk { chunkSize * 2 };
sndfile.readf(buffer.data(), numFrames);
auto bufferSpan = absl::MakeSpan(buffer);
auto leftSpan = absl::MakeSpan(leftInput);
auto rightSpan = absl::MakeSpan(rightInput);
auto chunkSpan = absl::MakeSpan(chunk);
Upsampler2x upsampler2xLeft;
Upsampler2x upsampler2xRight;
Upsampler4x upsampler4xLeft;
Upsampler4x upsampler4xRight;
upsampler2xLeft.set_coefs(coeffsStage2x.data());
upsampler2xRight.set_coefs(coeffsStage2x.data());
upsampler4xLeft.set_coefs(coeffsStage4x.data());
upsampler4xRight.set_coefs(coeffsStage4x.data());
size_t inputFrameCounter { 0 };
size_t outputFrameCounter { 0 };
while(inputFrameCounter < numFrames)
{
// std::cout << "Input frames: " << inputFrameCounter << "/" << numFrames << '\n';
const auto thisChunkSize = std::min(chunkSize, numFrames - inputFrameCounter);
const auto bufferChunk = bufferSpan.subspan(
inputFrameCounter * sndfile.channels(),
thisChunkSize * sndfile.channels()
);
sfz::readInterleaved(bufferChunk, leftSpan, rightSpan);
upsampler2xLeft.process_block(chunkSpan.data(), leftSpan.data(), static_cast<long>(thisChunkSize));
upsampler4xLeft.process_block(output->channelWriter(0) + outputFrameCounter, chunkSpan.data(), static_cast<long>(thisChunkSize * 2));
upsampler2xRight.process_block(chunkSpan.data(), rightSpan.data(), static_cast<long>(thisChunkSize));
upsampler4xRight.process_block(output->channelWriter(1) + outputFrameCounter, chunkSpan.data(), static_cast<long>(thisChunkSize * 2));
inputFrameCounter += chunkSize;
outputFrameCounter += chunkSize * 4;
}
}
}
BENCHMARK_REGISTER_F(FileFixture, NoResampling);
BENCHMARK_REGISTER_F(FileFixture, ResampleAtOnce);
BENCHMARK_REGISTER_F(FileFixture, ResampleInChunks)->RangeMultiplier(4)->Range((1 << 4), (1 << 16));
BENCHMARK_MAIN();

View file

@ -34,24 +34,24 @@ public:
std::vector<float> output;
};
BENCHMARK_DEFINE_F(SmootherFixture, Linear) (benchmark::State& state)
BENCHMARK_DEFINE_F(SmootherFixture, OnePole) (benchmark::State& state)
{
sfz::Smoother smoother;
sfz::OnePoleSmoother smoother;
smoother.setSmoothing(10, sfz::config::defaultSampleRate);
for (auto _ : state) {
smoother.process(input, absl::MakeSpan(output));
}
}
// BENCHMARK_DEFINE_F(SmootherFixture, Multiplicative)(benchmark::State& state) {
// sfz::MultiplicativeSmoother smoother;
// smoother.setSmoothing(10, sfz::config::defaultSampleRate);
// for (auto _ : state)
// {
// smoother.process(input, absl::MakeSpan(output));
// }
// }
BENCHMARK_DEFINE_F(SmootherFixture, Linear) (benchmark::State& state)
{
sfz::LinearSmoother smoother;
smoother.setSmoothing(10, sfz::config::defaultSampleRate);
for (auto _ : state) {
smoother.process(input, absl::MakeSpan(output));
}
}
BENCHMARK_REGISTER_F(SmootherFixture, OnePole)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
BENCHMARK_REGISTER_F(SmootherFixture, Linear)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
// BENCHMARK_REGISTER_F(SmootherFixture, Multiplicative)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
BENCHMARK_MAIN();

View file

@ -4,10 +4,10 @@
// 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 "Macros.h"
#include "ScopedFTZ.h"
#include "MathHelpers.h"
#include "SIMDConfig.h"
#include "utility/Macros.h"
#include "effects/impl/ResonantArray.h"
#include "effects/impl/ResonantArraySSE.h"
#include "effects/impl/ResonantArrayAVX.h"

View file

@ -1,38 +1,13 @@
project(sfizz)
# Check SIMD
include (SfizzSIMDSourceFiles)
set(BENCHMARK_SIMD_SOURCES)
sfizz_add_simd_sources(BENCHMARK_SIMD_SOURCES "../src")
find_package(benchmark CONFIG REQUIRED)
# Check libsamplerate
find_library(SAMPLERATE_LIBRARY "samplerate")
find_path(SAMPLERATE_INCLUDE_DIR "samplerate.h")
message(STATUS "Checking samplerate library: ${SAMPLERATE_LIBRARY}")
message(STATUS "Checking samplerate includes: ${SAMPLERATE_INCLUDE_DIR}")
if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR)
add_library(sfizz-samplerate INTERFACE)
target_include_directories(sfizz-samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}")
target_link_libraries(sfizz-samplerate INTERFACE "${SAMPLERATE_LIBRARY}")
endif()
add_library(bm_simd STATIC ${BENCHMARK_SIMD_SOURCES})
target_link_libraries(bm_simd PRIVATE absl::span sfizz-cpuid)
target_include_directories(bm_simd PRIVATE ../src/external)
add_library(bm_ftz STATIC ../src/sfizz/ScopedFTZ.cpp)
macro(sfizz_add_benchmark TARGET)
add_executable("${TARGET}" ${ARGN})
target_link_libraries("${TARGET}"
PRIVATE absl::span absl::algorithm
PRIVATE benchmark::benchmark benchmark::benchmark_main
PRIVATE bm_simd bm_ftz)
if (LIBATOMIC_FOUND)
target_link_libraries ("${TARGET}" PRIVATE atomic)
if (NOT TARGET sfizz_benchmarks)
add_custom_target(sfizz_benchmarks)
endif()
target_include_directories("${TARGET}" PRIVATE ../src/sfizz ../src/external)
sfizz_enable_fast_math("${TARGET}")
add_executable("${TARGET}" ${ARGN})
add_dependencies(sfizz_benchmarks "${TARGET}")
target_link_libraries("${TARGET}"
PRIVATE sfizz::internal sfizz::filesystem absl::span absl::algorithm
PRIVATE benchmark::benchmark benchmark::benchmark_main)
sfizz_enable_fast_math("${TARGET}")
endmacro()
sfizz_add_benchmark(bm_opf_high_vs_low BM_OPF_high_vs_low.cpp)
@ -44,7 +19,6 @@ sfizz_add_benchmark(bm_gain BM_gain.cpp)
sfizz_add_benchmark(bm_divide BM_divide.cpp)
sfizz_add_benchmark(bm_ramp BM_ramp.cpp)
sfizz_add_benchmark(bm_ADSR BM_ADSR.cpp)
target_link_libraries(bm_ADSR PRIVATE sfizz::sfizz)
sfizz_add_benchmark(bm_add BM_add.cpp)
sfizz_add_benchmark(bm_multiplyAdd BM_multiplyAdd.cpp)
@ -66,91 +40,44 @@ sfizz_add_benchmark(bm_clamp BM_clamp.cpp)
sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp)
sfizz_add_benchmark(bm_logger BM_logger.cpp)
target_link_libraries(bm_logger PRIVATE sfizz::sfizz)
sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp)
target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz)
sfizz_add_benchmark(bm_powerFollower BM_powerFollower.cpp)
target_link_libraries(bm_powerFollower PRIVATE sfizz::sfizz)
if (TARGET sfizz-samplerate)
if(TARGET sfizz::samplerate)
sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES})
target_link_libraries(bm_resample PRIVATE sfizz-samplerate sfizz-sndfile sfizz-cpuid)
target_link_libraries(bm_resample PRIVATE sfizz::samplerate sfizz::sndfile sfizz::hiir)
endif()
sfizz_add_benchmark(bm_envelopes BM_envelopes.cpp)
sfizz_add_benchmark(bm_wavfile BM_wavfile.cpp)
target_link_libraries(bm_wavfile PRIVATE sfizz-sndfile)
target_link_libraries(bm_wavfile PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_flacfile BM_flacfile.cpp)
target_link_libraries(bm_flacfile PRIVATE sfizz-sndfile)
target_link_libraries(bm_flacfile PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_audioReaders BM_audioReaders.cpp ../src/sfizz/AudioReader.cpp)
target_link_libraries(bm_audioReaders PRIVATE sfizz-sndfile)
target_link_libraries(bm_audioReaders PRIVATE st_audiofile sfizz::sndfile)
sfizz_add_benchmark(bm_readChunk BM_readChunk.cpp)
target_link_libraries(bm_readChunk PRIVATE sfizz-sndfile)
target_link_libraries(bm_readChunk PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_readChunkFlac BM_readChunkFlac.cpp)
target_link_libraries(bm_readChunkFlac PRIVATE sfizz-sndfile)
sfizz_add_benchmark(bm_resampleChunk BM_resampleChunk.cpp)
target_link_libraries(bm_resampleChunk PRIVATE sfizz-sndfile)
target_link_libraries(bm_readChunkFlac PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_interpolators BM_interpolators.cpp)
sfizz_add_benchmark(bm_filterModulation BM_filterModulation.cpp ../src/sfizz/SfzFilter.cpp)
target_link_libraries(bm_filterModulation PRIVATE sfizz-sndfile)
target_link_libraries(bm_filterModulation PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_filterStereoMono BM_filterStereoMono.cpp ../src/sfizz/SfzFilter.cpp)
target_link_libraries(bm_filterStereoMono PRIVATE sfizz-sndfile)
target_link_libraries(bm_filterStereoMono PRIVATE sfizz::sndfile)
sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp
../src/sfizz/effects/impl/ResonantArray.cpp
../src/sfizz/effects/impl/ResonantArraySSE.cpp
../src/sfizz/effects/impl/ResonantArrayAVX.cpp
../src/sfizz/effects/impl/ResonantString.cpp
../src/sfizz/effects/impl/ResonantStringSSE.cpp
../src/sfizz/effects/impl/ResonantStringAVX.cpp)
target_link_libraries(bm_stringResonator PRIVATE sfizz-sndfile)
sfizz_add_benchmark(bm_stringResonator BM_stringResonator.cpp)
target_link_libraries(bm_stringResonator PRIVATE sfizz::sndfile)
add_custom_target(sfizz_benchmarks)
add_dependencies(sfizz_benchmarks
bm_opf_high_vs_low
bm_write
bm_clock
bm_pointerIterationOrOffsets
bm_read
bm_mean
bm_meanSquared
bm_cumsum
bm_diff
bm_mathfuns
bm_gain
bm_divide
bm_ramp
bm_ADSR
bm_add
bm_logger
bm_subtract
bm_multiplyAdd
bm_readChunk
bm_resampleChunk
bm_envelopes
bm_wavfile
bm_flacfile
bm_filterModulation
bm_filterStereoMono
bm_stringResonator
)
if (TARGET bm_resample)
add_dependencies(sfizz_benchmarks bm_resample)
endif()
if (SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l")
if(SFIZZ_SYSTEM_PROCESSOR MATCHES "armv7l")
sfizz_add_benchmark(bm_pan_arm BM_pan_arm.cpp ../src/sfizz/Panning.cpp)
target_link_libraries(bm_pan_arm PRIVATE sfizz-jsl)
add_dependencies(sfizz_benchmarks bm_pan_arm)
target_link_libraries(bm_pan_arm PRIVATE sfizz::jsl)
endif()
configure_file("sample.wav" "${CMAKE_BINARY_DIR}/benchmarks/sample1.wav" COPYONLY)

View file

@ -1,27 +1,14 @@
project (sfizz)
if (SFIZZ_JACK)
find_package(PkgConfig REQUIRED)
pkg_check_modules(JACK "jack" REQUIRED)
link_directories (${JACK_LIBRARY_DIRS})
add_executable (sfizz_jack MidiHelpers.h jack_client.cpp)
target_include_directories (sfizz_jack PRIVATE ${JACK_INCLUDE_DIRS})
target_link_libraries (sfizz_jack PRIVATE sfizz::sfizz absl::flags_parse ${JACK_LIBRARIES})
sfizz_enable_lto_if_needed (sfizz_jack)
install (TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR}
if(SFIZZ_JACK)
add_executable(sfizz_jack MidiHelpers.h jack_client.cpp)
target_link_libraries(sfizz_jack PRIVATE sfizz::sfizz sfizz::jack sfizz::spin_mutex absl::flags_parse)
sfizz_enable_lto_if_needed(sfizz_jack)
install(TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR}
COMPONENT "jack" OPTIONAL)
endif()
if (SFIZZ_RENDER)
add_library(sfizz-fmidi STATIC
"external/fmidi/sources/fmidi/fmidi.h"
"external/fmidi/sources/fmidi/fmidi_mini.cpp")
target_include_directories(sfizz-fmidi PUBLIC "external/fmidi/sources")
target_compile_definitions(sfizz-fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1")
if(SFIZZ_RENDER)
add_executable(sfizz_render MidiHelpers.h sfizz_render.cpp)
target_link_libraries(sfizz_render PRIVATE sfizz::sfizz sfizz-fmidi sfizz-sndfile)
sfizz_enable_lto_if_needed (sfizz_render)
install (TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL)
target_link_libraries(sfizz_render PRIVATE sfizz::internal sfizz::fmidi sfizz::cxxopts st_audiofile_formats)
sfizz_enable_lto_if_needed(sfizz_render)
install(TARGETS sfizz_render DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT "render" OPTIONAL)
endif()

View file

@ -26,6 +26,7 @@
#include <absl/flags/parse.h>
#include <absl/flags/flag.h>
#include <absl/types/span.h>
#include <SpinMutex.h>
#include <atomic>
#include <cstddef>
#include <ios>
@ -38,11 +39,14 @@
#include <string_view>
#include <chrono>
#include <thread>
#include <mutex>
#include <algorithm>
static jack_port_t* midiInputPort;
static jack_port_t* outputPort1;
static jack_port_t* outputPort2;
static jack_client_t* client;
static SpinMutex processMutex;
int process(jack_nframes_t numFrames, void* arg)
{
@ -51,6 +55,16 @@ int process(jack_nframes_t numFrames, void* arg)
auto* buffer = jack_port_get_buffer(midiInputPort, numFrames);
assert(buffer);
auto* leftOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort1, numFrames));
auto* rightOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort2, numFrames));
std::unique_lock<SpinMutex> lock { processMutex, std::try_to_lock };
if (!lock.owns_lock()) {
std::fill_n(leftOutput, numFrames, 0.0f);
std::fill_n(rightOutput, numFrames, 0.0f);
return 0;
}
auto numMidiEvents = jack_midi_get_event_count(buffer);
jack_midi_event_t event;
@ -64,41 +78,34 @@ int process(jack_nframes_t numFrames, void* arg)
switch (midi::status(event.buffer[0])) {
case midi::noteOff: noteoff:
// DBG("[MIDI] Note " << +event.buffer[1] << " OFF at time " << event.time);
synth->noteOff(event.time, event.buffer[1], event.buffer[2]);
break;
case midi::noteOn:
if (event.buffer[2] == 0)
goto noteoff;
// DBG("[MIDI] Note " << +event.buffer[1] << " ON at time " << event.time);
synth->noteOn(event.time, event.buffer[1], event.buffer[2]);
break;
case midi::polyphonicPressure:
// DBG("[MIDI] Polyphonic pressure on at time " << event.time);
synth->polyAftertouch(event.time, event.buffer[1], event.buffer[2]);
break;
case midi::controlChange:
// DBG("[MIDI] CC " << +event.buffer[1] << " at time " << event.time);
synth->cc(event.time, event.buffer[1], event.buffer[2]);
break;
case midi::programChange:
// DBG("[MIDI] Program change at time " << event.time);
// Not implemented
break;
case midi::channelPressure:
// DBG("[MIDI] Channel pressure at time " << event.time);
synth->channelAftertouch(event.time, event.buffer[1]);
break;
case midi::pitchBend:
synth->pitchWheel(event.time, midi::buildAndCenterPitch(event.buffer[1], event.buffer[2]));
// DBG("[MIDI] Pitch bend at time " << event.time);
break;
case midi::systemMessage:
// DBG("[MIDI] System message at time " << event.time);
// Not implemented
break;
}
}
auto* leftOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort1, numFrames));
auto* rightOutput = reinterpret_cast<float*>(jack_port_get_buffer(outputPort2, numFrames));
float* stereoOutput[] = { leftOutput, rightOutput };
synth->renderBlock(stereoOutput, numFrames);
@ -112,6 +119,7 @@ int sampleBlockChanged(jack_nframes_t nframes, void* arg)
auto* synth = reinterpret_cast<sfz::Sfizz*>(arg);
// DBG("Sample per block changed to " << nframes);
std::lock_guard<SpinMutex> lock { processMutex };
synth->setSamplesPerBlock(nframes);
return 0;
}
@ -123,6 +131,7 @@ int sampleRateChanged(jack_nframes_t nframes, void* arg)
auto* synth = reinterpret_cast<sfz::Sfizz*>(arg);
// DBG("Sample rate changed to " << nframes);
std::lock_guard<SpinMutex> lock { processMutex };
synth->setSampleRate(nframes);
return 0;
}

View file

@ -1,11 +1,11 @@
#include <sndfile.hh>
#include "sfizz/Synth.h"
#include "sfizz/MathHelpers.h"
#include "sfizz/SfzHelpers.h"
#include "sfizz/SIMDHelpers.h"
#include "MidiHelpers.h"
#include "cxxopts.hpp"
#include <st_audiofile_libs.h>
#include <cxxopts.hpp>
#include <fmidi/fmidi.h>
#include <iostream>
@ -66,7 +66,6 @@ int main(int argc, char** argv)
bool help { false };
bool useEOT { false };
int quality { 2 };
int oversampling { 1 };
options.add_options()
("sfz", "SFZ file", cxxopts::value<std::string>())
@ -74,7 +73,6 @@ int main(int argc, char** argv)
("wav", "Output wav file", cxxopts::value<std::string>())
("b,blocksize", "Block size for the sfizz callbacks", cxxopts::value(blockSize))
("s,samplerate", "Output sample rate", cxxopts::value(sampleRate))
("oversampling", "Internal oversampling factor", cxxopts::value(oversampling))
("q,quality", "Resampling quality", cxxopts::value(quality))
("v,verbose", "Verbose output", cxxopts::value(verbose))
("log", "Produce logs", cxxopts::value<std::string>())
@ -126,23 +124,6 @@ int main(int argc, char** argv)
if (params.count("log") > 0)
synth.enableLogging(params["log"].as<std::string>());
const auto osFactor = [oversampling] {
switch (oversampling){
case 1:
return sfz::Oversampling::x1;
case 2:
return sfz::Oversampling::x2;
case 4:
return sfz::Oversampling::x4;
case 5:
return sfz::Oversampling::x8;
default:
LOG_ERROR("Bad oversampling factor: " << oversampling);
std::exit(-1);
}
}();
synth.setOversamplingFactor(osFactor);
ERROR_IF(!synth.loadSfzFile(sfzPath), "There was an error loading the SFZ file.");
LOG_INFO(synth.getNumRegions() << " regions in the SFZ.");
@ -158,14 +139,27 @@ int main(int argc, char** argv)
LOG_INFO("-- Cutting the rendering at the last MIDI End of Track message");
}
SndfileHandle outputFile (outputPath.u8string(), SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, sampleRate);
ERROR_IF(outputFile.error() != 0, "Error writing out the wav file: " << outputFile.strError());
drwav outputFile;
drwav_data_format outputFormat {};
outputFormat.container = drwav_container_riff;
outputFormat.format = DR_WAVE_FORMAT_PCM;
outputFormat.channels = 2;
outputFormat.sampleRate = sampleRate;
outputFormat.bitsPerSample = 16;
#if !defined(_WIN32)
drwav_bool32 outputFileOk = drwav_init_file_write(&outputFile, outputPath.c_str(), &outputFormat, nullptr);
#else
drwav_bool32 outputFileOk = drwav_init_file_write_w(&outputFile, outputPath.c_str(), &outputFormat, nullptr);
#endif
ERROR_IF(!outputFileOk, "Error opening the wav file for writing");
auto sampleRateDouble = static_cast<double>(sampleRate);
const double increment { 1.0 / sampleRateDouble };
int numFramesWritten { 0 };
uint64_t numFramesWritten { 0 };
sfz::AudioBuffer<float> audioBuffer { 2, blockSize };
sfz::Buffer<float> interleavedBuffer { 2 * blockSize };
sfz::Buffer<int16_t> interleavedPcm { 2 * blockSize };
fmidi_player_u midiPlayer { fmidi_player_new(midiFile.get()) };
CallbackData callbackData { synth, 0, false };
@ -178,7 +172,8 @@ int main(int argc, char** argv)
fmidi_player_tick(midiPlayer.get(), increment);
synth.renderBlock(audioBuffer);
sfz::writeInterleaved(audioBuffer.getConstSpan(0), audioBuffer.getConstSpan(1), absl::MakeSpan(interleavedBuffer));
numFramesWritten += outputFile.writef(interleavedBuffer.data(), blockSize);
drwav_f32_to_s16(interleavedPcm.data(), interleavedBuffer.data(), 2 * blockSize);
numFramesWritten += drwav_write_pcm_frames(&outputFile, blockSize, interleavedPcm.data());
}
if (!useEOT) {
@ -186,12 +181,13 @@ int main(int argc, char** argv)
while (averagePower > 1e-12f) {
synth.renderBlock(audioBuffer);
sfz::writeInterleaved(audioBuffer.getConstSpan(0), audioBuffer.getConstSpan(1), absl::MakeSpan(interleavedBuffer));
numFramesWritten += outputFile.writef(interleavedBuffer.data(), blockSize);
drwav_f32_to_s16(interleavedPcm.data(), interleavedBuffer.data(), 2 * blockSize);
numFramesWritten += drwav_write_pcm_frames(&outputFile, blockSize, interleavedPcm.data());
averagePower = sfz::meanSquared<float>(interleavedBuffer);
}
}
outputFile.writeSync();
drwav_uninit(&outputFile);
LOG_INFO("Wrote " << numFramesWritten << " frames of sound data in" << outputPath.string());
return 0;

View file

@ -13,7 +13,7 @@ function(bundle_dylibs NAME PATH)
return()
endif()
set(_relative_libdir "../libs")
set(_relative_libdir "../Frameworks")
get_filename_component(_dir "${PATH}" DIRECTORY)
set(_dir "${_dir}/${_relative_libdir}")

View file

@ -1,37 +1,37 @@
# Added in CMake 3.9
if (CMAKE_VERSION VERSION_LESS 3.9)
message (WARNING "\nIPO checks are only available on CMake 3.9 and later.")
if(CMAKE_VERSION VERSION_LESS 3.9)
message(WARNING "\nIPO checks are only available on CMake 3.9 and later.")
set(ENABLE_LTO OFF CACHE BOOL "" FORCE)
function (SFIZZ_ENABLE_LTO_IF_NEEDED TARGET)
function(SFIZZ_ENABLE_LTO_IF_NEEDED TARGET)
endfunction()
return()
endif()
include (CheckIPOSupported)
check_ipo_supported (RESULT result OUTPUT output)
include(CheckIPOSupported)
check_ipo_supported(RESULT result OUTPUT output)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
set(ENABLE_LTO OFF CACHE BOOL "" FORCE)
endif()
if (result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release")
message (STATUS "\nLTO enabled.")
if(result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release")
message(STATUS "\nLTO enabled.")
else()
if (${output})
message (WARNING "\nIPO disabled: ${output}")
if(${output})
message(WARNING "\nIPO disabled: ${output}")
else()
message (WARNING "\nIPO was disabled or not in a Release build.")
message(WARNING "\nIPO was disabled or not in a Release build.")
endif()
set(ENABLE_LTO OFF CACHE BOOL "" FORCE)
endif()
function (SFIZZ_ENABLE_LTO_IF_NEEDED TARGET)
if (${ENABLE_LTO})
function(SFIZZ_ENABLE_LTO_IF_NEEDED TARGET)
if(${ENABLE_LTO})
message(STATUS "Enabling LTO on ${TARGET}")
set_property (TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
set_property(TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
endif()
endfunction()

94
cmake/GNUWarnings.cmake Normal file
View file

@ -0,0 +1,94 @@
# A CMake module to use GNU warning flags with C and C++
# and detect their availability.
#
# Usage:
# gw_warn(<Wflag>...)
# gw_warn_c(<Wflag>...)
# gw_warn_cxx(<Wflag>...)
# gw_target_warn(<target> <PUBLIC|PRIVATE|INTERFACE> <Wflag>...)
# gw_target_warn_c(<target> <PUBLIC|PRIVATE|INTERFACE> <Wflag>...)
# gw_target_warn_cxx(<target> <PUBLIC|PRIVATE|INTERFACE> <Wflag>...)
#
# Copyright 2020, Jean Pierre Cimalando <jp-dev@inbox.ru>
# SPDX-License-Identifier: BSD-2-Clause
function(gw_warn)
gw_warn_c(${ARGN})
gw_warn_cxx(${ARGN})
endfunction()
function(gw_warn_c)
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
foreach(flag ${ARGN})
_gw_check_c_flag_is_silent("${flag}")
if("${GNUWARNINGS_C_FLAG_${flag}_SILENT}")
add_compile_options("$<$<COMPILE_LANGUAGE:C>:${flag}>")
endif()
endforeach()
endif()
endfunction()
function(gw_warn_cxx)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
foreach(flag ${ARGN})
_gw_check_cxx_flag_is_silent("${flag}")
if("${GNUWARNINGS_CXX_FLAG_${flag}_SILENT}")
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:${flag}>")
endif()
endforeach()
endif()
endfunction()
function(gw_target_warn TARGET DOMAIN)
gw_target_warn_c("${TARGET}" "${DOMAIN}" ${ARGN})
gw_target_warn_cxx("${TARGET}" "${DOMAIN}" ${ARGN})
endfunction()
function(gw_target_warn_c TARGET DOMAIN)
if(CMAKE_C_COMPILER_ID MATCHES "GNU|Clang")
foreach(flag ${ARGN})
_gw_check_c_flag_is_silent("${flag}")
if("${GNUWARNINGS_C_FLAG_${flag}_SILENT}")
target_compile_options("${TARGET}" "${DOMAIN}" "$<$<COMPILE_LANGUAGE:C>:${flag}>")
endif()
endforeach()
endif()
endfunction()
function(gw_target_warn_cxx TARGET DOMAIN)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
foreach(flag ${ARGN})
_gw_check_cxx_flag_is_silent("${flag}")
if("${GNUWARNINGS_CXX_FLAG_${flag}_SILENT}")
target_compile_options("${TARGET}" "${DOMAIN}" "$<$<COMPILE_LANGUAGE:CXX>:${flag}>")
endif()
endforeach()
endif()
endfunction()
function(_gw_check_c_flag_is_silent FLAG)
if(NOT DEFINED "GNUWARNINGS_C_FLAG_${FLAG}_SILENT")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.c" "")
_gw_check_command_succeeds_silently(_result "${CMAKE_C_COMPILER}" "${FLAG}" "-c" "-o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.c")
message(STATUS "Have C warning ${flag}: ${_result}")
set("GNUWARNINGS_C_FLAG_${FLAG}_SILENT" "${_result}" CACHE INTERNAL "Have C warning ${flag}")
endif()
endfunction()
function(_gw_check_cxx_flag_is_silent FLAG)
if(NOT DEFINED "GNUWARNINGS_CXX_FLAG_${FLAG}_SILENT")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.cpp" "")
_gw_check_command_succeeds_silently(_result "${CMAKE_CXX_COMPILER}" "${FLAG}" "-c" "-o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.o" "${CMAKE_CURRENT_BINARY_DIR}/CheckGNUWarning.cpp")
message(STATUS "Have C++ warning ${flag}: ${_result}")
set("GNUWARNINGS_CXX_FLAG_${FLAG}_SILENT" "${_result}" CACHE INTERNAL "Have C++ warning ${flag}")
endif()
endfunction()
function(_gw_check_command_succeeds_silently RESULT_VARIABLE)
execute_process(COMMAND ${ARGN} RESULT_VARIABLE _result OUTPUT_VARIABLE _output ERROR_VARIABLE _error OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE)
if(_result EQUAL 0 AND _output STREQUAL "" AND _error STREQUAL "")
set("${RESULT_VARIABLE}" TRUE PARENT_SCOPE)
else()
set("${RESULT_VARIABLE}" FALSE PARENT_SCOPE)
endif()
endfunction()

View file

@ -1,17 +1,20 @@
# This option is for MIDI CC support in absence of host midi:binding support
option(SFIZZ_LV2_PSA "Enable plugin-side MIDI automations" OFF)
# Configuration for this plugin
# TODO: generate version from git
set (LV2PLUGIN_VERSION_MINOR 6)
set (LV2PLUGIN_VERSION_MICRO 0)
set (LV2PLUGIN_NAME "sfizz")
set (LV2PLUGIN_COMMENT "SFZ sampler")
set (LV2PLUGIN_URI "http://sfztools.github.io/sfizz")
set (LV2PLUGIN_REPOSITORY "https://github.com/sfztools/sfizz")
set (LV2PLUGIN_AUTHOR "SFZTools")
set (LV2PLUGIN_EMAIL "paul@ferrand.cc")
if (SFIZZ_USE_VCPKG)
set (LV2PLUGIN_SPDX_LICENSE_ID "LGPL-3.0-only")
set(LV2PLUGIN_VERSION_MINOR 8)
set(LV2PLUGIN_VERSION_MICRO 0)
set(LV2PLUGIN_NAME "sfizz")
set(LV2PLUGIN_COMMENT "SFZ sampler")
set(LV2PLUGIN_URI "http://sfztools.github.io/sfizz")
set(LV2PLUGIN_REPOSITORY "https://github.com/sfztools/sfizz")
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")
set(LV2PLUGIN_SPDX_LICENSE_ID "ISC")
endif()
if(SFIZZ_LV2_UI)
@ -30,13 +33,69 @@ else()
set(LV2_UI_TYPE "X11UI")
endif()
if (APPLE)
set (LV2PLUGIN_INSTALL_DIR "$ENV{HOME}/Library/Audio/Plug-Ins/LV2" CACHE STRING
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
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
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 "${SFIZZ_NUM_CCS}-1")
foreach(_i RANGE "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" "
sfizz:cc${_i}
a lv2:Parameter ;
rdfs:label \"Controller ${_i}\" ;
rdfs:range atom:Float")
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 sfizz:cc000")
foreach(_i RANGE 1 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
file(APPEND "${FILE}" " ;
")
file(APPEND "${FILE}" " patch:writable sfizz:cc000")
foreach(_i RANGE 1 "${_j}")
string_left_pad(_i "${_i}" 3 0)
file(APPEND "${FILE}" ", sfizz:cc${_i}")
endforeach()
file(APPEND "${FILE}" " .
")
endfunction()

19
cmake/OptionEx.cmake Normal file
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
# Macro: option_ex(OPTION DOC [CONDITION])
# Defines an option, with these characteristics:
# - A suffix [default: ON/OFF] is appended to the documentation
# - The value is interpreted like a conditional expression
macro(option_ex option doc)
if(${ARGN})
set(_value ON)
else()
set(_value OFF)
endif()
option("${option}" "${doc} [default: ${_value}]" "${_value}")
unset(_value)
endmacro()

View file

@ -1,51 +1,51 @@
include(CMakeDependentOption)
include(CheckCXXCompilerFlag)
include(GNUWarnings)
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used")
set(CMAKE_C_STANDARD 99 CACHE STRING "C standard to be used")
# Export the compile_commands.json file
set (CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Only install what's explicitely said
set (CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
set (CMAKE_CXX_VISIBILITY_PRESET hidden)
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON)
# Set C++ compatibility level
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND CMAKE_CXX_STANDARD LESS 17)
set(CMAKE_CXX_STANDARD 17)
elseif((SFIZZ_LV2_UI OR SFIZZ_VST OR SFIZZ_AU OR SFIZZ_VST2) AND CMAKE_CXX_STANDARD LESS 14)
# if the UI is part of the build, make it 14
set(CMAKE_CXX_STANDARD 14)
endif()
# Process sources as UTF-8
if(MSVC)
add_compile_options("/utf-8")
endif()
# Set Windows compatibility level to 7
if (WIN32)
if(WIN32)
add_compile_definitions(_WIN32_WINNT=0x601)
endif()
# Set macOS compatibility level
if (APPLE)
if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
endif()
# Do not define macros `min` and `max`
if (WIN32)
if(WIN32)
add_compile_definitions(NOMINMAX)
endif()
# Find macOS system libraries
if(APPLE)
find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation")
find_library(APPLE_FOUNDATION_LIBRARY "Foundation")
find_library(APPLE_COCOA_LIBRARY "Cocoa")
find_library(APPLE_CARBON_LIBRARY "Carbon")
find_library(APPLE_OPENGL_LIBRARY "OpenGL")
find_library(APPLE_ACCELERATE_LIBRARY "Accelerate")
find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore")
find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox")
find_library(APPLE_AUDIOUNIT_LIBRARY "AudioUnit")
find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio")
find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI")
endif()
# The variable CMAKE_SYSTEM_PROCESSOR is incorrect on Visual studio...
# see https://gitlab.kitware.com/cmake/cmake/issues/15170
if (NOT SFIZZ_SYSTEM_PROCESSOR)
if(NOT SFIZZ_SYSTEM_PROCESSOR)
if(MSVC)
set(SFIZZ_SYSTEM_PROCESSOR "${MSVC_CXX_ARCHITECTURE_ID}")
else()
@ -54,109 +54,61 @@ if (NOT SFIZZ_SYSTEM_PROCESSOR)
endif()
# Add required flags for the builds
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_compile_options(-Wall)
add_compile_options(-Wextra)
add_compile_options(-Wno-multichar)
add_compile_options(-Werror=return-type)
if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(i.86|x86_64)$")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
gw_warn(-Wall -Wextra -Wno-multichar -Werror=return-type)
if(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(i.86|x86_64)$")
add_compile_options(-msse2)
elseif(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(arm.*)$")
add_compile_options(-mfpu=neon)
if (NOT ANDROID)
if(NOT ANDROID)
add_compile_options(-mfloat-abi=hard)
endif()
endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(CMAKE_CXX_STANDARD 17)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/Zc:__cplusplus)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
function(sfizz_enable_fast_math NAME)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options("${NAME}" PRIVATE "-ffast-math")
elseif(MSVC)
target_compile_options("${NAME}" PRIVATE "/fp:fast")
endif()
endfunction()
# The sndfile library
add_library(sfizz-sndfile INTERFACE)
# The jsl utility library for C++
add_library(sfizz-jsl INTERFACE)
target_include_directories(sfizz-jsl INTERFACE "external/jsl/include")
if (SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
find_package(SndFile CONFIG REQUIRED)
find_path(SNDFILE_INCLUDE_DIR sndfile.hh)
target_include_directories(sfizz-sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
target_link_libraries(sfizz-sndfile INTERFACE SndFile::sndfile)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(SNDFILE "sndfile" REQUIRED)
target_include_directories(sfizz-sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS})
if (SFIZZ_STATIC_DEPENDENCIES)
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES})
else()
target_link_libraries(sfizz-sndfile INTERFACE ${SNDFILE_LIBRARIES})
endif()
link_directories(${SNDFILE_LIBRARY_DIRS})
endif()
# If we build with Clang, optionally use libc++. Enabled by default on Apple OS.
cmake_dependent_option(USE_LIBCPP "Use libc++ with clang" "${APPLE}"
"CMAKE_CXX_COMPILER_ID MATCHES Clang" OFF)
if (USE_LIBCPP)
if(USE_LIBCPP)
add_compile_options(-stdlib=libc++)
# Presumably need the above for linking too, maybe other options missing as well
add_link_options(-stdlib=libc++) # New command on CMake master, not in 3.12 release
add_link_options(-lc++abi) # New command on CMake master, not in 3.12 release
endif()
add_library(sfizz-pugixml STATIC "src/external/pugixml/src/pugixml.cpp")
target_include_directories(sfizz-pugixml PUBLIC "src/external/pugixml/src")
add_library(sfizz-spline STATIC "src/external/spline/spline/spline.cpp")
target_include_directories(sfizz-spline PUBLIC "src/external/spline")
add_library(sfizz-tunings STATIC "src/external/tunings/src/Tunings.cpp")
target_include_directories(sfizz-tunings PUBLIC "src/external/tunings/include")
include (CheckLibraryExists)
add_library (sfizz-atomic INTERFACE)
if (UNIX AND NOT APPLE)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }")
try_compile(SFIZZ_LINK_LIBATOMIC "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic"
SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c"
LINK_LIBRARIES "atomic")
if (SFIZZ_LINK_LIBATOMIC)
target_link_libraries (sfizz-atomic INTERFACE "atomic")
endif()
else()
set(SFIZZ_LINK_LIBATOMIC FALSE)
endif()
# Don't show build information when building a different project
function (show_build_info_if_needed)
if (CMAKE_PROJECT_NAME STREQUAL "sfizz")
message (STATUS "
function(show_build_info_if_needed)
if(CMAKE_PROJECT_NAME STREQUAL "sfizz")
message(STATUS "
Project name: ${PROJECT_NAME}
Build type: ${CMAKE_BUILD_TYPE}
Build processor: ${SFIZZ_SYSTEM_PROCESSOR}
Build using LTO: ${ENABLE_LTO}
Build as shared library: ${SFIZZ_SHARED}
Build JACK stand-alone client: ${SFIZZ_JACK}
Build render client: ${SFIZZ_RENDER}
Build LV2 plug-in: ${SFIZZ_LV2}
Build LV2 user interface: ${SFIZZ_LV2_UI}
Build VST plug-in: ${SFIZZ_VST}
Build AU plug-in: ${SFIZZ_AU}
Build benchmarks: ${SFIZZ_BENCHMARKS}
Build tests: ${SFIZZ_TESTS}
Build demos: ${SFIZZ_DEMOS}
Build devtools: ${SFIZZ_DEVTOOLS}
Use sndfile: ${SFIZZ_USE_SNDFILE}
Use vcpkg: ${SFIZZ_USE_VCPKG}
Statically link dependencies: ${SFIZZ_STATIC_DEPENDENCIES}
Link libatomic: ${SFIZZ_LINK_LIBATOMIC}
Use clang libc++: ${USE_LIBCPP}
Release asserts: ${SFIZZ_RELEASE_ASSERTS}
@ -169,5 +121,3 @@ Compiler CXX min size flags: ${CMAKE_CXX_FLAGS_MINSIZEREL}
")
endif()
endfunction()
find_package (Threads REQUIRED)

261
cmake/SfizzDeps.cmake Normal file
View file

@ -0,0 +1,261 @@
# Find system threads
find_package(Threads REQUIRED)
# Find OpenMP
find_package(OpenMP)
if(OPENMP_FOUND)
add_library(sfizz_openmp INTERFACE)
add_library(sfizz::openmp ALIAS sfizz_openmp)
# OpenMP flags are provided as a space-separated string, we need a list
if(NOT CMAKE_VERSION VERSION_LESS 3.9)
separate_arguments(SFIZZ_OpenMP_C_OPTIONS NATIVE_COMMAND "${OpenMP_C_FLAGS}")
separate_arguments(SFIZZ_OpenMP_CXX_OPTIONS NATIVE_COMMAND "${OpenMP_CXX_FLAGS}")
elseif(CMAKE_HOST_WIN32)
separate_arguments(SFIZZ_OpenMP_C_OPTIONS WINDOWS_COMMAND "${OpenMP_C_FLAGS}")
separate_arguments(SFIZZ_OpenMP_CXX_OPTIONS WINDOWS_COMMAND "${OpenMP_CXX_FLAGS}")
else()
separate_arguments(SFIZZ_OpenMP_C_OPTIONS UNIX_COMMAND "${OpenMP_C_FLAGS}")
separate_arguments(SFIZZ_OpenMP_CXX_OPTIONS UNIX_COMMAND "${OpenMP_CXX_FLAGS}")
endif()
target_compile_options(sfizz_openmp INTERFACE
$<$<COMPILE_LANGUAGE:C>:${SFIZZ_OpenMP_C_OPTIONS}>
$<$<COMPILE_LANGUAGE:CXX>:${SFIZZ_OpenMP_CXX_OPTIONS}>)
endif()
# Find macOS system libraries
if(APPLE)
find_library(APPLE_COREFOUNDATION_LIBRARY "CoreFoundation")
find_library(APPLE_FOUNDATION_LIBRARY "Foundation")
find_library(APPLE_COCOA_LIBRARY "Cocoa")
find_library(APPLE_CARBON_LIBRARY "Carbon")
find_library(APPLE_OPENGL_LIBRARY "OpenGL")
find_library(APPLE_ACCELERATE_LIBRARY "Accelerate")
find_library(APPLE_QUARTZCORE_LIBRARY "QuartzCore")
find_library(APPLE_AUDIOTOOLBOX_LIBRARY "AudioToolbox")
find_library(APPLE_AUDIOUNIT_LIBRARY "AudioUnit")
find_library(APPLE_COREAUDIO_LIBRARY "CoreAudio")
find_library(APPLE_COREMIDI_LIBRARY "CoreMIDI")
endif()
# Set up macOS library paths
if(APPLE)
# See https://stackoverflow.com/a/54103956
# and https://stackoverflow.com/a/21692023
# Apparently this is not needed in Travis CI using addons
# but it is in Appveyor instead
list(APPEND CMAKE_PREFIX_PATH /usr/local)
endif()
# Add Abseil
if(SFIZZ_USE_SYSTEM_ABSEIL)
find_package(absl REQUIRED)
else()
function(sfizz_add_vendor_abseil)
set(BUILD_SHARED_LIBS OFF) # only changed at local scope
add_subdirectory("external/abseil-cpp" EXCLUDE_FROM_ALL)
endfunction()
sfizz_add_vendor_abseil()
endif()
# The jsl utility library for C++
add_library(sfizz_jsl INTERFACE)
add_library(sfizz::jsl ALIAS sfizz_jsl)
target_include_directories(sfizz_jsl INTERFACE "external/jsl/include")
# The cxxopts library
add_library(sfizz_cxxopts INTERFACE)
add_library(sfizz::cxxopts ALIAS sfizz_cxxopts)
target_include_directories(sfizz_cxxopts INTERFACE "external/cxxopts")
# The sndfile library
if(SFIZZ_USE_SNDFILE OR SFIZZ_DEMOS OR SFIZZ_DEVTOOLS OR SFIZZ_BENCHMARKS)
add_library(sfizz_sndfile INTERFACE)
add_library(sfizz::sndfile ALIAS sfizz_sndfile)
if(SFIZZ_USE_VCPKG OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
find_package(SndFile CONFIG REQUIRED)
find_path(SNDFILE_INCLUDE_DIR "sndfile.hh")
target_include_directories(sfizz_sndfile INTERFACE "${SNDFILE_INCLUDE_DIR}")
target_link_libraries(sfizz_sndfile INTERFACE SndFile::sndfile)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(SNDFILE "sndfile" REQUIRED)
target_include_directories(sfizz_sndfile INTERFACE ${SNDFILE_INCLUDE_DIRS})
if(SFIZZ_STATIC_DEPENDENCIES)
target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_STATIC_LIBRARIES})
else()
target_link_libraries(sfizz_sndfile INTERFACE ${SNDFILE_LIBRARIES})
endif()
link_directories(${SNDFILE_LIBRARY_DIRS})
endif()
endif()
# The st_audiofile library
if(SFIZZ_USE_SNDFILE)
set(ST_AUDIO_FILE_USE_SNDFILE ON CACHE BOOL "" FORCE)
set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "sfizz::sndfile" CACHE STRING "" FORCE)
else()
set(ST_AUDIO_FILE_USE_SNDFILE OFF CACHE BOOL "" FORCE)
set(ST_AUDIO_FILE_EXTERNAL_SNDFILE "" CACHE STRING "" FORCE)
endif()
add_subdirectory("external/st_audiofile" EXCLUDE_FROM_ALL)
# The simde library
add_library(sfizz_simde INTERFACE)
add_library(sfizz::simde ALIAS sfizz_simde)
if(SFIZZ_USE_SYSTEM_SIMDE)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SIMDE "simde" REQUIRED)
target_include_directories(sfizz_simde INTERFACE "${SIMDE_INCLUDE_DIRS}")
if(NOT SIMDE_VERSION OR SIMDE_VERSION VERSION_LESS_EQUAL "0.7.2")
message(WARNING "The version of SIMDe on this system has known issues. \
It is recommended to either update if a newer version is available, or use the \
version bundled with this package. Refer to following issues: \
simd-everywhere/simde#704, simd-everywhere/simde#706")
endif()
else()
target_include_directories(sfizz_simde INTERFACE "external/simde")
endif()
if(TARGET sfizz::openmp)
target_link_libraries(sfizz_simde INTERFACE sfizz::openmp)
endif()
# The pugixml library
add_library(sfizz_pugixml STATIC "src/external/pugixml/src/pugixml.cpp")
add_library(sfizz::pugixml ALIAS sfizz_pugixml)
target_include_directories(sfizz_pugixml PUBLIC "src/external/pugixml/src")
# The spline library
add_library(sfizz_spline STATIC "src/external/spline/spline/spline.cpp")
add_library(sfizz::spline ALIAS sfizz_spline)
target_include_directories(sfizz_spline PUBLIC "src/external/spline")
# The tunings library
add_library(sfizz_tunings STATIC "src/external/tunings/src/Tunings.cpp")
add_library(sfizz::tunings ALIAS sfizz_tunings)
target_include_directories(sfizz_tunings PUBLIC "src/external/tunings/include")
# The hiir library
add_library(sfizz_hiir INTERFACE)
add_library(sfizz::hiir ALIAS sfizz_hiir)
target_include_directories(sfizz_hiir INTERFACE "src/external/hiir")
# The hiir filter designer
add_library(sfizz_hiir_polyphase_iir2designer STATIC
"src/external/hiir/hiir/PolyphaseIir2Designer.cpp")
add_library(sfizz::hiir_polyphase_iir2designer ALIAS sfizz_hiir_polyphase_iir2designer)
target_link_libraries(sfizz_hiir_polyphase_iir2designer PUBLIC sfizz::hiir)
# The kissfft library
add_library(sfizz_kissfft STATIC
"src/external/kiss_fft/kiss_fft.c"
"src/external/kiss_fft/tools/kiss_fftr.c")
add_library(sfizz::kissfft ALIAS sfizz_kissfft)
target_include_directories(sfizz_kissfft
PUBLIC "src/external/kiss_fft"
PUBLIC "src/external/kiss_fft/tools")
# The cephes library
add_library(sfizz_cephes STATIC
"external/cephes/src/chbevl.c"
"external/cephes/src/i0.c")
add_library(sfizz::cephes ALIAS sfizz_cephes)
# The cpuid library
add_library(sfizz_cpuid STATIC
"src/external/cpuid/src/cpuid/cpuinfo.cpp"
"src/external/cpuid/src/cpuid/version.cpp")
add_library(sfizz::cpuid ALIAS sfizz_cpuid)
set_property(TARGET sfizz_cpuid PROPERTY CXX_STANDARD 11)
target_include_directories(sfizz_cpuid
PUBLIC "src/external/cpuid/src"
PRIVATE "src/external/cpuid/platform/src")
# The threadpool library
add_library(sfizz_threadpool INTERFACE)
add_library(sfizz::threadpool ALIAS sfizz_threadpool)
target_include_directories(sfizz_threadpool INTERFACE "external/threadpool")
# The atomic_queue library
add_library(sfizz_atomic_queue INTERFACE)
add_library(sfizz::atomic_queue ALIAS sfizz_atomic_queue)
target_include_directories(sfizz_atomic_queue INTERFACE "external/atomic_queue/include")
# The ghc::filesystem library
add_library(sfizz_filesystem INTERFACE)
add_library(sfizz::filesystem ALIAS sfizz_filesystem)
target_include_directories(sfizz_filesystem INTERFACE "external/filesystem/include")
# The atomic library
add_library(sfizz_atomic INTERFACE)
add_library(sfizz::atomic ALIAS sfizz_atomic)
if(UNIX AND NOT APPLE)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic")
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c" "int main() { return 0; }")
try_compile(SFIZZ_LINK_LIBATOMIC "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic"
SOURCES "${CMAKE_CURRENT_BINARY_DIR}/check_libatomic/check_libatomic.c"
LINK_LIBRARIES "atomic")
if(SFIZZ_LINK_LIBATOMIC)
target_link_libraries(sfizz_atomic INTERFACE "atomic")
endif()
endif()
# The jack library
if(SFIZZ_JACK)
find_package(PkgConfig REQUIRED)
pkg_check_modules(JACK "jack" REQUIRED)
elseif()
find_package(PkgConfig)
if(PKGCONFIG_FOUND)
pkg_check_modules(JACK "jack")
endif()
endif()
if(JACK_FOUND)
add_library(sfizz_jacklib INTERFACE)
add_library(sfizz::jack ALIAS sfizz_jacklib)
target_include_directories(sfizz_jacklib INTERFACE ${JACK_INCLUDE_DIRS})
target_link_libraries(sfizz_jacklib INTERFACE ${JACK_LIBRARIES})
link_directories(${JACK_LIBRARY_DIRS})
endif()
# The Qt library
find_package(Qt5 COMPONENTS Widgets)
# The fmidi library
add_library(sfizz_fmidi STATIC
"external/fmidi/sources/fmidi/fmidi.h"
"external/fmidi/sources/fmidi/fmidi_mini.cpp")
add_library(sfizz::fmidi ALIAS sfizz_fmidi)
target_include_directories(sfizz_fmidi PUBLIC "external/fmidi/sources")
target_compile_definitions(sfizz_fmidi PUBLIC "FMIDI_STATIC=1" "FMIDI_DISABLE_DESCRIBE_API=1")
# The samplerate library
find_package(PkgConfig)
if(PKGCONFIG_FOUND)
pkg_check_modules(SAMPLERATE "samplerate")
if(SAMPLERATE_FOUND)
add_library(sfizz_samplerate INTERFACE)
add_library(sfizz::samplerate ALIAS sfizz_samplerate)
target_include_directories(sfizz_samplerate INTERFACE ${SAMPLERATE_INCLUDE_DIRS})
target_link_libraries(sfizz_samplerate INTERFACE ${SAMPLERATE_LIBRARIES})
link_directories(${SAMPLERATE_LIBRARY_DIRS})
endif()
endif()
if(NOT TARGET sfizz::samplerate)
find_library(SAMPLERATE_LIBRARY "samplerate")
find_path(SAMPLERATE_INCLUDE_DIR "samplerate.h")
message(STATUS "Checking samplerate library: ${SAMPLERATE_LIBRARY}")
message(STATUS "Checking samplerate includes: ${SAMPLERATE_INCLUDE_DIR}")
if(SAMPLERATE_LIBRARY AND SAMPLERATE_INCLUDE_DIR)
add_library(sfizz_samplerate INTERFACE)
add_library(sfizz::samplerate ALIAS sfizz_samplerate)
target_include_directories(sfizz_samplerate INTERFACE "${SAMPLERATE_INCLUDE_DIR}")
target_link_libraries(sfizz_samplerate INTERFACE "${SAMPLERATE_LIBRARY}")
endif()
endif()
# The benchmark library
if(SFIZZ_BENCHMARKS)
find_package(benchmark CONFIG REQUIRED)
endif()

72
cmake/SfizzFaust.cmake Normal file
View file

@ -0,0 +1,72 @@
include(CMakeParseArguments)
option(SFIZZ_RECOMPILE_FAUST "Recompile faust sources" OFF)
if(SFIZZ_RECOMPILE_FAUST)
find_program(RDMD "rdmd")
if(NOT RDMD)
message(FATAL_ERROR "rdmd is missing, it is required for regenerating faust sources.")
endif()
endif()
function(add_faust_command INPUT OUTPUT)
set(_options ONE_SAMPLE DOUBLE IN_PLACE VECTORIZE MATH_APPROXIMATION)
set(_one_args PROCESS_NAME CLASS_NAME SUPERCLASS_NAME)
set(_multi_args IMPORT_DIRS)
cmake_parse_arguments(_FAUST "${_options}" "${_one_args}" "${_multi_args}" ${ARGN})
if(NOT SFIZZ_RECOMPILE_FAUST)
return()
endif()
if(NOT RDMD)
return()
endif()
if(NOT INPUT)
message(FATAL_ERROR "No input file given.")
endif()
if(NOT OUTPUT)
message(FATAL_ERROR "No output file given.")
endif()
set(_cmd "${RDMD}" "${PROJECT_SOURCE_DIR}/scripts/faustwrap.d")
if(NOT IS_ABSOLUTE "${INPUT}")
set(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
endif()
if(NOT IS_ABSOLUTE "${OUTPUT}")
set(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/${OUTPUT}")
endif()
get_filename_component(_output_dir "${OUTPUT}" DIRECTORY)
file(MAKE_DIRECTORY "${_output_dir}")
list(APPEND _cmd "-o" "${OUTPUT}" "${INPUT}")
if(_FAUST_ONE_SAMPLE)
list(APPEND _cmd "--os")
endif()
if(_FAUST_DOUBLE)
list(APPEND _cmd "--double")
endif()
if(_FAUST_IN_PLACE)
list(APPEND _cmd "--inpl")
endif()
if(_FAUST_VECTORIZE)
list(APPEND _cmd "--vec")
endif()
if(_FAUST_MATH_APPROXIMATION)
list(APPEND _cmd "--mapp")
endif()
if(_FAUST_PROCESS_NAME)
list(APPEND _cmd "--pn" "${_FAUST_PROCESS_NAME}")
endif()
if(_FAUST_CLASS_NAME)
list(APPEND _cmd "--cn" "${_FAUST_CLASS_NAME}")
endif()
if(_FAUST_SUPERCLASS_NAME)
list(APPEND _cmd "--scn" "${_FAUST_SUPERCLASS_NAME}")
endif()
if (_FAUST_IMPORT_DIRS)
foreach(_dir IN LISTS _FAUST_IMPORT_DIRS)
if(NOT IS_ABSOLUTE "${_dir}")
set(_dir "${CMAKE_CURRENT_SOURCE_DIR}/${_dir}")
endif()
list(APPEND _cmd "--import-dir" "${_dir}")
endforeach()
endif()
add_custom_command(OUTPUT "${OUTPUT}" COMMAND ${_cmd} DEPENDS "${INPUT}")
endfunction()

View file

@ -1,7 +1,7 @@
macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
# It needs a macro, otherwise the source properties cannot take effect.
list (APPEND ${SOURCES_VAR}
list(APPEND ${SOURCES_VAR}
${PREFIX}/sfizz/SIMDHelpers.cpp
${PREFIX}/sfizz/simd/HelpersNEON.cpp
${PREFIX}/sfizz/simd/HelpersSSE.cpp
@ -9,10 +9,10 @@ macro(sfizz_add_simd_sources SOURCES_VAR PREFIX)
# For CPU-dispatched X86 sources
# Always build them for all X86 targets.
if (SFIZZ_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64|i.86|x86|X86)$")
if(SFIZZ_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64|x64|X64|i.86|x86|X86)$")
# on GCC, it requires to set ISA support flags on individual files
# to be able to use the intrinsics
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set_source_files_properties(
${PREFIX}/sfizz/effects/impl/ResonantStringAVX.cpp
${PREFIX}/sfizz/effects/impl/ResonantArrayAVX.cpp

View file

@ -7,12 +7,12 @@ if(NOT TARGET uninstall)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/MakeUninstall.cmake)
if (SFIZZ_LV2 AND LV2PLUGIN_INSTALL_DIR)
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)
if(SFIZZ_VST AND VSTPLUGIN_INSTALL_DIR)
add_custom_command(TARGET uninstall
COMMAND rm -rv "${VSTPLUGIN_INSTALL_DIR}/${PROJECT_NAME}.vst3")
endif()

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

View file

@ -1,22 +1,22 @@
set (VSTPLUGIN_NAME "sfizz")
set (VSTPLUGIN_VENDOR "Paul Ferrand")
set (VSTPLUGIN_URL "http://sfztools.github.io/sfizz")
set (VSTPLUGIN_EMAIL "paul@ferrand.cc")
set(VSTPLUGIN_NAME "sfizz")
set(VSTPLUGIN_VENDOR "Paul Ferrand")
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
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
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
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
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)
if(NOT VST3_SYSTEM_PROCESSOR)
set(VST3_SYSTEM_PROCESSOR "${SFIZZ_SYSTEM_PROCESSOR}")
endif()

110
common.mk
View file

@ -4,6 +4,10 @@ ifndef SFIZZ_DIR
$(error sfizz: The source directory must be set before including)
endif
### Options
SFIZZ_USE_SNDFILE ?= 0
###
SFIZZ_MACHINE := $(shell $(CC) -dumpmachine)
@ -44,7 +48,9 @@ SFIZZ_CXX_FLAGS = $(SFIZZ_C_FLAGS)
SFIZZ_SOURCES = \
src/sfizz/ADSREnvelope.cpp \
src/sfizz/AudioReader.cpp \
src/sfizz/BeatClock.cpp \
src/sfizz/Curve.cpp \
src/sfizz/Defaults.cpp \
src/sfizz/effects/Apan.cpp \
src/sfizz/Effects.cpp \
src/sfizz/modulations/ModId.cpp \
@ -52,6 +58,8 @@ SFIZZ_SOURCES = \
src/sfizz/modulations/ModKeyHash.cpp \
src/sfizz/modulations/ModMatrix.cpp \
src/sfizz/modulations/sources/ADSREnvelope.cpp \
src/sfizz/modulations/sources/ChannelAftertouch.cpp \
src/sfizz/modulations/sources/PolyAftertouch.cpp \
src/sfizz/modulations/sources/Controller.cpp \
src/sfizz/modulations/sources/FlexEnvelope.cpp \
src/sfizz/modulations/sources/LFO.cpp \
@ -81,16 +89,18 @@ SFIZZ_SOURCES = \
src/sfizz/FilterPool.cpp \
src/sfizz/FlexEGDescription.cpp \
src/sfizz/FlexEnvelope.cpp \
src/sfizz/FloatEnvelopes.cpp \
src/sfizz/Interpolators.cpp \
src/sfizz/Layer.cpp \
src/sfizz/Logger.cpp \
src/sfizz/LFO.cpp \
src/sfizz/LFODescription.cpp \
src/sfizz/Messaging.cpp \
src/sfizz/Metronome.cpp \
src/sfizz/MidiState.cpp \
src/sfizz/OpcodeCleanup.cpp \
src/sfizz/Opcode.cpp \
src/sfizz/Oversampler.cpp \
src/sfizz/Panning.cpp \
src/sfizz/Parser.cpp \
src/sfizz/parser/Parser.cpp \
src/sfizz/parser/ParserPrivate.cpp \
src/sfizz/PolyphonyGroup.cpp \
@ -102,22 +112,26 @@ SFIZZ_SOURCES = \
src/sfizz/sfizz.cpp \
src/sfizz/sfizz_wrapper.cpp \
src/sfizz/SfzFilter.cpp \
src/sfizz/SfzHelpers.cpp \
src/sfizz/SIMDHelpers.cpp \
src/sfizz/simd/HelpersSSE.cpp \
src/sfizz/simd/HelpersAVX.cpp \
src/sfizz/Smoothers.cpp \
src/sfizz/Synth.cpp \
src/sfizz/SynthMessaging.cpp \
src/sfizz/Tuning.cpp \
src/sfizz/utility/SpinMutex.cpp \
src/sfizz/utility/spin_mutex/SpinMutex.cpp \
src/sfizz/Voice.cpp \
src/sfizz/VoiceManager.cpp \
src/sfizz/VoiceStealing.cpp \
src/sfizz/Wavetables.cpp
src/sfizz/Wavetables.cpp \
src/sfizz/WindowedSinc.cpp
### Other internal
SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/sfizz
SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/external
SFIZZ_C_FLAGS += \
-I$(SFIZZ_DIR)/src/sfizz \
-I$(SFIZZ_DIR)/src/sfizz/utility/bit_array \
-I$(SFIZZ_DIR)/src/sfizz/utility/spin_mutex
# Pkg-config dependency
@ -125,13 +139,69 @@ SFIZZ_PKG_CONFIG ?= pkg-config
# Sndfile dependency
ifeq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_SNDFILE_C_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --cflags sndfile)
SFIZZ_SNDFILE_CXX_FLAGS ?= $(SFIZZ_SNDFILE_C_FLAGS)
SFIZZ_SNDFILE_LINK_FLAGS ?= $(shell $(SFIZZ_PKG_CONFIG) --libs sndfile)
SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS)
SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS)
SFIZZ_C_FLAGS += -DSFIZZ_USE_SNDFILE=1
SFIZZ_CXX_FLAGS += -DSFIZZ_USE_SNDFILE=1
endif
# st_audiofile dependency
SFIZZ_SOURCES += \
external/st_audiofile/src/st_audiofile.c \
external/st_audiofile/src/st_audiofile_common.c \
external/st_audiofile/src/st_audiofile_libs.c \
external/st_audiofile/src/st_audiofile_sndfile.c
ifneq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_SOURCES += \
external/st_audiofile/src/st_audiofile_libs.c
endif
SFIZZ_C_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/src \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/stb_vorbis
SFIZZ_CXX_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/src \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/dr_libs \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/stb_vorbis
ifeq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_C_FLAGS += $(SFIZZ_SNDFILE_C_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1
SFIZZ_CXX_FLAGS += $(SFIZZ_SNDFILE_CXX_FLAGS) -DST_AUDIO_FILE_USE_SNDFILE=1
SFIZZ_LINK_FLAGS += $(SFIZZ_SNDFILE_LINK_FLAGS)
endif
# libaiff dependency
ifneq ($(SFIZZ_USE_SNDFILE),1)
SFIZZ_SOURCES += \
external/st_audiofile/thirdparty/libaiff/libaiff.all.c
SFIZZ_C_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff
SFIZZ_CXX_FLAGS += \
-I$(SFIZZ_DIR)/external/st_audiofile/thirdparty/libaiff
endif
# hiir dependency
SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/src/external/hiir
# threadpool dependency
SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/threadpool
# atomic_queue dependency
SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/atomic_queue/include
# ghc::filesystem dependency
SFIZZ_CXX_FLAGS += -I$(SFIZZ_DIR)/external/filesystem/include
### Abseil dependency
@ -146,9 +216,6 @@ SFIZZ_SOURCES += \
# absl::exponential_biased
SFIZZ_SOURCES += \
external/abseil-cpp/absl/base/internal/exponential_biased.cc
# absl::dynamic_annotations
SFIZZ_SOURCES += \
external/abseil-cpp/absl/base/dynamic_annotations.cc
# absl::malloc_internal
SFIZZ_SOURCES += \
external/abseil-cpp/absl/base/internal/low_level_alloc.cc
@ -233,6 +300,9 @@ SFIZZ_SOURCES += \
# absl::city
SFIZZ_SOURCES += \
external/abseil-cpp/absl/hash/internal/city.cc
# absl::wyhash
SFIZZ_SOURCES += \
external/abseil-cpp/absl/hash/internal/wyhash.cc
# absl::int128
SFIZZ_SOURCES += \
external/abseil-cpp/absl/numeric/int128.cc
@ -255,6 +325,10 @@ SFIZZ_SOURCES += \
src/external/cpuid/src/cpuid/cpuinfo.cpp \
src/external/cpuid/src/cpuid/version.cpp
### simde dependency
SFIZZ_C_FLAGS += \
-I$(SFIZZ_DIR)/external/simde
### Pugixml dependency
SFIZZ_C_FLAGS += -I$(SFIZZ_DIR)/src/external/pugixml/src
@ -281,6 +355,12 @@ SFIZZ_SOURCES += \
SFIZZ_CXX_FLAGS += \
-I$(SFIZZ_DIR)/external/jsl/include
### cephes dependency
SFIZZ_SOURCES += \
external/cephes/src/chbevl.c \
external/cephes/src/i0.c
### math dependency
ifdef SFIZZ_OS_LINUX
@ -294,3 +374,9 @@ SFIZZ_C_FLAGS += -pthread
SFIZZ_CXX_FLAGS += -pthread
SFIZZ_LINK_FLAGS += -pthread
endif
### OpenMP dependency
SFIZZ_C_FLAGS += -fopenmp
SFIZZ_CXX_FLAGS += -fopenmp
SFIZZ_LINK_FLAGS += -fopenmp

51
demos/CMakeLists.txt Normal file
View file

@ -0,0 +1,51 @@
if(TARGET Qt5::Widgets AND TARGET sfizz::jack)
add_executable(sfizz_demo_filters DemoFilters.cpp)
target_link_libraries(sfizz_demo_filters PRIVATE sfizz::internal sfizz::jack Qt5::Widgets)
set_target_properties(sfizz_demo_filters PROPERTIES AUTOUIC ON)
add_executable(sfizz_demo_smooth DemoSmooth.cpp)
target_link_libraries(sfizz_demo_smooth PRIVATE sfizz::internal sfizz::jack Qt5::Widgets)
set_target_properties(sfizz_demo_smooth PROPERTIES AUTOUIC ON)
add_executable(sfizz_demo_stereo DemoStereo.cpp)
target_link_libraries(sfizz_demo_stereo PRIVATE sfizz::internal sfizz::jack Qt5::Widgets)
set_target_properties(sfizz_demo_stereo PROPERTIES AUTOUIC ON)
add_executable(sfizz_demo_wavetables DemoWavetables.cpp)
target_link_libraries(sfizz_demo_wavetables PRIVATE sfizz::internal sfizz::jack Qt5::Widgets)
set_target_properties(sfizz_demo_wavetables PROPERTIES AUTOUIC ON)
endif()
if(TARGET Qt5::Widgets)
add_executable(sfizz_demo_parser DemoParser.cpp)
target_link_libraries(sfizz_demo_parser PRIVATE sfizz::parser Qt5::Widgets)
set_target_properties(sfizz_demo_parser PROPERTIES AUTOUIC ON)
add_executable(sfizz_demo_stretch_tuning DemoStretchTuning.cpp)
target_link_libraries(sfizz_demo_stretch_tuning PRIVATE sfizz::internal Qt5::Widgets)
set_target_properties(sfizz_demo_stretch_tuning PROPERTIES AUTOUIC ON)
endif()
add_executable(eq_apply EQ.cpp)
target_link_libraries(eq_apply PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts sfizz::filesystem)
add_executable(filter_apply Filter.cpp)
target_link_libraries(filter_apply PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts sfizz::filesystem)
add_executable(sfizz_plot_curve PlotCurve.cpp)
target_link_libraries(sfizz_plot_curve PRIVATE sfizz::internal)
add_executable(sfizz_plot_wavetables PlotWavetables.cpp)
target_link_libraries(sfizz_plot_wavetables PRIVATE sfizz::internal)
add_executable(sfizz_plot_lfo PlotLFO.cpp)
target_link_libraries(sfizz_plot_lfo PRIVATE sfizz::internal sfizz::sndfile sfizz::cxxopts)
add_executable(sfizz_file_instrument FileInstrument.cpp)
target_link_libraries(sfizz_file_instrument PRIVATE sfizz::internal sfizz::sndfile)
add_executable(sfizz_file_wavetable FileWavetable.cpp)
target_link_libraries(sfizz_file_wavetable PRIVATE sfizz::internal)
add_executable(sfizz_tuning Tuning.cpp)
target_link_libraries(sfizz_tuning PRIVATE sfizz::internal sfizz::cxxopts)

View file

@ -247,7 +247,7 @@ void DemoApp::initWindow()
grpMode->setExclusive(true);
connect(
grpMode, QOverload<int, bool>::of(&QButtonGroup::buttonToggled), this,
grpMode, &QButtonGroup::idToggled, this,
[this](int id, bool toggled) {
if (toggled)
valueChangedFilterMode(id);

View file

@ -1,15 +1,13 @@
#include "sfizz/SfzFilter.h"
#include "sfizz/Buffer.h"
#include "sfizz/SIMDHelpers.h"
#include "ghc/filesystem.hpp"
#include "cxxopts.hpp"
#include "sfizz/StringViewHelpers.h"
#include "sfizz/utility/StringViewHelpers.h"
#include <sndfile.hh>
#include <cxxopts.hpp>
#include <ghc/fs_std.hpp>
#include <string>
#include <iostream>
namespace fs = ghc::filesystem;
int main(int argc, char** argv)
{
(void)argc;

View file

@ -12,20 +12,21 @@
static const char* modeString(int mode, const char* valueFallback = nullptr)
{
switch (mode) {
case SF_LOOP_NONE:
case sfz::LoopNone:
return "none";
case SF_LOOP_FORWARD:
case sfz::LoopForward:
return "forward";
case SF_LOOP_BACKWARD:
case sfz::LoopBackward:
return "backward";
case SF_LOOP_ALTERNATING:
case sfz::LoopAlternating:
return "alternating";
default:
return valueFallback;
}
}
static void printInstrument(const SF_INSTRUMENT& ins)
template <class Instrument>
static void printInstrument(const Instrument& ins)
{
printf("Gain: %d\n", ins.gain);
printf("Base note: %d\n", ins.basenote);
@ -34,7 +35,7 @@ static void printInstrument(const SF_INSTRUMENT& ins)
printf("Key: %d:%d\n", ins.key_lo, ins.key_hi);
printf("Loop count: %d\n", ins.loop_count);
for (int i = 0; i < ins.loop_count; ++i) {
for (unsigned i = 0, n = ins.loop_count; i < n; ++i) {
printf("\nLoop %d:\n", i + 1);
printf("\tMode: %s\n", modeString(ins.loops[i].mode, "(unknown)"));
printf("\tStart: %u\n", ins.loops[i].start);
@ -83,18 +84,18 @@ int main(int argc, char *argv[])
return 1;
}
SF_INSTRUMENT ins {};
if (method == kMethodRiff) {
sfz::FileMetadataReader reader;
if (!reader.open(path)) {
fprintf(stderr, "Cannot open file\n");
return 1;
}
if (!reader.extractRiffInstrument(ins)) {
sfz::InstrumentInfo ins {};
if (!reader.extractInstrument(ins)) {
fprintf(stderr, "Cannot get instrument\n");
return 1;
}
printInstrument(ins);
}
else {
SndfileHandle sndFile(path);
@ -102,13 +103,13 @@ int main(int argc, char *argv[])
fprintf(stderr, "Cannot open file\n");
return 1;
}
SF_INSTRUMENT ins {};
if (sndFile.command(SFC_GET_INSTRUMENT, &ins, sizeof(ins)) != 1) {
fprintf(stderr, "Cannot get instrument\n");
return 1;
}
printInstrument(ins);
}
printInstrument(ins);
return 0;
}

View file

@ -1,15 +1,13 @@
#include "sfizz/SfzFilter.h"
#include "sfizz/Buffer.h"
#include "sfizz/SIMDHelpers.h"
#include "ghc/filesystem.hpp"
#include "cxxopts.hpp"
#include "sfizz/StringViewHelpers.h"
#include "sfizz/utility/StringViewHelpers.h"
#include <sndfile.hh>
#include <cxxopts.hpp>
#include <ghc/fs_std.hpp>
#include <string>
#include <iostream>
namespace fs = ghc::filesystem;
int main(int argc, char** argv)
{
(void)argc;

View file

@ -17,12 +17,14 @@
#include "sfizz/Synth.h"
#include "sfizz/LFO.h"
#include "sfizz/Region.h"
#include "sfizz/LFODescription.h"
#include "sfizz/MathHelpers.h"
#include "cxxopts.hpp"
#include <absl/types/span.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <cmath>
#ifdef _WIN32
#define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1
@ -107,25 +109,34 @@ int main(int argc, char* argv[])
return 1;
}
constexpr size_t bufferSize = 1024;
sfz::Resources resources;
resources.setSamplesPerBlock(bufferSize);
size_t numLfos = desc.size();
std::vector<sfz::LFO> lfos(numLfos);
std::vector<std::unique_ptr<sfz::LFO>> lfos(numLfos);
for (size_t l = 0; l < numLfos; ++l) {
lfos[l].setSampleRate(sampleRate);
lfos[l].configure(&desc[l]);
sfz::LFO* lfo = new sfz::LFO(resources);
lfos[l].reset(lfo);
lfo->setSampleRate(sampleRate);
lfo->configure(&desc[l]);
}
size_t numFrames = (size_t)std::ceil(sampleRate * duration);
std::vector<float> outputMemory(numLfos * numFrames);
for (size_t l = 0; l < numLfos; ++l) {
lfos[l].start(0);
lfos[l]->start(0);
}
std::vector<absl::Span<float>> lfoOutputs(numLfos);
for (size_t l = 0; l < numLfos; ++l) {
lfoOutputs[l] = absl::MakeSpan(&outputMemory[l * numFrames], numFrames);
lfos[l].process(lfoOutputs[l]);
for (size_t i = 0, currentFrames; i < numFrames; i += currentFrames) {
currentFrames = std::min(numFrames - i, bufferSize);
lfos[l]->process(lfoOutputs[l].subspan(i, currentFrames));
}
}
if (saveFlac) {

View file

@ -1,18 +1,18 @@
###############################
# Developer tools
find_package(PkgConfig)
if(PKGCONFIG_FOUND)
pkg_check_modules(JACK "jack")
endif()
find_package(Qt5 COMPONENTS Widgets)
if(JACK_FOUND AND TARGET Qt5::Widgets)
if(TARGET sfizz::jack AND TARGET Qt5::Widgets)
add_executable(sfizz_capture_eg CaptureEG.h CaptureEG.cpp)
target_include_directories(sfizz_capture_eg PRIVATE . ${JACK_INCLUDE_DIRS})
target_link_libraries(sfizz_capture_eg PRIVATE sfizz-sndfile Qt5::Widgets ${JACK_LIBRARIES})
target_include_directories(sfizz_capture_eg PRIVATE .)
target_link_libraries(sfizz_capture_eg PRIVATE sfizz::sndfile Qt5::Widgets sfizz::jack)
set_target_properties(sfizz_capture_eg PROPERTIES AUTOUIC ON)
endif()
add_executable(sfizz_preprocessor Preprocessor.cpp)
target_link_libraries(sfizz_preprocessor sfizz_parser)
target_link_libraries(sfizz_preprocessor PRIVATE sfizz::parser sfizz::pugixml sfizz::cxxopts)
add_executable(sfizz_importer Importer.cpp)
target_link_libraries(sfizz_importer PRIVATE sfizz::import)
add_executable(sfizz_hiir_designer HIIRDesigner.cpp)
target_link_libraries(sfizz_hiir_designer PRIVATE sfizz::hiir_polyphase_iir2designer)

420
devtools/HIIRDesigner.cpp Normal file
View file

@ -0,0 +1,420 @@
// 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 <hiir/PolyphaseIir2Designer.h>
#include <vector>
#include <memory>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using FD = hiir::PolyphaseIir2Designer;
struct Stage {
int factor;
double tbw;
int nbr_coefs;
std::unique_ptr<double[]> coefs;
};
static std::vector<Stage> calculate_stages(int oversampling, double attenuation, double transition);
static void generate_cpp_prologue(int argc, char *argv[]);
static void generate_cpp_epilogue();
static void generate_cpp_coefs(const Stage *stages, int num_stages);
static void generate_cpp_upsampler(const Stage *stages, int num_stages);
static void generate_cpp_downsampler(const Stage *stages, int num_stages);
int main(int argc, char *argv[])
{
double attenuation = 0.0;
double transition = 0.0;
int oversampling = 16;
bool have_a = false;
bool have_t = false;
for (int argi = 1; argi < argc; ++argi) {
const char *arg = argv[argi];
if (!strcmp(arg, "-a")) {
if (++argi >= argc) {
fprintf(stderr, "The option %s expects a value.\n", arg);
return 1;
}
arg = argv[argi];
attenuation = atof(arg);
have_a = true;
}
else if (!strcmp(arg, "-t")) {
if (++argi >= argc) {
fprintf(stderr, "The option %s expects a value.\n", arg);
return 1;
}
arg = argv[argi];
transition = atof(arg);
have_t = true;
}
else if (!strcmp(arg, "-o")) {
if (++argi >= argc) {
fprintf(stderr, "The option %s expects a value.\n", arg);
return 1;
}
arg = argv[argi];
oversampling = atoi(arg);
}
else {
fprintf(stderr, "Unrecognized argument: %s\n", arg);
return 1;
}
}
if (!have_a) {
fprintf(stderr, "No attenuation given (-a)\n");
return 1;
}
if (!have_t) {
fprintf(stderr, "No transition bandwidth given (-t)\n");
return 1;
}
else if (attenuation < 0.0) {
fprintf(stderr, "Invalid attenuation\n");
return 1;
}
else if (transition <= 0.0 || transition >= 0.5) {
fprintf(stderr, "Invalid transition bandwidth\n");
return 1;
}
else if (oversampling < 2) {
fprintf(stderr, "Invalid oversampling\n");
return 1;
}
std::vector<Stage> stages = calculate_stages(oversampling, attenuation, transition);
int num_stages = (int)stages.size();
// generate the coeffs
generate_cpp_prologue(argc, argv);
printf("\n");
generate_cpp_coefs(stages.data(), num_stages);
printf("\n");
generate_cpp_upsampler(stages.data(), num_stages);
printf("\n");
generate_cpp_downsampler(stages.data(), num_stages);
printf("\n");
generate_cpp_epilogue();
return 0;
}
static std::vector<Stage> calculate_stages(int oversampling, double attenuation, double transition)
{
std::vector<Stage> stages;
stages.reserve(8);
bool done = false;
for (int num_stage = 0; !done; ++num_stage) {
if (num_stage > 0)
printf("\n");
Stage stage;
stage.factor = 2 << num_stage;
stage.tbw = transition *
std::pow(0.5, num_stage) + 0.5 * (1 - std::pow(0.5, num_stage));
stage.nbr_coefs = FD::compute_nbr_coefs_from_proto(attenuation, stage.tbw);
double *coefs = new double[stage.nbr_coefs]{};
stage.coefs.reset(coefs);
FD::compute_coefs(coefs, attenuation, stage.tbw);
done = stage.factor >= oversampling;
stages.push_back(std::move(stage));
}
return stages;
}
static void generate_cpp_prologue(int argc, char *argv[])
{
printf("//------------------------------------------------------------------------------\n");
printf("// This is generated by the Sfizz HIIR designer\n");
printf("// Using options:");
for (int i = 1; i < argc; ++i)
printf(" %s", argv[i]);
printf("\n");
printf("//------------------------------------------------------------------------------\n");
printf("\n");
printf(
"#pragma once\n"
"#include \"OversamplerHelpers.h\"\n"
"#include \"MathHelpers\"\n"
"\n"
"namespace sfz {\n"
);
}
static void generate_cpp_epilogue()
{
printf("} // namespace sfz\n");
}
static void generate_cpp_coefs(const Stage *stages, int num_stages)
{
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
const double *coefs = stage.coefs.get();
printf("// %dx <-> %dx: TBW = %g\n", stage.factor, stage.factor / 2, stage.tbw);
printf("static constexpr double OSCoeffs%dx[%d] = {\n", stage.factor, stage.nbr_coefs);
for (int i = 0; i < stage.nbr_coefs; ++i) {
printf("\t" "%.18f,\n", coefs[i]);
}
printf("};\n");
}
}
static void generate_cpp_upsampler(const Stage *stages, int num_stages)
{
printf("class Upsampler {\n");
printf("public:\n");
printf("\t" "Upsampler()\n");
printf("\t" "{\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t\t" "up%d_.set_coefs(OSCoeffs%dx);\n", stage.factor, stage.factor);
}
printf("\t" "}\n");
printf("\t" "void clear()\n");
printf("\t" "{\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t\t" "up%d_.clear_buffers();\n", stage.factor);
}
printf("\t" "}\n");
printf("\t" "static int recommendedBuffer(int factor, int spl)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
printf("\t\t" "case 2:\n");
printf("\t\t\t" "return 0;\n");
printf("\t\t" "case 4:\n");
printf("\t\t\t" "return 2 * spl;\n");
printf("\t\t" "default:\n");
printf("\t\t\t" "return factor * spl;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
printf("\t" "static unsigned conversionFactor(double sourceRate, double targetRate)\n");
printf("\t" "{\n");
printf("\t\t" "int factor = static_cast<int>(std::ceil(targetRate / sourceRate));\n");
printf("\t\t" "factor = (factor > 1) ? factor : 1;\n");
printf("\t\t" "factor = (factor < 128) ? factor : 128;\n");
printf("\t\t" "return nextPow2(factor);\n");
printf("\t" "}\n");
printf("\t" "static bool canProcess(int factor)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
printf("\t\t" "case 1:\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t\t" "case %d:\n", stage.factor);
}
printf("\t\t\t" "return true;\n");
printf("\t\t" "default:\n");
printf("\t\t\t" "return false;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
printf("\t" "void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
printf("\t\t" "case 1:\n");
printf("\t\t\t" "if (in != out) std::memcpy(out, in, spl * sizeof(float));\n");
printf("\t\t\t" "break;\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t\t" "case %d:\n", stage.factor);
printf("\t\t\t" "process%dx(in, out, spl, temp, ntemp);\n", stage.factor);
printf("\t\t\t" "break;\n");
}
printf("\t\t" "default:\n");
printf("\t\t\t" "ASSERTFALSE;\n");
printf("\t\t\t" "break;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
for (int n = 1; n <= num_stages; ++n) {
// special case factor=2, buffer not required
if (stages[n - 1].factor == 2) {
printf("\t" "void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0)\n");
printf("\t" "{\n");
printf("\t\t" "up2_.process_block(out, in, spl);\n");
printf("\t" "}\n");
continue;
}
printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor);
printf("\t" "{\n");
// special case factor=4, only 1 buffer required
if (stages[n - 1].factor > 4)
printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor);
else
printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor / 2);
printf("\t\t" "ASSERT(maxspl > 0);\n");
printf("\t\t" "float *t1 = temp;\n");
if (stages[n - 1].factor > 4)
printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2);
printf("\t\t" "while (spl > 0) {\n");
printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n");
for (int i = 0; i < n; ++i) {
const Stage &stage = stages[i];
const char *tempnames[] = {"t1", "t2"};
const char *outname = tempnames[i & 1];
const char *inname = tempnames[1 - (i & 1)];
if (i == 0)
inname = "in";
if (i + 1 == n)
outname = "out";
printf("\t\t\t" "up%d_.process_block(%s, %s, %d * curspl);\n", stage.factor, outname, inname, stage.factor / 2);
}
printf("\t\t\t" "in += curspl;\n");
printf("\t\t\t" "out += curspl;\n");
printf("\t\t\t" "spl -= curspl;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
}
printf("private:\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t" "hiir::Upsampler2x<%d> up%d_;\n", stage.nbr_coefs, stage.factor);
}
printf("};\n");
}
static void generate_cpp_downsampler(const Stage *stages, int num_stages)
{
printf("class Downsampler {\n");
printf("public:\n");
printf("\t" "Downsampler()\n");
printf("\t" "{\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[num_stages - 1 - i];
printf("\t\t" "down%d_.set_coefs(OSCoeffs%dx);\n", stage.factor, stage.factor);
}
printf("\t" "}\n");
printf("\t" "void clear()\n");
printf("\t" "{\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[num_stages - 1 - i];
printf("\t\t" "down%d_.clear_buffers();\n", stage.factor);
}
printf("\t" "}\n");
printf("\t" "static int recommendedBuffer(int factor, int spl)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
printf("\t\t" "case 2:\n");
printf("\t\t\t" "return 0;\n");
printf("\t\t" "case 4:\n");
printf("\t\t\t" "return 2 * spl;\n");
printf("\t\t" "default:\n");
printf("\t\t\t" "return factor * spl;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
printf("\t" "static unsigned conversionFactor(double sourceRate, double targetRate)\n");
printf("\t" "{\n");
printf("\t\t" "int factor = static_cast<int>(std::ceil(targetRate / sourceRate));\n");
printf("\t\t" "factor = (factor > 1) ? factor : 1;\n");
printf("\t\t" "factor = (factor < 128) ? factor : 128;\n");
printf("\t\t" "return nextPow2(factor);\n");
printf("\t" "}\n");
printf("\t" "static bool canProcess(int factor)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
printf("\t\t" "case 1:\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[i];
printf("\t\t" "case %d:\n", stage.factor);
}
printf("\t\t\t" "return true;\n");
printf("\t\t" "default:\n");
printf("\t\t\t" "return false;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
printf("\t" "void process(int factor, const float *in, float *out, int spl, float *temp, int ntemp)\n");
printf("\t" "{\n");
printf("\t\t" "switch (factor) {\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[num_stages - 1 - i];
printf("\t\t" "case %d:\n", stage.factor);
printf("\t\t\t" "process%dx(in, out, spl, temp, ntemp);\n", stage.factor);
printf("\t\t\t" "break;\n");
}
printf("\t\t" "case 1:\n");
printf("\t\t\t" "if (in != out) std::memcpy(out, in, spl * sizeof(float));\n");
printf("\t\t\t" "break;\n");
printf("\t\t" "default:\n");
printf("\t\t\t" "ASSERTFALSE;\n");
printf("\t\t\t" "break;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
for (int n = 1; n <= num_stages; ++n) {
// special case factor=2, buffer not required
if (stages[n - 1].factor == 2) {
printf("\t" "void process2x(const float *in, float *out, int spl, float * = nullptr, int = 0)\n");
printf("\t" "{\n");
printf("\t\t" "down2_.process_block(out, in, spl);\n");
printf("\t" "}\n");
continue;
}
printf("\t" "void process%dx(const float *in, float *out, int spl, float *temp, int ntemp)\n", stages[n - 1].factor);
printf("\t" "{\n");
// special case factor=4, only 1 buffer required
if (stages[n - 1].factor > 4)
printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor);
else
printf("\t\t" "int maxspl = ntemp / %d;\n", stages[n - 1].factor / 2);
printf("\t\t" "ASSERT(maxspl > 0);\n");
printf("\t\t" "float *t1 = temp;\n");
if (stages[n - 1].factor > 4)
printf("\t\t" "float *t2 = temp + %d * maxspl;\n", stages[n - 1].factor / 2);
printf("\t\t" "while (spl > 0) {\n");
printf("\t\t\t" "int curspl = (spl < maxspl) ? spl : maxspl;\n");
for (int i = 0; i < n; ++i) {
const Stage &stage = stages[n - 1 - i];
const char *tempnames[] = {"t1", "t2"};
const char *outname = tempnames[i & 1];
const char *inname = tempnames[1 - (i & 1)];
if (i == 0)
inname = "in";
if (i + 1 == n)
outname = "out";
printf("\t\t\t" "down%d_.process_block(%s, %s, %d * curspl);\n", stage.factor, outname, inname, stage.factor / 2);
}
printf("\t\t\t" "in += curspl;\n");
printf("\t\t\t" "out += curspl;\n");
printf("\t\t\t" "spl -= curspl;\n");
printf("\t\t" "}\n");
printf("\t" "}\n");
}
printf("private:\n");
for (int i = 0; i < num_stages; ++i) {
const Stage &stage = stages[num_stages - 1 - i];
printf("\t" "hiir::Downsampler2x<%d> down%d_;\n", stage.nbr_coefs, stage.factor);
}
printf("};\n");
}

39
devtools/Importer.cpp Normal file
View file

@ -0,0 +1,39 @@
#include "sfizz/import/ForeignInstrument.h"
#include <iostream>
int main(int argc, char* argv[])
{
const sfz::InstrumentFormatRegistry& formatRegistry = sfz::InstrumentFormatRegistry::getInstance();
if (argc != 2) {
std::cerr << "Usage: sfizz_importer <foreign-instrument>\n";
std::cerr << "--\n" "Supported formats:\n";
for (const sfz::InstrumentFormat* format : formatRegistry.getAllFormats())
std::cerr << " * " << format->name() << '\n';
return 1;
}
const fs::path foreignPath = fs::u8path(argv[1]);
const sfz::InstrumentFormat* format = formatRegistry.getMatchingFormat(foreignPath);
if (!format) {
std::cerr << "There is no support for files of this format.\n";
return 1;
}
auto importer = format->createImporter();
std::string text = importer->convertToSfz(foreignPath);
if (text.empty()) {
std::cerr << "The conversion has failed.\n";
return 1;
}
std::cout << text;
if (text.back() != '\n')
std::cout << '\n';
std::cout << std::flush;
return 0;
}

View file

@ -13,10 +13,18 @@
*/
#include "parser/Parser.h"
#include "../tests/cxxopts.hpp"
#include "absl/strings/string_view.h"
#include <pugixml.hpp>
#include <cxxopts.hpp>
#include <absl/strings/string_view.h>
#include <iostream>
namespace {
enum Mode { OutputSFZ, OutputXML };
Mode g_mode = OutputSFZ;
pugi::xml_document g_xml_doc;
}
class MyParserListener : public sfz::Parser::Listener {
public:
explicit MyParserListener(sfz::Parser& parser)
@ -27,10 +35,20 @@ public:
protected:
void onParseFullBlock(const std::string& header, const std::vector<sfz::Opcode>& opcodes) override
{
std::cout << '\n';
std::cout << '<' << header << '>' << '\n';
for (const sfz::Opcode& opc : opcodes)
std::cout << opc.opcode << '=' << opc.value << '\n';
if (g_mode == OutputSFZ) {
std::cout << '\n';
std::cout << '<' << header << '>' << '\n';
for (const sfz::Opcode& opc : opcodes)
std::cout << opc.name << '=' << opc.value << '\n';
}
else if (g_mode == OutputXML) {
pugi::xml_node block_node = g_xml_doc.append_child(header.c_str());
for (const sfz::Opcode& opc : opcodes) {
pugi::xml_node opcode_node = block_node.append_child("opcode");
opcode_node.append_attribute("name").set_value(opc.name.c_str());
opcode_node.append_attribute("value").set_value(opc.value.c_str());
}
}
}
void onParseError(const sfz::SourceRange& range, const std::string& message) override
@ -58,6 +76,7 @@ int main(int argc, char *argv[])
options.add_options()
("D,define", "Add external definition", cxxopts::value<std::vector<std::string>>())
("i,input", "Input SFZ file", cxxopts::value<std::string>())
("m,mode", "Mode of operation (sfz, xml)", cxxopts::value<std::string>())
("h,help", "Print usage");
options.parse_positional({"input"});
@ -81,6 +100,18 @@ int main(int argc, char *argv[])
return 1;
}
if (result.count("mode")) {
const std::string& modeString = result["mode"].as<std::string>();
if (modeString == "sfz")
g_mode = OutputSFZ;
else if (modeString == "xml")
g_mode = OutputXML;
else {
std::cerr << "Unknown mode of operation: " << modeString << "\n";
return 1;
}
}
const fs::path sfzFilePath { result["input"].as<std::string>() };
sfz::Parser parser;
@ -106,5 +137,8 @@ int main(int argc, char *argv[])
if (parser.getErrorCount() > 0)
return 1;
if (g_mode == OutputXML)
g_xml_doc.save(std::cout);
return 0;
}

View file

@ -1,88 +0,0 @@
set(VSTGUI_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/vstgui4")
include("cmake/Vstgui.cmake")
set(EDITOR_RESOURCES
logo.png
logo_text.png
logo_text_white.png
logo_text@2x.png
logo_text_white@2x.png
background.png
background@2x.png
icon_white.png
icon_white@2x.png
knob48.png
knob48@2x.png
Fonts/sfizz-fluentui-system-r20.ttf
Fonts/Roboto-Regular.ttf
PARENT_SCOPE)
function(copy_editor_resources SOURCE_DIR DESTINATION_DIR)
foreach(res ${EDITOR_RESOURCES})
get_filename_component(_dir "${res}" DIRECTORY)
file(MAKE_DIRECTORY "${DESTINATION_DIR}/${_dir}")
file(COPY "${SOURCE_DIR}/${res}" DESTINATION "${DESTINATION_DIR}/${_dir}")
endforeach()
endfunction()
# editor
add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
src/editor/EditIds.h
src/editor/EditIds.cpp
src/editor/Editor.h
src/editor/Editor.cpp
src/editor/EditorController.h
src/editor/GUIComponents.h
src/editor/GUIComponents.cpp
src/editor/GUIPiano.h
src/editor/GUIPiano.cpp
src/editor/NativeHelpers.h
src/editor/NativeHelpers.cpp
src/editor/layout/main.hpp
src/editor/utility/vstgui_after.h
src/editor/utility/vstgui_before.h)
target_include_directories(sfizz_editor PUBLIC "src")
target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui)
target_link_libraries(sfizz_editor PUBLIC absl::strings)
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)
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
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_include_directories(sfizz_editor PRIVATE "../src/external") # ghc::filesystem
# 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)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/main.hpp"
COMMAND "$<TARGET_FILE:layout-maker>"
"${CMAKE_CURRENT_SOURCE_DIR}/layout/main.fl"
> "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/main.hpp"
DEPENDS layout-maker "${CMAKE_CURRENT_SOURCE_DIR}/layout/main.fl")
endif()

@ -1 +0,0 @@
Subproject commit 055cbcc9ae858f0b07d5d86c205a1111e2fba7a4

View file

@ -1,37 +0,0 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include <cassert>
enum class EditId : int {
SfzFile,
Volume,
Polyphony,
Oversampling,
PreloadSize,
ScalaFile,
ScalaRootKey,
TuningFrequency,
StretchTuning,
UINumCurves,
UINumMasters,
UINumGroups,
UINumRegions,
UINumPreloadedSamples,
UINumActiveVoices,
UIActivePanel,
};
struct EditRange {
float def = 0.0;
float min = 0.0;
float max = 1.0;
constexpr EditRange() = default;
constexpr EditRange(float def, float min, float max)
: def(def), min(min), max(max) {}
static EditRange get(EditId id);
};

View file

@ -1,495 +0,0 @@
// 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 "GUIComponents.h"
#include <complex>
#include <cmath>
#include "utility/vstgui_before.h"
#include "vstgui/lib/cdrawcontext.h"
#include "vstgui/lib/cgraphicspath.h"
#include "vstgui/lib/cframe.h"
#include "utility/vstgui_after.h"
///
SBoxContainer::SBoxContainer(const CRect& size)
: CViewContainer(size)
{
CViewContainer::setBackgroundColor(CColor(0, 0, 0, 0));
}
void SBoxContainer::setCornerRadius(CCoord radius)
{
cornerRadius_ = radius;
invalid();
}
void SBoxContainer::setBackgroundColor(const CColor& color)
{
backgroundColor_ = color;
invalid();
}
CColor SBoxContainer::getBackgroundColor() const
{
return backgroundColor_;
}
void SBoxContainer::drawRect(CDrawContext* dc, const CRect& updateRect)
{
CRect bounds = getViewSize();
dc->setDrawMode(kAntiAliasing);
SharedPointer<CGraphicsPath> path = owned(dc->createGraphicsPath());
path->addRoundRect(bounds, cornerRadius_);
dc->setFillColor(backgroundColor_);
dc->drawGraphicsPath(path.get(), CDrawContext::kPathFilled);
CViewContainer::drawRect(dc, updateRect);
}
///
STitleContainer::STitleContainer(const CRect& size, UTF8StringPtr text)
: SBoxContainer(size), text_(text ? text : ""), titleFont_(kNormalFont)
{
}
void STitleContainer::setTitleFont(CFontRef font)
{
titleFont_ = font;
invalid();
}
void STitleContainer::setTitleFontColor(CColor color)
{
titleFontColor_ = color;
invalid();
}
void STitleContainer::setTitleBackgroundColor(CColor color)
{
titleBackgroundColor_ = color;
invalid();
}
void STitleContainer::drawRect(CDrawContext* dc, const CRect& updateRect)
{
SBoxContainer::drawRect(dc, updateRect);
CRect bounds = getViewSize();
CCoord cornerRadius = cornerRadius_;
dc->setDrawMode(kAntiAliasing);
CCoord fontHeight = titleFont_->getSize();
CCoord titleHeight = fontHeight + 8.0;
CRect titleBounds = bounds;
titleBounds.bottom = titleBounds.top + titleHeight;
SharedPointer<CGraphicsPath> path = owned(dc->createGraphicsPath());
path->beginSubpath(titleBounds.getBottomRight());
path->addLine(titleBounds.getBottomLeft());
path->addArc(CRect(titleBounds.left, titleBounds.top, titleBounds.left + 2.0 * cornerRadius, titleBounds.top + 2.0 * cornerRadius), 180., 270., true);
path->addArc(CRect(titleBounds.right - 2.0 * cornerRadius, titleBounds.top, titleBounds.right, titleBounds.top + 2.0 * cornerRadius), 270., 360., true);
path->closeSubpath();
dc->setFillColor(titleBackgroundColor_);
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
dc->setFont(titleFont_);
dc->setFontColor(titleFontColor_);
dc->drawString(text_.c_str(), titleBounds, kCenterText);
}
///
void SFileDropTarget::setFileDropFunction(FileDropFunction f)
{
dropFunction_ = std::move(f);
}
DragOperation SFileDropTarget::onDragEnter(DragEventData data)
{
op_ = isFileDrop(data.drag) ?
DragOperation::Copy : DragOperation::None;
return op_;
}
DragOperation SFileDropTarget::onDragMove(DragEventData data)
{
(void)data;
return op_;
}
void SFileDropTarget::onDragLeave(DragEventData data)
{
(void)data;
op_ = DragOperation::None;
}
bool SFileDropTarget::onDrop(DragEventData data)
{
if (op_ != DragOperation::Copy || !isFileDrop(data.drag))
return false;
IDataPackage::Type type;
const void* bytes;
uint32_t size = data.drag->getData(0, bytes, type);
std::string path(reinterpret_cast<const char*>(bytes), size);
if (dropFunction_)
dropFunction_(path);
return true;
}
bool SFileDropTarget::isFileDrop(IDataPackage* package)
{
return package->getCount() == 1 &&
package->getDataType(0) == IDataPackage::kFilePath;
}
///
SValueMenu::SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag)
: CParamDisplay(bounds), menuListener_(owned(new MenuListener(*this)))
{
setListener(listener);
setTag(tag);
}
CMenuItem* SValueMenu::addEntry(CMenuItem* item, float value, int32_t index)
{
if (index < 0 || index > getNbEntries()) {
menuItems_.emplace_back(owned(item));
menuItemValues_.emplace_back(value);
}
else
{
menuItems_.insert(menuItems_.begin() + index, owned(item));
menuItemValues_.insert(menuItemValues_.begin() + index, value);
}
return item;
}
CMenuItem* SValueMenu::addEntry(const UTF8String& title, float value, int32_t index, int32_t itemFlags)
{
if (title == "-")
return addSeparator(index);
CMenuItem* item = new CMenuItem(title, nullptr, 0, nullptr, itemFlags);
return addEntry(item, value, index);
}
CMenuItem* SValueMenu::addSeparator(int32_t index)
{
CMenuItem* item = new CMenuItem("", nullptr, 0, nullptr, CMenuItem::kSeparator);
return addEntry(item, 0.0f, index);
}
int32_t SValueMenu::getNbEntries() const
{
return static_cast<int32_t>(menuItems_.size());
}
CMouseEventResult SValueMenu::onMouseDown(CPoint& where, const CButtonState& buttons)
{
(void)where;
if (buttons & (kLButton|kRButton|kApple)) {
CFrame* frame = getFrame();
CRect bounds = getViewSize();
CPoint frameWhere = bounds.getBottomLeft();
this->localToFrame(frameWhere);
auto self = shared(this);
frame->doAfterEventProcessing([self, frameWhere]() {
if (CFrame* frame = self->getFrame()) {
SharedPointer<COptionMenu> menu = owned(new COptionMenu(CRect(), self->menuListener_, -1, nullptr, nullptr, COptionMenu::kPopupStyle));
for (const SharedPointer<CMenuItem>& item : self->menuItems_) {
menu->addEntry(item);
item->remember(); // above call does not increment refcount
}
menu->setFont(self->getFont());
menu->setFontColor(self->getFontColor());
menu->setBackColor(self->getBackColor());
menu->popup(frame, frameWhere + CPoint(0.0, 1.0));
}
});
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
}
return kMouseEventNotHandled;
}
void SValueMenu::onItemClicked(int32_t index)
{
float oldValue = getValue();
setValue(menuItemValues_[index]);
if (getValue() != oldValue)
valueChanged();
}
///
SActionMenu::SActionMenu(const CRect& bounds, IControlListener* listener)
: CParamDisplay(bounds), menuListener_(owned(new MenuListener(*this)))
{
setListener(listener);
auto toString = [](float, std::string& result, CParamDisplay* display) {
result = static_cast<SActionMenu*>(display)->getTitle();
return true;
};
setValueToStringFunction2(toString);
}
void SActionMenu::setTitle(std::string title)
{
title_ = std::move(title);
invalid();
}
void SActionMenu::setHoverColor(const CColor& color)
{
hoverColor_ = color;
invalid();
}
CMenuItem* SActionMenu::addEntry(CMenuItem* item, int32_t tag, int32_t index)
{
if (index < 0 || index > getNbEntries()) {
menuItems_.emplace_back(owned(item));
menuItemTags_.emplace_back(tag);
}
else
{
menuItems_.insert(menuItems_.begin() + index, owned(item));
menuItemTags_.insert(menuItemTags_.begin() + index, tag);
}
return item;
}
CMenuItem* SActionMenu::addEntry(const UTF8String& title, int32_t tag, int32_t index, int32_t itemFlags)
{
if (title == "-")
return addSeparator(index);
CMenuItem* item = new CMenuItem(title, nullptr, 0, nullptr, itemFlags);
return addEntry(item, tag, index);
}
CMenuItem* SActionMenu::addSeparator(int32_t index)
{
CMenuItem* item = new CMenuItem("", nullptr, 0, nullptr, CMenuItem::kSeparator);
return addEntry(item, 0.0f, index);
}
int32_t SActionMenu::getNbEntries() const
{
return static_cast<int32_t>(menuItems_.size());
}
void SActionMenu::draw(CDrawContext* dc)
{
CColor backupColor = fontColor;
if (hovered_)
fontColor = hoverColor_;
CParamDisplay::draw(dc);
if (hovered_)
fontColor = backupColor;
}
CMouseEventResult SActionMenu::onMouseEntered(CPoint& where, const CButtonState& buttons)
{
hovered_ = true;
invalid();
return CParamDisplay::onMouseEntered(where, buttons);
}
CMouseEventResult SActionMenu::onMouseExited(CPoint& where, const CButtonState& buttons)
{
hovered_ = false;
invalid();
return CParamDisplay::onMouseExited(where, buttons);
}
CMouseEventResult SActionMenu::onMouseDown(CPoint& where, const CButtonState& buttons)
{
(void)where;
if (buttons & (kLButton|kRButton|kApple)) {
CFrame* frame = getFrame();
CRect bounds = getViewSize();
CPoint frameWhere = bounds.getBottomLeft();
this->localToFrame(frameWhere);
auto self = shared(this);
frame->doAfterEventProcessing([self, frameWhere]() {
if (CFrame* frame = self->getFrame()) {
SharedPointer<COptionMenu> menu = owned(new COptionMenu(CRect(), self->menuListener_, -1, nullptr, nullptr, COptionMenu::kPopupStyle));
for (const SharedPointer<CMenuItem>& item : self->menuItems_) {
menu->addEntry(item);
item->remember(); // above call does not increment refcount
}
menu->setFont(self->getFont());
menu->setFontColor(self->getFontColor());
menu->setBackColor(self->getBackColor());
menu->popup(frame, frameWhere + CPoint(0.0, 1.0));
}
});
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
}
return kMouseEventNotHandled;
}
void SActionMenu::onItemClicked(int32_t index)
{
setTag(menuItemTags_[index]);
setValue(1.0f);
if (listener)
listener->valueChanged(this);
setValue(0.0f);
if (listener)
listener->valueChanged(this);
}
///
void STextButton::setHoverColor(const CColor& color)
{
hoverColor_ = color;
invalid();
}
void STextButton::setInactiveColor(const CColor& color)
{
inactiveColor_ = color;
invalid();
}
void STextButton::setInactive(bool b)
{
inactive_ = b;
invalid();
}
void STextButton::draw(CDrawContext* context)
{
CColor backupColor = textColor;
if (hovered_)
textColor = hoverColor_; // textColor is protected
else if (inactive_)
textColor = inactiveColor_;
CTextButton::draw(context);
textColor = backupColor;
}
CMouseEventResult STextButton::onMouseEntered (CPoint& where, const CButtonState& buttons)
{
hovered_ = true;
invalid();
return CTextButton::onMouseEntered(where, buttons);
}
CMouseEventResult STextButton::onMouseExited (CPoint& where, const CButtonState& buttons)
{
hovered_ = false;
invalid();
return CTextButton::onMouseExited(where, buttons);
}
///
SStyledKnob::SStyledKnob(const CRect& size, IControlListener* listener, int32_t tag)
: CKnobBase(size, listener, tag, nullptr)
{
}
void SStyledKnob::setActiveTrackColor(const CColor& color)
{
if (activeTrackColor_ == color)
return;
activeTrackColor_ = color;
invalid();
}
void SStyledKnob::setInactiveTrackColor(const CColor& color)
{
if (inactiveTrackColor_ == color)
return;
inactiveTrackColor_ = color;
invalid();
}
void SStyledKnob::setLineIndicatorColor(const CColor& color)
{
if (lineIndicatorColor_ == color)
return;
lineIndicatorColor_ = color;
invalid();
}
void SStyledKnob::draw(CDrawContext* dc)
{
const CCoord lineWidth = 4.0;
const CCoord indicatorLineLength = 10.0;
const CCoord angleSpread = 250.0;
const CCoord angle1 = 270.0 - 0.5 * angleSpread;
const CCoord angle2 = 270.0 + 0.5 * angleSpread;
dc->setDrawMode(kAntiAliasing);
const CRect bounds = getViewSize();
// compute inner bounds
CRect rect(bounds);
rect.setWidth(std::min(rect.getWidth(), rect.getHeight()));
rect.setHeight(rect.getWidth());
rect.centerInside(bounds);
rect.extend(-lineWidth, -lineWidth);
SharedPointer<CGraphicsPath> path;
// inactive track
path = owned(dc->createGraphicsPath());
path->addArc(rect, angle1, angle2, true);
dc->setFrameColor(inactiveTrackColor_);
dc->setLineWidth(lineWidth);
dc->setLineStyle(kLineSolid);
dc->drawGraphicsPath(path, CDrawContext::kPathStroked);
// active track
const CCoord v = getValueNormalized();
const CCoord vAngle = angle1 + v * angleSpread;
path = owned(dc->createGraphicsPath());
path->addArc(rect, angle1, vAngle, true);
dc->setFrameColor(activeTrackColor_);
dc->setLineWidth(lineWidth + 0.5);
dc->setLineStyle(kLineSolid);
dc->drawGraphicsPath(path, CDrawContext::kPathStroked);
// indicator line
{
CCoord module1 = 0.5 * rect.getWidth() - indicatorLineLength;
CCoord module2 = 0.5 * rect.getWidth();
std::complex<CCoord> c1 = std::polar(module1, vAngle * (M_PI / 180.0));
std::complex<CCoord> c2 = std::polar(module2, vAngle * (M_PI / 180.0));
CPoint p1(c1.real(), c1.imag());
CPoint p2(c2.real(), c2.imag());
p1.offset(rect.getCenter());
p2.offset(rect.getCenter());
dc->setFrameColor(lineIndicatorColor_);
dc->setLineWidth(1.0);
dc->setLineStyle(kLineSolid);
dc->drawLine(p1, p2);
}
}

View file

@ -1,238 +0,0 @@
// 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 "GUIPiano.h"
#include "utility/vstgui_before.h"
#include "vstgui/lib/cdrawcontext.h"
#include "vstgui/lib/cgraphicspath.h"
#include "utility/vstgui_after.h"
#include <algorithm>
#include <cmath>
static constexpr CCoord keyoffs[12] = {0, 0.6, 1, 1.8, 2, 3,
3.55, 4, 4.7, 5, 5.85, 6};
static constexpr bool black[12] = {0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0};
SPiano::SPiano(CRect bounds)
: CView(bounds)
{
setNumOctaves(10);
}
void SPiano::setFont(CFontRef font)
{
font_ = font;
getDimensions(true);
invalid();
}
void SPiano::setNumOctaves(unsigned octs)
{
keyval_.resize(octs * 12);
octs_ = std::max(1u, octs);
getDimensions(true);
invalid();
}
void SPiano::draw(CDrawContext* dc)
{
const Dimensions dim = getDimensions(false);
const unsigned octs = octs_;
const unsigned keyCount = octs * 12;
dc->setDrawMode(kAntiAliasing);
if (backgroundFill_.alpha > 0) {
SharedPointer<CGraphicsPath> path;
path = owned(dc->createGraphicsPath());
path->addRoundRect(dim.bounds, backgroundRadius_);
dc->setFillColor(CColor(0xca, 0xca, 0xca));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
}
for (unsigned key = 0; key < keyCount; ++key) {
if (!black[key % 12]) {
CRect rect = keyRect(key);
CColor keycolor = whiteFill_;
if (keyval_[key])
keycolor = pressedFill_;
dc->setFillColor(keycolor);
dc->drawRect(rect, kDrawFilled);
}
}
dc->setFrameColor(outline_);
dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getBottomLeft());
for (unsigned key = 0; key < keyCount; ++key) {
if (!black[key % 12]) {
CRect rect = keyRect(key);
dc->drawLine(rect.getTopRight(), rect.getBottomRight());
}
}
for (unsigned key = 0; key < keyCount; ++key) {
if (black[key % 12]) {
CRect rect = keyRect(key);
CColor keycolor = blackFill_;
if (keyval_[key])
keycolor = pressedFill_;
dc->setFillColor(keycolor);
dc->drawRect(rect, kDrawFilled);
dc->setFrameColor(outline_);
dc->drawRect(rect);
}
}
if (const CFontRef& font = font_) {
for (unsigned o = 0; o < octs; ++o) {
CRect rect = keyRect(o * 12);
CRect textRect(
rect.left, dim.labelBounds.top,
rect.right, dim.labelBounds.bottom);
dc->setFont(font);
dc->setFontColor(labelStroke_);
std::string text = std::to_string(static_cast<int>(o) - 1);
dc->drawString(text.c_str(), textRect, kCenterText);
}
}
{
dc->setFrameColor(outline_);
dc->drawLine(dim.keyBounds.getTopLeft(), dim.keyBounds.getTopRight());
dc->setFrameColor(shadeOutline_);
dc->drawLine(dim.keyBounds.getBottomLeft(), dim.keyBounds.getBottomRight());
}
dc->setFrameColor(outline_);
}
CMouseEventResult SPiano::onMouseDown(CPoint& where, const CButtonState& buttons)
{
unsigned key = keyAtPos(where);
if (key != ~0u) {
keyval_[key] = 1;
mousePressedKey_ = key;
if (onKeyPressed)
onKeyPressed(key, mousePressVelocity(key, where.y));
invalid();
return kMouseEventHandled;
}
return CView::onMouseDown(where, buttons);
}
CMouseEventResult SPiano::onMouseUp(CPoint& where, const CButtonState& buttons)
{
unsigned key = mousePressedKey_;
if (key != ~0u) {
keyval_[key] = 0;
if (onKeyReleased)
onKeyReleased(key, mousePressVelocity(key, where.y));
mousePressedKey_ = ~0u;
invalid();
return kMouseEventHandled;
}
return CView::onMouseUp(where, buttons);
}
CMouseEventResult SPiano::onMouseMoved(CPoint& where, const CButtonState& buttons)
{
if (mousePressedKey_ != ~0u) {
unsigned key = keyAtPos(where);
if (mousePressedKey_ != key) {
keyval_[mousePressedKey_] = 0;
if (onKeyReleased)
onKeyReleased(mousePressedKey_, mousePressVelocity(key, where.y));
// mousePressedKey_ = ~0u;
if (key != ~0u) {
keyval_[key] = 1;
mousePressedKey_ = key;
if (onKeyPressed)
onKeyPressed(key, mousePressVelocity(key, where.y));
}
invalid();
}
return kMouseEventHandled;
}
return CView::onMouseMoved(where, buttons);
}
const SPiano::Dimensions& SPiano::getDimensions(bool forceUpdate) const
{
if (!forceUpdate && dim_.bounds == getViewSize())
return dim_;
Dimensions dim;
dim.bounds = getViewSize();
dim.paddedBounds = CRect(dim.bounds)
.extend(-2 * innerPaddingX_, -2 * innerPaddingY_);
CCoord keyHeight = std::floor(dim.paddedBounds.getHeight());
CCoord fontHeight = font_ ? font_->getSize() : 0.0;
keyHeight -= spacingY_ + fontHeight;
dim.keyBounds = CRect(dim.paddedBounds)
.setHeight(keyHeight);
dim.keyWidth = static_cast<unsigned>(
dim.paddedBounds.getWidth() / octs_ / 7.0);
dim.keyBounds.setWidth(dim.keyWidth * octs_ * 7.0);
dim.keyBounds.offset(
std::floor(0.5 * (dim.paddedBounds.getWidth() - dim.keyBounds.getWidth())), 0.0);
if (!font_)
dim.labelBounds = CRect();
else
dim.labelBounds = CRect(
dim.keyBounds.left, dim.keyBounds.bottom + spacingY_,
dim.keyBounds.right, dim.keyBounds.bottom + spacingY_ + fontHeight);
dim_ = dim;
return dim_;
}
CRect SPiano::keyRect(const Dimensions& dim, unsigned key)
{
unsigned oct = key / 12;
unsigned note = key % 12;
unsigned keyw = dim.keyWidth;
unsigned keyh = static_cast<unsigned>(dim.keyBounds.getHeight());
CCoord octwidth = (keyoffs[11] + 1.0) * keyw;
CCoord octx = octwidth * oct;
CCoord notex = octx + keyoffs[note] * keyw;
CCoord notew = black[note] ? (0.6 * keyw) : keyw;
CCoord noteh = black[note] ? (0.6 * keyh) : keyh;
return CRect(notex, 0.0, notex + notew, noteh).offset(dim.keyBounds.getTopLeft());
}
CRect SPiano::keyRect(unsigned key) const
{
return keyRect(getDimensions(false), key);
}
unsigned SPiano::keyAtPos(CPoint pos) const
{
const unsigned octs = octs_;
for (unsigned key = 0; key < octs * 12; ++key) {
if (black[key % 12]) {
if (keyRect(key).pointInside(pos))
return key;
}
}
for (unsigned key = 0; key < octs * 12; ++key) {
if (!black[key % 12]) {
if (keyRect(key).pointInside(pos))
return key;
}
}
return ~0u;
}
float SPiano::mousePressVelocity(unsigned key, CCoord posY)
{
const CRect rect = keyRect(key);
CCoord value = (posY - rect.top) / rect.getHeight();
return std::max(0.0f, std::min(1.0f, static_cast<float>(value)));
}

View file

@ -1,50 +0,0 @@
// 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"
#if defined(_WIN32)
#include "ghc/fs_std.hpp"
#include <windows.h>
#include <cstring>
bool openFileInExternalEditor(const char *filename)
{
std::wstring path = fs::u8path(filename).wstring();
SHELLEXECUTEINFOW info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.fMask = SEE_MASK_CLASSNAME;
info.lpVerb = L"open";
info.lpFile = path.c_str();
info.lpClass = L"txtfile";
info.nShow = SW_SHOW;
return ShellExecuteExW(&info);
}
#elif defined(__APPLE__)
// implemented in NativeHelpers.mm
#else
#include <gio/gio.h>
bool openFileInExternalEditor(const char *filename)
{
GAppInfo* appinfo = g_app_info_get_default_for_type("text/plain", FALSE);
if (!appinfo)
return 1;
GList* files = nullptr;
GFile* file = g_file_new_for_path(filename);
files = g_list_append(files, file);
gboolean success = g_app_info_launch(appinfo, files, nullptr, nullptr);
g_object_unref(file);
g_list_free(files);
g_object_unref(appinfo);
return success == TRUE;
}
#endif

View file

@ -1,30 +0,0 @@
// 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"
#if defined(__APPLE__)
#import <AppKit/AppKit.h>
#import <CoreServices/CoreServices.h>
#import <Foundation/Foundation.h>
bool openFileInExternalEditor(const char *fileNameUTF8)
{
BOOL wasOpened = NO;
NSURL* applicationURL = (__bridge_transfer NSURL*)LSCopyDefaultApplicationURLForContentType(
kUTTypePlainText, kLSRolesEditor, nil);
if (!applicationURL)
return false;
if ([applicationURL isFileURL]) {
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
NSString* fileName = [NSString stringWithUTF8String:fileNameUTF8];
wasOpened = [workspace openFile:fileName withApplication:[applicationURL path]];
}
return wasOpened == YES;
}
#endif

View file

@ -1,155 +0,0 @@
/* This file is generated by the layout maker tool. */
LogicalGroup* const view__0 = createLogicalGroup(CRect(0, 0, 800, 475), -1, "", kCenterText, 14);
mainView = view__0;
Background* const view__1 = createBackground(CRect(190, 110, 790, 390), -1, "", kCenterText, 14);
view__0->addView(view__1);
enterTheme(darkTheme);
LogicalGroup* const view__2 = createLogicalGroup(CRect(0, 0, 800, 110), -1, "", kCenterText, 14);
view__0->addView(view__2);
RoundedGroup* const view__3 = createRoundedGroup(CRect(5, 4, 180, 105), -1, "", kCenterText, 14);
view__2->addView(view__3);
SfizzMainButton* const view__4 = createSfizzMainButton(CRect(30, 5, 150, 65), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14);
view__3->addView(view__4);
HomeButton* const view__5 = createHomeButton(CRect(44, 69, 69, 94), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 24);
view__3->addView(view__5);
CCButton* const view__6 = createCCButton(CRect(76, 69, 101, 94), kTagFirstChangePanel+kPanelControls, "", kCenterText, 24);
view__3->addView(view__6);
SettingsButton* const view__7 = createSettingsButton(CRect(107, 69, 132, 94), kTagFirstChangePanel+kPanelSettings, "", kCenterText, 24);
view__3->addView(view__7);
RoundedGroup* const view__8 = createRoundedGroup(CRect(185, 5, 565, 105), -1, "", kCenterText, 14);
view__2->addView(view__8);
HLine* const view__9 = createHLine(CRect(10, 36, 370, 41), -1, "", kCenterText, 14);
view__8->addView(view__9);
HLine* const view__10 = createHLine(CRect(10, 68, 370, 73), -1, "", kCenterText, 14);
view__8->addView(view__10);
ClickableLabel* const view__11 = createClickableLabel(CRect(10, 6, 260, 37), kTagLoadSfzFile, "DefaultInstrument.sfz", kLeftText, 20);
sfzFileLabel_ = view__11;
view__8->addView(view__11);
Label* const view__12 = createLabel(CRect(10, 39, 260, 69), -1, "Key switch:", kLeftText, 20);
view__8->addView(view__12);
Label* const view__13 = createLabel(CRect(10, 71, 70, 96), -1, "Voices:", kRightText, 12);
view__8->addView(view__13);
PreviousFileButton* const view__14 = createPreviousFileButton(CRect(295, 9, 320, 34), kTagPreviousSfzFile, "", kCenterText, 24);
view__8->addView(view__14);
NextFileButton* const view__15 = createNextFileButton(CRect(320, 9, 345, 34), kTagNextSfzFile, "", kCenterText, 24);
view__8->addView(view__15);
ChevronDropDown* const view__16 = createChevronDropDown(CRect(345, 9, 370, 34), kTagFileOperations, "", kCenterText, 24);
fileOperationsMenu_ = view__16;
view__8->addView(view__16);
Label* const view__17 = createLabel(CRect(75, 71, 125, 96), -1, "", kCenterText, 12);
infoVoicesLabel_ = view__17;
view__8->addView(view__17);
Label* const view__18 = createLabel(CRect(130, 71, 190, 96), -1, "Max:", kRightText, 12);
view__8->addView(view__18);
Label* const view__19 = createLabel(CRect(195, 71, 245, 96), -1, "", kCenterText, 12);
numVoicesLabel_ = view__19;
view__8->addView(view__19);
Label* const view__20 = createLabel(CRect(250, 71, 310, 96), -1, "Memory:", kRightText, 12);
view__8->addView(view__20);
Label* const view__21 = createLabel(CRect(315, 71, 365, 96), -1, "", kCenterText, 12);
memoryLabel_ = view__21;
view__8->addView(view__21);
RoundedGroup* const view__22 = createRoundedGroup(CRect(570, 5, 795, 105), -1, "", kCenterText, 14);
view__2->addView(view__22);
Knob48* const view__23 = createKnob48(CRect(45, 15, 93, 63), -1, "", kCenterText, 14);
view__22->addView(view__23);
view__23->setVisible(false);
ValueLabel* const view__24 = createValueLabel(CRect(40, 65, 100, 70), -1, "Center", kCenterText, 12);
view__22->addView(view__24);
view__24->setVisible(false);
StyledKnob* const view__25 = createStyledKnob(CRect(110, 15, 158, 63), kTagSetVolume, "", kCenterText, 14);
volumeSlider_ = view__25;
view__22->addView(view__25);
ValueLabel* const view__26 = createValueLabel(CRect(105, 65, 165, 87), -1, "0.0 dB", kCenterText, 12);
volumeLabel_ = view__26;
view__22->addView(view__26);
VMeter* const view__27 = createVMeter(CRect(175, 15, 210, 70), -1, "", kCenterText, 14);
view__22->addView(view__27);
enterTheme(defaultTheme);
LogicalGroup* const view__28 = createLogicalGroup(CRect(5, 110, 796, 395), -1, "", kCenterText, 14);
subPanels_[kPanelGeneral] = view__28;
view__0->addView(view__28);
RoundedGroup* const view__29 = createRoundedGroup(CRect(0, 0, 175, 280), -1, "", kCenterText, 14);
view__28->addView(view__29);
Label* const view__30 = createLabel(CRect(15, 10, 75, 35), -1, "Curves:", kLeftText, 14);
view__29->addView(view__30);
Label* const view__31 = createLabel(CRect(15, 35, 75, 60), -1, "Masters:", kLeftText, 14);
view__29->addView(view__31);
Label* const view__32 = createLabel(CRect(15, 60, 75, 85), -1, "Groups:", kLeftText, 14);
view__29->addView(view__32);
Label* const view__33 = createLabel(CRect(15, 85, 75, 110), -1, "Regions:", kLeftText, 14);
view__29->addView(view__33);
Label* const view__34 = createLabel(CRect(15, 110, 75, 135), -1, "Samples:", kLeftText, 14);
view__29->addView(view__34);
Label* const view__35 = createLabel(CRect(115, 10, 155, 35), -1, "0", kCenterText, 14);
infoCurvesLabel_ = view__35;
view__29->addView(view__35);
Label* const view__36 = createLabel(CRect(115, 35, 155, 60), -1, "0", kCenterText, 14);
infoMastersLabel_ = view__36;
view__29->addView(view__36);
Label* const view__37 = createLabel(CRect(115, 60, 155, 85), -1, "0", kCenterText, 14);
infoGroupsLabel_ = view__37;
view__29->addView(view__37);
Label* const view__38 = createLabel(CRect(115, 85, 155, 110), -1, "0", kCenterText, 14);
infoRegionsLabel_ = view__38;
view__29->addView(view__38);
Label* const view__39 = createLabel(CRect(115, 110, 155, 135), -1, "0", kCenterText, 14);
infoSamplesLabel_ = view__39;
view__29->addView(view__39);
LogicalGroup* const view__40 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelControls] = view__40;
view__0->addView(view__40);
view__40->setVisible(false);
RoundedGroup* const view__41 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14);
view__40->addView(view__41);
Label* const view__42 = createLabel(CRect(0, 0, 790, 285), -1, "Controls not available", kCenterText, 40);
view__41->addView(view__42);
LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 109, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelSettings] = view__43;
view__0->addView(view__43);
view__43->setVisible(false);
TitleGroup* const view__44 = createTitleGroup(CRect(255, 26, 535, 126), -1, "Engine", kCenterText, 12);
view__43->addView(view__44);
ValueMenu* const view__45 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12);
numVoicesSlider_ = view__45;
view__44->addView(view__45);
ValueLabel* const view__46 = createValueLabel(CRect(15, 20, 95, 45), -1, "Polyphony", kCenterText, 12);
view__44->addView(view__46);
ValueMenu* const view__47 = createValueMenu(CRect(110, 60, 170, 85), kTagSetOversampling, "", kCenterText, 12);
oversamplingSlider_ = view__47;
view__44->addView(view__47);
ValueLabel* const view__48 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oversampling", kCenterText, 12);
view__44->addView(view__48);
ValueLabel* const view__49 = createValueLabel(CRect(185, 20, 265, 45), -1, "Preload size", kCenterText, 12);
view__44->addView(view__49);
ValueMenu* const view__50 = createValueMenu(CRect(195, 60, 255, 85), kTagSetPreloadSize, "", kCenterText, 12);
preloadSizeSlider_ = view__50;
view__44->addView(view__50);
TitleGroup* const view__51 = createTitleGroup(CRect(200, 161, 590, 261), -1, "Tuning", kCenterText, 12);
view__43->addView(view__51);
ValueLabel* const view__52 = createValueLabel(CRect(125, 20, 205, 45), -1, "Root key", kCenterText, 12);
view__51->addView(view__52);
ValueMenu* const view__53 = createValueMenu(CRect(220, 60, 280, 85), kTagSetTuningFrequency, "", kCenterText, 12);
tuningFrequencySlider_ = view__53;
view__51->addView(view__53);
ValueLabel* const view__54 = createValueLabel(CRect(210, 20, 290, 45), -1, "Frequency", kCenterText, 12);
view__51->addView(view__54);
StyledKnob* const view__55 = createStyledKnob(CRect(310, 45, 358, 93), kTagSetStretchedTuning, "", kCenterText, 14);
stretchedTuningSlider_ = view__55;
view__51->addView(view__55);
ValueLabel* const view__56 = createValueLabel(CRect(295, 20, 375, 45), -1, "Stretch", kCenterText, 12);
view__51->addView(view__56);
ValueLabel* const view__57 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12);
view__51->addView(view__57);
ValueButton* const view__58 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12);
scalaFileButton_ = view__58;
view__51->addView(view__58);
ValueMenu* const view__59 = createValueMenu(CRect(135, 60, 170, 85), kTagSetScalaRootKey, "", kCenterText, 12);
scalaRootKeySlider_ = view__59;
view__51->addView(view__59);
ValueMenu* const view__60 = createValueMenu(CRect(170, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12);
scalaRootOctaveSlider_ = view__60;
view__51->addView(view__60);
Piano* const view__61 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 12);
piano_ = view__61;
view__0->addView(view__61);

View file

@ -1,298 +0,0 @@
#include "reader.h"
#include <absl/strings/string_view.h>
#include <iostream>
#include <fstream>
typedef std::vector<std::string> TokenList;
static bool read_file_tokens(const char *filename, TokenList &tokens);
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end);
Layout read_file_layout(const char *filename)
{
std::vector<std::string> tokens;
if (!read_file_tokens(filename, tokens))
throw std::runtime_error("Cannot read fluid design file.");
TokenList::iterator tok_it = tokens.begin();
TokenList::iterator tok_end = tokens.end();
return read_tokens_layout(tok_it, tok_end);
}
static std::string consume_next_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it == tok_end)
throw file_format_error("Premature end of tokens");
return *tok_it++;
}
static bool try_consume_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it == tok_end)
return false;
if (*tok_it != text)
return false;
++tok_it;
return true;
}
static void ensure_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string tok = consume_next_token(tok_it, tok_end);
if (tok != text)
throw file_format_error("Unexpected token: " + tok);
}
static std::string consume_enclosed_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
ensure_next_token("{", tok_it, tok_end);
unsigned depth = 1;
std::string text;
for (;;) {
std::string part = consume_next_token(tok_it, tok_end);
if (part == "}") {
if (--depth == 0)
return text;
}
else if (part == "{")
++depth;
if (!text.empty())
text.push_back(' ');
text.append(part);
}
return text;
}
static std::string consume_any_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it != tok_end && *tok_it == "{")
return consume_enclosed_string(tok_it, tok_end);
else
return consume_next_token(tok_it, tok_end);
}
static int consume_int_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string text = consume_next_token(tok_it, tok_end);
return std::stoi(text);
}
static int consume_real_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string text = consume_next_token(tok_it, tok_end);
return std::stod(text);
}
static void consume_layout_item_properties(LayoutItem &item, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
ensure_next_token("{", tok_it, tok_end);
for (bool have = true; have;) {
if (try_consume_next_token("open", tok_it, tok_end))
; // skip
else if (try_consume_next_token("selected", tok_it, tok_end))
; // skip
else if (try_consume_next_token("label", tok_it, tok_end))
item.label = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("xywh", tok_it, tok_end)) {
ensure_next_token("{", tok_it, tok_end);
item.x = consume_int_token(tok_it, tok_end);
item.y = consume_int_token(tok_it, tok_end);
item.w = consume_int_token(tok_it, tok_end);
item.h = consume_int_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (try_consume_next_token("box", tok_it, tok_end))
item.box = consume_next_token(tok_it, tok_end);
else if (try_consume_next_token("down_box", tok_it, tok_end))
item.down_box = consume_next_token(tok_it, tok_end);
else if (try_consume_next_token("labelfont", tok_it, tok_end))
item.labelfont = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("labelsize", tok_it, tok_end))
item.labelsize = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("labeltype", tok_it, tok_end))
item.labeltype = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("textsize", tok_it, tok_end))
item.textsize = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("align", tok_it, tok_end))
item.align = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("type", tok_it, tok_end))
item.type = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("callback", tok_it, tok_end))
item.callback = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("class", tok_it, tok_end))
item.classname = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("value", tok_it, tok_end))
item.value = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("minimum", tok_it, tok_end))
item.minimum = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("maximum", tok_it, tok_end))
item.maximum = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("step", tok_it, tok_end))
item.step = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("image", tok_it, tok_end))
item.image.filepath = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("hide", tok_it, tok_end))
item.hidden = true;
else if (try_consume_next_token("visible", tok_it, tok_end))
/* skip */;
else if (try_consume_next_token("comment", tok_it, tok_end))
item.comment = consume_any_string(tok_it, tok_end);
else
have = false;
}
ensure_next_token("}", tok_it, tok_end);
}
static LayoutItem consume_layout_item(const std::string &classname, TokenList::iterator &tok_it, TokenList::iterator tok_end, bool anonymous = false)
{
LayoutItem item;
item.classname = classname;
if (!anonymous)
item.id = consume_any_string(tok_it, tok_end);
consume_layout_item_properties(item, tok_it, tok_end);
if (tok_it != tok_end && *tok_it == "{") {
consume_next_token(tok_it, tok_end);
for (std::string text; (text = consume_next_token(tok_it, tok_end)) != "}";) {
if (text == "decl") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else if (text == "Function") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else
item.items.push_back(consume_layout_item(text, tok_it, tok_end));
}
}
return item;
}
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
Layout layout;
std::string version_name;
std::string header_name;
std::string code_name;
while (tok_it != tok_end) {
std::string key = consume_next_token(tok_it, tok_end);
if (key == "version")
version_name = consume_next_token(tok_it, tok_end);
else if (key == "header_name") {
ensure_next_token("{", tok_it, tok_end);
header_name = consume_next_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (key == "code_name") {
ensure_next_token("{", tok_it, tok_end);
code_name = consume_next_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (key == "decl") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else if (key == "widget_class") {
key = consume_next_token(tok_it, tok_end);
layout.items.push_back(consume_layout_item(key, tok_it, tok_end, true));
layout.items.back().id = key;
}
else
layout.items.push_back(consume_layout_item(key, tok_it, tok_end));
}
return layout;
}
///
class tokenizer {
public:
tokenizer(
absl::string_view text,
absl::string_view dropped_delims,
absl::string_view kept_delims);
absl::string_view next();
private:
absl::string_view text_;
absl::string_view dropped_delims_;
absl::string_view kept_delims_;
};
tokenizer::tokenizer(
absl::string_view text,
absl::string_view dropped_delims,
absl::string_view kept_delims)
: text_(text), dropped_delims_(dropped_delims), kept_delims_(kept_delims)
{
}
absl::string_view tokenizer::next()
{
auto is_dropped = [this](char c) -> bool {
return dropped_delims_.find(c) != dropped_delims_.npos;
};
auto is_kept = [this](char c) -> bool {
return kept_delims_.find(c) != kept_delims_.npos;
};
auto is_delim = [this](char c) -> bool {
return dropped_delims_.find(c) != dropped_delims_.npos ||
kept_delims_.find(c) != kept_delims_.npos;
};
absl::string_view text = text_;
while (!text.empty() && is_dropped(text[0]))
text.remove_prefix(1);
if (text.empty())
return {};
size_t pos;
{
auto it = std::find_if(text.begin(), text.end(), is_delim);
if (it == text.end())
pos = text.size();
else {
pos = std::distance(text.begin(), it);
pos += is_kept(text[0]);
}
}
absl::string_view token = text.substr(0, pos);
text_ = text.substr(pos);
return token;
}
///
static bool read_file_tokens(const char *filename, TokenList &tokens)
{
std::ifstream stream(filename);
std::string line;
std::string text;
while (std::getline(stream, line)) {
if (!line.empty() && line[0] != '#') {
text.append(line);
text.push_back('\n');
}
}
if (stream.bad())
return false;
tokenizer tok(text, " \t\r\n", "{}");
absl::string_view token;
while (!(token = tok.next()).empty())
tokens.emplace_back(token);
return !stream.bad();
}

2
external/abseil-cpp vendored

@ -1 +1 @@
Subproject commit df3ea785d8c30a9503321a3d35ee7d35808f190d
Subproject commit 997aaf3a28308eba1b9156aa35ab7bca9688e9f6

21
external/atomic_queue/LICENSE vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Maxim Egorushkin
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

@ -55,15 +55,13 @@ struct GetIndexShuffleBits<false, array_size, elements_per_cache_line> {
// the element within the cache line) with the next N bits (which are the index of the cache line)
// of the element index.
template<int BITS>
constexpr unsigned remap_index_with_mix(unsigned index, unsigned mix)
{
constexpr unsigned remap_index_with_mix(unsigned index, unsigned mix) {
return index ^ mix ^ (mix << BITS);
}
template<int BITS>
constexpr unsigned remap_index(unsigned index) noexcept {
return remap_index_with_mix<BITS>(
index, (index ^ (index >> BITS)) & ((1u << BITS) - 1));
return remap_index_with_mix<BITS>(index, (index ^ (index >> BITS)) & ((1u << BITS) - 1));
}
template<>
@ -213,7 +211,7 @@ protected:
else {
for(;;) {
unsigned char expected = STORED;
if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, LOADING, X, X))) {
if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, LOADING, A, X))) {
T element{std::move(q_element)};
state.store(EMPTY, R);
return element;
@ -238,7 +236,7 @@ protected:
else {
for(;;) {
unsigned char expected = EMPTY;
if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, STORING, X, X))) {
if(ATOMIC_QUEUE_LIKELY(state.compare_exchange_strong(expected, STORING, A, X))) {
q_element = std::forward<U>(element);
state.store(STORED, R);
return;
@ -318,11 +316,16 @@ public:
}
bool was_empty() const noexcept {
return static_cast<int>(head_.load(X) - tail_.load(X)) <= 0;
return !was_size();
}
bool was_full() const noexcept {
return static_cast<int>(head_.load(X) - tail_.load(X)) >= static_cast<int>(static_cast<Derived const&>(*this).size_);
return was_size() >= static_cast<int>(static_cast<Derived const&>(*this).size_);
}
unsigned was_size() const noexcept {
// tail_ can be greater than head_ because of consumers doing pop, rather that try_pop, when the queue is empty.
return std::max(static_cast<int>(head_.load(X) - tail_.load(X)), 0);
}
unsigned capacity() const noexcept {

View file

@ -16,7 +16,6 @@ static inline void spin_loop_pause() noexcept {
}
} // namespace atomic_queue
#elif defined(__arm__) || defined(__aarch64__)
// TODO: These need to be verified as I do not have access to ARM platform.
namespace atomic_queue {
constexpr int CACHE_LINE_SIZE = 64;
static inline void spin_loop_pause() noexcept {
@ -48,9 +47,11 @@ namespace atomic_queue {
#if defined(__GNUC__) || defined(__clang__)
#define ATOMIC_QUEUE_LIKELY(expr) __builtin_expect(static_cast<bool>(expr), 1)
#define ATOMIC_QUEUE_UNLIKELY(expr) __builtin_expect(static_cast<bool>(expr), 0)
#define ATOMIC_QUEUE_NOINLINE __attribute__((noinline))
#else
#define ATOMIC_QUEUE_LIKELY(expr) expr
#define ATOMIC_QUEUE_UNLIKELY(expr) expr
#define ATOMIC_QUEUE_LIKELY(expr) (expr)
#define ATOMIC_QUEUE_UNLIKELY(expr) (expr)
#define ATOMIC_QUEUE_NOINLINE
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

119
external/cephes/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,119 @@
==== NOTE ====
The actual cephes library, shipped with and wrapped by this package, is available on The Netlib at http://www.netlib.org/cephes/ . It does not have any license specified. However, its original authors, Stephen Moshier, has kindly granted permission for inclusion in a BSD-licensed package. See email snippet below for reference.
Return-Path: <steve@moshier.net>
X-Original-To: julien@cornebise.com
Delivered-To: julien@cornebise.com
Received: from atl4mhob11.myregisteredsite.com (atl4mhob11.myregisteredsite.com [209.17.115.49])
by cornebise.com (Postfix) with ESMTP id D47B139FC0
for <julien@cornebise.com>; Fri, 25 Oct 2013 16:32:40 +0200 (CEST)
Received: from mailpod1.hostingplatform.com ([10.30.71.116])
by atl4mhob11.myregisteredsite.com (8.14.4/8.14.4) with ESMTP id r9PEWcwQ003543
for <julien@cornebise.com>; Fri, 25 Oct 2013 10:32:38 -0400
Received: (qmail 11948 invoked by uid 0); 25 Oct 2013 12:36:20 -0000
X-TCPREMOTEIP: 76.24.25.74
X-Authenticated-UID: steve@moshier.net
Received: from unknown (HELO d510.local) (steve@moshier.net@76.24.25.74)
by 0 with ESMTPA; 25 Oct 2013 12:36:20 -0000
Date: Fri, 25 Oct 2013 08:36:19 -0400 (EDT)
From: Stephen Moshier <steve@moshier.net>
X-X-Sender: steve@d510
To: Julien Cornebise <julien@cornebise.com>
Subject: Re: Cephes: permission to wrap+distribute for Lua
In-Reply-To: <52653AD3.1010004@cornebise.com>
Message-ID: <alpine.DEB.2.02.1310250827040.17646@d510>
References: <52653AD3.1010004@cornebise.com>
User-Agent: Alpine 2.02 (DEB 1266 2009-07-14)
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed
Julien, thank you for writing.
BSD license is fine, modification is OK.
There are more build scripts available in the web site distributions than
there are on the Netlib. I think there is an update to Planck's radiation
function that I haven't sent to Netlib yet. But Netlib is a more stable
site, so it is better to cite that as a reference.
On Mon, 21 Oct 2013, Julien Cornebise wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Dear Mr Moshier
>
> I am a researcher in mathematics and machine learning in London, and
> am writing about your awesome Cephes library, whom I found at the
> heart of Scipy.
>
> It is so useful that, with your permission, I would like to wrap it
> for Lua and Torch (a machine learning overlay to Lua, specialized in
> neural nets, see http://www.torch.ch). I would like to distribute it
> as a package for Torch, including your source code along the wrapping
> code.
> This wouldbe a public package, distributed under BSD License. I have
> put a first draft on github:
> https://github.com/jucor/torch-cephes
>
> Hence my three questions, please:
>
> 1/ How would you like to be acknowledged, beyond the comments that are
> already in your code? Do you have any standard header/disclaimer that
> I could add to the documentation?
>
> 2/ At the moment, your code is left untouched. However, if I ever need
> to modify bits of the code, what are the conditions/restrictions?
> Nothing huge -- I definitely do not want to mess with it: I was
> planning to use the natural completion of some functions on the
> completed real line (e.g. CDF returing 1 when called with "infinity",
> or quantiles returning -Infinity when called with 0), either natively
> if supported, or by setting a specific flag via mtherr().
>
> 3/ I am currently using the source from Netlib. Do you recommend using
> the source from your website instead ?
>
> Thank you very much for your attention,
> and, more importantly, for the time and effort your poured into Cephes.
>
> Best regards,
>
> Julien Cornebise, Ph.D.
> London, UK
> http://www.cornebise.com/julien
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.14 (Darwin)
> Comment: GPGTools - http://gpgtools.org
> Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/
>
> iEYEARECAAYFAlJlOtEACgkQKYR3gC0rw/gIpQCfZKu6+iDh9ghhm6QfsLXnldKN
> BuIAn2zZHu1c/IrRAevhjM7N7xGg0LHO
> =WeP5
> -----END PGP SIGNATURE-----
==== LICENSE ====
Copyright (c) 2013, Julien Cornebise
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of the organization nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
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 <COPYRIGHT HOLDER> 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.

82
external/cephes/src/chbevl.c vendored Normal file
View file

@ -0,0 +1,82 @@
/* chbevl.c
*
* Evaluate Chebyshev series
*
*
*
* SYNOPSIS:
*
* int N;
* double x, y, coef[N], chebevl();
*
* y = chbevl( x, coef, N );
*
*
*
* DESCRIPTION:
*
* Evaluates the series
*
* N-1
* - '
* y = > coef[i] T (x/2)
* - i
* i=0
*
* of Chebyshev polynomials Ti at argument x/2.
*
* Coefficients are stored in reverse order, i.e. the zero
* order term is last in the array. Note N is the number of
* coefficients, not the order.
*
* If coefficients are for the interval a to b, x must
* have been transformed to x -> 2(2x - b - a)/(b-a) before
* entering the routine. This maps x from (a, b) to (-1, 1),
* over which the Chebyshev polynomials are defined.
*
* If the coefficients are for the inverted interval, in
* which (a, b) is mapped to (1/b, 1/a), the transformation
* required is x -> 2(2ab/x - b - a)/(b-a). If b is infinity,
* this becomes x -> 4a/x - 1.
*
*
*
* SPEED:
*
* Taking advantage of the recurrence properties of the
* Chebyshev polynomials, the routine requires one more
* addition per loop than evaluating a nested polynomial of
* the same degree.
*
*/
/* chbevl.c */
/*
Cephes Math Library Release 2.0: April, 1987
Copyright 1985, 1987 by Stephen L. Moshier
Direct inquiries to 30 Frost Street, Cambridge, MA 02140
*/
double chbevl( x, array, n )
double x;
double array[];
int n;
{
double b0, b1, b2, *p;
int i;
p = array;
b0 = *p++;
b1 = 0.0;
i = n - 1;
do
{
b2 = b1;
b1 = b0;
b0 = x * b1 - b2 + *p++;
}
while( --i );
return( 0.5*(b0-b2) );
}

193
external/cephes/src/i0.c vendored Normal file
View file

@ -0,0 +1,193 @@
/* i0.c
*
* Modified Bessel function of order zero
*
*
*
* SYNOPSIS:
*
* double x, y, i0();
*
* y = i0( x );
*
*
*
* DESCRIPTION:
*
* Returns modified Bessel function of order zero of the
* argument.
*
* The function is defined as i0(x) = j0( ix ).
*
* The range is partitioned into the two intervals [0,8] and
* (8, infinity). Chebyshev polynomial expansions are employed
* in each interval.
*
*
*
* ACCURACY:
*
* Relative error:
* arithmetic domain # trials peak rms
* DEC 0,30 6000 8.2e-17 1.9e-17
* IEEE 0,30 30000 5.8e-16 1.4e-16
*
*/
/* i0e.c
*
* Modified Bessel function of order zero,
* exponentially scaled
*
*
*
* SYNOPSIS:
*
* double x, y, i0e();
*
* y = i0e( x );
*
*
*
* DESCRIPTION:
*
* Returns exponentially scaled modified Bessel function
* of order zero of the argument.
*
* The function is defined as i0e(x) = exp(-|x|) j0( ix ).
*
*
*
* ACCURACY:
*
* Relative error:
* arithmetic domain # trials peak rms
* IEEE 0,30 30000 5.4e-16 1.2e-16
* See i0().
*
*/
/* i0.c */
/*
Cephes Math Library Release 2.8: June, 2000
Copyright 1984, 1987, 2000 by Stephen L. Moshier
*/
#include <math.h>
/* Chebyshev coefficients for exp(-x) I0(x)
* in the interval [0,8].
*
* lim(x->0){ exp(-x) I0(x) } = 1.
*/
static double A[] =
{
-4.41534164647933937950E-18,
3.33079451882223809783E-17,
-2.43127984654795469359E-16,
1.71539128555513303061E-15,
-1.16853328779934516808E-14,
7.67618549860493561688E-14,
-4.85644678311192946090E-13,
2.95505266312963983461E-12,
-1.72682629144155570723E-11,
9.67580903537323691224E-11,
-5.18979560163526290666E-10,
2.65982372468238665035E-9,
-1.30002500998624804212E-8,
6.04699502254191894932E-8,
-2.67079385394061173391E-7,
1.11738753912010371815E-6,
-4.41673835845875056359E-6,
1.64484480707288970893E-5,
-5.75419501008210370398E-5,
1.88502885095841655729E-4,
-5.76375574538582365885E-4,
1.63947561694133579842E-3,
-4.32430999505057594430E-3,
1.05464603945949983183E-2,
-2.37374148058994688156E-2,
4.93052842396707084878E-2,
-9.49010970480476444210E-2,
1.71620901522208775349E-1,
-3.04682672343198398683E-1,
6.76795274409476084995E-1
};
/* Chebyshev coefficients for exp(-x) sqrt(x) I0(x)
* in the inverted interval [8,infinity].
*
* lim(x->inf){ exp(-x) sqrt(x) I0(x) } = 1/sqrt(2pi).
*/
static double B[] =
{
-7.23318048787475395456E-18,
-4.83050448594418207126E-18,
4.46562142029675999901E-17,
3.46122286769746109310E-17,
-2.82762398051658348494E-16,
-3.42548561967721913462E-16,
1.77256013305652638360E-15,
3.81168066935262242075E-15,
-9.55484669882830764870E-15,
-4.15056934728722208663E-14,
1.54008621752140982691E-14,
3.85277838274214270114E-13,
7.18012445138366623367E-13,
-1.79417853150680611778E-12,
-1.32158118404477131188E-11,
-3.14991652796324136454E-11,
1.18891471078464383424E-11,
4.94060238822496958910E-10,
3.39623202570838634515E-9,
2.26666899049817806459E-8,
2.04891858946906374183E-7,
2.89137052083475648297E-6,
6.88975834691682398426E-5,
3.36911647825569408990E-3,
8.04490411014108831608E-1
};
extern double chbevl ( double, void *, int );
double i0(x)
double x;
{
double y;
if( x < 0 )
x = -x;
if( x <= 8.0 )
{
y = (x/2.0) - 2.0;
return( exp(x) * chbevl( y, A, 30 ) );
}
return( exp(x) * chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) );
}
double i0e( x )
double x;
{
double y;
if( x < 0 )
x = -x;
if( x <= 8.0 )
{
y = (x/2.0) - 2.0;
return( chbevl( y, A, 30 ) );
}
return( chbevl( 32.0/x - 2.0, B, 25 ) / sqrt(x) );
}

19
external/cxxopts/LICENSE vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2014 Jarryd Beck
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.

File diff suppressed because it is too large Load diff

1
external/filesystem vendored Submodule

@ -0,0 +1 @@
Subproject commit 2a8b380f8d4e77b389c42a194ab9c70d8e3a0f1e

View file

@ -1,4 +1,11 @@
// -*- C++ -*-
// SPDX-License-Identifier: BSL-1.0
//
// Copyright Jean Pierre Cimalando 2018-2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include <limits>
#include <utility>

View file

@ -1,3 +1,11 @@
// -*- C++ -*-
// SPDX-License-Identifier: BSL-1.0
//
// Copyright Jean Pierre Cimalando 2018-2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "../../allocator"
#include <new>
#if defined(_WIN32)

View file

@ -1,3 +1,11 @@
// -*- C++ -*-
// SPDX-License-Identifier: BSL-1.0
//
// Copyright Jean Pierre Cimalando 2018-2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "../../allocator"
#include <new>

View file

@ -1,3 +1,11 @@
// -*- C++ -*-
// SPDX-License-Identifier: BSL-1.0
//
// Copyright Jean Pierre Cimalando 2018-2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "../../allocator"
#include <stdlib.h>

1
external/simde vendored Submodule

@ -0,0 +1 @@
Subproject commit 5c2f423b41c06228e4be0cce0010a252297da4e7

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