Merge branch 'develop'
This commit is contained in:
commit
35fbf7d36b
362 changed files with 50367 additions and 8207 deletions
|
|
@ -4,11 +4,15 @@
|
|||
# Top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# No trailing whitespaces, but with a newline ending every file,
|
||||
# UTF-8 charset, set indent to spaces with width of four
|
||||
# UTF-8 charset, set indent to spaces with width of four,
|
||||
# with no trailing whitespaces and a newline ending every file.
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
|
||||
[*.{ttl,in,sh,yml}]
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
|
|
|||
22
.gitignore
vendored
22
.gitignore
vendored
|
|
@ -1,9 +1,5 @@
|
|||
build
|
||||
build-arm
|
||||
build-asan
|
||||
build-release
|
||||
build-reldeb
|
||||
build-debug
|
||||
build*
|
||||
docs
|
||||
.vscode
|
||||
perf.data
|
||||
perf.data.old
|
||||
|
|
@ -15,6 +11,7 @@ cmake_install.cmake
|
|||
compile_commands.json
|
||||
*.a
|
||||
*.txt.user
|
||||
*.autosave
|
||||
|
||||
.DS_Store
|
||||
|
||||
|
|
@ -22,10 +19,15 @@ clients/sfizz_jack
|
|||
clients/sfzprint
|
||||
|
||||
# gh-pages unstaged files:
|
||||
|
||||
.bundle/
|
||||
Gemfile.lock
|
||||
_api/
|
||||
_site/
|
||||
.bundle/
|
||||
api/
|
||||
assets/
|
||||
node_modules/
|
||||
yarn.lock
|
||||
.jekyll-cache
|
||||
.jekyll-metadata
|
||||
.sass-cache
|
||||
*.lock
|
||||
*.sublime-*
|
||||
*.code-*
|
||||
|
|
|
|||
6
.gitmodules
vendored
6
.gitmodules
vendored
|
|
@ -1,8 +1,4 @@
|
|||
[submodule "external/abseil-cpp"]
|
||||
path = external/abseil-cpp
|
||||
url = https://github.com/abseil/abseil-cpp
|
||||
branch = lts_2019_08_08
|
||||
[submodule "external/benchmark"]
|
||||
path = external/benchmark
|
||||
url = https://github.com/google/benchmark
|
||||
branch = master
|
||||
branch = lts_2019_08_08
|
||||
65
.travis.yml
65
.travis.yml
|
|
@ -1,43 +1,66 @@
|
|||
language: cpp
|
||||
env:
|
||||
global:
|
||||
- INSTALL_DIR="sfizz-${TRAVIS_BRANCH}-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
- os: linux
|
||||
dist: xenial
|
||||
- os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- gcc-8
|
||||
- g++-8
|
||||
env:
|
||||
- MATRIX_EVAL="CC=gcc-8 && CXX=g++-8"
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
|
||||
# - os: osx
|
||||
# osx_image: xcode10.1
|
||||
packages:
|
||||
- doxygen
|
||||
|
||||
- os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode10.1
|
||||
|
||||
before_install:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/before_install.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/before_install.sh
|
||||
|
||||
install:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/install.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/install.sh
|
||||
|
||||
script:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/script.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/script.sh
|
||||
|
||||
after_failure:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/after_failure.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/discord_webhook.sh failure
|
||||
|
||||
after_success:
|
||||
- sh ${TRAVIS_BUILD_DIR}/.travis/after_success.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/discord_webhook.sh success
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/update_dox.sh
|
||||
- bash ${TRAVIS_BUILD_DIR}/.travis/after_success.sh
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: cc6IkdalZRb+lOWzPkubCUvTcP9lBwiNBBPkXWVmeX7YXkdQlsoVQ11bZThd1Go+5Lt+jGFtEqEjJ0L7GxpdatEeBMEK5HXl0QtHAybl9J4Ax7hKba8FSX5RqPFOuKixCob6eCqJRchT26qRsQE/WYMY8DmproEFGMBHk0K4HXDWEq0HP8dbWVx3KudvellCYszUrVQYb2s49sDiF8OwSog5TiqdBqO5PRcqyt2ySmHgqwBYq7XV0pb+DxcKJcc7/gCBpBN7nyEhl8gmKELypLF81l8xUDBUjRy1jjf0r33ISHpX1MWeWIN9YzSNL0aLPQvwynAQ7OeckFAIMABah2UuYcxdd4ioXduPTbprVYpSwIyyxkeafK2jxgxwoKWi9GJZ3yAUHNS/V7Gh5DsFb7C6QDqr5gOxOMtjHwjmHnxmD44SsugjSosVzirvQR+JbrSsPsmZThQjCvwG+7hO3JatX4BXA7bp9WtgsoMrCH61gCp2GogQVLvYpgRpVErKK8PMTkt71OouewTDqD5iwc3N/2pNWP3cXxpPegerjl4R2sY0sZ57WRfW8ts7akPyqJZa2uKpzpM0eXy35fZl6WoJSlIv3akCnzdtLtaWAptzfXhgRSlF/33+gZ3jRcSP7ca2YpUviuZ+KYk+uGfMh092CMRMjPv1Et5h7zYGD+o=
|
||||
file: "$DEPLOYFILE"
|
||||
file: "${INSTALL_DIR}.tar.gz"
|
||||
token:
|
||||
secure: jBIMWMPva8OazC8Wnqc2vqATa3exjvGDGvejEu6fgwt/BMDkgJCsJ7gS3ITpYFuO0HoHtLGfTVrFcZIE+agGVRdRGRni5xZRp5Vuf9hvLf8hCTaxkS/HYoliYYPp9FLY6J4yq9mp/R/QyGrwgssQEjhYlI2GL4+lJzt750AcmYibnQo2AMe5SSOp3q8KdLBG1vca1o1BZWBhW/S7l2hA1aJ7y1ytwm0ETIdrTZHxgfz7bqdqQcw/Ytqjm1rgzty6iQKX3B/InaZNB6CqXy6FoGLf771lery8nWJbjTjKYD4QK2NelExldyp1vrdHGvknWguFk+8vlQ16Dt0+R7Byr/LOPRLTCf/T+IehMQGtVA9/gjrkH8LqHy9oVFB+33p11gGu3h6hvg7yB6z3sSck0u4FHjrlpNd5XmmCsKQVQ9vI1cPPkVkbMHIewc7uOu+bD6cmotFj1vJ9UYesvN6n4siyCiPOIhgV9++bjcyiLqX3DWP5UWyZ9/VT8bz5VcxUdJnEYtdNPx4x5pRW4081VUjIf2EmHhQTrjb1iz6FAGwNU/fpefA8x+bBxXP9MkFFgU0tbCDKw2y6o0GOXX82mZr/IB0/DIBg7UllTzCBKTuiJQV1prFPlZLc6V22H5ozAXHgu3E+qNjvHoMsoYjGssX3+AYHwu8isBINo/gGo6Y=
|
||||
on:
|
||||
repo: sfztools/sfizz
|
||||
repo: ${TRAVIS_REPO_SLUG}
|
||||
tags: true
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "ircs://chat.freenode.net:7070/#sfztools"
|
||||
|
||||
template:
|
||||
- "[%{repository_name}:%{branch}] Build #%{build_number}: %{message}"
|
||||
- "%{author} : %{commit_subject}"
|
||||
- "Commit URL : https://github.com/%{repository_slug}/commit/%{commit}"
|
||||
- "Build Details : %{build_url}"
|
||||
|
|
|
|||
|
|
@ -1,25 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
# Travis Webhook
|
||||
wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
|
||||
chmod +x send.sh
|
||||
./send.sh success $WEBHOOK_URL
|
||||
|
||||
# Deploy
|
||||
export VERSION=$(git describe --tags)
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export DEPLOYFILE=Sfizz-$VERSION-x86_64.AppImage
|
||||
wget -c -nv "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||
chmod +x linuxdeploy-x86_64.AppImage
|
||||
for size in 16 32 48 128 256; do dirname="sfizz/usr/share/icons/hicolor/${size}x${size}/apps"; mkdir -p $dirname; cp ./resources/icons/icon_${size}px.png ./${dirname}/sfizz.png; done
|
||||
./linuxdeploy-x86_64.AppImage --appdir=sfizz --desktop-file=./resources/linux/sfizz.desktop --executable=./build/clients/sfizz_jack --output=appimage
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export DEPLOYFILE=sfizz-$VERSION.dmg
|
||||
mkdir ./output
|
||||
cp -r /build/* ./output/
|
||||
cp ./resources/icons/icon.icns ./output/sfizz.app/Contents/Resources/
|
||||
hdiutil create /tmp/tmp.dmg -ov -volname "sfizz-$VERSION" -fs HFS+ -srcfolder "./output/"
|
||||
hdiutil convert /tmp/tmp.dmg -format UDZO -o ./$DEPLOYFILE;
|
||||
fi
|
||||
cd build
|
||||
make install
|
||||
tar -zcvf "${INSTALL_DIR}.tar.gz" ${INSTALL_DIR}
|
||||
mv "${INSTALL_DIR}.tar.gz" ${TRAVIS_BUILD_DIR}
|
||||
cd ..
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
wget https://cmake.org/files/v3.13/cmake-3.13.0-Linux-x86_64.sh
|
||||
sudo sh cmake-3.13.0-Linux-x86_64.sh --skip-license --prefix=/usr/local
|
||||
cmake_dir="cmake-3.13.0-${TRAVIS_OS_NAME}-${TRAVIS_CPU_ARCH}"
|
||||
cmake_arc="${cmake_dir}.tar.gz"
|
||||
cmake_url="https://github.com/sfztools/cmake/releases/download/${TRAVIS_OS_NAME}/${cmake_arc}"
|
||||
|
||||
if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
|
||||
wget -q ${cmake_url}
|
||||
tar xzf ${cmake_arc}
|
||||
cd ${TRAVIS_BUILD_DIR}/${cmake_dir}
|
||||
sudo cp bin/* /usr/local/bin/
|
||||
sudo cp -r share/* /usr/local/share/
|
||||
export PATH="/usr/local/bin:$PATH" # FIXME
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
elif [[ ${TRAVIS_OS_NAME} == "osx" ]]; then
|
||||
sudo ln -s /usr/local /opt/local
|
||||
brew update
|
||||
brew upgrade cmake
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
# Travis Webhook
|
||||
wget https://raw.githubusercontent.com/DiscordHooks/travis-ci-discord-webhook/master/send.sh
|
||||
chmod +x send.sh
|
||||
./send.sh failure $WEBHOOK_URL
|
||||
./send.sh ${1} ${WEBHOOK_URL}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get install libasound2-dev libjack-jackd2-dev libsndfile1-dev
|
||||
if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
|
||||
sudo apt-get install libasound2-dev libjack-jackd2-dev libsndfile1-dev lv2-dev
|
||||
gcc -v && g++ -v && cmake --version && /usr/local/bin/cmake --version && $SHELL --version
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -ex
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 100
|
||||
gcc -v && g++ -v && cmake --version && /usr/local/bin/cmake --version && $SHELL --version
|
||||
mkdir -p build/${INSTALL_DIR} && cd build
|
||||
/usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=${PWD}/${INSTALL_DIR} ..
|
||||
|
||||
if [[ ${TRAVIS_OS_NAME} == "linux" ]]; then
|
||||
|
||||
mkdir build && cd build
|
||||
/usr/local/bin/cmake -D CMAKE_BUILD_TYPE=Debug -D SFIZZ_CLIENTS=ON ..
|
||||
make -j$(nproc)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
mkdir build && cd build
|
||||
cmake -D SFIZZ_CLIENTS=OFF -G Xcode .. # FIXME: client build
|
||||
xcodebuild -project sfizz.xcodeproj -alltargets -configuration Debug build
|
||||
elif [[ ${TRAVIS_OS_NAME} == "osx" ]]; then
|
||||
|
||||
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
|
||||
fi
|
||||
|
|
|
|||
19
.travis/update_dox.sh
Executable file
19
.travis/update_dox.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -x # No fail, we need to go back to the original branch at the end
|
||||
|
||||
# Build documentation only from Linux x86_64 builds
|
||||
if [[ ${TRAVIS_CPU_ARCH} != "amd64" || ${TRAVIS_OS_NAME} != "linux" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
doxygen Doxyfile
|
||||
git fetch --depth=1 https://github.com/${TRAVIS_REPO_SLUG}.git refs/heads/gh-pages:refs/remotes/origin/gh-pages
|
||||
git checkout origin/gh-pages
|
||||
git checkout -b gh-pages
|
||||
rm -rf ./api
|
||||
mv _api api
|
||||
git add api && git commit -m "Travis build: ${TRAVIS_BUILD_NUMBER}"
|
||||
git remote add origin-pages https://${GITHUB_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git > /dev/null 2>&1
|
||||
git push --quiet --set-upstream origin-pages gh-pages
|
||||
git checkout ${TRAVIS_BRANCH}
|
||||
134
CMakeLists.txt
134
CMakeLists.txt
|
|
@ -1,98 +1,56 @@
|
|||
cmake_minimum_required(VERSION 3.13)
|
||||
project(sfizz VERSION 1.0.0 LANGUAGES CXX)
|
||||
if(WIN32)
|
||||
cmake_minimum_required (VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
else()
|
||||
cmake_minimum_required (VERSION 3.11)
|
||||
endif()
|
||||
project (sfizz VERSION 0.2.0 LANGUAGES CXX C)
|
||||
set(PROJECT_DESCRIPTION "A library to load SFZ description files and use them to render music.")
|
||||
|
||||
# Do not override if set to more than 14
|
||||
if (NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
# External configuration CMake scripts
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
include (SfizzConfig)
|
||||
|
||||
# Build Options
|
||||
set (BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests [default: OFF]")
|
||||
|
||||
# On macOS add the needed directories for both library and jack client
|
||||
if (APPLE)
|
||||
include_directories (SYSTEM /usr/local/opt/libsndfile/include)
|
||||
link_directories (/usr/local/opt/libsndfile/lib)
|
||||
endif()
|
||||
|
||||
# Enable LTO
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # To override the policy in abseil and benchmark
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
option (ENABLE_LTO "Enable Link Time Optimization [default: ON]" ON)
|
||||
option (SFIZZ_JACK "Enable JACK stand-alone build [default: ON]" ON)
|
||||
option (SFIZZ_LV2 "Enable LV2 plug-in build [default: ON]" ON)
|
||||
option (SFIZZ_BENCHMARKS "Enable benchmarks build [default: OFF]" OFF)
|
||||
option (SFIZZ_TESTS "Enable tests build [default: OFF]" OFF)
|
||||
option (SFIZZ_SHARED "Enable shared library build [default: ON]" ON)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT ANDROID)
|
||||
set(USE_LIBCPP ON CACHE BOOL "Use libc++ with clang")
|
||||
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
|
||||
# Don't use IPO in non Release builds
|
||||
include (CheckIPO)
|
||||
|
||||
# Add Abseil
|
||||
add_subdirectory (external/abseil-cpp EXCLUDE_FROM_ALL)
|
||||
|
||||
# Add the static library targets and sources
|
||||
add_subdirectory (src)
|
||||
|
||||
# Optional targets
|
||||
if (SFIZZ_JACK)
|
||||
add_subdirectory (clients)
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
add_compile_options(-Wall)
|
||||
add_compile_options(-Wextra)
|
||||
add_compile_options(-ffast-math)
|
||||
add_compile_options(-fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
# TODO: Remove when abseil updates (deprecation warning from c++17 onwards)
|
||||
add_compile_options(/wd4996)
|
||||
# add_compile_options(/W3)
|
||||
# add_compile_options(/GR-)
|
||||
# add_compile_options(/permissive-)
|
||||
# add_compile_options(/fp:fast)
|
||||
endif()
|
||||
|
||||
message("Cmake flags: ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Export the compile_commands.json file
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# find_package(Git QUIET)
|
||||
# if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
# Update submodules as needed
|
||||
# option(GIT_SUBMODULE "Check submodules during build" ON)
|
||||
# if(GIT_SUBMODULE)
|
||||
# message(STATUS "Submodule update")
|
||||
# execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive --remote
|
||||
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
# RESULT_VARIABLE GIT_SUBMOD_RESULT)
|
||||
# if(NOT GIT_SUBMOD_RESULT EQUAL "0")
|
||||
# message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
|
||||
# endif()
|
||||
# endif()
|
||||
# endif()
|
||||
|
||||
# Build options and includes
|
||||
set(BUILD_TESTING OFF CACHE BOOL "Disable Abseil's tests")
|
||||
add_subdirectory(external/abseil-cpp EXCLUDE_FROM_ALL)
|
||||
|
||||
# Download libsndfile
|
||||
if (WIN32)
|
||||
# file(DOWNLOAD https://github.com/bastibe/libsndfile-binaries/raw/master/libsndfile32bit.dll external/libsndfile-win/libsndfile32bit.dll)
|
||||
# file(DOWNLOAD https://github.com/bastibe/libsndfile-binaries/raw/master/libsndfile64bit.dll external/libsndfile-win/libsndfile64bit.dll)
|
||||
# message(STATUS "Downloading libsndfile")
|
||||
# # find_library(sndfile libsndfile-1.lib HINTS ${WIN_SNDFILE_PATH}/lib)
|
||||
set(WIN_SNDFILE_PATH "C:/Program Files/Mega-Nerd/libsndfile")
|
||||
add_library(sndfile STATIC IMPORTED)
|
||||
set_target_properties(sndfile PROPERTIES IMPORTED_LOCATION "${WIN_SNDFILE_PATH}/lib/libsndfile-1.lib")
|
||||
set_target_properties(sndfile PROPERTIES LINKER_LANGUAGE CXX)
|
||||
file(COPY "${WIN_SNDFILE_PATH}/bin/libsndfile-1.dll" DESTINATION ${CMAKE_BINARY_DIR})
|
||||
target_include_directories(sndfile INTERFACE "${WIN_SNDFILE_PATH}/include")
|
||||
elseif(APPLE)
|
||||
find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.hh PATHS "/usr/local/include")
|
||||
find_library(SNDFILE_LIBRARY NAMES sndfile PATHS "/usr/local/lib")
|
||||
message(STATUS "include dir: " ${SNDFILE_INCLUDE_DIR} " lib: " ${SNDFILE_LIBRARY})
|
||||
add_library(sndfile SHARED IMPORTED GLOBAL)
|
||||
target_include_directories(sndfile INTERFACE ${SNDFILE_INCLUDE_DIR})
|
||||
target_link_libraries(sndfile INTERFACE ${SNDFILE_LIBRARY})
|
||||
endif()
|
||||
|
||||
add_subdirectory(sfizz)
|
||||
|
||||
if (SFIZZ_CLIENTS)
|
||||
add_subdirectory(clients)
|
||||
endif()
|
||||
|
||||
if (SFIZZ_TESTS)
|
||||
add_subdirectory(tests)
|
||||
if (SFIZZ_LV2)
|
||||
add_subdirectory (lv2)
|
||||
endif()
|
||||
|
||||
if (SFIZZ_BENCHMARKS)
|
||||
# Benchmarks
|
||||
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable Google Benchmark tests")
|
||||
set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "Disable Google Benchmark install")
|
||||
add_subdirectory(external/benchmark EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(benchmarks)
|
||||
add_subdirectory (benchmarks)
|
||||
endif()
|
||||
|
||||
if (SFIZZ_TESTS)
|
||||
add_subdirectory (tests)
|
||||
endif()
|
||||
|
||||
show_build_info_if_needed()
|
||||
|
|
|
|||
11
LICENSE.md
11
LICENSE.md
|
|
@ -1,6 +1,15 @@
|
|||
BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Paul Ferrand
|
||||
The code is copyrighted by their respective authors, as indicated by the
|
||||
source control mechanism.
|
||||
|
||||
Contributors include:
|
||||
- Paul Ferrand (2019-) paul at ferrand dot cc
|
||||
- Andrea Zanellato (2019-)
|
||||
- Jean-Pierre Cimalando (2020-)
|
||||
- Michael Willis (2020-)
|
||||
- Alexander Mitchell (2020-)
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
|||
118
README.md
118
README.md
|
|
@ -1,53 +1,61 @@
|
|||
# sfizz
|
||||
|
||||
[](https://travis-ci.com/sfztools/sfizz)
|
||||
|
||||
## Building
|
||||
|
||||
[![Travis Build Status]](https://travis-ci.com/sfztools/sfizz)
|
||||
Most people will probably want the LV2 plugin with `libsndfile` built-in statically.
|
||||
You can directly build it this way through Docker:
|
||||
```
|
||||
wget https://raw.githubusercontent.com/sfztools/sfizz/develop/scripts/Dockerfile
|
||||
wget https://raw.githubusercontent.com/sfztools/sfizz/develop/scripts/x64-linux-hidden.cmake
|
||||
docker build -t sfizz .
|
||||
docker cp $(docker create sfizz:latest):/tmp/sfizz/build/sfizz.lv2 .
|
||||
```
|
||||
Note that the statically linked LV2 plugin is to be distributed under the LGPL license, as per the terms of the `libsndfile` library.
|
||||
|
||||
Sfizz depends on the [sndfile] library.
|
||||
The [JACK] client that you will probably build depends on the `jack` library.
|
||||
To build `sfizz` you need to install both as shared libraries on the system.
|
||||
### More generic builds and development
|
||||
|
||||
`sfizz` depends mainly on the `libsndfile` library.
|
||||
To build the other `sfizz` targets you need to install both `libsndfile` and `JACK` as shared libraries on the system.
|
||||
In Debian-based distributions, this translates into
|
||||
|
||||
```bash
|
||||
sudo apt install libjack-jackd2-dev libsndfile1-dev
|
||||
```
|
||||
The benchmarks depend on the `benchmark` library (https://github.com/google/benchmark).
|
||||
If you wish to build the benchmarks you should either build it from source and install the static library, or use the library from your distribution---Ubuntu proposes a `libbenchmark-dev` package that does this.
|
||||
|
||||
The process is as follows:
|
||||
1. Clone the repository with all the submodules
|
||||
2. Create a build directory for CMake and `cd` into it
|
||||
3. Build
|
||||
3. Build as release
|
||||
4. Enjoy :)
|
||||
|
||||
In the shell world, this means
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/sfztools/sfizz.git
|
||||
git checkout develop
|
||||
cd sfizz
|
||||
mkdir build && cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Current configuration switches for CMake are:
|
||||
By default this builds and installs:
|
||||
- The shared library version of sfizz with both C and C++ interfaces
|
||||
- The JACK client
|
||||
|
||||
The JACK client client will forcefully connect to the system output, and open an event input in Jack for you to connect a midi capable software or hardware (e.g. `jack-keyboard`).
|
||||
|
||||
Note that you can disable all targets but the LV2 plugin using
|
||||
```sh
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DSFIZZ_JACK=OFF -DSFIZZ_SHARED=OFF ..
|
||||
```
|
||||
ENABLE_LTO Enable Link Time Optimization [default: ON]
|
||||
SFIZZ_JACK Enable JACK stand-alone build [default: ON]
|
||||
SFIZZ_LV2 Enable LV2 plug-in build [default: ON]
|
||||
SFIZZ_BENCHMARKS Enable benchmarks build [default: OFF]
|
||||
SFIZZ_TESTS Enable tests build [default: OFF]
|
||||
SFIZZ_SHARED Enable shared library build [default: ON]
|
||||
```
|
||||
|
||||
For details about building under macOS, see [here].
|
||||
|
||||
You can then find the JACK client in `clients/sfizz_jack`.
|
||||
Just specify an `.sfz` file as a parameter and you are good to go.
|
||||
The client will forcefully connect to the system output,
|
||||
and open an event input in JACK for you to connect a midi capable software
|
||||
or hardware (e.g. `jack-keyboard`).
|
||||
If no Jack server is already started it will start one with basic options.
|
||||
and process as before.
|
||||
In this case, the LV2 plugin will load `libsndfile` dynamically from your system.
|
||||
|
||||
## Possible pitfalls and alternatives
|
||||
|
||||
|
|
@ -58,11 +66,65 @@ update the submodules manually with
|
|||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
You can build with `clang`, although in that case the CMakeFile
|
||||
defaults to using `libc++` instead of `libstdc++`.
|
||||
You can build with `clang`, although in that case the CMakeFile defaults to using `libc++` instead of `libstdc++`.
|
||||
|
||||
[Travis Build Status]: https://img.shields.io/travis/com/sfztools/sfizz.svg?label=Linux-macOS&style=popout&logo=travis
|
||||
[JACK]: https://jackaudio.org/
|
||||
[sndfile]: http://mega-nerd.com/libsndfile/
|
||||
[here]: https://sfztools.github.io/sfizz/macos
|
||||
### Building with MSVC on windows
|
||||
|
||||
The simplest is to use `vcpkg` as a package manager, which will give you access to `libsndfile`.
|
||||
```powershell
|
||||
git clone https://github.com/Microsoft/vcpkg.git
|
||||
cd vcpkg
|
||||
.\bootstrap-vcpkg.bat
|
||||
.\vcpkg integrate install
|
||||
.\vcpkg integrate powershell
|
||||
```
|
||||
|
||||
Assuming you want to build for x64, install the relevant packages as follows
|
||||
```powershell
|
||||
.\vcpkg.exe install libsndfile:x64-windows-static benchmark:x64-windows-static
|
||||
```
|
||||
|
||||
In the sfizz source directory, you can then build with CMake as usual, although you should clone the windows branch:
|
||||
```powershell
|
||||
git clone --recursive https://github.com/sfztools/sfizz.git
|
||||
cd sfizz
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DSFIZZ_JACK=OFF "-DCMAKE_TOOLCHAIN_FILE=C:\Users\Paul\source\vcpkg\scripts\buildsystems\vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows-static
|
||||
cmake --build . -j 16 --config Release
|
||||
```
|
||||
|
||||
This builds the lv2 plugin in `build\lv2\Release` and the Turtle files in `build\sfizz.lv2`, but the installation procedure is not entirely automatic yet.
|
||||
In particular, having the required DLLs along with `sfizz.dll` is actually not helpful because the system cannot find dlls from another dll's root directory.
|
||||
You thus need to add all of `FLAC.dll`, `libsndfile-1.dll`, `vorbis.dll`, `ogg.dll`, `vorbisenc.dll` in some directory in your `PATH` variable, and manually add `sfizz.dll` to the `sfizz.lv2` directory, and the the `sfizz.lv2` directory to `%APPDATA%\Roaming\LV2`.
|
||||
Ardour should then find the plugin correctly and load it without issues.
|
||||
|
||||
### Building the LV2 plugin with static linkage to `libsndfile` on Linux
|
||||
|
||||
This uses Docker and `vcpkg` on Linux.
|
||||
Install a Docker version and use the `Dockerfile` located in `scripts/`.
|
||||
The `scripts/` directory also contains a `docker_lv2_release.sh` file that automates downloading the current `develop` branch and building an LV2 release plugin.
|
||||
Note that the statically linked LV2 plugin is to be distributed under the LGPL license, as per the terms of the `libsndfile` library.
|
||||
|
||||
## License and contribution information
|
||||
|
||||
Contributors to `sfizz` include:
|
||||
- Paul Ferrand (2019-) (maintainer)
|
||||
- Andrea Zanellato (2019-) (devops, documentation and distribution)
|
||||
- Jean-Pierre Cimalando (2020-)
|
||||
- Michael Willis (2020-)
|
||||
- Alexander Mitchell (2020-)
|
||||
|
||||
The sfizz library makes primary use of:
|
||||
- [libsndfile](https://github.com/erikd/libsndfile/) (licensed under the GNU Lesser General Public License v2.1)
|
||||
- [Abseil](https://github.com/abseil/abseil-cpp) (licensed under the Apache License 2.0)
|
||||
- [atomic_queue](https://github.com/max0x7ba/atomic_queue) by Maxim Egorushkin (licensed under the MIT license)
|
||||
- [filesystem](https://github.com/gulrak/filesystem) by Steffen Schümann (licensed under the BSD 3-Clause license)
|
||||
- [hiir](http://ldesoras.free.fr/prod.html#src_hiir) by Laurent de Soras (licensed under the Do What The Fuck You Want To Public License v2 license)
|
||||
|
||||
The sfizz library also uses in some subprojects:
|
||||
- [Catch2](https://github.com/catchorg/Catch2) (licensed under the Boost Software License 1.0)
|
||||
- [benchmark](https://github.com/google/benchmark) (licensed under the Apache License 2.0)
|
||||
- [LV2](https://lv2plug.in/) (licensed under the ISC license)
|
||||
- [JACK](https://github.com/jackaudio/jack2) (licensed under the GNU Lesser General Public License v2.1)
|
||||
- `neon_mathfun.h` and `sse_mathfun.h` by Julien Pommier (licensed under the zlib license)
|
||||
|
|
|
|||
|
|
@ -1,28 +1,12 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "Config.h"
|
||||
#include "ADSREnvelope.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "../sfizz/ADSREnvelope.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
|
|
@ -35,7 +19,7 @@ constexpr int release = attack;
|
|||
constexpr int releaseTime = envelopeSize - static_cast<int>(envelopeSize / 4);
|
||||
|
||||
// Explicitely instantiate class
|
||||
#include "../sfizz/ADSREnvelope.cpp"
|
||||
#include "ADSREnvelope.cpp"
|
||||
template class sfz::ADSREnvelope<float>;
|
||||
|
||||
static void Point(benchmark::State& state) {
|
||||
|
|
@ -44,12 +28,12 @@ static void Point(benchmark::State& state) {
|
|||
for (auto _ : state) {
|
||||
envelope.reset(attack, release, 1.0, fixedAmount, decay, fixedAmount);
|
||||
envelope.startRelease(releaseTime);
|
||||
for(int offset = 0; offset < envelopeSize; offset += state.range(0))
|
||||
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["Per block"] = benchmark::Counter(envelopeSize / state.range(0), benchmark::Counter::kIsIterationInvariantRate);
|
||||
state.counters["Per block"] = benchmark::Counter(envelopeSize / static_cast<double>(state.range(0)), benchmark::Counter::kIsRate);
|
||||
}
|
||||
|
||||
static void Block(benchmark::State& state) {
|
||||
|
|
@ -58,14 +42,14 @@ static void Block(benchmark::State& state) {
|
|||
for (auto _ : state) {
|
||||
envelope.reset(attack, release, 1.0, fixedAmount, decay, fixedAmount);
|
||||
envelope.startRelease(releaseTime);
|
||||
for(int offset = 0; offset < envelopeSize; offset += state.range(0))
|
||||
for(int offset = 0; offset < envelopeSize; offset += static_cast<int>(state.range(0)))
|
||||
envelope.getBlock(absl::MakeSpan(output));
|
||||
benchmark::DoNotOptimize(output);
|
||||
}
|
||||
|
||||
state.counters["Per block"] = benchmark::Counter(envelopeSize / state.range(0), benchmark::Counter::kIsIterationInvariantRate);
|
||||
state.counters["Per block"] = benchmark::Counter(envelopeSize / static_cast<double>(state.range(0)), benchmark::Counter::kIsRate);
|
||||
}
|
||||
|
||||
BENCHMARK(Point)->RangeMultiplier(2)->Range((2<<6), (2<<11));
|
||||
BENCHMARK(Block)->RangeMultiplier(2)->Range((2<<6), (2<<11));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,26 +1,10 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "Config.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <absl/types/span.h>
|
||||
#include <random>
|
||||
|
|
@ -111,7 +95,7 @@ static void Low(benchmark::State& state) {
|
|||
std::vector<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
|
||||
|
||||
std::normal_distribution<float> dist { };
|
||||
std::generate(input.begin(), input.end(), [&]() {
|
||||
return dist(gen);
|
||||
|
|
@ -126,7 +110,7 @@ static void High(benchmark::State& state) {
|
|||
std::vector<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
|
||||
|
||||
std::normal_distribution<float> dist { };
|
||||
std::generate(input.begin(), input.end(), [&]() {
|
||||
return dist(gen);
|
||||
|
|
@ -141,7 +125,7 @@ static void High_Raw(benchmark::State& state) {
|
|||
std::vector<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
|
||||
|
||||
std::normal_distribution<float> dist { };
|
||||
std::generate(input.begin(), input.end(), [&]() {
|
||||
return dist(gen);
|
||||
|
|
@ -156,7 +140,7 @@ static void High_SSE(benchmark::State& state) {
|
|||
std::vector<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
|
||||
|
||||
std::normal_distribution<float> dist { };
|
||||
std::generate(input.begin(), input.end(), [&]() {
|
||||
return dist(gen);
|
||||
|
|
@ -171,4 +155,4 @@ BENCHMARK(Low)->RangeMultiplier(2)->Range((2<<5), (2<<10));
|
|||
BENCHMARK(High)->RangeMultiplier(2)->Range((2<<5), (2<<10));
|
||||
BENCHMARK(High_Raw)->RangeMultiplier(2)->Range((2<<5), (2<<10));
|
||||
BENCHMARK(High_SSE)->RangeMultiplier(2)->Range((2<<5), (2<<10));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class AddArray : public benchmark::Fixture {
|
||||
public:
|
||||
|
|
@ -113,4 +96,4 @@ BENCHMARK_REGISTER_F(AddArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 1
|
|||
BENCHMARK_REGISTER_F(AddArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(AddArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(AddArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class CopyArray : public benchmark::Fixture {
|
||||
public:
|
||||
|
|
@ -98,4 +81,4 @@ BENCHMARK_REGISTER_F(CopyArray, SIMD)->RangeMultiplier(4)->Range(1 << 4, 1 << 16
|
|||
BENCHMARK_REGISTER_F(CopyArray, StdCopy_Unaligned)->RangeMultiplier(4)->Range(1 << 4, 1 << 16);
|
||||
BENCHMARK_REGISTER_F(CopyArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 4, 1 << 16);
|
||||
BENCHMARK_REGISTER_F(CopyArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 4, 1 << 16);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,40 +1,23 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class CumArray : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.1, 1 };
|
||||
std::uniform_real_distribution<float> dist { 0.1f, 1.0f };
|
||||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
|
|
@ -82,4 +65,4 @@ BENCHMARK_REGISTER_F(CumArray, Sum_Scalar)->RangeMultiplier(4)->Range(1 << 2, 1
|
|||
BENCHMARK_REGISTER_F(CumArray, Sum_SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(CumArray, Sum_Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(CumArray, Sum_SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
class DiffArray : public benchmark::Fixture {
|
||||
|
|
@ -35,7 +18,7 @@ public:
|
|||
void SetUp(const ::benchmark::State& state) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.1, 1 };
|
||||
std::uniform_real_distribution<float> dist { 0.1f, 1.0f };
|
||||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
|
|
@ -84,4 +67,4 @@ BENCHMARK_REGISTER_F(DiffArray, Diff_Scalar)->RangeMultiplier(4)->Range(1 << 2,
|
|||
BENCHMARK_REGISTER_F(DiffArray, Diff_SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(DiffArray, Diff_Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(DiffArray, Diff_SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
79
benchmarks/BM_divide.cpp
Normal file
79
benchmarks/BM_divide.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class Divide : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0, 1 };
|
||||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
divisor = std::vector<float>(state.range(0));
|
||||
std::generate(divisor.begin(), divisor.end(), [&]() { return dist(gen); });
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<float> divisor;
|
||||
std::vector<float> input;
|
||||
std::vector<float> output;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, Straight)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = input[i] / divisor[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, Scalar)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, false>(input, divisor, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, SIMD)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, true>(input, divisor, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, Scalar_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, false>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(Divide, SIMD_Unaligned)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::divide<float, true>(absl::MakeSpan(input).subspan(1), absl::MakeSpan(divisor).subspan(1), absl::MakeSpan(output).subspan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(Divide, Straight)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(Divide, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(Divide, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(Divide, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(Divide, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
81
benchmarks/BM_envelopes.cpp
Normal file
81
benchmarks/BM_envelopes.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
#include "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "EventEnvelopes.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
#include "FloatEnvelopes.cpp"
|
||||
|
||||
class EnvelopeFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state)
|
||||
{
|
||||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(input));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]])
|
||||
{
|
||||
|
||||
}
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 30 };
|
||||
std::vector<float> input;
|
||||
std::vector<float> output;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, Linear)(benchmark::State& state) {
|
||||
sfz::LinearEnvelope<float> envelope;
|
||||
for (auto _ : state)
|
||||
{
|
||||
envelope.registerEvent(static_cast<int>(state.range(0) - 1), dist(gen));
|
||||
envelope.getBlock(absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, LinearQuantized)(benchmark::State& state) {
|
||||
sfz::LinearEnvelope<float> envelope;
|
||||
for (auto _ : state)
|
||||
{
|
||||
envelope.registerEvent(static_cast<int>(state.range(0) - 1), dist(gen));
|
||||
envelope.getQuantizedBlock(absl::MakeSpan(output), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, Multiplicative)(benchmark::State& state) {
|
||||
sfz::MultiplicativeEnvelope<float> envelope;
|
||||
for (auto _ : state)
|
||||
{
|
||||
envelope.registerEvent(static_cast<int>(state.range(0) - 1), dist(gen));
|
||||
envelope.getBlock(absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, MultiplicativeQuantized)(benchmark::State& state) {
|
||||
sfz::MultiplicativeEnvelope<float> envelope;
|
||||
for (auto _ : state)
|
||||
{
|
||||
envelope.registerEvent(static_cast<int>(state.range(0) - 1), dist(gen));
|
||||
envelope.getQuantizedBlock(absl::MakeSpan(output), 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_REGISTER_F(EnvelopeFixture, Linear)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(EnvelopeFixture, LinearQuantized)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(EnvelopeFixture, Multiplicative)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(EnvelopeFixture, MultiplicativeQuantized)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -1,29 +1,12 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "../sfizz/Buffer.h"
|
||||
#include "Buffer.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
|
|
@ -79,9 +62,9 @@ static void FillSIMD_unaligned(benchmark::State& state) {
|
|||
}
|
||||
}
|
||||
|
||||
BENCHMARK(Dummy)->Range((2<<6), (2<<16));
|
||||
BENCHMARK(FillScalar)->Range((2<<6), (2<<16));
|
||||
BENCHMARK(FillSIMD)->Range((2<<6), (2<<16));
|
||||
BENCHMARK(FillScalar_unaligned)->Range((2<<6), (2<<16));
|
||||
BENCHMARK(FillSIMD_unaligned)->Range((2<<6), (2<<16));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1<<2), (1<<12));
|
||||
BENCHMARK(FillScalar)->RangeMultiplier(4)->Range((1<<2), (1<<12));
|
||||
BENCHMARK(FillSIMD)->RangeMultiplier(4)->Range((1<<2), (1<<12));
|
||||
BENCHMARK(FillScalar_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12));
|
||||
BENCHMARK(FillSIMD_unaligned)->RangeMultiplier(4)->Range((1<<2), (1<<12));
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
90
benchmarks/BM_flacfile.cpp
Normal file
90
benchmarks/BM_flacfile.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// 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 <benchmark/benchmark.h>
|
||||
#include <sndfile.hh>
|
||||
#define DR_FLAC_IMPLEMENTATION
|
||||
#include "dr_flac.h"
|
||||
#include "ghc/filesystem.hpp"
|
||||
#include <memory>
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
// #include "libnyquist/Decoders.h"
|
||||
|
||||
class FileFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
filePath1 = getPath() / "sample1.flac";
|
||||
filePath2 = getPath() / "sample2.flac";
|
||||
filePath3 = getPath() / "sample3.flac";
|
||||
if ( !ghc::filesystem::exists(filePath1)
|
||||
|| !ghc::filesystem::exists(filePath2)
|
||||
|| !ghc::filesystem::exists(filePath3) ) {
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Can't find path" << '\n';
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
}
|
||||
|
||||
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::Buffer<float>> buffer;
|
||||
|
||||
ghc::filesystem::path filePath1;
|
||||
ghc::filesystem::path filePath2;
|
||||
ghc::filesystem::path filePath3;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, SndFile)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
SndfileHandle sndfile(filePath1.c_str());
|
||||
buffer = std::make_unique<sfz::Buffer<float>>(sndfile.channels() * sndfile.frames());
|
||||
sndfile.readf(buffer->data(), sndfile.frames());
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, DrFlac)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto* flac = drflac_open_file(filePath2.c_str(), nullptr);
|
||||
buffer = std::make_unique<sfz::Buffer<float>>(flac->channels * flac->totalPCMFrameCount);
|
||||
drflac_read_pcm_frames_f32(flac, flac->totalPCMFrameCount, buffer->data());
|
||||
}
|
||||
}
|
||||
|
||||
// BENCHMARK_DEFINE_F(FileFixture, LibNyquist)(benchmark::State& state) {
|
||||
// for (auto _ : state)
|
||||
// {
|
||||
// nqr::AudioData data;
|
||||
// nqr::NyquistIO loader;
|
||||
// loader.Load(&data, filePath3.string());
|
||||
// benchmark::DoNotOptimize(data);
|
||||
// }
|
||||
// }
|
||||
|
||||
BENCHMARK_REGISTER_F(FileFixture, SndFile);
|
||||
BENCHMARK_REGISTER_F(FileFixture, DrFlac);
|
||||
// BENCHMARK_REGISTER_F(FileFixture, LibNyquist);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class GainSingle : public benchmark::Fixture {
|
||||
public:
|
||||
|
|
@ -140,4 +123,4 @@ BENCHMARK_REGISTER_F(GainArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 <<
|
|||
BENCHMARK_REGISTER_F(GainArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(GainArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(GainArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,32 +1,15 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <absl/algorithm/container.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
// In this one we have an array of jumps
|
||||
|
||||
|
|
@ -90,4 +73,4 @@ BENCHMARK_REGISTER_F(InterpolationCast, Scalar)->RangeMultiplier(2)->Range((2<<6
|
|||
BENCHMARK_REGISTER_F(InterpolationCast, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(InterpolationCast, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,32 +1,15 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 <benchmark/benchmark.h>
|
||||
#include "SIMDHelpers.h"
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <absl/algorithm/container.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
// In this one we have an array of indices
|
||||
|
||||
|
|
@ -92,4 +75,4 @@ BENCHMARK_REGISTER_F(LoopingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6),
|
|||
BENCHMARK_REGISTER_F(LoopingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(LoopingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(LoopingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,27 +1,10 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include "absl/types/span.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <cmath>
|
||||
|
|
@ -36,7 +19,7 @@ public:
|
|||
{
|
||||
std::random_device rd {};
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.1, 1 };
|
||||
std::uniform_real_distribution<float> dist { 0.1f, 1.0f };
|
||||
source = std::vector<float>(state.range(0));
|
||||
result = std::vector<float>(state.range(0));
|
||||
std::generate(source.begin(), source.end(), [&]() { return dist(gen); });
|
||||
|
|
@ -162,4 +145,4 @@ BENCHMARK_REGISTER_F(MyFixture, SIMDSin)->RangeMultiplier(4)->Range(1 << 6, 1 <<
|
|||
BENCHMARK_REGISTER_F(MyFixture, ScalarCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
BENCHMARK_REGISTER_F(MyFixture, SIMDCos)->RangeMultiplier(4)->Range(1 << 6, 1 << 10);
|
||||
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,27 +1,10 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
|
@ -87,4 +70,4 @@ BENCHMARK_REGISTER_F(MeanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 <<
|
|||
BENCHMARK_REGISTER_F(MeanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,27 +1,10 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// 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
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
|
@ -87,4 +70,4 @@ BENCHMARK_REGISTER_F(MeanSquaredArray, Scalar)->RangeMultiplier(4)->Range(1 << 2
|
|||
BENCHMARK_REGISTER_F(MeanSquaredArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanSquaredArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MeanSquaredArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class MultiplyAdd : public benchmark::Fixture {
|
||||
public:
|
||||
|
|
@ -93,4 +76,4 @@ BENCHMARK_REGISTER_F(MultiplyAdd, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 <
|
|||
BENCHMARK_REGISTER_F(MultiplyAdd, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MultiplyAdd, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(MultiplyAdd, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,34 +1,17 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "../sfizz/Config.h"
|
||||
#include "Config.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
class PanArray : public benchmark::Fixture {
|
||||
|
|
@ -36,7 +19,7 @@ public:
|
|||
void SetUp(const ::benchmark::State& state) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.001, 1 };
|
||||
std::uniform_real_distribution<float> dist { 0.001f, 1.0f };
|
||||
pan = std::vector<float>(state.range(0));
|
||||
left = std::vector<float>(state.range(0));
|
||||
right = std::vector<float>(state.range(0));
|
||||
|
|
@ -93,4 +76,4 @@ BENCHMARK_DEFINE_F(PanArray, BlockOps)(benchmark::State& state) {
|
|||
BENCHMARK_REGISTER_F(PanArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(PanArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(PanArray, BlockOps)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,30 +1,13 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <absl/algorithm/container.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
constexpr int bigNumber { 2399132 };
|
||||
|
|
@ -33,8 +16,8 @@ class IterOffset : public benchmark::Fixture {
|
|||
public:
|
||||
void SetUp(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.001, 1 };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.001f, 1.0f };
|
||||
std::uniform_int_distribution<int> jumpDist { 0, 3 };
|
||||
source = std::vector<float>(bigNumber);
|
||||
result.resize(state.range(0));
|
||||
|
|
@ -57,7 +40,7 @@ public:
|
|||
|
||||
BENCHMARK_DEFINE_F(IterOffset, Pointers)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
{
|
||||
sfz::diff<int>(offsets, absl::MakeSpan(jumps));
|
||||
auto jump = jumps.begin();
|
||||
auto in = source.begin();
|
||||
|
|
@ -71,7 +54,7 @@ BENCHMARK_DEFINE_F(IterOffset, Pointers)(benchmark::State& state) {
|
|||
|
||||
BENCHMARK_DEFINE_F(IterOffset, Offsets)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
{
|
||||
auto offset = offsets.begin();
|
||||
auto out = result.begin();
|
||||
while (offset < offsets.end())
|
||||
|
|
@ -83,4 +66,4 @@ BENCHMARK_DEFINE_F(IterOffset, Offsets)(benchmark::State& state) {
|
|||
// Register the function as a benchmark
|
||||
BENCHMARK_REGISTER_F(IterOffset, Pointers)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK_REGISTER_F(IterOffset, Offsets)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,30 +1,13 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "../sfizz/Buffer.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
|
||||
static void Dummy(benchmark::State& state) {
|
||||
|
|
@ -133,6 +116,63 @@ static void MulSIMDUnaligned(benchmark::State& state) {
|
|||
}
|
||||
}
|
||||
|
||||
static void LogDomainScalar(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, false>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::applyGain<float, false>(std::log(2.0f), absl::MakeSpan(output));
|
||||
sfz::exp<float, false>(output, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
static void LogDomainSIMD(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
sfz::linearRamp<float, true>(absl::MakeSpan(output), 1.0f, value);
|
||||
sfz::applyGain<float, true>(std::log(2.0f), absl::MakeSpan(output));
|
||||
sfz::exp<float, true>(output, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
static void LogDomainScalarUnaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
auto outputSpan = absl::MakeSpan(output).subspan(1);
|
||||
sfz::linearRamp<float, false>(outputSpan, 1.0f, value);
|
||||
sfz::applyGain<float, false>(std::log(2.0f), outputSpan);
|
||||
sfz::exp<float, false>(outputSpan, outputSpan);
|
||||
}
|
||||
}
|
||||
|
||||
static void LogDomainSIMDUnaligned(benchmark::State& state) {
|
||||
sfz::Buffer<float> output(state.range(0));
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 1, 2 };
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto value = dist(gen);
|
||||
auto outputSpan = absl::MakeSpan(output).subspan(1);
|
||||
sfz::linearRamp<float, true>(outputSpan, 1.0f, value);
|
||||
sfz::applyGain<float, true>(std::log(2.0f), outputSpan);
|
||||
sfz::exp<float, true>(outputSpan, outputSpan);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the function as a benchmark
|
||||
BENCHMARK(Dummy)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(LinearScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
|
|
@ -143,4 +183,8 @@ BENCHMARK(MulScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
|||
BENCHMARK(MulSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(MulScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(MulSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK(LogDomainScalar)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(LogDomainSIMD)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(LogDomainScalarUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK(LogDomainSIMDUnaligned)->RangeMultiplier(4)->Range((1 << 2), (1 << 12));
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
141
benchmarks/BM_readChunk.cpp
Normal file
141
benchmarks/BM_readChunk.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// 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 "SIMDHelpers.h"
|
||||
#include "Buffer.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <sndfile.hh>
|
||||
#include "ghc/filesystem.hpp"
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#include "dr_wav.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include <memory>
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
class FileFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& /* state */) {
|
||||
rootPath = getPath() / "sample1.wav";
|
||||
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 = std::make_unique<sfz::AudioBuffer<float>>(sndfile.channels(), sndfile.frames());
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, JustRead)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
|
||||
sndfile.readf(buffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, AllocInside)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
auto chunkSize = static_cast<size_t>(state.range(0));
|
||||
size_t framesRead = 0;
|
||||
sndfile.seek(0, SEEK_SET);
|
||||
while(framesRead < numFrames)
|
||||
{
|
||||
sfz::Buffer<float> buffer { chunkSize * sndfile.channels() };
|
||||
auto read = sndfile.readf(buffer.data(), chunkSize);
|
||||
sfz::readInterleaved<float>(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
);
|
||||
framesRead += read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, AllocOutside)(benchmark::State& state) {
|
||||
auto chunkSize = static_cast<size_t>(state.range(0));
|
||||
sfz::Buffer<float> buffer { chunkSize * sndfile.channels() };
|
||||
for (auto _ : state)
|
||||
{
|
||||
size_t framesRead = 0;
|
||||
sndfile.seek(0, SEEK_SET);
|
||||
while(framesRead < numFrames)
|
||||
{
|
||||
auto read = sndfile.readf(buffer.data(), chunkSize);
|
||||
sfz::readInterleaved<float>(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
);
|
||||
framesRead += read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, DrWavChunked)(benchmark::State& state) {
|
||||
auto chunkSize = static_cast<size_t>(state.range(0));
|
||||
drwav wav;
|
||||
if (!drwav_init_file(&wav, rootPath.c_str(), nullptr)) {
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Can't find path" << '\n';
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
sfz::Buffer<float> buffer { chunkSize * wav.channels };
|
||||
|
||||
for (auto _ : state)
|
||||
{
|
||||
size_t framesRead = 0;
|
||||
drwav_seek_to_first_pcm_frame(&wav);
|
||||
while(framesRead < numFrames)
|
||||
{
|
||||
auto read = drwav_read_pcm_frames_f32(&wav, chunkSize, buffer.data());
|
||||
sfz::readInterleaved<float>(
|
||||
absl::MakeSpan(buffer).first(read),
|
||||
output->getSpan(0).subspan(framesRead),
|
||||
output->getSpan(1).subspan(framesRead)
|
||||
);
|
||||
framesRead += read;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(FileFixture, JustRead);
|
||||
BENCHMARK_REGISTER_F(FileFixture, AllocInside)->RangeMultiplier(4)->Range((1 << 8), (1 << 16));
|
||||
BENCHMARK_REGISTER_F(FileFixture, AllocOutside)->RangeMultiplier(4)->Range((1 << 8), (1 << 16));
|
||||
BENCHMARK_REGISTER_F(FileFixture, DrWavChunked)->RangeMultiplier(4)->Range((1 << 8), (1 << 16));
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -1,29 +1,12 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include "Buffer.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "../sfizz/Buffer.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <absl/types/span.h>
|
||||
|
|
@ -96,4 +79,4 @@ BENCHMARK(Scalar_Unaligned)->Range((8<<10), (8<<20));
|
|||
BENCHMARK(SSE_Unaligned)->Range((8<<10), (8<<20));
|
||||
BENCHMARK(Scalar_Unaligned_2)->Range((8<<10), (8<<20));
|
||||
BENCHMARK(SSE_Unaligned_2)->Range((8<<10), (8<<20));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
471
benchmarks/BM_resample.cpp
Normal file
471
benchmarks/BM_resample.cpp
Normal file
|
|
@ -0,0 +1,471 @@
|
|||
// 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 "AudioBuffer.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <memory>
|
||||
#include <samplerate.h>
|
||||
#include <sndfile.hh>
|
||||
#include "ghc/filesystem.hpp"
|
||||
#include "hiir/Upsampler2xFpu.h"
|
||||
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
|
||||
};
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample2xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample4xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample8xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include "hiir/Upsampler2xSse.h"
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
#elif defined(__arm__) || defined (__aarch64__)
|
||||
|
||||
#include "hiir/Upsampler2xNeon.h"
|
||||
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), static_cast<long>(input.size()));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample2xStage<false>(input, output);
|
||||
}
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample4xStage<false>(input, output);
|
||||
}
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample8xStage<false>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample2x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
// auto tempBuffer = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 2);
|
||||
for (size_t channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample4x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
auto tempBuffer = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 4);
|
||||
for (size_t channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer));
|
||||
upsample4xStage<SIMD>(absl::MakeConstSpan(*tempBuffer), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample8x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
auto tempBuffer2x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto tempBuffer4x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 4);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 8);
|
||||
for (size_t channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer2x));
|
||||
upsample4xStage<SIMD>(absl::MakeConstSpan(*tempBuffer2x), absl::MakeSpan(*tempBuffer4x));
|
||||
upsample8xStage<SIMD>(absl::MakeConstSpan(*tempBuffer4x), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
|
||||
class SndFile : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& /* state */)
|
||||
{
|
||||
|
||||
const auto rootPath = getPath() / "sample1.wav";
|
||||
if (!ghc::filesystem::exists(rootPath)) {
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Can't find path" << '\n';
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
SndfileHandle sndfile(rootPath.c_str());
|
||||
numFrames = sndfile.frames();
|
||||
numChannels = sndfile.channels();
|
||||
interleavedBuffer = std::make_unique<sfz::Buffer<float>>(numChannels * numFrames);
|
||||
sndfile.readf(interleavedBuffer->data(), sndfile.frames());
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]])
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
size_t numChannels;
|
||||
size_t numFrames;
|
||||
std::unique_ptr<sfz::Buffer<float>> interleavedBuffer;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR2X_scalar)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample2x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR4X_scalar)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample4x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR8X_scalar)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR2X_vector)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample2x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR4X_vector)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample4x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR8X_vector)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC2x_BEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 2.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC2x_MEDIUM)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 2.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC2x_FASTEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 2.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC4x_BEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 4.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC4x_MEDIUM)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 4.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC4x_FASTEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 4.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC8x_BEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 8.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_BEST_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC8x_MEDIUM)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 8.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_MEDIUM_QUALITY, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, SRC8x_FASTEST)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto intermediateBuffer = std::make_unique<sfz::Buffer<float>>(2 * numChannels * numFrames);
|
||||
SRC_DATA srcData;
|
||||
srcData.data_in = interleavedBuffer->data();
|
||||
srcData.data_out = intermediateBuffer->data();
|
||||
srcData.src_ratio = 8.0;
|
||||
srcData.input_frames = static_cast<long>(numFrames);
|
||||
srcData.output_frames = static_cast<long>(2 * numFrames);
|
||||
src_simple(&srcData, SRC_SINC_FASTEST, static_cast<int>(numChannels));
|
||||
auto outBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, 2 * numFrames);
|
||||
sfz::readInterleaved<float>(*intermediateBuffer, outBuffer->getSpan(0), outBuffer->getSpan(1));
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(SndFile, HIIR8X_default)(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = upsample8x<float>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR2X_scalar);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR4X_scalar);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR8X_scalar);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR2X_vector);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR4X_vector);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR8X_vector);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC2x_BEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC4x_BEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC8x_BEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC2x_MEDIUM);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC4x_MEDIUM);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC2x_FASTEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC8x_MEDIUM);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC4x_FASTEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, SRC8x_FASTEST);
|
||||
BENCHMARK_REGISTER_F(SndFile, HIIR8X_default);
|
||||
BENCHMARK_MAIN();
|
||||
191
benchmarks/BM_resampleChunk.cpp
Normal file
191
benchmarks/BM_resampleChunk.cpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// 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 <memory>
|
||||
#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 = std::make_unique<sfz::AudioBuffer<float>>(sndfile.channels(), numFrames * 4);
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
}
|
||||
|
||||
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<float>(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<float>(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<float>(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();
|
||||
|
|
@ -1,32 +1,15 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <vector>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <absl/algorithm/container.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
// In this one we have an array of indices
|
||||
|
||||
|
|
@ -91,4 +74,4 @@ BENCHMARK_REGISTER_F(SaturatingFixture, Scalar)->RangeMultiplier(2)->Range((2<<6
|
|||
BENCHMARK_REGISTER_F(SaturatingFixture, SIMD)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(SaturatingFixture, Scalar_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_REGISTER_F(SaturatingFixture, SIMD_Unaligned)->RangeMultiplier(2)->Range((2<<6), (2<<12));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,33 +1,16 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
|
||||
class SubArray : public benchmark::Fixture {
|
||||
public:
|
||||
|
|
@ -82,4 +65,4 @@ BENCHMARK_REGISTER_F(SubArray, Scalar)->RangeMultiplier(4)->Range(1 << 2, 1 << 1
|
|||
BENCHMARK_REGISTER_F(SubArray, SIMD)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(SubArray, Scalar_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_REGISTER_F(SubArray, SIMD_Unaligned)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
95
benchmarks/BM_wavfile.cpp
Normal file
95
benchmarks/BM_wavfile.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// 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 <benchmark/benchmark.h>
|
||||
#include <sndfile.hh>
|
||||
#define DR_WAV_IMPLEMENTATION
|
||||
#include "dr_wav.h"
|
||||
#include "ghc/filesystem.hpp"
|
||||
#include <memory>
|
||||
#ifndef NDEBUG
|
||||
#include <iostream>
|
||||
#endif
|
||||
// #include "libnyquist/Decoders.h"
|
||||
|
||||
class FileFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
filePath1 = getPath() / "sample1.wav";
|
||||
filePath2 = getPath() / "sample2.wav";
|
||||
filePath3 = getPath() / "sample3.wav";
|
||||
if ( !ghc::filesystem::exists(filePath1)
|
||||
|| !ghc::filesystem::exists(filePath2)
|
||||
|| !ghc::filesystem::exists(filePath3)) {
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Can't find path" << '\n';
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]]) {
|
||||
}
|
||||
|
||||
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::Buffer<float>> buffer;
|
||||
|
||||
ghc::filesystem::path filePath1;
|
||||
ghc::filesystem::path filePath2;
|
||||
ghc::filesystem::path filePath3;
|
||||
};
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, SndFile)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
SndfileHandle sndfile(filePath1.c_str());
|
||||
buffer = std::make_unique<sfz::Buffer<float>>(sndfile.channels() * sndfile.frames());
|
||||
sndfile.readf(buffer->data(), sndfile.frames());
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FileFixture, DrWav)(benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
drwav wav;
|
||||
if (!drwav_init_file(&wav, filePath2.c_str(), nullptr)) {
|
||||
#ifndef NDEBUG
|
||||
std::cerr << "Can't find path" << '\n';
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
buffer = std::make_unique<sfz::Buffer<float>>(wav.channels * wav.totalPCMFrameCount);
|
||||
drwav_read_pcm_frames_f32(&wav, wav.totalPCMFrameCount, buffer->data());
|
||||
}
|
||||
}
|
||||
|
||||
// BENCHMARK_DEFINE_F(FileFixture, LibNyquist)(benchmark::State& state) {
|
||||
// for (auto _ : state)
|
||||
// {
|
||||
// nqr::AudioData data;
|
||||
// nqr::NyquistIO loader;
|
||||
// loader.Load(&data, filePath3.string());
|
||||
// benchmark::DoNotOptimize(data);
|
||||
// }
|
||||
// }
|
||||
|
||||
BENCHMARK_REGISTER_F(FileFixture, SndFile);
|
||||
BENCHMARK_REGISTER_F(FileFixture, DrWav);
|
||||
// BENCHMARK_REGISTER_F(FileFixture, LibNyquist);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -1,29 +1,12 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// 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 "SIMDHelpers.h"
|
||||
#include "Buffer.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include "../sfizz/SIMDHelpers.h"
|
||||
#include "../sfizz/Buffer.h"
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <absl/types/span.h>
|
||||
|
|
@ -106,4 +89,4 @@ BENCHMARK(Unaligned_Interleaved_Write)->Range((8<<10), (8<<20));
|
|||
BENCHMARK(Unaligned_Interleaved_Write_SSE)->Range((8<<10), (8<<20));
|
||||
BENCHMARK(Unaligned_Interleaved_Write_2)->Range((8<<10), (8<<20));
|
||||
BENCHMARK(Unaligned_Interleaved_Write_SSE_2)->Range((8<<10), (8<<20));
|
||||
BENCHMARK_MAIN();
|
||||
BENCHMARK_MAIN();
|
||||
|
|
|
|||
|
|
@ -1,95 +1,133 @@
|
|||
project(sfizz)
|
||||
|
||||
# Check SIMD
|
||||
include(CheckIncludeFiles)
|
||||
CHECK_INCLUDE_FILES(x86intrin.h HAVE_X86INTRIN_H)
|
||||
CHECK_INCLUDE_FILES(intrin.h HAVE_INTRIN_H)
|
||||
CHECK_INCLUDE_FILES(arm_neon.h HAVE_ARM_NEON_H)
|
||||
|
||||
# SIMD checks
|
||||
if (HAVE_X86INTRIN_H AND UNIX)
|
||||
add_compile_options(-DHAVE_X86INTRIN_H)
|
||||
set(SFIZZ_SIMD_SOURCES ../sfizz/SIMDSSE.cpp)
|
||||
elseif (HAVE_INTRIN_H AND WIN32)
|
||||
add_compile_options(/DHAVE_INTRIN_H)
|
||||
set(SFIZZ_SIMD_SOURCES ../sfizz/SIMDSSE.cpp)
|
||||
elseif (HAVE_ARM_NEON_H AND UNIX)
|
||||
add_compile_options(-DHAVE_ARM_NEON_H)
|
||||
add_compile_options(-mfpu=neon-fp-armv8)
|
||||
add_compile_options(-march=native)
|
||||
add_compile_options(-mtune=cortex-a53)
|
||||
add_compile_options(-funsafe-math-optimizations)
|
||||
set(SFIZZ_SIMD_SOURCES ../sfizz/SIMDNEON.cpp)
|
||||
else()
|
||||
set(SFIZZ_SIMD_SOURCES ../sfizz/SIMDDummy.cpp)
|
||||
endif()
|
||||
include (SfizzSIMDSourceFilesCheck)
|
||||
set(BENCHMARK_SIMD_SOURCES ${SFIZZ_SIMD_SOURCES})
|
||||
list(TRANSFORM BENCHMARK_SIMD_SOURCES PREPEND "../src/")
|
||||
find_package(benchmark CONFIG REQUIRED)
|
||||
|
||||
add_executable(bm_opf_high_vs_low BM_OPF_high_vs_low.cpp)
|
||||
target_link_libraries(bm_opf_high_vs_low benchmark absl::span)
|
||||
target_link_libraries(bm_opf_high_vs_low PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_opf_high_vs_low PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_write BM_writeInterleaved.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_write benchmark absl::span)
|
||||
add_executable(bm_write BM_writeInterleaved.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_write PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_write PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_read BM_readInterleaved.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_read benchmark absl::span)
|
||||
add_executable(bm_read BM_readInterleaved.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_read PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_read PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_fill BM_fill.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_fill benchmark absl::span)
|
||||
add_executable(bm_fill BM_fill.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_fill PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_fill PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_mathfuns BM_mathfuns.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_mathfuns benchmark absl::span)
|
||||
add_executable(bm_mathfuns BM_mathfuns.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_mathfuns PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_mathfuns PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_gain BM_gain.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_gain benchmark absl::span)
|
||||
add_executable(bm_gain BM_gain.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_gain PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_gain PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_looping BM_looping.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_looping benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_divide BM_divide.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_divide PRIVATE absl::span benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_divide PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_saturating BM_saturating.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_saturating benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_looping BM_looping.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_looping PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_looping PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_ramp BM_ramp.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_ramp benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_saturating BM_saturating.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_saturating PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_saturating PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_ADSR BM_ADSR.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_ADSR benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_ramp BM_ramp.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_ramp PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_ramp PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_add BM_add.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_add benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_ADSR BM_ADSR.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_ADSR PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_ADSR PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_multiplyAdd BM_multiplyAdd.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_multiplyAdd benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_add BM_add.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_add PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_add PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_subtract BM_subtract.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_subtract benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_multiplyAdd BM_multiplyAdd.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_multiplyAdd PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_multiplyAdd PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_copy BM_copy.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_copy benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_subtract BM_subtract.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_subtract PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_subtract PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_pan BM_pan.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_pan benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_copy BM_copy.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_copy PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_copy PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_mean BM_mean.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_mean benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_pan BM_pan.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_pan PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_pan PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_meanSquared BM_meanSquared.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_meanSquared benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_mean BM_mean.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_mean PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_mean PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_cumsum BM_cumsum.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_cumsum benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_meanSquared BM_meanSquared.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_meanSquared PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_meanSquared PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_diff BM_diff.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_diff benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_cumsum BM_cumsum.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_cumsum PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_cumsum PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_interpolationCast BM_interpolationCast.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_interpolationCast benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_diff BM_diff.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_diff PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_diff PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp ${SFIZZ_SIMD_SOURCES})
|
||||
target_link_libraries(bm_pointerIterationOrOffsets benchmark absl::span absl::algorithm)
|
||||
add_executable(bm_interpolationCast BM_interpolationCast.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_interpolationCast PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_interpolationCast PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_pointerIterationOrOffsets PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_pointerIterationOrOffsets PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
if (NOT WIN32)
|
||||
add_executable(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_resample PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main samplerate)
|
||||
sfizz_link_libsndfile(bm_resample)
|
||||
target_include_directories(bm_resample PRIVATE ../src/sfizz ../src/external)
|
||||
endif()
|
||||
|
||||
add_executable(bm_envelopes BM_envelopes.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_envelopes PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
target_include_directories(bm_envelopes PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_wavfile BM_wavfile.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_wavfile PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
sfizz_link_libsndfile(bm_wavfile)
|
||||
target_include_directories(bm_wavfile PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_flacfile BM_flacfile.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_flacfile PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
sfizz_link_libsndfile(bm_flacfile)
|
||||
target_include_directories(bm_flacfile PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_readChunk BM_readChunk.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_readChunk PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
sfizz_link_libsndfile(bm_readChunk)
|
||||
target_include_directories(bm_readChunk PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_executable(bm_resampleChunk BM_resampleChunk.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
target_link_libraries(bm_resampleChunk PRIVATE absl::span absl::algorithm benchmark::benchmark benchmark::benchmark_main)
|
||||
sfizz_link_libsndfile(bm_resampleChunk)
|
||||
target_include_directories(bm_resampleChunk PRIVATE ../src/sfizz ../src/external)
|
||||
|
||||
add_custom_target(sfizz_benchmarks)
|
||||
add_dependencies(sfizz_benchmarks
|
||||
bm_opf_high_vs_low
|
||||
add_dependencies(sfizz_benchmarks
|
||||
bm_opf_high_vs_low
|
||||
bm_write
|
||||
bm_pointerIterationOrOffsets
|
||||
bm_read
|
||||
|
|
@ -101,6 +139,7 @@ add_dependencies(sfizz_benchmarks
|
|||
bm_interpolationCast
|
||||
bm_mathfuns
|
||||
bm_gain
|
||||
bm_divide
|
||||
bm_looping
|
||||
bm_saturating
|
||||
bm_ramp
|
||||
|
|
@ -109,4 +148,20 @@ add_dependencies(sfizz_benchmarks
|
|||
bm_pan
|
||||
bm_subtract
|
||||
bm_multiplyAdd
|
||||
)
|
||||
bm_readChunk
|
||||
bm_resampleChunk
|
||||
bm_envelopes
|
||||
bm_wavfile
|
||||
bm_flacfile
|
||||
)
|
||||
|
||||
if (NOT WIN32)
|
||||
add_dependencies(sfizz_benchmarks bm_resample)
|
||||
endif()
|
||||
|
||||
file(COPY "sample1.wav" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
file(COPY "sample2.wav" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
file(COPY "sample3.wav" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
file(COPY "sample1.flac" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
file(COPY "sample2.flac" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
file(COPY "sample3.flac" DESTINATION ${CMAKE_BINARY_DIR}/benchmarks)
|
||||
|
|
|
|||
11060
benchmarks/dr_flac.h
Normal file
11060
benchmarks/dr_flac.h
Normal file
File diff suppressed because it is too large
Load diff
5358
benchmarks/dr_wav.h
Normal file
5358
benchmarks/dr_wav.h
Normal file
File diff suppressed because it is too large
Load diff
BIN
benchmarks/ride.wav
Executable file
BIN
benchmarks/ride.wav
Executable file
Binary file not shown.
BIN
benchmarks/ride2.wav
Executable file
BIN
benchmarks/ride2.wav
Executable file
Binary file not shown.
BIN
benchmarks/sample1.flac
Executable file
BIN
benchmarks/sample1.flac
Executable file
Binary file not shown.
BIN
benchmarks/sample1.wav
Executable file
BIN
benchmarks/sample1.wav
Executable file
Binary file not shown.
BIN
benchmarks/sample2.flac
Executable file
BIN
benchmarks/sample2.flac
Executable file
Binary file not shown.
BIN
benchmarks/sample2.wav
Executable file
BIN
benchmarks/sample2.wav
Executable file
Binary file not shown.
BIN
benchmarks/sample3.flac
Executable file
BIN
benchmarks/sample3.flac
Executable file
Binary file not shown.
BIN
benchmarks/sample3.wav
Executable file
BIN
benchmarks/sample3.wav
Executable file
Binary file not shown.
|
|
@ -1,19 +1,11 @@
|
|||
project(sfizz)
|
||||
project (sfizz)
|
||||
|
||||
###############################
|
||||
add_executable(sfzprint sfzprint.cpp)
|
||||
target_link_libraries(sfzprint sfizz::parser absl::flags_parse)
|
||||
|
||||
###############################
|
||||
# Basic command line program
|
||||
if(APPLE)
|
||||
find_path(JACK_INCLUDE_DIR NAMES jack.h PATHS "/usr/local/include/jack")
|
||||
find_library(JACK_LIBRARY NAMES jack PATHS "/usr/local/lib")
|
||||
message(STATUS "include dir: " ${JACK_INCLUDE_DIR} " lib: " ${JACK_LIBRARY})
|
||||
add_library(jack SHARED IMPORTED GLOBAL)
|
||||
target_include_directories(jack INTERFACE ${JACK_INCLUDE_DIR})
|
||||
target_link_libraries(jack INTERFACE ${JACK_LIBRARY})
|
||||
if (APPLE)
|
||||
include_directories (SYSTEM /usr/local/opt/jack/include)
|
||||
link_directories (/usr/local/opt/jack/lib)
|
||||
endif()
|
||||
|
||||
add_executable(sfizz_jack jack_client.cpp)
|
||||
target_link_libraries(sfizz_jack sfizz::sfizz jack absl::flags_parse)
|
||||
add_executable (sfizz_jack jack_client.cpp)
|
||||
target_link_libraries (sfizz_jack sfizz::sfizz jack absl::flags_parse)
|
||||
sfizz_enable_lto_if_needed (sfizz_jack)
|
||||
install (TARGETS sfizz_jack DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "AudioSpan.h"
|
||||
#include "Synth.h"
|
||||
#include "sfizz/Synth.h"
|
||||
#include <absl/flags/parse.h>
|
||||
#include <absl/flags/flag.h>
|
||||
#include <absl/types/span.h>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
|
|
@ -64,6 +64,11 @@ constexpr uint8_t channel(uint8_t midiStatusByte)
|
|||
{
|
||||
return midiStatusByte & channelMask;
|
||||
}
|
||||
|
||||
constexpr int buildAndCenterPitch(uint8_t firstByte, uint8_t secondByte)
|
||||
{
|
||||
return (int)(((unsigned int)secondByte << 7) + (unsigned int)firstByte) - 8192;
|
||||
}
|
||||
}
|
||||
|
||||
static std::atomic<bool> keepRunning [[maybe_unused]] { true };
|
||||
|
|
@ -88,31 +93,32 @@ int process(jack_nframes_t numFrames, void* arg [[maybe_unused]])
|
|||
|
||||
switch (midi::status(event.buffer[0])) {
|
||||
case midi::noteOff:
|
||||
DBG("[MIDI] Note " << +event.buffer[1] << " OFF at time " << event.time);
|
||||
synth->noteOff(event.time, midi::channel(event.buffer[0]) + 1, event.buffer[1], event.buffer[2]);
|
||||
// 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:
|
||||
DBG("[MIDI] Note " << +event.buffer[1] << " ON at time " << event.time);
|
||||
synth->noteOn(event.time, midi::channel(event.buffer[0]) + 1, event.buffer[1], event.buffer[2]);
|
||||
// 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);
|
||||
// DBG("[MIDI] Polyphonic pressure on at time " << event.time);
|
||||
break;
|
||||
case midi::controlChange:
|
||||
DBG("[MIDI] CC " << +event.buffer[1] << " at time " << event.time);
|
||||
synth->cc(event.time, midi::channel(event.buffer[0]) + 1, event.buffer[1], event.buffer[2]);
|
||||
// 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);
|
||||
// DBG("[MIDI] Program change at time " << event.time);
|
||||
break;
|
||||
case midi::channelPressure:
|
||||
DBG("[MIDI] Channel pressure at time " << event.time);
|
||||
// DBG("[MIDI] Channel pressure at time " << event.time);
|
||||
break;
|
||||
case midi::pitchBend:
|
||||
DBG("[MIDI] Pitch bend at time " << event.time);
|
||||
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);
|
||||
// DBG("[MIDI] System message at time " << event.time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -130,7 +136,7 @@ int sampleBlockChanged(jack_nframes_t nframes, void* arg [[maybe_unused]])
|
|||
return 0;
|
||||
|
||||
auto synth = reinterpret_cast<sfz::Synth*>(arg);
|
||||
DBG("Sample per block changed to " << nframes);
|
||||
// DBG("Sample per block changed to " << nframes);
|
||||
synth->setSamplesPerBlock(nframes);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -141,7 +147,7 @@ int sampleRateChanged(jack_nframes_t nframes, void* arg [[maybe_unused]])
|
|||
return 0;
|
||||
|
||||
auto synth = reinterpret_cast<sfz::Synth*>(arg);
|
||||
DBG("Sample rate changed to " << nframes);
|
||||
// DBG("Sample rate changed to " << nframes);
|
||||
synth->setSampleRate(nframes);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -157,17 +163,41 @@ static void done(int sig [[maybe_unused]])
|
|||
// exit(0);
|
||||
}
|
||||
|
||||
ABSL_FLAG(std::string, oversampling, "1x", "Internal oversampling factor (value values are x1, x2, x4, x8)");
|
||||
ABSL_FLAG(uint32_t, preload_size, 8192, "Preloaded value");
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// std::ios::sync_with_stdio(false);
|
||||
auto arguments = absl::ParseCommandLine(argc, argv);
|
||||
if (arguments.size() < 2) {
|
||||
std::cout << "You need to specify an SFZ file to load." << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto filesToParse = absl::MakeConstSpan(arguments).subspan(1);
|
||||
const std::string oversampling = absl::GetFlag(FLAGS_oversampling);
|
||||
const uint32_t preload_size = absl::GetFlag(FLAGS_preload_size);
|
||||
|
||||
std::cout << "Flags" << '\n';
|
||||
std::cout << "- Oversampling: " << oversampling << '\n';
|
||||
std::cout << "- Preloaded Size: " << preload_size << '\n';
|
||||
const auto factor = [&]() {
|
||||
if (oversampling == "x1") return sfz::Oversampling::x1;
|
||||
if (oversampling == "x2") return sfz::Oversampling::x2;
|
||||
if (oversampling == "x4") return sfz::Oversampling::x4;
|
||||
if (oversampling == "x8") return sfz::Oversampling::x8;
|
||||
return sfz::Oversampling::x1;
|
||||
}();
|
||||
|
||||
std::cout << "Positional arguments:";
|
||||
for (auto& file : filesToParse)
|
||||
std::cout << " " << file << ',';
|
||||
std::cout << '\n';
|
||||
|
||||
sfz::Synth synth;
|
||||
synth.setOversamplingFactor(factor);
|
||||
synth.setPreloadSize(preload_size);
|
||||
synth.loadSfzFile(filesToParse[0]);
|
||||
std::cout << "==========" << '\n';
|
||||
std::cout << "Total:" << '\n';
|
||||
|
|
@ -254,11 +284,14 @@ int main(int argc, char** argv)
|
|||
signal(SIGQUIT, done);
|
||||
|
||||
while (!shouldClose){
|
||||
// synth.garbageCollect();
|
||||
std::this_thread::sleep_for(1s);
|
||||
#ifndef NDEBUG
|
||||
std::cout << "Allocated buffers: " << synth.getAllocatedBuffers() << '\n';
|
||||
std::cout << "Total size: " << synth.getAllocatedBytes() << '\n';
|
||||
#endif
|
||||
std::this_thread::sleep_for(2s);
|
||||
}
|
||||
|
||||
std::cout << "Closing..." << '\n';
|
||||
jack_client_close(client);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright (c) 2019, Paul Ferrand
|
||||
// All rights reserved.
|
||||
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Parser.h"
|
||||
#include "StringViewHelpers.h"
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
#include <absl/flags/parse.h>
|
||||
#include <absl/types/span.h>
|
||||
|
||||
class PrintingParser: public sfz::Parser
|
||||
{
|
||||
public:
|
||||
int getNumRegions() const noexcept { return numRegions; }
|
||||
int getNumGroups() const noexcept { return numGroups; }
|
||||
int getNumMasters() const noexcept { return numMasters; }
|
||||
int getNumCurves() const noexcept { return numCurves; }
|
||||
protected:
|
||||
void callback(absl::string_view header, const std::vector<sfz::Opcode>& members [[maybe_unused]]) final
|
||||
{
|
||||
switch (hash(header))
|
||||
{
|
||||
case hash("master"): numMasters++; break;
|
||||
case hash("group"): numGroups++; break;
|
||||
case hash("region"): numRegions++; break;
|
||||
case hash("curve"): numCurves++; break;
|
||||
}
|
||||
std::cout << "[" << header << "]" << ' ';
|
||||
for (auto& member: members)
|
||||
{
|
||||
std::cout << member.opcode << "=" << member.value;
|
||||
if (member.parameter)
|
||||
std::cout << " (" << (int)*member.parameter << ")";
|
||||
std::cout << ' ';
|
||||
}
|
||||
std::cout << '\n';
|
||||
}
|
||||
private:
|
||||
int numRegions { 0 };
|
||||
int numGroups { 0 };
|
||||
int numMasters { 0 };
|
||||
int numCurves { 0 };
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::ios::sync_with_stdio(false);
|
||||
auto arguments = absl::ParseCommandLine(argc, argv);
|
||||
auto filesToParse = absl::MakeConstSpan(arguments).subspan(1);
|
||||
std::cout << "Positional arguments:";
|
||||
for (auto& file: filesToParse)
|
||||
std::cout << " " << file << ',';
|
||||
std::cout << '\n';
|
||||
|
||||
PrintingParser parser;
|
||||
parser.loadSfzFile(filesToParse[0]);
|
||||
std::cout << "==========" << '\n';
|
||||
std::cout << "Total:" << '\n';
|
||||
std::cout << "\tMasters: " << parser.getNumMasters() << '\n';
|
||||
std::cout << "\tGroups: " << parser.getNumGroups() << '\n';
|
||||
std::cout << "\tRegions: " << parser.getNumRegions() << '\n';
|
||||
std::cout << "\tCurves: " << parser.getNumCurves() << '\n';
|
||||
std::cout << "==========" << '\n';
|
||||
std::cout << "Included files:" << '\n';
|
||||
for (auto& file: parser.getIncludedFiles())
|
||||
std::cout << '\t' << file.c_str() << '\n';
|
||||
std::cout << "==========" << '\n';
|
||||
std::cout << "Defines:" << '\n';
|
||||
for (auto& define: parser.getDefines())
|
||||
std::cout << '\t' << define.first << '=' << define.second << '\n';
|
||||
// spdlog::info("Done!");
|
||||
return 0;
|
||||
}
|
||||
25
cmake/CheckIPO.cmake
Normal file
25
cmake/CheckIPO.cmake
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# Added in CMake 3.9
|
||||
include (CheckIPOSupported)
|
||||
check_ipo_supported (RESULT result OUTPUT output)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
|
||||
set(ENABLE_LTO OFF)
|
||||
endif()
|
||||
|
||||
if (result AND ENABLE_LTO AND CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
message (STATUS "\nLTO enabled.")
|
||||
else()
|
||||
if (${output})
|
||||
message (WARNING "\nIPO disabled: ${output}")
|
||||
else()
|
||||
message (WARNING "\nIPO was disabled or not in a Release build.")
|
||||
endif()
|
||||
set (ENABLE_LTO OFF)
|
||||
endif()
|
||||
|
||||
function (SFIZZ_ENABLE_LTO_IF_NEEDED TARGET)
|
||||
if (${ENABLE_LTO})
|
||||
message(STATUS "Enabling LTO on ${TARGET}")
|
||||
set_property (TARGET ${TARGET} PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
|
||||
endif()
|
||||
endfunction()
|
||||
24
cmake/LV2Config.cmake
Normal file
24
cmake/LV2Config.cmake
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Configuration for this plugin
|
||||
# TODO: generate version from git
|
||||
set (LV2PLUGIN_VERSION_MINOR 2)
|
||||
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 "Paul Ferrand")
|
||||
set (LV2PLUGIN_EMAIL "paul at ferrand dot cc")
|
||||
if (SFIZZ_USE_VCPKG)
|
||||
set (LV2PLUGIN_SPDX_LICENSE_ID "LGPL-3.0-only")
|
||||
else()
|
||||
set (LV2PLUGIN_SPDX_LICENSE_ID "ISC")
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
set (LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lv2" CACHE STRING
|
||||
"Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lv2}]")
|
||||
else()
|
||||
set (LV2PLUGIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib/lv2" CACHE STRING
|
||||
"Install destination for LV2 bundle [default: ${CMAKE_INSTALL_PREFIX}/lib/lv2}]")
|
||||
endif()
|
||||
75
cmake/SfizzConfig.cmake
Normal file
75
cmake/SfizzConfig.cmake
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Do not override the C++ standard if set to more than 14
|
||||
if (NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
endif()
|
||||
|
||||
# Export the compile_commands.json file
|
||||
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)
|
||||
|
||||
# Add required flags for the builds
|
||||
if (UNIX)
|
||||
add_compile_options(-Wall)
|
||||
add_compile_options(-Wextra)
|
||||
add_compile_options(-ffast-math)
|
||||
add_compile_options(-fno-omit-frame-pointer) # For debugging purposes
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
add_compile_options(/Zc:__cplusplus)
|
||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
endif()
|
||||
|
||||
if (WIN32 OR SFIZZ_USE_VCPKG)
|
||||
find_package(LibSndFile REQUIRED)
|
||||
find_path(SNDFILE_INCLUDE_DIR sndfile.hh)
|
||||
endif()
|
||||
|
||||
function(SFIZZ_LINK_LIBSNDFILE TARGET)
|
||||
if (WIN32 OR SFIZZ_USE_VCPKG)
|
||||
target_link_libraries (${TARGET} PRIVATE sndfile-static)
|
||||
target_include_directories(${TARGET} PUBLIC ${SNDFILE_INCLUDE_DIR})
|
||||
else()
|
||||
target_link_libraries(${TARGET} PRIVATE sndfile)
|
||||
endif()
|
||||
endfunction(SFIZZ_LINK_LIBSNDFILE)
|
||||
|
||||
# If we build with Clang use libc++
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT ANDROID)
|
||||
set(USE_LIBCPP ON CACHE BOOL "Use libc++ with clang")
|
||||
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()
|
||||
|
||||
# Don't show build information when building a different project
|
||||
function (show_build_info_if_needed)
|
||||
if (CMAKE_PROJECT_NAME STREQUAL "sfizz")
|
||||
message (STATUS "
|
||||
Project name: ${PROJECT_NAME}
|
||||
Build type: ${CMAKE_BUILD_TYPE}
|
||||
Build using LTO: ${ENABLE_LTO}
|
||||
Build as shared library: ${SFIZZ_SHARED}
|
||||
Build JACK stand-alone client: ${SFIZZ_JACK}
|
||||
Build LV2 plug-in: ${SFIZZ_LV2}
|
||||
Build benchmarks: ${SFIZZ_BENCHMARKS}
|
||||
Build tests: ${SFIZZ_TESTS}
|
||||
|
||||
Install prefix: ${CMAKE_INSTALL_PREFIX}
|
||||
LV2 destination directory: ${LV2PLUGIN_INSTALL_DIR}
|
||||
|
||||
Compiler CXX debug flags: ${CMAKE_CXX_FLAGS_DEBUG}
|
||||
Compiler CXX release flags: ${CMAKE_CXX_FLAGS_RELEASE}
|
||||
Compiler CXX min size flags: ${CMAKE_CXX_FLAGS_MINSIZEREL}
|
||||
")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
find_package (Threads REQUIRED)
|
||||
27
cmake/SfizzSIMDSourceFilesCheck.cmake
Normal file
27
cmake/SfizzSIMDSourceFilesCheck.cmake
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Check SIMD
|
||||
include (CheckIncludeFiles)
|
||||
CHECK_INCLUDE_FILES(x86intrin.h HAVE_X86INTRIN_H)
|
||||
CHECK_INCLUDE_FILES(intrin.h HAVE_INTRIN_H)
|
||||
|
||||
if (!APPLE)
|
||||
CHECK_INCLUDE_FILES (arm_neon.h HAVE_ARM_NEON_H)
|
||||
endif()
|
||||
|
||||
# SIMD checks
|
||||
if (HAVE_X86INTRIN_H AND UNIX)
|
||||
add_compile_options (-DHAVE_X86INTRIN_H)
|
||||
set (SFIZZ_SIMD_SOURCES sfizz/SIMDSSE.cpp)
|
||||
elseif (HAVE_INTRIN_H AND WIN32)
|
||||
add_compile_options (/DHAVE_INTRIN_H)
|
||||
set (SFIZZ_SIMD_SOURCES sfizz/SIMDSSE.cpp)
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l")
|
||||
add_compile_options (-DHAVE_ARM_NEON_H)
|
||||
add_compile_options (-mfpu=neon)
|
||||
add_compile_options (-march=native)
|
||||
add_compile_options (-mtune=cortex-a53)
|
||||
set (SFIZZ_SIMD_SOURCES sfizz/SIMDNEON.cpp)
|
||||
else()
|
||||
set (SFIZZ_SIMD_SOURCES sfizz/SIMDDummy.cpp)
|
||||
endif()
|
||||
|
||||
set (SFIZZ_SOURCES ${SFIZZ_SOURCES} ${SFIZZ_SIMD_SOURCES})
|
||||
187
doxygen/layout/DoxygenLayout.xml
Normal file
187
doxygen/layout/DoxygenLayout.xml
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<doxygenlayout version="1.0">
|
||||
<!-- Navigation index tabs for HTML output -->
|
||||
<navindex>
|
||||
<tab type="mainpage" visible="no" title=""/>
|
||||
<tab type="pages" visible="yes" title="" intro=""/>
|
||||
<tab type="modules" visible="yes" title="Categories" intro=""/>
|
||||
<tab type="namespaces" visible="yes" title="">
|
||||
<tab type="namespacelist" visible="yes" title="" intro=""/>
|
||||
<tab type="namespacemembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="classes" visible="yes" title="">
|
||||
<tab type="classlist" visible="yes" title="" intro=""/>
|
||||
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
|
||||
<tab type="hierarchy" visible="yes" title="" intro=""/>
|
||||
<tab type="classmembers" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="files" visible="yes" title="">
|
||||
<tab type="filelist" visible="yes" title="" intro=""/>
|
||||
<tab type="globals" visible="yes" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
<!-- Layout definition for a class page -->
|
||||
<class>
|
||||
<briefdescription visible="no"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<inheritancegraph visible="$CLASS_GRAPH"/>
|
||||
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<membergroups visible="yes"/>
|
||||
<nestedclasses visible="yes" title=""/>
|
||||
<publictypes title=""/>
|
||||
<publicslots title=""/>
|
||||
<signals title=""/>
|
||||
<publicmethods title=""/>
|
||||
<publicstaticmethods title=""/>
|
||||
<publicattributes title=""/>
|
||||
<publicstaticattributes title=""/>
|
||||
<protectedtypes title=""/>
|
||||
<protectedslots title=""/>
|
||||
<protectedmethods title=""/>
|
||||
<protectedstaticmethods title=""/>
|
||||
<protectedattributes title=""/>
|
||||
<protectedstaticattributes title=""/>
|
||||
<packagetypes title=""/>
|
||||
<packagemethods title=""/>
|
||||
<packagestaticmethods title=""/>
|
||||
<packageattributes title=""/>
|
||||
<packagestaticattributes title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
<privatetypes title=""/>
|
||||
<privateslots title=""/>
|
||||
<privatemethods title=""/>
|
||||
<privatestaticmethods title=""/>
|
||||
<privateattributes title=""/>
|
||||
<privatestaticattributes title=""/>
|
||||
<friends title=""/>
|
||||
<related title="" subtitle=""/>
|
||||
</memberdecl>
|
||||
<allmemberslink visible="yes"/>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<constructors title=""/>
|
||||
<functions title=""/>
|
||||
<related title=""/>
|
||||
<variables title=""/>
|
||||
<properties title=""/>
|
||||
<events title=""/>
|
||||
</memberdef>
|
||||
<usedfiles visible="$SHOW_USED_FILES"/>
|
||||
<authorsection visible="yes"/>
|
||||
</class>
|
||||
|
||||
<!-- Layout definition for a namespace page -->
|
||||
<namespace>
|
||||
<briefdescription visible="no"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<membergroups visible="yes"/>
|
||||
<nestednamespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</namespace>
|
||||
|
||||
<!-- Layout definition for a file page -->
|
||||
<file>
|
||||
<briefdescription visible="no"/>
|
||||
<includes visible="$SHOW_INCLUDE_FILES"/>
|
||||
<includegraph visible="$INCLUDE_GRAPH"/>
|
||||
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
|
||||
<sourcelink visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<membergroups visible="yes"/>
|
||||
<classes visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
</memberdef>
|
||||
<authorsection/>
|
||||
</file>
|
||||
|
||||
<!-- Layout definition for a group page -->
|
||||
<group>
|
||||
<briefdescription visible="no"/>
|
||||
<groupgraph visible="$GROUP_GRAPHS"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<membergroups visible="yes"/>
|
||||
<nestedgroups visible="yes" title=""/>
|
||||
<dirs visible="yes" title=""/>
|
||||
<files visible="yes" title=""/>
|
||||
<namespaces visible="yes" title=""/>
|
||||
<classes visible="yes" title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdecl>
|
||||
<memberdef>
|
||||
<pagedocs/>
|
||||
<inlineclasses title=""/>
|
||||
<defines title=""/>
|
||||
<typedefs title=""/>
|
||||
<enums title=""/>
|
||||
<enumvalues title=""/>
|
||||
<functions title=""/>
|
||||
<variables title=""/>
|
||||
<signals title=""/>
|
||||
<publicslots title=""/>
|
||||
<protectedslots title=""/>
|
||||
<privateslots title=""/>
|
||||
<events title=""/>
|
||||
<properties title=""/>
|
||||
<friends title=""/>
|
||||
</memberdef>
|
||||
<authorsection visible="yes"/>
|
||||
</group>
|
||||
|
||||
<!-- Layout definition for a directory page -->
|
||||
<directory>
|
||||
<briefdescription visible="yes"/>
|
||||
<directorygraph visible="yes"/>
|
||||
<detaileddescription title=""/>
|
||||
<memberdecl>
|
||||
<dirs visible="yes"/>
|
||||
<files visible="yes"/>
|
||||
</memberdecl>
|
||||
</directory>
|
||||
</doxygenlayout>
|
||||
12
doxygen/layout/custom_footer.html
Normal file
12
doxygen/layout/custom_footer.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<hr>
|
||||
<footer>
|
||||
<p style="text-align:left">Copyright © 2019 Paul Ferrand
|
||||
<span style="float:right">Generated for sfizz by
|
||||
<a href="http://www.doxygen.org/index.html"
|
||||
target="_new">Doxygen</a> $doxygenversion</span>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="./../assets/js/scripts.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
86
doxygen/layout/custom_header.html
Normal file
86
doxygen/layout/custom_header.html
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>Home - Sfizz</title>
|
||||
|
||||
<meta name="author" content="Paul Ferrand">
|
||||
<meta name="web-author" content="RedTide">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Atom Feeds -->
|
||||
<link href="./../atom.xml" rel="alternate" title="News"
|
||||
type="application/atom+xml" />
|
||||
|
||||
<!-- Favicon Generator Icons -->
|
||||
<link rel="apple-touch-icon" sizes="180x180"
|
||||
href="./../assets/ico/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="./../assets/ico/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="./../assets/ico/favicon-16x16.png">
|
||||
<link rel="manifest" href="./../assets/ico/site.webmanifest">
|
||||
<link rel="mask-icon" href="./../assets/ico/safari-pinned-tab.svg"
|
||||
color="#5bbad5">
|
||||
<link rel="shortcut icon" href="./../assets/ico/favicon.ico">
|
||||
<meta name="msapplication-TileColor"
|
||||
content="#da532c">
|
||||
<meta name="msapplication-config" content="./../assets/ico/browserconfig.xml">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<link href="$relpath$tabs.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="$relpath$jquery.js"></script>
|
||||
<script type="text/javascript" src="$relpath$dynsections.js"></script>
|
||||
$treeview
|
||||
$search
|
||||
$mathjax
|
||||
<link href="$relpath$$stylesheet" rel="stylesheet" type="text/css" />
|
||||
$extrastylesheet
|
||||
|
||||
<!-- Stylesheets -->
|
||||
<link href="./../assets/css/style.min.css"
|
||||
rel="stylesheet" media="screen">
|
||||
|
||||
<!-- Font Awesome Icons -->
|
||||
<script src="https://kit.fontawesome.com/8d25d19870.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<button onclick="topFunction()" id="scrollButton" title="Go to top">Top</button>
|
||||
<a href="#content" class="sr-only">Skip to content</a>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark" style="background-color:#222">
|
||||
<a class="navbar-brand" href="./../"><img src="./../assets/img/logo.png"
|
||||
width="30" height="30" class="d-inline-block">Sfizz</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse"
|
||||
data-target="#navbarContent" aria-controls="navbarContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarContent">
|
||||
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./../status"><i class="fas fa-tasks fa-fw"
|
||||
aria-hidden="true"></i> Status</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./../downloads"><i class="fas fa-download fa-fw"
|
||||
aria-hidden="true"></i> Downloads</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="./../contacts"><i class="fas fa-at fa-fw"
|
||||
aria-hidden="true"></i> Contacts</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://sfztools.github.io/"><i class="fas fa-home fa-fw"
|
||||
aria-hidden="true"></i> Home</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!--BEGIN DISABLE_INDEX-->
|
||||
<!--BEGIN SEARCHENGINE-->
|
||||
$searchbox
|
||||
<!--END SEARCHENGINE-->
|
||||
<!--END DISABLE_INDEX-->
|
||||
</nav>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
198
doxygen/layout/extra_stylesheet.css
Normal file
198
doxygen/layout/extra_stylesheet.css
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
#page_container {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
div.contents, div.searchresults {
|
||||
margin-top: 10px;
|
||||
margin-right: 12px;
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
#projectlogo {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#projectnumber {
|
||||
font-size: 120%;
|
||||
font-family: Tahoma, Arial, sans-serif;
|
||||
text-align: right;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
font-size: 14px;
|
||||
}
|
||||
.tabs2, .tabs3 {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.navpath ul {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #002D88;
|
||||
font-weight: normal;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 0.5em;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 4px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 150%;
|
||||
border-bottom: 1px solid #3276FF;
|
||||
}
|
||||
h2 {
|
||||
font-size: 135%;
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
h3 {
|
||||
font-size: 120%;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
h4 {
|
||||
font-size: 100%;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
div.headertitle h1 {
|
||||
margin: 10px 2px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
width: auto;
|
||||
color: black;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.toc h3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
div.toc li {
|
||||
font-size: 12px;
|
||||
line-height: 1.3;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
img.logo {
|
||||
float: right;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
div.logo {
|
||||
float: right;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
table.directory {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.icon {
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
div.appearance {
|
||||
margin: 1em 0em;
|
||||
}
|
||||
div.appearance table {
|
||||
margin: 0.5em 0em;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
div.appearance img {
|
||||
margin: 0.5em;
|
||||
}
|
||||
div.appearance .caption {
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.appearance_brief table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
div.appearance_brief table td:first-child {
|
||||
width: 20em;
|
||||
text-align: left;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
div.appearance_brief table td {
|
||||
border-style: none solid solid none;
|
||||
border-width: 1px;
|
||||
border-color: lightblue;
|
||||
}
|
||||
|
||||
|
||||
td.green { color: green; }
|
||||
td.orange { color: #ff8000; }
|
||||
td.red { color: red; }
|
||||
|
||||
span.literal {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
font-family: monospace, fixed;
|
||||
}
|
||||
|
||||
/* we make all the following <span> tags render the text just like
|
||||
the standard Doxygen @remarks, @see tags do, to obtain a uniform
|
||||
look and feel */
|
||||
span.itemdef, span.lib, span.category, span.stdobj, span.styles,
|
||||
span.events, span.flags, span.appearance, span.impl, span.avail {
|
||||
font-weight: bold;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
span.style, span.event, span.flag {
|
||||
font-weight: bold;
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
div.styleDesc, div.eventDesc, div.flagDesc {
|
||||
margin-left: 3%;
|
||||
margin-bottom: 1ex;
|
||||
}
|
||||
|
||||
div.eventHandler {
|
||||
margin: 1em;
|
||||
text-indent: 3%;
|
||||
}
|
||||
|
||||
div.eventHandler span {
|
||||
padding: 5px;
|
||||
background-color: #eeeeee;
|
||||
font-family: monospace, fixed;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 110%;
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
address.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #0043CC;
|
||||
background-image: url('nav_h.png');
|
||||
background-repeat: repeat-x;
|
||||
background-color: #F4F8FF;
|
||||
}
|
||||
|
||||
address.footer small {
|
||||
padding: 0 10px;
|
||||
}
|
||||
154
doxygen/pages/engine_description.md
Normal file
154
doxygen/pages/engine_description.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# Global view of the engine
|
||||
|
||||
The sfizz engine is basically a "Synth" object that takes an SFZ file in, receives MIDI-type events
|
||||
and is able to render audio through successive calls to a callback function. This is in line with
|
||||
the way most audio applications and plugins are working. A high-level overview is presented in the
|
||||
following diagram.
|
||||
|
||||
```
|
||||
C and C++ API entry point
|
||||
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
+--------v-------+
|
||||
| |
|
||||
+-------------------------- Synth -----------------------------+
|
||||
| | | |
|
||||
| +----------------+ |
|
||||
| | |
|
||||
+--------v------+ | +---------v--------+
|
||||
| | +---------v---------+ | |
|
||||
| Region list | | Common resources | | Voice pool |
|
||||
| | | and state | | |
|
||||
+---------------+ | ----------------- | +------------------+
|
||||
Built from the SFZ file | File pool |
|
||||
| Envelope pool | The voices are the polyphony
|
||||
Each region is a semi-passive | LFO pool | of the synth. They are idle
|
||||
description object that can | Buffer pool | and they get activated by the
|
||||
decide whether it is "active" | Midi state | synth to play a region on a
|
||||
or not depending on the chain | ... | specific event. They are then
|
||||
of MIDI events it receives. +-------------------+ "linked" to the region while
|
||||
Once activated, a voice is There are a number of common it is played, and reset to
|
||||
chosen to play the region until resources that are needed for their idle state when they
|
||||
it ends naturally or through all the regions and in parti- are done playing the region.
|
||||
note-offs or off-groups. cular the voices. This includes
|
||||
all the (preloaded) files for
|
||||
the SFZ instrument, but will
|
||||
include in the future the EG
|
||||
and LFOs that are needed to
|
||||
achieve compliance with the
|
||||
SFZ v2 specification. This will
|
||||
also include a temporary buffer
|
||||
holder that voices may share.
|
||||
A common resource of importance
|
||||
is the MIDI state: note durations
|
||||
are needed for some opcodes --
|
||||
for example rt_decay -- and
|
||||
triggering velocities too.
|
||||
```
|
||||
|
||||
The Synth, Voices and Regions form the bulk of the code complexity. The rest of the engine is dedicated of
|
||||
mostly helper classes to enable easy management of floating-point buffers in which the audio data is held,
|
||||
signal processing and accelerated (SIMD) computations, and abstractions that are specific to the SFZ format
|
||||
such as envelope generators, curves or LFOs.
|
||||
|
||||
# Parsing the SFZ files
|
||||
|
||||
The sfz file logic is pretty simple and well defined. The sfzformat.com website contains an extensive documentation
|
||||
on it. At its core, an SFZ file describes a list of `region` objects on which a certain number of "opcodes" will
|
||||
apply. Opcodes can determine the sample played, the event conditions that will trigger the sample such as the range
|
||||
of notes, channels, velocities, the processing to apply on the sample while playing, and many more things. It is
|
||||
also possible to describe a `group` of regions, as well as exclusive groups that will shut off other regions that may
|
||||
already be playing. There are also `master` groups, and `global` opcodes and some other types.
|
||||
|
||||
All the opcodes are declared within a header, in a pseudo-xml markup language that looks like this
|
||||
```sfz
|
||||
<global> volume=6
|
||||
<control> set_cc4=5
|
||||
<region> key=36 sample=kick.wav
|
||||
```
|
||||
Here we have 3 headers (`global`, `control` and `region`) and each header holds some opcodes. All of these opcodes
|
||||
have a value---for example the volume is equal to 6 in the `global` header. Some opcodes also have parameters.
|
||||
The `control` header holds an opcode `set_cc` with the parameter `4` and value `5`. The parameter here is the CC to set,
|
||||
and the value at which to set it is 5.
|
||||
|
||||
The parsing logic of sfizz is handled through a base class called Parser---a very original choice. This parser has
|
||||
a virtual callback that gets called whenever a header description is "complete", along with a list of opcodes that
|
||||
apply to the header. Subclassing the Parser then allows to build different SFZ handlers, from full-blown synths as
|
||||
with sfizz to simpler things such as printers (see in particular https://github.com/sfztools/sfz-flat/). If we look
|
||||
at the core of the latter example, it will look something like the following
|
||||
|
||||
```cpp
|
||||
class PrintingParser: public sfz::Parser
|
||||
{
|
||||
protected:
|
||||
void callback(absl::string_view header, const std::vector<sfz::Opcode>& members) final
|
||||
{
|
||||
switch (hash(header)) // The hash(...) function transforms strings to large integers
|
||||
{
|
||||
case hash("global"): // It is also compile-time defined, which allows to do switch-case
|
||||
// statements on strings, something that is usually not possible
|
||||
globalMembers = members; // We save the global headers since they apply to the next
|
||||
// region (and groups and masters)
|
||||
masterMembers.clear();
|
||||
groupMembers.clear();
|
||||
break;
|
||||
case hash("master"):
|
||||
masterMembers = members; // So on
|
||||
groupMembers.clear();
|
||||
break;
|
||||
case hash("group"):
|
||||
groupMembers = members; // .. and so forth
|
||||
break;
|
||||
case hash("region"):
|
||||
std::cout << "<" << header << ">" << ' '; // Now we print the region along with all the opcodes
|
||||
// we memorized from earlier headers.
|
||||
printMembers(globalMembers);
|
||||
printMembers(masterMembers);
|
||||
printMembers(groupMembers);
|
||||
printMembers(members);
|
||||
std::cout << '\n';
|
||||
break;
|
||||
default:
|
||||
std::cout << "<" << header << ">" << ' ';
|
||||
printMembers(members);
|
||||
std::cout << '\n';
|
||||
break;
|
||||
}
|
||||
}
|
||||
private:
|
||||
std::vector<sfz::Opcode> globalMembers;
|
||||
std::vector<sfz::Opcode> masterMembers;
|
||||
std::vector<sfz::Opcode> groupMembers;
|
||||
void printMembers(const std::vector<sfz::Opcode>& members)
|
||||
{
|
||||
for (auto& member: members)
|
||||
{
|
||||
std::cout << member.opcode;
|
||||
if (member.parameter)
|
||||
std::cout << +*member.parameter;
|
||||
std::cout << "=" << member.value;
|
||||
std::cout << ' ';
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The main function is then quite straightforward and we call a function from the Parser class that loads a file
|
||||
```cpp
|
||||
PrintingParser parser;
|
||||
parser.loadSfzFile("my_sfz_file.sfz");
|
||||
```
|
||||
If you circle back to the parser you will see that opcodes are stored in an `Opcode` class. This class does some parsing
|
||||
itself and separates the opcode name itself, parameters if any, and the value. Opcodes are very cheap to copy and pass
|
||||
around because they only refer to characters in the file that are stored inside the `Parser` class, so feel free to
|
||||
create vectors of them and move them around.
|
||||
|
||||
Note that you may also derive the loadSfzFile method if you have any processing you need to do before the actual parsing happens.
|
||||
|
||||
# Building the region list in sfizz
|
||||
|
||||
The callback method from sfizz is actually quite similar to the one shown above, except that instead of printing the region
|
||||
we actually fill a big structure from it.
|
||||
5
doxygen/pages/index.md
Normal file
5
doxygen/pages/index.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# sfizz
|
||||
|
||||
SFZ file format library
|
||||
|
||||
[public API](sfizz_8h.html)
|
||||
1
external/benchmark
vendored
1
external/benchmark
vendored
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 090faecb454fbd6e6e17a75ef8146acb037118d4
|
||||
37
lv2/CMakeLists.txt
Normal file
37
lv2/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
set (LV2PLUGIN_PRJ_NAME "${PROJECT_NAME}_lv2")
|
||||
|
||||
# Set the build directory as <build_dir>/lv2/<plugin_name>.lv2/
|
||||
set (PROJECT_BINARY_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.lv2")
|
||||
|
||||
# LV2 plugin specific settings
|
||||
include (LV2Config)
|
||||
|
||||
# Keep non build turtle files in IDE
|
||||
set (LV2PLUGIN_TTL_SRC_FILES
|
||||
manifest.ttl.in
|
||||
${PROJECT_NAME}.ttl.in
|
||||
)
|
||||
add_library (${LV2PLUGIN_PRJ_NAME} SHARED ${PROJECT_NAME}.c ${LV2PLUGIN_TTL_SRC_FILES})
|
||||
target_link_libraries (${LV2PLUGIN_PRJ_NAME} ${PROJECT_NAME}::${PROJECT_NAME})
|
||||
target_include_directories(${LV2PLUGIN_PRJ_NAME} PRIVATE .)
|
||||
sfizz_enable_lto_if_needed (${LV2PLUGIN_PRJ_NAME})
|
||||
|
||||
# Remove the "lib" prefix, rename the target name and build it in the .lv build dir
|
||||
# <build_dir>/lv2/<plugin_name>_lv2.<ext> to
|
||||
# <build_dir>/lv2/<plugin_name>.lv2/<plugin_name>.<ext>
|
||||
set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES PREFIX "")
|
||||
set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES OUTPUT_NAME "${PROJECT_NAME}")
|
||||
set_target_properties (${LV2PLUGIN_PRJ_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
|
||||
|
||||
# Generate *.ttl files from *.in sources,
|
||||
# create the destination directory if it doesn't exists and copy needed files
|
||||
file (MAKE_DIRECTORY ${PROJECT_BINARY_DIR})
|
||||
configure_file (manifest.ttl.in ${PROJECT_BINARY_DIR}/manifest.ttl)
|
||||
configure_file (${PROJECT_NAME}.ttl.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.ttl)
|
||||
configure_file (LICENSE.md.in ${PROJECT_BINARY_DIR}/LICENSE.md)
|
||||
if (SFIZZ_USE_VCPKG)
|
||||
file(COPY "lgpl-3.0.txt" DESTINATION ${PROJECT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
# Installation
|
||||
install (DIRECTORY ${PROJECT_BINARY_DIR} DESTINATION ${LV2PLUGIN_INSTALL_DIR})
|
||||
19
lv2/LICENSE.md.in
Normal file
19
lv2/LICENSE.md.in
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
The `sfizz` LV2 plugin is able to be built statically against all its components,
|
||||
which is a desirable property for audio plugin hosts. These components include
|
||||
`libsndfile` from Erik de Castro Lopo (http://www.mega-nerd.com/libsndfile).
|
||||
`libsndfile` is distributed under the terms of the LGPL v2 or v3. As such,
|
||||
statically-linked LV2 version of `sfizz` are to be distributed under the terms
|
||||
of the LGPL-v3.0 license. You should be able to rebuild from source the sfizz LV2
|
||||
plugin using any `libsndfile` version you wish to use.
|
||||
|
||||
See the file `lgpl-3.0.txt` or (https://www.gnu.org/licenses/lgpl-3.0.txt) for more
|
||||
information about the LGPL v3 license.
|
||||
|
||||
Most of the code in the plug comes from various examples in the LV2 distribution and
|
||||
example plugins. As such, the source code of the LV2 plugin version of `sfizz` is
|
||||
distributed under the same terms as the LV2 specification, which is the ISC license.
|
||||
Binaries of this LV2 plugin dynamically linked against e.g. a system installation
|
||||
of `libsndfile` thus have to respect the terms of the ISC license and BSD 2-clause
|
||||
license. Check the LICENSE.md at (@LV2PLUGIN_REPOSITORY@) file for more
|
||||
information about the license of the source code of the `sfizz` library and its
|
||||
contributors.
|
||||
165
lv2/lgpl-3.0.txt
Normal file
165
lv2/lgpl-3.0.txt
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
71
lv2/lv2/atom/atom-test-utils.c
Normal file
71
lv2/lv2/atom/atom-test-utils.c
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2012-2018 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/urid/urid.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
char** uris = NULL;
|
||||
uint32_t n_uris = 0;
|
||||
|
||||
static char*
|
||||
copy_string(const char* str)
|
||||
{
|
||||
const size_t len = strlen(str);
|
||||
char* dup = (char*)malloc(len + 1);
|
||||
memcpy(dup, str, len + 1);
|
||||
return dup;
|
||||
}
|
||||
|
||||
static LV2_URID
|
||||
urid_map(LV2_URID_Map_Handle handle, const char* uri)
|
||||
{
|
||||
for (uint32_t i = 0; i < n_uris; ++i) {
|
||||
if (!strcmp(uris[i], uri)) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
|
||||
uris[n_uris - 1] = copy_string(uri);
|
||||
return n_uris;
|
||||
}
|
||||
|
||||
static void
|
||||
free_urid_map(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < n_uris; ++i) {
|
||||
free(uris[i]);
|
||||
}
|
||||
|
||||
free(uris);
|
||||
}
|
||||
|
||||
static int
|
||||
test_fail(const char* fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
fprintf(stderr, "error: ");
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
return 1;
|
||||
}
|
||||
363
lv2/lv2/atom/atom-test.c
Normal file
363
lv2/lv2/atom/atom-test.c
Normal file
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
Copyright 2012-2015 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lv2/atom/atom-test-utils.c"
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/urid/urid.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
|
||||
LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object");
|
||||
LV2_URID eg_one = urid_map(NULL, "http://example.org/one");
|
||||
LV2_URID eg_two = urid_map(NULL, "http://example.org/two");
|
||||
LV2_URID eg_three = urid_map(NULL, "http://example.org/three");
|
||||
LV2_URID eg_four = urid_map(NULL, "http://example.org/four");
|
||||
LV2_URID eg_true = urid_map(NULL, "http://example.org/true");
|
||||
LV2_URID eg_false = urid_map(NULL, "http://example.org/false");
|
||||
LV2_URID eg_path = urid_map(NULL, "http://example.org/path");
|
||||
LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri");
|
||||
LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid");
|
||||
LV2_URID eg_string = urid_map(NULL, "http://example.org/string");
|
||||
LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal");
|
||||
LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple");
|
||||
LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector");
|
||||
LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2");
|
||||
LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq");
|
||||
|
||||
#define BUF_SIZE 1024
|
||||
#define NUM_PROPS 15
|
||||
|
||||
uint8_t buf[BUF_SIZE];
|
||||
lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE);
|
||||
|
||||
LV2_Atom_Forge_Frame obj_frame;
|
||||
LV2_Atom* obj = lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object));
|
||||
|
||||
// eg_one = (Int)1
|
||||
lv2_atom_forge_key(&forge, eg_one);
|
||||
LV2_Atom_Int* one = (LV2_Atom_Int*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_int(&forge, 1));
|
||||
if (one->body != 1) {
|
||||
return test_fail("%d != 1\n", one->body);
|
||||
}
|
||||
|
||||
// eg_two = (Long)2
|
||||
lv2_atom_forge_key(&forge, eg_two);
|
||||
LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_long(&forge, 2));
|
||||
if (two->body != 2) {
|
||||
return test_fail("%ld != 2\n", two->body);
|
||||
}
|
||||
|
||||
// eg_three = (Float)3.0
|
||||
lv2_atom_forge_key(&forge, eg_three);
|
||||
LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_float(&forge, 3.0f));
|
||||
if (three->body != 3) {
|
||||
return test_fail("%f != 3\n", three->body);
|
||||
}
|
||||
|
||||
// eg_four = (Double)4.0
|
||||
lv2_atom_forge_key(&forge, eg_four);
|
||||
LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_double(&forge, 4.0));
|
||||
if (four->body != 4) {
|
||||
return test_fail("%ld != 4\n", four->body);
|
||||
}
|
||||
|
||||
// eg_true = (Bool)1
|
||||
lv2_atom_forge_key(&forge, eg_true);
|
||||
LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_bool(&forge, true));
|
||||
if (t->body != 1) {
|
||||
return test_fail("%ld != 1 (true)\n", t->body);
|
||||
}
|
||||
|
||||
// eg_false = (Bool)0
|
||||
lv2_atom_forge_key(&forge, eg_false);
|
||||
LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_bool(&forge, false));
|
||||
if (f->body != 0) {
|
||||
return test_fail("%ld != 0 (false)\n", f->body);
|
||||
}
|
||||
|
||||
// eg_path = (Path)"/foo/bar"
|
||||
const char* pstr = "/foo/bar";
|
||||
const uint32_t pstr_len = (uint32_t)strlen(pstr);
|
||||
lv2_atom_forge_key(&forge, eg_path);
|
||||
LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_uri(&forge, pstr, pstr_len));
|
||||
char* pbody = (char*)LV2_ATOM_BODY(path);
|
||||
if (strcmp(pbody, pstr)) {
|
||||
return test_fail("%s != \"%s\"\n", pbody, pstr);
|
||||
}
|
||||
|
||||
// eg_uri = (URI)"http://example.org/value"
|
||||
const char* ustr = "http://example.org/value";
|
||||
const uint32_t ustr_len = (uint32_t)strlen(ustr);
|
||||
lv2_atom_forge_key(&forge, eg_uri);
|
||||
LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_uri(&forge, ustr, ustr_len));
|
||||
char* ubody = (char*)LV2_ATOM_BODY(uri);
|
||||
if (strcmp(ubody, ustr)) {
|
||||
return test_fail("%s != \"%s\"\n", ubody, ustr);
|
||||
}
|
||||
|
||||
// eg_urid = (URID)"http://example.org/value"
|
||||
LV2_URID eg_value = urid_map(NULL, "http://example.org/value");
|
||||
lv2_atom_forge_key(&forge, eg_urid);
|
||||
LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_urid(&forge, eg_value));
|
||||
if (urid->body != eg_value) {
|
||||
return test_fail("%u != %u\n", urid->body, eg_value);
|
||||
}
|
||||
|
||||
// eg_string = (String)"hello"
|
||||
lv2_atom_forge_key(&forge, eg_string);
|
||||
LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_string(
|
||||
&forge, "hello", strlen("hello")));
|
||||
char* sbody = (char*)LV2_ATOM_BODY(string);
|
||||
if (strcmp(sbody, "hello")) {
|
||||
return test_fail("%s != \"hello\"\n", sbody);
|
||||
}
|
||||
|
||||
// eg_literal = (Literal)"hello"@fr
|
||||
lv2_atom_forge_key(&forge, eg_literal);
|
||||
LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_literal(
|
||||
&forge, "bonjour", strlen("bonjour"),
|
||||
0, urid_map(NULL, "http://lexvo.org/id/term/fr")));
|
||||
char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal);
|
||||
if (strcmp(lbody, "bonjour")) {
|
||||
return test_fail("%s != \"bonjour\"\n", lbody);
|
||||
}
|
||||
|
||||
// eg_tuple = "foo",true
|
||||
lv2_atom_forge_key(&forge, eg_tuple);
|
||||
LV2_Atom_Forge_Frame tuple_frame;
|
||||
LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_tuple(&forge, &tuple_frame));
|
||||
LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_string(
|
||||
&forge, "foo", strlen("foo")));
|
||||
LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_bool(&forge, true));
|
||||
lv2_atom_forge_pop(&forge, &tuple_frame);
|
||||
LV2_Atom* i = lv2_atom_tuple_begin(tuple);
|
||||
if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
|
||||
return test_fail("Tuple iterator is empty\n");
|
||||
}
|
||||
LV2_Atom* tup0i = i;
|
||||
if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) {
|
||||
return test_fail("Corrupt tuple element 0\n");
|
||||
}
|
||||
i = lv2_atom_tuple_next(i);
|
||||
if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
|
||||
return test_fail("Premature end of tuple iterator\n");
|
||||
}
|
||||
LV2_Atom* tup1i = i;
|
||||
if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) {
|
||||
return test_fail("Corrupt tuple element 1\n");
|
||||
}
|
||||
i = lv2_atom_tuple_next(i);
|
||||
if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
|
||||
return test_fail("Tuple iter is not at end\n");
|
||||
}
|
||||
|
||||
// eg_vector = (Vector<Int>)1,2,3,4
|
||||
lv2_atom_forge_key(&forge, eg_vector);
|
||||
int32_t elems[] = { 1, 2, 3, 4 };
|
||||
LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_vector(
|
||||
&forge, sizeof(int32_t), forge.Int, 4, elems));
|
||||
void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector);
|
||||
if (memcmp(elems, vec_body, sizeof(elems))) {
|
||||
return test_fail("Corrupt vector\n");
|
||||
}
|
||||
|
||||
// eg_vector2 = (Vector<Int>)1,2,3,4
|
||||
lv2_atom_forge_key(&forge, eg_vector2);
|
||||
LV2_Atom_Forge_Frame vec_frame;
|
||||
LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_vector_head(
|
||||
&forge, &vec_frame, sizeof(int32_t), forge.Int));
|
||||
for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) {
|
||||
lv2_atom_forge_int(&forge, elems[e]);
|
||||
}
|
||||
lv2_atom_forge_pop(&forge, &vec_frame);
|
||||
if (!lv2_atom_equals(&vector->atom, &vector2->atom)) {
|
||||
return test_fail("Vector != Vector2\n");
|
||||
}
|
||||
|
||||
// eg_seq = (Sequence)1, 2
|
||||
lv2_atom_forge_key(&forge, eg_seq);
|
||||
LV2_Atom_Forge_Frame seq_frame;
|
||||
LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref(
|
||||
&forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0));
|
||||
lv2_atom_forge_frame_time(&forge, 0);
|
||||
lv2_atom_forge_int(&forge, 1);
|
||||
lv2_atom_forge_frame_time(&forge, 1);
|
||||
lv2_atom_forge_int(&forge, 2);
|
||||
lv2_atom_forge_pop(&forge, &seq_frame);
|
||||
|
||||
lv2_atom_forge_pop(&forge, &obj_frame);
|
||||
|
||||
// Test equality
|
||||
LV2_Atom_Int itwo = { { forge.Int, sizeof(int32_t) }, 2 };
|
||||
if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) {
|
||||
return test_fail("1 == 2.0\n");
|
||||
} else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) {
|
||||
return test_fail("1 == 2\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)one)) {
|
||||
return test_fail("1 != 1\n");
|
||||
}
|
||||
|
||||
unsigned n_events = 0;
|
||||
LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
|
||||
if (ev->time.frames != n_events) {
|
||||
return test_fail("Corrupt event %u has bad time\n", n_events);
|
||||
} else if (ev->body.type != forge.Int) {
|
||||
return test_fail("Corrupt event %u has bad type\n", n_events);
|
||||
} else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) {
|
||||
return test_fail("Event %u != %d\n", n_events, n_events + 1);
|
||||
}
|
||||
++n_events;
|
||||
}
|
||||
|
||||
int n_props = 0;
|
||||
LV2_ATOM_OBJECT_FOREACH((LV2_Atom_Object*)obj, prop) {
|
||||
if (!prop->key) {
|
||||
return test_fail("Corrupt property %u has no key\n", n_props);
|
||||
} else if (prop->context) {
|
||||
return test_fail("Corrupt property %u has context\n", n_props);
|
||||
}
|
||||
++n_props;
|
||||
}
|
||||
|
||||
if (n_props != NUM_PROPS) {
|
||||
return test_fail("Corrupt object has %u properties != %u\n",
|
||||
n_props, NUM_PROPS);
|
||||
}
|
||||
|
||||
struct {
|
||||
const LV2_Atom* one;
|
||||
const LV2_Atom* two;
|
||||
const LV2_Atom* three;
|
||||
const LV2_Atom* four;
|
||||
const LV2_Atom* affirmative;
|
||||
const LV2_Atom* negative;
|
||||
const LV2_Atom* path;
|
||||
const LV2_Atom* uri;
|
||||
const LV2_Atom* urid;
|
||||
const LV2_Atom* string;
|
||||
const LV2_Atom* literal;
|
||||
const LV2_Atom* tuple;
|
||||
const LV2_Atom* vector;
|
||||
const LV2_Atom* vector2;
|
||||
const LV2_Atom* seq;
|
||||
} matches;
|
||||
|
||||
memset(&matches, 0, sizeof(matches));
|
||||
|
||||
LV2_Atom_Object_Query q[] = {
|
||||
{ eg_one, &matches.one },
|
||||
{ eg_two, &matches.two },
|
||||
{ eg_three, &matches.three },
|
||||
{ eg_four, &matches.four },
|
||||
{ eg_true, &matches.affirmative },
|
||||
{ eg_false, &matches.negative },
|
||||
{ eg_path, &matches.path },
|
||||
{ eg_uri, &matches.uri },
|
||||
{ eg_urid, &matches.urid },
|
||||
{ eg_string, &matches.string },
|
||||
{ eg_literal, &matches.literal },
|
||||
{ eg_tuple, &matches.tuple },
|
||||
{ eg_vector, &matches.vector },
|
||||
{ eg_vector2, &matches.vector2 },
|
||||
{ eg_seq, &matches.seq },
|
||||
LV2_ATOM_OBJECT_QUERY_END
|
||||
};
|
||||
|
||||
int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q);
|
||||
for (int n = 0; n < 2; ++n) {
|
||||
if (n_matches != n_props) {
|
||||
return test_fail("Query failed, %u matches != %u\n",
|
||||
n_matches, n_props);
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) {
|
||||
return test_fail("Bad match one\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) {
|
||||
return test_fail("Bad match two\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) {
|
||||
return test_fail("Bad match three\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) {
|
||||
return test_fail("Bad match four\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) {
|
||||
return test_fail("Bad match true\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) {
|
||||
return test_fail("Bad match false\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) {
|
||||
return test_fail("Bad match path\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) {
|
||||
return test_fail("Bad match URI\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) {
|
||||
return test_fail("Bad match string\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) {
|
||||
return test_fail("Bad match literal\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) {
|
||||
return test_fail("Bad match tuple\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) {
|
||||
return test_fail("Bad match vector\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) {
|
||||
return test_fail("Bad match vector2\n");
|
||||
} else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) {
|
||||
return test_fail("Bad match sequence\n");
|
||||
}
|
||||
memset(&matches, 0, sizeof(matches));
|
||||
n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj,
|
||||
eg_one, &matches.one,
|
||||
eg_two, &matches.two,
|
||||
eg_three, &matches.three,
|
||||
eg_four, &matches.four,
|
||||
eg_true, &matches.affirmative,
|
||||
eg_false, &matches.negative,
|
||||
eg_path, &matches.path,
|
||||
eg_uri, &matches.uri,
|
||||
eg_urid, &matches.urid,
|
||||
eg_string, &matches.string,
|
||||
eg_literal, &matches.literal,
|
||||
eg_tuple, &matches.tuple,
|
||||
eg_vector, &matches.vector,
|
||||
eg_vector2, &matches.vector2,
|
||||
eg_seq, &matches.seq,
|
||||
0);
|
||||
}
|
||||
|
||||
free_urid_map();
|
||||
|
||||
return 0;
|
||||
}
|
||||
256
lv2/lv2/atom/atom.h
Normal file
256
lv2/lv2/atom/atom.h
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
Copyright 2008-2016 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup atom Atom
|
||||
|
||||
A generic value container and several data types, see
|
||||
<http://lv2plug.in/ns/ext/atom> for details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_H
|
||||
#define LV2_ATOM_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" ///< http://lv2plug.in/ns/ext/atom
|
||||
#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" ///< http://lv2plug.in/ns/ext/atom#
|
||||
|
||||
#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" ///< http://lv2plug.in/ns/ext/atom#Atom
|
||||
#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" ///< http://lv2plug.in/ns/ext/atom#AtomPort
|
||||
#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" ///< http://lv2plug.in/ns/ext/atom#Blank
|
||||
#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" ///< http://lv2plug.in/ns/ext/atom#Bool
|
||||
#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/atom#Chunk
|
||||
#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" ///< http://lv2plug.in/ns/ext/atom#Double
|
||||
#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" ///< http://lv2plug.in/ns/ext/atom#Event
|
||||
#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" ///< http://lv2plug.in/ns/ext/atom#Float
|
||||
#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" ///< http://lv2plug.in/ns/ext/atom#Int
|
||||
#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" ///< http://lv2plug.in/ns/ext/atom#Literal
|
||||
#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" ///< http://lv2plug.in/ns/ext/atom#Long
|
||||
#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" ///< http://lv2plug.in/ns/ext/atom#Number
|
||||
#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" ///< http://lv2plug.in/ns/ext/atom#Object
|
||||
#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" ///< http://lv2plug.in/ns/ext/atom#Path
|
||||
#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" ///< http://lv2plug.in/ns/ext/atom#Property
|
||||
#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" ///< http://lv2plug.in/ns/ext/atom#Resource
|
||||
#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" ///< http://lv2plug.in/ns/ext/atom#Sequence
|
||||
#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" ///< http://lv2plug.in/ns/ext/atom#Sound
|
||||
#define LV2_ATOM__String LV2_ATOM_PREFIX "String" ///< http://lv2plug.in/ns/ext/atom#String
|
||||
#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" ///< http://lv2plug.in/ns/ext/atom#Tuple
|
||||
#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" ///< http://lv2plug.in/ns/ext/atom#URI
|
||||
#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" ///< http://lv2plug.in/ns/ext/atom#URID
|
||||
#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" ///< http://lv2plug.in/ns/ext/atom#Vector
|
||||
#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" ///< http://lv2plug.in/ns/ext/atom#atomTransfer
|
||||
#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" ///< http://lv2plug.in/ns/ext/atom#beatTime
|
||||
#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" ///< http://lv2plug.in/ns/ext/atom#bufferType
|
||||
#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" ///< http://lv2plug.in/ns/ext/atom#childType
|
||||
#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" ///< http://lv2plug.in/ns/ext/atom#eventTransfer
|
||||
#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" ///< http://lv2plug.in/ns/ext/atom#frameTime
|
||||
#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" ///< http://lv2plug.in/ns/ext/atom#supports
|
||||
#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" ///< http://lv2plug.in/ns/ext/atom#timeUnit
|
||||
|
||||
#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @cond */
|
||||
/** This expression will fail to compile if double does not fit in 64 bits. */
|
||||
typedef char lv2_atom_assert_double_fits_in_64_bits[
|
||||
((sizeof(double) <= sizeof(uint64_t)) * 2) - 1];
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
Return a pointer to the contents of an Atom. The "contents" of an atom
|
||||
is the data past the complete type-specific header.
|
||||
@param type The type of the atom, e.g. LV2_Atom_String.
|
||||
@param atom A variable-sized atom.
|
||||
*/
|
||||
#define LV2_ATOM_CONTENTS(type, atom) \
|
||||
((void*)((uint8_t*)(atom) + sizeof(type)))
|
||||
|
||||
/**
|
||||
Const version of LV2_ATOM_CONTENTS.
|
||||
*/
|
||||
#define LV2_ATOM_CONTENTS_CONST(type, atom) \
|
||||
((const void*)((const uint8_t*)(atom) + sizeof(type)))
|
||||
|
||||
/**
|
||||
Return a pointer to the body of an Atom. The "body" of an atom is the
|
||||
data just past the LV2_Atom head (i.e. the same offset for all types).
|
||||
*/
|
||||
#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom)
|
||||
|
||||
/**
|
||||
Const version of LV2_ATOM_BODY.
|
||||
*/
|
||||
#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom)
|
||||
|
||||
/** The header of an atom:Atom. */
|
||||
typedef struct {
|
||||
uint32_t size; /**< Size in bytes, not including type and size. */
|
||||
uint32_t type; /**< Type of this atom (mapped URI). */
|
||||
} LV2_Atom;
|
||||
|
||||
/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
int32_t body; /**< Integer value. */
|
||||
} LV2_Atom_Int;
|
||||
|
||||
/** An atom:Long. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
int64_t body; /**< Integer value. */
|
||||
} LV2_Atom_Long;
|
||||
|
||||
/** An atom:Float. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
float body; /**< Floating point value. */
|
||||
} LV2_Atom_Float;
|
||||
|
||||
/** An atom:Double. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
double body; /**< Floating point value. */
|
||||
} LV2_Atom_Double;
|
||||
|
||||
/** An atom:Bool. May be cast to LV2_Atom. */
|
||||
typedef LV2_Atom_Int LV2_Atom_Bool;
|
||||
|
||||
/** An atom:URID. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
uint32_t body; /**< URID. */
|
||||
} LV2_Atom_URID;
|
||||
|
||||
/** An atom:String. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
/* Contents (a null-terminated UTF-8 string) follow here. */
|
||||
} LV2_Atom_String;
|
||||
|
||||
/** The body of an atom:Literal. */
|
||||
typedef struct {
|
||||
uint32_t datatype; /**< Datatype URID. */
|
||||
uint32_t lang; /**< Language URID. */
|
||||
/* Contents (a null-terminated UTF-8 string) follow here. */
|
||||
} LV2_Atom_Literal_Body;
|
||||
|
||||
/** An atom:Literal. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Literal_Body body; /**< Body. */
|
||||
} LV2_Atom_Literal;
|
||||
|
||||
/** An atom:Tuple. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
/* Contents (a series of complete atoms) follow here. */
|
||||
} LV2_Atom_Tuple;
|
||||
|
||||
/** The body of an atom:Vector. */
|
||||
typedef struct {
|
||||
uint32_t child_size; /**< The size of each element in the vector. */
|
||||
uint32_t child_type; /**< The type of each element in the vector. */
|
||||
/* Contents (a series of packed atom bodies) follow here. */
|
||||
} LV2_Atom_Vector_Body;
|
||||
|
||||
/** An atom:Vector. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Vector_Body body; /**< Body. */
|
||||
} LV2_Atom_Vector;
|
||||
|
||||
/** The body of an atom:Property (e.g. in an atom:Object). */
|
||||
typedef struct {
|
||||
uint32_t key; /**< Key (predicate) (mapped URI). */
|
||||
uint32_t context; /**< Context URID (may be, and generally is, 0). */
|
||||
LV2_Atom value; /**< Value atom header. */
|
||||
/* Value atom body follows here. */
|
||||
} LV2_Atom_Property_Body;
|
||||
|
||||
/** An atom:Property. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Property_Body body; /**< Body. */
|
||||
} LV2_Atom_Property;
|
||||
|
||||
/** The body of an atom:Object. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
uint32_t id; /**< URID, or 0 for blank. */
|
||||
uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */
|
||||
/* Contents (a series of property bodies) follow here. */
|
||||
} LV2_Atom_Object_Body;
|
||||
|
||||
/** An atom:Object. May be cast to LV2_Atom. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Object_Body body; /**< Body. */
|
||||
} LV2_Atom_Object;
|
||||
|
||||
/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */
|
||||
typedef struct {
|
||||
/** Time stamp. Which type is valid is determined by context. */
|
||||
union {
|
||||
int64_t frames; /**< Time in audio frames. */
|
||||
double beats; /**< Time in beats. */
|
||||
} time;
|
||||
LV2_Atom body; /**< Event body atom header. */
|
||||
/* Body atom contents follow here. */
|
||||
} LV2_Atom_Event;
|
||||
|
||||
/**
|
||||
The body of an atom:Sequence (a sequence of events).
|
||||
|
||||
The unit field is either a URID that described an appropriate time stamp
|
||||
type, or may be 0 where a default stamp type is known. For
|
||||
LV2_Descriptor::run(), the default stamp type is audio frames.
|
||||
|
||||
The contents of a sequence is a series of LV2_Atom_Event, each aligned
|
||||
to 64-bits, e.g.:
|
||||
<pre>
|
||||
| Event 1 (size 6) | Event 2
|
||||
| | | | | | | | |
|
||||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
|FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|...
|
||||
</pre>
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t unit; /**< URID of unit of event time stamps. */
|
||||
uint32_t pad; /**< Currently unused. */
|
||||
/* Contents (a series of events) follow here. */
|
||||
} LV2_Atom_Sequence_Body;
|
||||
|
||||
/** An atom:Sequence. */
|
||||
typedef struct {
|
||||
LV2_Atom atom; /**< Atom header. */
|
||||
LV2_Atom_Sequence_Body body; /**< Body. */
|
||||
} LV2_Atom_Sequence;
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_H */
|
||||
602
lv2/lv2/atom/atom.ttl
Normal file
602
lv2/lv2/atom/atom.ttl
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
@prefix atom: <http://lv2plug.in/ns/ext/atom#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
|
||||
@prefix units: <http://lv2plug.in/ns/extensions/units#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/atom>
|
||||
a owl:Ontology ;
|
||||
rdfs:seeAlso <atom.h> ,
|
||||
<util.h> ,
|
||||
<forge.h> ,
|
||||
<lv2-atom.doap.ttl> ;
|
||||
lv2:documentation """
|
||||
|
||||
<p>An #Atom is a simple generic data container for holding any type of Plain
|
||||
Old Data (POD). An #Atom can contain simple primitive types like integers,
|
||||
floating point numbers, and strings; as well as structured data like lists and
|
||||
dictionary-like <q>Objects</q>. Since Atoms are POD, they can be easily copied
|
||||
(e.g. using <code>memcpy</code>) anywhere and are suitable for use in real-time
|
||||
code.</p>
|
||||
|
||||
<p>Every atom starts with an LV2_Atom header, followed by the contents. This
|
||||
allows code to process atoms without requiring special code for every type of
|
||||
data. For example, plugins that mutually understand a type can be used
|
||||
together in a host that does not understand that type, because the host is only
|
||||
required to copy atoms, not interpret their contents. Similarly, plugins (such
|
||||
as routers, delays, or data structures) can meaningfully process atoms of a
|
||||
type unknown to them.</p>
|
||||
|
||||
<p>Atoms should be used anywhere values of various types must be stored or
|
||||
transmitted. The port type #AtomPort can be used to transmit atoms via ports.
|
||||
An #AtomPort that contains an #Sequence can be used for sample accurate event
|
||||
communication, such as MIDI, and replaces the earlier event extension.</p>
|
||||
|
||||
<h3>Serialisation</h3>
|
||||
|
||||
<p>Each Atom type defines a binary format for use at runtime, but also a
|
||||
serialisation that is natural to express in Turtle format. Thus, this
|
||||
specification defines a powerful real-time appropriate data model, as well as a
|
||||
portable way to serialise any data in that model. This is particularly useful
|
||||
for inter-process communication, saving/restoring state, and describing values
|
||||
in plugin data files.</p>
|
||||
|
||||
<h3>Custom Atom Types</h3>
|
||||
|
||||
<p>While it is possible to define new Atom types for any binary format, the
|
||||
standard types defined here are powerful enough to describe almost anything.
|
||||
Implementations SHOULD build structures out of the types provided here, rather
|
||||
than define new binary formats (e.g. use #Tuple or #Object rather than
|
||||
a new C <code>struct</code> type). Current implementations have support for
|
||||
serialising all standard types, so new binary formats are an implementation
|
||||
burden which harms interoperabilty. In particular, plugins SHOULD NOT expect
|
||||
UI communication or state saving with custom Atom types to work. In general,
|
||||
new Atom types should only be defined where absolutely necessary due to
|
||||
performance reasons and serialisation is not a concern.</p>
|
||||
""" .
|
||||
|
||||
atom:cType
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
owl:FunctionalProperty ;
|
||||
rdfs:label "C type" ;
|
||||
rdfs:domain rdfs:Class ;
|
||||
rdfs:range lv2:Symbol ;
|
||||
rdfs:comment """The identifier for a C type describing the binary representation of an Atom of this type.""" .
|
||||
|
||||
atom:Atom
|
||||
a rdfs:Class ;
|
||||
rdfs:label "Atom" ;
|
||||
atom:cType "LV2_Atom" ;
|
||||
lv2:documentation """
|
||||
<p>Abstract base class for all atoms. An LV2_Atom has a 32-bit
|
||||
<code>size</code> and <code>type</code> followed by a body of <code>size</code>
|
||||
bytes. Atoms MUST be 64-bit aligned.</p>
|
||||
|
||||
<p>All concrete Atom types (subclasses of this class) MUST define a precise
|
||||
binary layout for their body.</p>
|
||||
|
||||
<p>The <code>type</code> field is the URI of an Atom type mapped to an integer.
|
||||
Implementations SHOULD gracefully pass through, or ignore, atoms with unknown
|
||||
types.</p>
|
||||
|
||||
<p>All atoms are POD by definition except references, which as a special case
|
||||
have <code>type = 0</code>. An Atom MUST NOT contain a Reference. It is safe
|
||||
to copy any non-reference Atom with a simple <code>memcpy</code>, even if the
|
||||
implementation does not understand <code>type</code>. Though this extension
|
||||
reserves the type 0 for references, the details of reference handling are
|
||||
currently unspecified. A future revision of this extension, or a different
|
||||
extension, may define how to use non-POD data and references. Implementations
|
||||
MUST NOT send references to another implementation unless the receiver is
|
||||
explicitly known to support references (e.g. by supporting a feature).</p>
|
||||
|
||||
<p>The atom with both <code>type</code> <em>and</em> <code>size</code> 0 is
|
||||
<q>null</q>, which is not considered a Reference.</p>
|
||||
""" .
|
||||
|
||||
atom:Chunk
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Chunk of memory" ;
|
||||
owl:onDatatype xsd:base64Binary ;
|
||||
lv2:documentation """
|
||||
<p>A chunk of memory with undefined contents. This type is used to indicate a
|
||||
certain amount of space is available. For example, output ports with a
|
||||
variably sized type are connected to a Chunk so the plugin knows the size of
|
||||
the buffer available for writing.</p>
|
||||
|
||||
<p>The use of a Chunk should be constrained to a local scope, since
|
||||
interpreting it is impossible without context. However, if serialised to RDF,
|
||||
a Chunk may be represented directly as an xsd:base64Binary string, e.g.:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
[] eg:someChunk "vu/erQ=="^^xsd:base64Binary .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:Number
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Number" .
|
||||
|
||||
atom:Int
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Number ;
|
||||
rdfs:label "Signed 32-bit integer" ;
|
||||
atom:cType "LV2_Atom_Int" ;
|
||||
owl:onDatatype xsd:int .
|
||||
|
||||
atom:Long
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Number ;
|
||||
rdfs:label "Signed 64-bit integer" ;
|
||||
atom:cType "LV2_Atom_Long" ;
|
||||
owl:onDatatype xsd:long .
|
||||
|
||||
atom:Float
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Number ;
|
||||
rdfs:label "32-bit floating point number" ;
|
||||
atom:cType "LV2_Atom_Float" ;
|
||||
owl:onDatatype xsd:float .
|
||||
|
||||
atom:Double
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Number ;
|
||||
rdfs:label "64-bit floating point number" ;
|
||||
atom:cType "LV2_Atom_Double" ;
|
||||
owl:onDatatype xsd:double .
|
||||
|
||||
atom:Bool
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Boolean" ;
|
||||
atom:cType "LV2_Atom_Bool" ;
|
||||
owl:onDatatype xsd:boolean ;
|
||||
rdfs:comment "An Int where 0 is false and any other value is true." .
|
||||
|
||||
atom:String
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "String" ;
|
||||
atom:cType "LV2_Atom_String" ;
|
||||
owl:onDatatype xsd:string ;
|
||||
lv2:documentation """
|
||||
<p>A UTF-8 encoded string.</p>
|
||||
|
||||
<p>The body of an LV2_Atom_String is a C string in UTF-8 encoding, i.e. an
|
||||
array of bytes (<code>uint8_t</code>) terminated with a NULL byte
|
||||
(<code>'\\0'</code>).</p>
|
||||
|
||||
<p>This type is for free-form strings, but SHOULD NOT be used for typed data or
|
||||
text in any language. Use atom:Literal unless translating the string does not
|
||||
make sense and the string has no meaningful datatype.</p>
|
||||
""" .
|
||||
|
||||
atom:Literal
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "String Literal" ;
|
||||
atom:cType "LV2_Atom_Literal" ;
|
||||
lv2:documentation """
|
||||
<p>A UTF-8 encoded string literal, with an optional datatype or language.</p>
|
||||
|
||||
<p>This type is compatible with rdfs:Literal and is capable of expressing a
|
||||
string in any language or a value of any type. A Literal has a
|
||||
<code>datatype</code> and <code>lang</code> followed by string data in UTF-8
|
||||
encoding. The length of the string data in bytes is <code>size -
|
||||
sizeof(LV2_Atom_Literal)</code>, including the terminating NULL character. The
|
||||
<code>lang</code> field SHOULD be a URI of the form
|
||||
<http://lexvo.org/id/iso639-3/LANG> or
|
||||
<http://lexvo.org/id/iso639-1/LANG> where LANG is a 3-character ISO 693-3
|
||||
language code, or a 2-character ISO 693-1 language code, respectively.</p>
|
||||
|
||||
<p>A Literal may have a <code>datatype</code> OR a <code>lang</code>, but never
|
||||
both.</p>
|
||||
|
||||
<p>For example, a Literal can be "Hello" in English:</p>
|
||||
<pre class="c-code">
|
||||
void set_to_hello_in_english(LV2_Atom_Literal* lit) {
|
||||
lit->atom.type = map(expand("atom:Literal"));
|
||||
lit->atom.size = 14;
|
||||
lit->body.datatype = 0;
|
||||
lit->body.lang = map("http://lexvo.org/id/iso639-1/en");
|
||||
memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
|
||||
"Hello",
|
||||
sizeof("Hello")); // Assumes enough space
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>or a Turtle string:</p>
|
||||
<pre class="c-code">
|
||||
void set_to_turtle_string(LV2_Atom_Literal* lit, const char* ttl) {
|
||||
lit->atom.type = map(expand("atom:Literal"));
|
||||
lit->atom.size = 64;
|
||||
lit->body.datatype = map("http://www.w3.org/2008/turtle#turtle");
|
||||
lit->body.lang = 0;
|
||||
memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit),
|
||||
ttl,
|
||||
strlen(ttl) + 1); // Assumes enough space
|
||||
}
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:Path
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:URI ;
|
||||
owl:onDatatype atom:URI ;
|
||||
rdfs:label "File path string" ;
|
||||
lv2:documentation """
|
||||
<p>A local file path.</p>
|
||||
|
||||
<p>A Path is a URI reference with only a path component: no scheme, authority,
|
||||
query, or fragment. In particular, paths to files in the same bundle may be
|
||||
cleanly written in Turtle files as a relative URI. However, implementations
|
||||
may assume any binary Path (e.g. in an event payload) is a valid file path
|
||||
which can passed to system functions like fopen() directly, without any
|
||||
character encoding or escape expansion required.</p>
|
||||
|
||||
<p>Any implemenation that creates a Path atom to transmit to another is
|
||||
responsible for ensuring it is valid. A Path SHOULD always be absolute, unless
|
||||
there is some mechanism in place that defines a base path. Since this is not
|
||||
the case for plugin instances, effectively any Path sent to or received from a
|
||||
plugin instance MUST be absolute.</p>
|
||||
""" .
|
||||
|
||||
atom:URI
|
||||
a rdfs:Class ,
|
||||
rdfs:Datatype ;
|
||||
rdfs:subClassOf atom:String ;
|
||||
owl:onDatatype xsd:anyURI ;
|
||||
rdfs:label "URI string" ;
|
||||
lv2:documentation """
|
||||
<p>A URI string. This is useful when a URI is needed but mapping is
|
||||
inappropriate, for example with temporary or relative URIs. Since the ability
|
||||
to distinguish URIs from plain strings is often necessary, URIs MUST NOT be
|
||||
transmitted as atom:String.</p>
|
||||
|
||||
<p>This is not strictly a URI, since UTF-8 is allowed. Escaping and related
|
||||
issues are the host's responsibility.</p>
|
||||
""" .
|
||||
|
||||
atom:URID
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Integer URID" ;
|
||||
atom:cType "LV2_Atom_URID" ;
|
||||
lv2:documentation """
|
||||
<p>An unsigned 32-bit integer mapped from a URI (e.g. with LV2_URID_Map).</p>
|
||||
""" .
|
||||
|
||||
atom:Vector
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Vector" ;
|
||||
atom:cType "LV2_Atom_Vector" ;
|
||||
lv2:documentation """
|
||||
<p>A homogeneous series of atom bodies with equivalent type and size.</p>
|
||||
|
||||
<p>An LV2_Atom_Vector is a 32-bit <code>child_size</code> and
|
||||
<code>child_type</code> followed by <code>size / child_size</code> atom
|
||||
bodies.</p>
|
||||
|
||||
<p>For example, an atom:Vector containing 42 elements of type atom:Float:</p>
|
||||
<pre class="c-code">
|
||||
struct VectorOf42Floats {
|
||||
uint32_t size; // sizeof(LV2_Atom_Vector_Body) + (42 * sizeof(float);
|
||||
uint32_t type; // map(expand("atom:Vector"))
|
||||
uint32_t child_size; // sizeof(float)
|
||||
uint32_t child_type; // map(expand("atom:Float"))
|
||||
float elems[42];
|
||||
};
|
||||
</pre>
|
||||
|
||||
<p>Note that it is possible to construct a valid Atom for each element
|
||||
of the vector, even by an implementation which does not understand
|
||||
<code>child_type</code>.</p>
|
||||
|
||||
<p>If serialised to RDF, a Vector SHOULD have the form:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
eg:someVector
|
||||
a atom:Vector ;
|
||||
atom:childType atom:Int ;
|
||||
rdf:value (
|
||||
"1"^^xsd:int
|
||||
"2"^^xsd:int
|
||||
"3"^^xsd:int
|
||||
"4"^^xsd:int
|
||||
) .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:Tuple
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Tuple" ;
|
||||
lv2:documentation """
|
||||
<p>A series of Atoms with varying <code>type</code> and <code>size</code>.</p>
|
||||
|
||||
<p>The body of a Tuple is simply a series of complete atoms, each aligned to
|
||||
64 bits.</p>
|
||||
|
||||
<p>If serialised to RDF, a Tuple SHOULD have the form:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
eg:someVector
|
||||
a atom:Tuple ;
|
||||
rdf:value (
|
||||
"1"^^xsd:int
|
||||
"3.5"^^xsd:float
|
||||
"etc"
|
||||
) .
|
||||
</pre>
|
||||
|
||||
""" .
|
||||
|
||||
atom:Property
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Property" ;
|
||||
atom:cType "LV2_Atom_Property" ;
|
||||
lv2:documentation """
|
||||
<p>A property of an atom:Object. An LV2_Atom_Property has a URID
|
||||
<code>key</code> and <code>context</code>, and an Atom <code>value</code>.
|
||||
This corresponds to an RDF Property, where the <q>key</q> is the <q>predicate</q>
|
||||
and the <q>value</q> is the object.</p>
|
||||
|
||||
<p>The <code>context</code> field can be used to specify a different context
|
||||
for each property, where this is useful. Otherwise, it may be 0.</p>
|
||||
|
||||
<p>Properties generally only exist as part of an atom:Object. Accordingly,
|
||||
they will typically be represented directly as properties in RDF (see
|
||||
atom:Object). If this is not possible, they may be expressed as partial
|
||||
reified statements, e.g.:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
eg:someProperty
|
||||
rdf:predicate eg:theKey ;
|
||||
rdf:object eg:theValue .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:Object
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Object" ;
|
||||
atom:cType "LV2_Atom_Object" ;
|
||||
lv2:documentation """
|
||||
<p>An <q>Object</q> is an atom with a set of properties. This corresponds to
|
||||
an RDF Resource, and can be thought of as a dictionary with URID keys.</p>
|
||||
|
||||
<p>An LV2_Atom_Object body has a uint32_t <code>id</code> and
|
||||
<code>type</code>, followed by a series of atom:Property bodies
|
||||
(LV2_Atom_Property_Body). The LV2_Atom_Object_Body::otype field is equivalent
|
||||
to a property with key rdf:type, but is included in the structure to allow for
|
||||
fast dispatching.</p>
|
||||
|
||||
<p>Code SHOULD check for objects using lv2_atom_forge_is_object() or
|
||||
lv2_atom_forge_is_blank() if a forge is available, rather than checking the
|
||||
atom type directly. This will correctly handle the deprecated atom:Resource
|
||||
and atom:Blank types.</p>
|
||||
|
||||
<p>When serialised to RDF, an Object is represented as a resource, e.g.:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
eg:someObject
|
||||
eg:firstPropertyKey "first property value" ;
|
||||
eg:secondPropertyKey "first loser" ;
|
||||
eg:andSoOn "and so on" .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:Resource
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Object ;
|
||||
rdfs:label "Resource" ;
|
||||
owl:deprecated "true"^^xsd:boolean ;
|
||||
atom:cType "LV2_Atom_Object" ;
|
||||
lv2:documentation """
|
||||
<p>This class is deprecated. Use atom:Object instead.</p>
|
||||
|
||||
<p>An atom:Object where the <code>id</code> field is a URID, i.e. an Object
|
||||
with a URI.</p>
|
||||
""" .
|
||||
|
||||
atom:Blank
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Object ;
|
||||
rdfs:label "Blank" ;
|
||||
owl:deprecated "true"^^xsd:boolean ;
|
||||
atom:cType "LV2_Atom_Object" ;
|
||||
lv2:documentation """
|
||||
<p>This class is deprecated. Use atom:Object with ID 0 instead.</p>
|
||||
|
||||
<p>An atom:Object where the LV2_Atom_Object::id is a blank node ID (NOT a URI).
|
||||
The ID of a Blank is valid only within the context the Blank appears in. For
|
||||
ports this is the context of the associated run() call, i.e. all ports share
|
||||
the same context so outputs can contain IDs that correspond to IDs of blanks in
|
||||
the input.</p>
|
||||
""" .
|
||||
|
||||
atom:Sound
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Vector ;
|
||||
rdfs:label "Sound" ;
|
||||
atom:cType "LV2_Atom_Sound" ;
|
||||
lv2:documentation """
|
||||
<p>An atom:Vector of atom:Float which represents an audio waveform. The format
|
||||
is the same as the buffer format for lv2:AudioPort (except the size may be
|
||||
arbitrary). An atom:Sound inherently depends on the sample rate, which is
|
||||
assumed to be known from context. Because of this, directly serialising an
|
||||
atom:Sound is probably a bad idea, use a standard format like WAV instead.</p>
|
||||
""" .
|
||||
|
||||
atom:frameTime
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
owl:FunctionalProperty ;
|
||||
rdfs:range xsd:decimal ;
|
||||
rdfs:label "frame time" ;
|
||||
lv2:documentation """
|
||||
<p>Time stamp in audio frames. Typically used for events.</p>
|
||||
""" .
|
||||
|
||||
atom:beatTime
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
owl:FunctionalProperty ;
|
||||
rdfs:range xsd:decimal ;
|
||||
rdfs:label "beat time" ;
|
||||
lv2:documentation """
|
||||
<p>Time stamp in beats. Typically used for events.</p>
|
||||
""" .
|
||||
|
||||
atom:Event
|
||||
a rdfs:Class ;
|
||||
rdfs:label "Event" ;
|
||||
atom:cType "LV2_Atom_Event" ;
|
||||
lv2:documentation """
|
||||
<p>An atom with a time stamp prefix, typically an element of an atom:Sequence.
|
||||
Note this is not an Atom type.</p>
|
||||
""" .
|
||||
|
||||
atom:Sequence
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf atom:Atom ;
|
||||
rdfs:label "Sequence" ;
|
||||
atom:cType "LV2_Atom_Sequence" ;
|
||||
lv2:documentation """
|
||||
<p>A sequence of atom:Event, i.e. a series of time-stamped Atoms.</p>
|
||||
|
||||
<p>LV2_Atom_Sequence_Body.unit describes the time unit for the contained atoms.
|
||||
If the unit is known from context (e.g. run() stamps are always audio frames),
|
||||
this field may be zero. Otherwise, it SHOULD be either units:frame or
|
||||
units:beat, in which case ev.time.frames or ev.time.beats is valid,
|
||||
respectively.</p>
|
||||
|
||||
<p>If serialised to RDF, a Sequence has a similar form to atom:Vector, but for
|
||||
brevity the elements may be assumed to be atom:Event, e.g.:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
eg:someSequence
|
||||
a atom:Sequence ;
|
||||
rdf:value (
|
||||
[
|
||||
atom:frameTime 1 ;
|
||||
rdf:value "901A01"^^midi:MidiEvent
|
||||
] [
|
||||
atom:frameTime 3 ;
|
||||
rdf:value "902B02"^^midi:MidiEvent
|
||||
]
|
||||
) .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:AtomPort
|
||||
a rdfs:Class ;
|
||||
rdfs:subClassOf lv2:Port ;
|
||||
rdfs:label "Atom Port" ;
|
||||
lv2:documentation """
|
||||
<p>A port which contains an atom:Atom. Ports of this type are connected to an
|
||||
LV2_Atom with a type specified by atom:bufferType.</p>
|
||||
|
||||
<p>Output ports with a variably sized type MUST be initialised by the host
|
||||
before every run() to an atom:Chunk with size set to the available space. The
|
||||
plugin reads this size to know how much space is available for writing. In all
|
||||
cases, the plugin MUST write a complete atom (including header) to outputs.
|
||||
However, to be robust, hosts SHOULD initialise output ports to a safe sentinel
|
||||
(e.g. the null Atom) before calling run().</p>
|
||||
""" .
|
||||
|
||||
atom:bufferType
|
||||
a rdf:Property ,
|
||||
owl:ObjectProperty ;
|
||||
rdfs:domain atom:AtomPort ;
|
||||
rdfs:range rdfs:Class ;
|
||||
rdfs:label "buffer type" ;
|
||||
lv2:documentation """
|
||||
<p>Indicates that an AtomPort may be connected to a certain Atom type. A port
|
||||
MAY support several buffer types. The host MUST NOT connect a port to an Atom
|
||||
with a type not explicitly listed with this property. The value of this
|
||||
property MUST be a sub-class of atom:Atom. For example, an input port that is
|
||||
connected directly to an LV2_Atom_Double value is described like so:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
<plugin>
|
||||
lv2:port [
|
||||
a lv2:InputPort , atom:AtomPort ;
|
||||
atom:bufferType atom:Double ;
|
||||
] .
|
||||
</pre>
|
||||
|
||||
<p>This property only describes the types a port may be <em>directly</em>
|
||||
connected to. It says nothing about the expected contents of containers. For
|
||||
that, use atom:supports.</p>
|
||||
""" .
|
||||
|
||||
atom:childType
|
||||
a rdf:Property ,
|
||||
owl:ObjectProperty ;
|
||||
rdfs:label "child type" ;
|
||||
rdfs:comment "The type of a container's children." .
|
||||
|
||||
atom:supports
|
||||
a rdf:Property ;
|
||||
rdfs:label "supports" ;
|
||||
rdfs:range rdfs:Class ;
|
||||
lv2:documentation """
|
||||
<p>Indicates that a particular Atom type is supported.</p>
|
||||
|
||||
<p>This property is defined loosely, it may be used to indicate that anything
|
||||
<q>supports</q> an Atom type, wherever that may be useful. It applies
|
||||
<q>recursively</q> where collections are involved.</p>
|
||||
|
||||
<p>In particular, this property can be used to describe which event types are
|
||||
expected by a port. For example, a port that receives MIDI events is described
|
||||
like so:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
<plugin>
|
||||
lv2:port [
|
||||
a lv2:InputPort , atom:AtomPort ;
|
||||
atom:bufferType atom:Sequence ;
|
||||
atom:supports midi:MidiEvent ;
|
||||
] .
|
||||
</pre>
|
||||
""" .
|
||||
|
||||
atom:eventTransfer
|
||||
a ui:PortProtocol ;
|
||||
rdfs:label "event transfer" ;
|
||||
lv2:documentation """
|
||||
<p>Transfer of individual events in a port buffer. Useful as the
|
||||
<code>format</code> for a LV2UI_Write_Function.</p>
|
||||
|
||||
<p>This protocol applies to ports which contain events, usually in an
|
||||
atom:Sequence. The host must transfer each individual event to the recipient.
|
||||
The format of the received data is an LV2_Atom, there is no timestamp
|
||||
header.</p>
|
||||
""" .
|
||||
|
||||
atom:atomTransfer
|
||||
a ui:PortProtocol ;
|
||||
rdfs:label "atom transfer" ;
|
||||
lv2:documentation """
|
||||
<p>Transfer of the complete atom in a port buffer. Useful as the
|
||||
<code>format</code> for a LV2UI_Write_Function.</p>
|
||||
|
||||
<p>This protocol applies to atom ports. The host must transfer the complete
|
||||
atom contained in the port, including header.</p>
|
||||
""" .
|
||||
237
lv2/lv2/atom/forge-overflow-test.c
Normal file
237
lv2/lv2/atom/forge-overflow-test.c
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
Copyright 2019 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lv2/atom/atom-test-utils.c"
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/forge.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/urid/urid.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int
|
||||
test_string_overflow(void)
|
||||
{
|
||||
#define MAX_CHARS 15
|
||||
|
||||
static const size_t capacity = sizeof(LV2_Atom_String) + MAX_CHARS + 1;
|
||||
static const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
|
||||
// Check that writing increasingly long strings fails at the right point
|
||||
for (size_t count = 0; count < MAX_CHARS; ++count) {
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
|
||||
const LV2_Atom_Forge_Ref ref =
|
||||
lv2_atom_forge_string(&forge, str, count);
|
||||
if (!ref) {
|
||||
return test_fail("Failed to write %zu byte string\n", count);
|
||||
}
|
||||
}
|
||||
|
||||
// Failure writing to an exactly full forge
|
||||
LV2_Atom_Forge_Ref ref = 0;
|
||||
if ((ref = lv2_atom_forge_string(&forge, str, MAX_CHARS + 1))) {
|
||||
return test_fail("Successfully wrote past end of buffer\n");
|
||||
}
|
||||
|
||||
// Failure writing body after successfully writing header
|
||||
lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1);
|
||||
if ((ref = lv2_atom_forge_string(&forge, "AB", 2))) {
|
||||
return test_fail("Successfully wrote atom header past end\n");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_literal_overflow(void)
|
||||
{
|
||||
static const size_t capacity = sizeof(LV2_Atom_Literal) + 2;
|
||||
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
LV2_Atom_Forge_Ref ref = 0;
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
|
||||
// Failure in atom header
|
||||
lv2_atom_forge_set_buffer(&forge, buf, 1);
|
||||
if ((ref = lv2_atom_forge_literal(&forge, "A", 1, 0, 0))) {
|
||||
return test_fail("Successfully wrote atom header past end\n");
|
||||
}
|
||||
|
||||
// Failure in literal header
|
||||
lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1);
|
||||
if ((ref = lv2_atom_forge_literal(&forge, "A", 1, 0, 0))) {
|
||||
return test_fail("Successfully wrote literal header past end\n");
|
||||
}
|
||||
|
||||
// Success (only room for one character + null terminator)
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
if (!(ref = lv2_atom_forge_literal(&forge, "A", 1, 0, 0))) {
|
||||
return test_fail("Failed to write small enough literal\n");
|
||||
}
|
||||
|
||||
// Failure in body
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
if ((ref = lv2_atom_forge_literal(&forge, "AB", 2, 0, 0))) {
|
||||
return test_fail("Successfully wrote literal body past end\n");
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_sequence_overflow(void)
|
||||
{
|
||||
static const size_t size = sizeof(LV2_Atom_Sequence) + 6 * sizeof(LV2_Atom);
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
|
||||
// Test over a range that fails in the sequence header and event components
|
||||
for (size_t capacity = 1; capacity < size; ++capacity) {
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom_Forge_Ref ref =
|
||||
lv2_atom_forge_sequence_head(&forge, &frame, 0);
|
||||
|
||||
assert(capacity >= sizeof(LV2_Atom_Sequence) || !frame.ref);
|
||||
assert(capacity >= sizeof(LV2_Atom_Sequence) || !ref);
|
||||
|
||||
lv2_atom_forge_frame_time(&forge, 0);
|
||||
lv2_atom_forge_int(&forge, 42);
|
||||
lv2_atom_forge_pop(&forge, &frame);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_vector_head_overflow(void)
|
||||
{
|
||||
static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom);
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
|
||||
// Test over a range that fails in the vector header and elements
|
||||
for (size_t capacity = 1; capacity < size; ++capacity) {
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector_head(
|
||||
&forge, &frame, sizeof(int32_t), forge.Int);
|
||||
|
||||
assert(capacity >= sizeof(LV2_Atom_Vector) || !frame.ref);
|
||||
assert(capacity >= sizeof(LV2_Atom_Vector) || !ref);
|
||||
|
||||
lv2_atom_forge_int(&forge, 1);
|
||||
lv2_atom_forge_int(&forge, 2);
|
||||
lv2_atom_forge_int(&forge, 3);
|
||||
lv2_atom_forge_pop(&forge, &frame);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_vector_overflow(void)
|
||||
{
|
||||
static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom);
|
||||
static const int32_t vec[] = { 1, 2, 3 };
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
|
||||
// Test over a range that fails in the vector header and elements
|
||||
for (size_t capacity = 1; capacity < size; ++capacity) {
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
|
||||
LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector(
|
||||
&forge, sizeof(int32_t), forge.Int, 3, vec);
|
||||
|
||||
assert(capacity >= sizeof(LV2_Atom_Vector) || !ref);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
test_tuple_overflow(void)
|
||||
{
|
||||
static const size_t size = sizeof(LV2_Atom_Tuple) + 3 * sizeof(LV2_Atom);
|
||||
LV2_URID_Map map = { NULL, urid_map };
|
||||
|
||||
// Test over a range that fails in the tuple header and elements
|
||||
for (size_t capacity = 1; capacity < size; ++capacity) {
|
||||
uint8_t* buf = (uint8_t*)malloc(capacity);
|
||||
|
||||
LV2_Atom_Forge forge;
|
||||
lv2_atom_forge_init(&forge, &map);
|
||||
lv2_atom_forge_set_buffer(&forge, buf, capacity);
|
||||
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom_Forge_Ref ref = lv2_atom_forge_tuple(&forge, &frame);
|
||||
|
||||
assert(capacity >= sizeof(LV2_Atom_Tuple) || !frame.ref);
|
||||
assert(capacity >= sizeof(LV2_Atom_Tuple) || !ref);
|
||||
|
||||
lv2_atom_forge_int(&forge, 1);
|
||||
lv2_atom_forge_float(&forge, 2.0f);
|
||||
lv2_atom_forge_string(&forge, "three", 5);
|
||||
lv2_atom_forge_pop(&forge, &frame);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
const int ret = test_string_overflow() || test_literal_overflow() ||
|
||||
test_sequence_overflow() || test_vector_head_overflow() ||
|
||||
test_vector_overflow() || test_tuple_overflow();
|
||||
|
||||
free_urid_map();
|
||||
|
||||
return ret;
|
||||
}
|
||||
696
lv2/lv2/atom/forge.h
Normal file
696
lv2/lv2/atom/forge.h
Normal file
|
|
@ -0,0 +1,696 @@
|
|||
/*
|
||||
Copyright 2008-2016 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file forge.h An API for constructing LV2 atoms.
|
||||
|
||||
This file provides an API for constructing Atoms which makes it relatively
|
||||
simple to build nested atoms of arbitrary complexity without requiring
|
||||
dynamic memory allocation.
|
||||
|
||||
The API is based on successively appending the appropriate pieces to build a
|
||||
complete Atom. The size of containers is automatically updated. Functions
|
||||
that begin a container return (via their frame argument) a stack frame which
|
||||
must be popped when the container is finished.
|
||||
|
||||
All output is written to a user-provided buffer or sink function. This
|
||||
makes it popssible to create create atoms on the stack, on the heap, in LV2
|
||||
port buffers, in a ringbuffer, or elsewhere, all using the same API.
|
||||
|
||||
This entire API is realtime safe if used with a buffer or a realtime safe
|
||||
sink, except lv2_atom_forge_init() which is only realtime safe if the URI
|
||||
map function is.
|
||||
|
||||
Note these functions are all static inline, do not take their address.
|
||||
|
||||
This header is non-normative, it is provided for convenience.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup forge Forge
|
||||
@ingroup atom
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_FORGE_H
|
||||
#define LV2_ATOM_FORGE_H
|
||||
|
||||
#include "lv2/atom/atom.h"
|
||||
#include "lv2/atom/util.h"
|
||||
#include "lv2/core/attributes.h"
|
||||
#include "lv2/urid/urid.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Disable deprecation warnings for Blank and Resource
|
||||
LV2_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
/** Handle for LV2_Atom_Forge_Sink. */
|
||||
typedef void* LV2_Atom_Forge_Sink_Handle;
|
||||
|
||||
/** A reference to a chunk of written output. */
|
||||
typedef intptr_t LV2_Atom_Forge_Ref;
|
||||
|
||||
/** Sink function for writing output. See lv2_atom_forge_set_sink(). */
|
||||
typedef LV2_Atom_Forge_Ref
|
||||
(*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
|
||||
const void* buf,
|
||||
uint32_t size);
|
||||
|
||||
/** Function for resolving a reference. See lv2_atom_forge_set_sink(). */
|
||||
typedef LV2_Atom*
|
||||
(*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle,
|
||||
LV2_Atom_Forge_Ref ref);
|
||||
|
||||
/** A stack frame used for keeping track of nested Atom containers. */
|
||||
typedef struct _LV2_Atom_Forge_Frame {
|
||||
struct _LV2_Atom_Forge_Frame* parent;
|
||||
LV2_Atom_Forge_Ref ref;
|
||||
} LV2_Atom_Forge_Frame;
|
||||
|
||||
/** A "forge" for creating atoms by appending to a buffer. */
|
||||
typedef struct {
|
||||
uint8_t* buf;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
|
||||
LV2_Atom_Forge_Sink sink;
|
||||
LV2_Atom_Forge_Deref_Func deref;
|
||||
LV2_Atom_Forge_Sink_Handle handle;
|
||||
|
||||
LV2_Atom_Forge_Frame* stack;
|
||||
|
||||
LV2_URID Blank LV2_DEPRECATED;
|
||||
LV2_URID Bool;
|
||||
LV2_URID Chunk;
|
||||
LV2_URID Double;
|
||||
LV2_URID Float;
|
||||
LV2_URID Int;
|
||||
LV2_URID Long;
|
||||
LV2_URID Literal;
|
||||
LV2_URID Object;
|
||||
LV2_URID Path;
|
||||
LV2_URID Property;
|
||||
LV2_URID Resource LV2_DEPRECATED;
|
||||
LV2_URID Sequence;
|
||||
LV2_URID String;
|
||||
LV2_URID Tuple;
|
||||
LV2_URID URI;
|
||||
LV2_URID URID;
|
||||
LV2_URID Vector;
|
||||
} LV2_Atom_Forge;
|
||||
|
||||
static inline void
|
||||
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
|
||||
|
||||
/**
|
||||
Initialise `forge`.
|
||||
|
||||
URIs will be mapped using `map` and stored, a reference to `map` itself is
|
||||
not held.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
|
||||
{
|
||||
lv2_atom_forge_set_buffer(forge, NULL, 0);
|
||||
forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
|
||||
forge->Bool = map->map(map->handle, LV2_ATOM__Bool);
|
||||
forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk);
|
||||
forge->Double = map->map(map->handle, LV2_ATOM__Double);
|
||||
forge->Float = map->map(map->handle, LV2_ATOM__Float);
|
||||
forge->Int = map->map(map->handle, LV2_ATOM__Int);
|
||||
forge->Long = map->map(map->handle, LV2_ATOM__Long);
|
||||
forge->Literal = map->map(map->handle, LV2_ATOM__Literal);
|
||||
forge->Object = map->map(map->handle, LV2_ATOM__Object);
|
||||
forge->Path = map->map(map->handle, LV2_ATOM__Path);
|
||||
forge->Property = map->map(map->handle, LV2_ATOM__Property);
|
||||
forge->Resource = map->map(map->handle, LV2_ATOM__Resource);
|
||||
forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence);
|
||||
forge->String = map->map(map->handle, LV2_ATOM__String);
|
||||
forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple);
|
||||
forge->URI = map->map(map->handle, LV2_ATOM__URI);
|
||||
forge->URID = map->map(map->handle, LV2_ATOM__URID);
|
||||
forge->Vector = map->map(map->handle, LV2_ATOM__Vector);
|
||||
}
|
||||
|
||||
/** Access the Atom pointed to by a reference. */
|
||||
static inline LV2_Atom*
|
||||
lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref)
|
||||
{
|
||||
return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref);
|
||||
}
|
||||
|
||||
/**
|
||||
@name Object Stack
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
Push a stack frame.
|
||||
This is done automatically by container functions (which take a stack frame
|
||||
pointer), but may be called by the user to push the top level container when
|
||||
writing to an existing Atom.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_push(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
LV2_Atom_Forge_Ref ref)
|
||||
{
|
||||
frame->parent = forge->stack;
|
||||
frame->ref = ref;
|
||||
|
||||
if (ref) {
|
||||
forge->stack = frame; // Don't push, so walking the stack is always safe
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/** Pop a stack frame. This must be called when a container is finished. */
|
||||
static inline void
|
||||
lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
|
||||
{
|
||||
if (frame->ref) {
|
||||
// If frame has a valid ref, it must be the top of the stack
|
||||
assert(frame == forge->stack);
|
||||
forge->stack = frame->parent;
|
||||
}
|
||||
// Otherwise, frame was not pushed because of overflow, do nothing
|
||||
}
|
||||
|
||||
/** Return true iff the top of the stack has the given type. */
|
||||
static inline bool
|
||||
lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type)
|
||||
{
|
||||
return forge->stack && forge->stack->ref &&
|
||||
(lv2_atom_forge_deref(forge, forge->stack->ref)->type == type);
|
||||
}
|
||||
|
||||
/** Return true iff `type` is an atom:Object. */
|
||||
static inline bool
|
||||
lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type)
|
||||
{
|
||||
return (type == forge->Object ||
|
||||
type == forge->Blank ||
|
||||
type == forge->Resource);
|
||||
}
|
||||
|
||||
/** Return true iff `type` is an atom:Object with a blank ID. */
|
||||
static inline bool
|
||||
lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge,
|
||||
uint32_t type,
|
||||
const LV2_Atom_Object_Body* body)
|
||||
{
|
||||
return (type == forge->Blank ||
|
||||
(type == forge->Object && body->id == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Output Configuration
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Set the output buffer where `forge` will write atoms. */
|
||||
static inline void
|
||||
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
|
||||
{
|
||||
forge->buf = buf;
|
||||
forge->size = (uint32_t)size;
|
||||
forge->offset = 0;
|
||||
forge->deref = NULL;
|
||||
forge->sink = NULL;
|
||||
forge->handle = NULL;
|
||||
forge->stack = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Set the sink function where `forge` will write output.
|
||||
|
||||
The return value of forge functions is an LV2_Atom_Forge_Ref which is an
|
||||
integer type safe to use as a pointer but is otherwise opaque. The sink
|
||||
function must return a ref that can be dereferenced to access as least
|
||||
sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For
|
||||
ringbuffers, this should be possible as long as the size of the buffer is a
|
||||
multiple of sizeof(LV2_Atom), since atoms are always aligned.
|
||||
|
||||
Note that 0 is an invalid reference, so if you are using a buffer offset be
|
||||
sure to offset it such that 0 is never a valid reference. You will get
|
||||
confusing errors otherwise.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Sink sink,
|
||||
LV2_Atom_Forge_Deref_Func deref,
|
||||
LV2_Atom_Forge_Sink_Handle handle)
|
||||
{
|
||||
forge->buf = NULL;
|
||||
forge->size = forge->offset = 0;
|
||||
forge->deref = deref;
|
||||
forge->sink = sink;
|
||||
forge->handle = handle;
|
||||
forge->stack = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Low Level Output
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
Write raw output. This is used internally, but is also useful for writing
|
||||
atom types not explicitly supported by the forge API. Note the caller is
|
||||
responsible for ensuring the output is approriately padded.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
|
||||
{
|
||||
LV2_Atom_Forge_Ref out = 0;
|
||||
if (forge->sink) {
|
||||
out = forge->sink(forge->handle, data, size);
|
||||
} else {
|
||||
out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset;
|
||||
uint8_t* mem = forge->buf + forge->offset;
|
||||
if (forge->offset + size > forge->size) {
|
||||
return 0;
|
||||
}
|
||||
forge->offset += size;
|
||||
memcpy(mem, data, size);
|
||||
}
|
||||
for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
|
||||
lv2_atom_forge_deref(forge, f->ref)->size += size;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Pad output accordingly so next write is 64-bit aligned. */
|
||||
static inline void
|
||||
lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
|
||||
{
|
||||
const uint64_t pad = 0;
|
||||
const uint32_t pad_size = lv2_atom_pad_size(written) - written;
|
||||
lv2_atom_forge_raw(forge, &pad, pad_size);
|
||||
}
|
||||
|
||||
/** Write raw output, padding to 64-bits as necessary. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
|
||||
{
|
||||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size);
|
||||
if (out) {
|
||||
lv2_atom_forge_pad(forge, size);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write a null-terminated string body. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
|
||||
const char* str,
|
||||
uint32_t len)
|
||||
{
|
||||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len);
|
||||
if (out && (out = lv2_atom_forge_raw(forge, "", 1))) {
|
||||
lv2_atom_forge_pad(forge, len + 1);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Atom Output
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Write an atom:Atom header. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
|
||||
{
|
||||
const LV2_Atom a = { size, type };
|
||||
return lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
}
|
||||
|
||||
/** Write a primitive (fixed-size) atom. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a)
|
||||
{
|
||||
return (lv2_atom_forge_top_is(forge, forge->Vector)
|
||||
? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size)
|
||||
: lv2_atom_forge_write(
|
||||
forge, a, (uint32_t)sizeof(LV2_Atom) + a->size));
|
||||
}
|
||||
|
||||
/** Write an atom:Int. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val)
|
||||
{
|
||||
const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom:Long. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val)
|
||||
{
|
||||
const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom:Float. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
|
||||
{
|
||||
const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom:Double. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
|
||||
{
|
||||
const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom:Bool. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
|
||||
{
|
||||
const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom:URID. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
|
||||
{
|
||||
const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id };
|
||||
return lv2_atom_forge_primitive(forge, &a.atom);
|
||||
}
|
||||
|
||||
/** Write an atom compatible with atom:String. Used internally. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
|
||||
uint32_t type,
|
||||
const char* str,
|
||||
uint32_t len)
|
||||
{
|
||||
const LV2_Atom_String a = { { len + 1, type } };
|
||||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
if (out) {
|
||||
if (!lv2_atom_forge_string_body(forge, str, len)) {
|
||||
LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
|
||||
atom->size = atom->type = 0;
|
||||
out = 0;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Write an atom:String. Note that `str` need not be NULL terminated. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->String, str, len);
|
||||
}
|
||||
|
||||
/**
|
||||
Write an atom:URI. Note that `uri` need not be NULL terminated.
|
||||
This does not map the URI, but writes the complete URI string. To write
|
||||
a mapped URI, use lv2_atom_forge_urid().
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
|
||||
}
|
||||
|
||||
/** Write an atom:Path. Note that `path` need not be NULL terminated. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len)
|
||||
{
|
||||
return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
|
||||
}
|
||||
|
||||
/** Write an atom:Literal. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_literal(LV2_Atom_Forge* forge,
|
||||
const char* str,
|
||||
uint32_t len,
|
||||
uint32_t datatype,
|
||||
uint32_t lang)
|
||||
{
|
||||
const LV2_Atom_Literal a = {
|
||||
{ (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1),
|
||||
forge->Literal },
|
||||
{ datatype,
|
||||
lang }
|
||||
};
|
||||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
|
||||
if (out) {
|
||||
if (!lv2_atom_forge_string_body(forge, str, len)) {
|
||||
LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
|
||||
atom->size = atom->type = 0;
|
||||
out = 0;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Start an atom:Vector. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
uint32_t child_size,
|
||||
uint32_t child_type)
|
||||
{
|
||||
const LV2_Atom_Vector a = {
|
||||
{ sizeof(LV2_Atom_Vector_Body), forge->Vector },
|
||||
{ child_size, child_type }
|
||||
};
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/** Write a complete atom:Vector. */
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_vector(LV2_Atom_Forge* forge,
|
||||
uint32_t child_size,
|
||||
uint32_t child_type,
|
||||
uint32_t n_elems,
|
||||
const void* elems)
|
||||
{
|
||||
const LV2_Atom_Vector a = {
|
||||
{ (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size),
|
||||
forge->Vector },
|
||||
{ child_size, child_type }
|
||||
};
|
||||
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
|
||||
if (out) {
|
||||
lv2_atom_forge_write(forge, elems, child_size * n_elems);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header of an atom:Tuple.
|
||||
|
||||
The passed frame will be initialised to represent this tuple. To complete
|
||||
the tuple, write a sequence of atoms, then pop the frame with
|
||||
lv2_atom_forge_pop().
|
||||
|
||||
For example:
|
||||
@code
|
||||
// Write tuple (1, 2.0)
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
|
||||
lv2_atom_forge_int32(forge, 1);
|
||||
lv2_atom_forge_float(forge, 2.0);
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
@endcode
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
|
||||
{
|
||||
const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header of an atom:Object.
|
||||
|
||||
The passed frame will be initialised to represent this object. To complete
|
||||
the object, write a sequence of properties, then pop the frame with
|
||||
lv2_atom_forge_pop().
|
||||
|
||||
For example:
|
||||
@code
|
||||
LV2_URID eg_Cat = map("http://example.org/Cat");
|
||||
LV2_URID eg_name = map("http://example.org/name");
|
||||
|
||||
// Start object with type eg_Cat and blank ID
|
||||
LV2_Atom_Forge_Frame frame;
|
||||
lv2_atom_forge_object(forge, &frame, 0, eg_Cat);
|
||||
|
||||
// Append property eg:name = "Hobbes"
|
||||
lv2_atom_forge_key(forge, eg_name);
|
||||
lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
|
||||
|
||||
// Finish object
|
||||
lv2_atom_forge_pop(forge, &frame);
|
||||
@endcode
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_object(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
LV2_URID id,
|
||||
LV2_URID otype)
|
||||
{
|
||||
const LV2_Atom_Object a = {
|
||||
{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object },
|
||||
{ id, otype }
|
||||
};
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/**
|
||||
The same as lv2_atom_forge_object(), but for object:Resource.
|
||||
|
||||
This function is deprecated and should not be used in new code.
|
||||
Use lv2_atom_forge_object() directly instead.
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_resource(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
LV2_URID id,
|
||||
LV2_URID otype)
|
||||
{
|
||||
const LV2_Atom_Object a = {
|
||||
{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource },
|
||||
{ id, otype }
|
||||
};
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/**
|
||||
The same as lv2_atom_forge_object(), but for object:Blank.
|
||||
|
||||
This function is deprecated and should not be used in new code.
|
||||
Use lv2_atom_forge_object() directly instead.
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_blank(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
uint32_t id,
|
||||
LV2_URID otype)
|
||||
{
|
||||
const LV2_Atom_Object a = {
|
||||
{ (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank },
|
||||
{ id, otype }
|
||||
};
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/**
|
||||
Write a property key in an Object, to be followed by the value.
|
||||
|
||||
See lv2_atom_forge_object() documentation for an example.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_key(LV2_Atom_Forge* forge,
|
||||
LV2_URID key)
|
||||
{
|
||||
const LV2_Atom_Property_Body a = { key, 0, { 0, 0 } };
|
||||
return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header for a property body in an object, with context.
|
||||
|
||||
If you do not need the context, which is almost certainly the case,
|
||||
use the simpler lv2_atom_forge_key() instead.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
|
||||
LV2_URID key,
|
||||
LV2_URID context)
|
||||
{
|
||||
const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
|
||||
return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the header for a Sequence.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
|
||||
LV2_Atom_Forge_Frame* frame,
|
||||
uint32_t unit)
|
||||
{
|
||||
const LV2_Atom_Sequence a = {
|
||||
{ (uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence },
|
||||
{ unit, 0 }
|
||||
};
|
||||
return lv2_atom_forge_push(
|
||||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the time stamp header of an Event (in a Sequence) in audio frames.
|
||||
After this, call the appropriate forge method(s) to write the body. Note
|
||||
the returned reference is to an LV2_Event which is NOT an Atom.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
|
||||
{
|
||||
return lv2_atom_forge_write(forge, &frames, sizeof(frames));
|
||||
}
|
||||
|
||||
/**
|
||||
Write the time stamp header of an Event (in a Sequence) in beats. After
|
||||
this, call the appropriate forge method(s) to write the body. Note the
|
||||
returned reference is to an LV2_Event which is NOT an Atom.
|
||||
*/
|
||||
static inline LV2_Atom_Forge_Ref
|
||||
lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
|
||||
{
|
||||
return lv2_atom_forge_write(forge, &beats, sizeof(beats));
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@}
|
||||
*/
|
||||
|
||||
LV2_RESTORE_WARNINGS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_FORGE_H */
|
||||
103
lv2/lv2/atom/lv2-atom.doap.ttl
Normal file
103
lv2/lv2/atom/lv2-atom.doap.ttl
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/atom>
|
||||
a doap:Project ;
|
||||
doap:name "LV2 Atom" ;
|
||||
doap:shortdesc "A generic value container and several data types." ;
|
||||
doap:license <http://opensource.org/licenses/isc> ;
|
||||
doap:created "2007-00-00" ;
|
||||
doap:developer <http://drobilla.net/drobilla#me> ;
|
||||
doap:release [
|
||||
doap:revision "2.2" ;
|
||||
doap:created "2019-02-03" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add lv2_atom_object_get_typed() for easy type-safe access to object properties."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "2.0" ;
|
||||
doap:created "2014-08-08" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Deprecate Blank and Resource in favour of just Object."
|
||||
] , [
|
||||
rdfs:label "Add lv2_atom_forge_is_object_type() and lv2_atom_forge_is_blank() to ease backwards compatibility."
|
||||
] , [
|
||||
rdfs:label "Add lv2_atom_forge_key() for terser object writing."
|
||||
] , [
|
||||
rdfs:label "Add lv2_atom_sequence_clear() and lv2_atom_sequence_append_event() helper functions."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.8" ;
|
||||
doap:created "2014-01-04" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Make lv2_atom_*_is_end() arguments const."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.6" ;
|
||||
doap:created "2013-05-26" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.6.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix crash in forge.h when pushing atoms to a full buffer."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.4" ;
|
||||
doap:created "2013-01-27" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix lv2_atom_sequence_end()."
|
||||
] , [
|
||||
rdfs:label "Remove atom:stringType in favour of owl:onDatatype so generic tools can understand and validate atom literals."
|
||||
] , [
|
||||
rdfs:label "Improve atom documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.2" ;
|
||||
doap:created "2012-10-14" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix implicit conversions in forge.h that are invalid in C++11."
|
||||
] , [
|
||||
rdfs:label "Fix lv2_atom_object_next() on 32-bit platforms."
|
||||
] , [
|
||||
rdfs:label "Add lv2_atom_object_body_get()."
|
||||
] , [
|
||||
rdfs:label "Fix outdated documentation in forge.h."
|
||||
] , [
|
||||
rdfs:label "Use consistent label style."
|
||||
] , [
|
||||
rdfs:label "Add LV2_ATOM_CONTENTS_CONST and LV2_ATOM_BODY_CONST."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.0" ;
|
||||
doap:created "2012-04-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release."
|
||||
]
|
||||
]
|
||||
] .
|
||||
8
lv2/lv2/atom/manifest.ttl
Normal file
8
lv2/lv2/atom/manifest.ttl
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/atom>
|
||||
a lv2:Specification ;
|
||||
lv2:minorVersion 2 ;
|
||||
lv2:microVersion 2 ;
|
||||
rdfs:seeAlso <atom.ttl> .
|
||||
509
lv2/lv2/atom/util.h
Normal file
509
lv2/lv2/atom/util.h
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
/*
|
||||
Copyright 2008-2015 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file util.h Helper functions for the LV2 Atom extension.
|
||||
|
||||
Note these functions are all static inline, do not take their address.
|
||||
|
||||
This header is non-normative, it is provided for convenience.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup util Utilities
|
||||
@ingroup atom
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_ATOM_UTIL_H
|
||||
#define LV2_ATOM_UTIL_H
|
||||
|
||||
#include "lv2/atom/atom.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Pad a size to 64 bits. */
|
||||
static inline uint32_t
|
||||
lv2_atom_pad_size(uint32_t size)
|
||||
{
|
||||
return (size + 7U) & (~7U);
|
||||
}
|
||||
|
||||
/** Return the total size of `atom`, including the header. */
|
||||
static inline uint32_t
|
||||
lv2_atom_total_size(const LV2_Atom* atom)
|
||||
{
|
||||
return (uint32_t)sizeof(LV2_Atom) + atom->size;
|
||||
}
|
||||
|
||||
/** Return true iff `atom` is null. */
|
||||
static inline bool
|
||||
lv2_atom_is_null(const LV2_Atom* atom)
|
||||
{
|
||||
return !atom || (atom->type == 0 && atom->size == 0);
|
||||
}
|
||||
|
||||
/** Return true iff `a` is equal to `b`. */
|
||||
static inline bool
|
||||
lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b)
|
||||
{
|
||||
return (a == b) || ((a->type == b->type) &&
|
||||
(a->size == b->size) &&
|
||||
!memcmp(a + 1, b + 1, a->size));
|
||||
}
|
||||
|
||||
/**
|
||||
@name Sequence Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Get an iterator pointing to the first event in a Sequence body. */
|
||||
static inline LV2_Atom_Event*
|
||||
lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body)
|
||||
{
|
||||
return (LV2_Atom_Event*)(body + 1);
|
||||
}
|
||||
|
||||
/** Get an iterator pointing to the end of a Sequence body. */
|
||||
static inline LV2_Atom_Event*
|
||||
lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size)
|
||||
{
|
||||
return (LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size));
|
||||
}
|
||||
|
||||
/** Return true iff `i` has reached the end of `body`. */
|
||||
static inline bool
|
||||
lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body,
|
||||
uint32_t size,
|
||||
const LV2_Atom_Event* i)
|
||||
{
|
||||
return (const uint8_t*)i >= ((const uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return an iterator to the element following `i`. */
|
||||
static inline LV2_Atom_Event*
|
||||
lv2_atom_sequence_next(const LV2_Atom_Event* i)
|
||||
{
|
||||
return (LV2_Atom_Event*)((const uint8_t*)i
|
||||
+ sizeof(LV2_Atom_Event)
|
||||
+ lv2_atom_pad_size(i->body.size));
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all events in a Sequence.
|
||||
@param seq The sequence to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) {
|
||||
// Do something with ev (an LV2_Atom_Event*) here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \
|
||||
for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \
|
||||
!lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \
|
||||
(iter) = lv2_atom_sequence_next(iter))
|
||||
|
||||
/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */
|
||||
#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \
|
||||
!lv2_atom_sequence_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_atom_sequence_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Sequence Utilities
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
Clear all events from `sequence`.
|
||||
|
||||
This simply resets the size field, the other fields are left untouched.
|
||||
*/
|
||||
static inline void
|
||||
lv2_atom_sequence_clear(LV2_Atom_Sequence* seq)
|
||||
{
|
||||
seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
|
||||
}
|
||||
|
||||
/**
|
||||
Append an event at the end of `sequence`.
|
||||
|
||||
@param seq Sequence to append to.
|
||||
@param capacity Total capacity of the sequence atom
|
||||
(e.g. as set by the host for sequence output ports).
|
||||
@param event Event to write.
|
||||
|
||||
@return A pointer to the newly written event in `seq`,
|
||||
or NULL on failure (insufficient space).
|
||||
*/
|
||||
static inline LV2_Atom_Event*
|
||||
lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq,
|
||||
uint32_t capacity,
|
||||
const LV2_Atom_Event* event)
|
||||
{
|
||||
const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size;
|
||||
if (capacity - seq->atom.size < total_size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size);
|
||||
memcpy(e, event, total_size);
|
||||
|
||||
seq->atom.size += lv2_atom_pad_size(total_size);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Tuple Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Get an iterator pointing to the first element in `tup`. */
|
||||
static inline LV2_Atom*
|
||||
lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup)
|
||||
{
|
||||
return (LV2_Atom*)(LV2_ATOM_BODY(tup));
|
||||
}
|
||||
|
||||
/** Return true iff `i` has reached the end of `body`. */
|
||||
static inline bool
|
||||
lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i)
|
||||
{
|
||||
return (const uint8_t*)i >= ((const uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return an iterator to the element following `i`. */
|
||||
static inline LV2_Atom*
|
||||
lv2_atom_tuple_next(const LV2_Atom* i)
|
||||
{
|
||||
return (LV2_Atom*)(
|
||||
(const uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size));
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all properties of a Tuple.
|
||||
@param tuple The tuple to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_ATOM_TUPLE_FOREACH(tuple, elem) {
|
||||
// Do something with elem (an LV2_Atom*) here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \
|
||||
for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \
|
||||
!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \
|
||||
(iter) = lv2_atom_tuple_next(iter))
|
||||
|
||||
/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */
|
||||
#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom* (iter) = (LV2_Atom*)(body); \
|
||||
!lv2_atom_tuple_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_atom_tuple_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Object Iterator
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Return a pointer to the first property in `body`. */
|
||||
static inline LV2_Atom_Property_Body*
|
||||
lv2_atom_object_begin(const LV2_Atom_Object_Body* body)
|
||||
{
|
||||
return (LV2_Atom_Property_Body*)(body + 1);
|
||||
}
|
||||
|
||||
/** Return true iff `i` has reached the end of `obj`. */
|
||||
static inline bool
|
||||
lv2_atom_object_is_end(const LV2_Atom_Object_Body* body,
|
||||
uint32_t size,
|
||||
const LV2_Atom_Property_Body* i)
|
||||
{
|
||||
return (const uint8_t*)i >= ((const uint8_t*)body + size);
|
||||
}
|
||||
|
||||
/** Return an iterator to the property following `i`. */
|
||||
static inline LV2_Atom_Property_Body*
|
||||
lv2_atom_object_next(const LV2_Atom_Property_Body* i)
|
||||
{
|
||||
const LV2_Atom* const value = (const LV2_Atom*)(
|
||||
(const uint8_t*)i + 2 * sizeof(uint32_t));
|
||||
return (LV2_Atom_Property_Body*)(
|
||||
(const uint8_t*)i + lv2_atom_pad_size(
|
||||
(uint32_t)sizeof(LV2_Atom_Property_Body) + value->size));
|
||||
}
|
||||
|
||||
/**
|
||||
A macro for iterating over all properties of an Object.
|
||||
@param obj The object to iterate over
|
||||
@param iter The name of the iterator
|
||||
|
||||
This macro is used similarly to a for loop (which it expands to), e.g.:
|
||||
@code
|
||||
LV2_ATOM_OBJECT_FOREACH(object, i) {
|
||||
// Do something with i (an LV2_Atom_Property_Body*) here...
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \
|
||||
for (LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \
|
||||
!lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \
|
||||
(iter) = lv2_atom_object_next(iter))
|
||||
|
||||
/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */
|
||||
#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \
|
||||
for (LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \
|
||||
!lv2_atom_object_is_end(body, size, (iter)); \
|
||||
(iter) = lv2_atom_object_next(iter))
|
||||
|
||||
/**
|
||||
@}
|
||||
@name Object Query
|
||||
@{
|
||||
*/
|
||||
|
||||
/** A single entry in an Object query. */
|
||||
typedef struct {
|
||||
uint32_t key; /**< Key to query (input set by user) */
|
||||
const LV2_Atom** value; /**< Found value (output set by query function) */
|
||||
} LV2_Atom_Object_Query;
|
||||
|
||||
/** Sentinel for lv2_atom_object_query(). */
|
||||
static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL };
|
||||
|
||||
/**
|
||||
Get an object's values for various keys.
|
||||
|
||||
The value pointer of each item in `query` will be set to the location of
|
||||
the corresponding value in `object`. Every value pointer in `query` MUST
|
||||
be initialised to NULL. This function reads `object` in a single linear
|
||||
sweep. By allocating `query` on the stack, objects can be "queried"
|
||||
quickly without allocating any memory. This function is realtime safe.
|
||||
|
||||
This function can only do "flat" queries, it is not smart enough to match
|
||||
variables in nested objects.
|
||||
|
||||
For example:
|
||||
@code
|
||||
const LV2_Atom* name = NULL;
|
||||
const LV2_Atom* age = NULL;
|
||||
LV2_Atom_Object_Query q[] = {
|
||||
{ urids.eg_name, &name },
|
||||
{ urids.eg_age, &age },
|
||||
LV2_ATOM_OBJECT_QUERY_END
|
||||
};
|
||||
lv2_atom_object_query(obj, q);
|
||||
// name and age are now set to the appropriate values in obj, or NULL.
|
||||
@endcode
|
||||
*/
|
||||
static inline int
|
||||
lv2_atom_object_query(const LV2_Atom_Object* object,
|
||||
LV2_Atom_Object_Query* query)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of query keys so we can short-circuit when done */
|
||||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
|
||||
++n_queries;
|
||||
}
|
||||
|
||||
LV2_ATOM_OBJECT_FOREACH(object, prop) {
|
||||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) {
|
||||
if (q->key == prop->key && !*q->value) {
|
||||
*q->value = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
Body only version of lv2_atom_object_get().
|
||||
*/
|
||||
static inline int
|
||||
lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of keys so we can short-circuit when done */
|
||||
va_list args;
|
||||
va_start(args, body);
|
||||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
|
||||
if (!va_arg(args, const LV2_Atom**)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
LV2_ATOM_OBJECT_BODY_FOREACH(body, size, prop) {
|
||||
va_start(args, body);
|
||||
for (int i = 0; i < n_queries; ++i) {
|
||||
uint32_t qkey = va_arg(args, uint32_t);
|
||||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
|
||||
if (qkey == prop->key && !*qval) {
|
||||
*qval = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
Variable argument version of lv2_atom_object_query().
|
||||
|
||||
This is nicer-looking in code, but a bit more error-prone since it is not
|
||||
type safe and the argument list must be terminated.
|
||||
|
||||
The arguments should be a series of uint32_t key and const LV2_Atom** value
|
||||
pairs, terminated by a zero key. The value pointers MUST be initialized to
|
||||
NULL. For example:
|
||||
|
||||
@code
|
||||
const LV2_Atom* name = NULL;
|
||||
const LV2_Atom* age = NULL;
|
||||
lv2_atom_object_get(obj,
|
||||
uris.name_key, &name,
|
||||
uris.age_key, &age,
|
||||
0);
|
||||
@endcode
|
||||
*/
|
||||
static inline int
|
||||
lv2_atom_object_get(const LV2_Atom_Object* object, ...)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of keys so we can short-circuit when done */
|
||||
va_list args;
|
||||
va_start(args, object);
|
||||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
|
||||
if (!va_arg(args, const LV2_Atom**)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
LV2_ATOM_OBJECT_FOREACH(object, prop) {
|
||||
va_start(args, object);
|
||||
for (int i = 0; i < n_queries; ++i) {
|
||||
uint32_t qkey = va_arg(args, uint32_t);
|
||||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
|
||||
if (qkey == prop->key && !*qval) {
|
||||
*qval = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
Variable argument version of lv2_atom_object_query() with types.
|
||||
|
||||
This is like lv2_atom_object_get(), but each entry has an additional
|
||||
parameter to specify the required type. Only atoms with a matching type
|
||||
will be selected.
|
||||
|
||||
The arguments should be a series of uint32_t key, const LV2_Atom**, uint32_t
|
||||
type triples, terminated by a zero key. The value pointers MUST be
|
||||
initialized to NULL. For example:
|
||||
|
||||
@code
|
||||
const LV2_Atom_String* name = NULL;
|
||||
const LV2_Atom_Int* age = NULL;
|
||||
lv2_atom_object_get(obj,
|
||||
uris.name_key, &name, uris.atom_String,
|
||||
uris.age_key, &age, uris.atom_Int
|
||||
0);
|
||||
@endcode
|
||||
*/
|
||||
static inline int
|
||||
lv2_atom_object_get_typed(const LV2_Atom_Object* object, ...)
|
||||
{
|
||||
int matches = 0;
|
||||
int n_queries = 0;
|
||||
|
||||
/* Count number of keys so we can short-circuit when done */
|
||||
va_list args;
|
||||
va_start(args, object);
|
||||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) {
|
||||
if (!va_arg(args, const LV2_Atom**) ||
|
||||
!va_arg(args, uint32_t)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
LV2_ATOM_OBJECT_FOREACH(object, prop) {
|
||||
va_start(args, object);
|
||||
for (int i = 0; i < n_queries; ++i) {
|
||||
const uint32_t qkey = va_arg(args, uint32_t);
|
||||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**);
|
||||
const uint32_t qtype = va_arg(args, uint32_t);
|
||||
if (!*qval && qkey == prop->key && qtype == prop->value.type) {
|
||||
*qval = &prop->value;
|
||||
if (++matches == n_queries) {
|
||||
return matches;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
@}
|
||||
@}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_ATOM_UTIL_H */
|
||||
44
lv2/lv2/buf-size/buf-size.h
Normal file
44
lv2/lv2/buf-size/buf-size.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Copyright 2007-2016 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LV2_BUF_SIZE_H
|
||||
#define LV2_BUF_SIZE_H
|
||||
|
||||
/**
|
||||
@defgroup buf-size Buffer Size
|
||||
|
||||
Access to, and restrictions on, buffer sizes; see
|
||||
<http://lv2plug.in/ns/ext/buf-size> for details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size" ///< http://lv2plug.in/ns/ext/buf-size
|
||||
#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#" ///< http://lv2plug.in/ns/ext/buf-size#
|
||||
|
||||
#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#boundedBlockLength
|
||||
#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#fixedBlockLength
|
||||
#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#maxBlockLength
|
||||
#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#minBlockLength
|
||||
#define LV2_BUF_SIZE__nominalBlockLength LV2_BUF_SIZE_PREFIX "nominalBlockLength" ///< http://lv2plug.in/ns/ext/buf-size#nominalBlockLength
|
||||
#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength" ///< http://lv2plug.in/ns/ext/buf-size#powerOf2BlockLength
|
||||
#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize" ///< http://lv2plug.in/ns/ext/buf-size#sequenceSize
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
#endif /* LV2_BUF_SIZE_H */
|
||||
129
lv2/lv2/buf-size/buf-size.ttl
Normal file
129
lv2/lv2/buf-size/buf-size.ttl
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
@prefix bufsz: <http://lv2plug.in/ns/ext/buf-size#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/buf-size>
|
||||
a lv2:Specification ;
|
||||
rdfs:seeAlso <buf-size.h> ,
|
||||
<lv2-buf-size.doap.ttl> ;
|
||||
lv2:documentation """
|
||||
<p>This extension defines a facility for plugins to get information about the
|
||||
block length (the sample_count parameter of LV2_Descriptor::run) and
|
||||
port buffer sizes, as well as several features which can be used to restrict
|
||||
the block length.</p>
|
||||
|
||||
<p>This extension defines features and properties but has no special purpose
|
||||
API of its own. The host provides all the relevant information to the plugin
|
||||
as <a href="options.html#options">options</a>.</p>
|
||||
|
||||
<p>To require restrictions on the block length, plugins can require additional
|
||||
features: bufsz:boundedBlockLength, bufsz:powerOf2BlockLength, and
|
||||
bufsz:fixedBlockLength. These features are data-only, that is they merely
|
||||
indicate a restriction and do not carry any data or API.</p>
|
||||
""" .
|
||||
|
||||
bufsz:boundedBlockLength
|
||||
a lv2:Feature ;
|
||||
lv2:documentation """
|
||||
<p>A feature that indicates the host will provide both the bufsz:minBlockLength
|
||||
and bufsz:maxBlockLength options to the plugin. Plugins that copy data from
|
||||
audio inputs can require this feature to ensure they know how much space is
|
||||
required for auxiliary buffers. Note the minimum may be zero, this feature is
|
||||
mainly useful to ensure a maximum is available.</p>
|
||||
|
||||
<p>All hosts SHOULD support this feature, since it is simple to support and
|
||||
necessary for any plugins that may need to copy the input.</p>
|
||||
""" .
|
||||
|
||||
bufsz:fixedBlockLength
|
||||
a lv2:Feature ;
|
||||
lv2:documentation """
|
||||
<p>A feature that indicates the host will always call LV2_Descriptor::run()
|
||||
with the same value for sample_count. This length MUST be provided as the
|
||||
value of both the bufsz:minBlockLength and bufsz:maxBlockLength options.</p>
|
||||
|
||||
<p>Note that requiring this feature may severely limit the number of hosts
|
||||
capable of running the plugin.</p>
|
||||
""" .
|
||||
|
||||
bufsz:powerOf2BlockLength
|
||||
a lv2:Feature ;
|
||||
lv2:documentation """
|
||||
<p>A feature that indicates the host will always call LV2_Descriptor::run()
|
||||
with a power of two sample_count. Note that this feature does not guarantee
|
||||
the value is the same each call, to guarantee a fixed power of two block length
|
||||
plugins must require both this feature and bufsz:fixedBlockLength.</p>
|
||||
|
||||
<p>Note that requiring this feature may severely limit the number of hosts
|
||||
capable of running the plugin.</p>
|
||||
""" .
|
||||
|
||||
bufsz:coarseBlockLength
|
||||
a lv2:Feature ;
|
||||
rdfs:label "coarse block length" ;
|
||||
lv2:documentation """
|
||||
<p>A feature that indicates the plugin prefers coarse, regular block lengths.
|
||||
For example, plugins that do not implement sample-accurate control use this
|
||||
feature to indicate that the host should not split the run cycle because
|
||||
controls have changed.</p>
|
||||
|
||||
<p>Note that this feature is merely a hint, and does not guarantee a fixed
|
||||
block length. The run cycle may be split for other reasons, and the blocksize
|
||||
itself may change anytime.</p>
|
||||
""" .
|
||||
|
||||
bufsz:maxBlockLength
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
opts:Option ;
|
||||
rdfs:label "maximum block length" ;
|
||||
rdfs:range xsd:nonNegativeInteger ;
|
||||
lv2:documentation """
|
||||
<p>The maximum block length the host will ever request the plugin to process at
|
||||
once, that is, the maximum <code>sample_count</code> parameter that will ever
|
||||
be passed to LV2_Descriptor::run().</p>
|
||||
""" .
|
||||
|
||||
bufsz:minBlockLength
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
opts:Option ;
|
||||
rdfs:label "minimum block length" ;
|
||||
rdfs:range xsd:nonNegativeInteger ;
|
||||
lv2:documentation """
|
||||
<p>The minimum block length the host will ever request the plugin to process at
|
||||
once, that is, the minimum <code>sample_count</code> parameter that will ever
|
||||
be passed to LV2_Descriptor::run().</p>
|
||||
""" .
|
||||
|
||||
bufsz:nominalBlockLength
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
opts:Option ;
|
||||
rdfs:label "nominal block length" ;
|
||||
rdfs:range xsd:nonNegativeInteger ;
|
||||
lv2:documentation """
|
||||
<p>The typical block length the host will request the plugin to process at
|
||||
once, that is, the typical <code>sample_count</code> parameter that will
|
||||
be passed to LV2_Descriptor::run(). This will usually be equivalent, or close
|
||||
to, the maximum block length, but there are no strong guarantees about this
|
||||
value whatsoever. Plugins may use this length for optimization purposes, but
|
||||
MUST NOT assume the host will always process blocks of this length. In
|
||||
particular, the host MAY process longer blocks.</p>
|
||||
""" .
|
||||
|
||||
bufsz:sequenceSize
|
||||
a rdf:Property ,
|
||||
owl:DatatypeProperty ,
|
||||
opts:Option ;
|
||||
rdfs:label "sequence size" ;
|
||||
rdfs:range xsd:nonNegativeInteger ;
|
||||
lv2:documentation """
|
||||
<p>The maximum size of a sequence, in bytes. This should be provided as an
|
||||
option by hosts that support event ports (including but not limited to MIDI),
|
||||
so plugins have the ability to allocate auxiliary buffers large enough to copy
|
||||
the input.</p> """ .
|
||||
44
lv2/lv2/buf-size/lv2-buf-size.doap.ttl
Normal file
44
lv2/lv2/buf-size/lv2-buf-size.doap.ttl
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/buf-size>
|
||||
a doap:Project ;
|
||||
doap:name "LV2 Buf Size" ;
|
||||
doap:shortdesc "Access to, and restrictions on, buffer sizes." ;
|
||||
doap:created "2012-08-07" ;
|
||||
doap:developer <http://drobilla.net/drobilla#me> ;
|
||||
doap:release [
|
||||
doap:revision "1.4" ;
|
||||
doap:created "2015-09-18" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add bufsz:nominalBlockLength option."
|
||||
] , [
|
||||
rdfs:label "Add bufsz:coarseBlockLength feature."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.2" ;
|
||||
doap:created "2012-12-21" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix typo in bufsz:sequenceSize label."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.0" ;
|
||||
doap:created "2012-10-14" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release."
|
||||
]
|
||||
]
|
||||
] .
|
||||
9
lv2/lv2/buf-size/manifest.ttl
Normal file
9
lv2/lv2/buf-size/manifest.ttl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/buf-size>
|
||||
a lv2:Specification ;
|
||||
lv2:minorVersion 1 ;
|
||||
lv2:microVersion 4 ;
|
||||
rdfs:seeAlso <buf-size.ttl> .
|
||||
|
||||
58
lv2/lv2/core/attributes.h
Normal file
58
lv2/lv2/core/attributes.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright 2018 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LV2_CORE_ATTRIBUTES_H
|
||||
#define LV2_CORE_ATTRIBUTES_H
|
||||
|
||||
/**
|
||||
@defgroup attributes Attributes
|
||||
|
||||
Macros for source code attributes.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
|
||||
#define LV2_DEPRECATED __attribute__((__deprecated__))
|
||||
#else
|
||||
#define LV2_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define LV2_DISABLE_DEPRECATION_WARNINGS \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#define LV2_DISABLE_DEPRECATION_WARNINGS \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#else
|
||||
#define LV2_DISABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
#define LV2_RESTORE_WARNINGS _Pragma("clang diagnostic pop")
|
||||
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
|
||||
#define LV2_RESTORE_WARNINGS _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define LV2_RESTORE_WARNINGS
|
||||
#endif
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
|
||||
#endif /* LV2_CORE_ATTRIBUTES_H */
|
||||
474
lv2/lv2/core/lv2.h
Normal file
474
lv2/lv2/core/lv2.h
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
LV2 - An audio plugin interface specification.
|
||||
Copyright 2006-2012 Steve Harris, David Robillard.
|
||||
|
||||
Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse,
|
||||
Paul Barton-Davis, Stefan Westerfeld.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup lv2core LV2 Core
|
||||
|
||||
Core LV2 specification, see <http://lv2plug.in/ns/lv2core> for details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_H_INCLUDED
|
||||
#define LV2_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" ///< http://lv2plug.in/ns/lv2core
|
||||
#define LV2_CORE_PREFIX LV2_CORE_URI "#" ///< http://lv2plug.in/ns/lv2core#
|
||||
|
||||
#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" ///< http://lv2plug.in/ns/lv2core#AllpassPlugin
|
||||
#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" ///< http://lv2plug.in/ns/lv2core#AmplifierPlugin
|
||||
#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" ///< http://lv2plug.in/ns/lv2core#AnalyserPlugin
|
||||
#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" ///< http://lv2plug.in/ns/lv2core#AudioPort
|
||||
#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" ///< http://lv2plug.in/ns/lv2core#BandpassPlugin
|
||||
#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort" ///< http://lv2plug.in/ns/lv2core#CVPort
|
||||
#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" ///< http://lv2plug.in/ns/lv2core#ChorusPlugin
|
||||
#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" ///< http://lv2plug.in/ns/lv2core#CombPlugin
|
||||
#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" ///< http://lv2plug.in/ns/lv2core#CompressorPlugin
|
||||
#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" ///< http://lv2plug.in/ns/lv2core#ConstantPlugin
|
||||
#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" ///< http://lv2plug.in/ns/lv2core#ControlPort
|
||||
#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" ///< http://lv2plug.in/ns/lv2core#ConverterPlugin
|
||||
#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" ///< http://lv2plug.in/ns/lv2core#DelayPlugin
|
||||
#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" ///< http://lv2plug.in/ns/lv2core#DistortionPlugin
|
||||
#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" ///< http://lv2plug.in/ns/lv2core#DynamicsPlugin
|
||||
#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" ///< http://lv2plug.in/ns/lv2core#EQPlugin
|
||||
#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin" ///< http://lv2plug.in/ns/lv2core#EnvelopePlugin
|
||||
#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" ///< http://lv2plug.in/ns/lv2core#ExpanderPlugin
|
||||
#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" ///< http://lv2plug.in/ns/lv2core#ExtensionData
|
||||
#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" ///< http://lv2plug.in/ns/lv2core#Feature
|
||||
#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" ///< http://lv2plug.in/ns/lv2core#FilterPlugin
|
||||
#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" ///< http://lv2plug.in/ns/lv2core#FlangerPlugin
|
||||
#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" ///< http://lv2plug.in/ns/lv2core#FunctionPlugin
|
||||
#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" ///< http://lv2plug.in/ns/lv2core#GatePlugin
|
||||
#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" ///< http://lv2plug.in/ns/lv2core#GeneratorPlugin
|
||||
#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" ///< http://lv2plug.in/ns/lv2core#HighpassPlugin
|
||||
#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" ///< http://lv2plug.in/ns/lv2core#InputPort
|
||||
#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" ///< http://lv2plug.in/ns/lv2core#InstrumentPlugin
|
||||
#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" ///< http://lv2plug.in/ns/lv2core#LimiterPlugin
|
||||
#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" ///< http://lv2plug.in/ns/lv2core#LowpassPlugin
|
||||
#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" ///< http://lv2plug.in/ns/lv2core#MixerPlugin
|
||||
#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" ///< http://lv2plug.in/ns/lv2core#ModulatorPlugin
|
||||
#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" ///< http://lv2plug.in/ns/lv2core#MultiEQPlugin
|
||||
#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" ///< http://lv2plug.in/ns/lv2core#OscillatorPlugin
|
||||
#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" ///< http://lv2plug.in/ns/lv2core#OutputPort
|
||||
#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" ///< http://lv2plug.in/ns/lv2core#ParaEQPlugin
|
||||
#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" ///< http://lv2plug.in/ns/lv2core#PhaserPlugin
|
||||
#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" ///< http://lv2plug.in/ns/lv2core#PitchPlugin
|
||||
#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" ///< http://lv2plug.in/ns/lv2core#Plugin
|
||||
#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" ///< http://lv2plug.in/ns/lv2core#PluginBase
|
||||
#define LV2_CORE__Point LV2_CORE_PREFIX "Point" ///< http://lv2plug.in/ns/lv2core#Point
|
||||
#define LV2_CORE__Port LV2_CORE_PREFIX "Port" ///< http://lv2plug.in/ns/lv2core#Port
|
||||
#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" ///< http://lv2plug.in/ns/lv2core#PortProperty
|
||||
#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" ///< http://lv2plug.in/ns/lv2core#Resource
|
||||
#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" ///< http://lv2plug.in/ns/lv2core#ReverbPlugin
|
||||
#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" ///< http://lv2plug.in/ns/lv2core#ScalePoint
|
||||
#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" ///< http://lv2plug.in/ns/lv2core#SimulatorPlugin
|
||||
#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" ///< http://lv2plug.in/ns/lv2core#SpatialPlugin
|
||||
#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" ///< http://lv2plug.in/ns/lv2core#Specification
|
||||
#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" ///< http://lv2plug.in/ns/lv2core#SpectralPlugin
|
||||
#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" ///< http://lv2plug.in/ns/lv2core#UtilityPlugin
|
||||
#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" ///< http://lv2plug.in/ns/lv2core#WaveshaperPlugin
|
||||
#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" ///< http://lv2plug.in/ns/lv2core#appliesTo
|
||||
#define LV2_CORE__binary LV2_CORE_PREFIX "binary" ///< http://lv2plug.in/ns/lv2core#binary
|
||||
#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" ///< http://lv2plug.in/ns/lv2core#connectionOptional
|
||||
#define LV2_CORE__control LV2_CORE_PREFIX "control" ///< http://lv2plug.in/ns/lv2core#control
|
||||
#define LV2_CORE__default LV2_CORE_PREFIX "default" ///< http://lv2plug.in/ns/lv2core#default
|
||||
#define LV2_CORE__designation LV2_CORE_PREFIX "designation" ///< http://lv2plug.in/ns/lv2core#designation
|
||||
#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" ///< http://lv2plug.in/ns/lv2core#documentation
|
||||
#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" ///< http://lv2plug.in/ns/lv2core#enumeration
|
||||
#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" ///< http://lv2plug.in/ns/lv2core#extensionData
|
||||
#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" ///< http://lv2plug.in/ns/lv2core#freeWheeling
|
||||
#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" ///< http://lv2plug.in/ns/lv2core#hardRTCapable
|
||||
#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" ///< http://lv2plug.in/ns/lv2core#inPlaceBroken
|
||||
#define LV2_CORE__index LV2_CORE_PREFIX "index" ///< http://lv2plug.in/ns/lv2core#index
|
||||
#define LV2_CORE__integer LV2_CORE_PREFIX "integer" ///< http://lv2plug.in/ns/lv2core#integer
|
||||
#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" ///< http://lv2plug.in/ns/lv2core#isLive
|
||||
#define LV2_CORE__latency LV2_CORE_PREFIX "latency" ///< http://lv2plug.in/ns/lv2core#latency
|
||||
#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" ///< http://lv2plug.in/ns/lv2core#maximum
|
||||
#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" ///< http://lv2plug.in/ns/lv2core#microVersion
|
||||
#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" ///< http://lv2plug.in/ns/lv2core#minimum
|
||||
#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" ///< http://lv2plug.in/ns/lv2core#minorVersion
|
||||
#define LV2_CORE__name LV2_CORE_PREFIX "name" ///< http://lv2plug.in/ns/lv2core#name
|
||||
#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" ///< http://lv2plug.in/ns/lv2core#optionalFeature
|
||||
#define LV2_CORE__port LV2_CORE_PREFIX "port" ///< http://lv2plug.in/ns/lv2core#port
|
||||
#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" ///< http://lv2plug.in/ns/lv2core#portProperty
|
||||
#define LV2_CORE__project LV2_CORE_PREFIX "project" ///< http://lv2plug.in/ns/lv2core#project
|
||||
#define LV2_CORE__prototype LV2_CORE_PREFIX "prototype" ///< http://lv2plug.in/ns/lv2core#prototype
|
||||
#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" ///< http://lv2plug.in/ns/lv2core#reportsLatency
|
||||
#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" ///< http://lv2plug.in/ns/lv2core#requiredFeature
|
||||
#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" ///< http://lv2plug.in/ns/lv2core#sampleRate
|
||||
#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" ///< http://lv2plug.in/ns/lv2core#scalePoint
|
||||
#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" ///< http://lv2plug.in/ns/lv2core#symbol
|
||||
#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" ///< http://lv2plug.in/ns/lv2core#toggled
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Plugin Instance Handle.
|
||||
|
||||
This is a handle for one particular instance of a plugin. It is valid to
|
||||
compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to
|
||||
interpret it.
|
||||
*/
|
||||
typedef void * LV2_Handle;
|
||||
|
||||
/**
|
||||
Feature.
|
||||
|
||||
Features allow hosts to make additional functionality available to plugins
|
||||
without requiring modification to the LV2 API. Extensions may define new
|
||||
features and specify the `URI` and `data` to be used if necessary.
|
||||
Some features, such as lv2:isLive, do not require the host to pass data.
|
||||
*/
|
||||
typedef struct _LV2_Feature {
|
||||
/**
|
||||
A globally unique, case-sensitive identifier (URI) for this feature.
|
||||
|
||||
This MUST be a valid URI string as defined by RFC 3986.
|
||||
*/
|
||||
const char * URI;
|
||||
|
||||
/**
|
||||
Pointer to arbitrary data.
|
||||
|
||||
The format of this data is defined by the extension which describes the
|
||||
feature with the given `URI`.
|
||||
*/
|
||||
void * data;
|
||||
} LV2_Feature;
|
||||
|
||||
/**
|
||||
Plugin Descriptor.
|
||||
|
||||
This structure provides the core functions necessary to instantiate and use
|
||||
a plugin.
|
||||
*/
|
||||
typedef struct _LV2_Descriptor {
|
||||
/**
|
||||
A globally unique, case-sensitive identifier for this plugin.
|
||||
|
||||
This MUST be a valid URI string as defined by RFC 3986. All plugins with
|
||||
the same URI MUST be compatible to some degree, see
|
||||
http://lv2plug.in/ns/lv2core for details.
|
||||
*/
|
||||
const char * URI;
|
||||
|
||||
/**
|
||||
Instantiate the plugin.
|
||||
|
||||
Note that instance initialisation should generally occur in activate()
|
||||
rather than here. If a host calls instantiate(), it MUST call cleanup()
|
||||
at some point in the future.
|
||||
|
||||
@param descriptor Descriptor of the plugin to instantiate.
|
||||
|
||||
@param sample_rate Sample rate, in Hz, for the new plugin instance.
|
||||
|
||||
@param bundle_path Path to the LV2 bundle which contains this plugin
|
||||
binary. It MUST include the trailing directory separator (e.g. '/') so
|
||||
that simply appending a filename will yield the path to that file in the
|
||||
bundle.
|
||||
|
||||
@param features A NULL terminated array of LV2_Feature structs which
|
||||
represent the features the host supports. Plugins may refuse to
|
||||
instantiate if required features are not found here. However, hosts MUST
|
||||
NOT use this as a discovery mechanism: instead, use the RDF data to
|
||||
determine which features are required and do not attempt to instantiate
|
||||
unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host
|
||||
that supports no features MUST pass a single element array containing
|
||||
NULL.
|
||||
|
||||
@return A handle for the new plugin instance, or NULL if instantiation
|
||||
has failed.
|
||||
*/
|
||||
LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor,
|
||||
double sample_rate,
|
||||
const char * bundle_path,
|
||||
const LV2_Feature *const * features);
|
||||
|
||||
/**
|
||||
Connect a port on a plugin instance to a memory location.
|
||||
|
||||
Plugin writers should be aware that the host may elect to use the same
|
||||
buffer for more than one port and even use the same buffer for both
|
||||
input and output (see lv2:inPlaceBroken in lv2.ttl).
|
||||
|
||||
If the plugin has the feature lv2:hardRTCapable then there are various
|
||||
things that the plugin MUST NOT do within the connect_port() function;
|
||||
see lv2core.ttl for details.
|
||||
|
||||
connect_port() MUST be called at least once for each port before run()
|
||||
is called, unless that port is lv2:connectionOptional. The plugin must
|
||||
pay careful attention to the block size passed to run() since the block
|
||||
allocated may only just be large enough to contain the data, and is not
|
||||
guaranteed to remain constant between run() calls.
|
||||
|
||||
connect_port() may be called more than once for a plugin instance to
|
||||
allow the host to change the buffers that the plugin is reading or
|
||||
writing. These calls may be made before or after activate() or
|
||||
deactivate() calls.
|
||||
|
||||
@param instance Plugin instance containing the port.
|
||||
|
||||
@param port Index of the port to connect. The host MUST NOT try to
|
||||
connect a port index that is not defined in the plugin's RDF data. If
|
||||
it does, the plugin's behaviour is undefined (a crash is likely).
|
||||
|
||||
@param data_location Pointer to data of the type defined by the port
|
||||
type in the plugin's RDF data (e.g. an array of float for an
|
||||
lv2:AudioPort). This pointer must be stored by the plugin instance and
|
||||
used to read/write data when run() is called. Data present at the time
|
||||
of the connect_port() call MUST NOT be considered meaningful.
|
||||
*/
|
||||
void (*connect_port)(LV2_Handle instance,
|
||||
uint32_t port,
|
||||
void * data_location);
|
||||
|
||||
/**
|
||||
Initialise a plugin instance and activate it for use.
|
||||
|
||||
This is separated from instantiate() to aid real-time support and so
|
||||
that hosts can reinitialise a plugin instance by calling deactivate()
|
||||
and then activate(). In this case the plugin instance MUST reset all
|
||||
state information dependent on the history of the plugin instance except
|
||||
for any data locations provided by connect_port(). If there is nothing
|
||||
for activate() to do then this field may be NULL.
|
||||
|
||||
When present, hosts MUST call this function once before run() is called
|
||||
for the first time. This call SHOULD be made as close to the run() call
|
||||
as possible and indicates to real-time plugins that they are now live,
|
||||
however plugins MUST NOT rely on a prompt call to run() after
|
||||
activate().
|
||||
|
||||
The host MUST NOT call activate() again until deactivate() has been
|
||||
called first. If a host calls activate(), it MUST call deactivate() at
|
||||
some point in the future. Note that connect_port() may be called before
|
||||
or after activate().
|
||||
*/
|
||||
void (*activate)(LV2_Handle instance);
|
||||
|
||||
/**
|
||||
Run a plugin instance for a block.
|
||||
|
||||
Note that if an activate() function exists then it must be called before
|
||||
run(). If deactivate() is called for a plugin instance then run() may
|
||||
not be called until activate() has been called again.
|
||||
|
||||
If the plugin has the feature lv2:hardRTCapable then there are various
|
||||
things that the plugin MUST NOT do within the run() function (see
|
||||
lv2core.ttl for details).
|
||||
|
||||
As a special case, when `sample_count` is 0, the plugin should update
|
||||
any output ports that represent a single instant in time (e.g. control
|
||||
ports, but not audio ports). This is particularly useful for latent
|
||||
plugins, which should update their latency output port so hosts can
|
||||
pre-roll plugins to compute latency. Plugins MUST NOT crash when
|
||||
`sample_count` is 0.
|
||||
|
||||
@param instance Instance to be run.
|
||||
|
||||
@param sample_count The block size (in samples) for which the plugin
|
||||
instance must run.
|
||||
*/
|
||||
void (*run)(LV2_Handle instance,
|
||||
uint32_t sample_count);
|
||||
|
||||
/**
|
||||
Deactivate a plugin instance (counterpart to activate()).
|
||||
|
||||
Hosts MUST deactivate all activated instances after they have been run()
|
||||
for the last time. This call SHOULD be made as close to the last run()
|
||||
call as possible and indicates to real-time plugins that they are no
|
||||
longer live, however plugins MUST NOT rely on prompt deactivation. If
|
||||
there is nothing for deactivate() to do then this field may be NULL
|
||||
|
||||
Deactivation is not similar to pausing since the plugin instance will be
|
||||
reinitialised by activate(). However, deactivate() itself MUST NOT fully
|
||||
reset plugin state. For example, the host may deactivate a plugin, then
|
||||
store its state (using some extension to do so).
|
||||
|
||||
Hosts MUST NOT call deactivate() unless activate() was previously
|
||||
called. Note that connect_port() may be called before or after
|
||||
deactivate().
|
||||
*/
|
||||
void (*deactivate)(LV2_Handle instance);
|
||||
|
||||
/**
|
||||
Clean up a plugin instance (counterpart to instantiate()).
|
||||
|
||||
Once an instance of a plugin has been finished with it must be deleted
|
||||
using this function. The instance handle passed ceases to be valid after
|
||||
this call.
|
||||
|
||||
If activate() was called for a plugin instance then a corresponding call
|
||||
to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT
|
||||
call cleanup() unless instantiate() was previously called.
|
||||
*/
|
||||
void (*cleanup)(LV2_Handle instance);
|
||||
|
||||
/**
|
||||
Return additional plugin data defined by some extenion.
|
||||
|
||||
A typical use of this facility is to return a struct containing function
|
||||
pointers to extend the LV2_Descriptor API.
|
||||
|
||||
The actual type and meaning of the returned object MUST be specified
|
||||
precisely by the extension. This function MUST return NULL for any
|
||||
unsupported URI. If a plugin does not support any extension data, this
|
||||
field may be NULL.
|
||||
|
||||
The host is never responsible for freeing the returned value.
|
||||
*/
|
||||
const void * (*extension_data)(const char * uri);
|
||||
} LV2_Descriptor;
|
||||
|
||||
/**
|
||||
Helper macro needed for LV2_SYMBOL_EXPORT when using C++.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
# define LV2_SYMBOL_EXTERN extern "C"
|
||||
#else
|
||||
# define LV2_SYMBOL_EXTERN
|
||||
#endif
|
||||
|
||||
/**
|
||||
Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded
|
||||
by the host as a symbol from the dynamic library.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __declspec(dllexport)
|
||||
#else
|
||||
# define LV2_SYMBOL_EXPORT LV2_SYMBOL_EXTERN __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
/**
|
||||
Prototype for plugin accessor function.
|
||||
|
||||
Plugins are discovered by hosts using RDF data (not by loading libraries).
|
||||
See http://lv2plug.in for details on the discovery process, though most
|
||||
hosts should use an existing library to implement this functionality.
|
||||
|
||||
This is the simple plugin discovery API, suitable for most statically
|
||||
defined plugins. Advanced plugins that need access to their bundle during
|
||||
discovery can use lv2_lib_descriptor() instead. Plugin libraries MUST
|
||||
include a function called "lv2_descriptor" or "lv2_lib_descriptor" with
|
||||
C-style linkage, but SHOULD provide "lv2_descriptor" wherever possible.
|
||||
|
||||
When it is time to load a plugin (designated by its URI), the host loads the
|
||||
plugin's library, gets the lv2_descriptor() function from it, and uses this
|
||||
function to find the LV2_Descriptor for the desired plugin. Plugins are
|
||||
accessed by index using values from 0 upwards. This function MUST return
|
||||
NULL for out of range indices, so the host can enumerate plugins by
|
||||
increasing `index` until NULL is returned.
|
||||
|
||||
Note that `index` has no meaning, hosts MUST NOT depend on it remaining
|
||||
consistent between loads of the plugin library.
|
||||
*/
|
||||
LV2_SYMBOL_EXPORT
|
||||
const LV2_Descriptor * lv2_descriptor(uint32_t index);
|
||||
|
||||
/**
|
||||
Type of the lv2_descriptor() function in a library (old discovery API).
|
||||
*/
|
||||
typedef const LV2_Descriptor *
|
||||
(*LV2_Descriptor_Function)(uint32_t index);
|
||||
|
||||
/**
|
||||
Handle for a library descriptor.
|
||||
*/
|
||||
typedef void* LV2_Lib_Handle;
|
||||
|
||||
/**
|
||||
Descriptor for a plugin library.
|
||||
|
||||
To access a plugin library, the host creates an LV2_Lib_Descriptor via the
|
||||
lv2_lib_descriptor() function in the shared object.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
Opaque library data which must be passed as the first parameter to all
|
||||
the methods of this struct.
|
||||
*/
|
||||
LV2_Lib_Handle handle;
|
||||
|
||||
/**
|
||||
The total size of this struct. This allows for this struct to be
|
||||
expanded in the future if necessary. This MUST be set by the library to
|
||||
sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this
|
||||
struct beyond get_plugin() unless this field indicates they are present.
|
||||
*/
|
||||
uint32_t size;
|
||||
|
||||
/**
|
||||
Destroy this library descriptor and free all related resources.
|
||||
*/
|
||||
void (*cleanup)(LV2_Lib_Handle handle);
|
||||
|
||||
/**
|
||||
Plugin accessor.
|
||||
|
||||
Plugins are accessed by index using values from 0 upwards. Out of range
|
||||
indices MUST result in this function returning NULL, so the host can
|
||||
enumerate plugins by increasing `index` until NULL is returned.
|
||||
*/
|
||||
const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle,
|
||||
uint32_t index);
|
||||
} LV2_Lib_Descriptor;
|
||||
|
||||
/**
|
||||
Prototype for library accessor function.
|
||||
|
||||
This is the more advanced discovery API, which allows plugin libraries to
|
||||
access their bundles during discovery, which makes it possible for plugins to
|
||||
be dynamically defined by files in their bundle. This API also has an
|
||||
explicit cleanup function, removing any need for non-portable shared library
|
||||
destructors. Simple plugins that do not require these features may use
|
||||
lv2_descriptor() instead.
|
||||
|
||||
This is the entry point for a plugin library. Hosts load this symbol from
|
||||
the library and call this function to obtain a library descriptor which can
|
||||
be used to access all the contained plugins. The returned object must not
|
||||
be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded
|
||||
from that library have been destroyed.
|
||||
*/
|
||||
LV2_SYMBOL_EXPORT
|
||||
const LV2_Lib_Descriptor *
|
||||
lv2_lib_descriptor(const char * bundle_path,
|
||||
const LV2_Feature *const * features);
|
||||
|
||||
/**
|
||||
Type of the lv2_lib_descriptor() function in an LV2 library.
|
||||
*/
|
||||
typedef const LV2_Lib_Descriptor *
|
||||
(*LV2_Lib_Descriptor_Function)(const char * bundle_path,
|
||||
const LV2_Feature *const * features);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LV2_H_INCLUDED */
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
103
lv2/lv2/core/lv2_util.h
Normal file
103
lv2/lv2/core/lv2_util.h
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright 2016 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup util Utilities
|
||||
@ingroup lv2core
|
||||
@{
|
||||
*/
|
||||
|
||||
#include "lv2/core/lv2.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Return the data for a feature in a features array.
|
||||
|
||||
If the feature is not found, NULL is returned. Note that this function is
|
||||
only useful for features with data, and can not detect features that are
|
||||
present but have NULL data.
|
||||
*/
|
||||
static inline void*
|
||||
lv2_features_data(const LV2_Feature*const* features,
|
||||
const char* const uri)
|
||||
{
|
||||
if (features) {
|
||||
for (const LV2_Feature*const* f = features; *f; ++f) {
|
||||
if (!strcmp(uri, (*f)->URI)) {
|
||||
return (*f)->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Query a features array.
|
||||
|
||||
This function allows getting several features in one call, and detect
|
||||
missing required features, with the same caveat of lv2_features_data().
|
||||
|
||||
The arguments should be a series of const char* uri, void** data, bool
|
||||
required, terminated by a NULL URI. The data pointers MUST be initialized
|
||||
to NULL. For example:
|
||||
|
||||
@code
|
||||
LV2_URID_Log* log = NULL;
|
||||
LV2_URID_Map* map = NULL;
|
||||
const char* missing = lv2_features_query(
|
||||
features,
|
||||
LV2_LOG__log, &log, false,
|
||||
LV2_URID__map, &map, true,
|
||||
NULL);
|
||||
@endcode
|
||||
|
||||
@return NULL on success, otherwise the URI of this missing feature.
|
||||
*/
|
||||
static inline const char*
|
||||
lv2_features_query(const LV2_Feature* const* features, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, features);
|
||||
|
||||
const char* uri = NULL;
|
||||
while ((uri = va_arg(args, const char*))) {
|
||||
void** data = va_arg(args, void**);
|
||||
bool required = va_arg(args, int);
|
||||
|
||||
*data = lv2_features_data(features, uri);
|
||||
if (required && !*data) {
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
/**
|
||||
@}
|
||||
@}
|
||||
*/
|
||||
204
lv2/lv2/core/lv2core.doap.ttl
Normal file
204
lv2/lv2/core/lv2core.doap.ttl
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/lv2core>
|
||||
a doap:Project ;
|
||||
rdfs:seeAlso <meta.ttl> ;
|
||||
doap:license <http://opensource.org/licenses/isc> ;
|
||||
doap:name "LV2" ;
|
||||
doap:homepage <http://lv2plug.in> ;
|
||||
doap:created "2004-04-21" ;
|
||||
doap:shortdesc "An open and extensible audio plugin standard" ;
|
||||
doap:programming-language "C" ;
|
||||
doap:developer <http://plugin.org.uk/swh.xrdf#me> ,
|
||||
<http://drobilla.net/drobilla#me> ;
|
||||
doap:maintainer <http://drobilla.net/drobilla#me> ;
|
||||
doap:release [
|
||||
doap:revision "16.0" ;
|
||||
doap:created "2019-02-03" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add lv2:MIDIPlugin class."
|
||||
] , [
|
||||
rdfs:label "Rework port restrictions so that presets can be validated."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "14.0" ;
|
||||
doap:created "2016-09-18" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add lv2_util.h with lv2_features_data() and lv2_features_query()."
|
||||
] , [
|
||||
rdfs:label "Add lv2:enabled designation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "12.4" ;
|
||||
doap:created "2015-04-07" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Relax domain of lv2:minimum lv2:maximum and lv2:default so they can be used to describe properties/parameters as well."
|
||||
] , [
|
||||
rdfs:label "Add extern C and visibility attribute to LV2_SYMBOL_EXPORT."
|
||||
] , [
|
||||
rdfs:label "Add lv2:isSideChain port property."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "12.2" ;
|
||||
doap:created "2014-08-08" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Clarify lv2_descriptor() and lv2_lib_descriptor() documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "12.0" ;
|
||||
doap:created "2014-01-04" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add lv2:prototype for property inheritance."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "10.0" ;
|
||||
doap:created "2013-02-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add lv2:EnvelopePlugin class."
|
||||
] , [
|
||||
rdfs:label "Add lv2:control for designating primary event-based control ports."
|
||||
] , [
|
||||
rdfs:label "Set range of lv2:designation to lv2:Designation."
|
||||
] , [
|
||||
rdfs:label "Make lv2:Parameter rdfs:subClassOf rdf:Property."
|
||||
] , [
|
||||
rdfs:label "Reserve minor version 0 for unstable development plugins."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "8.2" ;
|
||||
doap:created "2012-10-14" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Use consistent label style."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "8.0" ;
|
||||
doap:created "2012-04-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix LV2_SYMBOL_EXPORT and lv2_descriptor prototype for Windows."
|
||||
] , [
|
||||
rdfs:label "Add metadata concept of a designation, a channel or parameter description which can be assigned to ports for more intelligent use by hosts."
|
||||
] , [
|
||||
rdfs:label "Add new discovery API which allows libraries to read bundle files during discovery, makes library construction/destruction explicit, and adds extensibility to prevent future breakage."
|
||||
] , [
|
||||
rdfs:label "Relax the range of lv2:index so it can be used for things other than ports."
|
||||
] , [
|
||||
rdfs:label "Remove lv2:Resource, which turned out to be meaningless."
|
||||
] , [
|
||||
rdfs:label "Add lv2:CVPort."
|
||||
] , [
|
||||
rdfs:label "Merge with unified LV2 package."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "6.0" ;
|
||||
doap:created "2011-11-21" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2core-6.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Rename core.lv2 and lv2.ttl to lv2core.lv2 and lv2core.ttl to adhere to modern conventions."
|
||||
] , [
|
||||
rdfs:label "Add lv2:extensionData and lv2:ExtensionData for plugins to indicate that they support some URI for extension_data()."
|
||||
] , [
|
||||
rdfs:label "Remove lv2config in favour of the simple convention that specifications install headers to standard URI-based paths."
|
||||
] , [
|
||||
rdfs:label "Switch to the ISC license, a simple BSD-style license (with permission of all contributors to lv2.h and its ancestor, ladspa.h)."
|
||||
] , [
|
||||
rdfs:label "Make lv2core.ttl a valid OWL 2 DL ontology."
|
||||
] , [
|
||||
rdfs:label "Improve documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "4.0" ;
|
||||
doap:created "2011-03-18" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2core-4.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Make doap:license suggested, but not required (for wrappers)."
|
||||
] , [
|
||||
rdfs:label "Define lv2:binary (MUST be in manifest.ttl)."
|
||||
] , [
|
||||
rdfs:label "Define lv2:minorVersion and lv2:microVersion (MUST be in manifest.ttl)."
|
||||
] , [
|
||||
rdfs:label "Define lv2:documentation and use it to document lv2core."
|
||||
] , [
|
||||
rdfs:label "Add lv2:FunctionPlugin and lv2:ConstantPlugin classes."
|
||||
] , [
|
||||
rdfs:label "Move lv2:AmplifierPlugin under lv2:DynamicsPlugin."
|
||||
] , [
|
||||
rdfs:label "Loosen domain of lv2:optionalFeature and lv2:requiredFeature (to allow re-use in extensions)."
|
||||
] , [
|
||||
rdfs:label "Add generic lv2:Resource and lv2:PluginBase classes."
|
||||
] , [
|
||||
rdfs:label "Fix definition of lv2:minimum etc. (used for values, not scale points)."
|
||||
] , [
|
||||
rdfs:label "More precisely define properties with OWL."
|
||||
] , [
|
||||
rdfs:label "Move project metadata to manifest."
|
||||
] , [
|
||||
rdfs:label "Add lv2:enumeration port property."
|
||||
] , [
|
||||
rdfs:label "Define run() pre-roll special case (sample_count == 0)."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "3.0" ;
|
||||
doap:created "2008-11-08" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2core-3.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Require that serialisations refer to ports by symbol rather than index."
|
||||
] , [
|
||||
rdfs:label "Minor stylistic changes to lv2.ttl."
|
||||
] , [
|
||||
rdfs:label "No header changes."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "2.0" ;
|
||||
doap:created "2008-02-10" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2core-2.0.tar.gz> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release."
|
||||
]
|
||||
]
|
||||
] .
|
||||
1065
lv2/lv2/core/lv2core.ttl
Normal file
1065
lv2/lv2/core/lv2core.ttl
Normal file
File diff suppressed because it is too large
Load diff
13
lv2/lv2/core/manifest.ttl
Normal file
13
lv2/lv2/core/manifest.ttl
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/lv2core>
|
||||
a lv2:Specification ;
|
||||
lv2:minorVersion 16 ;
|
||||
lv2:microVersion 0 ;
|
||||
rdfs:seeAlso <lv2core.ttl> .
|
||||
|
||||
<http://lv2plug.in/ns/lv2>
|
||||
a doap:Project ;
|
||||
rdfs:seeAlso <meta.ttl> .
|
||||
230
lv2/lv2/core/meta.ttl
Normal file
230
lv2/lv2/core/meta.ttl
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix meta: <http://lv2plug.in/ns/meta#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://opensource.org/licenses/isc>
|
||||
rdf:value """
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
""" .
|
||||
|
||||
<http://lv2plug.in/ns/lv2>
|
||||
a doap:Project ;
|
||||
lv2:symbol "lv2" ;
|
||||
doap:name "LV2" ;
|
||||
doap:license <http://opensource.org/licenses/isc> ;
|
||||
doap:shortdesc "The LV2 Plugin Interface Project" ;
|
||||
doap:description "LV2 is a plugin standard for audio systems. It defines a minimal yet extensible C API for plugin code and a format for plugin bundles" ;
|
||||
doap:created "2006-05-10" ;
|
||||
doap:homepage <http://lv2plug.in/> ;
|
||||
doap:mailing-list <http://lists.lv2plug.in/listinfo.cgi/devel-lv2plug.in> ;
|
||||
doap:programming-language "C" ;
|
||||
doap:repository [
|
||||
a doap:SVNRepository ;
|
||||
doap:location <http://lv2plug.in/repo>
|
||||
] ;
|
||||
doap:developer <http://drobilla.net/drobilla#me> ,
|
||||
<http://plugin.org.uk/swh.xrdf#me> ;
|
||||
doap:helper meta:larsl ,
|
||||
meta:bmwiedemann ,
|
||||
meta:gabrbedd ,
|
||||
meta:daste ,
|
||||
meta:kfoltman ,
|
||||
meta:paniq ;
|
||||
doap:release [
|
||||
doap:revision "1.16.1" ;
|
||||
doap:created "2019-03-27" ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Improve documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.16.0" ;
|
||||
doap:created "2019-02-03" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add core/attributes.h utility header."
|
||||
] , [
|
||||
rdfs:label "eg-sampler: Add waveform display to UI."
|
||||
] , [
|
||||
rdfs:label "eg-midigate: Respond to \"all notes off\" MIDI message."
|
||||
] , [
|
||||
rdfs:label "Simplify use of lv2specgen."
|
||||
] , [
|
||||
rdfs:label "Add lv2_validate utility."
|
||||
] , [
|
||||
rdfs:label "Install headers to simpler paths."
|
||||
] , [
|
||||
rdfs:label "Aggressively deprecate uri-map and event extensions."
|
||||
] , [
|
||||
rdfs:label "Upgrade build system and fix building with Python 3.7."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.14.0" ;
|
||||
doap:created "2016-09-19" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.14.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "eg-scope: Don't feed back UI state updates."
|
||||
] , [
|
||||
rdfs:label "eg-sampler: Fix handling of state file paths."
|
||||
] , [
|
||||
rdfs:label "eg-sampler: Support thread-safe state restoration."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.12.0" ;
|
||||
doap:created "2015-04-07" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.12.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "eg-sampler: Support patch:Get, and request initial state from UI."
|
||||
] , [
|
||||
rdfs:label "eg-sampler: Add gain parameter."
|
||||
] , [
|
||||
rdfs:label "Fix merging of version histories in specification documentation."
|
||||
] , [
|
||||
rdfs:label "Improve API documentation."
|
||||
] , [
|
||||
rdfs:label "Simplify property restrictions by removing redundancy."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.10.0" ;
|
||||
doap:created "2014-08-08" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "lv2specgen: Display deprecated warning on classes marked owl:deprecated."
|
||||
] , [
|
||||
rdfs:label "Fix -Wconversion warnings in headers."
|
||||
] , [
|
||||
rdfs:label "Upgrade to waf 1.7.16."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.8.0" ;
|
||||
doap:created "2014-01-04" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add scope example plugin from Robin Gareus."
|
||||
] , [
|
||||
rdfs:label "lv2specgen: Fix links to externally defined terms."
|
||||
] , [
|
||||
rdfs:label "Install lv2specgen for use by other projects."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.6.0" ;
|
||||
doap:created "2013-08-09" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.6.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Fix port indices of metronome example."
|
||||
] , [
|
||||
rdfs:label "Fix lv2specgen usage from command line."
|
||||
] , [
|
||||
rdfs:label "Upgrade to waf 1.7.11."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.4.0" ;
|
||||
doap:created "2013-02-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add metronome example plugin to demonstrate sample accurate tempo sync."
|
||||
] , [
|
||||
rdfs:label "Generate book-style HTML documentation from example plugins."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.2.0" ;
|
||||
doap:created "2012-10-14" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Move all project metadata for extensions (e.g. change log) to separate files to spare hosts from loading them during discovery."
|
||||
] , [
|
||||
rdfs:label "Use stricter datatype definitions conformant with the XSD and OWL specifications for better validation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.0.0" ;
|
||||
doap:created "2012-04-16" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release as a unified project. Projects can now simply depend on the pkg-config package 'lv2' for all official LV2 APIs."
|
||||
] , [
|
||||
rdfs:label "New extensions: atom, log, parameters, patch, port-groups, port-props, resize-port, state, time, worker."
|
||||
]
|
||||
]
|
||||
] .
|
||||
|
||||
<http://drobilla.net/drobilla#me>
|
||||
a foaf:Person ;
|
||||
foaf:name "David Robillard" ;
|
||||
foaf:mbox <mailto:d@drobilla.net> ;
|
||||
rdfs:seeAlso <http://drobilla.net/drobilla> .
|
||||
|
||||
<http://plugin.org.uk/swh.xrdf#me>
|
||||
a foaf:Person ;
|
||||
foaf:name "Steve Harris" ;
|
||||
foaf:mbox <mailto:steve@plugin.org.uk> ;
|
||||
rdfs:seeAlso <http://plugin.org.uk/swh.xrdf> .
|
||||
|
||||
meta:larsl
|
||||
a foaf:Person ;
|
||||
foaf:name "Lars Luthman" ;
|
||||
foaf:mbox <mailto:lars.luthman@gmail.com> .
|
||||
|
||||
meta:gabrbedd
|
||||
a foaf:Person ;
|
||||
foaf:name "Gabriel M. Beddingfield" ;
|
||||
foaf:mbox <mailto:gabrbedd@gmail.com> .
|
||||
|
||||
meta:daste
|
||||
a foaf:Person ;
|
||||
foaf:name "Stefano D'Angelo" ;
|
||||
foaf:mbox <mailto:zanga.mail@gmail.com> .
|
||||
|
||||
meta:kfoltman
|
||||
a foaf:Person ;
|
||||
foaf:name "Krzysztof Foltman" ;
|
||||
foaf:mbox <mailto:wdev@foltman.com> .
|
||||
|
||||
meta:paniq
|
||||
a foaf:Person ;
|
||||
foaf:name "Leonard Ritter" ;
|
||||
foaf:mbox <mailto:paniq@paniq.org> .
|
||||
|
||||
meta:harry
|
||||
a foaf:Person ;
|
||||
foaf:name "Harry van Haaren" ;
|
||||
foaf:mbox <harryhaaren@gmail.com> .
|
||||
|
||||
meta:bmwiedemann
|
||||
a foaf:Person ;
|
||||
foaf:name "Bernhard M. Wiedemann" ;
|
||||
foaf:mbox <bwiedemann@suse.de> .
|
||||
|
||||
68
lv2/lv2/data-access/data-access.h
Normal file
68
lv2/lv2/data-access/data-access.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
LV2 Data Access Extension
|
||||
Copyright 2008-2016 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup data-access Data Access
|
||||
|
||||
Access to plugin extension_data() for UIs, see
|
||||
<http://lv2plug.in/ns/ext/data-access> for details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_DATA_ACCESS_H
|
||||
#define LV2_DATA_ACCESS_H
|
||||
|
||||
#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" ///< http://lv2plug.in/ns/ext/data-access
|
||||
#define LV2_DATA_ACCESS_PREFIX LV2_DATA_ACCESS_URI "#" ///< http://lv2plug.in/ns/ext/data-access#
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
The data field of the LV2_Feature for this extension.
|
||||
|
||||
To support this feature the host must pass an LV2_Feature struct to the
|
||||
instantiate method with URI "http://lv2plug.in/ns/ext/data-access"
|
||||
and data pointed to an instance of this struct.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
A pointer to a method the UI can call to get data (of a type specified
|
||||
by some other extension) from the plugin.
|
||||
|
||||
This call never is never guaranteed to return anything, UIs should
|
||||
degrade gracefully if direct access to the plugin data is not possible
|
||||
(in which case this function will return NULL).
|
||||
|
||||
This is for access to large data that can only possibly work if the UI
|
||||
and plugin are running in the same process. For all other things, use
|
||||
the normal LV2 UI communication system.
|
||||
*/
|
||||
const void* (*data_access)(const char* uri);
|
||||
} LV2_Extension_Data_Feature;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_DATA_ACCESS_H */
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
23
lv2/lv2/data-access/data-access.ttl
Normal file
23
lv2/lv2/data-access/data-access.ttl
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
@prefix da: <http://lv2plug.in/ns/ext/data-access#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/data-access>
|
||||
a lv2:Feature ;
|
||||
rdfs:seeAlso <data-access.h> ,
|
||||
<lv2-data-access.doap.ttl> ;
|
||||
lv2:documentation """
|
||||
<p>This extension defines a feature, LV2_Extension_Data_Feature, which provides
|
||||
access to LV2_Descriptor::extension_data() for plugin UIs or other potentially
|
||||
remote users of a plugin.</p>
|
||||
|
||||
<p>Note that the use of this extension by UIs violates the important principle
|
||||
of UI/plugin separation, and is potentially a source of many problems.
|
||||
Accordingly, <strong>use of this extension is highly discouraged</strong>, and
|
||||
plugins should not expect hosts to support it, since it is often impossible to
|
||||
do so.</p>
|
||||
|
||||
<p>To support this feature the host must pass an LV2_Feature struct to the
|
||||
instantiate method with URI LV2_DATA_ACCESS_URI and data pointed to an instance
|
||||
of LV2_Extension_Data_Feature.</p>
|
||||
""" .
|
||||
58
lv2/lv2/data-access/lv2-data-access.doap.ttl
Normal file
58
lv2/lv2/data-access/lv2-data-access.doap.ttl
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/data-access>
|
||||
a doap:Project ;
|
||||
rdfs:seeAlso <data-access.h> ;
|
||||
doap:license <http://opensource.org/licenses/isc> ;
|
||||
doap:name "LV2 Data Access" ;
|
||||
doap:shortdesc "Provides access to LV2_Descriptor::extension_data()." ;
|
||||
doap:created "2008-00-00" ;
|
||||
doap:developer <http://drobilla.net/drobilla#me> ;
|
||||
doap:release [
|
||||
doap:revision "1.6" ;
|
||||
doap:created "2012-04-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Merge with unified LV2 package."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.4" ;
|
||||
doap:created "2011-11-21" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.4.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Update packaging."
|
||||
] , [
|
||||
rdfs:label "Improve documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.2" ;
|
||||
doap:created "2011-05-26" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.2.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Add build system for installation."
|
||||
] , [
|
||||
rdfs:label "Switch to ISC license."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.0" ;
|
||||
doap:created "2010-10-04" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-data-access-1.0.tar.gz> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release."
|
||||
]
|
||||
]
|
||||
] .
|
||||
9
lv2/lv2/data-access/manifest.ttl
Normal file
9
lv2/lv2/data-access/manifest.ttl
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/data-access>
|
||||
a lv2:Specification ;
|
||||
lv2:minorVersion 1 ;
|
||||
lv2:microVersion 6 ;
|
||||
rdfs:seeAlso <data-access.ttl> .
|
||||
|
||||
151
lv2/lv2/dynmanifest/dynmanifest.h
Normal file
151
lv2/lv2/dynmanifest/dynmanifest.h
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
Dynamic manifest specification for LV2
|
||||
Copyright 2008-2011 Stefano D'Angelo <zanga.mail@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup dynmanifest Dynamic Manifest
|
||||
|
||||
Support for dynamic data generation, see
|
||||
<http://lv2plug.in/ns/ext/dynmanifest> for details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_DYN_MANIFEST_H_INCLUDED
|
||||
#define LV2_DYN_MANIFEST_H_INCLUDED
|
||||
|
||||
#include "lv2/core/lv2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest" ///< http://lv2plug.in/ns/ext/dynmanifest
|
||||
#define LV2_DYN_MANIFEST_PREFIX LV2_DYN_MANIFEST_URI "#" ///< http://lv2plug.in/ns/ext/dynmanifest#
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
Dynamic manifest generator handle.
|
||||
|
||||
This handle indicates a particular status of a dynamic manifest generator.
|
||||
The host MUST NOT attempt to interpret it and, unlikely LV2_Handle, it is
|
||||
NOT even valid to compare this to NULL. The dynamic manifest generator MAY
|
||||
use it to reference internal data.
|
||||
*/
|
||||
typedef void * LV2_Dyn_Manifest_Handle;
|
||||
|
||||
/**
|
||||
Generate the dynamic manifest.
|
||||
|
||||
@param handle Pointer to an uninitialized dynamic manifest generator handle.
|
||||
|
||||
@param features NULL terminated array of LV2_Feature structs which represent
|
||||
the features the host supports. The dynamic manifest generator may refuse to
|
||||
(re)generate the dynamic manifest if required features are not found here
|
||||
(however hosts SHOULD NOT use this as a discovery mechanism, instead of
|
||||
reading the static manifest file). This array must always exist; if a host
|
||||
has no features, it MUST pass a single element array containing NULL.
|
||||
|
||||
@return 0 on success, otherwise a non-zero error code. The host SHOULD
|
||||
evaluate the result of the operation by examining the returned value and
|
||||
MUST NOT try to interpret the value of handle.
|
||||
*/
|
||||
int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle,
|
||||
const LV2_Feature *const * features);
|
||||
|
||||
/**
|
||||
Fetch a "list" of subject URIs described in the dynamic manifest.
|
||||
|
||||
The dynamic manifest generator has to fill the resource only with the needed
|
||||
triples to make the host aware of the "objects" it wants to expose. For
|
||||
example, if the plugin library exposes a regular LV2 plugin, it should
|
||||
output only a triple like the following:
|
||||
|
||||
<http://example.org/plugin> a lv2:Plugin .
|
||||
|
||||
The objects that are elegible for exposure are those that would need to be
|
||||
represented by a subject node in a static manifest.
|
||||
|
||||
@param handle Dynamic manifest generator handle.
|
||||
|
||||
@param fp FILE * identifying the resource the host has to set up for the
|
||||
dynamic manifest generator. The host MUST pass a writable, empty resource to
|
||||
this function, and the dynamic manifest generator MUST ONLY perform write
|
||||
operations on it at the end of the stream (e.g., using only fprintf(),
|
||||
fwrite() and similar).
|
||||
|
||||
@return 0 on success, otherwise a non-zero error code.
|
||||
*/
|
||||
int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle,
|
||||
FILE * fp);
|
||||
|
||||
/**
|
||||
Function that fetches data related to a specific URI.
|
||||
|
||||
The dynamic manifest generator has to fill the resource with data related to
|
||||
object represented by the given URI. For example, if the library exposes a
|
||||
regular LV2 plugin whose URI, as retrieved by the host using
|
||||
lv2_dyn_manifest_get_subjects() is http://example.org/plugin then it
|
||||
should output something like:
|
||||
|
||||
<pre>
|
||||
<http://example.org/plugin>
|
||||
a lv2:Plugin ;
|
||||
doap:name "My Plugin" ;
|
||||
lv2:binary <mylib.so> ;
|
||||
etc:etc "..." .
|
||||
</pre>
|
||||
|
||||
@param handle Dynamic manifest generator handle.
|
||||
|
||||
@param fp FILE * identifying the resource the host has to set up for the
|
||||
dynamic manifest generator. The host MUST pass a writable resource to this
|
||||
function, and the dynamic manifest generator MUST ONLY perform write
|
||||
operations on it at the current position of the stream (e.g. using only
|
||||
fprintf(), fwrite() and similar).
|
||||
|
||||
@param uri URI to get data about (in the "plain" form, i.e., absolute URI
|
||||
without Turtle prefixes).
|
||||
|
||||
@return 0 on success, otherwise a non-zero error code.
|
||||
*/
|
||||
int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle,
|
||||
FILE * fp,
|
||||
const char * uri);
|
||||
|
||||
/**
|
||||
Function that ends the operations on the dynamic manifest generator.
|
||||
|
||||
This function SHOULD be used by the dynamic manifest generator to perform
|
||||
cleanup operations, etc.
|
||||
|
||||
Once this function is called, referring to handle will cause undefined
|
||||
behavior.
|
||||
|
||||
@param handle Dynamic manifest generator handle.
|
||||
*/
|
||||
void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LV2_DYN_MANIFEST_H_INCLUDED */
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
85
lv2/lv2/dynmanifest/dynmanifest.ttl
Normal file
85
lv2/lv2/dynmanifest/dynmanifest.ttl
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
@prefix dman: <http://lv2plug.in/ns/ext/dynmanifest#> .
|
||||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/dynmanifest>
|
||||
a lv2:Specification ;
|
||||
rdfs:seeAlso <dynmanifest.h> ,
|
||||
<lv2-dynmanifest.doap.ttl> ;
|
||||
lv2:documentation """
|
||||
<p>The LV2 API, on its own, cannot be used to write plugin libraries where data
|
||||
is dynamically generated at runtime (e.g. API wrappers), since LV2 requires
|
||||
needed information to be provided in one or more static data (RDF) files. This
|
||||
API addresses this limitation by extending the LV2 API.</p>
|
||||
|
||||
<p>To detect that a plugin library implements a dynamic manifest generator,
|
||||
the host checks its static manifest for a description like:</p>
|
||||
|
||||
<pre class="turtle-code">
|
||||
<http://example.org/my-dynamic-manifest>
|
||||
a dman:DynManifest ;
|
||||
lv2:binary <mydynmanifest.so> .
|
||||
</pre>
|
||||
|
||||
<p>To load the data, the host loads the library
|
||||
(e.g. <code>mydynmanifest.so</code>) as usual and fetches the dynamic Turtle
|
||||
data from it using this API.</p>
|
||||
|
||||
<p>The host is allowed to request regeneration of the dynamic manifest multiple
|
||||
times, and the plugin library is expected to provide updated data if/when
|
||||
possible. All data and references provided via this API before the last
|
||||
regeneration of the dynamic manifest is to be considered invalid by the host,
|
||||
including plugin descriptors whose URIs were discovered using this API.</p>
|
||||
|
||||
<h3>Accessing Data</h3>
|
||||
|
||||
<p>Whenever a host wants to access data using this API, it could:</p>
|
||||
|
||||
<ol>
|
||||
<li>Call lv2_dyn_manifest_open().</li>
|
||||
<li>Create a FILE for functions to write data to (e.g. using tmpfile()).</li>
|
||||
<li>Get a <q>list</q> of exposed subject URIs using
|
||||
lv2_dyn_manifest_get_subjects().</li>
|
||||
<li>Call lv2_dyn_manifest_get_data() for each URI of interest to
|
||||
get the data related to that URI (which can be written to any FILE).</li>
|
||||
<li>Call lv2_dyn_manifest_close().</li>
|
||||
<li>Parse the content of the FILE(s).</li>
|
||||
<li>Free/delete/unlink the FILE(s).</li>
|
||||
</ol>
|
||||
|
||||
<p>Each call to the above mentioned dynamic manifest functions MUST write a
|
||||
complete, valid Turtle document (including all needed prefix definitions) to
|
||||
the output FILE.</p>
|
||||
|
||||
<p>Each call to lv2_dyn_manifest_open() causes the (re)generation of the
|
||||
dynamic manifest data, and invalidates all data fetched before the call.</p>
|
||||
|
||||
<p>In case the plugin library uses this same API to access other dynamic
|
||||
manifests, it MUST implement some mechanism to avoid potentially endless loops
|
||||
(such as A loads B, B loads A, etc.) and, in case such a loop is detected, the
|
||||
operation MUST fail. For this purpose, use of a static boolean flag is
|
||||
suggested.</p>
|
||||
|
||||
<h3>Threading Rules</h3>
|
||||
|
||||
<p>All of the functions defined by this specification belong to the Discovery
|
||||
class.</p>
|
||||
""" .
|
||||
|
||||
dman:DynManifest
|
||||
a rdfs:Class ;
|
||||
rdfs:label "Dynamic Manifest" ;
|
||||
rdfs:subClassOf [
|
||||
a owl:Restriction ;
|
||||
owl:onProperty lv2:binary ;
|
||||
owl:minCardinality 1 ;
|
||||
rdfs:comment "A DynManifest MUST have at least 1 lv2:binary, which MUST implement all the functions defined in dynmanifest.h."
|
||||
] ;
|
||||
rdfs:comment """The class which represents a dynamic manifest generator.
|
||||
|
||||
There MUST NOT be any instances of dman:DynManifest in the generated manifest.
|
||||
|
||||
All relative URIs in the generated data MUST be relative to the base path that would be used to parse a normal LV2 manifest (the bundle path).""" .
|
||||
55
lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl
Normal file
55
lv2/lv2/dynmanifest/lv2-dynmanifest.doap.ttl
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
@prefix dcs: <http://ontologi.es/doap-changeset#> .
|
||||
@prefix doap: <http://usefulinc.com/ns/doap#> .
|
||||
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/dynmanifest>
|
||||
a doap:Project ;
|
||||
doap:license <http://opensource.org/licenses/isc> ;
|
||||
doap:name "LV2 Dynamic Manifest" ;
|
||||
doap:homepage <http://naspro.atheme.org> ;
|
||||
doap:created "2009-06-13" ;
|
||||
doap:shortdesc "Support for dynamic data generation." ;
|
||||
doap:programming-language "C" ;
|
||||
doap:developer <http://lv2plug.in/ns/meta#daste> ;
|
||||
doap:release [
|
||||
doap:revision "1.6" ;
|
||||
doap:created "2012-10-14" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Use consistent label style."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.4" ;
|
||||
doap:created "2012-04-17" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Merge with unified LV2 package."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.2" ;
|
||||
doap:created "2011-11-21" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-dynmanifest-1.2.tar.bz2> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Improve documentation."
|
||||
]
|
||||
]
|
||||
] , [
|
||||
doap:revision "1.0" ;
|
||||
doap:created "2010-04-10" ;
|
||||
doap:file-release <http://lv2plug.in/spec/lv2-dyn-manifest-1.0.tar.gz> ;
|
||||
dcs:blame <http://drobilla.net/drobilla#me> ;
|
||||
dcs:changeset [
|
||||
dcs:item [
|
||||
rdfs:label "Initial release."
|
||||
]
|
||||
]
|
||||
] .
|
||||
8
lv2/lv2/dynmanifest/manifest.ttl
Normal file
8
lv2/lv2/dynmanifest/manifest.ttl
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
|
||||
<http://lv2plug.in/ns/ext/dynmanifest>
|
||||
a lv2:Specification ;
|
||||
lv2:minorVersion 1 ;
|
||||
lv2:microVersion 6 ;
|
||||
rdfs:seeAlso <dynmanifest.ttl> .
|
||||
268
lv2/lv2/event/event-helpers.h
Normal file
268
lv2/lv2/event/event-helpers.h
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
Copyright 2008-2015 David Robillard <http://drobilla.net>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file event-helpers.h Helper functions for the LV2 Event extension
|
||||
<http://lv2plug.in/ns/ext/event>.
|
||||
*/
|
||||
|
||||
#ifndef LV2_EVENT_HELPERS_H
|
||||
#define LV2_EVENT_HELPERS_H
|
||||
|
||||
#include "lv2/core/attributes.h"
|
||||
#include "lv2/event/event.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LV2_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
/** @file
|
||||
* Helper functions for the LV2 Event extension
|
||||
* <http://lv2plug.in/ns/ext/event>.
|
||||
*
|
||||
* These functions are provided for convenience only, use of them is not
|
||||
* required for supporting lv2ev (i.e. the events extension is defined by the
|
||||
* raw buffer format described in lv2_event.h and NOT by this API).
|
||||
*
|
||||
* Note that these functions are all static inline which basically means:
|
||||
* do not take the address of these functions. */
|
||||
|
||||
|
||||
/** Pad a size to 64 bits (for event sizes) */
|
||||
static inline uint16_t
|
||||
lv2_event_pad_size(uint16_t size)
|
||||
{
|
||||
return (uint16_t)(size + 7U) & (uint16_t)(~7U);
|
||||
}
|
||||
|
||||
|
||||
/** Initialize (empty, reset..) an existing event buffer.
|
||||
* The contents of buf are ignored entirely and overwritten, except capacity
|
||||
* which is unmodified. */
|
||||
static inline void
|
||||
lv2_event_buffer_reset(LV2_Event_Buffer* buf,
|
||||
uint16_t stamp_type,
|
||||
uint8_t* data)
|
||||
{
|
||||
buf->data = data;
|
||||
buf->header_size = sizeof(LV2_Event_Buffer);
|
||||
buf->stamp_type = stamp_type;
|
||||
buf->event_count = 0;
|
||||
buf->size = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Allocate a new, empty event buffer. */
|
||||
static inline LV2_Event_Buffer*
|
||||
lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
|
||||
{
|
||||
const size_t size = sizeof(LV2_Event_Buffer) + capacity;
|
||||
LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size);
|
||||
if (buf != NULL) {
|
||||
buf->capacity = capacity;
|
||||
lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1));
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/** An iterator over an LV2_Event_Buffer.
|
||||
*
|
||||
* Multiple simultaneous read iterators over a single buffer is fine,
|
||||
* but changing the buffer invalidates all iterators (e.g. RW Lock). */
|
||||
typedef struct {
|
||||
LV2_Event_Buffer* buf;
|
||||
uint32_t offset;
|
||||
} LV2_Event_Iterator;
|
||||
|
||||
|
||||
/** Reset an iterator to point to the start of `buf`.
|
||||
* @return True if `iter` is valid, otherwise false (buffer is empty) */
|
||||
static inline bool
|
||||
lv2_event_begin(LV2_Event_Iterator* iter,
|
||||
LV2_Event_Buffer* buf)
|
||||
{
|
||||
iter->buf = buf;
|
||||
iter->offset = 0;
|
||||
return (buf->size > 0);
|
||||
}
|
||||
|
||||
|
||||
/** Check if `iter` is valid.
|
||||
* @return True if `iter` is valid, otherwise false (past end of buffer) */
|
||||
static inline bool
|
||||
lv2_event_is_valid(LV2_Event_Iterator* iter)
|
||||
{
|
||||
return (iter->buf && (iter->offset < iter->buf->size));
|
||||
}
|
||||
|
||||
|
||||
/** Advance `iter` forward one event.
|
||||
* `iter` must be valid.
|
||||
* @return True if `iter` is valid, otherwise false (reached end of buffer) */
|
||||
static inline bool
|
||||
lv2_event_increment(LV2_Event_Iterator* iter)
|
||||
{
|
||||
if (!lv2_event_is_valid(iter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
|
||||
|
||||
iter->offset += lv2_event_pad_size(
|
||||
(uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Dereference an event iterator (get the event currently pointed at).
|
||||
* `iter` must be valid.
|
||||
* `data` if non-NULL, will be set to point to the contents of the event
|
||||
* returned.
|
||||
* @return A Pointer to the event `iter` is currently pointing at, or NULL
|
||||
* if the end of the buffer is reached (in which case `data` is
|
||||
* also set to NULL). */
|
||||
static inline LV2_Event*
|
||||
lv2_event_get(LV2_Event_Iterator* iter,
|
||||
uint8_t** data)
|
||||
{
|
||||
if (!lv2_event_is_valid(iter)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
|
||||
|
||||
if (data) {
|
||||
*data = (uint8_t*)ev + sizeof(LV2_Event);
|
||||
}
|
||||
|
||||
return ev;
|
||||
}
|
||||
|
||||
|
||||
/** Write an event at `iter`.
|
||||
* The event (if any) pointed to by `iter` will be overwritten, and `iter`
|
||||
* incremented to point to the following event (i.e. several calls to this
|
||||
* function can be done in sequence without twiddling iter in-between).
|
||||
* @return True if event was written, otherwise false (buffer is full). */
|
||||
static inline bool
|
||||
lv2_event_write(LV2_Event_Iterator* iter,
|
||||
uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint16_t type,
|
||||
uint16_t size,
|
||||
const uint8_t* data)
|
||||
{
|
||||
if (!iter->buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
|
||||
|
||||
ev->frames = frames;
|
||||
ev->subframes = subframes;
|
||||
ev->type = type;
|
||||
ev->size = size;
|
||||
memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
|
||||
++iter->buf->event_count;
|
||||
|
||||
size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size));
|
||||
iter->buf->size += size;
|
||||
iter->offset += size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Reserve space for an event in the buffer and return a pointer to
|
||||
the memory where the caller can write the event data, or NULL if there
|
||||
is not enough room in the buffer. */
|
||||
static inline uint8_t*
|
||||
lv2_event_reserve(LV2_Event_Iterator* iter,
|
||||
uint32_t frames,
|
||||
uint32_t subframes,
|
||||
uint16_t type,
|
||||
uint16_t size)
|
||||
{
|
||||
const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size);
|
||||
if (iter->buf->capacity - iter->buf->size < total_size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LV2_Event* const ev = (LV2_Event*)(iter->buf->data + iter->offset);
|
||||
|
||||
ev->frames = frames;
|
||||
ev->subframes = subframes;
|
||||
ev->type = type;
|
||||
ev->size = size;
|
||||
++iter->buf->event_count;
|
||||
|
||||
const uint16_t padded_size = lv2_event_pad_size(total_size);
|
||||
iter->buf->size += padded_size;
|
||||
iter->offset += padded_size;
|
||||
|
||||
return (uint8_t*)ev + sizeof(LV2_Event);
|
||||
}
|
||||
|
||||
|
||||
/** Write an event at `iter`.
|
||||
* The event (if any) pointed to by `iter` will be overwritten, and `iter`
|
||||
* incremented to point to the following event (i.e. several calls to this
|
||||
* function can be done in sequence without twiddling iter in-between).
|
||||
* @return True if event was written, otherwise false (buffer is full). */
|
||||
static inline bool
|
||||
lv2_event_write_event(LV2_Event_Iterator* iter,
|
||||
const LV2_Event* ev,
|
||||
const uint8_t* data)
|
||||
{
|
||||
const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size);
|
||||
if (iter->buf->capacity - iter->buf->size < total_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LV2_Event* const write_ev = (LV2_Event*)(iter->buf->data + iter->offset);
|
||||
|
||||
*write_ev = *ev;
|
||||
memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
|
||||
++iter->buf->event_count;
|
||||
|
||||
const uint16_t padded_size = lv2_event_pad_size(total_size);
|
||||
iter->buf->size += padded_size;
|
||||
iter->offset += padded_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LV2_RESTORE_WARNINGS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_EVENT_HELPERS_H */
|
||||
303
lv2/lv2/event/event.h
Normal file
303
lv2/lv2/event/event.h
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
Copyright 2008-2016 David Robillard <http://drobilla.net>
|
||||
Copyright 2006-2007 Lars Luthman <lars.luthman@gmail.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@defgroup event Event
|
||||
|
||||
Generic time-stamped events, see <http://lv2plug.in/ns/ext/event> for
|
||||
details.
|
||||
|
||||
@{
|
||||
*/
|
||||
|
||||
#ifndef LV2_EVENT_H
|
||||
#define LV2_EVENT_H
|
||||
|
||||
#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" ///< http://lv2plug.in/ns/ext/event
|
||||
#define LV2_EVENT_PREFIX LV2_EVENT_URI "#" ///< http://lv2plug.in/ns/ext/event#
|
||||
|
||||
#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event" ///< http://lv2plug.in/ns/ext/event#Event
|
||||
#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort" ///< http://lv2plug.in/ns/ext/event#EventPort
|
||||
#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp" ///< http://lv2plug.in/ns/ext/event#FrameStamp
|
||||
#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp" ///< http://lv2plug.in/ns/ext/event#TimeStamp
|
||||
#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp" ///< http://lv2plug.in/ns/ext/event#generatesTimeStamp
|
||||
#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic" ///< http://lv2plug.in/ns/ext/event#generic
|
||||
#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent" ///< http://lv2plug.in/ns/ext/event#inheritsEvent
|
||||
#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp" ///< http://lv2plug.in/ns/ext/event#inheritsTimeStamp
|
||||
#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent" ///< http://lv2plug.in/ns/ext/event#supportsEvent
|
||||
#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp" ///< http://lv2plug.in/ns/ext/event#supportsTimeStamp
|
||||
|
||||
#define LV2_EVENT_AUDIO_STAMP 0 ///< Special timestamp type for audio frames
|
||||
|
||||
#include "lv2/core/attributes.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
LV2_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
/**
|
||||
The best Pulses Per Quarter Note for tempo-based uint32_t timestamps.
|
||||
Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble
|
||||
by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12.
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
static const uint32_t LV2_EVENT_PPQN = 3136573440U;
|
||||
|
||||
/**
|
||||
An LV2 event (header only).
|
||||
|
||||
LV2 events are generic time-stamped containers for any type of event.
|
||||
The type field defines the format of a given event's contents.
|
||||
|
||||
This struct defines the header of an LV2 event. An LV2 event is a single
|
||||
chunk of POD (plain old data), usually contained in a flat buffer (see
|
||||
LV2_EventBuffer below). Unless a required feature says otherwise, hosts may
|
||||
assume a deep copy of an LV2 event can be created safely using a simple:
|
||||
|
||||
memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent)
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
typedef struct {
|
||||
/**
|
||||
The frames portion of timestamp. The units used here can optionally be
|
||||
set for a port (with the lv2ev:timeUnits property), otherwise this is
|
||||
audio frames, corresponding to the sample_count parameter of the LV2 run
|
||||
method (e.g. frame 0 is the first frame for that call to run).
|
||||
*/
|
||||
uint32_t frames;
|
||||
|
||||
/**
|
||||
The sub-frames portion of timestamp. The units used here can optionally
|
||||
be set for a port (with the lv2ev:timeUnits property), otherwise this is
|
||||
1/(2^32) of an audio frame.
|
||||
*/
|
||||
uint32_t subframes;
|
||||
|
||||
/**
|
||||
The type of this event, as a number which represents some URI
|
||||
defining an event type. This value MUST be some value previously
|
||||
returned from a call to the uri_to_id function defined in the LV2
|
||||
URI map extension (see lv2_uri_map.h).
|
||||
There are special rules which must be followed depending on the type
|
||||
of an event. If the plugin recognizes an event type, the definition
|
||||
of that event type will describe how to interpret the event, and
|
||||
any required behaviour. Otherwise, if the type is 0, this event is a
|
||||
non-POD event and lv2_event_unref MUST be called if the event is
|
||||
'dropped' (see above). Even if the plugin does not understand an event,
|
||||
it may pass the event through to an output by simply copying (and NOT
|
||||
calling lv2_event_unref). These rules are designed to allow for generic
|
||||
event handling plugins and large non-POD events, but with minimal hassle
|
||||
on simple plugins that "don't care" about these more advanced features.
|
||||
*/
|
||||
uint16_t type;
|
||||
|
||||
/**
|
||||
The size of the data portion of this event in bytes, which immediately
|
||||
follows. The header size (12 bytes) is not included in this value.
|
||||
*/
|
||||
uint16_t size;
|
||||
|
||||
/* size bytes of data follow here */
|
||||
} LV2_Event;
|
||||
|
||||
|
||||
/**
|
||||
A buffer of LV2 events (header only).
|
||||
|
||||
Like events (which this contains) an event buffer is a single chunk of POD:
|
||||
the entire buffer (including contents) can be copied with a single memcpy.
|
||||
The first contained event begins sizeof(LV2_EventBuffer) bytes after the
|
||||
start of this struct.
|
||||
|
||||
After this header, the buffer contains an event header (defined by struct
|
||||
LV2_Event), followed by that event's contents (padded to 64 bits), followed
|
||||
by another header, etc:
|
||||
|
||||
| | | | | | |
|
||||
| | | | | | | | | | | | | | | | | | | | | | | | |
|
||||
|FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ...
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
typedef struct {
|
||||
/**
|
||||
The contents of the event buffer. This may or may not reside in the
|
||||
same block of memory as this header, plugins must not assume either.
|
||||
The host guarantees this points to at least capacity bytes of allocated
|
||||
memory (though only size bytes of that are valid events).
|
||||
*/
|
||||
uint8_t* data;
|
||||
|
||||
/**
|
||||
The size of this event header in bytes (including everything).
|
||||
|
||||
This is to allow for extending this header in the future without
|
||||
breaking binary compatibility. Whenever this header is copied,
|
||||
it MUST be done using this field (and NOT the sizeof this struct).
|
||||
*/
|
||||
uint16_t header_size;
|
||||
|
||||
/**
|
||||
The type of the time stamps for events in this buffer.
|
||||
As a special exception, '0' always means audio frames and subframes
|
||||
(1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate.
|
||||
|
||||
INPUTS: The host must set this field to the numeric ID of some URI
|
||||
defining the meaning of the frames/subframes fields of contained events
|
||||
(obtained by the LV2 URI Map uri_to_id function with the URI of this
|
||||
extension as the 'map' argument, see lv2_uri_map.h). The host must
|
||||
never pass a plugin a buffer which uses a stamp type the plugin does not
|
||||
'understand'. The value of this field must never change, except when
|
||||
connect_port is called on the input port, at which time the host MUST
|
||||
have set the stamp_type field to the value that will be used for all
|
||||
subsequent run calls.
|
||||
|
||||
OUTPUTS: The plugin may set this to any value that has been returned
|
||||
from uri_to_id with the URI of this extension for a 'map' argument.
|
||||
When connected to a buffer with connect_port, output ports MUST set this
|
||||
field to the type of time stamp they will be writing. On any call to
|
||||
connect_port on an event input port, the plugin may change this field on
|
||||
any output port, it is the responsibility of the host to check if any of
|
||||
these values have changed and act accordingly.
|
||||
*/
|
||||
uint16_t stamp_type;
|
||||
|
||||
/**
|
||||
The number of events in this buffer.
|
||||
|
||||
INPUTS: The host must set this field to the number of events contained
|
||||
in the data buffer before calling run(). The plugin must not change
|
||||
this field.
|
||||
|
||||
OUTPUTS: The plugin must set this field to the number of events it has
|
||||
written to the buffer before returning from run(). Any initial value
|
||||
should be ignored by the plugin.
|
||||
*/
|
||||
uint32_t event_count;
|
||||
|
||||
/**
|
||||
The size of the data buffer in bytes.
|
||||
This is set by the host and must not be changed by the plugin.
|
||||
The host is allowed to change this between run() calls.
|
||||
*/
|
||||
uint32_t capacity;
|
||||
|
||||
/**
|
||||
The size of the initial portion of the data buffer containing data.
|
||||
|
||||
INPUTS: The host must set this field to the number of bytes used
|
||||
by all events it has written to the buffer (including headers)
|
||||
before calling the plugin's run().
|
||||
The plugin must not change this field.
|
||||
|
||||
OUTPUTS: The plugin must set this field to the number of bytes
|
||||
used by all events it has written to the buffer (including headers)
|
||||
before returning from run().
|
||||
Any initial value should be ignored by the plugin.
|
||||
*/
|
||||
uint32_t size;
|
||||
} LV2_Event_Buffer;
|
||||
|
||||
|
||||
/**
|
||||
Opaque pointer to host data.
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
typedef void* LV2_Event_Callback_Data;
|
||||
|
||||
|
||||
/**
|
||||
Non-POD events feature.
|
||||
|
||||
To support this feature the host must pass an LV2_Feature struct to the
|
||||
plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event"
|
||||
and data pointed to an instance of this struct. Note this feature
|
||||
is not mandatory to support the event extension.
|
||||
*/
|
||||
LV2_DEPRECATED
|
||||
typedef struct {
|
||||
/**
|
||||
Opaque pointer to host data.
|
||||
|
||||
The plugin MUST pass this to any call to functions in this struct.
|
||||
Otherwise, it must not be interpreted in any way.
|
||||
*/
|
||||
LV2_Event_Callback_Data callback_data;
|
||||
|
||||
/**
|
||||
Take a reference to a non-POD event.
|
||||
|
||||
If a plugin receives an event with type 0, it means the event is a
|
||||
pointer to some object in memory and not a flat sequence of bytes
|
||||
in the buffer. When receiving a non-POD event, the plugin already
|
||||
has an implicit reference to the event. If the event is stored AND
|
||||
passed to an output, lv2_event_ref MUST be called on that event.
|
||||
If the event is only stored OR passed through, this is not necessary
|
||||
(as the plugin already has 1 implicit reference).
|
||||
|
||||
@param event An event received at an input that will not be copied to
|
||||
an output or stored in any way.
|
||||
|
||||
@param context The calling context. Like event types, this is a mapped
|
||||
URI, see lv2_context.h. Simple plugin with just a run() method should
|
||||
pass 0 here (the ID of the 'standard' LV2 run context). The host
|
||||
guarantees that this function is realtime safe iff the context is
|
||||
realtime safe.
|
||||
|
||||
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
|
||||
*/
|
||||
uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data,
|
||||
LV2_Event* event);
|
||||
|
||||
/**
|
||||
Drop a reference to a non-POD event.
|
||||
|
||||
If a plugin receives an event with type 0, it means the event is a
|
||||
pointer to some object in memory and not a flat sequence of bytes
|
||||
in the buffer. If the plugin does not pass the event through to
|
||||
an output or store it internally somehow, it MUST call this function
|
||||
on the event (more information on using non-POD events below).
|
||||
|
||||
@param event An event received at an input that will not be copied to an
|
||||
output or stored in any way.
|
||||
|
||||
@param context The calling context. Like event types, this is a mapped
|
||||
URI, see lv2_context.h. Simple plugin with just a run() method should
|
||||
pass 0 here (the ID of the 'standard' LV2 run context). The host
|
||||
guarantees that this function is realtime safe iff the context is
|
||||
realtime safe.
|
||||
|
||||
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS.
|
||||
*/
|
||||
uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data,
|
||||
LV2_Event* event);
|
||||
} LV2_Event_Feature;
|
||||
|
||||
LV2_RESTORE_WARNINGS
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV2_EVENT_H */
|
||||
|
||||
/**
|
||||
@}
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue