Song Architecture
Song Class
TheSong class manages song data and metadata:
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 inassets/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
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)
- 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
- Instrumental starts 50ms early
- BF vocals start 40ms early (-50 + 10)
- Dad vocals start 50ms early (-50 + 0)
Play Data
TheplayData 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 inassets/songs/[id]/:
Required files:
Inst.ogg- Main instrumental trackVoices-Player.ogg- Player vocals (if song has vocals)Voices-Opponent.ogg- Opponent vocals (if song has vocals)
Inst-[altId].ogg- Alternate instrumental (e.g.,Inst-remix.ogg)
- Use
.oggformat (Vorbis codec) - Capitalize properly:
Inst.ogg, notinst.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):Song Variations
Variations allow alternate versions of a song: Variation structure:- 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)
Ticks
- 1 beat =
divisionsticks (typically 96) - Grid-aligned, prevents floating point errors
Float
Loading Songs
Songs are loaded viaSongRegistry:
Conductor Integration
Songs provide timing data to the Conductor:- Loads time changes from song metadata
- Calculates beat/step times based on BPM
- Fires timing signals (stepHit, beatHit, measureHit)
- Provides timing utilities for gameplay
