Developer docs
Game developer start-up guide
Zero to a live, adaptive soundtrack: pick your engine, map game state to a handful of controls, handle save games, and license it. The terse version is the adaptive runtime reference.
What Fenophone is, for a game
Getting the SDK. The runtime and its engine bindings ship privately today — join the waitlist for access (commercial titles and free game-jam builds both start there). These pages are the integration reference for what you get.
Fenophone is a generative music engine you embed in your game. Instead of shipping fixed audio tracks and cross-fading between them, you ship a small engine that composes the score live, and you steer it from gameplay: danger raises the intensity, entering a boss room switches the mood on the next downbeat, a scripted beat pins a build.
Why it fits games specifically:
- Deterministic. The same seed and the same sequence of calls produce the exact same score, bit for bit at the note layer. Replays and netcode stay in sync; a soundtrack is testable in CI; and every shipped sound is provenance-cleared, so streamers are safe.
- A living feel that actually replays. The humanized microtiming — the drift and push that keep the score from sounding like a grid — is itself deterministic: a pure function of the seed, not a per-playback random jitter. The exact feel survives replays, rollback netcode, and save states. No other humanize control can promise that.
- The music is tiny state. A whole performance is a small state vector — save the seed (or the full state chunk) in your save game and the score resumes exactly.
- One engine, every control. Dials, layer pins, tempo-sync, and beat-quantized mood transitions are all built in — the parts middleware usually makes you assemble yourself.
- It can drive the game, too. An instance can emit the raw event stream instead of audio, so you can pulse lights, spawns, or haptics off the music's harmonic tension.
You do not author notes, DSP, or stems. You pick packs (authored four-voice ensembles) and map game signals to a handful of controls. That mapping is your creative work, and it lives in your game code.
Pick your engine
| Engine | Binding | Start with |
|---|---|---|
| Unity | C# / P/Invoke package | Add a FenophoneSource to an AudioSource |
| Godot 4 | GDExtension | A FenophoneMusic node |
| Unreal | C++ plugin | A UFenophoneMusicComponent (a USynthComponent) |
| Any C++ engine | Header-only wrapper | fenophone::Instance |
| Any C engine | The raw C interface | One small header, framework-free |
Each binding is a 1:1 wrapper over the same C interface, so this guide's concepts apply everywhere; only the syntax changes. The SDK ships the compiled engine library (static and shared) with per-engine install notes — see the bindings overview.
Your first score in ~20 minutes
-
Construct
Create an instance with a seed and your device sample rate. The seed is the soundtrack's identity — save it.
-
Open on a pack
Pick a pack from the embedded registry (warm ambient, beat-driven, cinematic, and more — every launch pack ships in the engine).
-
Map game state to controls
Each gameplay tick, feed your signals to the dials: danger to Intensity, world scale to Spread, pacing to Change Rate. All live, no audio glitch.
-
Render
On your audio thread, render stereo into your mixer at any block size. The component bindings (Unity, Godot, Unreal) do this for you.
-
Save
Store the seed — or the full state chunk — with your save game. Loading resumes the exact take, pins and all.
The shape, in C++
#include "fenophone.hpp"
// 1. construct (seed = the soundtrack's identity; save it)
fenophone::Instance music(saveGame.musicSeed, deviceSampleRate);
// 2. open on a pack, and follow the game clock if you have one
music.set_scaffold(fenophone::scaffold_index_of("launch-warm-ambient"));
music.set_host_tempo(120.0, /*has_tempo=*/true);
// 3. each gameplay tick — game state -> music, live and glitch-free
music.set_param(fenophone::Param::Intensity, danger01); // combat heat
music.set_param(fenophone::Param::Spread, openness01); // world scale
if (enteringCombat) music.set_scaffold_at_next_bar(combatPack); // mood, on the next bar
// 4. on your audio thread, any block size
music.process_stereo(left, right, frames); // -> your mixer
// 5. on save
auto chunk = music.save_state();
In Unity that's a FenophoneSource component and
source.SetIntensity(danger); in Godot a FenophoneMusic node and
music.set_intensity(danger); in Unreal a
UFenophoneMusicComponent and Music->SetIntensity(Danger). Same
five steps.
The mapping: game state → music
This table is the heart of integration. Wire your game's signals to these controls; all of them are live (no audio glitch, no re-anchor) unless noted.
| Game signal | Control | Notes |
|---|---|---|
| Danger / combat heat | Intensity | the primary dial — most games drive this every frame |
| World scale / openness | Spread | how wide and open the music feels |
| Pacing | Change Rate | how often the music shifts |
| Scene detail | Layers, Flow | density of the texture |
| Mix level | Level | smoothed master volume |
| The game clock / beat grid | host tempo | bars phase-lock to your grid |
| Scripted build / stinger | pin a slow layer | hold a layer high for a sustained build, then release |
| Scene / mood change | pack switch | use the bar-quantized transition below |
Reading the score back (music → game): advance the event stream and read each event's harmonic-tension lane to drive lighting, enemy spawns, or haptics. The C++ bindings expose the raw events; the component bindings expose a mean-tension helper.
Two transition styles
- Switch on the next bar — the musical transition. The current pack finishes its bar, the new pack's downbeat lands exactly on the next bar, and the audio never breaks. This is what you want for "explore → combat." It's replay-stable: the same request at the same musical position always produces the same audio.
- Switch immediately — a hard cut. Re-anchors the take (like loading a preset). Use it for scene loads and teleports, not mid-scene mood shifts.
Vertical layering and crossfades. There is no engine-side blend between packs (yet). The intended pattern is two instances: run a calm bed and a combat layer as two independent instances driven from the same host-tempo clock, and equal-power crossfade their outputs in your mixer as gameplay dictates. Instances are cheap and fully independent.
Packs
A pack is an authored, four-voice ensemble with its own timbres, key and modes, and stereo image. The engine ships an embedded registry — the launch packs (warm ambient, beat-driven, cinematic) and more — which you enumerate at runtime and select by id.
Every shipped pack passes the same ten quality invariants the web product enforces, including the long-range-correlation ("1/f") floor — so a mood switch can never land on a pack that lost its multi-scale musical character. You select and map packs; you do not author DSP.
Determinism, save games, and replays
- The feel replays, not just the notes. The microtiming humanization is computed on the same integer-exact path as the notes, so the living groove is bit-identical for a given seed — a replay, a rollback resim, or a loaded save resumes the exact feel, not a fresh approximation.
- Seed = identity. Save the seed with your save game and the score comes back fresh-but-identical — the same character, a new improvisation.
- State chunk = the exact take. Saving state returns a small chunk (seed, dials, pins, active pack); loading it resumes the exact take, pins and all. It's the same portable state vector the web app and DAW plugin use.
- Replays and netcode. The note layer is bit-exact for a given seed + call timeline, so a recorded input timeline reproduces the same score. If your replays must survive engine updates, pin the engine version — the event stream is bit-exact per version.
Threading
Engine calls are not thread-safe per instance. The rule everywhere:
- your audio thread owns the render call;
- serialize parameter/state/pack calls against it — with a lock or a message queue.
The component bindings already do this for you (the Unity/Unreal wrappers serialize with a lock; the Godot node runs on the main thread and pushes to the generator). If you use the raw C interface or the C++ wrapper directly, add the lock yourself. Separate instances need no synchronization between them.
Licensing
The engine is proprietary; embedding it in a game is not covered by any product or plugin purchase — it needs the Fenophone runtime license. The shape:
- Free for game jams and free prototypes — embed the runtime with no payment under those terms, the required credit ("adaptive music by Fenophone") being the fee. This is the intended way to evaluate it.
- Per-title, one-time, own-it-forever to ship commercially — no royalties, no revenue share, no phone-home, no DRM. The runtime never gates your players. All audio the runtime generates at play time is yours (including gameplay videos, streams, and trailers).
- One agreement per title. A sequel or a new-SKU re-release is a new agreement.
- Compiled form only, and don't re-expose the engine as a general-purpose music tool to your players (that's redistributing the instrument, not scoring your game).
The license document is currently a draft pending counsel review. In practice: build and ship a jam game with it today under the free tier; for a commercial title, join the waitlist and you'll be contacted to countersign.
