add Python bindings code

This commit is contained in:
David Braun 2025-01-08 14:33:09 -05:00
parent dfe00cdbaa
commit 5af8eed1e3
27 changed files with 7190 additions and 141 deletions

209
.github/workflows/all.yml vendored Normal file
View file

@ -0,0 +1,209 @@
name: Python package
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-ubuntu:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- { python-version: "3.9", pythonLibPath: "/opt/python/cp39-cp39/lib", pythonInclude: "/opt/python/cp39-cp39/include/python3.9", cibwbuild: "cp39-manylinux_x86_64"}
- { python-version: "3.10", pythonLibPath: "/opt/python/cp310-cp310/lib", pythonInclude: "/opt/python/cp310-cp310/include/python3.10", cibwbuild: "cp310-manylinux_x86_64"}
- { python-version: "3.11", pythonLibPath: "/opt/python/cp311-cp311/lib", pythonInclude: "/opt/python/cp311-cp311/include/python3.11", cibwbuild: "cp311-manylinux_x86_64"}
- { python-version: "3.12", pythonLibPath: "/opt/python/cp312-cp312/lib", pythonInclude: "/opt/python/cp312-cp312/include/python3.12", cibwbuild: "cp312-manylinux_x86_64"}
- { python-version: "3.13", pythonLibPath: "/opt/python/cp313-cp313/lib", pythonInclude: "/opt/python/cp313-cp313/include/python3.13", cibwbuild: "cp313-manylinux_x86_64"}
# - { python-version: "3.9", pythonLibPath: "/opt/python/cp39-cp39/lib", pythonInclude: "/opt/python/cp39-cp39/include/python3.9", cibwbuild: "cp39-manylinux_aarch64"}
# - { python-version: "3.10", pythonLibPath: "/opt/python/cp310-cp310/lib", pythonInclude: "/opt/python/cp310-cp310/include/python3.10", cibwbuild: "cp310-manylinux_aarch64"}
# - { python-version: "3.11", pythonLibPath: "/opt/python/cp311-cp311/lib", pythonInclude: "/opt/python/cp311-cp311/include/python3.11", cibwbuild: "cp311-manylinux_aarch64"}
# - { python-version: "3.12", pythonLibPath: "/opt/python/cp312-cp312/lib", pythonInclude: "/opt/python/cp312-cp312/include/python3.12", cibwbuild: "cp312-manylinux_aarch64"}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: true
- name: Set up QEMU for aarch64 on Linux
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v3
with:
platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
env:
CIBW_PLATFORM: linux
CIBW_BUILD: ${{ matrix.cibwbuild }}
CIBW_BUILD_VERBOSITY: 3
CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014
CIBW_BEFORE_BUILD_LINUX:
export LIBDIR=${{ matrix.pythonLibPath }} && export PYTHONLIBPATH=${{ matrix.pythonLibPath }} && export PYTHONINCLUDEPATH=${{ matrix.pythonInclude }} && sh -v build_linux.sh
CIBW_REPAIR_WHEEL_COMMAND_LINUX: pip install auditwheel-symbols && (auditwheel repair -w {dest_dir} {wheel} || auditwheel-symbols --manylinux 2014 {wheel})
CIBW_TEST_REQUIRES: -r test-requirements.txt
CIBW_TEST_COMMAND: "rm -rf vita/*.so* && cd {project}/tests && python -m pytest -v ."
CIBW_ARCHS: auto64
CIBW_ARCHS_LINUX: auto64 aarch64 # On an Linux Intel runner with qemu installed, build Intel and ARM wheels
- uses: actions/upload-artifact@v4
with:
name: artifact-${{ matrix.cibwbuild}}
path: ./wheelhouse/*.whl
build-macos:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { os: macos-13, build: cp39-macosx_x86_64, python-version: "3.9", ARCHS: "x86_64" }
- { os: macos-13, build: cp310-macosx_x86_64, python-version: "3.10", ARCHS: "x86_64" }
- { os: macos-13, build: cp311-macosx_x86_64, python-version: "3.11", ARCHS: "x86_64" }
- { os: macos-13, build: cp312-macosx_x86_64, python-version: "3.12", ARCHS: "x86_64" }
- { os: macos-13, build: cp313-macosx_x86_64, python-version: "3.13", ARCHS: "x86_64" }
- { os: macos-14, build: cp39-macosx_arm64, python-version: "3.9", ARCHS: "arm64" }
- { os: macos-14, build: cp310-macosx_arm64, python-version: "3.10", ARCHS: "arm64" }
- { os: macos-14, build: cp311-macosx_arm64, python-version: "3.11", ARCHS: "arm64" }
- { os: macos-14, build: cp312-macosx_arm64, python-version: "3.12", ARCHS: "arm64" }
- { os: macos-14, build: cp313-macosx_arm64, python-version: "3.13", ARCHS: "arm64" }
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Get CMake
uses: lukka/get-cmake@latest
- name: Build wheels ${{ matrix.python-version }}
uses: pypa/cibuildwheel@v2.20.0
env:
# note that the Projucer project refers to PYTHONMAJOR and pythonLocation, so they must be set here
PYTHONMAJOR: ${{ matrix.python-version }}
MACOSX_DEPLOYMENT_TARGET: 11.0
CIBW_BUILD_VERBOSITY: 1
CIBW_BEFORE_BUILD: export pythonLocation=$(python${{matrix.python-version}}-config --prefix) && sh -v build_macos.sh
CIBW_TEST_REQUIRES: -r test-requirements.txt
CIBW_TEST_COMMAND: "cd {project}/tests; python -m pytest -v ."
CIBW_BUILD: ${{matrix.build}}
CIBW_ARCHS: auto64
CIBW_ARCHS_MACOS: ${{matrix.ARCHS}}
CIBW_ENVIRONMENT_MACOS: ARCHS="${{matrix.ARCHS}}"
- uses: actions/upload-artifact@v4
with:
name: artifact-macos-${{ matrix.build}}
path: ./wheelhouse/*.whl
build-windows:
runs-on: ${{ matrix.os }}
strategy:
# fail-fast: false
matrix:
include:
- { os: windows-2022, python-version: "3.9", CIBW-BUILD: "cp39*"}
- { os: windows-2022, python-version: "3.10", CIBW-BUILD: "cp310*"}
- { os: windows-2022, python-version: "3.11", CIBW-BUILD: "cp311*"}
- { os: windows-2022, python-version: "3.12", CIBW-BUILD: "cp312*"}
- { os: windows-2022, python-version: "3.13", CIBW-BUILD: "cp313*"}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Get CMake
uses: lukka/get-cmake@latest
- name: Build Nanobind
run: |
cd third_party/nanobind
git submodule update --init --recursive
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
- name: Build Windows
run: |
msbuild headless/builds/VisualStudio2022/Vita.sln /property:Configuration=Release
- name: Install cibuildwheel
run: python -m pip install cibuildwheel
- name: Build Wheels
run: |
python -m cibuildwheel --output-dir wheelhouse
env:
PYTHONMAJOR: ${{ matrix.python-version }}
CIBW_BUILD_VERBOSITY: 1
CIBW_TEST_REQUIRES: -r test-requirements.txt
CIBW_TEST_COMMAND: "cd /D {project}\\tests && python -m pytest -v ."
CIBW_ARCHS: auto64
CIBW_BUILD: ${{matrix.CIBW-BUILD}}
- uses: actions/upload-artifact@v4
with:
name: artifact-windows-${{ matrix.python-version}}
path: ./wheelhouse/*.whl
# build_docs:
# permissions:
# contents: write
# runs-on: ubuntu-latest
# needs: test
# steps:
# - name: Checkout code
# uses: actions/checkout@v4
# - name: Set up Python
# uses: actions/setup-python@v5
# with:
# python-version: 3.11
# - name: Install dependencies
# run: |
# sudo apt-get install libsndfile-dev
# python -m pip install --upgrade pip
# pip install pytest
# pip install furo
# - name: Build Docs
# run: |
# cd docs
# make html
# - name: Deploy Docs to GitHub Pages
# uses: peaceiris/actions-gh-pages@v4
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_dir: ./docs/build/html
upload-pypi:
needs: [build-windows, build-ubuntu, build-macos]
runs-on: ubuntu-latest
name: "Upload wheels to PyPI"
if: github.event_name == 'release' && github.event.action == 'published'
steps:
- uses: actions/download-artifact@v4
with:
pattern: artifact-*
merge-multiple: true
path: dist
- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

74
.gitignore vendored
View file

@ -1,35 +1,41 @@
.DS_Store
.DS_Store?
VTune\ Profiler\ Results
cmake-build*
*.swp
*.Trashes
xcuserdata
xcshareddata
*.xcworkspace
build
.clang_complete
.vs
.ycm_extra_conf.py*
*.pbxuser
*.perspective
*.perspectivev3
*.sdf
*.suo
*.psess
*.vsp
*.tlog
*.user
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
*.opendb
*.opensdf
*.component
*.VST
*.lv2
*.vst
*.VST3
*.vst3
*.tar.gz
Debug
Profile
Release
.DS_STORE
build
dataset
.vs
.egg
*.egg-info*
vita/LICENSE
dist

1
MANIFEST.in Normal file
View file

@ -0,0 +1 @@
graft vita # copy everything

View file

@ -1,17 +1,20 @@
PYTHONINCLUDEPATH := $(shell python3.10 -c "import sysconfig; print(sysconfig.get_path('include'))")
PYTHONLIBPATH := $(shell python3.10 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
ifndef CONFIG
CONFIG=Release
endif
ifndef LIBDIR
LIBDIR=/usr/lib/
# LIBDIR=/usr/lib/
LIBDIR=$(shell python3.10 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
endif
BUILD_DATE="$(shell date +'%Y %m %d %H %M')"
PAID := 1
VERSION := $(shell sh -c 'grep -oh -m 1 "VERSION=[0-9\.]*" standalone/builds/linux/Makefile | cut -d "=" -f 2')
MACHINE := $(shell sh -c 'uname -m 2> /dev/null || echo not')
@ -106,19 +109,25 @@ effects_vst3:
$(MAKE) -C effects/builds/linux_vst VST3 CONFIG=$(CONFIG) AR=gcc-ar SIMDFLAGS="$(SIMDFLAGS)" GLFLAGS="$(GLFLAGS)" BUILD_DATE=$(BUILD_DATE)
headless_server:
$(MAKE) -C headless/builds/linux CONFIG=$(CONFIG) SIMDFLAGS="$(SIMDFLAGS)" GLFLAGS="$(GLFLAGS)" BUILD_DATE=$(BUILD_DATE)
cd headless/builds/linux
ldconfig
cd ../../..
$(MAKE) VERBOSE=1 -C headless/builds/linux CONFIG=$(CONFIG) SIMDFLAGS="$(SIMDFLAGS)" GLFLAGS="$(GLFLAGS)" BUILD_DATE=$(BUILD_DATE) LIBS="-lstdc++fs" LDFLAGS="-L$(PYTHONLIBPATH)" CXXFLAGS="-I$(PYTHONINCLUDEPATH)"
cp headless/builds/linux/build/libvita.so tests/vita.so
strip --strip-unneeded tests/vita.so
cp tests/vita.so vita/vita.so
test:
$(MAKE) -C tests/builds/linux CONFIG=$(CONFIG) SIMDFLAGS="$(SIMDFLAGS)" GLFLAGS="$(GLFLAGS)" BUILD_DATE=$(BUILD_DATE)
clean:
$(MAKE) clean -C standalone/builds/linux CONFIG=$(CONFIG)
$(MAKE) clean -C plugin/builds/linux_vst CONFIG=$(CONFIG)
$(MAKE) clean -C plugin/builds/linux_lv2 CONFIG=$(CONFIG)
$(MAKE) clean -C effects/builds/linux_vst CONFIG=$(CONFIG)
$(MAKE) clean -C effects/builds/linux_lv2 CONFIG=$(CONFIG)
# $(MAKE) clean -C standalone/builds/linux CONFIG=$(CONFIG)
# $(MAKE) clean -C plugin/builds/linux_vst CONFIG=$(CONFIG)
# $(MAKE) clean -C plugin/builds/linux_lv2 CONFIG=$(CONFIG)
# $(MAKE) clean -C effects/builds/linux_vst CONFIG=$(CONFIG)
# $(MAKE) clean -C effects/builds/linux_lv2 CONFIG=$(CONFIG)
$(MAKE) clean -C headless/builds/linux CONFIG=$(CONFIG)
$(MAKE) clean -C tests/builds/linux CONFIG=$(CONFIG)
# $(MAKE) clean -C tests/builds/linux CONFIG=$(CONFIG)
install_standalone: standalone install_icons
install -d $(BIN) $(MAN) $(CHANGES) $(DESKTOP)

View file

@ -1,23 +1,82 @@
# Vital
Vital is a spectral warping wavetable synthesizer. This is the source.
# Vita
This repository is updated on a delay after binary releases.
Vita is a Python module for interacting with the [Vital Synthesizer](https://github.com/mtytel/vital). **It is not an official product related to Vital**.
## Code Licensing
## Installation
Vita is supported on Linux, macOS, and Windows. Install with `pip`:
```bash
pip install vita
```
## Example
```python
from scipy.io import wavfile
import vita
SAMPLE_RATE = 44_100
bpm = 120.0
note_dur = 1.0
render_dur = 3.0
pitch = 36 # integer
velocity = 0.7 # [0.0 to 1.0]
synth = vita.Synth()
# The initial preset is loaded by default.
synth.set_bpm(bpm)
# Let's make a custom modulation using
# the available modulation sources and destinations.
# These lists are constant.
print("potential sources:", vita.get_modulation_sources())
print("potential destinations:", vita.get_modulation_destinations())
# "lfo_1" and "filter_1_cutoff" are potential sources and destinations.
assert synth.connect_modulation("lfo_1", "filter_1_cutoff")
controls = synth.get_controls()
controls["modulation_1_amount"].set(1.0)
controls["filter_1_on"].set(1.0)
controls["lfo_1_tempo"].set(vita.constants.SyncedFrequency.k1_16)
# Render audio to numpy array shaped (2, NUM_SAMPLES)
audio = synth.render(pitch, velocity, note_dur, render_dur)
wavfile.write("generated_preset.wav", SAMPLE_RATE, audio.T)
# Dump current state to JSON text
preset_path = "generated_preset.vital"
json_text = synth.to_json()
with open(preset_path, "w") as f:
f.write(json_text)
# Load JSON text
with open(preset_path, "r") as f:
json_text = f.read()
assert synth.load_json(json_text)
# Or load directly from file
assert synth.load_preset(preset_path)
# Load the initial preset, which also clears modulations
synth.load_init_preset()
# Or just clear modulations.
synth.clear_modulations()
```
### Issues
If you find any issues with the code, report them at https://github.com/DBraun/Vita.
### Code Licensing
If you are making a proprietary or closed source app and would like to use Vital's source code, contact licensing@vital.audio for non GPLv3 licensing options.
## Installing
Create an account and download Vital at [vital.audio](https://vital.audio)
## Issues
Report bugs (e.g.non-code and non-compiling issues) to https://forum.vital.audio
Feel free to report issues on building/compiling here but note that I'm not prioritizing them.
## Pull requests
I will not take any pull requests.
## What can you do with the source
### What can you do with the source
The source code is licensed under the GPLv3. If you download the source or create builds you must comply with that license.
### Things you can't do with this source

18
build_linux.sh Normal file
View file

@ -0,0 +1,18 @@
echo "PYTHONLIBPATH: $PYTHONLIBPATH"
echo "PYTHONINCLUDEPATH: $PYTHONINCLUDEPATH"
echo "LIBDIR: $LIBDIR"
yum install -y \
libsndfile \
libsndfile-devel
echo "Build Nanobind"
cd third_party/nanobind
git submodule update --init --recursive
cmake -S . -B build -DCMAKE_POSITION_INDEPENDENT_CODE=ON
cmake --build build
cd ../..
make headless_server
echo "build_linux.sh is done!"

42
build_macos.sh Normal file
View file

@ -0,0 +1,42 @@
if [ -z "$PYTHONMAJOR" ]; then
echo "Build failed. You must set the environment variable PYTHONMAJOR to a value such as 3.11"
exit 1
fi
if [ -z "$pythonLocation" ]; then
echo "Build failed. You must set the environment variable pythonLocation to a value such as /Library/Frameworks/Python.framework/Versions/3.11"
exit 1
fi
# if [[ $(uname -m) == 'arm64' ]]; then
# export ARCHS="arm64"
# export CFLAGS="-arch arm64"
# export ARCHFLAGS="-arch arm64"
# else
# export ARCHS="x86_64"
# export CFLAGS="-arch x86_64"
# export ARCHFLAGS="-arch x86_64"
# fi
# build Nanobind
cd third_party/nanobind
git submodule update --init --recursive
cmake -S . -B build
cmake --build build
cd ../..
# build macOS release
xcodebuild ONLY_ACTIVE_ARCH=NO -configuration Release -project headless/builds/osx/Vita.xcodeproj/ CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED="NO" CODE_SIGN_ENTITLEMENTS="" CODE_SIGNING_ALLOWED="NO"
mv headless/builds/osx/build/Release/vita.so.dylib headless/builds/osx/build/Release/vita.so
rm tests/vita.so
cp headless/builds/osx/build/Release/vita.so tests/vita.so
# # To make a wheel locally:
# pip install setuptools wheel build delocate
# python3 -m build --wheel
# delocate-listdeps dist/vita-0.0.1-cp311-cp311-macosx_10_15_universal2.whl
# delocate-wheel --require-archs x86_64 -w repaired_wheel dist/vita-0.0.1-cp311-cp311-macosx_10_15_universal2.whl
# pip install repaired_wheel/vita-0.0.1-cp311-cp311-macosx_10_15_universal2.whl
# cd tests
# python -m pytest -s .

View file

@ -20,30 +20,7 @@
// [END_USER_CODE_SECTION]
/*
==============================================================================
In accordance with the terms of the JUCE 6 End-Use License Agreement, the
JUCE Code in SECTION A cannot be removed, changed or otherwise rendered
ineffective unless you have a JUCE Indie or Pro license, or are using JUCE
under the GPL v3 license.
End User License Agreement: www.juce.com/juce-6-licence
==============================================================================
*/
// BEGIN SECTION A
#ifndef JUCE_DISPLAY_SPLASH_SCREEN
#define JUCE_DISPLAY_SPLASH_SCREEN 0
#endif
// END SECTION A
#define JUCE_USE_DARK_SPLASH_SCREEN 1
#define JUCE_PROJUCER_VERSION 0x60005
#define JUCE_PROJUCER_VERSION 0x80004
//==============================================================================
#define JUCE_MODULE_AVAILABLE_juce_audio_basics 1
@ -102,7 +79,7 @@
#endif
#ifndef JUCE_USE_CURL
#define JUCE_USE_CURL 1
#define JUCE_USE_CURL 0
#endif
#ifndef JUCE_LOAD_CURL_SYMBOLS_LAZILY
@ -160,6 +137,6 @@
#if defined(JucePlugin_Name) && defined(JucePlugin_Build_Standalone)
#define JUCE_STANDALONE_APPLICATION JucePlugin_Build_Standalone
#else
#define JUCE_STANDALONE_APPLICATION 1
#define JUCE_STANDALONE_APPLICATION 0
#endif
#endif

View file

@ -26,7 +26,7 @@
/** If you've hit this error then the version of the Projucer that was used to generate this project is
older than the version of the JUCE modules being included. To fix this error, re-save your project
using the latest version of the Projucer or, if you aren't using the Projucer to manage your project,
remove the JUCE_PROJUCER_VERSION define from the AppConfig.h file.
remove the JUCE_PROJUCER_VERSION define.
*/
#error "This project was last saved using an outdated version of the Projucer! Re-save this project with the latest version to fix this error."
#endif
@ -40,8 +40,8 @@
#if ! JUCE_DONT_DECLARE_PROJECTINFO
namespace ProjectInfo
{
const char* const projectName = "Vital";
const char* const companyName = "Matt Tytel";
const char* const projectName = "Vita";
const char* const companyName = "";
const char* const versionString = "99999.9.9";
const int versionNumber = 0x869f0909;
}

View file

@ -0,0 +1,21 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio Version 17
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vita - Dynamic Library", "Vita_DynamicLibrary.vcxproj", "{41660EB1-C0C6-734A-3560-3AAEEFA3048B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{41660EB1-C0C6-734A-3560-3AAEEFA3048B}.Debug|x64.ActiveCfg = Debug|x64
{41660EB1-C0C6-734A-3560-3AAEEFA3048B}.Debug|x64.Build.0 = Debug|x64
{41660EB1-C0C6-734A-3560-3AAEEFA3048B}.Release|x64.ActiveCfg = Release|x64
{41660EB1-C0C6-734A-3560-3AAEEFA3048B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
#pragma code_page(65001)
#ifdef JUCE_USER_DEFINED_RC_FILE
#include JUCE_USER_DEFINED_RC_FILE
#else
#undef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 99999,9,9,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "FileDescription", "Vita\0"
VALUE "FileVersion", "99999.9.9\0"
VALUE "ProductName", "Vita\0"
VALUE "ProductVersion", "99999.9.9\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
#endif

View file

@ -11,6 +11,10 @@ endif
# (this disables dependency generation if multiple architectures are set)
DEPFLAGS := $(if $(word 2, $(TARGET_ARCH)), , -MMD)
ifndef PKG_CONFIG
PKG_CONFIG=pkg-config
endif
ifndef STRIP
STRIP=strip
endif
@ -35,15 +39,17 @@ ifeq ($(CONFIG),Debug)
TARGET_ARCH :=
endif
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DBUILD_DATE=$(BUILD_DATE)" "-DJUCE_JACK_CLIENT_NAME=\"Vital\"" "-DJUCE_ALSA_MIDI_INPUT_NAME=\"Vital\"" "-DJUCE_ALSA_MIDI_OUTPUT_NAME=\"Vital\"" "-DJUCE_USE_XRANDR=0" "-DJUCE_DSP_USE_SHARED_FFTW=1" "-DHEADLESS=1" "-DNO_AUTH=1" "-DJUCER_LINUX_MAKE_6B3E762A=1" "-DJUCE_APP_VERSION=99999.9.9" "-DJUCE_APP_VERSION_HEX=0x869f0909" $(shell pkg-config --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../third_party/JUCE/modules -I../../../src/common -I../../../src/common/wavetable -I../../../src/interface/editor_components -I../../../src/interface/editor_sections -I../../../src/interface/look_and_feel -I../../../src/interface/wavetable -I../../../src/interface/wavetable/editors -I../../../src/interface/wavetable/overlays -I../../../src/standalone -I../../../src/synthesis/synth_engine -I../../../src/synthesis/effects -I../../../src/synthesis/filters -I../../../src/synthesis/framework -I../../../src/synthesis/lookups -I../../../src/synthesis/modulators -I../../../src/synthesis/modules -I../../../src/synthesis/producers -I../../../src/synthesis/utilities -I../../../third_party $(CPPFLAGS)
JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_RTAS=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0"
JUCE_TARGET_APP := vital
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DBUILD_DATE=$(BUILD_DATE)" "-DJUCE_JACK_CLIENT_NAME=\"Vita\"" "-DJUCE_ALSA_MIDI_INPUT_NAME=\"Vita\"" "-DJUCE_ALSA_MIDI_OUTPUT_NAME=\"Vita\"" "-DJUCE_USE_XRANDR=0" "-DJUCE_DSP_USE_SHARED_FFTW=1" "-DHEADLESS=1" "-DNO_AUTH=1" "-DJUCER_LINUX_MAKE_6B3E762A=1" "-DJUCE_APP_VERSION=99999.9.9" "-DJUCE_APP_VERSION_HEX=0x869f0909" -pthread -I../../JuceLibraryCode -I../../../third_party/JUCE/modules -I../../../src/common -I../../../src/common/wavetable -I../../../src/interface/editor_components -I../../../src/interface/editor_sections -I../../../src/interface/look_and_feel -I../../../src/interface/wavetable -I../../../src/interface/wavetable/editors -I../../../src/interface/wavetable/overlays -I../../../src/standalone -I../../../src/synthesis/synth_engine -I../../../src/synthesis/effects -I../../../src/synthesis/filters -I../../../src/synthesis/framework -I../../../src/synthesis/lookups -I../../../src/synthesis/modulators -I../../../src/synthesis/modules -I../../../src/synthesis/producers -I../../../src/synthesis/utilities -I../../../third_party -I../../../third_party/nanobind/include $(CPPFLAGS)
JUCE_CPPFLAGS_DYNAMIC_LIBRARY := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
JUCE_CFLAGS_DYNAMIC_LIBRARY := -fPIC -fvisibility=hidden
JUCE_LDFLAGS_DYNAMIC_LIBRARY := -shared
JUCE_TARGET_DYNAMIC_LIBRARY := libvita.so
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -funroll-loops $(CFLAGS)
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++14 $(CXXFLAGS)
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) -L/usr/X11R6/lib/ $(shell pkg-config --libs libcurl) -fvisibility=hidden -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -lcurl -lrt -ldl -lpthread $(LDFLAGS)
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -fPIC -g -ggdb -O0 -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -funroll-loops -fPIC $(CFLAGS)
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS)
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) -L/usr/X11R6/lib/ -L../../../third_party/nanobind/build/tests -fvisibility=hidden -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -lrt -ldl -lpthread -lnanobind-static $(LDFLAGS)
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY) $(JUCE_OBJDIR)
endif
ifeq ($(CONFIG),Release)
@ -56,19 +62,21 @@ ifeq ($(CONFIG),Release)
TARGET_ARCH :=
endif
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DBUILD_DATE=$(BUILD_DATE)" "-DJUCE_JACK_CLIENT_NAME=\"Vital\"" "-DJUCE_ALSA_MIDI_INPUT_NAME=\"Vital\"" "-DJUCE_ALSA_MIDI_OUTPUT_NAME=\"Vital\"" "-DJUCE_USE_XRANDR=0" "-DJUCE_DSP_USE_SHARED_FFTW=1" "-DHEADLESS=1" "-DNO_AUTH=1" "-DJUCER_LINUX_MAKE_6B3E762A=1" "-DJUCE_APP_VERSION=99999.9.9" "-DJUCE_APP_VERSION_HEX=0x869f0909" $(shell pkg-config --cflags libcurl) -pthread -I../../JuceLibraryCode -I../../../third_party/JUCE/modules -I../../../src/common -I../../../src/common/wavetable -I../../../src/interface/editor_components -I../../../src/interface/editor_sections -I../../../src/interface/look_and_feel -I../../../src/interface/wavetable -I../../../src/interface/wavetable/editors -I../../../src/interface/wavetable/overlays -I../../../src/standalone -I../../../src/synthesis/synth_engine -I../../../src/synthesis/effects -I../../../src/synthesis/filters -I../../../src/synthesis/framework -I../../../src/synthesis/lookups -I../../../src/synthesis/modulators -I../../../src/synthesis/modules -I../../../src/synthesis/producers -I../../../src/synthesis/utilities -I../../../third_party $(CPPFLAGS)
JUCE_CPPFLAGS_APP := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_RTAS=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0"
JUCE_TARGET_APP := vital
JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DBUILD_DATE=$(BUILD_DATE)" "-DJUCE_JACK_CLIENT_NAME=\"Vita\"" "-DJUCE_ALSA_MIDI_INPUT_NAME=\"Vita\"" "-DJUCE_ALSA_MIDI_OUTPUT_NAME=\"Vita\"" "-DJUCE_USE_XRANDR=0" "-DJUCE_DSP_USE_SHARED_FFTW=1" "-DHEADLESS=1" "-DNO_AUTH=1" "-DJUCER_LINUX_MAKE_6B3E762A=1" "-DJUCE_APP_VERSION=99999.9.9" "-DJUCE_APP_VERSION_HEX=0x869f0909" -pthread -I../../JuceLibraryCode -I../../../third_party/JUCE/modules -I../../../src/common -I../../../src/common/wavetable -I../../../src/interface/editor_components -I../../../src/interface/editor_sections -I../../../src/interface/look_and_feel -I../../../src/interface/wavetable -I../../../src/interface/wavetable/editors -I../../../src/interface/wavetable/overlays -I../../../src/standalone -I../../../src/synthesis/synth_engine -I../../../src/synthesis/effects -I../../../src/synthesis/filters -I../../../src/synthesis/framework -I../../../src/synthesis/lookups -I../../../src/synthesis/modulators -I../../../src/synthesis/modules -I../../../src/synthesis/producers -I../../../src/synthesis/utilities -I../../../third_party -I../../../third_party/nanobind/include $(CPPFLAGS)
JUCE_CPPFLAGS_DYNAMIC_LIBRARY := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
JUCE_CFLAGS_DYNAMIC_LIBRARY := -fPIC -fvisibility=hidden
JUCE_LDFLAGS_DYNAMIC_LIBRARY := -shared
JUCE_TARGET_DYNAMIC_LIBRARY := libvita.so
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -Ofast -flto -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -funroll-loops $(CFLAGS)
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++14 $(CXXFLAGS)
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) -L/usr/X11R6/lib/ $(shell pkg-config --libs libcurl) -fvisibility=hidden -flto -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -lcurl -lrt -ldl -lpthread $(LDFLAGS)
JUCE_CFLAGS += $(JUCE_CPPFLAGS) $(TARGET_ARCH) -fPIC -Ofast -flto -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -funroll-loops -fPIC $(CFLAGS)
JUCE_CXXFLAGS += $(JUCE_CFLAGS) -std=c++17 $(CXXFLAGS)
JUCE_LDFLAGS += $(TARGET_ARCH) -L$(JUCE_BINDIR) -L$(JUCE_LIBDIR) -L/usr/X11R6/lib/ -L../../../third_party/nanobind/build/tests -fvisibility=hidden -flto -ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -lrt -ldl -lpthread -lnanobind-static $(LDFLAGS)
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(TARGET) $(JUCE_OBJDIR)
CLEANCMD = rm -rf $(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY) $(JUCE_OBJDIR)
endif
OBJECTS_APP := \
$(JUCE_OBJDIR)/main_f0db04ea.o \
OBJECTS_DYNAMIC_LIBRARY := \
$(JUCE_OBJDIR)/bindings_c58fd13f.o \
$(JUCE_OBJDIR)/common_24cbed85.o \
$(JUCE_OBJDIR)/synthesis_1ee447c4.o \
$(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o \
@ -80,68 +88,76 @@ OBJECTS_APP := \
.PHONY: clean all strip
all : $(JUCE_OUTDIR)/$(JUCE_TARGET_APP)
all : $(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY)
$(JUCE_OUTDIR)/$(JUCE_TARGET_APP) : $(OBJECTS_APP) $(RESOURCES)
@command -v pkg-config >/dev/null 2>&1 || { echo >&2 "pkg-config not installed. Please, install it."; exit 1; }
@pkg-config --print-errors libcurl
@echo Linking "Vital - App"
$(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY) : $(OBJECTS_DYNAMIC_LIBRARY) $(JUCE_OBJDIR)/execinfo.cmd $(RESOURCES)
@echo Linking "Vita - Dynamic Library"
-$(V_AT)mkdir -p $(JUCE_BINDIR)
-$(V_AT)mkdir -p $(JUCE_LIBDIR)
-$(V_AT)mkdir -p $(JUCE_OUTDIR)
$(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_APP) $(OBJECTS_APP) $(JUCE_LDFLAGS) $(JUCE_LDFLAGS_APP) $(RESOURCES) $(TARGET_ARCH)
$(V_AT)$(CXX) -o $(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY) $(OBJECTS_DYNAMIC_LIBRARY) $(JUCE_LDFLAGS) $(shell cat $(JUCE_OBJDIR)/execinfo.cmd) $(JUCE_LDFLAGS_DYNAMIC_LIBRARY) $(RESOURCES) $(TARGET_ARCH)
$(JUCE_OBJDIR)/main_f0db04ea.o: ../../../src/headless/main.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
@echo "Compiling main.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(JUCE_OBJDIR)/bindings_c58fd13f.o: ../../../src/headless/bindings.cpp
-$(V_AT)mkdir -p $(@D)
@echo "Compiling bindings.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/common_24cbed85.o: ../../../src/unity_build/common.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling common.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/synthesis_1ee447c4.o: ../../../src/unity_build/synthesis.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling synthesis.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_audio_basics_8a4e984a.o: ../../JuceLibraryCode/include_juce_audio_basics.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_audio_basics.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_audio_formats_15f82001.o: ../../JuceLibraryCode/include_juce_audio_formats.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_audio_formats.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_core_f26d17db.o: ../../JuceLibraryCode/include_juce_core.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_core.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_data_structures_7471b1e3.o: ../../JuceLibraryCode/include_juce_data_structures.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_data_structures.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_dsp_aeb2060f.o: ../../JuceLibraryCode/include_juce_dsp.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_dsp.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/include_juce_events_fd7d695.o: ../../JuceLibraryCode/include_juce_events.cpp
-$(V_AT)mkdir -p $(JUCE_OBJDIR)
-$(V_AT)mkdir -p $(@D)
@echo "Compiling include_juce_events.cpp"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_APP) $(JUCE_CFLAGS_APP) -o "$@" -c "$<"
$(V_AT)$(CXX) $(JUCE_CXXFLAGS) $(JUCE_CPPFLAGS_DYNAMIC_LIBRARY) $(JUCE_CFLAGS_DYNAMIC_LIBRARY) -o "$@" -c "$<"
$(JUCE_OBJDIR)/execinfo.cmd:
-$(V_AT)mkdir -p $(@D)
-@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link libexecinfo"; fi
$(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/execinfo.x -lexecinfo - >/dev/null 2>&1 && printf -- "-lexecinfo" > "$@" || touch "$@"
$(JUCE_OBJDIR)/cxxfs.cmd:
-$(V_AT)mkdir -p $(@D)
-@if [ -z "$(V_AT)" ]; then echo "Checking if we need to link stdc++fs"; fi
$(V_AT)printf "int main() { return 0; }" | $(CXX) -x c++ -o $(@D)/cxxfs.x -lstdc++fs - >/dev/null 2>&1 && printf -- "-lstdc++fs" > "$@" || touch "$@"
clean:
@echo Cleaning Vital
@echo Cleaning Vita
$(V_AT)$(CLEANCMD)
strip:
@echo Stripping Vital
-$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(TARGET)
@echo Stripping Vita
-$(V_AT)$(STRIP) --strip-unneeded $(JUCE_OUTDIR)/$(JUCE_TARGET_DYNAMIC_LIBRARY)
-include $(OBJECTS_APP:%.o=%.d)
-include $(OBJECTS_DYNAMIC_LIBRARY:%.o=%.d)

File diff suppressed because it is too large Load diff

411
headless/vita.jucer Normal file
View file

@ -0,0 +1,411 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="GfsdNK" name="Vita" projectType="dll" version="99999.9.9"
bundleIdentifier="design.dirt.Vita" includeBinaryInAppConfig="1"
defines="" reportAppUsage="0" splashScreenColour="Dark" jucerFormatVersion="1"
headerPath="../../../src/common&#10;../../../src/common/wavetable&#10;../../../src/interface/editor_components&#10;../../../src/interface/editor_sections&#10;../../../src/interface/look_and_feel&#10;../../../src/interface/wavetable&#10;../../../src/interface/wavetable/editors&#10;../../../src/interface/wavetable/overlays&#10;../../../src/standalone&#10;../../../src/synthesis/synth_engine&#10;../../../src/synthesis/effects&#10;../../../src/synthesis/filters&#10;../../../src/synthesis/framework&#10;../../../src/synthesis/lookups&#10;../../../src/synthesis/modulators&#10;../../../src/synthesis/modules&#10;../../../src/synthesis/producers&#10;../../../src/synthesis/utilities&#10;../../../third_party&#10;../../../third_party/nanobind/include"
displaySplashScreen="1">
<MAINGROUP id="CeypXq" name="Vita">
<GROUP id="{5E20F1A0-5E75-7060-2F6C-FA57FB1890B9}" name="src">
<GROUP id="{24238426-E22D-9B0B-53E8-F1FE2E36A406}" name="common">
<GROUP id="{4ABC3884-D1B2-B9F8-BBBE-13809C729B01}" name="wavetable">
<FILE id="oe6zDB" name="file_source.cpp" compile="0" resource="0" file="../src/common/wavetable/file_source.cpp"/>
<FILE id="PNqFcj" name="file_source.h" compile="0" resource="0" file="../src/common/wavetable/file_source.h"/>
<FILE id="KdwN2l" name="frequency_filter_modifier.cpp" compile="0"
resource="0" file="../src/common/wavetable/frequency_filter_modifier.cpp"/>
<FILE id="jUH4x2" name="frequency_filter_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/frequency_filter_modifier.h"/>
<FILE id="EeWkLu" name="phase_modifier.cpp" compile="0" resource="0"
file="../src/common/wavetable/phase_modifier.cpp"/>
<FILE id="evrRrr" name="phase_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/phase_modifier.h"/>
<FILE id="EE6gxY" name="pitch_detector.cpp" compile="0" resource="0"
file="../src/common/wavetable/pitch_detector.cpp"/>
<FILE id="ICq0kR" name="pitch_detector.h" compile="0" resource="0"
file="../src/common/wavetable/pitch_detector.h"/>
<FILE id="eanv2x" name="shepard_tone_source.cpp" compile="0" resource="0"
file="../src/common/wavetable/shepard_tone_source.cpp"/>
<FILE id="r9ixAB" name="shepard_tone_source.h" compile="0" resource="0"
file="../src/common/wavetable/shepard_tone_source.h"/>
<FILE id="NSw3FK" name="slew_limit_modifier.cpp" compile="0" resource="0"
file="../src/common/wavetable/slew_limit_modifier.cpp"/>
<FILE id="oY7wsX" name="slew_limit_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/slew_limit_modifier.h"/>
<FILE id="xezXym" name="wave_fold_modifier.cpp" compile="0" resource="0"
file="../src/common/wavetable/wave_fold_modifier.cpp"/>
<FILE id="mbOjU5" name="wave_fold_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/wave_fold_modifier.h"/>
<FILE id="xXN8oh" name="wave_line_source.cpp" compile="0" resource="0"
file="../src/common/wavetable/wave_line_source.cpp"/>
<FILE id="SqTW26" name="wave_line_source.h" compile="0" resource="0"
file="../src/common/wavetable/wave_line_source.h"/>
<FILE id="Trqfzt" name="wave_source.cpp" compile="0" resource="0" file="../src/common/wavetable/wave_source.cpp"/>
<FILE id="LnOIlK" name="wave_source.h" compile="0" resource="0" file="../src/common/wavetable/wave_source.h"/>
<FILE id="S5enhN" name="wave_warp_modifier.cpp" compile="0" resource="0"
file="../src/common/wavetable/wave_warp_modifier.cpp"/>
<FILE id="txcV3N" name="wave_warp_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/wave_warp_modifier.h"/>
<FILE id="sSIrCT" name="wave_window_modifier.cpp" compile="0" resource="0"
file="../src/common/wavetable/wave_window_modifier.cpp"/>
<FILE id="QpecXl" name="wave_window_modifier.h" compile="0" resource="0"
file="../src/common/wavetable/wave_window_modifier.h"/>
<FILE id="BBS3SC" name="wavetable_component.cpp" compile="0" resource="0"
file="../src/common/wavetable/wavetable_component.cpp"/>
<FILE id="GjVmR5" name="wavetable_component.h" compile="0" resource="0"
file="../src/common/wavetable/wavetable_component.h"/>
<FILE id="EC6VRW" name="wavetable_component_factory.cpp" compile="0"
resource="0" file="../src/common/wavetable/wavetable_component_factory.cpp"/>
<FILE id="mLuOfy" name="wavetable_component_factory.h" compile="0"
resource="0" file="../src/common/wavetable/wavetable_component_factory.h"/>
<FILE id="lIeQfH" name="wavetable_creator.cpp" compile="0" resource="0"
file="../src/common/wavetable/wavetable_creator.cpp"/>
<FILE id="xrhpt4" name="wavetable_creator.h" compile="0" resource="0"
file="../src/common/wavetable/wavetable_creator.h"/>
<FILE id="ttfQpv" name="wavetable_group.cpp" compile="0" resource="0"
file="../src/common/wavetable/wavetable_group.cpp"/>
<FILE id="i84L1E" name="wavetable_group.h" compile="0" resource="0"
file="../src/common/wavetable/wavetable_group.h"/>
<FILE id="loSZ0a" name="wavetable_keyframe.cpp" compile="0" resource="0"
file="../src/common/wavetable/wavetable_keyframe.cpp"/>
<FILE id="gncjoq" name="wavetable_keyframe.h" compile="0" resource="0"
file="../src/common/wavetable/wavetable_keyframe.h"/>
</GROUP>
<FILE id="kZoVCz" name="border_bounds_constrainer.cpp" compile="0"
resource="0" file="../src/common/border_bounds_constrainer.cpp"/>
<FILE id="izwxRz" name="border_bounds_constrainer.h" compile="0" resource="0"
file="../src/common/border_bounds_constrainer.h"/>
<FILE id="O7P8do" name="fourier_transform.h" compile="0" resource="0"
file="../src/common/fourier_transform.h"/>
<FILE id="oqQjU3" name="line_generator.cpp" compile="0" resource="0"
file="../src/common/line_generator.cpp"/>
<FILE id="WochiB" name="line_generator.h" compile="0" resource="0"
file="../src/common/line_generator.h"/>
<FILE id="shXQuy" name="load_save.cpp" compile="0" resource="0" file="../src/common/load_save.cpp"/>
<FILE id="YsKDUQ" name="load_save.h" compile="0" resource="0" file="../src/common/load_save.h"/>
<FILE id="LN5QQ0" name="midi_manager.cpp" compile="0" resource="0"
file="../src/common/midi_manager.cpp"/>
<FILE id="sE0Jer" name="midi_manager.h" compile="0" resource="0" file="../src/common/midi_manager.h"/>
<FILE id="Xxn5pD" name="startup.cpp" compile="0" resource="0" file="../src/common/startup.cpp"/>
<FILE id="VY2QQ2" name="startup.h" compile="0" resource="0" file="../src/common/startup.h"/>
<FILE id="JLxUzB" name="synth_base.cpp" compile="0" resource="0" file="../src/common/synth_base.cpp"/>
<FILE id="FYbklc" name="synth_base.h" compile="0" resource="0" file="../src/common/synth_base.h"/>
<FILE id="pOB6Hr" name="synth_constants.h" compile="0" resource="0"
file="../src/common/synth_constants.h"/>
<FILE id="J88miL" name="synth_gui_interface.cpp" compile="0" resource="0"
file="../src/common/synth_gui_interface.cpp"/>
<FILE id="EURXvy" name="synth_gui_interface.h" compile="0" resource="0"
file="../src/common/synth_gui_interface.h"/>
<FILE id="V9u92v" name="synth_parameters.cpp" compile="0" resource="0"
file="../src/common/synth_parameters.cpp"/>
<FILE id="p1Q9zF" name="synth_parameters.h" compile="0" resource="0"
file="../src/common/synth_parameters.h"/>
<FILE id="uNVeO7" name="synth_types.cpp" compile="0" resource="0" file="../src/common/synth_types.cpp"/>
<FILE id="GjKj1E" name="synth_types.h" compile="0" resource="0" file="../src/common/synth_types.h"/>
<FILE id="xhXY3Q" name="tuning.cpp" compile="0" resource="0" file="../src/common/tuning.cpp"/>
<FILE id="hr0FmH" name="tuning.h" compile="0" resource="0" file="../src/common/tuning.h"/>
</GROUP>
<GROUP id="{994C5173-6686-7ED5-90AC-C96AACD31CB9}" name="headless">
<FILE id="wwfb66" name="bindings.cpp" compile="1" resource="0" file="../src/headless/bindings.cpp"/>
<FILE id="sp5m0v" name="main.cpp" compile="0" resource="0" file="../src/headless/main.cpp"/>
</GROUP>
<GROUP id="{A5C9FACE-F05D-CF5D-CF7D-2B2E3AAAC5C6}" name="synthesis">
<GROUP id="{5CFAF50C-54C0-50C0-7CC6-12E5173CC110}" name="effects">
<FILE id="aCNwJd" name="compressor.cpp" compile="0" resource="0" file="../src/synthesis/effects/compressor.cpp"/>
<FILE id="m8TLhD" name="compressor.h" compile="0" resource="0" file="../src/synthesis/effects/compressor.h"/>
<FILE id="sxlSiK" name="delay.cpp" compile="0" resource="0" file="../src/synthesis/effects/delay.cpp"/>
<FILE id="kTeDfB" name="delay.h" compile="0" resource="0" file="../src/synthesis/effects/delay.h"/>
<FILE id="y8R5gV" name="distortion.cpp" compile="0" resource="0" file="../src/synthesis/effects/distortion.cpp"/>
<FILE id="lAtVZz" name="distortion.h" compile="0" resource="0" file="../src/synthesis/effects/distortion.h"/>
<FILE id="YXzEAf" name="phaser.cpp" compile="0" resource="0" file="../src/synthesis/effects/phaser.cpp"/>
<FILE id="v4goRR" name="phaser.h" compile="0" resource="0" file="../src/synthesis/effects/phaser.h"/>
<FILE id="CJ0cmj" name="reverb.cpp" compile="0" resource="0" file="../src/synthesis/effects/reverb.cpp"/>
<FILE id="Tevudl" name="reverb.h" compile="0" resource="0" file="../src/synthesis/effects/reverb.h"/>
</GROUP>
<GROUP id="{E64E341B-EC07-8E8D-EDA9-A409B614FDF7}" name="filters">
<FILE id="lPtPzS" name="comb_filter.cpp" compile="0" resource="0" file="../src/synthesis/filters/comb_filter.cpp"/>
<FILE id="j5EId2" name="comb_filter.h" compile="0" resource="0" file="../src/synthesis/filters/comb_filter.h"/>
<FILE id="RIzg4Y" name="dc_filter.cpp" compile="0" resource="0" file="../src/synthesis/filters/dc_filter.cpp"/>
<FILE id="XpqKwH" name="dc_filter.h" compile="0" resource="0" file="../src/synthesis/filters/dc_filter.h"/>
<FILE id="y50aDm" name="decimator.cpp" compile="0" resource="0" file="../src/synthesis/filters/decimator.cpp"/>
<FILE id="MgJKf7" name="decimator.h" compile="0" resource="0" file="../src/synthesis/filters/decimator.h"/>
<FILE id="Jh9lo5" name="digital_svf.cpp" compile="0" resource="0" file="../src/synthesis/filters/digital_svf.cpp"/>
<FILE id="Hz7pGs" name="digital_svf.h" compile="0" resource="0" file="../src/synthesis/filters/digital_svf.h"/>
<FILE id="Efu2pW" name="diode_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/diode_filter.cpp"/>
<FILE id="R8kJxY" name="diode_filter.h" compile="0" resource="0" file="../src/synthesis/filters/diode_filter.h"/>
<FILE id="fRKKE7" name="dirty_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/dirty_filter.cpp"/>
<FILE id="Yhizwh" name="dirty_filter.h" compile="0" resource="0" file="../src/synthesis/filters/dirty_filter.h"/>
<FILE id="iFOzQV" name="fir_halfband_decimator.cpp" compile="0" resource="0"
file="../src/synthesis/filters/fir_halfband_decimator.cpp"/>
<FILE id="Gv6EpA" name="fir_halfband_decimator.h" compile="0" resource="0"
file="../src/synthesis/filters/fir_halfband_decimator.h"/>
<FILE id="TmxuEz" name="formant_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/formant_filter.cpp"/>
<FILE id="EMpV5T" name="formant_filter.h" compile="0" resource="0"
file="../src/synthesis/filters/formant_filter.h"/>
<FILE id="rzspcD" name="formant_manager.cpp" compile="0" resource="0"
file="../src/synthesis/filters/formant_manager.cpp"/>
<FILE id="EhTc2y" name="formant_manager.h" compile="0" resource="0"
file="../src/synthesis/filters/formant_manager.h"/>
<FILE id="w1i83Y" name="iir_halfband_decimator.cpp" compile="0" resource="0"
file="../src/synthesis/filters/iir_halfband_decimator.cpp"/>
<FILE id="ZfvMzK" name="iir_halfband_decimator.h" compile="0" resource="0"
file="../src/synthesis/filters/iir_halfband_decimator.h"/>
<FILE id="QJw5bc" name="ladder_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/ladder_filter.cpp"/>
<FILE id="XlAdkz" name="ladder_filter.h" compile="0" resource="0" file="../src/synthesis/filters/ladder_filter.h"/>
<FILE id="CMjLtN" name="linkwitz_riley_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/linkwitz_riley_filter.cpp"/>
<FILE id="ShoZK2" name="linkwitz_riley_filter.h" compile="0" resource="0"
file="../src/synthesis/filters/linkwitz_riley_filter.h"/>
<FILE id="u7SfJu" name="one_pole_filter.h" compile="0" resource="0"
file="../src/synthesis/filters/one_pole_filter.h"/>
<FILE id="TN4e3F" name="phaser_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/phaser_filter.cpp"/>
<FILE id="CXTqre" name="phaser_filter.h" compile="0" resource="0" file="../src/synthesis/filters/phaser_filter.h"/>
<FILE id="dXxyVr" name="sallen_key_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/sallen_key_filter.cpp"/>
<FILE id="Et5X2A" name="sallen_key_filter.h" compile="0" resource="0"
file="../src/synthesis/filters/sallen_key_filter.h"/>
<FILE id="cq1Bv6" name="synth_filter.cpp" compile="0" resource="0"
file="../src/synthesis/filters/synth_filter.cpp"/>
<FILE id="EEmVZX" name="synth_filter.h" compile="0" resource="0" file="../src/synthesis/filters/synth_filter.h"/>
</GROUP>
<GROUP id="{77B6F61E-3BFE-28DD-28BB-9F3780938AC4}" name="framework">
<FILE id="qHGm97" name="circular_queue.h" compile="0" resource="0"
file="../src/synthesis/framework/circular_queue.h"/>
<FILE id="HmdVGQ" name="common.h" compile="0" resource="0" file="../src/synthesis/framework/common.h"/>
<FILE id="IgLqPT" name="feedback.cpp" compile="0" resource="0" file="../src/synthesis/framework/feedback.cpp"/>
<FILE id="birmLJ" name="feedback.h" compile="0" resource="0" file="../src/synthesis/framework/feedback.h"/>
<FILE id="f7K13U" name="futils.h" compile="0" resource="0" file="../src/synthesis/framework/futils.h"/>
<FILE id="iCcsYn" name="matrix.h" compile="0" resource="0" file="../src/synthesis/framework/matrix.h"/>
<FILE id="OjPY4Y" name="note_handler.h" compile="0" resource="0" file="../src/synthesis/framework/note_handler.h"/>
<FILE id="ttUKze" name="operators.cpp" compile="0" resource="0" file="../src/synthesis/framework/operators.cpp"/>
<FILE id="iFcCHi" name="operators.h" compile="0" resource="0" file="../src/synthesis/framework/operators.h"/>
<FILE id="xFsi2z" name="poly_utils.h" compile="0" resource="0" file="../src/synthesis/framework/poly_utils.h"/>
<FILE id="rx7EqI" name="poly_values.h" compile="0" resource="0" file="../src/synthesis/framework/poly_values.h"/>
<FILE id="IWVKrn" name="processor.cpp" compile="0" resource="0" file="../src/synthesis/framework/processor.cpp"/>
<FILE id="yYEj6C" name="processor.h" compile="0" resource="0" file="../src/synthesis/framework/processor.h"/>
<FILE id="pEikV1" name="processor_router.cpp" compile="0" resource="0"
file="../src/synthesis/framework/processor_router.cpp"/>
<FILE id="xjyJUA" name="processor_router.h" compile="0" resource="0"
file="../src/synthesis/framework/processor_router.h"/>
<FILE id="V2hnUG" name="synth_module.cpp" compile="0" resource="0"
file="../src/synthesis/framework/synth_module.cpp"/>
<FILE id="LMO1qK" name="synth_module.h" compile="0" resource="0" file="../src/synthesis/framework/synth_module.h"/>
<FILE id="HtuRKh" name="utils.cpp" compile="0" resource="0" file="../src/synthesis/framework/utils.cpp"/>
<FILE id="JIQPrc" name="utils.h" compile="0" resource="0" file="../src/synthesis/framework/utils.h"/>
<FILE id="gXRMaO" name="value.cpp" compile="0" resource="0" file="../src/synthesis/framework/value.cpp"/>
<FILE id="hq4ULs" name="value.h" compile="0" resource="0" file="../src/synthesis/framework/value.h"/>
<FILE id="IHvsNC" name="voice_handler.cpp" compile="0" resource="0"
file="../src/synthesis/framework/voice_handler.cpp"/>
<FILE id="VQpRmA" name="voice_handler.h" compile="0" resource="0" file="../src/synthesis/framework/voice_handler.h"/>
</GROUP>
<GROUP id="{3DA70314-F7FB-917E-089C-A6DAFFF1A5FC}" name="lookups">
<FILE id="sXc1yd" name="lookup_table.h" compile="0" resource="0" file="../src/synthesis/lookups/lookup_table.h"/>
<FILE id="avsD8m" name="memory.h" compile="0" resource="0" file="../src/synthesis/lookups/memory.h"/>
<FILE id="PJfaJL" name="wave_frame.cpp" compile="0" resource="0" file="../src/synthesis/lookups/wave_frame.cpp"/>
<FILE id="ocfU1s" name="wave_frame.h" compile="0" resource="0" file="../src/synthesis/lookups/wave_frame.h"/>
<FILE id="IBeYrU" name="wavetable.cpp" compile="0" resource="0" file="../src/synthesis/lookups/wavetable.cpp"/>
<FILE id="Fc1QKT" name="wavetable.h" compile="0" resource="0" file="../src/synthesis/lookups/wavetable.h"/>
</GROUP>
<GROUP id="{D78B1446-F592-53F1-FC62-7D5C966375F2}" name="modulators">
<FILE id="XonX7g" name="envelope.cpp" compile="0" resource="0" file="../src/synthesis/modulators/envelope.cpp"/>
<FILE id="MLCOkP" name="envelope.h" compile="0" resource="0" file="../src/synthesis/modulators/envelope.h"/>
<FILE id="PSmy36" name="line_map.cpp" compile="0" resource="0" file="../src/synthesis/modulators/line_map.cpp"/>
<FILE id="EcfIJt" name="line_map.h" compile="0" resource="0" file="../src/synthesis/modulators/line_map.h"/>
<FILE id="zJmtl5" name="random_lfo.cpp" compile="0" resource="0" file="../src/synthesis/modulators/random_lfo.cpp"/>
<FILE id="bo3lkH" name="random_lfo.h" compile="0" resource="0" file="../src/synthesis/modulators/random_lfo.h"/>
<FILE id="Y3a60G" name="synth_lfo.cpp" compile="0" resource="0" file="../src/synthesis/modulators/synth_lfo.cpp"/>
<FILE id="iGi53L" name="synth_lfo.h" compile="0" resource="0" file="../src/synthesis/modulators/synth_lfo.h"/>
<FILE id="vanrpw" name="trigger_random.cpp" compile="0" resource="0"
file="../src/synthesis/modulators/trigger_random.cpp"/>
<FILE id="HiTq3x" name="trigger_random.h" compile="0" resource="0"
file="../src/synthesis/modulators/trigger_random.h"/>
</GROUP>
<GROUP id="{7AD7C86B-0DF8-2FF3-4B00-48E56A12CDD6}" name="modules">
<FILE id="YvP9VT" name="chorus_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/chorus_module.cpp"/>
<FILE id="WvrPiI" name="chorus_module.h" compile="0" resource="0" file="../src/synthesis/modules/chorus_module.h"/>
<FILE id="uH4eoI" name="comb_module.cpp" compile="0" resource="0" file="../src/synthesis/modules/comb_module.cpp"/>
<FILE id="mfYz3m" name="comb_module.h" compile="0" resource="0" file="../src/synthesis/modules/comb_module.h"/>
<FILE id="a4bXu6" name="compressor_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/compressor_module.cpp"/>
<FILE id="Lm66nP" name="compressor_module.h" compile="0" resource="0"
file="../src/synthesis/modules/compressor_module.h"/>
<FILE id="NOmCK3" name="delay_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/delay_module.cpp"/>
<FILE id="cJah2Y" name="delay_module.h" compile="0" resource="0" file="../src/synthesis/modules/delay_module.h"/>
<FILE id="AuUpM4" name="distortion_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/distortion_module.cpp"/>
<FILE id="xE2cXp" name="distortion_module.h" compile="0" resource="0"
file="../src/synthesis/modules/distortion_module.h"/>
<FILE id="GH1YXC" name="envelope_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/envelope_module.cpp"/>
<FILE id="g0ZUlf" name="envelope_module.h" compile="0" resource="0"
file="../src/synthesis/modules/envelope_module.h"/>
<FILE id="eenLYS" name="equalizer_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/equalizer_module.cpp"/>
<FILE id="P895N1" name="equalizer_module.h" compile="0" resource="0"
file="../src/synthesis/modules/equalizer_module.h"/>
<FILE id="L2p4rV" name="filter_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/filter_module.cpp"/>
<FILE id="JRQR6A" name="filter_module.h" compile="0" resource="0" file="../src/synthesis/modules/filter_module.h"/>
<FILE id="caguYj" name="filters_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/filters_module.cpp"/>
<FILE id="hSBDEw" name="filters_module.h" compile="0" resource="0"
file="../src/synthesis/modules/filters_module.h"/>
<FILE id="L5gTC7" name="flanger_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/flanger_module.cpp"/>
<FILE id="tkqRxb" name="flanger_module.h" compile="0" resource="0"
file="../src/synthesis/modules/flanger_module.h"/>
<FILE id="uR1p9q" name="formant_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/formant_module.cpp"/>
<FILE id="o2gMSE" name="formant_module.h" compile="0" resource="0"
file="../src/synthesis/modules/formant_module.h"/>
<FILE id="H1CKkp" name="lfo_module.cpp" compile="0" resource="0" file="../src/synthesis/modules/lfo_module.cpp"/>
<FILE id="wCtymg" name="lfo_module.h" compile="0" resource="0" file="../src/synthesis/modules/lfo_module.h"/>
<FILE id="Z6sUl0" name="modulation_connection_processor.cpp" compile="0"
resource="0" file="../src/synthesis/modules/modulation_connection_processor.cpp"/>
<FILE id="w5qtfY" name="modulation_connection_processor.h" compile="0"
resource="0" file="../src/synthesis/modules/modulation_connection_processor.h"/>
<FILE id="EhFVim" name="oscillator_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/oscillator_module.cpp"/>
<FILE id="RScZyn" name="oscillator_module.h" compile="0" resource="0"
file="../src/synthesis/modules/oscillator_module.h"/>
<FILE id="ly3McA" name="phaser_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/phaser_module.cpp"/>
<FILE id="Bxt5OJ" name="phaser_module.h" compile="0" resource="0" file="../src/synthesis/modules/phaser_module.h"/>
<FILE id="eWReLf" name="producers_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/producers_module.cpp"/>
<FILE id="z5wG4V" name="producers_module.h" compile="0" resource="0"
file="../src/synthesis/modules/producers_module.h"/>
<FILE id="ag0jZx" name="random_lfo_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/random_lfo_module.cpp"/>
<FILE id="mjELIt" name="random_lfo_module.h" compile="0" resource="0"
file="../src/synthesis/modules/random_lfo_module.h"/>
<FILE id="d7nvCd" name="reorderable_effect_chain.cpp" compile="0" resource="0"
file="../src/synthesis/modules/reorderable_effect_chain.cpp"/>
<FILE id="hbv7nz" name="reorderable_effect_chain.h" compile="0" resource="0"
file="../src/synthesis/modules/reorderable_effect_chain.h"/>
<FILE id="vyagYY" name="reverb_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/reverb_module.cpp"/>
<FILE id="xfYwSE" name="reverb_module.h" compile="0" resource="0" file="../src/synthesis/modules/reverb_module.h"/>
<FILE id="y9GvZL" name="sample_module.cpp" compile="0" resource="0"
file="../src/synthesis/modules/sample_module.cpp"/>
<FILE id="ayVUKi" name="sample_module.h" compile="0" resource="0" file="../src/synthesis/modules/sample_module.h"/>
</GROUP>
<GROUP id="{1F81E4BF-5696-7696-7E95-7AA0E119A748}" name="producers">
<FILE id="k2LDTh" name="sample_source.cpp" compile="0" resource="0"
file="../src/synthesis/producers/sample_source.cpp"/>
<FILE id="mZfVF9" name="sample_source.h" compile="0" resource="0" file="../src/synthesis/producers/sample_source.h"/>
<FILE id="kyMr1d" name="synth_oscillator.cpp" compile="0" resource="0"
file="../src/synthesis/producers/synth_oscillator.cpp"/>
<FILE id="nehC8Y" name="synth_oscillator.h" compile="0" resource="0"
file="../src/synthesis/producers/synth_oscillator.h"/>
</GROUP>
<GROUP id="{48203804-B755-4600-7713-4492E108CDF6}" name="utilities">
<FILE id="Pile5u" name="legato_filter.cpp" compile="0" resource="0"
file="../src/synthesis/utilities/legato_filter.cpp"/>
<FILE id="hTumTZ" name="legato_filter.h" compile="0" resource="0" file="../src/synthesis/utilities/legato_filter.h"/>
<FILE id="E8XJvz" name="peak_meter.cpp" compile="0" resource="0" file="../src/synthesis/utilities/peak_meter.cpp"/>
<FILE id="fqz6b7" name="peak_meter.h" compile="0" resource="0" file="../src/synthesis/utilities/peak_meter.h"/>
<FILE id="nH8lht" name="portamento_slope.cpp" compile="0" resource="0"
file="../src/synthesis/utilities/portamento_slope.cpp"/>
<FILE id="xminR9" name="portamento_slope.h" compile="0" resource="0"
file="../src/synthesis/utilities/portamento_slope.h"/>
<FILE id="E9KdfW" name="smooth_value.cpp" compile="0" resource="0"
file="../src/synthesis/utilities/smooth_value.cpp"/>
<FILE id="JKOlA3" name="smooth_value.h" compile="0" resource="0" file="../src/synthesis/utilities/smooth_value.h"/>
<FILE id="lB9jFO" name="value_switch.cpp" compile="0" resource="0"
file="../src/synthesis/utilities/value_switch.cpp"/>
<FILE id="chFZdz" name="value_switch.h" compile="0" resource="0" file="../src/synthesis/utilities/value_switch.h"/>
</GROUP>
</GROUP>
<GROUP id="{7156E271-CE4F-69F7-BD16-1AE4D1B568AC}" name="unity_build">
<FILE id="ykH5qq" name="common.cpp" compile="1" resource="0" file="../src/unity_build/common.cpp"/>
<FILE id="Hh2SQe" name="synthesis.cpp" compile="1" resource="0" file="../src/unity_build/synthesis.cpp"/>
</GROUP>
</GROUP>
</MAINGROUP>
<EXPORTFORMATS>
<LINUX_MAKE targetFolder="builds/linux" bigIcon="JqKIEw" smallIcon="oFf3hH"
extraCompilerFlags="-ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize -funroll-loops -fPIC"
extraLinkerFlags="-ffast-math ${SIMDFLAGS} ${GLFLAGS} -ftree-vectorize -ftree-slp-vectorize"
extraDefs="BUILD_DATE=$(BUILD_DATE)&#10;JUCE_JACK_CLIENT_NAME=&quot;Vita&quot;&#10;JUCE_ALSA_MIDI_INPUT_NAME=&quot;Vita&quot;&#10;JUCE_ALSA_MIDI_OUTPUT_NAME=&quot;Vita&quot;&#10;JUCE_USE_XRANDR=0&#10;JUCE_DSP_USE_SHARED_FFTW=1&#10;HEADLESS=1&#10;NO_AUTH=1"
externalLibraries="nanobind-static">
<CONFIGURATIONS>
<CONFIGURATION name="Debug" libraryPath="/usr/X11R6/lib/&#10;../../../third_party/nanobind/build/tests"
isDebug="1" optimisation="1" targetName="vita" linuxArchitecture=""
defines=""/>
<CONFIGURATION name="Release" libraryPath="/usr/X11R6/lib/&#10;../../../third_party/nanobind/build/tests"
isDebug="0" optimisation="6" targetName="vita" linuxArchitecture=""
defines="" linkTimeOptimisation="1"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_core" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_events" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_data_structures" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_audio_basics" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_audio_formats" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_dsp" path="../third_party/JUCE/modules"/>
</MODULEPATHS>
</LINUX_MAKE>
<XCODE_MAC targetFolder="builds/osx" extraDefs="HEADLESS=1&#10;NO_AUTH=1"
xcodeValidArchs="arm64,x86_64" extraLinkerFlags="-shared -Wl,-undefined,dynamic_lookup"
extraCompilerFlags="-fPIC" externalLibraries="nanobind-static">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" osxCompatibility="11.0 SDK" macOSDeploymentTarget="11.0"
targetName="vita.so" headerPath="$(pythonLocation)/include/python$(PYTHONMAJOR);"
libraryPath="$(pythonLocation)/lib&#10;../../../third_party/nanobind/build/tests&#10;../../../third_party/libfaust/darwin-x64/Release/lib&#10;../../../third_party/libsamplerate/build_release/src"/>
<CONFIGURATION isDebug="0" name="Release" optimisation="6" targetName="vita.so"
headerPath="$(pythonLocation)/include/python$(PYTHONMAJOR);"
libraryPath="$(pythonLocation)/lib&#10;../../../third_party/nanobind/build/tests&#10;../../../third_party/libfaust/darwin-x64/Release/lib&#10;../../../third_party/libsamplerate/build_release/src"
macOSDeploymentTarget="11.0" osxCompatibility="11.0 SDK"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_events" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_dsp" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_data_structures" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_core" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_audio_formats" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_audio_basics" path="../third_party/JUCE/modules"/>
</MODULEPATHS>
</XCODE_MAC>
<VS2022 targetFolder="builds/VisualStudio2022" externalLibraries="nanobind-static.lib"
extraDefs="HEADLESS=1&#10;NO_AUTH=1&#10;__SSE2__">
<CONFIGURATIONS>
<CONFIGURATION isDebug="1" name="Debug" targetName="vita" headerPath="$(pythonLocation)/include;"
libraryPath="$(pythonLocation)\libs;&#10;..\..\..\third_party\nanobind\build\tests\Debug;"
postbuildCommand="copy &quot;x64\Debug\Dynamic Library\vita.dll&quot; &quot;$(pythonLocation)\vita.pyd&quot;;"/>
<CONFIGURATION isDebug="0" name="Release" targetName="vita" postbuildCommand="copy &quot;x64\Release\Dynamic Library\vita.dll&quot; &quot;$(pythonLocation)\vita.pyd&quot;;"
libraryPath="$(pythonLocation)\libs;&#10;..\..\..\third_party\nanobind\build\tests\Release;"
headerPath="$(pythonLocation)/include;"/>
</CONFIGURATIONS>
<MODULEPATHS>
<MODULEPATH id="juce_audio_basics" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_audio_formats" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_core" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_data_structures" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_dsp" path="../third_party/JUCE/modules"/>
<MODULEPATH id="juce_events" path="../third_party/JUCE/modules"/>
</MODULEPATHS>
</VS2022>
</EXPORTFORMATS>
<MODULES>
<MODULES id="juce_audio_basics" showAllCode="1" useLocalCopy="0"/>
<MODULES id="juce_audio_formats" showAllCode="1" useLocalCopy="0"/>
<MODULES id="juce_core" showAllCode="1" useLocalCopy="0"/>
<MODULES id="juce_data_structures" showAllCode="1" useLocalCopy="0"/>
<MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
<MODULES id="juce_events" showAllCode="1" useLocalCopy="0"/>
</MODULES>
<JUCEOPTIONS JUCE_WASAPI="1" JUCE_DIRECTSOUND="1" JUCE_ALSA="1" JUCE_JACK="1"
JUCE_WEB_BROWSER="0" JUCE_USE_CURL="0"/>
<LIVE_SETTINGS>
<OSX/>
<WINDOWS/>
<LINUX/>
</LIVE_SETTINGS>
</JUCERPROJECT>

3
pyproject.toml Normal file
View file

@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

119
setup.py Normal file
View file

@ -0,0 +1,119 @@
#! /usr/bin/env python
# NOTE: You can test building wheels locally with
# `python -m build --wheel`
# Then in the `dist` directory, `pip install vita`
import setuptools
from setuptools import setup, Extension
from setuptools.dist import Distribution
import os
import os.path
from pathlib import Path
import shutil
import platform
import glob
this_dir = os.path.abspath(os.path.dirname(__file__))
def get_VITA_VERSION():
with open('vita/version.py', 'r') as f:
text = f.read()
version = text.split("=")[-1].strip().replace('"', "")
return version
VITA_VERSION = get_VITA_VERSION()
class BinaryDistribution(Distribution):
"""Distribution which always forces a binary package with platform name"""
def has_ext_modules(foo):
return True
ext_modules = []
package_data = []
shutil.copy('LICENSE', 'vita')
if platform.system() == "Windows":
build_folder = os.path.join(this_dir, "headless", "builds", "VisualStudio2022", "x64", "Release", "Dynamic Library")
shutil.copy(os.path.join(build_folder, 'vita.dll'), os.path.join('vita', 'vita.pyd'))
package_data += ['vita/vita.pyd']
elif platform.system() == "Linux":
files = ['vita/vita.so']
for file in files:
filepath = os.path.abspath(file)
assert os.path.isfile(filepath), ValueError("File not found: " + filepath)
print('Using compiled files: ', str(files))
package_data += files
elif platform.system() == "Darwin":
build_folder = os.path.join(this_dir, "headless", "builds", "osx", "build", "Release")
shutil.copy(os.path.join(build_folder, 'vita.so'), os.path.join('vita', 'vita.so'))
package_data += ['vita/vita.so']
else:
raise NotImplementedError(
f"setup.py hasn't been implemented for platform: {platform}."
)
package_data.append('vita/LICENSE')
# Every item in package_data should be inside the vita directory.
# Then we make the paths relative to this directory.
package_data = [os.path.relpath(os.path.abspath(a), os.path.join(this_dir, "vita")).replace('\\', '/') for a in package_data]
print('package_data: ', package_data)
long_description = (Path(__file__).parent / "README.md").read_text()
setup(
name='vita',
url='https://github.com/DBraun/Vita',
project_urls={
'Documentation': 'https://dirt.design/Vita',
'Source': 'https://github.com/DBraun/Vita',
},
version=VITA_VERSION,
author='David Braun',
author_email='braun@ccrma.stanford.edu',
description='Python bindings for the Vital synthesizer',
long_description=long_description,
long_description_content_type='text/markdown',
classifiers=[
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
"Programming Language :: C++",
"Programming Language :: Python",
"Topic :: Multimedia :: Sound/Audio",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
],
keywords='audio music sound synthesizer',
python_requires=">=3.9",
install_requires=[],
packages=setuptools.find_packages(),
py_modules=['vita'],
include_package_data=True,
package_data={
"": package_data
},
zip_safe=False,
distclass=BinaryDistribution,
ext_modules=ext_modules
)

View file

@ -26,6 +26,10 @@
#include "synth_parameters.h"
#include "utils.h"
#include <iostream>
#include <fstream>
#include <filesystem>
SynthBase::SynthBase() : expired_(false) {
expired_ = LoadSave::isExpired();
self_reference_ = std::make_shared<SynthBase*>();
@ -190,6 +194,22 @@ bool SynthBase::connectModulation(const std::string& source, const std::string&
return create;
}
bool SynthBase::pyConnectModulation(const std::string& source, const std::string& destination) {
vital::ModulationConnection* connection = getConnection(source, destination);
bool create = connection == nullptr;
if (create)
connection = getModulationBank().createConnection(source, destination);
if (connection) {
connectModulation(connection);
LineGenerator* map_generator = connection->modulation_processor->lineMapGenerator();
map_generator->initLinear(); // todo: allow more options via kwarg
}
return create;
}
void SynthBase::disconnectModulation(vital::ModulationConnection* connection) {
if (mod_connections_.count(connection) == 0)
return;
@ -380,7 +400,53 @@ bool SynthBase::loadFromFile(File preset, std::string& error) {
return true;
}
void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vector<int> notes, bool render_images) {
bool SynthBase::pyLoadFromFile(std::string path) {
try {
File jsonFile(path);
std::string error;
bool result = loadFromFile(jsonFile, error);
if (!result) {
std::cerr << "Error: " << error << std::endl;
}
return result;
} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
}
return false;
}
bool SynthBase::loadFromString(std::string json_text) {
std::string error;
try {
json parsed_json_state = json::parse(json_text, nullptr);
if (!loadFromJson(parsed_json_state)) {
error = "Preset was created with a newer version.";
return false;
}
//active_file_ = preset; // todo:
} catch (const json::exception& e) {
error = "Preset file is corrupted.";
return false;
}
//setPresetName(preset.getFileNameWithoutExtension()); // todo:
SynthGuiInterface* gui_interface = getGuiInterface();
if (gui_interface) {
gui_interface->updateFullGui();
gui_interface->notifyFresh();
}
return true;
}
void SynthBase::pySetBPM(float bpm) {
// todo: this is hopefully safe as a public method just for headless mode.
engine_->setBpm(bpm);
};
void SynthBase::renderAudioToFile(File file, std::vector<int> notes, float velocity, float note_dur, float render_dur, bool render_images) {
static constexpr int kSampleRate = 44100;
static constexpr int kPreProcessSamples = 44100;
static constexpr int kFadeSamples = 200;
@ -390,13 +456,14 @@ void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vect
static constexpr int kImageWidth = 500;
static constexpr int kImageHeight = 250;
static constexpr int kOscilloscopeResolution = 512;
static constexpr float kFadeRatio = 0.3f;
ScopedLock lock(getCriticalSection());
engine_->allSoundsOff(); // note: dbraun added this
processModulationChanges();
engine_->setSampleRate(kSampleRate);
engine_->setBpm(bpm);
// engine_->setBpm(bpm);
engine_->updateAllModulationSwitches();
double sample_time = 1.0 / getSampleRate();
@ -409,15 +476,15 @@ void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vect
}
for (int note : notes)
engine_->noteOn(note, 0.7f, 0, 0);
engine_->noteOn(note, velocity, 0, 0);
file.deleteFile();
std::unique_ptr<FileOutputStream> file_stream = file.createOutputStream();
WavAudioFormat wav_format;
std::unique_ptr<AudioFormatWriter> writer(wav_format.createWriterFor(file_stream.get(), kSampleRate, 2, 16, {}, 0));
int on_samples = seconds * kSampleRate;
int total_samples = on_samples + seconds * kSampleRate * kFadeRatio;
int on_samples = note_dur * kSampleRate;
int total_samples = render_dur * kSampleRate;
std::unique_ptr<float[]> left_buffer = std::make_unique<float[]>(kBufferSize);
std::unique_ptr<float[]> right_buffer = std::make_unique<float[]>(kBufferSize);
float* buffers[2] = { left_buffer.get(), right_buffer.get() };
@ -505,6 +572,87 @@ void SynthBase::renderAudioToFile(File file, float seconds, float bpm, std::vect
file_stream.release();
}
nb::ndarray<float, nb::shape<2, -1>, nb::numpy> SynthBase::renderAudioToNumpy(const int& midi_note, float velocity, float note_dur, float render_dur) {
static constexpr int kSampleRate = 44100;
static constexpr int kFadeSamples = 200;
static constexpr int kBufferSize = 64;
static constexpr int kPreProcessSamples = 256; // note: dbraun decreased this from 44100.
ScopedLock lock(getCriticalSection());
engine_->allSoundsOff(); // note: dbraun added this
processModulationChanges();
engine_->setSampleRate(kSampleRate);
engine_->updateAllModulationSwitches();
// Preprocess modulation
double sample_time = 1.0 / getSampleRate();
double current_time = -kPreProcessSamples * sample_time;
for (int samples = 0; samples < kPreProcessSamples; samples += kBufferSize) {
engine_->correctToTime(current_time);
current_time += kBufferSize * sample_time;
engine_->process(kBufferSize);
}
engine_->noteOn(midi_note, velocity, 0, 0);
int on_samples = note_dur * kSampleRate;
int total_samples = render_dur * kSampleRate;
const vital::mono_float* engine_output =
(const vital::mono_float*)engine_->output(0)->buffer;
size_t total_frames =
static_cast<size_t>(total_samples * 2); // stereo: 2 channels
auto* data = new float[total_frames](); // Zero-initialized
auto capsule = nb::capsule(
data, [](void* p) noexcept { delete[] static_cast<float*>(p); });
int baseSample = 0;
for (int samples = 0; samples < total_samples; samples += kBufferSize) {
engine_->correctToTime(current_time);
current_time += kBufferSize * sample_time;
engine_->process(kBufferSize);
updateMemoryOutput(kBufferSize, engine_->output(0)->buffer);
if (on_samples > samples && on_samples <= samples + kBufferSize) {
engine_->noteOff(midi_note, 0.5f, 0, 0);
}
for (int i = 0; i < kBufferSize; ++i) {
vital::mono_float t = (total_samples - samples) / (1.0f * kFadeSamples);
t = vital::utils::min(t, 1.0f);
baseSample = samples + i;
if (baseSample < total_samples) {
data[samples + i] = t * engine_output[vital::poly_float::kSize * i];
data[samples + i + total_samples] =
t * engine_output[vital::poly_float::kSize * i + 1];
}
}
}
// Return the data as a NumPy array
return nb::ndarray<float, nb::shape<2, -1>, nb::numpy>(
data, {2, static_cast<size_t>(total_samples)}, capsule);
}
bool SynthBase::renderAudioToFile2(const std::string& output_path, const int& midi_note, float velocity, float note_dur, float render_dur) {
File output_file(output_path);
if (!output_file.hasWriteAccess()) {
std::cout << "Error: Don't have permission to write output file." << newLine;
return false;
}
bool render_images = false;
std::vector<int> midi_notes = {midi_note};
renderAudioToFile(output_file, midi_notes, velocity, note_dur, render_dur, render_images);
return true;
}
void SynthBase::renderAudioForResynthesis(float* data, int samples, int note) {
static constexpr int kPreProcessSamples = 44100;
static constexpr int kBufferSize = 64;

View file

@ -28,6 +28,14 @@
#include <set>
#include <string>
#include <nanobind/nanobind.h>
#include <nanobind/ndarray.h>
#include <filesystem>
namespace nb = nanobind;
namespace vital {
class SoundEngine;
struct Output;
@ -58,6 +66,7 @@ class SynthBase : public MidiManager::Listener {
void valueChangedExternal(const std::string& name, vital::mono_float value);
void valueChangedInternal(const std::string& name, vital::mono_float value);
bool connectModulation(const std::string& source, const std::string& destination);
bool pyConnectModulation(const std::string& source, const std::string& destination);
void connectModulation(vital::ModulationConnection* connection);
void disconnectModulation(const std::string& source, const std::string& destination);
void disconnectModulation(vital::ModulationConnection* connection);
@ -83,7 +92,12 @@ class SynthBase : public MidiManager::Listener {
void loadTuningFile(const File& file);
void loadInitPreset();
bool loadFromFile(File preset, std::string& error);
void renderAudioToFile(File file, float seconds, float bpm, std::vector<int> notes, bool render_images);
bool pyLoadFromFile(std::string path);
std::string pyToJson() { return saveToJson().dump(); }
bool loadFromString(std::string json_text);
void renderAudioToFile(File file, std::vector<int> notes, float velocity, float note_dur, float render_dur, bool render_images);
bool renderAudioToFile2(const std::string& output_path, const int& midi_note, float velocity, float note_dur, float render_dur);
nb::ndarray<float, nb::shape<2, -1>, nb::numpy> renderAudioToNumpy(const int& midi_note, float velocity, float note_dur, float render_dur);
void renderAudioForResynthesis(float* data, int samples, int note);
bool saveToFile(File preset);
bool saveToActiveFile();
@ -123,6 +137,8 @@ class SynthBase : public MidiManager::Listener {
virtual const CriticalSection& getCriticalSection() = 0;
virtual void pauseProcessing(bool pause) = 0;
Tuning* getTuning() { return &tuning_; }
void pySetBPM(float bpm);
struct ValueChangedCallback : public CallbackMessage {
ValueChangedCallback(std::shared_ptr<SynthBase*> listener, std::string name, vital::mono_float val) :

434
src/headless/bindings.cpp Normal file
View file

@ -0,0 +1,434 @@
#include <iostream>
#include <nanobind/nanobind.h>
#include <nanobind/stl/string.h>
#include <nanobind/stl/map.h>
#include <nanobind/stl/array.h>
#include <nanobind/stl/list.h>
#include <nanobind/stl/shared_ptr.h>
#include "compressor.h"
#include "processor_router.h"
#include "random_lfo.h"
#include "sound_engine.h"
#include "synth_base.h"
#include "synth_filter.h"
#include "synth_lfo.h"
#include "synth_oscillator.h"
#include "value.h"
#include "voice_handler.h"
#include "wave_frame.h"
namespace nb = nanobind;
using namespace vital;
class ModulationDestinationListCache {
private:
static std::vector<std::string> cached_list;
static bool initialized;
static void initialize() {
if (!initialized) {
SoundEngine engine;
vital::input_map &mono_destination_map =
engine.getMonoModulationDestinations();
for (auto &destination_iter : mono_destination_map) {
cached_list.push_back(destination_iter.first);
}
initialized = true;
}
}
public:
static const std::vector<std::string> &get() {
initialize();
return cached_list;
}
};
class ModulationSourceListCache {
private:
static std::vector<std::string> cached_list;
static bool initialized;
static void initialize() {
if (!initialized) {
SoundEngine engine;
vital::output_map &source_map = engine.getModulationSources();
for (auto &source_iter : source_map) {
cached_list.push_back(source_iter.first);
}
initialized = true;
}
}
public:
static const std::vector<std::string> &get() {
initialize();
return cached_list;
}
};
// Initialize static members
std::vector<std::string> ModulationDestinationListCache::cached_list;
bool ModulationDestinationListCache::initialized = false;
std::vector<std::string> ModulationSourceListCache::cached_list;
bool ModulationSourceListCache::initialized = false;
nb::list get_modulation_destinations() {
const auto &cpp_list = ModulationDestinationListCache::get();
nb::list result;
for (const auto &str : cpp_list) {
result.append(str);
}
return result;
}
nb::list get_modulation_sources() {
const auto &cpp_list = ModulationSourceListCache::get();
nb::list result;
for (const auto &str : cpp_list) {
result.append(str);
}
return result;
}
NB_MODULE(vita, m) {
m.def("get_modulation_sources", &get_modulation_sources,
"Returns a list of allowed modulation sources.");
m.def("get_modulation_destinations", &get_modulation_destinations,
"Returns a list of allowed modulation destinations");
auto m_constants = m.def_submodule("constants", "Submodule containing constants and enums");
// Expose Enums
nb::enum_<constants::SourceDestination>(m_constants, "SourceDestination")
.value("Filter1", constants::SourceDestination::kFilter1)
.value("Filter2", constants::SourceDestination::kFilter2)
.value("DualFilters", constants::SourceDestination::kDualFilters)
.value("Effects", constants::SourceDestination::kEffects)
.value("DirectOut", constants::SourceDestination::kDirectOut)
.def("__int__", [](constants::SourceDestination self) {
return static_cast<int>(self);
});
nb::enum_<constants::Effect>(m_constants, "Effect")
.value("Chorus", constants::Effect::kChorus)
.value("Compressor", constants::Effect::kCompressor)
.value("Delay", constants::Effect::kDelay)
.value("Distortion", constants::Effect::kDistortion)
.value("Eq", constants::Effect::kEq)
.value("FilterFx", constants::Effect::kFilterFx)
.value("Flanger", constants::Effect::kFlanger)
.value("Phaser", constants::Effect::kPhaser)
.value("Reverb", constants::Effect::kReverb)
.def("__int__",
[](constants::Effect self) { return static_cast<int>(self); });
nb::enum_<constants::FilterModel>(m_constants, "FilterModel")
.value("Analog", constants::FilterModel::kAnalog)
.value("Dirty", constants::FilterModel::kDirty)
.value("Ladder", constants::FilterModel::kLadder)
.value("Digital", constants::FilterModel::kDigital)
.value("Diode", constants::FilterModel::kDiode)
.value("Formant", constants::FilterModel::kFormant)
.value("Comb", constants::FilterModel::kComb)
.value("Phase", constants::FilterModel::kPhase)
.def("__int__", [](constants::FilterModel self) {
return static_cast<int>(self);
});
nb::enum_<constants::RetriggerStyle>(m_constants, "RetriggerStyle")
.value("Free", constants::RetriggerStyle::kFree)
.value("Retrigger", constants::RetriggerStyle::kRetrigger)
.value("SyncToPlayHead", constants::RetriggerStyle::kSyncToPlayHead)
.def("__int__", [](constants::RetriggerStyle self) {
return static_cast<int>(self);
});
nb::enum_<SynthOscillator::SpectralMorph>(m_constants, "SpectralMorph")
.value("NoSpectralMorph", SynthOscillator::SpectralMorph::kNoSpectralMorph)
.value("Vocode", SynthOscillator::SpectralMorph::kVocode)
.value("FormScale", SynthOscillator::SpectralMorph::kFormScale)
.value("HarmonicScale", SynthOscillator::SpectralMorph::kHarmonicScale)
.value("InharmonicScale", SynthOscillator::SpectralMorph::kInharmonicScale)
.value("Smear", SynthOscillator::SpectralMorph::kSmear)
.value("RandomAmplitudes", SynthOscillator::SpectralMorph::kRandomAmplitudes)
.value("LowPass", SynthOscillator::SpectralMorph::kLowPass)
.value("HighPass", SynthOscillator::SpectralMorph::kHighPass)
.value("PhaseDisperse", SynthOscillator::SpectralMorph::kPhaseDisperse)
.value("ShepardTone", SynthOscillator::SpectralMorph::kShepardTone)
.value("Skew", SynthOscillator::SpectralMorph::kSkew)
.def("__int__", [](SynthOscillator::SpectralMorph self) {
return static_cast<int>(self);
});
nb::enum_<SynthOscillator::DistortionType>(m_constants, "DistortionType")
.value("None", SynthOscillator::DistortionType::kNone)
.value("Sync", SynthOscillator::DistortionType::kSync)
.value("Formant", SynthOscillator::DistortionType::kFormant)
.value("Quantize", SynthOscillator::DistortionType::kQuantize)
.value("Bend", SynthOscillator::DistortionType::kBend)
.value("Squeeze", SynthOscillator::DistortionType::kSqueeze)
.value("PulseWidth", SynthOscillator::DistortionType::kPulseWidth)
.value("FmOscillatorA", SynthOscillator::DistortionType::kFmOscillatorA)
.value("FmOscillatorB", SynthOscillator::DistortionType::kFmOscillatorB)
.value("FmSample", SynthOscillator::DistortionType::kFmSample)
.value("RmOscillatorA", SynthOscillator::DistortionType::kRmOscillatorA)
.value("RmOscillatorB", SynthOscillator::DistortionType::kRmOscillatorB)
.value("RmSample", SynthOscillator::DistortionType::kRmSample)
.def("__int__", [](SynthOscillator::DistortionType self) {
return static_cast<int>(self);
});
nb::enum_<SynthOscillator::UnisonStackType>(m_constants, "UnisonStackType")
.value("Normal", SynthOscillator::UnisonStackType::kNormal)
.value("CenterDropOctave", SynthOscillator::UnisonStackType::kCenterDropOctave)
.value("CenterDropOctave2", SynthOscillator::UnisonStackType::kCenterDropOctave2)
.value("Octave", SynthOscillator::UnisonStackType::kOctave)
.value("Octave2", SynthOscillator::UnisonStackType::kOctave2)
.value("PowerChord", SynthOscillator::UnisonStackType::kPowerChord)
.value("PowerChord2", SynthOscillator::UnisonStackType::kPowerChord2)
.value("MajorChord", SynthOscillator::UnisonStackType::kMajorChord)
.value("MinorChord", SynthOscillator::UnisonStackType::kMinorChord)
.value("HarmonicSeries", SynthOscillator::UnisonStackType::kHarmonicSeries)
.value("OddHarmonicSeries",
SynthOscillator::UnisonStackType::kOddHarmonicSeries)
.def("__int__", [](SynthOscillator::UnisonStackType self) {
return static_cast<int>(self);
});
nb::enum_<RandomLfo::RandomType>(m_constants, "RandomLFOStyle")
.value("Perlin", RandomLfo::RandomType::kPerlin)
.value("SampleAndHold", RandomLfo::RandomType::kSampleAndHold)
.value("SinInterpolate", RandomLfo::RandomType::kSinInterpolate)
.value("LorenzAttractor", RandomLfo::RandomType::kLorenzAttractor)
.def("__int__",
[](RandomLfo::RandomType self) { return static_cast<int>(self); });
nb::enum_<VoiceHandler::VoicePriority>(m_constants, "VoicePriority")
.value("Newest", VoiceHandler::VoicePriority::kNewest)
.value("Oldest", VoiceHandler::VoicePriority::kOldest)
.value("Highest", VoiceHandler::VoicePriority::kHighest)
.value("Lowest", VoiceHandler::VoicePriority::kLowest)
.value("RoundRobin", VoiceHandler::VoicePriority::kRoundRobin)
.def("__int__", [](VoiceHandler::VoicePriority self) {
return static_cast<int>(self);
});
nb::enum_<VoiceHandler::VoiceOverride>(m_constants, "VoiceOverride")
.value("Kill",VoiceHandler::VoiceOverride::kKill)
.value("Steal", VoiceHandler::VoiceOverride::kSteal)
.def("__int__", [](VoiceHandler::VoiceOverride self) {
return static_cast<int>(self);
});
nb::enum_<PredefinedWaveFrames::Shape>(m_constants, "WaveShape")
.value("Sin", PredefinedWaveFrames::kSin)
.value("SaturatedSin", PredefinedWaveFrames::kSaturatedSin)
.value("Triangle", PredefinedWaveFrames::kTriangle)
.value("Square", PredefinedWaveFrames::kSquare)
.value("Pulse", PredefinedWaveFrames::kPulse)
.value("Saw", PredefinedWaveFrames::kSaw)
.def("__int__", [](PredefinedWaveFrames::Shape self) {
return static_cast<int>(self);
});
nb::enum_<SynthLfo::SyncType>(m_constants, "SynthLFOSyncType")
.value("Trigger", SynthLfo::SyncType::kTrigger)
.value("Sync", SynthLfo::SyncType::kSync)
.value("Envelope", SynthLfo::SyncType::kEnvelope)
.value("SustainEnvelope", SynthLfo::SyncType::kSustainEnvelope)
.value("LoopPoint", SynthLfo::SyncType::kLoopPoint)
.value("LoopHold", SynthLfo::SyncType::kLoopHold)
.def("__int__",
[](SynthLfo::SyncType self) { return static_cast<int>(self); });
nb::enum_<MultibandCompressor::BandOptions>(m_constants, "CompressorBandOption")
.value("Multiband", MultibandCompressor::BandOptions::kMultiband)
.value("LowBand", MultibandCompressor::BandOptions::kLowBand)
.value("HighBand", MultibandCompressor::BandOptions::kHighBand)
.value("SingleBand", MultibandCompressor::BandOptions::kSingleBand)
.def("__int__", [](MultibandCompressor::BandOptions self) {
return static_cast<int>(self);
});
nb::enum_<SynthFilter::Style>(m_constants, "SynthFilterStyle")
.value("k12Db", SynthFilter::Style::k12Db)
.value("k24Db", SynthFilter::Style::k24Db)
.value("NotchPassSwap", SynthFilter::Style::kNotchPassSwap)
.value("DualNotchBand", SynthFilter::Style::kDualNotchBand)
.value("BandPeakNotch", SynthFilter::Style::kBandPeakNotch)
.value("Shelving", SynthFilter::Style::kShelving)
.def("__int__",
[](SynthFilter::Style self) { return static_cast<int>(self); });
// https://github.com/mtytel/vital/blob/636ca0ef517a4db087a6a08a6a8a5e704e21f836/src/interface/look_and_feel/synth_strings.h#L174
enum SyncedFrequencyName {
k32_1,
k16_1,
k8_1,
k4_1,
k2_1,
k1_1,
k1_2,
k1_4,
k1_8,
k1_16,
k1_32,
k1_64
};
nb::enum_<SyncedFrequencyName>(m_constants, "SyncedFrequency")
.value("k32_1", SyncedFrequencyName::k32_1)
.value("k16_1", SyncedFrequencyName::k16_1)
.value("k8_1", SyncedFrequencyName::k8_1)
.value("k4_1", SyncedFrequencyName::k4_1)
.value("k2_1", SyncedFrequencyName::k2_1)
.value("k1_1", SyncedFrequencyName::k1_1)
.value("k1_2", SyncedFrequencyName::k1_2)
.value("k1_4", SyncedFrequencyName::k1_4)
.value("k1_8", SyncedFrequencyName::k1_8)
.value("k1_16", SyncedFrequencyName::k1_16)
.value("k1_32", SyncedFrequencyName::k1_32)
.value("k1_64", SyncedFrequencyName::k1_64)
.def("__int__",
[](SyncedFrequencyName self) { return static_cast<int>(self); });
// https://github.com/mtytel/vital/blob/636ca0ef517a4db087a6a08a6a8a5e704e21f836/src/synthesis/modulators/synth_lfo.h#L58C1-L65C9
enum SyncOption {
kTime,
kTempo,
kDottedTempo,
kTripletTempo,
kKeytrack,
};
nb::enum_<SyncOption>(m_constants, "SynthLFOSyncOption")
.value("Time", SyncOption::kTime)
.value("Tempo", SyncOption::kTempo)
.value("DottedTempo", SyncOption::kDottedTempo)
.value("TripletTempo", SyncOption::kTripletTempo)
.value("Keytrack", SyncOption::kKeytrack)
.def("__int__", [](SyncOption self) { return static_cast<int>(self); });
// Binding for poly_float
nb::class_<vital::poly_float>(m, "poly_float")
.def(nb::init_implicit<float>());
// Expose the ProcessorRouter class
nb::class_<ProcessorRouter>(m, "ProcessorRouter")
.def(nb::init<int, int, bool>(),
nb::arg("num_inputs") = 0,
nb::arg("num_outputs") = 0,
nb::arg("control_rate") = false);
nb::class_<vital::Value>(m, "Value")
.def(nb::init<poly_float, bool>(),
nb::arg("value") = 0.0f,
nb::arg("control_rate") = false)
.def("process", &vital::Value::process, nb::arg("num_samples"))
.def("set_oversample_amount", &vital::Value::setOversampleAmount, nb::arg("oversample"))
.def("value", &vital::Value::value)
// Handle floating point values (both float and double)
.def("set", [](vital::Value &self, double value) {
self.set(poly_float(static_cast<float>(value)));
}, nb::arg("value"))
// Handle enum values
.def("set", [](vital::Value &self, SyncedFrequencyName value) {
self.set(poly_float(static_cast<float>(static_cast<int>(value))));
}, nb::arg("value"))
// Handle integer values
.def("set", [](vital::Value &self, int value) {
self.set(poly_float(static_cast<float>(value)));
}, nb::arg("value"))
.def("__repr__", [](const vital::Value &v) {
return "<Value value=" + std::to_string(v.value()) + ">";
});
nb::class_<vital::cr::Value, vital::Value>(m, "CRValue")
.def(nb::init<poly_float>(),
nb::arg("value") = 0.0f)
.def("process", &vital::cr::Value::process, nb::arg("num_samples"))
// Add the same method overloads for CRValue
.def("set", [](vital::cr::Value &self, double value) {
self.set(poly_float(static_cast<float>(value)));
}, nb::arg("value"))
.def("set", [](vital::cr::Value &self, SyncedFrequencyName value) {
self.set(poly_float(static_cast<float>(static_cast<int>(value))));
}, nb::arg("value"))
.def("set", [](vital::cr::Value &self, int value) {
self.set(poly_float(static_cast<float>(value)));
}, nb::arg("value"))
.def("__repr__", [](const vital::cr::Value &v) {
return "<CRValue value=" + std::to_string(v.value()) + ">";
});
// Expose the SynthBase class, specifying ProcessorRouter as its base
nb::class_<HeadlessSynth>(m, "Synth")
.def(nb::init<>()) // Ensure there's a default constructor or adjust
// accordingly
// Bind the first overload of connectModulation
.def("connect_modulation",
nb::overload_cast<const std::string &, const std::string &>(
&HeadlessSynth::pyConnectModulation),
nb::arg("source"), nb::arg("destination"),
"Connects a modulation source to a destination by name.")
.def("disconnect_modulation",
nb::overload_cast<const std::string &, const std::string &>(
&HeadlessSynth::disconnectModulation),
nb::arg("source"), nb::arg("destination"),
"Disconnects a modulation source from a destination by name.")
.def("set_bpm", &HeadlessSynth::pySetBPM, nb::arg("bpm"))
.def("render_file", &HeadlessSynth::renderAudioToFile2,
nb::arg("output_path"), nb::arg("midi_note"),
nb::arg("midi_velocity"), nb::arg("note_dur"),
nb::arg("render_dur"),
"Renders audio to a file.\n\n"
"Parameters:\n"
" output_path (str): Path to the output audio file.\n"
" midi_note (int): MIDI note to render.\n"
" midi_velocity (float): Velocity of the note [0-1].\n"
" note_dur (float): Length of the note sustain in seconds.\n"
" render_dur (float): Length of the audio render in seconds.\n"
"\n"
"Returns:\n"
" bool: True if rendering was successful, False otherwise.")
.def("render", &HeadlessSynth::renderAudioToNumpy, nb::arg("midi_note"),
nb::arg("midi_velocity"), nb::arg("note_dur"),
nb::arg("render_dur"),
"Renders audio to a file.\n\n"
"Parameters:\n"
" midi_note (int): MIDI note to render.\n"
" midi_velocity (float): Velocity of the note [0-1].\n"
" note_dur (float): Length of the note sustain in seconds.\n"
" render_dur (float): Length of the audio render in seconds.\n"
"\n"
"Returns:\n"
" bool: True if rendering was successful, False otherwise.")
.def("load_json", &HeadlessSynth::loadFromString, nb::arg("json"))
.def("to_json", &HeadlessSynth::pyToJson)
.def("load_preset", &HeadlessSynth::pyLoadFromFile, nb::arg("filepath"))
.def("load_init_preset", &HeadlessSynth::loadInitPreset, "Load the initial preset.")
.def("clear_modulations", &HeadlessSynth::clearModulations)
.def("get_controls", &HeadlessSynth::getControls, nb::rv_policy::reference);
}

4
test-requirements.txt Normal file
View file

@ -0,0 +1,4 @@
numpy
scipy
librosa
pytest

3
tests/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
tmp_*
generated_preset*
*.pyc

65
tests/test_render.py Normal file
View file

@ -0,0 +1,65 @@
from scipy.io import wavfile
import vita
from vita.constants import (
SourceDestination,
Effect,
FilterModel,
RetriggerStyle,
SpectralMorph,
DistortionType,
UnisonStackType,
RandomLFOStyle,
SynthFilterStyle,
WaveShape,
CompressorBandOption,
VoiceOverride,
VoicePriority,
SynthLFOSyncOption,
SynthLFOSyncType,
SyncedFrequency,
)
SAMPLE_RATE = 44_100
def test_render(bpm=120.0, note_dur=1.0, render_dur=3.0, pitch=36, velocity=0.7):
synth = vita.Synth()
# The initial preset is laoded by default.
synth.set_bpm(bpm)
assert vita.get_modulation_sources()
assert vita.get_modulation_destinations()
# Custom synthesizer settings
assert synth.connect_modulation("lfo_1", "filter_1_cutoff")
controls = synth.get_controls()
controls["modulation_1_amount"].set(1.0)
controls["filter_1_on"].set(1.0)
controls["lfo_1_tempo"].set(SyncedFrequency.k1_16)
# Render audio to numpy array shaped (2, NUM_SAMPLES)
audio = synth.render(pitch, velocity, note_dur, render_dur)
wavfile.write("generated_preset.wav", SAMPLE_RATE, audio.T)
# Dump current state to json text
json_text = synth.to_json()
preset_path = "generated_preset.vital"
with open(preset_path, "w") as f:
f.write(json_text)
# Load JSON text
with open(preset_path, "r") as f:
json_text = f.read()
assert synth.load_json(json_text)
# Or load directly from file:
assert synth.load_preset(preset_path)
# Load the initial preset, which also clears modulations
synth.load_init_preset()
# Or just clear modulations.
synth.clear_modulations()

2
vita/__init__.py Normal file
View file

@ -0,0 +1,2 @@
from .vita import *
from .version import *

View file

@ -0,0 +1 @@
from ..vita.constants import *

1
vita/version.py Normal file
View file

@ -0,0 +1 @@
__version__ = "0.0.1"