Building From Source
Use this procedure to build the s3g-dsp CLAP plugins from source. Because this is pre-release software, plugin names, parameters, saved states, and included plugins may change.
The prerelease targets REAPER on Apple silicon macOS and experimental Windows x64, with Ambi Energy excluded on Windows. See Tracker VSTGUI builds for Tracker's focused build options and acceptance limits.
Requirements
- CMake 3.20 or newer.
- A C++17 compiler, such as Apple Clang through Xcode Command Line Tools.
- macOS for the current CLAP GUI/plugin bundles.
- REAPER.
- Optional:
clap-validatorfor plugin validation.
Smoke Test
The dev preset builds the DSP smoke tests without CLAP bundles:
cmake --preset dev
cmake --build --preset dev
./build/s3g_dsp_smoke
./build/s3g_ambi_effect_displacement_smoke
./build/s3g_ambi_imprint_safety_smoke
./build/s3g_ambi_ray_encoder_smoke
./build/s3g_psd_raw_field_smoke
./build/s3g_psd_raw_field_parameter_audit
Build CLAP Plugins
Build the CLAP plugins:
cmake --preset clap
cmake --build --preset clap
By default, the build fetches CLAP headers with CMake. To use an existing local CLAP checkout, configure manually with S3G_FETCH_CLAP=OFF and S3G_CLAP_INCLUDE_DIR.
cmake -S . -B build-clap \
-DS3G_BUILD_CLAP_PLUGIN=ON \
-DS3G_FETCH_CLAP=OFF \
-DS3G_CLAP_INCLUDE_DIR=/path/to/clap/include
cmake --build build-clap
WORLD speech vocoder support is enabled by default for Ambi Encoder Vox and fetched at a pinned revision. Disable it only when a build without Ambi Vox WORLD analysis is required:
cmake -S . -B build-clap \
-DS3G_BUILD_CLAP_PLUGIN=ON \
-DS3G_ENABLE_WORLD=OFF
Release Components
The normal CLAP configuration includes the complete current inventory. Along with Ambi Encoder Cartography, it builds Low Frequency Synth, Processor Lowform, Processor Feedback Shift, Ambi Encoder Membrane Kick, Ambi Encoder Acid, Ambi Encoder Horizon, Processor Errant, the Drum and Sample families, s3g Tracker, and s3g Relay.
No additional component switch is required with the clap or clap-release preset. The compatibility switches remain available for focused development configurations, but the release presets enable every packaged component.
s3g Tracker has a focused CLAP preset. Use the explicit VSTGUI configuration below for its current portable editor; selecting the product alone does not enable all portable pages on Mac.
To build and validate only Relay after configuring the ordinary CLAP tree:
cmake --build build-clap --target s3g_relay_clap s3g_relay_clap_smoke
ctest --test-dir build-clap -R relay --output-on-failure
Tracker VSTGUI Builds
Tracker is now CLAP-only; its former standalone app is retired. On Mac, enable S3G_ENABLE_TRACKER_PORTABLE_SHELL_ON_MACOS to include all ten VSTGUI pages. That option enables the prerequisite portable-page options automatically. Build the core-test aggregate explicitly: the focused build preset alone does not build every test labeled tracker.
cmake --preset clap-tracker -DBUILD_TESTING=ON \
-DS3G_ENABLE_TRACKER_PORTABLE_SHELL_ON_MACOS=ON
cmake --build build-tracker --parallel 4 \
--target s3g_tracker_clap s3g_tracker_clap_smoke \
s3g_tracker_portable_core_tests
ctest --test-dir build-tracker -L core -R '^s3g_tracker_' --output-on-failure
ctest --test-dir build-tracker -R '^s3g_tracker_clap_smoke$' --output-on-failure
The Mac bundle is build-tracker/plugins/clap_tracker/s3g_tracker.clap. GUI smoke checks require a logged-in graphical Mac session. These commands cover the portable core and CLAP integration, not every optional page-parity test or real-REAPER interaction. See tracker/reaper/README.md for the host acceptance checklist.
For a Windows x64 build on Mac, the cross preset needs MinGW-w64's x86_64-w64-mingw32-g++ and windres on PATH; packaging also uses its objdump and strip. Explicitly enable Tracker and testing, which this preset otherwise disables:
cmake --preset clap-windows-cross \
-DS3G_BUILD_TRACKER_PREVIEW=ON -DBUILD_TESTING=ON
cmake --build build-clap-windows-cross --parallel 4 \
--target s3g_tracker_windows_clap_smoke
cmake -P scripts/package-windows-tracker.cmake
This builds the actual Windows CLAP and integration-test executable, then creates a timestamped dist/s3g-tracker-windows-x64-test-*.zip with fonts, licenses, checksums, and run-windows-check.cmd. Cross-compilation does not execute the Windows binaries. Copy the complete package to Windows and run the check there before testing in REAPER; retain its report.
For native Windows builds, use an x64 Visual Studio C++ development environment. Run the following commands from the repository root (each displayed line is one command). These match the dedicated .github/workflows/tracker-windows-clap.yml build path:
cmake -S . -B build-tracker-windows -A x64 -DBUILD_TESTING=ON -DS3G_BUILD_CLAP_PLUGIN=ON -DS3G_BUILD_TRACKER_PREVIEW=ON -DS3G_ENABLE_PORTABLE_CLAP_GUI=ON -DS3G_BUILD_STANDALONE_APPS=OFF -DS3G_BUILD_FUTURE_COMPONENTS=OFF -DS3G_ENABLE_WORLD=OFF
cmake --build build-tracker-windows --config Release --parallel 4 --target s3g_tracker_windows_clap_smoke s3g_tracker_portable_core_tests s3g_tracker_workspace_layout_tests s3g_tracker_grid_selection_tests
ctest --test-dir build-tracker-windows -C Release -R "^s3g_tracker_" --output-on-failure
To include the additional CLAP MIDI-adapter regression, configure with -DS3G_TRACKER_CLAP_TEST_INCLUDE_DIR=/path/to/clap/include; the Windows workflow supplies a CLAP 1.2.6 checkout for this. The native Release payload is under build-tracker-windows/plugins/clap_tracker/Release/. Keep its CLAP, sibling Resources directory, and license notices together. The cross-build packaging script above is not a Visual Studio packager.
Windows remains a test target pending native REAPER acceptance, including DPI scaling, detached tools, keyboard focus, Unicode file paths, project recall, and MIDI/display synchronization. A successful compile or mock-host smoke check is not that acceptance. See the Tracker platform guide and plugins/common/TRACKER_WINDOWS_README.txt.
Windows Prerelease and Test Packages
The Windows suite contains 121 canonical CLAP files exposing 128 descriptors: every entry in scripts/clap-bundles.tsv except s3g_analyzer_ambi_energy_64.clap. Ambi Energy's separate renderer prototype is not a Windows plug-in. Windows downloads are explicitly experimental.
For a native prerelease build, install Visual Studio's x64 C++ build tools and Windows SDK, CMake 3.25 or newer, Git, and 64-bit Python 3.10 or newer. The preset lets CMake select the installed Visual Studio toolchain. From a clean, committed checkout:
cmake --preset clap-windows-release
cmake --build --preset clap-windows-release --parallel 4
ctest --test-dir build-clap-windows-release -C Release --output-on-failure --no-tests=error --timeout 300 -R "^(s3g_windows_|s3g_tracker_|s3g_[a-z0-9_]*_windows_|s3g_shared_efficiency_|s3g_sample_family_interaction_smoke$)"
python scripts/package-windows-clap-prerelease.py
The build preset selects s3g_windows_prerelease: every configured CLAP module, portable Tracker tests and pack generators, and Windows-specific regressions (including fonts, FFT and bit scanning). The generic ALL target still includes older POSIX-only CLAP test hosts and fixtures that are not MSVC-compatible; it is not the Windows release build command. This selection does not change the Mac test suite. The packager separately checks the complete 121-file manifest so missing plug-ins cannot silently become a partial release.
The native packager requires Release x64 with the static MSVC runtime, rebuilds every manifest target, checks PE architecture and CLAP exports, loads all runtime descriptors, merges resources only when identical, and verifies the extracted ZIP. It refuses a dirty source tree or existing output. --allow-dirty is only for explicitly named rehearsal archives. The result is dist/s3g-dsp-windows-x64-clap-0.10.0-pre-experimental.zip and its SHA-256 file. The manually dispatched Experimental Windows prerelease GitHub Actions workflow builds and uploads these candidate assets; it does not create tags or publish a release. Native REAPER testing of the exact archive remains a separate gate.
The older cross-build route remains useful for development snapshots; it does not exercise MSVC-specific optimizations:
From a Mac with MinGW-w64 on PATH, configure the cross-build with the full component set, Tracker, Sample Slicer, testing, and WORLD enabled. The older pilot preset alone disables some of these options:
cmake --preset clap-windows-cross \
-DS3G_BUILD_FUTURE_COMPONENTS=ON \
-DS3G_BUILD_TRACKER_PREVIEW=ON \
-DS3G_BUILD_RELAY_PREVIEW=ON \
-DS3G_BUILD_BREAKBEAT_SLICER_PREVIEW=ON \
-DS3G_ENABLE_WORLD=ON -DBUILD_TESTING=ON
cmake -P scripts/package-windows-clap-suite.cmake
The packager resolves and rebuilds every configured manifest target, checks Windows x64 binaries and CLAP exports, rejects external MinGW runtime DLL dependencies, and merges resources only when identically named files have identical contents. Missing targets, fonts, licenses, or atlas responses stop packaging. The result is a fresh dist/s3g-dsp-windows-clap-suite-x64-test-*.zip plus an archive SHA-256 file; earlier packages are untouched.
The ZIP contains canonical plug-in names, the shared Resources folder, all 19 Imprint Atlas and 19 Ray Atlas responses, licenses, PLUGIN_MANIFEST.tsv, EXCLUDED.txt, source hashes, and payload checksums. It also includes Tracker's optional run-windows-check.cmd; that test covers Tracker only, not the entire suite. Native Windows/REAPER testing remains required. See Windows test installation.
Audit CLAP Realtime Cost
Timing measurements must use optimized plugins and an optimized audit executable. The dedicated clap-release preset creates a separate Release build without changing the ordinary development or CLAP build directories:
cmake --preset clap-release
cmake --build --preset clap-release --target audit_clap_realtime_representative
The representative target is a focused, report-only manual check spanning a simple 24-channel baseline, zero-input generators, the zero-audio-port NIM Gesture utility, the 64-voice/64-channel Ambi Insect encoder, a wide Ambi decoder, 24-channel Spectral Topology, and 128-channel transform and matrix processors. It intentionally applies no portable pass/fail timing threshold. To audit one product or retain machine-readable results, invoke the executable directly:
./build-clap-release/s3g_clap_realtime_audit \
--json /tmp/nim-realtime.json \
--sample-rates 48000,96000 \
--blocks 64,128,256 \
build-clap-release/plugins/clap_no_input_mixer/s3g_no_input_mixer.clap \
org.s3g.s3g-dsp.no-input-mixer-8ch
Each configuration measures a baseline and, where the plugin exposes suitable continuous automatable parameters, a same-block automation-burst stress case. Use --event-burst 0 to measure only steady processing or choose a different burst size. The console's DATA label means that processing completed with valid finite output; inspect the deadline percentage and miss count to judge realtime risk.
After building the full Release tree, the manifest runner can audit every canonical bundle in manifest order and combine the individual reports. --filter accepts a regular expression for narrower families, and every child audit has a timeout so one faulty plugin cannot stall the run indefinitely:
cmake --build --preset clap-release
python3 scripts/run-clap-realtime-audit.py \
--audit-executable build-clap-release/s3g_clap_realtime_audit \
--build-root build-clap-release/plugins \
--full-sweep \
--output /tmp/s3g-clap-realtime-audit.json
--full-sweep covers 48 and 96 kHz at 32, 64, 128, and 256 frames. During optimization, --affected-only --automation-ladder narrows the run to the processors previously observed missing a deadline and compares 1, 4, 8, 16, and 64 simultaneous events with the same events distributed through a block. The equivalent Release target is:
cmake --build --preset clap-release \
--target audit_clap_realtime_weak_points
The manual release gate runs at least 10,000 measured blocks per scenario and requires p99 processing time no greater than 75 percent of the buffer deadline on the audit machine. This means at least 99 percent of measured callbacks retain 25 percent timing headroom. Wall-clock deadline misses in the excluded one-percent tail remain in the JSON and console diagnostics, and the gate additionally rejects any scenario whose miss rate exceeds one percent. The criteria are identical in every profile; only the documented supported buffer configurations differ:
- Group Rotate 64 and Node Bus Mixer 128: 48 and 96 kHz at 32, 64, 128, and 256 frames.
- Delay 24-channel, Ambisonic Rotate 64, and Group Rotate 128: 48 kHz at 32, 64, 128, and 256 frames; 96 kHz at 64, 128, and 256 frames.
- Spectral Topology 8-channel: 48 kHz at 64, 128, and 256 frames; 96 kHz at 128, 256, and 512 frames.
- Spectral Topology 24-channel: 48 kHz at 256 frames and 96 kHz at 512 frames.
- Spectral Spray 2-channel and 8-channel: 48 and 96 kHz at 32, 64, 128, and 256 frames.
- Ambi Water and Ambi Insect at maximum density: 48 kHz at 32, 64, 128, and 256 frames.
The spectral floors include the dense automation case, whose FFT-hop work is concentrated into particular callbacks. Smaller buffers remain available for manual, report-only investigation, but are not claimed as realtime-safe release configurations. The release target completes all nine strict profiles before returning failure, then measures maximum-density Water and Insect at 96 kHz as a report-only advisory. It writes a separate clap-realtime-release-gate-*.json file for every profile plus clap-realtime-release-gates-summary.json, so an early scheduling miss cannot hide later results. Full-density 96 kHz Water/Insect operation is deliberately not a release claim.
cmake --build --preset clap-release \
--target audit_clap_realtime_release_gate
cmake --build --preset clap-release \
--target audit_no_input_mixer_controller_realtime
The NIM controller gate covers 104 scenarios: 48 and 96 kHz at 32, 64, 128, and 256 frames, with baseline processing; 1, 4, 8, 16, and 64 simultaneous and sample-distributed parameter events; independent lock-free control publication; and synthetic MIDI 1 traffic matching BU16 Note On, poly pressure, and Note Off gestures plus E16 NRPN CC, command-note, and program-change messages. This verifies the CLAP-facing control paths; it does not measure CoreMIDI, USB hardware, or Cocoa event latency.
This is an offline processor-cost audit: it compares measured CLAP processing time with each sample-rate and block-size deadline. Results are machine-dependent and vary with CPU model, power mode, thermal state, background load, and compiler. The p99 boundary is deliberately robust to the rare operating-system preemptions that an ordinary userspace wall-clock timer cannot distinguish from plug-in execution; every extreme sample and deadline-miss count is still reported rather than discarded. Run the gate on a quiet reference machine without concurrent builds or audits and retain the JSON. Repeat a focused profile when p99 rises or misses cluster: repeatable elevated p99 is a DSP failure and must not be waived, while a miss that moves between unrelated scenarios is scheduler evidence. The one-percent tail allowance is not an audio-xrun allowance. A missed offline deadline identifies risk, but passing does not prove that a host will never underrun, and the guarded live Core Audio audit remains the check for actual callback delivery and HAL overloads.
Probe Realtime Allocations
On macOS, an injected probe can count malloc, calloc, realloc, aligned allocations, and free while each measured CLAP process() call is running. It remains opt-in for ordinary builds, while the clap-release preset enables it so the complete release target cannot silently make a non-allocation claim without evidence:
cmake --preset clap-release
cmake --build build-clap-release \
--target run_realtime_alloc_probe_tests
python3 scripts/run-clap-realtime-audit.py \
--audit-executable build-clap-release/s3g_clap_realtime_audit \
--build-root build-clap-release/plugins \
--allocation-probe-library build-clap-release/libs3g_realtime_alloc_probe.dylib \
--allocation-gate \
--output build-clap-release/clap-allocation-all.json
The probe test target checks the allocator hooks directly and runs a test-only CLAP that deliberately allocates and frees memory inside every measured process() block, confirming that a broken or no-op hook cannot create a false all-zero pass. --allocation-probe-library injects the dylib only into each audit child and implies measurement; --allocation-gate requires a complete probe report for every scenario and zero allocation, deallocation, failure, or invalid-alignment operations without imposing the separate 10,000-block timing threshold. The report separates blocks containing allocations, deallocations, total requested bytes, failures, and the maximum operations in one block. The probe measures only the thread that calls process(); plugin worker-thread activity and direct malloc_zone_* calls are outside its scope. Use it with a local non-hardened diagnostic executable, not a shipped or signed host.
The offline timing and allocation audits do not open or reconfigure an audio device. Use the guarded live audit below to observe actual Core Audio callback delivery and HAL signals.
Install Local Build
Preview and then install the CLAP products:
./scripts/install-clap-bundles.sh --dry-run
./scripts/install-clap-bundles.sh
# Optional: rename verified current installs without replacing their binaries.
./scripts/install-clap-bundles.sh --canonicalize-only
The default install location is:
~/Library/Audio/Plug-Ins/CLAP/s3g-dsp/
The install script reads scripts/clap-bundles.tsv and copies every manifest-listed product from build-clap/plugins/ under canonical family-first filenames. For example, Modal and Fault install as s3g_ambi_encoder_modal_16.clap and s3g_processor_fault_8.clap. These filesystem names mirror the host-browser families, while the CLAP IDs remain stable for saved-project compatibility.
Every audio plug-in's host-facing name ends in the fixed channel width of its main output bus as a bare number: for example, s3g Processor Fault 8, never 8ch. The number describes the bus presented to the host, even when an Ambisonic order or another internal setting uses fewer active channels. MIDI- and note-only plug-ins have no numeric suffix rather than the misleading suffix 0. Stable CLAP identifiers retain their existing spelling so saved projects continue to resolve the same plug-ins.
A normal run validates the complete source and destination set before changing the destination, then stages and copies the manifest-listed bundles. On the first upgrade from the former flat layout, it identity-checks recognized s3g-dsp bundles in the parent CLAP folder and moves those old copies to ~/Library/Application Support/s3g-dsp/CLAP Backups/<timestamp-pid>/Previous CLAP Root/ after installing the current set. --canonicalize-only instead moves verified current installations into the nested folder without replacing their binaries. The installer uses scripts/clap-legacy-bundles.tsv to recognize earlier filenames; unrelated plugins are not pruned. The --dry-run form reports the planned installs, migrations, and alias backups without writing anything.
After a successful run, ~/Library/Application Support/s3g-dsp/clap-install-receipt.tsv records the filenames owned by this package so later updates can distinguish them from other CLAP products.
Validate
CTest now registers the DSP smokes, numerical regressions, structural audits, installer migration test, focused CLAP ownership probes, and tagged state-compatibility fixtures exported by the released v0.5.0-pre binaries. Those fixtures contain deterministic non-default states plus old-release parameter ID/value sidecars. They cover representative panners, environmental and generative encoders, spectral processors, and larger state schemas; each current plugin must reproduce the released values, keep every parameter finite and in range, migrate and reload without value loss, and produce deterministic re-saved bytes. Build first, then run all tests or select the non-NIM release label:
cmake --build --preset clap-release
ctest --test-dir build-clap-release --output-on-failure
ctest --test-dir build-clap-release --output-on-failure -L non_nim
The sanitizer preset provides a separate RelWithDebInfo tree with AddressSanitizer and UndefinedBehaviorSanitizer enabled. Functional audio, finiteness, clipping, and discontinuity assertions remain active there; wall-clock realtime budgets are enabled only in the uninstrumented Release configuration so sanitizer overhead cannot create a false performance failure:
cmake --preset clap-sanitize
cmake --build --preset clap-sanitize
ctest --test-dir build-clap-sanitize --output-on-failure -L non_nim
Check the canonical CLAP inventory, installer migration behavior, static documentation, and advisory GUI conventions directly when investigating one layer:
python3 scripts/check-clap-bundle-manifest.py \
--build-root build-clap-release/plugins \
--defer-descriptor-version
./tests/clap_bundle_installer_smoke.sh
python3 scripts/check-docs.py
./scripts/audit-gui-style.sh
If clap-validator is installed, the manifest runner validates each bundle in an isolated subprocess with a per-bundle timeout, retains an individual log, and reports every failure instead of allowing one crash or hang to hide the rest:
python3 scripts/run-clap-validator-manifest.py \
--validator "$(command -v clap-validator)" \
--build-root build-clap-release/plugins \
--output build-clap-release/clap-validator-manifest.json
For a single bundle, invoke the validator directly. For example:
clap-validator validate --only-failed \
build-clap/plugins/clap_macro_shred/s3g_macro_shred_mono.clap \
build-clap/plugins/clap_macro_shred/s3g_macro_shred.clap \
build-clap/plugins/clap_macro_shred/s3g_24ch_macro_shred.clap \
build-clap/plugins/clap_psd_raw_field/s3g_fault.clap
On a quiet macOS release machine, the following target first runs the allocation-hook self-test and known-bad positive-control CLAP, then builds the complete manifest and runs the non-NIM CTest label, manifest and Objective-C audits, an isolated exact-inventory validator sweep, an inventory-derived non-NIM allocation gate, all strict realtime profiles with allocation evidence, and the 96 kHz environmental advisory sequentially. It refuses empty CTest selections and stale, malformed, partial, or mismatched JSON evidence. Each phase keeps its own log and the summary is written to build-clap-release/non-nim-release-checks.json:
cmake --build --preset clap-release \
--target release_checks_non_nim
Package a Pre-release
After a complete CLAP build, create the macOS zip used for GitHub pre-releases:
./scripts/package-macos-clap-prerelease.sh
The archive is written to dist/ and includes every manifest-listed CLAP product, Install s3g-dsp CLAPs.command, the active and legacy manifests, VOT wavetables, the Ambi Vox demo voicebank, the project license, and third-party notices. Packaging rebuilds and consumes build-clap-release/plugins/ by default, verifies that its CMake cache names this source tree and a Release configuration, and refuses a dirty source tree. Use S3G_CLAP_BUILD_DIR to select another verified Release build of this source tree; S3G_PACKAGE_ALLOW_DIRTY=1 is reserved for explicitly non-final test packages. Packaging and local installation consume the same manifest, so the archive inventory, installed filenames, and generated product list cannot drift independently.
The clap-release preset enables the completed VSTGUI migrations, including Tracker's portable shell and all ten pages. Before signing, the packager synchronizes each staged bundle's version metadata from its runtime CLAP descriptor; component versions remain independent of the suite archive version. It then requires exactly 122 manifest IDs and 129 unique runtime descriptors, arm64-only executables, matching descriptor, plist, ID, and host-name metadata, valid bundle signatures, and a successful isolated installer dry-run. The same checks run again after extracting the finished zip, and a .zip.sha256 checksum is written beside it. Bundles are ad-hoc signed by default for integrity verification. Set S3G_CODESIGN_IDENTITY to a Developer ID Application identity to enable hardened runtime and a secure timestamp, and set S3G_RELEASE_VERSION and S3G_RELEASE_DATE to override the pre-release metadata. A public release that opens without manual Gatekeeper approval must also be submitted to Apple notarization; a separately signed and notarized installer package is the preferred distribution path.
Cleanup
Reconfiguring an existing CMake directory does not necessarily remove artifacts produced under earlier target names. The manifest-driven installer and packager ignore unlisted build artifacts, and the installer backs up recognized aliases already present in the user plugin folder. Use --dry-run to inspect that cleanup before applying it; do not remove every s3g-named bundle because the folder may also contain products from other s3g projects.