Skip to main content
The song system manages song metadata, chart data, audio playback, and the integration between music and gameplay.

Song Architecture

Song Class

The Song class manages song data and metadata:
Key Properties:
String
Unique song identifier (e.g., “tutorial”, “bopeebo”)
String
Display name shown to players
String
Artist credit
String
Person who created the chart
String
Current variation (e.g., “default”, “erect”)

Song Metadata Format

Song metadata is stored in assets/data/songs/[id]/[id]-metadata.json:

Metadata Fields

String
required
Metadata format version (currently “2.2.4”)
String
required
Display name of the song
String
required
Song artist name
String
Person who charted the song
Int
default:"96"
Number of divisions per beat (used for chart precision)
Bool
default:"false"
Whether the song should loop
String
default:"ms"
Time format: "ms" (milliseconds), "ticks", or "float"
String
Tool or person that generated this metadata

Time Changes

Songs can have multiple BPM and time signature changes:

SongTimeChange Fields

Float
required
Timestamp when the change occurs (in the format specified by timeFormat)
Float
required
New BPM value (quarter notes per minute)
Int
default:"4"
Time signature numerator (the ‘4’ in 4/4)
Int
default:"4"
Time signature denominator (the ‘4’ in 4/4)
Float
Beat time at this change (calculated automatically if not provided)
Array<Int>
default:"[4, 4, 4, 4]"
Beat tuplets - defines step subdivisions for each beat
Example: BPM change mid-song
This song starts at 120 BPM, then changes to 180 BPM at 48 seconds.

Audio Offsets

Offsets compensate for timing discrepancies:

Offset Fields

Float
default:"0"
Offset for the main instrumental track (in milliseconds). Negative values start the track earlier.
Map<String, Float>
default:"{}"
Offsets for alternate instrumental tracks
Map<String, Float>
default:"{}"
Per-character vocal offsets (applied on top of instrumental offset)
How offsets work:
  • Negative offset: Audio starts earlier (compensates for delayed chart)
  • Positive offset: Audio starts later (compensates for early chart)
  • Vocal offsets are added to instrumental offset
Example:
  • Instrumental starts 50ms early
  • BF vocals start 40ms early (-50 + 10)
  • Dad vocals start 50ms early (-50 + 0)

Play Data

The playData section contains gameplay-related metadata:

Play Data Fields

Array<String>
default:"[]"
List of variations (e.g., ["erect"]). Each variation has its own metadata file.
Array<String>
required
Available difficulty levels for this song
SongCharacterData
required
Character IDs for player, opponent, and girlfriend
String
required
Stage ID to use for this song
String
default:"funkin"
Note skin/style ID
Map<String, Int>
Difficulty ratings shown in freeplay (1-10 scale)
String
Album ID for freeplay display
Int
default:"0"
Start time for audio preview in freeplay (milliseconds)
Int
default:"15000"
End time for audio preview in freeplay (milliseconds)

Character Data

String
default:"bf"
Player character ID
String
default:"dad"
Opponent character ID
String
default:"gf"
Girlfriend character ID
String
default:""
Default instrumental track ID (empty string = default)
Array<String>
default:"[]"
List of alternate instrumental IDs
Array<String>
Character IDs whose vocals are in the player track
Array<String>
Character IDs whose vocals are in the opponent track

Audio File Structure

Audio files are located in assets/songs/[id]/: Required files:
  • Inst.ogg - Main instrumental track
  • Voices-Player.ogg - Player vocals (if song has vocals)
  • Voices-Opponent.ogg - Opponent vocals (if song has vocals)
Optional alternate instrumentals:
  • Inst-[altId].ogg - Alternate instrumental (e.g., Inst-remix.ogg)
File naming conventions:
  • Use .ogg format (Vorbis codec)
  • Capitalize properly: Inst.ogg, not inst.ogg
  • Alternate instrumentals: Inst-[id].ogg
  • Character-specific vocals: Voices-[charId].ogg

Vocal Tracks

Vocals can be split by character or combined: Split by role (recommended):
Split by character:
Combined vocals (legacy):
The engine automatically determines which format is used.

Song Variations

Variations allow alternate versions of a song: Variation structure:
Default metadata references variations:
Each variation has:
  • Separate metadata file
  • Separate chart file
  • Can have different BPM, characters, or stage
  • Can share or have unique audio files

Time Formats

FNF supports three time formats:

Milliseconds (Default)

Times are in milliseconds. Most intuitive for editing.

Ticks

Ticks are divisions of a beat. Useful for MIDI imports.
  • 1 beat = divisions ticks (typically 96)
  • Grid-aligned, prevents floating point errors

Float

Times are in seconds as floating point values.

Loading Songs

Songs are loaded via SongRegistry:

Conductor Integration

Songs provide timing data to the Conductor:
The Conductor:
  1. Loads time changes from song metadata
  2. Calculates beat/step times based on BPM
  3. Fires timing signals (stepHit, beatHit, measureHit)
  4. Provides timing utilities for gameplay

Example: Complete Song Setup

Directory structure:
myawesomesong-metadata.json: