Choose backends and wire the composition root
Questa pagina è in inglese: in italiano ci sono per ora i tutorial e il glossario; menu, ricerca e navigazione sono in italiano.
The cores need a few capabilities from the outside world: a control thread,
a clock, files, devices, sockets. Each capability is a port (an abstract
class declared by a core). You pick an adapter for each port, create it in
your main, and pass it to the cores that need it.
The adapters without JUCE are part of shuffle_engine. The JUCE and Tracktion
adapters (juce_*, te_*) come from the
shuffle_juce satellite and
the audio.cpp adapter (ai_audiocpp) from
shuffle_ai; see
satellites.
1. Pick an adapter per capability
Section titled “1. Pick an adapter per capability”| Capability | Ports | Without JUCE (shuffle_engine) | With JUCE or Tracktion (shuffle_juce) |
|---|---|---|---|
| control thread, timer, workers, clock, files, settings, appearance, displays | TaskQueue, WorkerPool, Clock, FileStore, SettingsStore, SystemAppearance, DisplayInfo |
platform (ControlLoop, ControlTimer, ThreadWorkerPool, SteadyClock, OsFileStore, JsonSettingsStore, OsSystemAppearance, OsDisplayInfo) |
juce_platform (JuceTaskQueue, ControlTimer, JuceWorkerPool, JuceClock, JuceFileStore, JuceSettingsStore) |
| audio devices and the engine’s device callback | AudioDeviceChannels, AudioDeviceSwitch, DeviceEvents, ProcessingThreads |
miniaudio (MiniaudioDevices, EngineAudioCallback, OsProcessingThreads) |
juce_audio (JuceAudioDevices, EngineAudioCallback, JuceProcessingThreads) |
| MIDI devices, MIDI 1.0 and 2.0 | MidiInputDirectory, MidiOutputDirectory, DeviceEvents |
libremidi (LibremidiDevices) |
juce_midi (JuceMidiDevices, MIDI 1.0) |
| plugin hosting | PluginHost, PluginInstance, InsertProcessor |
plugin_host (NativePluginHost: CLAP, VST3, LV2, AU) |
juce_plugins (JucePluginHost: VST3, AU, LV2) |
| an embedded web UI | WebUiHost |
a WebSocket server for pages in a separate browser: net_websocket (WebSocketServer) |
juce_webui (JuceWebUiHost) |
| UDP, TCP, network interfaces | DatagramNetwork, StreamNetwork, NetworkInterfaces |
net_sockets (OsDatagramNetwork, OsStreamNetwork, OsNetworkInterfaces) |
|
| audio codecs | CodecProvider |
codecs (OpenCodecs: FLAC, Vorbis, Opus, MP3 read); AAC and ALAC through platform codecs: coming |
|
| songs as a multitrack engine | SongSessionFactory, Transport, MixControl, … |
the framework’s own core/engine (EngineSongSessionFactory, …) |
te_engine, te_devices on Tracktion Engine |
| AI audio tasks: speech, recognition, stems, audio to MIDI | SpeechSource, SpeechToText, StemSeparator, AudioToMidi (core/ai_tasks in shuffle_ai) |
ai_audiocpp on audio.cpp, in shuffle_ai (desktop only, opt-in) |
Each adapter’s README lists its classes, threads, declared limits and the platforms it was verified on: platform, miniaudio, libremidi, net_sockets, net_websocket, codecs, plugin_host; in the satellites, audiocpp, juce, tracktion. The complete port list is in ports.md.
You can mix them: JUCE for devices, net_sockets for OSC, codecs for
files; or no JUCE at all, with platform, miniaudio and libremidi. In tests, use the fakes instead (Test your app).
2. Ask CMake for them
Section titled “2. Ask CMake for them”List the modules after USES; the names are the ones above and the core
names (setlist, routing, engine, …). Without JUCE:
shuffle_engine_add_app (MyShow SOURCES src/main.cpp USES platform miniaudio setlist routing)With JUCE, add shuffle_juce after shuffle_engine so its modules exist:
add_subdirectory (../shuffle_engine shuffle_engine)add_subdirectory (../shuffle_juce shuffle_juce)shuffle_engine_add_app (MyShow BACKEND juce GUI SOURCES src/main.cpp USES juce_platform juce_audio juce_midi setlist routing)When shuffle_engine is a subproject of your build, adapters are off unless you switch them on at configure time:
| Option | Default as a subproject | Builds |
|---|---|---|
SHUFFLE_ENGINE_WITH_PLATFORM |
ON | platform |
SHUFFLE_ENGINE_WITH_MINIAUDIO |
ON | miniaudio (fetches miniaudio) |
SHUFFLE_ENGINE_WITH_NET_SOCKETS |
ON (not on WebAssembly) | net_sockets |
SHUFFLE_ENGINE_WITH_LIBREMIDI |
OFF | libremidi (fetches libremidi) |
SHUFFLE_ENGINE_WITH_CODECS |
OFF | codecs (fetches the codec libraries) |
SHUFFLE_ENGINE_WITH_PLUGIN_HOST |
OFF | plugin_host (desktop only; fetches the CLAP and VST3 interface headers) |
The satellites have options of their own: shuffle_juce builds the juce_*
modules (JUCE found through JUCE_HOME or downloaded at 9.0.3) and the
te_* modules with SHUFFLE_JUCE_WITH_TRACKTION (TRACKTION_HOME or a
download); shuffle_ai builds ai_audiocpp with SHUFFLE_AI_WITH_AUDIOCPP
(fetches and builds audio.cpp; desktop only).
BACKEND juce or tracktion in shuffle_engine_add_app makes the
executable a JUCE application; BACKEND core is a plain C++ program and can
still use the plain adapters (net_sockets, codecs, miniaudio).
3. Write the composition root
Section titled “3. Write the composition root”Create the adapters first, then the cores that take them, then what uses the cores. Destroy in reverse. Members of one struct give you that order for free. This is the JUCE wiring from shuffle_juce’s adapters/juce/README.md:
const juce::ScopedJuceInitialiser_GUI juce; // or a JUCEApplication
JuceTaskQueue tasks; // build in this order,JuceWorkerPool workers; // destroy in reverseJuceClock clock;JuceFileStore showFiles (showFolder);JuceSettingsStore settings (appData.getChildFile ("machine.settings"), tasks, workers);JuceMidiDevices midiDevices (clock, tasks);ControlTimer timer ([&] { /* the cores' periodic calls */ });JucePluginHost plugins (tasks, workers, settings, appFiles); // appFiles: a JuceFileStore on the app data folderJuceProcessingThreads threads (JuceProcessingThreads::countForThisMachine());engine::Engine engine ({ clock, &threads });EngineAudioCallback callback (engine, tasks, &threads);JuceAudioDevices audioDevices (callback, tasks); // opens nothing yetaudioDevices.requestDevice (audioDevices.defaultDeviceKey());Then the cores, each with the ports its constructor lists, for example a set list on the engine’s sessions or a routing core on the devices:
routing::RoutingCore routing ({ audioDevices, audioDevices, settings, clock });Rules that keep it working on every platform:
- create and destroy everything on the control thread;
- stop audio (close the devices) before destroying the callback, the engine and the threads it uses;
- never block in a constructor: devices, scans and loads answer later through a listener or a completion posted to the task queue.
Complete, runnable roots: examples/miniaudio/play (audio, no JUCE), examples/platform/settings (platform ports), examples/net/osc_udp (sockets), examples/libremidi/ports (MIDI, no JUCE); in shuffle_juce, examples/juce/play (audio on JUCE), examples/juce/platform (platform ports on JUCE) and examples/tracktion/song (Tracktion).
Why it is built this way: Cores, ports and adapters, Why no globals.
© 2026 Umberto Sorbo. Il software è distribuito con la Apache License, Version 2.0, e fornito “così com’è”, senza garanzie o condizioni di alcun tipo; leggi l’esclusione di responsabilità.
SHUFFLE Framework e il logo di SHUFFLE Framework sono marchi di Umberto Sorbo; la licenza non concede alcun diritto su di essi (marchi). Gli altri nomi appartengono ai rispettivi titolari. Caratteri: IBM Plex Sans e JetBrains Mono, SIL Open Font License 1.1.
Contatti: shuffleframework@gmail.com · Instagram @shuffleframework. Problemi di sicurezza: scrivi allo stesso indirizzo con “Security” nell’oggetto, non in una issue pubblica.