Skip to main content

Audio & music

Formats​

Paths.SOUND_EXT is ogg on native targets and mp3 on web/Flash. project.hxp excludes the unused format from each build, so only one copy ships. Audio assets were re-encoded for roughly 50 % size reduction without a quality change that matters at game volume.

KindPath
Instrumentalsongs/<song>/Inst.<ext>
Vocalssongs/<song>/Voices.<ext> (loaded only when needsVoices)
Musicmusic/<key>.<ext>
SFXsounds/<key>.<ext>

Paths.inst(song, difficulty) and Paths.voices(song, difficulty, postfix) handle difficulty-specific and postfixed variants (used by per-character vocal tracks via the character JSON's vocals_file).

Playback during a song​

play.helpers.PlayStatePlayback owns the song audio:

  • starts instrumental and vocals together and keeps them in sync,
  • resyncs when they drift (a dropped frame or a long GC pause),
  • applies playbackRate to both audio and the conductor,
  • handles pause/resume, including the vocals,
  • stops everything cleanly on game over and at the end of the song.

Conductor.songPosition is driven from the instrumental's time, not from elapsed, so rendering hitches cannot desync the chart.

Pitch on SWF targets

Flash and AIR have no pitch shifting. A haxelib patch gives FlxSound a store-only pitch property so the code compiles there, and #if FLX_PITCH guards the places where real pitch shifting is required.

Paths.playMenuMusic(force, volume) plays the menu theme, and Paths.playModMusic(file, fallback, volume) lets a mod replace it: it tries mods/<mod>/music/<file>.ogg, then the legacy name, then the base theme, then the default. This is what makes "modified freakyMenu names" work — a mod can ship its own menu track without renaming engine assets. ClientPrefs.daMenuMusic and ClientPrefs.pauseMusic choose between shipped variants.

The freeplay music player​

music.MusicPlayer is the overlay in states.FreeplayState that lets you listen to songs from the song list: play/pause (pauseOrResume), seek, track time (curTime) and switchPlayMusic() to toggle between browsing and listening. It owns Freeplay previews separately from gameplay. The Android Media3 session is currently attached by PlayStateAndroidMedia once a chart enters PlayState, so chart playback—not a Freeplay preview—is exposed to system media controls, the lock screen, Bluetooth devices and Android Auto.

Sound tray​

objects.CustomSoundTray replaces Flixel's volume overlay with the engine's styled version (CustomSoundFrontEnd extends Flixel's SoundFrontEnd). Volume and mute keys come from ClientPrefs.keyBinds and are pushed into TitleState.muteKeys, volumeUpKeys and volumeDownKeys on load. The tray is disabled on Flash/AIR via FLX_NO_SOUND_TRAY.

Hitsounds and feedback​

ClientPrefs.hitsoundVolume and hitsoundType (e.g. osu!mania) drive the per-note click; missSoundEnabled plays the classic miss sound. Both are played through FlxG.sound.play(Paths.sound(...)) with the sound preloaded by the playstate so the first hit does not stutter.

Video​

Video playback uses hxvlc behind VIDEOS_ALLOWED (desktop and mobile C++ targets only). play.CutsceneHandler sequences cutscenes, and Lua's startVideo(name) plays one from a script. On Linux this is why libvlc is a build requirement; the old hxCodec instructions in BUILDING.md no longer apply.

Spectrum analysis​

stages.objects.ABotSpeaker visualises the instrumental through funkin.vis (SpectralAnalyzer) and grig.audio. Both are forks, and the analyzer needed a patch so Flash/AIR builds compile without a Web-Audio or Lime AudioSource backend.