Skip to content

Audio

Patter doesn’t play audio, and it doesn’t impose an audio pipeline. Your engine and your audio tooling own that (Wwise, FMOD, engine-native, whatever you already use). What Patter gives you is the hook every pipeline needs: a stable id on every line (the same id that keys translations). Tie your voice-over to that id however suits your project (an addressable, a middleware event, a filename, a lookup table) and play it your way.

That id is all most teams need; the runtime hands it to you on every step:

const step = flow.advance();
if (step.type === "line") myAudioSystem.playFor(step.id); // your pipeline, keyed on the id

If you’d rather not wire up your own asset lookup, Patterpad ships an optional ready-made path on top of the id, described below. It’s a convenience for teams who want it rather than a requirement, and you can ignore everything past here and just key off the id.

For teams who don’t want to build their own lookup, Patterpad’s Audio Folders lets you keep takes as <beatId>.wav (or .mp3) files, ranked by recording status (scratch < recorded < final), and Patterplay resolves the best available take for each line without you reimplementing that folder-ranking search.

The ranking is resolved at build time, not in your game. When you Build (or run Production ▸ Update Audio Manifest), Patterpad writes a small sidecar next to your audio, patteraudio.json:

{ "schema": "patter/audio@0",
"clips": {
"L1": { "file": "final/L1.wav", "status": "final" },
"L2": { "file": "scratch/L2.mp3", "status": "scratch" } } }

Each beat maps to the winning file (highest recorded rung), as a path relative to your audio root. It’s a sidecar, never baked into the .patterc, so new takes don’t force a story rebuild.

To ship: drop the audio folder (subfolders + patteraudio.json) wherever your engine reads data, then point a resolver at it. The resolver resolves a path; it does not play the audio: playback is engine-native (and can’t be portable), but the part teams get stuck on, finding the right file, is done for you.

Each engine has the same tiny resolver: build it from the manifest + the base path where you deployed the audio, then resolve(beatId) returns the full path/URL (or nothing when a line has no recording).

JavaScript (@patterkit/play-helpers):

import { createAudioResolver } from "@patterkit/play-helpers";
const manifest = await (await fetch("audio/patteraudio.json")).text();
const audio = createAudioResolver(manifest, "audio"); // base = where you served the folder
const step = flow.advance();
const src = audio.resolve(step.id); // "audio/final/L1.wav", or null
if (src) new Audio(src).play(); // playback is yours

Unity (C#), deploy the folder under StreamingAssets:

var json = File.ReadAllText(Path.Combine(Application.streamingAssetsPath, "audio", "patteraudio.json"));
var audio = new PatterAudioResolver(json, Path.Combine(Application.streamingAssetsPath, "audio"));
string path = audio.Resolve(step.Id); // full path, or null

Unreal (C++ / Blueprint). UPatterAudioResolver is BlueprintCallable, so this can be graph-only:

UPatterAudioResolver* Audio = UPatterAudioResolver::Create(ManifestJson, TEXT("Audio"));
FString Path = Audio->Resolve(Step.Id); // full path, or empty

Godot (GDScript), deploy under res:// (or user://):

var json := FileAccess.get_file_as_string("res://audio/patteraudio.json")
var audio := PatterAudioResolver.new(json, "res://audio")
var path = audio.resolve(step.get("id", "")) # full path, or null when none
if path != null: my_player.stream = load(path)

Every engine resolves rather than plays. It returns a path/URL and you load and play it your way. That boundary is deliberate, audio playback isn’t portable, but resolution is.

No search is shipped. The winner is chosen at build time, so the runtime just does a map lookup.

A line with no recording is fine. resolve returns null / empty for a beat with no take, so you can fall back to on-screen text or silence.

It’s single language for now, since VO isn’t localised per-locale yet.

Keep it fresh. Re-run Update Audio Manifest (or Build) after adding takes so patteraudio.json reflects the latest winners.

Open source under the MIT licence, made by .