Skip to content
The Fenophone

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:

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

EngineBindingStart with
UnityC# / P/Invoke packageAdd a FenophoneSource to an AudioSource
Godot 4GDExtensionA FenophoneMusic node
UnrealC++ pluginA UFenophoneMusicComponent (a USynthComponent)
Any C++ engineHeader-only wrapperfenophone::Instance
Any C engineThe raw C interfaceOne 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

  1. Construct

    Create an instance with a seed and your device sample rate. The seed is the soundtrack's identity — save it.

  2. 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).

  3. 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.

  4. Render

    On your audio thread, render stereo into your mixer at any block size. The component bindings (Unity, Godot, Unreal) do this for you.

  5. 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 signalControlNotes
Danger / combat heatIntensitythe primary dial — most games drive this every frame
World scale / opennessSpreadhow wide and open the music feels
PacingChange Ratehow often the music shifts
Scene detailLayers, Flowdensity of the texture
Mix levelLevelsmoothed master volume
The game clock / beat gridhost tempobars phase-lock to your grid
Scripted build / stingerpin a slow layerhold a layer high for a sustained build, then release
Scene / mood changepack switchuse 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

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

Threading

Engine calls are not thread-safe per instance. The rule everywhere:

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:

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.

Where to go next