← Back to PMF
Specification

Procedural Music Format

Version1.0
Extension.pmf
EncodingJSON (UTF-8)
StatusStable

01 What PMF Is

PMF is a JSON-based format for describing procedural music compositions in a way that is immediately useful to any tool powered by an LLM or API. It is the serialization layer between a generative music engine and the wider world of AI tooling, game editors, web apps, and human inspection.

A .pmf file fully describes a composition — not the rendered audio, but the parameters, structure, and intent that produced it. Any tool that can read JSON can read a PMF file. Any LLM that knows music theory can reason about one without documentation.

02 Why PMF Exists

Existing music formats solve different problems:

FormatDesigned forWhy it fails here
MIDIPerformance captureBinary; every note is a timed event, no compositional intent
MusicXMLScore printingXML verbosity destroys LLM sequence efficiency
ABC NotationScore transcriptionNote-level only; no seed, mood, or generative parameters
ChordProChord sheetsNo melody, arrangement, or voice detail
YNote / HNoteLLM note generationNote sequences only; no composition structure

None of them describe how to generate music — only music that already exists. PMF fills that gap.

PMF is the right format when:

  • A composition is produced by a generative engine from a seed or parameters
  • You want an LLM to inspect, describe, modify, or reproduce it
  • You want any tool — game editor, web app, CLI — to read the same file

03 Design Principles

3.1 Musical Vocabulary First

Every numeric value that has a standard musical name is given that name. An LLM has been trained on music theory; use it.

"key": "A minor",
"progression": ["Am", "F", "C", "G"],
"progression_degrees": ["i", "VI", "III", "VII"],
"bpm_label": "mid-tempo",
"reverb_room": "warm medium hall"

3.2 Dual Representation

Machine-precise values and semantic labels coexist. Neither is omitted.

"bpm": 128.0,
"bpm_label": "mid-tempo",
"key_shift_semitones": 0,
"key": "A minor",
"delay_timing": "dotted_eighth",
"delay_timing_label": "3 × sixteenth note at 128 BPM ≈ 140ms"

3.3 Summary First

The top-level summary field is a single human-readable paragraph generated by the engine at render time. An LLM can read the summary alone and understand the composition. Everything below is supporting detail.

3.4 Layered Depth

Fields are ordered from high-level to precise. A tool that only needs to describe or compare tracks reads summary and identity. A tool that needs to reconstruct reads everything.

3.5 ABC for Note Sequences

Melody motifs are expressed in ABC notation — the format with the strongest LLM research backing for note-level data (ChatMusician, ABC-Eval 2024). PMF does not invent a new note syntax.

3.6 Engine-Agnostic Core, Engine-Specific Detail

The top sections (summary, identity, harmony, melody, arrangement) are generic — valid for any procedural music engine. The voices, fx, and mix sections carry engine-specific detail and are identified via the engine field at the root.

04 Top-Level Structure

{
  "pmf_version": "1.0",
  "engine": "<engine-name>",
  "engine_version": "<semver>",

  "summary": "<natural language paragraph>",

  "identity":     { ... },
  "render_key":   { ... },
  "harmony":      { ... },
  "melody":       { ... },
  "arrangement":  { ... },
  "voices":       { ... },
  "fx":           { ... },
  "mix":          { ... }
}

pmf_version, engine, summary, identity, and render_key are required. All other sections are optional — a minimal PMF file is valid with just those five.

05 Field Reference

5.1 Root

FieldTypeRequiredDescription
pmf_versionstringyesPMF format version. Currently "1.0"
enginestringyesName of the generating engine (e.g. "synthwave_engine")
engine_versionstringnoSemver of the engine that wrote this file
summarystringyesEngine-generated natural language description of the composition

5.2 identity

Who this composition is and what it sounds like.

FieldTypeRequiredDescription
seedu64yesThe seed that produced this composition
moodstringnoMood preset name (engine-defined)
bpmf32yesTempo in beats per minute
bpm_labelstringnoHuman label for the tempo (e.g. "mid-tempo")
keystringyesKey name in standard notation (e.g. "A minor", "F# minor")
key_typestringnoScale type: "natural_minor", "harmonic_minor", "major", etc.
key_shift_semitonesi8noSemitone offset from the engine's reference key
barsu32yesNumber of bars in the loop
time_signaturestringnoTime signature (default "4/4")

5.3 render_key

The exact rendering context. Together with identity.seed and pmf_version, this is sufficient to reproduce byte-identical output from a compatible engine version.

FieldTypeRequiredDescription
sample_rateu32yesAudio sample rate in Hz
barsu32yesBar count used for this render (must match identity.bars)
stem_formatstringyesChannel layout: "mono", "stereo", or engine-defined variants
loop_modestringyes"looped" or "finite"
engine_version_majoru32yesMajor version of the engine — determinism is stable within a major version
palette_pack_versionu32noVersion of the palette pack used, if the engine supports swappable packs

5.4 harmony

The harmonic structure of the composition.

FieldTypeRequiredDescription
progressionstring[]noChord names in order (e.g. ["Am", "F", "C", "G"])
progression_degreesstring[]noScale degrees (e.g. ["i", "VI", "III", "VII"])
progression_labelstringnoHuman description (e.g. "classic minor turnaround")
key_root_midiu8noMIDI note number of the key root (A4=69)
bass_patterni8[]noPer-beat interval offsets from chord root in semitones
bass_pattern_labelstringnoHuman description (e.g. "root-root-fifth-root")
arp_patternstringnoArp pattern name (engine-defined)
arp_pattern_labelstringnoHuman description of the arp movement
arp_bar_orderu8[]noWhich arp pattern index plays each bar

5.5 melody

Named melodic motifs. Keys are string identifiers ("motif_a", "motif_b", or any name the engine uses). Each motif object:

FieldTypeRequiredDescription
abcstringyesMotif body in ABC notation (no headers — key comes from identity.key)
intervals_semitonesi8[]noInterval steps in semitones (for LLM reasoning without ABC parsing)
rhythmstringnoHuman-readable rhythm description
labelstringnoHuman description of the motif's musical character
active_barsu8[]noBar indices where this motif plays
ABC usage: only the melody body is encoded — no headers, no key signature, no meter. Those come from identity. Example: "A2 c B A4" — two beats on A, then C, B, A.

5.6 arrangement

How the composition unfolds bar by bar.

FieldTypeRequiredDescription
templatestringnoArrangement template name (engine-defined)
sectionsobject[]noNamed sections with bar ranges and active stems
melody_on_barsu8[]noBar indices where melody plays
bar_gainsobjectnoPer-stem float arrays — gain multiplier per bar per stem

Each section object:

{ "name": "Intro", "bars": [0, 1], "stems_active": ["drums", "bass"] }

bar_gains keys are stem names. Values are arrays with one entry per bar. Gain semantics: 0.0 = silent, 1.0 = full, >1.0 = boosted.

5.7 voices

Per-voice synthesis parameters. Keys are voice names. Content is engine-defined — PMF specifies no fixed schema, only the convention that semantic labels accompany raw values.

5.8 fx

Post-processing chain. Common sub-keys: reverb, delay, sidechain, limiter. Engine-defined.

5.9 mix

Master mix parameters: stem volume presets, tween timing, reactive control tables. Engine-defined.

5.10 extensions

Optional. Engines may attach custom data here under a namespaced key to avoid polluting the core namespace. The key should match engine at the root.

"extensions": {
  "my_engine": {
    "custom_field": "value"
  }
}

06 Summary Generation

The summary field is computed by the engine — not written by hand and not filled by an external AI. A good PMF summary answers in one paragraph:

  1. What does it sound like overall? (tempo, mood, key, genre character)
  2. How does it unfold? (arrangement arc, when stems enter or drop)
  3. What makes it distinctive? (motif character, notable FX, anything unusual)

Template:

{tempo_label} {mood} track in {key} at {bpm} BPM. {arrangement_arc}. {melody_description}. {fx_highlight_if_notable}.

Example:

Mid-tempo NightDrive track in A minor at 128 BPM. Sparse intro over bars 0–1 (drums and bass only) builds through a melancholy i–VI–III–VII progression to full mix by bar 4. Ascending minor-third motif enters at bar 4 and resolves with a pentatonic descent in bar 6. Warm medium-hall reverb and dotted-eighth slap delay on the lead.

Rules:

  • Use musical vocabulary, not parameter names
  • Mention the arrangement arc if non-trivial
  • Keep it under 80 words
  • Do not mention seed, sample rate, or version numbers

07 AI Consumption Guide

When an LLM reads a PMF file, read in this order:

  1. summary first. Gestalt in one paragraph. Stop here for description or comparison tasks.
  2. identity and harmony. Key, BPM, progression, and mood determine character.
  3. arrangement.sections and bar_gains. Structure and dynamics.
  4. melody motifs. ABC body + label for melodic content.
  5. voices, fx, mix. Only for synthesis modification or exact reconstruction.

For modification tasks: change identity, harmony, or melody fields. Re-submit to the engine. Do not hand-edit bar_gains unless the arrangement template changes — the engine owns those values.

For comparison tasks: identity.mood, harmony.progression_degrees, arrangement.sections, and melody.*.label are the most semantically rich fields for clustering or ranking.

For reconstruction: identity.seed + render_key + engine + engine_version_major is the minimum key. All other fields are derived — the engine ignores them on exact round-trip.

08 Round-Trip Contract

Exact round-trip (byte-identical audio): identity.seed + render_key.* + engine + engine_version_major unchanged. Engine re-derives everything from the seed.

Approximate round-trip (musically consistent, different PCM): engine accepts an edited PMF with changed identity or harmony fields, renders a new composition consistent with those params.

Engine support for approximate round-trip is declared per-engine. Engines that do not support it may ignore all fields except the reconstruction key.

09 Versioning

pmf_version follows semver. The current version is 1.0.

BumpWhat changesNotes
PatchBug fixes in this documentNo format change
MinorNew optional fields addedExisting readers ignore unknown fields
MajorRequired fields changed or removedReaders must warn on mismatch

Field removal is always a major bump. Field rename is always a major bump.

10 Complete Example

See examples/synthwave-example.pmf for a full annotated file.

Minimal valid file: examples/minimal.pmf

11 What PMF Is Not

  • Not an audio format. Use WAV or OGG for rendered audio.
  • Not a score format. PMF does not encode every note in the final render. Use MIDI export for that.
  • Not a DAW project format. No clip editing, automation lanes, or plugin state.
  • Not a streaming format. PMF is a snapshot, not a real-time exchange protocol.
  • Not a replacement for MIDI. PMF and MIDI are complementary — an engine can export both from the same render.