JUCE SDK integration.

This commit is contained in:
Johannes Findeisen 2026-11-06 18:29:35 +01:00
commit adcbcdfd5e
16 changed files with 1057 additions and 0 deletions

85
docs/JUCE.md Normal file
View file

@ -0,0 +1,85 @@
# JUCE integration (Phase 107)
JUCE is used by optional, runnable examples alongside xtc's C99 engine and FLTK
application. It is an external SDK dependency, not vendored, fetched, linked by
normal builds or automatically installed. The integration uses:
| JUCE capability | Implemented use |
| --- | --- |
| AudioProcessor and plugin clients | mono/stereo VST3 instrument and standalone application |
| Audio/MIDI devices | standalone wrapper's device selection and MIDI routing UI |
| AudioProcessorValueTreeState | stable host parameters and validated versioned presets |
| GUI, graphics, events | custom native editor, parameter attachments, keyboard, meters and asynchronous preset chooser |
| DSP | low-pass filter, stereo reverb and smoothed output gain |
| MIDI | host event offsets, GUI event FIFO, Standard MIDI File parsing and tempo conversion |
| Audio formats | stereo float32 WAV export |
| Plugin hosting | explicit VST3 inspection, parameter discovery and state/processing qualification |
Synthesis is the real xtc **Soft Keys** implementation, called through
`xtc_plugin_*`. C++ remains confined to the optional integration. The SDK build
uses a separate PIC build of the C archive with JACK/FLTK disabled; the installed
application and existing build directories are not modified.
## Licensing and dependency impact
The inspected JUCE checkout is 9.0.4, revision
`3fb5cbc0340758596dac39f7c8de47d562b4896e`. Its modules are dual-licensed under
**AGPLv3 and the commercial JUCE licence**. A commercial JUCE licence may be
required for distribution; choose and comply with the applicable SDK licence.
xtc's MIT licence for original integration code does not relicense JUCE or a
combined binary. Read the actual SDK `LICENSE.md`, its third-party inventory
`JUCE.spdx.json`, and [JUCE licensing](https://juce.com/legal/juce-9-licence/)
before distributing those binaries. No SDK source or JUCE-linked binary is added
to the normal xtc install/package targets.
JUCE requires C++17 and its Linux development dependencies, including ALSA,
Fontconfig/FreeType and X11 libraries. CMake >= 3.25 and GNU Make build these
examples. Xvfb runs automated checks without a desktop. The SDK's `juceaide`
tool is compiled at configure time. Builds are substantially heavier than the
C-only core. Browser/network features are disabled; normal builds never fetch
SDKs or install system packages. Only the inspected SDK revision has been
qualified; use the documented revision for reproducibility.
## Processing and ownership
The processor creates/destroys its C synth and prepares JUCE DSP in quiescent
`prepareToPlay`/`releaseResources`. Host calls must obey AudioProcessor's lifecycle
contract. The callback splits arbitrary host buffers into 256-frame C blocks.
MIDI note, controller, pitch-bend and all-notes-off messages keep their sample
offsets; other messages, including SysEx/program change, are ignored. Events
outside the block are not rendered. More than 256 supported events in a chunk
silences the whole host block and clears voices. GUI notes enter a bounded
single-producer/single-consumer FIFO at offset zero in the next callback;
GUI queue overflow requests panic and discards queued notes. No keyboard-state
locks or GUI calls occur in the callback.
Five APVTS parameters control output gain, low-pass cutoff, room size, wet mix
and effect enable. Values are read atomically per host block; output gain ramps
for 10 ms. This is block-level parameter adoption, not sample-accurate automation.
Effects default off, making the wrapper output identical to the C synth at
unity gain. Mono/stereo work at 8–192 kHz; float64 is not exposed. The synth has
32 voices, attack/release, sustain and pitch bend from the C implementation.
The keyboard shows local GUI notes; it does not mirror external MIDI notes.
Presets contain the five parameter values and schema version 1, not voices,
plugin binaries, device choices, project arrangements or reverb history. Restore
validates the complete state before adoption (64 KiB maximum). Saving uses a
same-directory temporary file; the chooser asks about replacing an existing
preset. Host state APIs use the same schema. The wrapper's `.xtcjuce` presets
are separate from xtc project/chain presets.
## Limits and qualification
See [build and example commands](../examples/juce/README.md). These examples do
not migrate the main DAW to JUCE, add a new public backend, extend the C VST3
host's editor/controller support, or finish Phase 106's native ASIO work.
The JUCE VST3 can be loaded by xtc's existing instrument workflow in default
configuration. The C host translates all-off into individual note-offs, allowing
the synth release tail rather than an immediate hard stop. Its custom editor/parameters require a capable JUCE/VST3 host or
the standalone example. Explicit plugin inspection executes trusted plugin code;
it is not a scanner sandbox and must not run inside an audio callback.
Linux build/offline/editor/plugin results are recorded in Phase 107. Physical
audio/MIDI devices, Windows/macOS, ASIO and AU/AAX/LV2/VST2 exports require their
own platform, SDK, license and hardware qualification. Unrelated JUCE modules
such as video, network services and mobile UI are outside this audio phase.

View file

@ -3440,6 +3440,64 @@ configuration correctly rejects the unsupported platform; no Windows build or
ASIO hardware result is claimed.
---
## Phase 107 — JUCE Audio, Plugin, DSP and Interface Examples
### Goal
Use JUCE's relevant audio framework capabilities with the actual xtc C99 engine:
AudioProcessor/plugin wrappers, standalone audio/MIDI devices, a native editor,
parameter/state management, DSP effects, MIDI files, WAV export and VST3 hosting.
Keep this integration optional and externally supplied. This user-requested
phase can proceed alongside the unfinished platform work in Phase 106; it does
not replace the main FLTK application or move the C engine into C++.
### Tasks and acceptance criteria
- [x] Add an offline-by-default external JUCE build and explain its
AGPLv3/commercial licensing, dependencies and packaging boundary.
- [x] Build working VST3 and standalone synth targets using xtc Soft Keys through
the public C API; negotiate mono/stereo and handle variable host blocks.
- [x] Provide a native JUCE editor with attached host parameters, on-screen MIDI
keyboard, peak display, panic and transactional versioned preset files.
- [x] Use JUCE DSP for a low-pass filter, reverb and smoothed output gain, with
all processing storage prepared outside processBlock.
- [x] Implement bounded MIDI queues/overflow panic and preserve host MIDI sample
offsets without callback allocation, I/O, GUI calls or host-side locks.
- [x] Provide a console example for Standard MIDI File import with tempo
conversion and float32 stereo WAV rendering with atomic no-clobber output.
- [x] Demonstrate explicit JUCE VST3 discovery, parameter inspection, state
capture/restore and actual MIDI processing against the built example.
- [x] Test C-render equivalence, stereo/mono, variable blocks, reset, invalid
preparation, queue overflow, preset recovery, editor rendering/reopening
and loading the JUCE VST3 from xtc's existing C host.
- [x] Build with warnings enabled, run the focused integration checks and retain
ordinary C/FLTK builds/tests without a JUCE dependency.
### Implementation status
Implemented and qualified on Linux with external JUCE 9.0.4 revision
`3fb5cbc0340758596dac39f7c8de47d562b4896e`. See [JUCE.md](JUCE.md) and
[examples/juce](../examples/juce/README.md) for reproduction.
Validation (2026-11-06):
- `make -j4 all test`: ordinary C/FLTK build and regression suite passed.
- `make JUCE_ROOT=/path/to/JUCE test-juce`: warning-enabled VST3, standalone
and CLI builds; processor/JUCE-host CTests; file/editor acceptance checks;
and the existing C-host integration test passed under Xvfb.
- Steinberg VST 3.8.1 validator: 47 tests passed, zero failed.
- Rendered the demo to a 216000-frame 48 kHz stereo float32 WAV; inspected
the actual 1560 × 980 editor snapshot. No physical audio device was opened.
- C-host all-off uses individual note-offs, so acceptance checks finite release
and eventual silence; the JUCE host also verifies immediate MIDI all-off timing.
Broader adoption in
the main DAW, additional plugin formats, Windows/macOS portability, native ASIO
and physical-device latency/loopback qualification remain separate work. Merely
building JUCE's standalone wrapper does not establish hardware acceptance.
---
## Recommended Execution Order